neo.mjs 11.14.0 → 11.16.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/.gemini/settings.json +4 -0
- package/.github/VISION.md +3 -3
- package/ROADMAP.md +9 -6
- package/ServiceWorker.mjs +2 -2
- package/ai/demo-agents/dev.mjs +20 -19
- package/ai/demo-agents/pm.mjs +7 -6
- package/ai/examples/test-app-worker.mjs +74 -0
- package/ai/mcp/client/mcp-cli.mjs +5 -4
- package/ai/mcp/server/github-workflow/config.mjs +14 -8
- package/ai/mcp/server/github-workflow/mcp-stdio.mjs +2 -1
- package/ai/mcp/server/knowledge-base/config.mjs +11 -13
- package/ai/mcp/server/knowledge-base/mcp-stdio.mjs +2 -1
- package/ai/mcp/server/memory-core/Server.mjs +0 -1
- package/ai/mcp/server/memory-core/config.mjs +12 -14
- package/ai/mcp/server/memory-core/mcp-stdio.mjs +2 -1
- package/ai/mcp/server/memory-core/services/HealthService.mjs +1 -2
- package/ai/mcp/server/memory-core/services/TextEmbeddingService.mjs +7 -4
- package/ai/mcp/server/neural-link/Server.mjs +118 -0
- package/ai/mcp/server/neural-link/config.mjs +106 -0
- package/ai/mcp/server/neural-link/logger.mjs +20 -0
- package/ai/mcp/server/neural-link/mcp-stdio.mjs +33 -0
- package/ai/mcp/server/neural-link/openapi.yaml +181 -0
- package/ai/mcp/server/neural-link/services/ConnectionService.mjs +265 -0
- package/ai/mcp/server/neural-link/services/toolService.mjs +25 -0
- package/ai/mcp/server/neural-link/test_connection_service.mjs +21 -0
- package/ai/services.mjs +68 -58
- package/apps/agentos/index.css +128 -0
- package/apps/agentos/resources/data/interventions.json +26 -0
- package/apps/colors/view/Viewport.mjs +5 -5
- package/apps/colors/view/ViewportController.mjs +1 -1
- package/apps/portal/index.html +1 -1
- package/apps/portal/llms.txt +2 -1
- package/apps/portal/sitemap.xml +8 -4
- package/apps/portal/view/home/FooterContainer.mjs +1 -1
- package/buildScripts/addConfig.mjs +6 -5
- package/buildScripts/buildAll.mjs +15 -13
- package/buildScripts/buildThemes.mjs +14 -13
- package/buildScripts/copyFolder.mjs +5 -4
- package/buildScripts/copySeoFiles.mjs +10 -10
- package/buildScripts/createApp.mjs +22 -21
- package/buildScripts/createAppMinimal.mjs +22 -21
- package/buildScripts/createClass.mjs +8 -7
- package/buildScripts/createComponent.mjs +6 -5
- package/buildScripts/generateSeoFiles.mjs +7 -6
- package/buildScripts/tools/createExample.mjs +3 -2
- package/buildScripts/tools/createScss.mjs +3 -2
- package/buildScripts/util/Sanitizer.mjs +13 -0
- package/buildScripts/webpack/buildThreads.mjs +10 -9
- package/package.json +3 -1
- package/resources/scss/src/apps/agentos/InterventionPanel.scss +35 -0
- package/resources/scss/src/apps/agentos/Viewport.scss +125 -0
- package/resources/scss/src/grid/header/Button.scss +13 -3
- package/resources/scss/theme-cyberpunk/Global.scss +25 -0
- package/resources/scss/theme-cyberpunk/apps/agentos/InterventionPanel.scss +6 -0
- package/resources/scss/theme-cyberpunk/apps/agentos/Viewport.scss +21 -0
- package/resources/scss/theme-cyberpunk/button/Base.scss +113 -0
- package/resources/scss/theme-cyberpunk/container/Panel.scss +5 -0
- package/resources/scss/theme-cyberpunk/grid/Body.scss +15 -0
- package/resources/scss/theme-cyberpunk/grid/Container.scss +7 -0
- package/resources/scss/theme-cyberpunk/grid/header/Button.scss +12 -0
- package/resources/scss/theme-cyberpunk/toolbar/Base.scss +4 -0
- package/resources/scss/theme-dark/apps/agentos/InterventionPanel.scss +6 -0
- package/resources/scss/theme-dark/apps/agentos/Viewport.scss +24 -0
- package/resources/scss/theme-dark/grid/header/Button.scss +10 -4
- package/resources/scss/theme-light/apps/agentos/InterventionPanel.scss +6 -0
- package/resources/scss/theme-light/apps/agentos/Viewport.scss +24 -0
- package/resources/scss/theme-light/grid/header/Button.scss +10 -4
- package/resources/scss/theme-neo-light/apps/agentos/InterventionPanel.scss +6 -0
- package/resources/scss/theme-neo-light/apps/agentos/Viewport.scss +24 -0
- package/resources/scss/theme-neo-light/grid/header/Button.scss +10 -4
- package/src/DefaultConfig.mjs +11 -2
- package/src/ai/Client.mjs +160 -0
- package/src/component/Base.mjs +1 -1
- package/src/dashboard/Container.mjs +6 -0
- package/src/data/connection/WebSocket.mjs +5 -3
- package/src/draggable/dashboard/SortZone.mjs +10 -3
- package/src/worker/App.mjs +1 -0
- package/test/playwright/ai/neural-link.spec.mjs +52 -0
- package/.github/.sync-metadata.json +0 -12579
package/.gemini/settings.json
CHANGED
package/.github/VISION.md
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
Our vision is to build the platform for the next generation of web applications, **democratizing development** by making
|
|
4
4
|
elite performance and architectural patterns accessible to all. We are building towards a future where the distinction
|
|
5
|
-
between web and native applications disappears, and where the **interface for Humans and the interface for Agents are one and the same.**
|
|
5
|
+
between web and native applications disappears, and where the **interface for Humans and the interface for Agents are one and the same.** This convergence empowers not just developers, but **every user** to reshape their software tools to fit their needs, simply by asking.
|
|
6
6
|
|
|
7
7
|
This vision stands on four core pillars:
|
|
8
8
|
|
|
@@ -35,8 +35,7 @@ This principle radically reduces complexity and enables a cohesive ecosystem of
|
|
|
35
35
|
We are building the first platform architected for true AI collaboration. Our goal is to use AI as the great equalizer,
|
|
36
36
|
breaking down the barriers to contributing to and using a sophisticated framework. This is achieved through **Context Engineering**: building an AI-native ecosystem where the agent possesses **persistent memory** of past interactions and **deep semantic knowledge** of the codebase. This allows the AI to explain complex source code, guide new developers, and make meaningful contributions on its own. **Our architecture is inherently AI-native because it is built on a JSON Blueprint.** Instead of JSX, we use a clean, serializable structure for defining component trees and
|
|
37
37
|
the VDOM itself. This makes the entire application legible and manipulable in the native language of Large Language Models
|
|
38
|
-
(LLMs)
|
|
39
|
-
true architectural partner. **The end game is a development team where the AI is a proactive senior partner, mentoring
|
|
38
|
+
(LLMs). This allows an AI to not just write code, but to **orchestrate the application at runtime**—injecting entire component trees or modifying state on the fly without a reload. **The end game is a development team where the AI is a proactive senior partner, mentoring
|
|
40
39
|
developers and automating entire verticals of the workflow.**
|
|
41
40
|
|
|
42
41
|
### 4. The Agent Operating System (The Corporate HQ for AI)
|
|
@@ -49,6 +48,7 @@ a native Neo.mjs interface. This is our "Killer App":
|
|
|
49
48
|
- **The "Headless" Workforce:** We are moving beyond black-box CLI wrappers. We provide a native **Headless Agent SDK** that spawns
|
|
50
49
|
lightweight Node.js processes. These agents act as specialized employees—Strategic "CEOs" defining Epics, Tactical "PMs" breaking them down into tickets,
|
|
51
50
|
and Execution "Drones" submitting PRs—communicating asynchronously via a **Ticket-Driven Protocol**.
|
|
51
|
+
- **The "Neural Link" (Runtime Orchestration):** We are bridging the gap between the Agent (Node.js) and the App (Browser). Agents can connect to running applications to inspect state, **diagnose errors**, recover crashed components, or evolve the UI in real-time based on user voice commands ("Self-Evolving Apps").
|
|
52
52
|
- **The Feedback Loop:** Because the Command Center is built with Neo.mjs, and the Agents write Neo.mjs, the platform
|
|
53
53
|
is recursive. Agents can improve their own control interface, creating a self-reinforcing cycle of improvement.
|
|
54
54
|
**The end game is a new paradigm where you are not just a coder, but the Architect and CEO of an intelligent, automated software organization, managing it through a powerful, spatial interface built on the very technology you are deploying.**
|
package/ROADMAP.md
CHANGED
|
@@ -48,15 +48,18 @@ We will build the **Neo Command Center** (`apps/agent-os`), a desktop-class UI t
|
|
|
48
48
|
* **Human-in-the-Loop:** A "Plan Verification" mode where Strategic Agents propose a plan in the UI, and the human Chairman approves it before execution proceeds.
|
|
49
49
|
* **Competitive Edge:** This leverages Neo.mjs's unique multi-window and shared-worker capabilities to provide an interface that single-tab competitors cannot match.
|
|
50
50
|
|
|
51
|
-
### Phase 4: The
|
|
51
|
+
### Phase 4: The Self-Evolving App Platform (Runtime Orchestration) - **[ACTIVE RESEARCH]**
|
|
52
52
|
|
|
53
|
-
**Goal:**
|
|
53
|
+
**Goal:** Enable "Self-Healing" and "Self-Evolving" applications where AI Agents act as runtime operators.
|
|
54
54
|
|
|
55
|
-
|
|
55
|
+
We will evolve the **Neural Link** into a bidirectional bridge that allows Agents to not just write code, but **drive** the application at runtime:
|
|
56
56
|
|
|
57
|
-
* **
|
|
58
|
-
* **
|
|
59
|
-
* **
|
|
57
|
+
* **Runtime Blueprints:** Agents can inject entire component trees (via JSON Blueprints) into running applications without a reload.
|
|
58
|
+
* **Automated Diagnostics (Dev):** Agents capture multi-thread error context to auto-generate bug reports or PRs.
|
|
59
|
+
* **State Recovery (User):** Agents detect crashes or silent failures (e.g., "dead clicks") and intervene to reset component state or guide the user.
|
|
60
|
+
* **Live Customization:** Non-technical users can verbally instruct Agents to modify the UI layout or behavior on the fly (e.g., "Move the chart to the right").
|
|
61
|
+
* **Persistence Layer:** Agent-driven changes are stored (e.g., in `localStorage` or a remote user profile), allowing runtime customizations to survive page reloads and become permanent user preferences.
|
|
62
|
+
* **Technical Spec:** See [.github/AGENT_ARCHITECTURE.md](.github/AGENT_ARCHITECTURE.md) for the detailed technical specification.
|
|
60
63
|
|
|
61
64
|
### Phase 5: Decoupling the Ecosystem (Future)
|
|
62
65
|
|
package/ServiceWorker.mjs
CHANGED
package/ai/demo-agents/dev.mjs
CHANGED
|
@@ -11,15 +11,16 @@
|
|
|
11
11
|
* node ai/agents/dev.mjs --issue <number>
|
|
12
12
|
*/
|
|
13
13
|
|
|
14
|
-
import {
|
|
15
|
-
import fs
|
|
16
|
-
import path
|
|
17
|
-
import {
|
|
18
|
-
import yaml
|
|
19
|
-
import dotenv
|
|
20
|
-
import {
|
|
21
|
-
import {
|
|
22
|
-
import {
|
|
14
|
+
import {Command} from 'commander';
|
|
15
|
+
import fs from 'fs-extra';
|
|
16
|
+
import path from 'path';
|
|
17
|
+
import {fileURLToPath} from 'url';
|
|
18
|
+
import yaml from 'js-yaml';
|
|
19
|
+
import dotenv from 'dotenv';
|
|
20
|
+
import {exec} from 'child_process';
|
|
21
|
+
import {promisify} from 'util';
|
|
22
|
+
import {GoogleGenerativeAI, SchemaType} from '@google/generative-ai';
|
|
23
|
+
import {sanitizeInput} from '../../buildScripts/util/Sanitizer.mjs';
|
|
23
24
|
|
|
24
25
|
import {
|
|
25
26
|
GH_LocalFileService,
|
|
@@ -56,7 +57,7 @@ const program = new Command();
|
|
|
56
57
|
program
|
|
57
58
|
.name('dev-agent')
|
|
58
59
|
.description('Autonomous Developer Agent -> Ticket to PR')
|
|
59
|
-
.requiredOption('-i, --issue <number>', 'Issue Number to process')
|
|
60
|
+
.requiredOption('-i, --issue <number>', 'Issue Number to process', sanitizeInput)
|
|
60
61
|
.option('-d, --dry-run', 'Simulate execution without pushing/PR')
|
|
61
62
|
.parse(process.argv);
|
|
62
63
|
|
|
@@ -76,14 +77,14 @@ async function runGit(command) {
|
|
|
76
77
|
function parseIssueContent(rawContent) {
|
|
77
78
|
const parts = rawContent.split('---');
|
|
78
79
|
if (parts.length < 3) return { title: 'Unknown', body: rawContent };
|
|
79
|
-
|
|
80
|
+
|
|
80
81
|
const frontmatter = parts[1];
|
|
81
82
|
const body = parts.slice(2).join('---').trim();
|
|
82
|
-
|
|
83
|
+
|
|
83
84
|
let title = 'Unknown';
|
|
84
85
|
const titleMatch = frontmatter.match(/^title:\s*(.*)$/m);
|
|
85
86
|
if (titleMatch) title = titleMatch[1].trim().replace(/^['"](.*)['"]$/, '$1');
|
|
86
|
-
|
|
87
|
+
|
|
87
88
|
return { title, body };
|
|
88
89
|
}
|
|
89
90
|
|
|
@@ -107,7 +108,7 @@ async function parseYamlBody(body) {
|
|
|
107
108
|
|
|
108
109
|
async function generateCode(rawIssueContent, task, contextFiles, kbContext) {
|
|
109
110
|
console.log('🧠 Dev Agent is thinking...');
|
|
110
|
-
|
|
111
|
+
|
|
111
112
|
const genAI = new GoogleGenerativeAI(process.env.GEMINI_API_KEY);
|
|
112
113
|
const model = genAI.getGenerativeModel({
|
|
113
114
|
model: MODEL_NAME,
|
|
@@ -169,7 +170,7 @@ async function run() {
|
|
|
169
170
|
// 2. Fetch Issue (Local)
|
|
170
171
|
const issueId = String(options.issue);
|
|
171
172
|
console.log(`📥 Fetching Issue #${issueId}...`);
|
|
172
|
-
|
|
173
|
+
|
|
173
174
|
const issueFile = await GH_LocalFileService.getIssueById(issueId);
|
|
174
175
|
if (issueFile.error) throw new Error(`Issue #${issueId} not found locally.`);
|
|
175
176
|
|
|
@@ -240,17 +241,17 @@ async function run() {
|
|
|
240
241
|
console.log('📦 Committing changes...');
|
|
241
242
|
await runGit('git add .');
|
|
242
243
|
await runGit(`git commit -m "feat: ${title}"`);
|
|
243
|
-
|
|
244
|
+
|
|
244
245
|
console.log('⬆️ Pushing branch...');
|
|
245
246
|
// Construct authenticated URL for push
|
|
246
247
|
// Format: https://x-access-token:<TOKEN>@github.com/owner/repo.git
|
|
247
248
|
let remoteUrl = await runGit('git remote get-url origin');
|
|
248
|
-
|
|
249
|
+
|
|
249
250
|
// Strip existing auth if present (e.g. https://user:pass@...) and ensure .git suffix
|
|
250
251
|
remoteUrl = remoteUrl.replace(/^https?:\/\/([^@]*@)?/, 'https://');
|
|
251
|
-
|
|
252
|
+
|
|
252
253
|
const authenticatedUrl = remoteUrl.replace('https://', `https://x-access-token:${process.env.GH_TOKEN}@`);
|
|
253
|
-
|
|
254
|
+
|
|
254
255
|
await runGit(`git push -u "${authenticatedUrl}" ${branchName}`);
|
|
255
256
|
|
|
256
257
|
console.log('🔀 Creating Pull Request...');
|
package/ai/demo-agents/pm.mjs
CHANGED
|
@@ -11,11 +11,12 @@
|
|
|
11
11
|
* node ai/agents/pm.mjs --epic <issue_number>
|
|
12
12
|
*/
|
|
13
13
|
|
|
14
|
-
import {
|
|
15
|
-
import yaml
|
|
16
|
-
import dotenv
|
|
17
|
-
import path
|
|
18
|
-
import {
|
|
14
|
+
import {Command} from 'commander';
|
|
15
|
+
import yaml from 'js-yaml';
|
|
16
|
+
import dotenv from 'dotenv';
|
|
17
|
+
import path from 'path';
|
|
18
|
+
import {fileURLToPath} from 'url';
|
|
19
|
+
import {sanitizeInput} from '../../buildScripts/util/Sanitizer.mjs';
|
|
19
20
|
import {
|
|
20
21
|
GH_IssueService,
|
|
21
22
|
GH_HealthService,
|
|
@@ -32,7 +33,7 @@ const program = new Command();
|
|
|
32
33
|
program
|
|
33
34
|
.name('pm-agent')
|
|
34
35
|
.description('Autonomous PM Agent for breaking down Epics into Tickets')
|
|
35
|
-
.requiredOption('-e, --epic <number>', 'Epic Issue Number to process')
|
|
36
|
+
.requiredOption('-e, --epic <number>', 'Epic Issue Number to process', sanitizeInput)
|
|
36
37
|
.option('-d, --dry-run', 'Simulate execution without creating issues')
|
|
37
38
|
.parse(process.argv);
|
|
38
39
|
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
import { AppWorker_BridgeService } from '../services.mjs';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Test script for the App Worker MCP Server.
|
|
5
|
+
* Verifies that the Node.js agent can talk to the browser app.
|
|
6
|
+
*/
|
|
7
|
+
async function main() {
|
|
8
|
+
console.log('🧪 Testing App Worker Neural Link...');
|
|
9
|
+
|
|
10
|
+
// 1. Start the Bridge
|
|
11
|
+
console.log('[1] Starting Bridge Service...');
|
|
12
|
+
// Accessing the singleton instance starts the server
|
|
13
|
+
const bridge = AppWorker_BridgeService;
|
|
14
|
+
|
|
15
|
+
// Wait a moment for server to bind
|
|
16
|
+
await new Promise(resolve => setTimeout(resolve, 1000));
|
|
17
|
+
|
|
18
|
+
const status = bridge.getStatus();
|
|
19
|
+
console.log(` ✅ Bridge listening on port ${bridge.port}`);
|
|
20
|
+
console.log(` Clients connected: ${status.connectedClients}`);
|
|
21
|
+
|
|
22
|
+
if (status.connectedClients === 0) {
|
|
23
|
+
console.log(' ⚠️ No App Worker connected yet. Please reload the browser window.');
|
|
24
|
+
console.log(' Waiting for connection...');
|
|
25
|
+
|
|
26
|
+
// Poll for connection
|
|
27
|
+
let retries = 30;
|
|
28
|
+
while (retries > 0) {
|
|
29
|
+
await new Promise(resolve => setTimeout(resolve, 1000));
|
|
30
|
+
if (bridge.getStatus().connectedClients > 0) break;
|
|
31
|
+
process.stdout.write('.');
|
|
32
|
+
retries--;
|
|
33
|
+
}
|
|
34
|
+
console.log('');
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
if (bridge.getStatus().connectedClients === 0) {
|
|
38
|
+
console.error('❌ Timeout: App Worker did not connect.');
|
|
39
|
+
process.exit(1);
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
console.log(' ✅ App Worker Connected!');
|
|
43
|
+
|
|
44
|
+
// 2. Send Remote Command
|
|
45
|
+
console.log('[2] Sending Remote Command (createNeoInstance)...');
|
|
46
|
+
|
|
47
|
+
try {
|
|
48
|
+
const result = await bridge.evaluate({
|
|
49
|
+
method: 'Neo.worker.App.createNeoInstance',
|
|
50
|
+
params: [{
|
|
51
|
+
ntype: 'button',
|
|
52
|
+
text: 'Hello from Node.js!',
|
|
53
|
+
iconCls: 'fa fa-robot',
|
|
54
|
+
style: {
|
|
55
|
+
position: 'absolute',
|
|
56
|
+
top: '20px',
|
|
57
|
+
right: '20px',
|
|
58
|
+
zIndex: 1000
|
|
59
|
+
}
|
|
60
|
+
}]
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
console.log(' ✅ Command Sent. Result:', result);
|
|
64
|
+
console.log(' (Check browser to see the new button!)');
|
|
65
|
+
|
|
66
|
+
} catch (error) {
|
|
67
|
+
console.error(' ❌ Command Failed:', error);
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
// Keep process alive briefly to ensure message flush
|
|
71
|
+
setTimeout(() => process.exit(0), 1000);
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
main();
|
|
@@ -16,17 +16,18 @@ import * as core from '../../../src/core/_export.mjs'; // For Neo.core.B
|
|
|
16
16
|
import InstanceManager from '../../../src/manager/Instance.mjs'; // For Neo.core.Base setup
|
|
17
17
|
import Client from './Client.mjs';
|
|
18
18
|
import aiConfig from './config.mjs';
|
|
19
|
+
import {sanitizeInput} from '../../../buildScripts/util/Sanitizer.mjs';
|
|
19
20
|
|
|
20
21
|
const program = new Command();
|
|
21
22
|
|
|
22
23
|
program
|
|
23
24
|
.name('mcp-client')
|
|
24
25
|
.description('CLI for interacting with MCP servers')
|
|
25
|
-
.option('-s, --server <name>', 'Logical name of the MCP server to connect to (e.g., github-workflow)')
|
|
26
|
+
.option('-s, --server <name>', 'Logical name of the MCP server to connect to (e.g., github-workflow)', sanitizeInput)
|
|
26
27
|
.option('-l, --list-tools', 'List available tools on the specified server')
|
|
27
|
-
.option('-c, --config <path>', 'Path to an external client configuration file')
|
|
28
|
-
.option('-t, --call-tool <toolName>', 'Name of the tool to call')
|
|
29
|
-
.option('-a, --args <json>', 'JSON string of arguments for --call-tool', '{}')
|
|
28
|
+
.option('-c, --config <path>', 'Path to an external client configuration file', sanitizeInput)
|
|
29
|
+
.option('-t, --call-tool <toolName>', 'Name of the tool to call', sanitizeInput)
|
|
30
|
+
.option('-a, --args <json>', 'JSON string of arguments for --call-tool', '{}', sanitizeInput)
|
|
30
31
|
.option('-d, --debug', 'Enable debug logging');
|
|
31
32
|
|
|
32
33
|
program.parse(process.argv);
|
|
@@ -1,7 +1,13 @@
|
|
|
1
|
-
import fs
|
|
1
|
+
import fs from 'fs/promises';
|
|
2
2
|
import path from 'path';
|
|
3
|
+
import { fileURLToPath } from 'url';
|
|
3
4
|
import Base from '../../../../src/core/Base.mjs';
|
|
4
5
|
|
|
6
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
7
|
+
const __dirname = path.dirname(__filename);
|
|
8
|
+
const packageRoot = path.resolve(__dirname, '../../../../');
|
|
9
|
+
const projectRoot = process.cwd() === '/' ? packageRoot : process.cwd();
|
|
10
|
+
|
|
5
11
|
/**
|
|
6
12
|
* Default configuration object.
|
|
7
13
|
* Defines the structure and default values for the server configuration.
|
|
@@ -48,17 +54,17 @@ const defaultConfig = {
|
|
|
48
54
|
* The path to the directory for active issues.
|
|
49
55
|
* @type {string}
|
|
50
56
|
*/
|
|
51
|
-
issuesDir: path.resolve(
|
|
57
|
+
issuesDir: path.resolve(projectRoot, '.github', 'ISSUE'),
|
|
52
58
|
/**
|
|
53
59
|
* The path to the directory for archived issues.
|
|
54
60
|
* @type {string}
|
|
55
61
|
*/
|
|
56
|
-
archiveDir: path.resolve(
|
|
62
|
+
archiveDir: path.resolve(projectRoot, '.github', 'ISSUE_ARCHIVE'),
|
|
57
63
|
/**
|
|
58
64
|
* The path to the synchronization metadata file.
|
|
59
65
|
* @type {string}
|
|
60
66
|
*/
|
|
61
|
-
metadataFile: path.resolve(
|
|
67
|
+
metadataFile: path.resolve(projectRoot, '.github', '.sync-metadata.json'),
|
|
62
68
|
/**
|
|
63
69
|
* Labels that, when present on an issue, will cause it to be ignored and deleted locally.
|
|
64
70
|
* @type {string[]}
|
|
@@ -73,7 +79,7 @@ const defaultConfig = {
|
|
|
73
79
|
* The path to the directory for release notes.
|
|
74
80
|
* @type {string}
|
|
75
81
|
*/
|
|
76
|
-
releaseNotesDir: path.resolve(
|
|
82
|
+
releaseNotesDir: path.resolve(projectRoot, '.github', 'RELEASE_NOTES'),
|
|
77
83
|
/**
|
|
78
84
|
* The default version directory to use for archiving issues when no release is found.
|
|
79
85
|
* @type {string}
|
|
@@ -233,15 +239,15 @@ class Config extends Base {
|
|
|
233
239
|
|
|
234
240
|
try {
|
|
235
241
|
const absolutePath = path.resolve(filePath);
|
|
236
|
-
const ext
|
|
237
|
-
let
|
|
242
|
+
const ext = path.extname(absolutePath);
|
|
243
|
+
let customConfig;
|
|
238
244
|
|
|
239
245
|
if (ext === '.mjs' || ext === '.js') {
|
|
240
246
|
const module = await import(absolutePath);
|
|
241
247
|
customConfig = module.default;
|
|
242
248
|
} else {
|
|
243
249
|
const content = await fs.readFile(absolutePath, 'utf-8');
|
|
244
|
-
customConfig
|
|
250
|
+
customConfig = JSON.parse(content);
|
|
245
251
|
}
|
|
246
252
|
|
|
247
253
|
// Deep merge custom config into the data object
|
|
@@ -5,13 +5,14 @@ import InstanceManager from '../../../../src/manager/Instance.mjs';
|
|
|
5
5
|
import aiConfig from './config.mjs';
|
|
6
6
|
import logger from './logger.mjs';
|
|
7
7
|
import Server from './Server.mjs';
|
|
8
|
+
import {sanitizeInput} from '../../../../buildScripts/util/Sanitizer.mjs';
|
|
8
9
|
|
|
9
10
|
const program = new Command();
|
|
10
11
|
|
|
11
12
|
program
|
|
12
13
|
.name('neo-github-workflow-mcp')
|
|
13
14
|
.description('Neo.mjs GitHub Workflow MCP Server')
|
|
14
|
-
.option('-c, --config <path>', 'Path to the configuration file')
|
|
15
|
+
.option('-c, --config <path>', 'Path to the configuration file', sanitizeInput)
|
|
15
16
|
.option('-d, --debug', 'Enable debug logging')
|
|
16
17
|
.parse(process.argv);
|
|
17
18
|
|
|
@@ -1,10 +1,8 @@
|
|
|
1
|
-
import fs
|
|
2
|
-
import path
|
|
3
|
-
import
|
|
4
|
-
import Base from '../../../../src/core/Base.mjs';
|
|
1
|
+
import fs from 'fs/promises';
|
|
2
|
+
import path from 'path';
|
|
3
|
+
import Base from '../../../../src/core/Base.mjs';
|
|
5
4
|
|
|
6
|
-
const
|
|
7
|
-
const __dirname = path.dirname(__filename);
|
|
5
|
+
const cwd = process.cwd();
|
|
8
6
|
|
|
9
7
|
/**
|
|
10
8
|
* Default configuration object.
|
|
@@ -28,13 +26,13 @@ const defaultConfig = {
|
|
|
28
26
|
* @returns {Object} The dummy embedding function satisfying IEmbeddingFunction
|
|
29
27
|
*/
|
|
30
28
|
dummyEmbeddingFunction: {
|
|
31
|
-
generate: () => null,
|
|
32
|
-
name: 'dummy_embedding_function',
|
|
33
|
-
getConfig: () => ({}),
|
|
29
|
+
generate : () => null,
|
|
30
|
+
name : 'dummy_embedding_function',
|
|
31
|
+
getConfig : () => ({}),
|
|
34
32
|
constructor: {
|
|
35
33
|
buildFromConfig: () => ({
|
|
36
|
-
generate: () => null,
|
|
37
|
-
name: 'dummy_embedding_function',
|
|
34
|
+
generate : () => null,
|
|
35
|
+
name : 'dummy_embedding_function',
|
|
38
36
|
getConfig: () => ({})
|
|
39
37
|
})
|
|
40
38
|
}
|
|
@@ -53,12 +51,12 @@ const defaultConfig = {
|
|
|
53
51
|
* The local persistence path for the agent knowledge-base server.
|
|
54
52
|
* @type {string}
|
|
55
53
|
*/
|
|
56
|
-
path: path.resolve(
|
|
54
|
+
path: path.resolve(cwd, 'chroma-neo-knowledge-base'),
|
|
57
55
|
/**
|
|
58
56
|
* The path to the generated knowledge base JSONL file.
|
|
59
57
|
* @type {string}
|
|
60
58
|
*/
|
|
61
|
-
dataPath: path.resolve(
|
|
59
|
+
dataPath: path.resolve(cwd, 'dist/ai-knowledge-base.jsonl'),
|
|
62
60
|
/**
|
|
63
61
|
* The name of the ChromaDB collection for the knowledge base.
|
|
64
62
|
* @type {string}
|
|
@@ -5,13 +5,14 @@ import InstanceManager from '../../../../src/manager/Instance.mjs';
|
|
|
5
5
|
import aiConfig from './config.mjs';
|
|
6
6
|
import logger from './logger.mjs';
|
|
7
7
|
import Server from './Server.mjs';
|
|
8
|
+
import {sanitizeInput} from '../../../../buildScripts/util/Sanitizer.mjs';
|
|
8
9
|
|
|
9
10
|
const program = new Command();
|
|
10
11
|
|
|
11
12
|
program
|
|
12
13
|
.name('neo-knowledge-base-mcp')
|
|
13
14
|
.description('Neo.mjs Knowledge Base MCP Server')
|
|
14
|
-
.option('-c, --config <path>', 'Path to the configuration file')
|
|
15
|
+
.option('-c, --config <path>', 'Path to the configuration file', sanitizeInput)
|
|
15
16
|
.option('-d, --debug', 'Enable debug logging')
|
|
16
17
|
.parse(process.argv);
|
|
17
18
|
|
|
@@ -1,10 +1,8 @@
|
|
|
1
|
-
import fs
|
|
2
|
-
import path
|
|
3
|
-
import
|
|
4
|
-
import Base from '../../../../src/core/Base.mjs';
|
|
1
|
+
import fs from 'fs/promises';
|
|
2
|
+
import path from 'path';
|
|
3
|
+
import Base from '../../../../src/core/Base.mjs';
|
|
5
4
|
|
|
6
|
-
const
|
|
7
|
-
const __dirname = path.dirname(__filename);
|
|
5
|
+
const cwd = process.cwd();
|
|
8
6
|
|
|
9
7
|
/**
|
|
10
8
|
* Default configuration object.
|
|
@@ -28,13 +26,13 @@ const defaultConfig = {
|
|
|
28
26
|
* @returns {Object} The dummy embedding function satisfying IEmbeddingFunction
|
|
29
27
|
*/
|
|
30
28
|
dummyEmbeddingFunction: {
|
|
31
|
-
generate: () => null,
|
|
32
|
-
name: 'dummy_embedding_function',
|
|
33
|
-
getConfig: () => ({}),
|
|
29
|
+
generate : () => null,
|
|
30
|
+
name : 'dummy_embedding_function',
|
|
31
|
+
getConfig : () => ({}),
|
|
34
32
|
constructor: {
|
|
35
33
|
buildFromConfig: () => ({
|
|
36
|
-
generate: () => null,
|
|
37
|
-
name: 'dummy_embedding_function',
|
|
34
|
+
generate : () => null,
|
|
35
|
+
name : 'dummy_embedding_function',
|
|
38
36
|
getConfig: () => ({})
|
|
39
37
|
})
|
|
40
38
|
}
|
|
@@ -78,12 +76,12 @@ const defaultConfig = {
|
|
|
78
76
|
* The local persistence path for the agent memory server.
|
|
79
77
|
* @type {string}
|
|
80
78
|
*/
|
|
81
|
-
path: path.resolve(
|
|
79
|
+
path: path.resolve(cwd, 'chroma-neo-memory-core'),
|
|
82
80
|
/**
|
|
83
81
|
* The path to store memory backups.
|
|
84
82
|
* @type {string}
|
|
85
83
|
*/
|
|
86
|
-
backupPath: path.resolve(
|
|
84
|
+
backupPath: path.resolve(cwd, 'dist/memory-backups')
|
|
87
85
|
},
|
|
88
86
|
/**
|
|
89
87
|
* Configuration for the AI agent's session summary database.
|
|
@@ -108,7 +106,7 @@ const defaultConfig = {
|
|
|
108
106
|
* The path to store session summary backups.
|
|
109
107
|
* @type {string}
|
|
110
108
|
*/
|
|
111
|
-
backupPath: path.resolve(
|
|
109
|
+
backupPath: path.resolve(cwd, 'dist/session-backups')
|
|
112
110
|
}
|
|
113
111
|
};
|
|
114
112
|
|
|
@@ -5,13 +5,14 @@ import InstanceManager from '../../../../src/manager/Instance.mjs';
|
|
|
5
5
|
import aiConfig from './config.mjs';
|
|
6
6
|
import logger from './logger.mjs';
|
|
7
7
|
import Server from './Server.mjs';
|
|
8
|
+
import {sanitizeInput} from '../../../../buildScripts/util/Sanitizer.mjs';
|
|
8
9
|
|
|
9
10
|
const program = new Command();
|
|
10
11
|
|
|
11
12
|
program
|
|
12
13
|
.name('neo-memory-core-mcp')
|
|
13
14
|
.description('Neo.mjs Memory Core MCP Server')
|
|
14
|
-
.option('-c, --config <path>', 'Path to the configuration file')
|
|
15
|
+
.option('-c, --config <path>', 'Path to the configuration file', sanitizeInput)
|
|
15
16
|
.option('-d, --debug', 'Enable debug logging')
|
|
16
17
|
.parse(process.argv);
|
|
17
18
|
|
|
@@ -2,7 +2,6 @@ import aiConfig from '../config.mjs';
|
|
|
2
2
|
import Base from '../../../../../src/core/Base.mjs';
|
|
3
3
|
import ChromaManager from './ChromaManager.mjs';
|
|
4
4
|
import DatabaseLifecycleService from './DatabaseLifecycleService.mjs';
|
|
5
|
-
import SessionService from './SessionService.mjs';
|
|
6
5
|
import logger from '../logger.mjs';
|
|
7
6
|
|
|
8
7
|
/**
|
|
@@ -208,7 +207,7 @@ class HealthService extends Base {
|
|
|
208
207
|
status : 'healthy',
|
|
209
208
|
timestamp: new Date().toISOString(),
|
|
210
209
|
session : {
|
|
211
|
-
currentId: SessionService
|
|
210
|
+
currentId: Neo.ns('Neo.ai.mcp.server.memory-core.services.SessionService', false)?.currentSessionId
|
|
212
211
|
},
|
|
213
212
|
database : {
|
|
214
213
|
process: DatabaseLifecycleService.getDatabaseStatus(),
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import {GoogleGenerativeAI} from '@google/generative-ai';
|
|
2
2
|
import aiConfig from '../config.mjs';
|
|
3
3
|
import Base from '../../../../../src/core/Base.mjs';
|
|
4
|
+
import logger from '../logger.mjs';
|
|
4
5
|
|
|
5
6
|
/**
|
|
6
7
|
* @summary Service for creating embedding vectors for text.
|
|
@@ -42,10 +43,8 @@ class TextEmbeddingService extends Base {
|
|
|
42
43
|
const apiKey = process.env.GEMINI_API_KEY;
|
|
43
44
|
|
|
44
45
|
if (!apiKey) {
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
error.code = 'missing_gemini_api_key';
|
|
48
|
-
throw error;
|
|
46
|
+
logger.warn('⚠️ [TextEmbeddingService] GEMINI_API_KEY not set. Semantic search features will be unavailable.');
|
|
47
|
+
return;
|
|
49
48
|
}
|
|
50
49
|
|
|
51
50
|
const genAI = new GoogleGenerativeAI(apiKey);
|
|
@@ -58,6 +57,10 @@ class TextEmbeddingService extends Base {
|
|
|
58
57
|
* @returns {Promise<number[]>}
|
|
59
58
|
*/
|
|
60
59
|
async embedText(text) {
|
|
60
|
+
if (!process.env.GEMINI_API_KEY) {
|
|
61
|
+
throw new Error('Semantic search unavailable: GEMINI_API_KEY is missing.');
|
|
62
|
+
}
|
|
63
|
+
|
|
61
64
|
const result = await this.embeddingModel.embedContent(text);
|
|
62
65
|
return result.embedding.values;
|
|
63
66
|
}
|