@alisio/core 0.8.0 → 0.10.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.
Files changed (58) hide show
  1. package/dist/analysis/data/engine-client.d.ts +2 -0
  2. package/dist/analysis/data/engine-client.js +11 -4
  3. package/dist/application.d.ts +11 -1
  4. package/dist/application.js +46 -0
  5. package/dist/changelog/data.js +42 -0
  6. package/dist/commands/builtins.js +6 -0
  7. package/dist/commands/catalog.d.ts +4 -2
  8. package/dist/commands/catalog.js +23 -1
  9. package/dist/config.d.ts +31 -0
  10. package/dist/config.js +31 -1
  11. package/dist/context/elide.d.ts +50 -0
  12. package/dist/context/elide.js +222 -0
  13. package/dist/context/format.d.ts +21 -0
  14. package/dist/context/format.js +81 -0
  15. package/dist/context/governance.d.ts +58 -0
  16. package/dist/context/governance.js +96 -0
  17. package/dist/context/invariants.d.ts +88 -0
  18. package/dist/context/invariants.js +141 -0
  19. package/dist/context/inventory.d.ts +22 -0
  20. package/dist/context/inventory.js +178 -0
  21. package/dist/context/report.d.ts +35 -0
  22. package/dist/context/report.js +120 -0
  23. package/dist/context/sources.d.ts +20 -0
  24. package/dist/context/sources.js +41 -0
  25. package/dist/context/types.d.ts +43 -0
  26. package/dist/context/types.js +5 -0
  27. package/dist/context/usage.d.ts +96 -0
  28. package/dist/context/usage.js +264 -0
  29. package/dist/context/util.d.ts +22 -0
  30. package/dist/context/util.js +36 -0
  31. package/dist/core/compaction.d.ts +7 -2
  32. package/dist/core/compaction.js +9 -3
  33. package/dist/core/contracts.d.ts +8 -0
  34. package/dist/core/runner.d.ts +67 -0
  35. package/dist/core/runner.js +272 -10
  36. package/dist/eval/compare.d.ts +1 -1
  37. package/dist/eval/compare.js +18 -1
  38. package/dist/eval/engine.js +31 -1
  39. package/dist/eval/report.js +44 -1
  40. package/dist/forge/javascript/hosts/process-host.d.ts +1 -1
  41. package/dist/forge/javascript/hosts/process-host.js +4 -1
  42. package/dist/forge/python/wasm-node.d.ts +1 -1
  43. package/dist/forge/python/wasm-node.js +4 -1
  44. package/dist/index.d.ts +8 -2
  45. package/dist/index.js +8 -2
  46. package/dist/plugins/host.d.ts +5 -0
  47. package/dist/plugins/host.js +15 -1
  48. package/dist/plugins/install.d.ts +50 -2
  49. package/dist/plugins/install.js +102 -12
  50. package/dist/plugins/local-install.d.ts +33 -0
  51. package/dist/plugins/local-install.js +121 -0
  52. package/dist/plugins/npm-runner.d.ts +30 -0
  53. package/dist/plugins/npm-runner.js +66 -0
  54. package/dist/plugins/tarball.d.ts +39 -0
  55. package/dist/plugins/tarball.js +277 -0
  56. package/dist/plugins/version-compat.d.ts +20 -0
  57. package/dist/plugins/version-compat.js +154 -0
  58. package/package.json +2 -2
