neuralos 3.3.8 → 3.3.9
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.
|
Binary file
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "neuralos",
|
|
3
|
-
"version": "3.3.
|
|
3
|
+
"version": "3.3.9",
|
|
4
4
|
"description": "AI-native terminal & agentic-AI operations platform for Forward Deployed Engineers & SREs: AIOps closed-loop remediation, AI SRE, self-healing infrastructure, runbook automation, ChatOps; executes over SSH/WinRM/serial under policy with tamper-evident audit.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"forward-deployed-engineer",
|
|
@@ -1,12 +1,16 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* monid-bridge — thin wrapper around the official Monid CLI.
|
|
2
|
+
* monid-bridge — thin wrapper around the official Monid CLI (v0.1.6).
|
|
3
3
|
*
|
|
4
|
-
* Settings → Plugins → Monid (settings.monid):
|
|
5
|
-
*
|
|
6
|
-
* The API key is NEVER stored in settings.json. Saving a key in the UI runs
|
|
7
|
-
* `monid keys add -k <key> -l <label>` (see applyMonidApiKey).
|
|
4
|
+
* Settings → Plugins → Monid (settings.monid): enabled, binaryPath, keyLabel
|
|
5
|
+
* API key is NEVER stored in settings.json (`monid keys add -k … -l …`).
|
|
8
6
|
*
|
|
9
|
-
* Agent tools: monid_health, monid_discover, monid_run.
|
|
7
|
+
* Agent tools: monid_health, monid_discover, monid_inspect, monid_run.
|
|
8
|
+
*
|
|
9
|
+
* Argv MUST match `monid <cmd> --help`:
|
|
10
|
+
* discover --query <q> [--limit n] [--min-score s] --json
|
|
11
|
+
* inspect --provider <p> --endpoint <e> --json
|
|
12
|
+
* run --provider <p> --endpoint <e> [--input json] [--query json] [--path json] --json
|
|
13
|
+
* Bare `discover <query>` / `run <tool>` are false positives (CLI rejects them).
|
|
10
14
|
*/
|
|
11
15
|
|
|
12
16
|
import { createRequire } from 'node:module'
|
|
@@ -23,25 +27,80 @@ export function resolveConfig(ctx = {}, env = process.env) {
|
|
|
23
27
|
}
|
|
24
28
|
}
|
|
25
29
|
|
|
26
|
-
|
|
30
|
+
function reqStr(v, name) {
|
|
31
|
+
const s = String(v ?? '').trim()
|
|
32
|
+
if (!s) throw new Error(`${name} is required`)
|
|
33
|
+
return s
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
function optJsonFlag(argv, flag, value) {
|
|
37
|
+
if (value == null) return
|
|
38
|
+
const s = typeof value === 'string' ? value.trim() : JSON.stringify(value)
|
|
39
|
+
if (!s) return
|
|
40
|
+
argv.push(flag, s)
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
function optNumFlag(argv, flag, value) {
|
|
44
|
+
if (value == null || value === '') return
|
|
45
|
+
const n = Number(value)
|
|
46
|
+
if (!Number.isFinite(n)) throw new Error(`${flag} must be a number`)
|
|
47
|
+
argv.push(flag, String(n))
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* Build argv AFTER the binary name.
|
|
52
|
+
* Always pass --json so agents get structured output (no ANSI).
|
|
53
|
+
*/
|
|
27
54
|
export function buildMonidArgv(sub, params = {}) {
|
|
28
55
|
switch (sub) {
|
|
29
56
|
case 'version':
|
|
30
57
|
return ['--version']
|
|
31
58
|
case 'keys-list':
|
|
32
59
|
return ['keys', 'list']
|
|
60
|
+
case 'whoami':
|
|
61
|
+
return ['whoami']
|
|
33
62
|
case 'discover': {
|
|
34
|
-
const q =
|
|
35
|
-
|
|
36
|
-
|
|
63
|
+
const q = reqStr(params.query, 'query')
|
|
64
|
+
const argv = ['discover', '--query', q]
|
|
65
|
+
optNumFlag(argv, '--limit', params.limit)
|
|
66
|
+
optNumFlag(argv, '--min-score', params.minScore ?? params['min-score'])
|
|
67
|
+
argv.push('--json')
|
|
68
|
+
return argv
|
|
69
|
+
}
|
|
70
|
+
case 'inspect': {
|
|
71
|
+
const provider = reqStr(params.provider, 'provider')
|
|
72
|
+
const endpoint = reqStr(params.endpoint, 'endpoint')
|
|
73
|
+
return ['inspect', '--provider', provider, '--endpoint', endpoint, '--json']
|
|
37
74
|
}
|
|
38
75
|
case 'run': {
|
|
76
|
+
// FN: agents may pass tool="provider/endpoint" from older docs.
|
|
77
|
+
let provider = String(params.provider || '').trim()
|
|
78
|
+
let endpoint = String(params.endpoint || '').trim()
|
|
39
79
|
const tool = String(params.tool || '').trim()
|
|
40
|
-
if (!
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
80
|
+
if ((!provider || !endpoint) && tool) {
|
|
81
|
+
const slash = tool.indexOf('/')
|
|
82
|
+
if (slash > 0) {
|
|
83
|
+
provider = provider || tool.slice(0, slash)
|
|
84
|
+
endpoint = endpoint || tool.slice(slash)
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
if (!provider) throw new Error('monid_run needs provider (slug from discover)')
|
|
88
|
+
if (!endpoint) throw new Error('monid_run needs endpoint (path from discover, e.g. /news/search)')
|
|
89
|
+
if (!endpoint.startsWith('/')) {
|
|
90
|
+
throw new Error('endpoint must start with / (Monid endpoint path, not a free-form tool name)')
|
|
91
|
+
}
|
|
92
|
+
const argv = ['run', '--provider', provider, '--endpoint', endpoint]
|
|
93
|
+
const input = params.input ?? params.body
|
|
94
|
+
if (input != null && String(input).trim()) {
|
|
95
|
+
argv.push('--input', typeof input === 'string' ? input : JSON.stringify(input))
|
|
44
96
|
}
|
|
97
|
+
optJsonFlag(argv, '--query', params.queryParams ?? params.query)
|
|
98
|
+
optJsonFlag(argv, '--path', params.pathParams ?? params.path)
|
|
99
|
+
if (params.wait != null && params.wait !== false && params.wait !== '') {
|
|
100
|
+
argv.push('--wait')
|
|
101
|
+
if (params.wait !== true) argv.push(String(params.wait))
|
|
102
|
+
}
|
|
103
|
+
argv.push('--json')
|
|
45
104
|
return argv
|
|
46
105
|
}
|
|
47
106
|
default:
|
|
@@ -49,21 +108,30 @@ export function buildMonidArgv(sub, params = {}) {
|
|
|
49
108
|
}
|
|
50
109
|
}
|
|
51
110
|
|
|
111
|
+
/** True if argv looks like the broken 3.3.8 shapes (for tests / guards). */
|
|
112
|
+
export function isLegacyBrokenArgv(argv) {
|
|
113
|
+
if (!Array.isArray(argv) || argv.length < 2) return false
|
|
114
|
+
if (argv[0] === 'discover' && argv[1] !== '--query' && !argv[1].startsWith('-')) return true
|
|
115
|
+
if (argv[0] === 'run' && argv[1] !== '--provider' && !String(argv[1]).startsWith('-')) return true
|
|
116
|
+
return false
|
|
117
|
+
}
|
|
118
|
+
|
|
52
119
|
async function runMonid(ctx, cfg, argv) {
|
|
120
|
+
const env = { ...process.env, NO_COLOR: '1' }
|
|
53
121
|
if (typeof ctx.runCommand === 'function') {
|
|
54
|
-
const cmdline = [cfg.binaryPath, ...argv].map((a) => (/\s/.test(a) ?
|
|
55
|
-
return ctx.runCommand({ command: cmdline })
|
|
122
|
+
const cmdline = [cfg.binaryPath, ...argv].map((a) => (/\s/.test(a) ? JSON.stringify(a) : a)).join(' ')
|
|
123
|
+
return ctx.runCommand({ command: cmdline, env })
|
|
56
124
|
}
|
|
57
125
|
if (typeof ctx.exec === 'function') {
|
|
58
|
-
const cmdline = [cfg.binaryPath, ...argv].map((a) => (/\s/.test(a) ?
|
|
59
|
-
return ctx.exec(cmdline)
|
|
126
|
+
const cmdline = [cfg.binaryPath, ...argv].map((a) => (/\s/.test(a) ? JSON.stringify(a) : a)).join(' ')
|
|
127
|
+
return ctx.exec(cmdline, { env })
|
|
60
128
|
}
|
|
61
129
|
const { execFile } = require('node:child_process')
|
|
62
130
|
return new Promise((resolve) => {
|
|
63
|
-
execFile(cfg.binaryPath, argv, { timeout: 120000, env
|
|
131
|
+
execFile(cfg.binaryPath, argv, { timeout: 120000, env }, (err, stdout, stderr) => {
|
|
64
132
|
resolve({
|
|
65
133
|
ok: !err,
|
|
66
|
-
exitCode: err?.code
|
|
134
|
+
exitCode: typeof err?.code === 'number' ? err.code : err ? 1 : 0,
|
|
67
135
|
stdout: String(stdout ?? ''),
|
|
68
136
|
stderr: String(stderr ?? ''),
|
|
69
137
|
error: err ? String(err.message) : undefined,
|
|
@@ -80,7 +148,7 @@ async function guarded(fn, log) {
|
|
|
80
148
|
log?.(`[monid] ${msg}`)
|
|
81
149
|
return {
|
|
82
150
|
error: msg,
|
|
83
|
-
hint: 'Install @monid-ai/cli (`npm i -g @monid-ai/cli`) and paste an API key in Settings → Plugins → Monid
|
|
151
|
+
hint: 'Install @monid-ai/cli (`npm i -g @monid-ai/cli`) and paste an API key in Settings → Plugins → Monid. discover needs --query; run needs --provider and --endpoint.',
|
|
84
152
|
}
|
|
85
153
|
}
|
|
86
154
|
}
|
|
@@ -101,15 +169,19 @@ export function register(ctx) {
|
|
|
101
169
|
guarded(async () => {
|
|
102
170
|
const ver = await runMonid(ctx, cfg, buildMonidArgv('version'))
|
|
103
171
|
const keys = await runMonid(ctx, cfg, buildMonidArgv('keys-list'))
|
|
104
|
-
|
|
172
|
+
const who = await runMonid(ctx, cfg, buildMonidArgv('whoami'))
|
|
173
|
+
return { binaryPath: cfg.binaryPath, keyLabel: cfg.keyLabel, version: ver, keys, whoami: who }
|
|
105
174
|
}, log),
|
|
106
175
|
})
|
|
107
176
|
|
|
108
177
|
registerTool({
|
|
109
178
|
name: 'monid_discover',
|
|
110
|
-
description:
|
|
179
|
+
description:
|
|
180
|
+
'Search Monid data endpoints with natural language (company news, people, enrichment). Uses `monid discover --query`. Do not pass a bare positional query.',
|
|
111
181
|
params: {
|
|
112
|
-
query: { type: 'string', description: '
|
|
182
|
+
query: { type: 'string', description: 'Natural-language search (required)' },
|
|
183
|
+
limit: { type: 'number', description: 'Max results (max 50)', optional: true },
|
|
184
|
+
minScore: { type: 'number', description: 'Minimum relevance score', optional: true },
|
|
113
185
|
},
|
|
114
186
|
handler: async (p) =>
|
|
115
187
|
guarded(async () => {
|
|
@@ -119,12 +191,32 @@ export function register(ctx) {
|
|
|
119
191
|
}, log),
|
|
120
192
|
})
|
|
121
193
|
|
|
194
|
+
registerTool({
|
|
195
|
+
name: 'monid_inspect',
|
|
196
|
+
description: 'Get full details for one Monid endpoint (`monid inspect --provider --endpoint`).',
|
|
197
|
+
params: {
|
|
198
|
+
provider: { type: 'string', description: 'Provider slug (e.g. context.dev)' },
|
|
199
|
+
endpoint: { type: 'string', description: 'Endpoint path (e.g. /news/search)' },
|
|
200
|
+
},
|
|
201
|
+
handler: async (p) =>
|
|
202
|
+
guarded(async () => {
|
|
203
|
+
const argv = buildMonidArgv('inspect', p)
|
|
204
|
+
const r = await runMonid(ctx, cfg, argv)
|
|
205
|
+
return { argv: [cfg.binaryPath, ...argv], ...r }
|
|
206
|
+
}, log),
|
|
207
|
+
})
|
|
208
|
+
|
|
122
209
|
registerTool({
|
|
123
210
|
name: 'monid_run',
|
|
124
|
-
description:
|
|
211
|
+
description:
|
|
212
|
+
'Execute a Monid endpoint (`monid run --provider --endpoint`). provider+endpoint from discover; optional JSON --input / --query / --path. Not `monid run <toolName>`.',
|
|
125
213
|
params: {
|
|
126
|
-
|
|
127
|
-
|
|
214
|
+
provider: { type: 'string', description: 'Provider slug', optional: true },
|
|
215
|
+
endpoint: { type: 'string', description: 'Endpoint path starting with /', optional: true },
|
|
216
|
+
tool: { type: 'string', description: 'Optional shorthand provider/endpoint', optional: true },
|
|
217
|
+
input: { type: 'string', description: 'Body JSON string', optional: true },
|
|
218
|
+
queryParams: { type: 'string', description: 'Query-parameters JSON string', optional: true },
|
|
219
|
+
pathParams: { type: 'string', description: 'Path-parameters JSON string', optional: true },
|
|
128
220
|
},
|
|
129
221
|
handler: async (p) =>
|
|
130
222
|
guarded(async () => {
|
|
@@ -1,27 +1,75 @@
|
|
|
1
|
-
import { buildMonidArgv, resolveConfig } from './index.mjs'
|
|
1
|
+
import { buildMonidArgv, isLegacyBrokenArgv, resolveConfig } from './index.mjs'
|
|
2
2
|
|
|
3
3
|
const assert = (c, m) => {
|
|
4
4
|
if (!c) throw new Error(`assert failed: ${m}`)
|
|
5
5
|
}
|
|
6
6
|
|
|
7
|
+
// --- config ---
|
|
7
8
|
assert(resolveConfig({ settings: {} }).enabled === true, 'enabled default')
|
|
8
9
|
assert(resolveConfig({ settings: { monid: { enabled: false } } }).enabled === false, 'disabled')
|
|
9
10
|
assert(resolveConfig({ settings: { monid: { binaryPath: '/opt/monid' } } }).binaryPath === '/opt/monid', 'bin')
|
|
10
11
|
assert(resolveConfig({}, { MONID_BIN: 'custom-monid' }).binaryPath === 'custom-monid', 'env bin')
|
|
11
12
|
|
|
13
|
+
// --- FP: 3.3.8 positional argv must be detected as broken ---
|
|
14
|
+
assert(isLegacyBrokenArgv(['discover', 'company news']) === true, 'FP discover positional')
|
|
15
|
+
assert(isLegacyBrokenArgv(['run', 'foo']) === true, 'FP run positional')
|
|
16
|
+
assert(isLegacyBrokenArgv(['discover', '--query', 'company news']) === false, 'good discover')
|
|
17
|
+
assert(isLegacyBrokenArgv(['run', '--provider', 'x', '--endpoint', '/y']) === false, 'good run')
|
|
18
|
+
|
|
19
|
+
const disc = buildMonidArgv('discover', { query: 'company news', limit: 5 })
|
|
20
|
+
assert(!isLegacyBrokenArgv(disc), 'new discover not legacy')
|
|
21
|
+
assert(disc[0] === 'discover' && disc[1] === '--query' && disc[2] === 'company news', `disc=${disc}`)
|
|
22
|
+
assert(disc.includes('--limit') && disc.includes('5') && disc.includes('--json'), 'limit+json')
|
|
23
|
+
|
|
12
24
|
assert(buildMonidArgv('version').join(' ') === '--version', 'version')
|
|
13
25
|
assert(buildMonidArgv('keys-list').join(' ') === 'keys list', 'keys list')
|
|
14
|
-
assert(buildMonidArgv('
|
|
15
|
-
|
|
26
|
+
assert(buildMonidArgv('whoami').join(' ') === 'whoami', 'whoami')
|
|
27
|
+
|
|
28
|
+
const insp = buildMonidArgv('inspect', { provider: 'context.dev', endpoint: '/news/search' })
|
|
29
|
+
assert(insp.join(' ') === 'inspect --provider context.dev --endpoint /news/search --json', insp.join(' '))
|
|
30
|
+
|
|
31
|
+
const run = buildMonidArgv('run', {
|
|
32
|
+
provider: 'context.dev',
|
|
33
|
+
endpoint: '/news/search',
|
|
34
|
+
input: '{"q":"acme"}',
|
|
35
|
+
})
|
|
36
|
+
assert(run[0] === 'run' && run.includes('--provider') && run.includes('context.dev'), 'run provider')
|
|
37
|
+
assert(run.includes('--endpoint') && run.includes('/news/search'), 'run endpoint')
|
|
38
|
+
assert(run.includes('--input') && run.includes('--json'), 'run input+json')
|
|
39
|
+
assert(!isLegacyBrokenArgv(run), 'new run not legacy')
|
|
40
|
+
|
|
41
|
+
// FN: tool="provider/endpoint" shorthand
|
|
42
|
+
const fromTool = buildMonidArgv('run', { tool: 'apollo/mixed_companies/search' })
|
|
43
|
+
assert(fromTool.includes('apollo') && fromTool.includes('/mixed_companies/search'), `fromTool=${fromTool}`)
|
|
16
44
|
|
|
45
|
+
// FN: queryParams / pathParams
|
|
46
|
+
const withQP = buildMonidArgv('run', {
|
|
47
|
+
provider: 'akta',
|
|
48
|
+
endpoint: '/v1/news',
|
|
49
|
+
queryParams: '{"q":"x"}',
|
|
50
|
+
pathParams: '{"id":"1"}',
|
|
51
|
+
})
|
|
52
|
+
assert(withQP.includes('--query') && withQP.includes('{"q":"x"}'), 'query flag')
|
|
53
|
+
assert(withQP.includes('--path') && withQP.includes('{"id":"1"}'), 'path flag')
|
|
54
|
+
|
|
55
|
+
// rejects
|
|
17
56
|
let threw = false
|
|
18
|
-
try { buildMonidArgv('discover', { query: '' }) } catch { threw = true }
|
|
19
|
-
assert(threw, '
|
|
57
|
+
try { buildMonidArgv('discover', { query: ' ' }) } catch { threw = true }
|
|
58
|
+
assert(threw, 'empty query')
|
|
59
|
+
threw = false
|
|
60
|
+
try { buildMonidArgv('run', { tool: 'not-a-path' }) } catch { threw = true }
|
|
61
|
+
assert(threw, 'run without provider/endpoint')
|
|
20
62
|
threw = false
|
|
21
|
-
try { buildMonidArgv('run', {}) } catch { threw = true }
|
|
22
|
-
assert(threw, '
|
|
63
|
+
try { buildMonidArgv('run', { provider: 'x', endpoint: 'news' }) } catch { threw = true }
|
|
64
|
+
assert(threw, 'endpoint must start with /')
|
|
65
|
+
threw = false
|
|
66
|
+
try { buildMonidArgv('inspect', { provider: 'x' }) } catch { threw = true }
|
|
67
|
+
assert(threw, 'inspect needs endpoint')
|
|
23
68
|
threw = false
|
|
24
69
|
try { buildMonidArgv('nope') } catch { threw = true }
|
|
25
70
|
assert(threw, 'unknown sub')
|
|
71
|
+
threw = false
|
|
72
|
+
try { buildMonidArgv('discover', { query: 'q', limit: 'nope' }) } catch { threw = true }
|
|
73
|
+
assert(threw, 'bad limit')
|
|
26
74
|
|
|
27
75
|
console.log('monid-bridge: all cases passed')
|