@alisio/core 0.1.0-alpha.21 → 0.1.0-alpha.23
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/analysis/capabilities.d.ts +48 -0
- package/dist/analysis/capabilities.js +90 -0
- package/dist/analysis/data/csv.d.ts +46 -0
- package/dist/analysis/data/csv.js +240 -0
- package/dist/analysis/data/datasets.d.ts +132 -0
- package/dist/analysis/data/datasets.js +441 -0
- package/dist/analysis/data/describe.d.ts +27 -0
- package/dist/analysis/data/describe.js +103 -0
- package/dist/analysis/data/engine-client.d.ts +58 -0
- package/dist/analysis/data/engine-client.js +304 -0
- package/dist/analysis/data/engine-entry.d.ts +1 -0
- package/dist/analysis/data/engine-entry.js +59 -0
- package/dist/analysis/data/engine-source.d.ts +4 -0
- package/dist/analysis/data/engine-source.js +6 -0
- package/dist/analysis/data/engine-types.d.ts +86 -0
- package/dist/analysis/data/engine-types.js +7 -0
- package/dist/analysis/data/infer.d.ts +42 -0
- package/dist/analysis/data/infer.js +118 -0
- package/dist/analysis/data/ingest-worker.d.ts +17 -0
- package/dist/analysis/data/ingest-worker.js +365 -0
- package/dist/analysis/data/json.d.ts +19 -0
- package/dist/analysis/data/json.js +44 -0
- package/dist/analysis/data/query-worker.d.ts +12 -0
- package/dist/analysis/data/query-worker.js +75 -0
- package/dist/analysis/data/rows.d.ts +39 -0
- package/dist/analysis/data/rows.js +120 -0
- package/dist/analysis/data/sql-guard.d.ts +20 -0
- package/dist/analysis/data/sql-guard.js +129 -0
- package/dist/analysis/data/stats.d.ts +18 -0
- package/dist/analysis/data/stats.js +77 -0
- package/dist/analysis/install-hints.d.ts +33 -0
- package/dist/analysis/install-hints.js +144 -0
- package/dist/analysis/janitor.d.ts +60 -0
- package/dist/analysis/janitor.js +264 -0
- package/dist/analysis/jobs.d.ts +94 -0
- package/dist/analysis/jobs.js +165 -0
- package/dist/analysis/oci.d.ts +129 -0
- package/dist/analysis/oci.js +330 -0
- package/dist/analysis/python/sources.d.ts +2 -0
- package/dist/analysis/python/sources.js +10 -0
- package/dist/analysis/requirements.d.ts +32 -0
- package/dist/analysis/requirements.js +73 -0
- package/dist/analysis/rerun.d.ts +40 -0
- package/dist/analysis/rerun.js +136 -0
- package/dist/analysis/runtime-manager.d.ts +146 -0
- package/dist/analysis/runtime-manager.js +472 -0
- package/dist/analysis/status.d.ts +21 -0
- package/dist/analysis/status.js +52 -0
- package/dist/application.d.ts +41 -0
- package/dist/application.js +197 -0
- package/dist/artifacts/kinds.d.ts +35 -0
- package/dist/artifacts/kinds.js +177 -0
- package/dist/artifacts/publisher.d.ts +7 -0
- package/dist/artifacts/publisher.js +29 -0
- package/dist/artifacts/store.d.ts +119 -0
- package/dist/artifacts/store.js +581 -0
- package/dist/commands/builtins.js +13 -0
- package/dist/config.d.ts +110 -0
- package/dist/config.js +186 -8
- package/dist/core/contracts.d.ts +69 -1
- package/dist/core/runner.d.ts +53 -4
- package/dist/core/runner.js +549 -161
- package/dist/core/timeout.d.ts +15 -0
- package/dist/core/timeout.js +61 -0
- package/dist/index.d.ts +23 -4
- package/dist/index.js +22 -3
- package/dist/mcp/rich.js +4 -0
- package/dist/plugins/host.js +14 -6
- package/dist/runtime/blobs.d.ts +22 -0
- package/dist/runtime/blobs.js +84 -1
- package/dist/runtime/ids.d.ts +8 -0
- package/dist/runtime/ids.js +32 -0
- package/dist/runtime/paths.d.ts +5 -0
- package/dist/runtime/paths.js +6 -0
- package/dist/runtime/process.d.ts +12 -0
- package/dist/runtime/process.js +64 -4
- package/dist/runtime/sqlite.d.ts +2 -0
- package/dist/runtime/sqlite.js +18 -0
- package/dist/runtime/store.d.ts +5 -0
- package/dist/runtime/store.js +75 -0
- package/dist/runtime/zip.d.ts +24 -0
- package/dist/runtime/zip.js +126 -0
- package/dist/sessions/children.js +4 -0
- package/dist/tools/analysis.d.ts +37 -0
- package/dist/tools/analysis.js +572 -0
- package/dist/tools/artifacts.d.ts +14 -0
- package/dist/tools/artifacts.js +143 -0
- package/dist/tools/data.d.ts +7 -0
- package/dist/tools/data.js +160 -0
- package/dist/tools/execute.js +6 -2
- package/package.json +2 -2
package/dist/runtime/store.js
CHANGED
|
@@ -112,6 +112,81 @@ export class SQLiteStore {
|
|
|
112
112
|
this.db.exec("ALTER TABLE workspaces ADD COLUMN archived_at INTEGER");
|
|
113
113
|
this.db.exec("INSERT OR IGNORE INTO schema_migrations VALUES(5)");
|
|
114
114
|
});
|
|
115
|
+
if (!has(6))
|
|
116
|
+
this.db.transaction(() => {
|
|
117
|
+
// v6 (additive): Python analysis executions, published artifacts, persisted capability
|
|
118
|
+
// grants (audit included) and tabular datasets (used from the data phase on).
|
|
119
|
+
this.db.exec(`CREATE TABLE IF NOT EXISTS analysis_executions(
|
|
120
|
+
id TEXT PRIMARY KEY,
|
|
121
|
+
session TEXT NOT NULL,
|
|
122
|
+
root_session TEXT NOT NULL,
|
|
123
|
+
workspace TEXT NOT NULL,
|
|
124
|
+
run_id TEXT, call_id TEXT,
|
|
125
|
+
runtime TEXT NOT NULL CHECK(runtime IN ('managed','oci')),
|
|
126
|
+
status TEXT NOT NULL CHECK(status IN ('running','completed','failed','cancelled','timed_out')),
|
|
127
|
+
script_sha256 TEXT NOT NULL,
|
|
128
|
+
exit_code INTEGER, error TEXT,
|
|
129
|
+
rel_dir TEXT NOT NULL,
|
|
130
|
+
rerun_of TEXT,
|
|
131
|
+
created_at INTEGER NOT NULL, ended_at INTEGER);
|
|
132
|
+
CREATE INDEX IF NOT EXISTS analysis_executions_session
|
|
133
|
+
ON analysis_executions(root_session, created_at);
|
|
134
|
+
CREATE TABLE IF NOT EXISTS artifacts(
|
|
135
|
+
id TEXT PRIMARY KEY,
|
|
136
|
+
session TEXT NOT NULL, root_session TEXT NOT NULL, workspace TEXT NOT NULL,
|
|
137
|
+
run_id TEXT, call_id TEXT,
|
|
138
|
+
execution_id TEXT REFERENCES analysis_executions(id),
|
|
139
|
+
source_path TEXT,
|
|
140
|
+
title TEXT NOT NULL, file_name TEXT NOT NULL,
|
|
141
|
+
kind TEXT NOT NULL, mime TEXT NOT NULL,
|
|
142
|
+
bytes INTEGER NOT NULL, file_count INTEGER NOT NULL DEFAULT 1,
|
|
143
|
+
sha256 TEXT NOT NULL, entry TEXT,
|
|
144
|
+
rel_dir TEXT NOT NULL,
|
|
145
|
+
status TEXT NOT NULL CHECK(status IN ('ready','deleted','expired')),
|
|
146
|
+
provenance TEXT NOT NULL,
|
|
147
|
+
created_at INTEGER NOT NULL, deleted_at INTEGER,
|
|
148
|
+
UNIQUE(execution_id, source_path));
|
|
149
|
+
CREATE INDEX IF NOT EXISTS artifacts_session ON artifacts(root_session, created_at);
|
|
150
|
+
CREATE TABLE IF NOT EXISTS capability_grants(
|
|
151
|
+
id TEXT PRIMARY KEY,
|
|
152
|
+
capability TEXT NOT NULL,
|
|
153
|
+
session TEXT NOT NULL,
|
|
154
|
+
workspace TEXT NOT NULL,
|
|
155
|
+
scope TEXT NOT NULL CHECK(scope IN ('once','session')),
|
|
156
|
+
decision TEXT NOT NULL CHECK(decision IN ('allow','deny')),
|
|
157
|
+
source TEXT NOT NULL CHECK(source IN ('tui','web','flag','headless-grant')),
|
|
158
|
+
call_id TEXT, run_id TEXT, correlation_id TEXT,
|
|
159
|
+
created_at INTEGER NOT NULL,
|
|
160
|
+
revoked_at INTEGER, revoked_by TEXT);
|
|
161
|
+
CREATE INDEX IF NOT EXISTS capability_grants_lookup
|
|
162
|
+
ON capability_grants(capability, session, scope, decision, revoked_at);
|
|
163
|
+
CREATE TABLE IF NOT EXISTS datasets(
|
|
164
|
+
id TEXT PRIMARY KEY,
|
|
165
|
+
session TEXT NOT NULL, root_session TEXT NOT NULL,
|
|
166
|
+
name TEXT NOT NULL, format TEXT NOT NULL,
|
|
167
|
+
sha256 TEXT NOT NULL, bytes INTEGER NOT NULL,
|
|
168
|
+
blob_hash TEXT,
|
|
169
|
+
source_path TEXT,
|
|
170
|
+
db_rel_path TEXT NOT NULL,
|
|
171
|
+
ingest_version INTEGER NOT NULL,
|
|
172
|
+
sheets TEXT NOT NULL,
|
|
173
|
+
created_at INTEGER NOT NULL);
|
|
174
|
+
INSERT OR IGNORE INTO schema_migrations VALUES(6);`);
|
|
175
|
+
});
|
|
176
|
+
}
|
|
177
|
+
/**
|
|
178
|
+
* The root of a session (itself for roots), following `parent_id`. Unknown ids are their own
|
|
179
|
+
* root, so callers never throw on a session another process has not written yet.
|
|
180
|
+
*/
|
|
181
|
+
rootOf(id) {
|
|
182
|
+
let current = id;
|
|
183
|
+
for (let depth = 0; depth < 32; depth++) {
|
|
184
|
+
const row = this.db.prepare("SELECT parent_id FROM sessions WHERE id=?").get(current);
|
|
185
|
+
if (!row?.parent_id)
|
|
186
|
+
return current;
|
|
187
|
+
current = row.parent_id;
|
|
188
|
+
}
|
|
189
|
+
return current;
|
|
115
190
|
}
|
|
116
191
|
create(workspace, provider, model) {
|
|
117
192
|
const id = crypto.randomUUID();
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
export type ZipEntry = {
|
|
2
|
+
name: string;
|
|
3
|
+
source: string;
|
|
4
|
+
} | {
|
|
5
|
+
name: string;
|
|
6
|
+
data: Uint8Array;
|
|
7
|
+
};
|
|
8
|
+
/** CRC-32 (IEEE) of `bytes`, continuing from `crc`. */
|
|
9
|
+
export declare function crc32(bytes: Uint8Array, crc?: number): number;
|
|
10
|
+
/** Something to write the archive to (an HTTP response, a file stream…), honoring backpressure. */
|
|
11
|
+
export interface ZipSink {
|
|
12
|
+
write(chunk: Buffer): boolean;
|
|
13
|
+
once(event: "drain", listener: () => void): unknown;
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Writes `entries` as a ZIP archive to `out`, streaming file contents. Entry names use `/` and
|
|
17
|
+
* must be relative; the caller validates them. Throws when the archive would need ZIP64.
|
|
18
|
+
*/
|
|
19
|
+
export declare function writeZip(entries: ZipEntry[], out: ZipSink, options?: {
|
|
20
|
+
now?: Date;
|
|
21
|
+
signal?: AbortSignal;
|
|
22
|
+
}): Promise<{
|
|
23
|
+
bytes: number;
|
|
24
|
+
}>;
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Streaming ZIP writer on `node:zlib` (no dependency): DEFLATE entries with a data descriptor,
|
|
3
|
+
* UTF-8 names (general-purpose bit 11) and no ZIP64, so archives and entries must stay below
|
|
4
|
+
* 4 GiB. Used for multi-file artifact downloads and for folders published as one archive.
|
|
5
|
+
*/
|
|
6
|
+
import { createReadStream } from "node:fs";
|
|
7
|
+
import { createDeflateRaw } from "node:zlib";
|
|
8
|
+
let table;
|
|
9
|
+
/** CRC-32 (IEEE) of `bytes`, continuing from `crc`. */
|
|
10
|
+
export function crc32(bytes, crc = 0) {
|
|
11
|
+
if (!table) {
|
|
12
|
+
table = new Uint32Array(256);
|
|
13
|
+
for (let n = 0; n < 256; n++) {
|
|
14
|
+
let c = n;
|
|
15
|
+
for (let k = 0; k < 8; k++)
|
|
16
|
+
c = c & 1 ? 0xedb88320 ^ (c >>> 1) : c >>> 1;
|
|
17
|
+
table[n] = c >>> 0;
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
let value = ~crc >>> 0;
|
|
21
|
+
for (let i = 0; i < bytes.length; i++)
|
|
22
|
+
value = table[(value ^ bytes[i]) & 0xff] ^ (value >>> 8);
|
|
23
|
+
return ~value >>> 0;
|
|
24
|
+
}
|
|
25
|
+
/** MS-DOS date and time of `date` (local time, 2-second resolution, 1980 minimum). */
|
|
26
|
+
function dosTime(date) {
|
|
27
|
+
const year = Math.max(1980, date.getFullYear());
|
|
28
|
+
return {
|
|
29
|
+
time: (date.getHours() << 11) | (date.getMinutes() << 5) | Math.floor(date.getSeconds() / 2),
|
|
30
|
+
date: ((year - 1980) << 9) | ((date.getMonth() + 1) << 5) | date.getDate(),
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
const LIMIT = 0xffff_ffff;
|
|
34
|
+
/**
|
|
35
|
+
* Writes `entries` as a ZIP archive to `out`, streaming file contents. Entry names use `/` and
|
|
36
|
+
* must be relative; the caller validates them. Throws when the archive would need ZIP64.
|
|
37
|
+
*/
|
|
38
|
+
export async function writeZip(entries, out, options = {}) {
|
|
39
|
+
if (entries.length > 0xffff)
|
|
40
|
+
throw new Error("ZIP archives hold at most 65535 entries");
|
|
41
|
+
let offset = 0;
|
|
42
|
+
const put = async (chunk) => {
|
|
43
|
+
options.signal?.throwIfAborted();
|
|
44
|
+
offset += chunk.byteLength;
|
|
45
|
+
if (offset > LIMIT)
|
|
46
|
+
throw new Error("ZIP archives larger than 4 GiB are not supported");
|
|
47
|
+
if (!out.write(chunk))
|
|
48
|
+
await new Promise((resolve) => out.once("drain", resolve));
|
|
49
|
+
};
|
|
50
|
+
const { time, date } = dosTime(options.now ?? new Date());
|
|
51
|
+
const central = [];
|
|
52
|
+
for (const entry of entries) {
|
|
53
|
+
const name = Buffer.from(entry.name.replace(/\\/g, "/"), "utf8");
|
|
54
|
+
const start = offset;
|
|
55
|
+
const local = Buffer.alloc(30);
|
|
56
|
+
local.writeUInt32LE(0x04034b50, 0);
|
|
57
|
+
local.writeUInt16LE(20, 4); // version needed
|
|
58
|
+
local.writeUInt16LE(0x0808, 6); // data descriptor + UTF-8 names
|
|
59
|
+
local.writeUInt16LE(8, 8); // deflate
|
|
60
|
+
local.writeUInt16LE(time, 10);
|
|
61
|
+
local.writeUInt16LE(date, 12);
|
|
62
|
+
local.writeUInt16LE(name.length, 26);
|
|
63
|
+
await put(local);
|
|
64
|
+
await put(name);
|
|
65
|
+
let crc = 0, size = 0, compressed = 0;
|
|
66
|
+
const deflate = createDeflateRaw();
|
|
67
|
+
const feed = "data" in entry
|
|
68
|
+
? (async () => {
|
|
69
|
+
crc = crc32(entry.data);
|
|
70
|
+
size = entry.data.byteLength;
|
|
71
|
+
deflate.end(Buffer.from(entry.data));
|
|
72
|
+
})()
|
|
73
|
+
: new Promise((resolve, reject) => {
|
|
74
|
+
const input = createReadStream(entry.source);
|
|
75
|
+
input.on("data", (chunk) => {
|
|
76
|
+
const bytes = chunk;
|
|
77
|
+
crc = crc32(bytes, crc);
|
|
78
|
+
size += bytes.byteLength;
|
|
79
|
+
});
|
|
80
|
+
input.once("error", (error) => {
|
|
81
|
+
deflate.destroy(error);
|
|
82
|
+
reject(error);
|
|
83
|
+
});
|
|
84
|
+
input.once("end", resolve);
|
|
85
|
+
input.pipe(deflate);
|
|
86
|
+
});
|
|
87
|
+
for await (const chunk of deflate) {
|
|
88
|
+
compressed += chunk.byteLength;
|
|
89
|
+
await put(chunk);
|
|
90
|
+
}
|
|
91
|
+
await feed;
|
|
92
|
+
if (size > LIMIT || compressed > LIMIT)
|
|
93
|
+
throw new Error("ZIP entries larger than 4 GiB are not supported");
|
|
94
|
+
const descriptor = Buffer.alloc(16);
|
|
95
|
+
descriptor.writeUInt32LE(0x08074b50, 0);
|
|
96
|
+
descriptor.writeUInt32LE(crc, 4);
|
|
97
|
+
descriptor.writeUInt32LE(compressed, 8);
|
|
98
|
+
descriptor.writeUInt32LE(size, 12);
|
|
99
|
+
await put(descriptor);
|
|
100
|
+
const header = Buffer.alloc(46);
|
|
101
|
+
header.writeUInt32LE(0x02014b50, 0);
|
|
102
|
+
header.writeUInt16LE(20, 4); // version made by
|
|
103
|
+
header.writeUInt16LE(20, 6); // version needed
|
|
104
|
+
header.writeUInt16LE(0x0808, 8);
|
|
105
|
+
header.writeUInt16LE(8, 10);
|
|
106
|
+
header.writeUInt16LE(time, 12);
|
|
107
|
+
header.writeUInt16LE(date, 14);
|
|
108
|
+
header.writeUInt32LE(crc, 16);
|
|
109
|
+
header.writeUInt32LE(compressed, 20);
|
|
110
|
+
header.writeUInt32LE(size, 24);
|
|
111
|
+
header.writeUInt16LE(name.length, 28);
|
|
112
|
+
header.writeUInt32LE(start, 42);
|
|
113
|
+
central.push(header, name);
|
|
114
|
+
}
|
|
115
|
+
const directoryStart = offset;
|
|
116
|
+
for (const part of central)
|
|
117
|
+
await put(part);
|
|
118
|
+
const end = Buffer.alloc(22);
|
|
119
|
+
end.writeUInt32LE(0x06054b50, 0);
|
|
120
|
+
end.writeUInt16LE(entries.length, 8);
|
|
121
|
+
end.writeUInt16LE(entries.length, 10);
|
|
122
|
+
end.writeUInt32LE(offset - directoryStart, 12);
|
|
123
|
+
end.writeUInt32LE(directoryStart, 16);
|
|
124
|
+
await put(end);
|
|
125
|
+
return { bytes: offset };
|
|
126
|
+
}
|
|
@@ -148,6 +148,10 @@ export class ChildSessions {
|
|
|
148
148
|
write: caps.write,
|
|
149
149
|
process: caps.process,
|
|
150
150
|
external: root.external && !caps.readOnly,
|
|
151
|
+
// --allow-analysis carries to children whose process permission is not narrowed.
|
|
152
|
+
...(root.analysis && !caps.readOnly && (spec.permission?.process ?? "allow") === "allow"
|
|
153
|
+
? { analysis: true }
|
|
154
|
+
: {}),
|
|
151
155
|
},
|
|
152
156
|
approvals: caps.approvals,
|
|
153
157
|
label: this.label(id),
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import type { DatasetService } from "../analysis/data/datasets.ts";
|
|
2
|
+
import type { AnalysisJobs } from "../analysis/jobs.ts";
|
|
3
|
+
import type { OciRuntime } from "../analysis/oci.ts";
|
|
4
|
+
import type { AnalysisRerun } from "../analysis/rerun.ts";
|
|
5
|
+
import { type AnalysisRuntimeManager } from "../analysis/runtime-manager.ts";
|
|
6
|
+
import { type ArtifactStore } from "../artifacts/store.ts";
|
|
7
|
+
import type { ToolRegistry } from "../core/registry.ts";
|
|
8
|
+
export declare const NOT_SANDBOXED = "Managed Python is not a sandbox: the script runs with your user permissions and can read your files and use the network.";
|
|
9
|
+
export interface AnalysisLimits {
|
|
10
|
+
timeoutMs: number;
|
|
11
|
+
maxLogBytes: number;
|
|
12
|
+
}
|
|
13
|
+
export interface AnalysisToolDeps {
|
|
14
|
+
store: ArtifactStore;
|
|
15
|
+
jobs: AnalysisJobs;
|
|
16
|
+
/** Discovery (`interpreter`) and, for the optional extras, `hasExtras` / `installExtras`. */
|
|
17
|
+
runtime: Pick<AnalysisRuntimeManager, "interpreter"> & Partial<Pick<AnalysisRuntimeManager, "hasExtras" | "installExtras">>;
|
|
18
|
+
/** Container mode (`analysis.runtime: "oci"`), read when each call starts. */
|
|
19
|
+
oci?: {
|
|
20
|
+
mode(): "managed" | "oci";
|
|
21
|
+
runtime(): OciRuntime;
|
|
22
|
+
};
|
|
23
|
+
/** Rerun of an earlier execution (`rerunOf`). */
|
|
24
|
+
rerun?: AnalysisRerun;
|
|
25
|
+
/** Datasets of the session: `inputs: [{ datasetId }]` copies the dataset's SQLite file. */
|
|
26
|
+
datasets?: DatasetService;
|
|
27
|
+
rootOf: (sessionId: string) => string;
|
|
28
|
+
limits: AnalysisLimits;
|
|
29
|
+
/** Startup facts for the description (stat only; no process was launched). */
|
|
30
|
+
startup: {
|
|
31
|
+
candidates: boolean;
|
|
32
|
+
extras: string[];
|
|
33
|
+
};
|
|
34
|
+
}
|
|
35
|
+
/** `48 KB`, `1.2 MB`. */
|
|
36
|
+
export declare function formatBytes(bytes: number): string;
|
|
37
|
+
export declare function registerAnalysisTools(registry: ToolRegistry, deps: AnalysisToolDeps): void;
|