@ornexus/neocortex 4.60.44 → 4.60.46
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/dist/sbom.cdx.json +23 -23
- package/install.js +16 -1
- package/install.ps1 +57 -401
- package/install.sh +30 -37
- package/package.json +2 -2
- package/packages/client/dist/commands/invoke.d.ts +9 -0
- package/packages/client/dist/commands/invoke.js +50 -47
- package/packages/client/dist/runner/headless/run-yolo.js +1 -1
- package/packages/client/dist/runner/headless/run-yoloop.d.ts +9 -0
- package/packages/client/dist/runner/headless/run-yoloop.js +2 -2
- package/packages/client/dist/state/project-state-snapshot.js +1 -1
- package/packages/client/dist/yoloop/index.d.ts +1 -1
- package/packages/client/dist/yoloop/invoke-hooks.d.ts +23 -6
- package/packages/client/dist/yoloop/invoke-hooks.js +11 -8
- package/packages/client/dist/yoloop/shared-yoloop-types.d.ts +61 -0
- package/packages/client/dist/yoloop/yoloop-client-state-store.d.ts +23 -0
- package/packages/client/dist/yoloop/yoloop-client-state-store.js +1 -1
- package/packages/shared/dist/invocation/index.js +9 -2
- package/targets-stubs/antigravity/gemini.md +1 -1
- package/targets-stubs/antigravity/install-antigravity.sh +10 -101
- package/targets-stubs/antigravity/skill/SKILL.md +1 -1
- package/targets-stubs/claude-code/neocortex-root.agent.yaml +1 -1
- package/targets-stubs/claude-code/neocortex-root.md +2 -2
- package/targets-stubs/claude-code/neocortex.agent.yaml +1 -1
- package/targets-stubs/claude-code/neocortex.md +2 -2
- package/targets-stubs/codex/AGENTS.md +1 -1
- package/targets-stubs/codex/install-codex.sh +4 -1
- package/targets-stubs/cursor/agent.md +2 -2
- package/targets-stubs/cursor/install-cursor.sh +4 -1
- package/targets-stubs/gemini-cli/agent.md +2 -2
- package/targets-stubs/gemini-cli/install-gemini.sh +4 -1
- package/targets-stubs/grok/install-grok.sh +4 -1
- package/targets-stubs/lib/mcp-merge.js +220 -20
- package/targets-stubs/opencode/neocortex-root.md +1 -1
- package/targets-stubs/vscode/install-vscode.sh +4 -1
- package/targets-stubs/vscode/neocortex.agent.md +2 -2
|
@@ -6,6 +6,7 @@
|
|
|
6
6
|
|
|
7
7
|
const fs = require('fs');
|
|
8
8
|
const path = require('path');
|
|
9
|
+
const crypto = require('crypto');
|
|
9
10
|
|
|
10
11
|
const MANAGED_SERVERS = [
|
|
11
12
|
'playwright',
|
|
@@ -51,16 +52,168 @@ function stableJson(value) {
|
|
|
51
52
|
return `${JSON.stringify(value, null, 2)}\n`;
|
|
52
53
|
}
|
|
53
54
|
|
|
54
|
-
function
|
|
55
|
+
function ownershipPath(destFile) {
|
|
56
|
+
return `${destFile}.neocortex-ownership.json`;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
function atomicWrite(file, content) {
|
|
60
|
+
ensureDir(file);
|
|
61
|
+
const temporary = `${file}.tmp.${process.pid}.${crypto.randomBytes(6).toString('hex')}`;
|
|
62
|
+
let fd;
|
|
63
|
+
try {
|
|
64
|
+
fd = fs.openSync(temporary, 'wx', 0o600);
|
|
65
|
+
fs.writeFileSync(fd, content, 'utf8');
|
|
66
|
+
fs.fsyncSync(fd);
|
|
67
|
+
} finally {
|
|
68
|
+
if (fd !== undefined) fs.closeSync(fd);
|
|
69
|
+
}
|
|
70
|
+
try {
|
|
71
|
+
fs.renameSync(temporary, file);
|
|
72
|
+
try {
|
|
73
|
+
const dirFd = fs.openSync(path.dirname(file), 'r');
|
|
74
|
+
try { fs.fsyncSync(dirFd); } finally { fs.closeSync(dirFd); }
|
|
75
|
+
} catch { /* directory fsync is unavailable on some Windows filesystems */ }
|
|
76
|
+
} catch (error) {
|
|
77
|
+
try { fs.unlinkSync(temporary); } catch { /* best effort */ }
|
|
78
|
+
throw error;
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
function canonicalUrl(raw) {
|
|
83
|
+
if (typeof raw !== 'string' || raw.trim() === '') return null;
|
|
84
|
+
try {
|
|
85
|
+
const parsed = new URL(raw.trim());
|
|
86
|
+
parsed.protocol = parsed.protocol.toLowerCase();
|
|
87
|
+
parsed.hostname = parsed.hostname.toLowerCase();
|
|
88
|
+
parsed.hash = '';
|
|
89
|
+
if (parsed.pathname.length > 1) parsed.pathname = parsed.pathname.replace(/\/+$/, '');
|
|
90
|
+
return parsed.toString();
|
|
91
|
+
} catch { return null; }
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
function canonicalCommand(raw) {
|
|
95
|
+
const tokens = Array.isArray(raw) ? raw : [raw];
|
|
96
|
+
if (tokens.some((token) => typeof token !== 'string' || token.trim() === '')) return null;
|
|
97
|
+
return tokens.map((token, index) => {
|
|
98
|
+
const trimmed = token.trim();
|
|
99
|
+
if (index > 0) return trimmed;
|
|
100
|
+
const basename = trimmed.replace(/\\/g, '/').split('/').pop().toLowerCase();
|
|
101
|
+
return basename.replace(/\.(?:cmd|exe|bat)$/i, '');
|
|
102
|
+
});
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
function canonicalArgs(raw) {
|
|
106
|
+
if (raw === undefined) return [];
|
|
107
|
+
if (!Array.isArray(raw)
|
|
108
|
+
|| raw.some((token) => typeof token !== 'string' || token.trim() === '')) return null;
|
|
109
|
+
return raw.map((token) => token.trim());
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
function semanticIdentity(entry) {
|
|
113
|
+
if (!entry || typeof entry !== 'object' || Array.isArray(entry)) return null;
|
|
114
|
+
const remote = canonicalUrl(entry.url || entry.httpUrl || entry.serverUrl);
|
|
115
|
+
if (remote) return { transport: 'remote', url: remote };
|
|
116
|
+
const command = canonicalCommand(entry.command);
|
|
117
|
+
if (!command) return null;
|
|
118
|
+
const args = canonicalArgs(entry.args);
|
|
119
|
+
if (!args) return null;
|
|
120
|
+
return { transport: 'stdio', argv: [...command, ...args] };
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
function fingerprint(entry) {
|
|
124
|
+
const identity = semanticIdentity(entry);
|
|
125
|
+
return identity
|
|
126
|
+
? crypto.createHash('sha256').update(`neocortex-mcp-identity-v1\0${JSON.stringify(identity)}`).digest('hex')
|
|
127
|
+
: null;
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
function readOwnership(destFile, target, rootKey) {
|
|
131
|
+
const file = ownershipPath(destFile);
|
|
132
|
+
if (!fs.existsSync(file)) return { ok: true, file, value: { schemaVersion: 1, target, rootKey, entries: {} }, text: null };
|
|
133
|
+
try {
|
|
134
|
+
const text = fs.readFileSync(file, 'utf8');
|
|
135
|
+
const value = JSON.parse(text);
|
|
136
|
+
if (!value || value.schemaVersion !== 1 || typeof value.target !== 'string' || value.rootKey !== rootKey
|
|
137
|
+
|| !value.entries || typeof value.entries !== 'object' || Array.isArray(value.entries)) {
|
|
138
|
+
throw new Error('invalid ownership schema');
|
|
139
|
+
}
|
|
140
|
+
return { ok: true, file, value, text };
|
|
141
|
+
} catch (error) {
|
|
142
|
+
console.error(`[${target}] ERROR: MCP_OWNERSHIP_MANIFEST_INVALID (${error.message}); leaving config untouched.`);
|
|
143
|
+
return { ok: false, file };
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
function planSemanticMerge(existing, baseline, managed, ownership, target) {
|
|
148
|
+
const next = { ...existing };
|
|
149
|
+
const nextOwned = { ...ownership.entries };
|
|
150
|
+
const blockers = [];
|
|
151
|
+
let added = 0;
|
|
152
|
+
let updated = 0;
|
|
153
|
+
let deduplicated = 0;
|
|
154
|
+
|
|
155
|
+
for (const name of managed) {
|
|
156
|
+
const desired = baseline[name];
|
|
157
|
+
const desiredFingerprint = fingerprint(desired);
|
|
158
|
+
if (!desiredFingerprint) {
|
|
159
|
+
blockers.push(`MCP_BASELINE_IDENTITY_INVALID:${name}`);
|
|
160
|
+
continue;
|
|
161
|
+
}
|
|
162
|
+
const aliases = Object.entries(next)
|
|
163
|
+
.filter(([candidate]) => candidate !== name)
|
|
164
|
+
.filter(([, entry]) => fingerprint(entry) === desiredFingerprint)
|
|
165
|
+
.map(([candidate]) => candidate);
|
|
166
|
+
if (aliases.length > 1) {
|
|
167
|
+
blockers.push(`MCP_SEMANTIC_DUPLICATE_AMBIGUOUS:${name}:${aliases.sort().join(',')}`);
|
|
168
|
+
continue;
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
const current = next[name];
|
|
172
|
+
const currentFingerprint = fingerprint(current);
|
|
173
|
+
const ownedFingerprint = nextOwned[name] && nextOwned[name].fingerprint;
|
|
174
|
+
const currentlyOwned = typeof ownedFingerprint === 'string' && currentFingerprint === ownedFingerprint;
|
|
175
|
+
|
|
176
|
+
if (aliases.length === 1) {
|
|
177
|
+
if (currentlyOwned) {
|
|
178
|
+
delete next[name];
|
|
179
|
+
delete nextOwned[name];
|
|
180
|
+
deduplicated += 1;
|
|
181
|
+
}
|
|
182
|
+
// A user-owned semantic alias is authoritative. Never duplicate or claim it.
|
|
183
|
+
continue;
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
if (current !== undefined && !currentlyOwned && currentFingerprint !== desiredFingerprint) {
|
|
187
|
+
blockers.push(`MCP_UNOWNED_NAME_CONFLICT:${name}`);
|
|
188
|
+
continue;
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
if (current === undefined) added += 1;
|
|
192
|
+
else if (JSON.stringify(current) !== JSON.stringify(desired)) updated += 1;
|
|
193
|
+
next[name] = desired;
|
|
194
|
+
nextOwned[name] = { fingerprint: desiredFingerprint };
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
if (blockers.length) {
|
|
198
|
+
for (const reason of blockers) console.error(`[${target}] ERROR: ${reason}; leaving config untouched.`);
|
|
199
|
+
}
|
|
200
|
+
return { next, entries: nextOwned, blockers, added, updated, deduplicated };
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
function mergeJson(stubFile, destFile, rootKey, target, managedTopLevelCsv = '') {
|
|
55
204
|
const stubResult = readJson(stubFile, target);
|
|
56
205
|
if (!stubResult.ok) return 1;
|
|
57
206
|
const stub = stubResult.value;
|
|
58
207
|
const baseline = stub[rootKey] && typeof stub[rootKey] === 'object' ? stub[rootKey] : {};
|
|
59
208
|
const managed = MANAGED_SERVERS.filter((name) => Object.prototype.hasOwnProperty.call(baseline, name));
|
|
60
209
|
ensureDir(destFile);
|
|
210
|
+
const ownership = readOwnership(destFile, target, rootKey);
|
|
211
|
+
if (!ownership.ok) return 3;
|
|
61
212
|
|
|
62
213
|
if (!fs.existsSync(destFile)) {
|
|
63
|
-
|
|
214
|
+
const entries = Object.fromEntries(managed.map((name) => [name, { fingerprint: fingerprint(baseline[name]) }]));
|
|
215
|
+
atomicWrite(destFile, stableJson(stub));
|
|
216
|
+
atomicWrite(ownership.file, stableJson({ ...ownership.value, entries }));
|
|
64
217
|
console.log(`[${target}] Created MCP config: ${destFile} (added ${managed.length})`);
|
|
65
218
|
return 0;
|
|
66
219
|
}
|
|
@@ -74,22 +227,38 @@ function mergeJson(stubFile, destFile, rootKey, target) {
|
|
|
74
227
|
if (!existing[rootKey] || typeof existing[rootKey] !== 'object' || Array.isArray(existing[rootKey])) {
|
|
75
228
|
existing[rootKey] = {};
|
|
76
229
|
}
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
230
|
+
const migratedTopLevel = [];
|
|
231
|
+
for (const name of managedTopLevelCsv.split(',').map((entry) => entry.trim()).filter(Boolean)) {
|
|
232
|
+
if (!Object.prototype.hasOwnProperty.call(existing, name)) continue;
|
|
233
|
+
if (Object.prototype.hasOwnProperty.call(existing[rootKey], name)
|
|
234
|
+
&& fingerprint(existing[rootKey][name]) !== fingerprint(existing[name])) {
|
|
235
|
+
console.error(`[${target}] ERROR: MCP_LEGACY_SCOPE_CONFLICT:${name}; leaving config untouched.`);
|
|
236
|
+
return 3;
|
|
237
|
+
}
|
|
238
|
+
if (!Object.prototype.hasOwnProperty.call(existing[rootKey], name)) existing[rootKey][name] = existing[name];
|
|
239
|
+
migratedTopLevel.push(name);
|
|
84
240
|
}
|
|
85
241
|
|
|
242
|
+
const plan = planSemanticMerge(existing[rootKey], baseline, managed, ownership.value, target);
|
|
243
|
+
if (plan.blockers.length) return 3;
|
|
244
|
+
existing[rootKey] = plan.next;
|
|
245
|
+
for (const name of migratedTopLevel) delete existing[name];
|
|
246
|
+
|
|
86
247
|
const next = stableJson(existing);
|
|
248
|
+
const nextOwnership = stableJson({ ...ownership.value, entries: plan.entries });
|
|
87
249
|
if (next !== existingResult.text) {
|
|
88
|
-
|
|
89
|
-
|
|
250
|
+
if (migratedTopLevel.length > 0) {
|
|
251
|
+
const stamp = new Date().toISOString().replace(/[:.]/g, '-');
|
|
252
|
+
const structuralBackup = `${destFile}.neocortex-backup-structural-${stamp}`;
|
|
253
|
+
fs.copyFileSync(destFile, structuralBackup);
|
|
254
|
+
console.log(`[${target}] Legacy MCP scope migration backup created: ${structuralBackup}`);
|
|
255
|
+
}
|
|
256
|
+
atomicWrite(destFile, next);
|
|
257
|
+
console.log(`[${target}] Merged MCP config into: ${destFile} (added ${plan.added}, updated ${plan.updated}, deduplicated ${plan.deduplicated}, preserved user entries)`);
|
|
90
258
|
} else {
|
|
91
259
|
console.log(`[${target}] MCP config already up to date: ${destFile} (preserved user entries)`);
|
|
92
260
|
}
|
|
261
|
+
if (nextOwnership !== ownership.text) atomicWrite(ownership.file, nextOwnership);
|
|
93
262
|
return 0;
|
|
94
263
|
}
|
|
95
264
|
|
|
@@ -109,7 +278,7 @@ function splitManagedTomlSections(text) {
|
|
|
109
278
|
let currentName = null;
|
|
110
279
|
let current = [];
|
|
111
280
|
const flush = () => {
|
|
112
|
-
if (currentName
|
|
281
|
+
if (currentName) {
|
|
113
282
|
sections.set(currentName, current.join('\n').replace(/\s+$/, '') + '\n');
|
|
114
283
|
}
|
|
115
284
|
};
|
|
@@ -119,6 +288,10 @@ function splitManagedTomlSections(text) {
|
|
|
119
288
|
flush();
|
|
120
289
|
currentName = match[1];
|
|
121
290
|
current = [line];
|
|
291
|
+
} else if (/^\[[^\]]+\]$/.test(line)) {
|
|
292
|
+
flush();
|
|
293
|
+
currentName = null;
|
|
294
|
+
current = [];
|
|
122
295
|
} else if (currentName) {
|
|
123
296
|
current.push(line);
|
|
124
297
|
}
|
|
@@ -127,6 +300,14 @@ function splitManagedTomlSections(text) {
|
|
|
127
300
|
return sections;
|
|
128
301
|
}
|
|
129
302
|
|
|
303
|
+
function tomlEntry(section) {
|
|
304
|
+
const command = section.match(/^command\s*=\s*"([^"]+)"/m)?.[1];
|
|
305
|
+
const argsRaw = section.match(/^args\s*=\s*\[([^\]]*)\]/m)?.[1];
|
|
306
|
+
const args = argsRaw === undefined ? undefined : [...argsRaw.matchAll(/"((?:\\.|[^"])*)"/g)].map((match) => match[1].replace(/\\"/g, '"'));
|
|
307
|
+
const url = section.match(/^(?:url|http_url|server_url)\s*=\s*"([^"]+)"/m)?.[1];
|
|
308
|
+
return url ? { url } : { command, ...(args ? { args } : {}) };
|
|
309
|
+
}
|
|
310
|
+
|
|
130
311
|
function removeManagedTomlSections(text, managed) {
|
|
131
312
|
const lines = text.split(/\r?\n/);
|
|
132
313
|
const out = [];
|
|
@@ -146,11 +327,18 @@ function mergeToml(stubFile, destFile, target) {
|
|
|
146
327
|
if (stubInvalid) throw new Error(`invalid stub TOML: ${stubInvalid}`);
|
|
147
328
|
const stubSections = splitManagedTomlSections(stubText);
|
|
148
329
|
const managed = [...stubSections.keys()];
|
|
149
|
-
const
|
|
330
|
+
const baseline = Object.fromEntries(managed.map((name) => [name, tomlEntry(stubSections.get(name))]));
|
|
150
331
|
ensureDir(destFile);
|
|
332
|
+
const ownership = readOwnership(destFile, target, 'mcp_servers');
|
|
333
|
+
if (!ownership.ok) return 3;
|
|
151
334
|
|
|
152
335
|
if (!fs.existsSync(destFile)) {
|
|
153
|
-
|
|
336
|
+
const managedBlock = managed.map((name) => stubSections.get(name).trimEnd()).join('\n\n');
|
|
337
|
+
atomicWrite(destFile, `# Neocortex MCP Servers\n${managedBlock}\n`);
|
|
338
|
+
atomicWrite(ownership.file, stableJson({
|
|
339
|
+
...ownership.value,
|
|
340
|
+
entries: Object.fromEntries(managed.map((name) => [name, { fingerprint: fingerprint(baseline[name]) }])),
|
|
341
|
+
}));
|
|
154
342
|
console.log(`[${target}] Created MCP config: ${destFile} (added ${managed.length})`);
|
|
155
343
|
return 0;
|
|
156
344
|
}
|
|
@@ -162,23 +350,35 @@ function mergeToml(stubFile, destFile, target) {
|
|
|
162
350
|
return 0;
|
|
163
351
|
}
|
|
164
352
|
|
|
165
|
-
const
|
|
166
|
-
const
|
|
353
|
+
const existingSections = splitManagedTomlSections(existing);
|
|
354
|
+
const existingEntries = Object.fromEntries([...existingSections].map(([name, section]) => [name, tomlEntry(section)]));
|
|
355
|
+
const plan = planSemanticMerge(existingEntries, baseline, managed, ownership.value, target);
|
|
356
|
+
if (plan.blockers.length) return 3;
|
|
357
|
+
const namesToRemove = managed.filter((name) => !Object.prototype.hasOwnProperty.call(plan.next, name)
|
|
358
|
+
|| Object.prototype.hasOwnProperty.call(plan.entries, name));
|
|
359
|
+
const namesToAppend = managed.filter((name) => Object.prototype.hasOwnProperty.call(plan.entries, name));
|
|
360
|
+
const preserved = removeManagedTomlSections(existing, namesToRemove).replace(/\n*# Neocortex MCP Servers\s*\n*$/, '\n');
|
|
361
|
+
const managedBlock = namesToAppend.map((name) => stubSections.get(name).trimEnd()).join('\n\n');
|
|
362
|
+
const next = managedBlock
|
|
363
|
+
? `${preserved.trimEnd()}\n\n# Neocortex MCP Servers\n${managedBlock}\n`
|
|
364
|
+
: `${preserved.trimEnd()}\n`;
|
|
365
|
+
const nextOwnership = stableJson({ ...ownership.value, entries: plan.entries });
|
|
167
366
|
if (next !== existing) {
|
|
168
|
-
|
|
169
|
-
console.log(`[${target}] Merged MCP config into: ${destFile} (managed ${
|
|
367
|
+
atomicWrite(destFile, next);
|
|
368
|
+
console.log(`[${target}] Merged MCP config into: ${destFile} (managed ${namesToAppend.length}, deduplicated ${plan.deduplicated}, preserved unknown sections)`);
|
|
170
369
|
} else {
|
|
171
370
|
console.log(`[${target}] MCP config already up to date: ${destFile} (preserved unknown sections)`);
|
|
172
371
|
}
|
|
372
|
+
if (nextOwnership !== ownership.text) atomicWrite(ownership.file, nextOwnership);
|
|
173
373
|
return 0;
|
|
174
374
|
}
|
|
175
375
|
|
|
176
|
-
const [mode, stubFile, destFile, rootOrTarget, maybeTarget] = process.argv.slice(2);
|
|
376
|
+
const [mode, stubFile, destFile, rootOrTarget, maybeTarget, managedTopLevelCsv] = process.argv.slice(2);
|
|
177
377
|
if (!mode || !stubFile || !destFile) usage();
|
|
178
378
|
|
|
179
379
|
try {
|
|
180
380
|
const code = mode === 'json'
|
|
181
|
-
? mergeJson(stubFile, destFile, rootOrTarget, maybeTarget || 'MCP')
|
|
381
|
+
? mergeJson(stubFile, destFile, rootOrTarget, maybeTarget || 'MCP', managedTopLevelCsv)
|
|
182
382
|
: mode === 'toml'
|
|
183
383
|
? mergeToml(stubFile, destFile, rootOrTarget || 'MCP')
|
|
184
384
|
: (usage(), 64);
|
|
@@ -58,7 +58,7 @@ explicit server opt-in rather than a local assumption.
|
|
|
58
58
|
┌────────────────────────────────────────────────────────────┐
|
|
59
59
|
│ │
|
|
60
60
|
│ ####### N E O C O R T E X │
|
|
61
|
-
│ ### ######## v4.60.
|
|
61
|
+
│ ### ######## v4.60.46 │
|
|
62
62
|
│ ######### ##### │
|
|
63
63
|
│ ## ############## Development Orchestrator │
|
|
64
64
|
│ ## ### ###### ## OrNexus Team │
|
|
@@ -64,7 +64,10 @@ install_vscode() {
|
|
|
64
64
|
|
|
65
65
|
# 3. User-level additive merge MCP config
|
|
66
66
|
if [ -f "$vscode_target/mcp.json" ]; then
|
|
67
|
-
_merge_vscode_mcp "$vscode_target/mcp.json" "$(_vscode_user_mcp_path)" ||
|
|
67
|
+
_merge_vscode_mcp "$vscode_target/mcp.json" "$(_vscode_user_mcp_path)" || {
|
|
68
|
+
echo "[VSCODE] ERROR: MCP merge blocked; user config was preserved." >&2
|
|
69
|
+
return 1
|
|
70
|
+
}
|
|
68
71
|
fi
|
|
69
72
|
|
|
70
73
|
echo "[VSCODE] Thin-client installation complete!"
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: "neocortex"
|
|
3
|
-
description: "Neocortex v4.60.
|
|
3
|
+
description: "Neocortex v4.60.46 | OrNexus Team"
|
|
4
4
|
tools:
|
|
5
5
|
# Read / Edit (built-in tool sets)
|
|
6
6
|
- read
|
|
@@ -68,7 +68,7 @@ SEMPRE que este agente for invocado, imprima o banner abaixo como PRIMEIRO outpu
|
|
|
68
68
|
┌────────────────────────────────────────────────────────────┐
|
|
69
69
|
│ │
|
|
70
70
|
│ ####### N E O C O R T E X │
|
|
71
|
-
│ ### ######## v4.60.
|
|
71
|
+
│ ### ######## v4.60.46 │
|
|
72
72
|
│ ######### ##### │
|
|
73
73
|
│ ## ############## Development Orchestrator │
|
|
74
74
|
│ ## ### ###### ## OrNexus Team │
|