@ai-ecoverse/slicc-agent 6.3.2 → 6.4.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/README.md +17 -1
- package/dist/agents.js.map +2 -2
- package/dist/freezer/index.js +124 -30
- package/dist/freezer/index.js.map +2 -2
- package/dist/freezer/v6-place.js +86 -0
- package/dist/freezer/v6-place.js.map +7 -0
- package/dist/freezer/v6-write.js +88 -0
- package/dist/freezer/v6-write.js.map +7 -0
- package/dist/freezer/v6.js +407 -26
- package/dist/freezer/v6.js.map +2 -2
- package/dist/freezer/zip.js +42 -18
- package/dist/freezer/zip.js.map +2 -2
- package/dist/kernel/accounts.js +5 -1
- package/dist/kernel/accounts.js.map +2 -2
- package/dist/main.js +7 -3
- package/dist/main.js.map +2 -2
- package/dist/opfs-pool.js +15 -6
- package/dist/opfs-pool.js.map +2 -2
- package/dist/spectrum/messages.js +11 -1
- package/dist/spectrum/messages.js.map +2 -2
- package/dist/types/agents.d.ts +12 -0
- package/dist/types/freezer/index.d.ts +11 -4
- package/dist/types/freezer/v6-place.d.ts +16 -0
- package/dist/types/freezer/v6-write.d.ts +18 -0
- package/dist/types/freezer/v6.d.ts +79 -7
- package/dist/types/freezer/zip.d.ts +8 -2
- package/dist/types/kernel/accounts.d.ts +1 -0
- package/dist/types/opfs-pool.d.ts +2 -0
- package/package.json +3 -3
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
import { BACKGROUND_CONTEXT } from "@earendil-works/chord/context";
|
|
2
|
+
import { coneSpec } from "../kernel/accounts.js";
|
|
3
|
+
import { ROOT_HOME } from "../layout.js";
|
|
4
|
+
import { whereOf } from "./v6.js";
|
|
5
|
+
import { ownTree } from "./v6-write.js";
|
|
6
|
+
import { ImportError } from "./zip.js";
|
|
7
|
+
const V6_ROOT = `${ROOT_HOME}/v6`;
|
|
8
|
+
async function staged(run, zip) {
|
|
9
|
+
const read = await run.writer.env.readBinaryFile(`${run.stage}/${zip}`, run.writer.context);
|
|
10
|
+
if (!read.ok) throw new ImportError(`the staged copy of ${zip} is gone`);
|
|
11
|
+
return read.value;
|
|
12
|
+
}
|
|
13
|
+
async function prepare(run, unit) {
|
|
14
|
+
if (run.ready.has(unit)) return;
|
|
15
|
+
run.ready.add(unit);
|
|
16
|
+
const { users, layout, env } = run.deps;
|
|
17
|
+
if (unit.fresh)
|
|
18
|
+
run.writer.later(async () => {
|
|
19
|
+
await users?.remove(unit.cone).catch(() => false);
|
|
20
|
+
await env.remove(unit.home, { recursive: true, force: true }, BACKGROUND_CONTEXT);
|
|
21
|
+
});
|
|
22
|
+
if (layout.users && users) await users.add(coneSpec(unit.cone));
|
|
23
|
+
}
|
|
24
|
+
async function envOf(run, unit) {
|
|
25
|
+
if (!unit || unit.fresh || !run.deps.layout.users) return void 0;
|
|
26
|
+
const env = await run.deps.envOf?.(unit.cone);
|
|
27
|
+
if (!env) throw new ImportError(`there is no kernel user ${unit.cone} to write its files as`);
|
|
28
|
+
return env;
|
|
29
|
+
}
|
|
30
|
+
async function putIn(run, unit, root, rest, zip) {
|
|
31
|
+
if (unit) await prepare(run, unit);
|
|
32
|
+
const env = await envOf(run, unit);
|
|
33
|
+
let fresh = run.fresh.get(root);
|
|
34
|
+
if (fresh === void 0) {
|
|
35
|
+
fresh = unit?.fresh || await run.writer.tree(root, env);
|
|
36
|
+
run.fresh.set(root, fresh);
|
|
37
|
+
}
|
|
38
|
+
if (unit?.fresh) unit.roots.add(root);
|
|
39
|
+
const path = `${root}/${rest}`;
|
|
40
|
+
await run.writer.put(path, await staged(run, zip), fresh, env);
|
|
41
|
+
}
|
|
42
|
+
const clean = (name) => name.replace(/[^A-Za-z0-9._-]+/g, "_").slice(-80) || "file";
|
|
43
|
+
function targets(run, maps, where, zip) {
|
|
44
|
+
if (where.kind === "cone" || where.kind === "scoop") {
|
|
45
|
+
const unit = (where.kind === "cone" ? maps.byFolder : maps.owners).get(where.folder);
|
|
46
|
+
const root = where.kind === "cone" ? `${unit.home}/workspace${unit.suffix}` : `${unit.home}/scoops${unit.suffix}/${where.folder}`;
|
|
47
|
+
return [[unit, root, where.rest]];
|
|
48
|
+
}
|
|
49
|
+
if (where.kind !== "attachment") return [];
|
|
50
|
+
return run.parsed.units.flatMap(
|
|
51
|
+
(unit) => (unit.doc?.attachments ?? []).filter((item) => item.present && item.path === zip).map((item) => {
|
|
52
|
+
const rest = `${item.sha256.slice(0, 12)}-${clean(item.originalName)}`;
|
|
53
|
+
unit.files.set(item.id, `${unit.home}/v6-attachments/${rest}`);
|
|
54
|
+
return [unit, `${unit.home}/v6-attachments`, rest];
|
|
55
|
+
})
|
|
56
|
+
);
|
|
57
|
+
}
|
|
58
|
+
async function place(run) {
|
|
59
|
+
const { manifest } = run.opened;
|
|
60
|
+
const units = run.parsed.units;
|
|
61
|
+
const byFolder = new Map(
|
|
62
|
+
units.filter((unit) => unit.six).map((unit) => [unit.six, unit])
|
|
63
|
+
);
|
|
64
|
+
const owners = new Map(
|
|
65
|
+
units.flatMap(
|
|
66
|
+
(unit) => unit.scoops.filter((scoop) => scoop.six).map((scoop) => [scoop.six, unit])
|
|
67
|
+
)
|
|
68
|
+
);
|
|
69
|
+
const maps = { byFolder, owners };
|
|
70
|
+
const later = [];
|
|
71
|
+
for (const [at, file] of manifest.files.entries()) {
|
|
72
|
+
const where = whereOf(manifest, file.path);
|
|
73
|
+
if (where.kind === "home-user") later.push([file.path, where.rest]);
|
|
74
|
+
for (const [unit, root, rest] of targets(run, maps, where, file.path))
|
|
75
|
+
await putIn(run, unit, root, rest, file.path);
|
|
76
|
+
run.show("writing", at + 1, manifest.files.length);
|
|
77
|
+
}
|
|
78
|
+
for (const [zip, rest] of later) await putIn(run, null, `${V6_ROOT}/home-user`, rest, zip);
|
|
79
|
+
if (run.deps.layout.users)
|
|
80
|
+
for (const unit of units) await ownTree(run.writer, unit.cone, unit.home, unit.roots);
|
|
81
|
+
}
|
|
82
|
+
export {
|
|
83
|
+
V6_ROOT,
|
|
84
|
+
place
|
|
85
|
+
};
|
|
86
|
+
//# sourceMappingURL=v6-place.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../src/freezer/v6-place.ts"],
|
|
4
|
+
"sourcesContent": ["import { BACKGROUND_CONTEXT } from '@earendil-works/chord/context';\nimport type { ExecutionEnv } from '@earendil-works/pi-durable/env';\nimport { coneSpec } from '../kernel/accounts.ts';\nimport { ROOT_HOME } from '../layout.ts';\nimport type { ImportDeps } from './v6.ts';\nimport { type Opened, type Parsed, type Unit, type Where, whereOf } from './v6.ts';\nimport { ownTree, type Writer } from './v6-write.ts';\nimport { ImportError } from './zip.ts';\n\nexport const V6_ROOT = `${ROOT_HOME}/v6`;\n\nexport type Run = {\n deps: ImportDeps;\n opened: Opened;\n parsed: Parsed;\n writer: Writer;\n stage: string;\n date: string;\n show: (phase: 'writing', done: number, total: number) => void;\n fresh: Map<string, boolean>;\n ready: Set<Unit>;\n};\n\nasync function staged(run: Run, zip: string): Promise<Uint8Array> {\n const read = await run.writer.env.readBinaryFile(`${run.stage}/${zip}`, run.writer.context);\n if (!read.ok) throw new ImportError(`the staged copy of ${zip} is gone`);\n return read.value;\n}\n\nasync function prepare(run: Run, unit: Unit): Promise<void> {\n if (run.ready.has(unit)) return;\n run.ready.add(unit);\n const { users, layout, env } = run.deps;\n if (unit.fresh)\n run.writer.later(async () => {\n await users?.remove(unit.cone).catch(() => false);\n await env.remove(unit.home, { recursive: true, force: true }, BACKGROUND_CONTEXT);\n });\n if (layout.users && users) await users.add(coneSpec(unit.cone));\n}\n\nasync function envOf(run: Run, unit: Unit | null): Promise<ExecutionEnv | undefined> {\n if (!unit || unit.fresh || !run.deps.layout.users) return undefined;\n const env = await run.deps.envOf?.(unit.cone);\n if (!env) throw new ImportError(`there is no kernel user ${unit.cone} to write its files as`);\n return env;\n}\n\nasync function putIn(run: Run, unit: Unit | null, root: string, rest: string, zip: string) {\n if (unit) await prepare(run, unit);\n const env = await envOf(run, unit);\n let fresh = run.fresh.get(root);\n if (fresh === undefined) {\n fresh = unit?.fresh || (await run.writer.tree(root, env));\n run.fresh.set(root, fresh);\n }\n if (unit?.fresh) unit.roots.add(root);\n const path = `${root}/${rest}`;\n await run.writer.put(path, await staged(run, zip), fresh, env);\n}\n\nconst clean = (name: string) => name.replace(/[^A-Za-z0-9._-]+/g, '_').slice(-80) || 'file';\n\ntype Maps = { byFolder: Map<string, Unit>; owners: Map<string, Unit> };\n\nfunction targets(run: Run, maps: Maps, where: Where, zip: string): [Unit, string, string][] {\n if (where.kind === 'cone' || where.kind === 'scoop') {\n const unit = (where.kind === 'cone' ? maps.byFolder : maps.owners).get(where.folder) as Unit;\n const root =\n where.kind === 'cone'\n ? `${unit.home}/workspace${unit.suffix}`\n : `${unit.home}/scoops${unit.suffix}/${where.folder}`;\n return [[unit, root, where.rest]];\n }\n if (where.kind !== 'attachment') return [];\n return run.parsed.units.flatMap((unit) =>\n (unit.doc?.attachments ?? [])\n .filter((item) => item.present && item.path === zip)\n .map((item): [Unit, string, string] => {\n const rest = `${item.sha256.slice(0, 12)}-${clean(item.originalName)}`;\n unit.files.set(item.id, `${unit.home}/v6-attachments/${rest}`);\n return [unit, `${unit.home}/v6-attachments`, rest];\n })\n );\n}\n\nexport async function place(run: Run): Promise<void> {\n const { manifest } = run.opened;\n const units = run.parsed.units;\n const byFolder = new Map(\n units.filter((unit) => unit.six).map((unit) => [unit.six as string, unit])\n );\n const owners = new Map(\n units.flatMap((unit) =>\n unit.scoops.filter((scoop) => scoop.six).map((scoop) => [scoop.six as string, unit])\n )\n );\n const maps: Maps = { byFolder, owners };\n const later: [string, string][] = [];\n for (const [at, file] of manifest.files.entries()) {\n const where = whereOf(manifest, file.path);\n if (where.kind === 'home-user') later.push([file.path, where.rest]);\n for (const [unit, root, rest] of targets(run, maps, where, file.path))\n await putIn(run, unit, root, rest, file.path);\n run.show('writing', at + 1, manifest.files.length);\n }\n for (const [zip, rest] of later) await putIn(run, null, `${V6_ROOT}/home-user`, rest, zip);\n if (run.deps.layout.users)\n for (const unit of units) await ownTree(run.writer, unit.cone, unit.home, unit.roots);\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
import { BACKGROUND_CONTEXT } from "@earendil-works/chord/context";
|
|
2
|
+
import { quote } from "../kernel/env.js";
|
|
3
|
+
import { dirname } from "../kernel/paths.js";
|
|
4
|
+
import { ImportError } from "./zip.js";
|
|
5
|
+
const encoder = new TextEncoder();
|
|
6
|
+
function same(a, b) {
|
|
7
|
+
return a.length === b.length && a.every((byte, at) => byte === b[at]);
|
|
8
|
+
}
|
|
9
|
+
function done(result, what) {
|
|
10
|
+
if (!result.ok) throw new ImportError(`couldn't write ${what}: ${result.error.message}`);
|
|
11
|
+
return result.value;
|
|
12
|
+
}
|
|
13
|
+
class Writer {
|
|
14
|
+
#undo = [];
|
|
15
|
+
env;
|
|
16
|
+
context;
|
|
17
|
+
signal;
|
|
18
|
+
constructor(env, context, signal) {
|
|
19
|
+
this.env = env;
|
|
20
|
+
this.context = context;
|
|
21
|
+
this.signal = signal;
|
|
22
|
+
}
|
|
23
|
+
check() {
|
|
24
|
+
if (this.signal.aborted) throw new ImportError("the import was cancelled");
|
|
25
|
+
}
|
|
26
|
+
later(step) {
|
|
27
|
+
this.#undo.push(step);
|
|
28
|
+
}
|
|
29
|
+
async exists(path, env = this.env) {
|
|
30
|
+
const found = await env.exists(path, this.context);
|
|
31
|
+
return found.ok && found.value;
|
|
32
|
+
}
|
|
33
|
+
async tree(root, env = this.env) {
|
|
34
|
+
let top;
|
|
35
|
+
for (let dir = root; dir !== "/" && !await this.exists(dir, env); dir = dirname(dir))
|
|
36
|
+
top = dir;
|
|
37
|
+
if (top === void 0) return false;
|
|
38
|
+
const gone = top;
|
|
39
|
+
this.later(() => env.remove(gone, { recursive: true, force: true }, BACKGROUND_CONTEXT));
|
|
40
|
+
return true;
|
|
41
|
+
}
|
|
42
|
+
async put(path, content, fresh, env = this.env) {
|
|
43
|
+
this.check();
|
|
44
|
+
const bytes = typeof content === "string" ? encoder.encode(content) : content;
|
|
45
|
+
if (!fresh && !await this.tree(dirname(path), env)) {
|
|
46
|
+
const old = await env.readBinaryFile(path, this.context);
|
|
47
|
+
if (old.ok && same(old.value, bytes)) return false;
|
|
48
|
+
this.later(
|
|
49
|
+
() => old.ok ? env.writeFile(path, old.value, BACKGROUND_CONTEXT) : env.remove(path, { force: true }, BACKGROUND_CONTEXT)
|
|
50
|
+
);
|
|
51
|
+
}
|
|
52
|
+
done(await env.writeFile(path, bytes, this.context), path);
|
|
53
|
+
return true;
|
|
54
|
+
}
|
|
55
|
+
async sh(command) {
|
|
56
|
+
let err = "";
|
|
57
|
+
const ran = await this.env.exec(
|
|
58
|
+
command,
|
|
59
|
+
{
|
|
60
|
+
onOutput: (text, _context, info) => {
|
|
61
|
+
if (info.stream === "stderr") err += text;
|
|
62
|
+
}
|
|
63
|
+
},
|
|
64
|
+
this.context
|
|
65
|
+
);
|
|
66
|
+
const failed = ran.ok ? ran.value.exitCode === 0 ? "" : err.trim() || "it failed" : ran.error.message;
|
|
67
|
+
if (failed) throw new ImportError(`${command.split(" ")[0]}: ${failed}`);
|
|
68
|
+
}
|
|
69
|
+
async rollback() {
|
|
70
|
+
for (const step of this.#undo.reverse()) await step().catch(() => void 0);
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
async function ownTree(writer, user, home, roots) {
|
|
74
|
+
for (const root of roots) {
|
|
75
|
+
const parents = [];
|
|
76
|
+
for (let at = root.lastIndexOf("/"); at > home.length; at = root.lastIndexOf("/", at - 1))
|
|
77
|
+
parents.push(quote(root.slice(0, at)));
|
|
78
|
+
const owner = quote(`${user}:${user}`);
|
|
79
|
+
const lift = parents.length ? `chown ${owner} ${parents.join(" ")} && chmod 700 ${parents.join(" ")} && ` : "";
|
|
80
|
+
await writer.sh(`${lift}chown -R ${owner} ${quote(root)} && chmod -R u=rwX,go= ${quote(root)}`);
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
export {
|
|
84
|
+
Writer,
|
|
85
|
+
ownTree,
|
|
86
|
+
same
|
|
87
|
+
};
|
|
88
|
+
//# sourceMappingURL=v6-write.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../src/freezer/v6-write.ts"],
|
|
4
|
+
"sourcesContent": ["import type { Context } from '@earendil-works/chord';\nimport { BACKGROUND_CONTEXT } from '@earendil-works/chord/context';\nimport type { ExecutionEnv, Result } from '@earendil-works/pi-durable/env';\nimport { quote } from '../kernel/env.ts';\nimport { dirname } from '../kernel/paths.ts';\nimport { ImportError } from './zip.ts';\n\nconst encoder = new TextEncoder();\n\nexport function same(a: Uint8Array, b: Uint8Array): boolean {\n return a.length === b.length && a.every((byte, at) => byte === b[at]);\n}\n\nfunction done<T>(result: Result<T, { message: string }>, what: string): T {\n if (!result.ok) throw new ImportError(`couldn't write ${what}: ${result.error.message}`);\n return result.value;\n}\n\nexport class Writer {\n readonly #undo: (() => Promise<unknown>)[] = [];\n readonly env: ExecutionEnv;\n readonly context: Context;\n readonly signal: AbortSignal;\n\n constructor(env: ExecutionEnv, context: Context, signal: AbortSignal) {\n this.env = env;\n this.context = context;\n this.signal = signal;\n }\n\n check(): void {\n if (this.signal.aborted) throw new ImportError('the import was cancelled');\n }\n\n later(step: () => Promise<unknown>): void {\n this.#undo.push(step);\n }\n\n async exists(path: string, env = this.env): Promise<boolean> {\n const found = await env.exists(path, this.context);\n return found.ok && found.value;\n }\n\n async tree(root: string, env = this.env): Promise<boolean> {\n let top: string | undefined;\n for (let dir = root; dir !== '/' && !(await this.exists(dir, env)); dir = dirname(dir))\n top = dir;\n if (top === undefined) return false;\n const gone = top;\n this.later(() => env.remove(gone, { recursive: true, force: true }, BACKGROUND_CONTEXT));\n return true;\n }\n\n async put(path: string, content: Uint8Array | string, fresh: boolean, env = this.env) {\n this.check();\n const bytes = typeof content === 'string' ? encoder.encode(content) : content;\n if (!fresh && !(await this.tree(dirname(path), env))) {\n const old = await env.readBinaryFile(path, this.context);\n if (old.ok && same(old.value, bytes)) return false;\n this.later(() =>\n old.ok\n ? env.writeFile(path, old.value, BACKGROUND_CONTEXT)\n : env.remove(path, { force: true }, BACKGROUND_CONTEXT)\n );\n }\n done(await env.writeFile(path, bytes, this.context), path);\n return true;\n }\n\n async sh(command: string): Promise<void> {\n let err = '';\n const ran = await this.env.exec(\n command,\n {\n onOutput: (text, _context, info) => {\n if (info.stream === 'stderr') err += text;\n },\n },\n this.context\n );\n const failed = ran.ok\n ? ran.value.exitCode === 0\n ? ''\n : err.trim() || 'it failed'\n : ran.error.message;\n if (failed) throw new ImportError(`${command.split(' ')[0]}: ${failed}`);\n }\n\n async rollback(): Promise<void> {\n for (const step of this.#undo.reverse()) await step().catch(() => undefined);\n }\n}\n\nexport async function ownTree(writer: Writer, user: string, home: string, roots: Iterable<string>) {\n for (const root of roots) {\n const parents: string[] = [];\n for (let at = root.lastIndexOf('/'); at > home.length; at = root.lastIndexOf('/', at - 1))\n parents.push(quote(root.slice(0, at)));\n const owner = quote(`${user}:${user}`);\n const lift = parents.length\n ? `chown ${owner} ${parents.join(' ')} && chmod 700 ${parents.join(' ')} && `\n : '';\n await writer.sh(`${lift}chown -R ${owner} ${quote(root)} && chmod -R u=rwX,go= ${quote(root)}`);\n }\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|