@@ -0,0 +1,39 @@
1
+ import type { Readable } from "node:stream";
2
+ export declare const MAX_TARBALL_BYTES: number;
3
+ export declare const MAX_PACKAGE_JSON_BYTES: number;
4
+ export declare const MAX_TARBALL_ENTRIES = 20000;
5
+ export declare const MAX_EXPANDED_BYTES: number;
6
+ export interface TarballLimits {
7
+ maxPackageJsonBytes?: number;
8
+ maxEntries?: number;
9
+ maxExpandedBytes?: number;
10
+ }
11
+ export declare class TarballError extends Error {
12
+ }
13
+ /**
14
+ * Reads `package/package.json` from a gzip ustar stream. Throws `TarballError` with a user-facing
15
+ * reason for anything unusable (not gzip, corrupt, unsafe path, over a limit, no manifest).
16
+ */
17
+ export declare function readTarballPackageJson(source: Readable, limits?: TarballLimits): Promise<{
18
+ packageJson: unknown;
19
+ entries: number;
20
+ }>;
21
+ export interface PluginTarballInfo {
22
+ name?: string;
23
+ version?: string;
24
+ description?: string;
25
+ author?: string;
26
+ license?: string;
27
+ /** `peerDependencies["@alisio/sdk"]`. */
28
+ sdkRange?: string;
29
+ /** True when every check passed; `reasons` lists what failed otherwise. */
30
+ isAlisioPlugin: boolean;
31
+ reasons: string[];
32
+ /** Declared `preinstall`/`install`/`postinstall` scripts (npm runs them on install). */
33
+ lifecycleScripts: string[];
34
+ size: number;
35
+ }
36
+ /** Validates a tarball on disk as an Alisio plugin package; never throws for bad content. */
37
+ export declare function inspectPluginTarball(path: string, limits?: TarballLimits & {
38
+ maxBytes?: number;
39
+ }): Promise<PluginTarballInfo>;
@@ -0,0 +1,277 @@
1
+ /**
2
+ * Inspection of a plugin tarball (`.tgz` from `npm pack`/`pnpm pack`) without extracting it and
3
+ * without any external `tar`: a streaming gzip + ustar reader that only keeps `package/package.json`.
4
+ * Everything is bounded (compressed size, expanded size, entry count, manifest size) and any entry
5
+ * path that could escape the package directory rejects the whole archive.
6
+ */
7
+ import { createReadStream } from "node:fs";
8
+ import { stat } from "node:fs/promises";
9
+ import { createGunzip } from "node:zlib";
10
+ import { PLUGIN_KEYWORD } from "../runtime/modules.js";
11
+ import { parsePluginSpec } from "./install.js";
12
+ import { comparePluginVersions } from "./version-compat.js";
13
+ export const MAX_TARBALL_BYTES = 50 * 1024 * 1024;
14
+ export const MAX_PACKAGE_JSON_BYTES = 1024 * 1024;
15
+ export const MAX_TARBALL_ENTRIES = 20_000;
16
+ export const MAX_EXPANDED_BYTES = 1024 * 1024 * 1024;
17
+ const MAX_META_BYTES = 64 * 1024;
18
+ const LIFECYCLE = ["preinstall", "install", "postinstall"];
19
+ export class TarballError extends Error {
20
+ }
21
+ const str = (block, start, length) => {
22
+ const slice = block.subarray(start, start + length);
23
+ const end = slice.indexOf(0);
24
+ return slice.subarray(0, end < 0 ? slice.length : end).toString("utf8");
25
+ };
26
+ function parseSize(block) {
27
+ if ((block[124] ?? 0) & 0x80)
28
+ throw new TarballError("The archive has an entry that is too large");
29
+ const value = Number.parseInt(str(block, 124, 12).trim() || "0", 8);
30
+ if (!Number.isFinite(value) || value < 0)
31
+ throw new TarballError("The archive is corrupt");
32
+ return value;
33
+ }
34
+ function checksumOk(block) {
35
+ const stored = Number.parseInt(str(block, 148, 8).trim() || "x", 8);
36
+ let sum = 0;
37
+ for (let i = 0; i < 512; i++)
38
+ sum += i >= 148 && i < 156 ? 0x20 : (block[i] ?? 0);
39
+ return stored === sum;
40
+ }
41
+ /** Path of the `path=` record of a pax extended header, if any. */
42
+ function paxPath(data) {
43
+ let offset = 0;
44
+ while (offset < data.length) {
45
+ const space = data.indexOf(0x20, offset);
46
+ if (space < 0)
47
+ return undefined;
48
+ const length = Number.parseInt(data.subarray(offset, space).toString("utf8"), 10);
49
+ if (!Number.isFinite(length) || length <= 0)
50
+ return undefined;
51
+ const record = data.subarray(space + 1, offset + length - 1).toString("utf8");
52
+ if (record.startsWith("path="))
53
+ return record.slice(5);
54
+ offset += length;
55
+ }
56
+ return undefined;
57
+ }
58
+ /** Normalized entry name; throws for anything that is absolute or climbs out with `..`. */
59
+ function safeName(raw) {
60
+ const name = raw.replace(/\/+$/, "");
61
+ if (name.startsWith("/") || name.includes("\\") || /^[A-Za-z]:/.test(name))
62
+ throw new TarballError(`The archive has an unsafe path: ${raw.slice(0, 80)}`);
63
+ if (name.split("/").some((part) => part === ".."))
64
+ throw new TarballError(`The archive has an unsafe path: ${raw.slice(0, 80)}`);
65
+ return name;
66
+ }
67
+ /**
68
+ * Reads `package/package.json` from a gzip ustar stream. Throws `TarballError` with a user-facing
69
+ * reason for anything unusable (not gzip, corrupt, unsafe path, over a limit, no manifest).
70
+ */
71
+ export async function readTarballPackageJson(source, limits = {}) {
72
+ const maxJson = limits.maxPackageJsonBytes ?? MAX_PACKAGE_JSON_BYTES;
73
+ const maxEntries = limits.maxEntries ?? MAX_TARBALL_ENTRIES;
74
+ const maxExpanded = limits.maxExpandedBytes ?? MAX_EXPANDED_BYTES;
75
+ const gunzip = createGunzip();
76
+ source.on("error", (error) => gunzip.destroy(error));
77
+ source.pipe(gunzip);
78
+ let state = "header";
79
+ let buf = Buffer.alloc(0);
80
+ let remaining = 0;
81
+ let mode = "skip";
82
+ let collected = [];
83
+ let pendingName;
84
+ let entries = 0;
85
+ let expanded = 0;
86
+ let manifest;
87
+ let padding = 0;
88
+ const finishData = () => {
89
+ const data = Buffer.concat(collected);
90
+ collected = [];
91
+ if (mode === "manifest")
92
+ manifest = data;
93
+ else if (mode === "pax")
94
+ pendingName = paxPath(data) ?? pendingName;
95
+ else if (mode === "longname")
96
+ pendingName = str(data, 0, data.length);
97
+ mode = "skip";
98
+ };
99
+ const header = (block) => {
100
+ if (block.every((byte) => byte === 0)) {
101
+ state = "end";
102
+ return;
103
+ }
104
+ if (!checksumOk(block))
105
+ throw new TarballError("The file is not a valid tar archive (corrupt header checksum)");
106
+ const prefix = str(block, 345, 155);
107
+ const own = str(block, 0, 100);
108
+ const size = parseSize(block);
109
+ const type = String.fromCharCode(block[156] || 0x30);
110
+ padding = (512 - (size % 512)) % 512;
111
+ if (type === "x" || type === "L" || type === "g") {
112
+ if (size > MAX_META_BYTES)
113
+ throw new TarballError("The archive has an oversized header record");
114
+ mode = type === "x" ? "pax" : type === "L" ? "longname" : "skip";
115
+ }
116
+ else {
117
+ entries++;
118
+ if (entries > maxEntries)
119
+ throw new TarballError("The archive has too many entries");
120
+ const name = safeName(pendingName ?? (prefix ? `${prefix}/${own}` : own));
121
+ pendingName = undefined;
122
+ mode = "skip";
123
+ if (name === "package/package.json" && (type === "0" || type === "7")) {
124
+ if (size > maxJson)
125
+ throw new TarballError("package.json is too large");
126
+ mode = "manifest";
127
+ }
128
+ }
129
+ remaining = size;
130
+ state = remaining > 0 ? "data" : padding > 0 ? "pad" : "header";
131
+ if (remaining === 0 && mode !== "skip")
132
+ finishData();
133
+ };
134
+ const pump = () => {
135
+ for (;;) {
136
+ if (state === "end")
137
+ return;
138
+ if (state === "header") {
139
+ if (buf.length < 512)
140
+ return;
141
+ const block = buf.subarray(0, 512);
142
+ buf = buf.subarray(512);
143
+ header(block);
144
+ continue;
145
+ }
146
+ const take = Math.min(remaining, buf.length);
147
+ if (take === 0)
148
+ return;
149
+ if (state === "data" && mode !== "skip") {
150
+ collected.push(buf.subarray(0, take));
151
+ }
152
+ buf = buf.subarray(take);
153
+ remaining -= take;
154
+ if (remaining > 0)
155
+ return;
156
+ if (state === "data") {
157
+ if (mode !== "skip")
158
+ finishData();
159
+ remaining = padding;
160
+ state = padding > 0 ? "pad" : "header";
161
+ }
162
+ else
163
+ state = "header";
164
+ }
165
+ };
166
+ try {
167
+ for await (const chunk of gunzip) {
168
+ expanded += chunk.length;
169
+ if (expanded > maxExpanded)
170
+ throw new TarballError("The archive expands beyond the allowed size");
171
+ buf = buf.length ? Buffer.concat([buf, chunk]) : chunk;
172
+ pump();
173
+ }
174
+ }
175
+ catch (error) {
176
+ if (error instanceof TarballError)
177
+ throw error;
178
+ throw new TarballError("The file is not a gzip archive (.tgz)");
179
+ }
180
+ finally {
181
+ source.unpipe(gunzip);
182
+ source.destroy();
183
+ }
184
+ const last = state;
185
+ if (last !== "end" && last !== "header")
186
+ throw new TarballError("The archive is truncated");
187
+ if (entries === 0 && last !== "end")
188
+ throw new TarballError("The file is not a valid tar archive");
189
+ if (!manifest)
190
+ throw new TarballError("The archive has no package/package.json");
191
+ let packageJson;
192
+ try {
193
+ packageJson = JSON.parse(manifest.toString("utf8"));
194
+ }
195
+ catch {
196
+ throw new TarballError("package/package.json is not valid JSON");
197
+ }
198
+ return { packageJson, entries };
199
+ }
200
+ const text = (value, max = 500) => typeof value === "string" && value.trim() && value.length <= max ? value.trim() : undefined;
201
+ /** Validates a tarball on disk as an Alisio plugin package; never throws for bad content. */
202
+ export async function inspectPluginTarball(path, limits = {}) {
203
+ const size = (await stat(path)).size;
204
+ const info = {
205
+ isAlisioPlugin: false,
206
+ reasons: [],
207
+ lifecycleScripts: [],
208
+ size,
209
+ };
210
+ const maxBytes = limits.maxBytes ?? MAX_TARBALL_BYTES;
211
+ if (size > maxBytes) {
212
+ info.reasons.push(`The file is larger than ${Math.round(maxBytes / (1024 * 1024))} MB`);
213
+ return info;
214
+ }
215
+ let json;
216
+ try {
217
+ json = (await readTarballPackageJson(createReadStream(path), limits)).packageJson;
218
+ }
219
+ catch (error) {
220
+ info.reasons.push(error instanceof TarballError ? error.message : "The file could not be read");
221
+ return info;
222
+ }
223
+ if (!json || typeof json !== "object" || Array.isArray(json)) {
224
+ info.reasons.push("package/package.json is not an object");
225
+ return info;
226
+ }
227
+ const pkg = json;
228
+ const name = text(pkg.name, 214);
229
+ const version = text(pkg.version, 64);
230
+ let nameOk = false;
231
+ if (name) {
232
+ try {
233
+ const parsed = parsePluginSpec(name);
234
+ nameOk = parsed.version === undefined && parsed.name === name;
235
+ }
236
+ catch {
237
+ nameOk = false;
238
+ }
239
+ }
240
+ if (nameOk)
241
+ info.name = name;
242
+ else
243
+ info.reasons.push("The package name is missing or not a valid npm package name");
244
+ if (version && comparePluginVersions(version, version) !== undefined)
245
+ info.version = version;
246
+ else
247
+ info.reasons.push("The package version is missing or not a valid semver version");
248
+ const keywords = Array.isArray(pkg.keywords) ? pkg.keywords : [];
249
+ if (!keywords.includes(PLUGIN_KEYWORD))
250
+ info.reasons.push(`Not an Alisio plugin: package.json keywords must include "${PLUGIN_KEYWORD}"`);
251
+ const hasExports = (typeof pkg.exports === "string" && pkg.exports.length > 0) ||
252
+ (!!pkg.exports && typeof pkg.exports === "object" && Object.keys(pkg.exports).length > 0);
253
+ if (!hasExports && !text(pkg.main))
254
+ info.reasons.push('The package has no entry point ("exports" or "main" in package.json)');
255
+ const description = text(pkg.description, 600);
256
+ if (description)
257
+ info.description = description;
258
+ const author = text(pkg.author) ??
259
+ (pkg.author && typeof pkg.author === "object"
260
+ ? text(pkg.author.name)
261
+ : undefined);
262
+ if (author)
263
+ info.author = author;
264
+ const license = text(pkg.license, 80);
265
+ if (license)
266
+ info.license = license;
267
+ const peers = pkg.peerDependencies;
268
+ const range = peers && typeof peers === "object"
269
+ ? text(peers["@alisio/sdk"], 80)
270
+ : undefined;
271
+ if (range)
272
+ info.sdkRange = range;
273
+ const scripts = pkg.scripts && typeof pkg.scripts === "object" ? pkg.scripts : {};
274
+ info.lifecycleScripts = LIFECYCLE.filter((key) => typeof scripts[key] === "string");
275
+ info.isAlisioPlugin = info.reasons.length === 0;
276
+ return info;
277
+ }
@@ -0,0 +1,20 @@
1
+ /** Negative, zero or positive like a comparator; `undefined` when either version is malformed. */
2
+ export declare function comparePluginVersions(a: string, b: string): number | undefined;
3
+ /** Whether `version` satisfies `range`. An unparseable range or version never satisfies. */
4
+ export declare function satisfiesRange(version: string, range: string): boolean;
5
+ export interface CatalogPluginStateInput {
6
+ catalogVersion: string;
7
+ installedVersion?: string;
8
+ /** The plugin's declared `@alisio/sdk` range. */
9
+ sdkRange?: string;
10
+ /** The installed `@alisio/sdk` version, when known. */
11
+ sdkVersion?: string;
12
+ }
13
+ export interface CatalogPluginState {
14
+ installedVersion?: string;
15
+ /** False only when both the range and the SDK version are known and do not match. */
16
+ compatible: boolean;
17
+ updateAvailable: boolean;
18
+ }
19
+ /** Install state of one catalog entry against what is installed and the running SDK. */
20
+ export declare function catalogPluginState(input: CatalogPluginStateInput): CatalogPluginState;
@@ -0,0 +1,154 @@
1
+ function parse(version) {
2
+ const match = /^v?(\d+)\.(\d+)\.(\d+)(?:-([0-9A-Za-z.-]+))?(?:\+[0-9A-Za-z.-]+)?$/.exec(version.trim());
3
+ if (!match)
4
+ return undefined;
5
+ return {
6
+ triple: [Number(match[1]), Number(match[2]), Number(match[3])],
7
+ pre: match[4] ? match[4].split(".") : [],
8
+ };
9
+ }
10
+ function compareTriples(a, b) {
11
+ for (let i = 0; i < 3; i++) {
12
+ const diff = a[i] - b[i];
13
+ if (diff)
14
+ return diff;
15
+ }
16
+ return 0;
17
+ }
18
+ /** Negative, zero or positive like a comparator; `undefined` when either version is malformed. */
19
+ export function comparePluginVersions(a, b) {
20
+ const left = parse(a);
21
+ const right = parse(b);
22
+ if (!left || !right)
23
+ return undefined;
24
+ const core = compareTriples(left.triple, right.triple);
25
+ if (core)
26
+ return core;
27
+ if (!left.pre.length || !right.pre.length)
28
+ return right.pre.length - left.pre.length;
29
+ const length = Math.max(left.pre.length, right.pre.length);
30
+ for (let i = 0; i < length; i++) {
31
+ const x = left.pre[i];
32
+ const y = right.pre[i];
33
+ if (x === undefined)
34
+ return -1;
35
+ if (y === undefined)
36
+ return 1;
37
+ const xn = /^\d+$/.test(x);
38
+ const yn = /^\d+$/.test(y);
39
+ if (xn && yn) {
40
+ if (Number(x) !== Number(y))
41
+ return Number(x) - Number(y);
42
+ }
43
+ else if (xn !== yn)
44
+ return xn ? -1 : 1;
45
+ else if (x !== y)
46
+ return x < y ? -1 : 1;
47
+ }
48
+ return 0;
49
+ }
50
+ /** A partial version (`1`, `1.2`, `1.x`, `*`) as its numeric parts (`undefined` = wildcard). */
51
+ function partial(text) {
52
+ const parts = text.replace(/^v/, "").split(".");
53
+ if (parts.length > 3 || parts[0] === "")
54
+ return undefined;
55
+ const out = [];
56
+ for (const part of parts) {
57
+ if (part === "x" || part === "X" || part === "*")
58
+ out.push(undefined);
59
+ else if (/^\d+$/.test(part))
60
+ out.push(Number(part));
61
+ else
62
+ return undefined;
63
+ }
64
+ while (out.length < 3)
65
+ out.push(undefined);
66
+ return out;
67
+ }
68
+ function comparator(token) {
69
+ const match = /^(\^|~|>=|<=|>|<|=)?\s*(.+)$/.exec(token);
70
+ if (!match)
71
+ return undefined;
72
+ const op = match[1] ?? "";
73
+ const nums = partial(match[2]);
74
+ if (!nums)
75
+ return undefined;
76
+ const [maj, min, pat] = nums;
77
+ const floor = [maj ?? 0, min ?? 0, pat ?? 0];
78
+ const ge = (v) => compareTriples(v, floor) >= 0;
79
+ if (maj === undefined)
80
+ return () => true;
81
+ switch (op) {
82
+ case "^": {
83
+ const upper = maj > 0
84
+ ? [maj + 1, 0, 0]
85
+ : min === undefined
86
+ ? [1, 0, 0]
87
+ : min > 0 || pat === undefined
88
+ ? [0, min + 1, 0]
89
+ : [0, 0, pat + 1];
90
+ return (v) => ge(v) && compareTriples(v, upper) < 0;
91
+ }
92
+ case "~": {
93
+ const upper = min === undefined ? [maj + 1, 0, 0] : [maj, min + 1, 0];
94
+ return (v) => ge(v) && compareTriples(v, upper) < 0;
95
+ }
96
+ case ">=":
97
+ return ge;
98
+ case ">": {
99
+ const next = pat !== undefined
100
+ ? [maj, min ?? 0, pat]
101
+ : min !== undefined
102
+ ? [maj, min + 1, 0]
103
+ : [maj + 1, 0, 0];
104
+ return pat !== undefined
105
+ ? (v) => compareTriples(v, next) > 0
106
+ : (v) => compareTriples(v, next) >= 0;
107
+ }
108
+ case "<":
109
+ return (v) => compareTriples(v, floor) < 0;
110
+ case "<=": {
111
+ const top = pat !== undefined
112
+ ? [maj, min ?? 0, pat + 1]
113
+ : min !== undefined
114
+ ? [maj, min + 1, 0]
115
+ : [maj + 1, 0, 0];
116
+ return (v) => compareTriples(v, top) < 0;
117
+ }
118
+ default: {
119
+ // Exact or wildcard (`1.2.x`, `1`).
120
+ if (pat !== undefined)
121
+ return (v) => compareTriples(v, floor) === 0;
122
+ const upper = min === undefined ? [maj + 1, 0, 0] : [maj, min + 1, 0];
123
+ return (v) => ge(v) && compareTriples(v, upper) < 0;
124
+ }
125
+ }
126
+ }
127
+ /** Whether `version` satisfies `range`. An unparseable range or version never satisfies. */
128
+ export function satisfiesRange(version, range) {
129
+ const parsed = parse(version);
130
+ if (!parsed)
131
+ return false;
132
+ const alternatives = range.split("||").map((part) => part.trim());
133
+ return alternatives.some((alt) => {
134
+ const tokens = alt
135
+ .replace(/(\^|~|>=|<=|>|<|=)\s+/g, "$1")
136
+ .split(/\s+/)
137
+ .filter(Boolean);
138
+ if (tokens.length === 0)
139
+ return false;
140
+ const checks = tokens.map(comparator);
141
+ return checks.every((check) => check?.(parsed.triple) === true);
142
+ });
143
+ }
144
+ /** Install state of one catalog entry against what is installed and the running SDK. */
145
+ export function catalogPluginState(input) {
146
+ const compatible = !input.sdkRange || !input.sdkVersion ? true : satisfiesRange(input.sdkVersion, input.sdkRange);
147
+ const updateAvailable = input.installedVersion !== undefined &&
148
+ (comparePluginVersions(input.catalogVersion, input.installedVersion) ?? 0) > 0;
149
+ return {
150
+ compatible,
151
+ updateAvailable,
152
+ ...(input.installedVersion !== undefined ? { installedVersion: input.installedVersion } : {}),
153
+ };
154
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@alisio/core",
3
- "version": "0.8.0",
3
+ "version": "0.10.0",
4
4
  "description": "Embeddable provider-agnostic Alisio agent core: tool loop, context compaction, local tools, MCP, plugin host and SQLite session store. Runs on Node >=22.16 and Bun.",
5
5
  "author": "Gustavo Gutiérrez",
6
6
  "license": "MIT",
@@ -45,7 +45,7 @@
45
45
  "node": ">=22.16"
46
46
  },
47
47
  "dependencies": {
48
- "@alisio/sdk": "0.8.0",
48
+ "@alisio/sdk": "0.10.0",
49
49
  "@mixmark-io/domino": "2.2.0",
50
50
  "@modelcontextprotocol/client": "2.1.0",
51
51
  "ajv": "8.20.0",