@scramble-cloud/lurus-code-cli 2.4.6 → 2.5.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/dist/bundled-skills.json +1 -1
- package/dist/cli.js +628 -621
- package/dist/mcp-schema-worker.cjs +162 -0
- package/package.json +6 -2
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
const { parentPort, workerData } = require('node:worker_threads');
|
|
2
|
+
const Ajv = require('ajv');
|
|
3
|
+
const Ajv2020 = require('ajv/dist/2020');
|
|
4
|
+
const addFormats = require('ajv-formats');
|
|
5
|
+
|
|
6
|
+
function checkReferences(schema) {
|
|
7
|
+
const pending = [schema];
|
|
8
|
+
const edges = new Map();
|
|
9
|
+
const anchors = new Map();
|
|
10
|
+
const references = [];
|
|
11
|
+
while (pending.length) {
|
|
12
|
+
const current = pending.pop();
|
|
13
|
+
if (typeof current === 'boolean') continue;
|
|
14
|
+
if (!current || typeof current !== 'object' || Array.isArray(current))
|
|
15
|
+
throw new Error('schema');
|
|
16
|
+
const children = [];
|
|
17
|
+
for (const keyword of ['$anchor', '$dynamicAnchor']) {
|
|
18
|
+
if (typeof current[keyword] !== 'string') continue;
|
|
19
|
+
if (
|
|
20
|
+
anchors.has(current[keyword]) &&
|
|
21
|
+
anchors.get(current[keyword]) !== current
|
|
22
|
+
)
|
|
23
|
+
throw new Error('anchor');
|
|
24
|
+
anchors.set(current[keyword], current);
|
|
25
|
+
}
|
|
26
|
+
for (const keyword of ['$ref', '$dynamicRef', '$recursiveRef']) {
|
|
27
|
+
if (current[keyword] === undefined) continue;
|
|
28
|
+
if (
|
|
29
|
+
typeof current[keyword] !== 'string' ||
|
|
30
|
+
!current[keyword].startsWith('#')
|
|
31
|
+
)
|
|
32
|
+
throw new Error('reference');
|
|
33
|
+
references.push([current, current[keyword]]);
|
|
34
|
+
}
|
|
35
|
+
if (current.$async !== undefined || current.$data !== undefined)
|
|
36
|
+
throw new Error('dynamic schema');
|
|
37
|
+
if (current !== schema && current.$id !== undefined)
|
|
38
|
+
throw new Error('nested resource');
|
|
39
|
+
for (const keyword of [
|
|
40
|
+
'properties',
|
|
41
|
+
'patternProperties',
|
|
42
|
+
'$defs',
|
|
43
|
+
'definitions',
|
|
44
|
+
'dependentSchemas',
|
|
45
|
+
]) {
|
|
46
|
+
if (current[keyword] && typeof current[keyword] === 'object')
|
|
47
|
+
children.push(...Object.values(current[keyword]));
|
|
48
|
+
}
|
|
49
|
+
if (current.dependencies && typeof current.dependencies === 'object') {
|
|
50
|
+
for (const child of Object.values(current.dependencies))
|
|
51
|
+
if (!Array.isArray(child)) children.push(child);
|
|
52
|
+
}
|
|
53
|
+
for (const keyword of ['allOf', 'anyOf', 'oneOf', 'prefixItems']) {
|
|
54
|
+
if (Array.isArray(current[keyword])) children.push(...current[keyword]);
|
|
55
|
+
}
|
|
56
|
+
for (const keyword of [
|
|
57
|
+
'items',
|
|
58
|
+
'additionalItems',
|
|
59
|
+
'additionalProperties',
|
|
60
|
+
'unevaluatedProperties',
|
|
61
|
+
'unevaluatedItems',
|
|
62
|
+
'contains',
|
|
63
|
+
'propertyNames',
|
|
64
|
+
'not',
|
|
65
|
+
'if',
|
|
66
|
+
'then',
|
|
67
|
+
'else',
|
|
68
|
+
]) {
|
|
69
|
+
if (Array.isArray(current[keyword])) children.push(...current[keyword]);
|
|
70
|
+
else if (current[keyword] !== undefined) children.push(current[keyword]);
|
|
71
|
+
}
|
|
72
|
+
edges.set(
|
|
73
|
+
current,
|
|
74
|
+
children.filter((child) => typeof child !== 'boolean'),
|
|
75
|
+
);
|
|
76
|
+
pending.push(...children);
|
|
77
|
+
}
|
|
78
|
+
for (const [current, reference] of references) {
|
|
79
|
+
const fragment = decodeURIComponent(reference.slice(1));
|
|
80
|
+
let target = schema;
|
|
81
|
+
if (fragment && !fragment.startsWith('/')) target = anchors.get(fragment);
|
|
82
|
+
else if (fragment) {
|
|
83
|
+
for (const token of fragment.slice(1).split('/')) {
|
|
84
|
+
const key = token.replace(/~1/g, '/').replace(/~0/g, '~');
|
|
85
|
+
if (
|
|
86
|
+
!target ||
|
|
87
|
+
typeof target !== 'object' ||
|
|
88
|
+
!Object.hasOwn(target, key)
|
|
89
|
+
)
|
|
90
|
+
throw new Error('reference');
|
|
91
|
+
target = target[key];
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
if (typeof target === 'boolean') continue;
|
|
95
|
+
if (!edges.has(target)) throw new Error('reference');
|
|
96
|
+
edges.get(current).push(target);
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
try {
|
|
101
|
+
const schema = JSON.parse(workerData.schemaJson);
|
|
102
|
+
const values = [schema];
|
|
103
|
+
while (values.length) {
|
|
104
|
+
const value = values.pop();
|
|
105
|
+
if (!value || typeof value !== 'object') continue;
|
|
106
|
+
if (Object.hasOwn(value, '$data')) throw new Error('data reference');
|
|
107
|
+
values.push(...Object.values(value));
|
|
108
|
+
}
|
|
109
|
+
const dialect = schema.$schema;
|
|
110
|
+
const draft07 =
|
|
111
|
+
dialect === 'http://json-schema.org/draft-07/schema#' ||
|
|
112
|
+
dialect === 'https://json-schema.org/draft-07/schema';
|
|
113
|
+
if (
|
|
114
|
+
dialect !== undefined &&
|
|
115
|
+
!draft07 &&
|
|
116
|
+
dialect !== 'https://json-schema.org/draft/2020-12/schema'
|
|
117
|
+
) {
|
|
118
|
+
parentPort.postMessage({ status: 'unsupported-schema' });
|
|
119
|
+
} else {
|
|
120
|
+
checkReferences(schema);
|
|
121
|
+
const Validator = draft07 ? Ajv : Ajv2020;
|
|
122
|
+
const ajv = new Validator({
|
|
123
|
+
strictSchema: false,
|
|
124
|
+
strictTypes: false,
|
|
125
|
+
strictTuples: false,
|
|
126
|
+
strictNumbers: true,
|
|
127
|
+
validateSchema: true,
|
|
128
|
+
allErrors: false,
|
|
129
|
+
removeAdditional: false,
|
|
130
|
+
useDefaults: false,
|
|
131
|
+
coerceTypes: false,
|
|
132
|
+
ownProperties: true,
|
|
133
|
+
inlineRefs: false,
|
|
134
|
+
loopRequired: 50,
|
|
135
|
+
loopEnum: 50,
|
|
136
|
+
code: { optimize: false },
|
|
137
|
+
logger: false,
|
|
138
|
+
});
|
|
139
|
+
if (!draft07) ajv.addKeyword({ keyword: '$anchor', schemaType: 'string' });
|
|
140
|
+
addFormats(ajv);
|
|
141
|
+
if (typeof schema.$anchor === 'string') {
|
|
142
|
+
const pending = [schema];
|
|
143
|
+
while (pending.length) {
|
|
144
|
+
const current = pending.pop();
|
|
145
|
+
if (!current || typeof current !== 'object') continue;
|
|
146
|
+
if (current.$ref === `#${schema.$anchor}`) current.$ref = '#';
|
|
147
|
+
pending.push(...Object.values(current));
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
const validate = ajv.compile(schema);
|
|
151
|
+
if (workerData.argumentsJson === undefined)
|
|
152
|
+
parentPort.postMessage({ status: 'valid' });
|
|
153
|
+
else {
|
|
154
|
+
const input = JSON.parse(workerData.argumentsJson);
|
|
155
|
+
parentPort.postMessage({
|
|
156
|
+
status: validate(input) === true ? 'valid' : 'invalid-arguments',
|
|
157
|
+
});
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
} catch {
|
|
161
|
+
parentPort.postMessage({ status: 'invalid-schema' });
|
|
162
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@scramble-cloud/lurus-code-cli",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.5.0",
|
|
4
4
|
"description": "Lurus Code — Agentic Coding CLI",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"lurus",
|
|
@@ -65,11 +65,14 @@
|
|
|
65
65
|
"prettier": "prettier --write",
|
|
66
66
|
"test": "vitest run",
|
|
67
67
|
"verify": "npm run lint && npm run lint:rules && npm test",
|
|
68
|
-
"test:watch": "vitest"
|
|
68
|
+
"test:watch": "vitest",
|
|
69
|
+
"benchmark:context-reuse": "tsx scripts/context-reuse-benchmark.ts"
|
|
69
70
|
},
|
|
70
71
|
"dependencies": {
|
|
71
72
|
"@modelcontextprotocol/sdk": "^1.27.1",
|
|
72
73
|
"@vscode/ripgrep": "1.18.0",
|
|
74
|
+
"ajv": "8.18.0",
|
|
75
|
+
"ajv-formats": "3.0.1",
|
|
73
76
|
"commander": "^14.0.3",
|
|
74
77
|
"ignore": "^7.0.5",
|
|
75
78
|
"ink": "^6.8.0",
|
|
@@ -99,6 +102,7 @@
|
|
|
99
102
|
"eslint-config-prettier": "^10.1.8",
|
|
100
103
|
"eslint-plugin-prettier": "^5.5.5",
|
|
101
104
|
"globals": "^17.4.0",
|
|
105
|
+
"javascript-obfuscator": "^5.4.1",
|
|
102
106
|
"prettier": "^3.8.1",
|
|
103
107
|
"tslib": "^2.8.1",
|
|
104
108
|
"tsx": "^4.21.0",
|