@ai-ecoverse/slicc-agent 3.43.1 → 3.44.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 +12 -2
- package/dist/agent.js +1 -0
- package/dist/agent.js.map +2 -2
- package/dist/client.js +3 -1
- package/dist/client.js.map +2 -2
- package/dist/codemode/index.js +2 -1
- package/dist/codemode/index.js.map +2 -2
- package/dist/control.js +13 -3
- package/dist/control.js.map +2 -2
- package/dist/freezer/index.js +5 -4
- package/dist/freezer/index.js.map +2 -2
- package/dist/host.js +13 -2
- package/dist/host.js.map +2 -2
- package/dist/kernel/env.js +55 -4
- package/dist/kernel/env.js.map +2 -2
- package/dist/kernel/exec.js +84 -16
- package/dist/kernel/exec.js.map +3 -3
- package/dist/licks/licks.js +17 -1
- package/dist/licks/licks.js.map +2 -2
- package/dist/main.js +29 -10
- package/dist/main.js.map +2 -2
- package/dist/mcp/content.js +3 -1
- package/dist/mcp/content.js.map +2 -2
- package/dist/mcp/tools.js +2 -1
- package/dist/mcp/tools.js.map +2 -2
- package/dist/memory/prompt.js +3 -2
- package/dist/memory/prompt.js.map +2 -2
- package/dist/memory/store.js +5 -3
- package/dist/memory/store.js.map +2 -2
- package/dist/remote/host.js +21 -1
- package/dist/remote/host.js.map +2 -2
- package/dist/secrets/extension.js +150 -0
- package/dist/secrets/extension.js.map +7 -0
- package/dist/secrets/names.js +72 -0
- package/dist/secrets/names.js.map +7 -0
- package/dist/secrets/scrub.js +36 -0
- package/dist/secrets/scrub.js.map +7 -0
- package/dist/secrets/vault.js +161 -0
- package/dist/secrets/vault.js.map +7 -0
- package/dist/services.js.map +2 -2
- package/dist/skills/index.js +8 -1
- package/dist/skills/index.js.map +2 -2
- package/dist/spectrum/agent-port.js +6 -2
- package/dist/spectrum/agent-port.js.map +2 -2
- package/dist/types/agent.d.ts +1 -0
- package/dist/types/client.d.ts +2 -0
- package/dist/types/control.d.ts +2 -1
- package/dist/types/host.d.ts +9 -1
- package/dist/types/kernel/env.d.ts +6 -0
- package/dist/types/kernel/exec.d.ts +8 -1
- package/dist/types/licks/licks.d.ts +1 -0
- package/dist/types/mcp/content.d.ts +1 -1
- package/dist/types/remote/host.d.ts +5 -1
- package/dist/types/secrets/extension.d.ts +31 -0
- package/dist/types/secrets/names.d.ts +24 -0
- package/dist/types/secrets/scrub.d.ts +21 -0
- package/dist/types/secrets/vault.d.ts +30 -0
- package/dist/types/services.d.ts +3 -1
- package/dist/types/skills/index.d.ts +1 -0
- package/dist/types/spectrum/agent-port.d.ts +2 -0
- package/package.json +3 -3
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../src/freezer/index.ts"],
|
|
4
|
-
"sourcesContent": ["import { type Context, type ReplicatedState, replicatedState } from '@earendil-works/chord';\nimport { BACKGROUND_CONTEXT } from '@earendil-works/chord/context';\nimport type {\n Conversation,\n ConversationId,\n EntryRecord,\n Harness,\n} from '@earendil-works/pi-durable';\nimport type { ExecutionEnv } from '@earendil-works/pi-durable/env';\nimport { answerText } from '../agent.ts';\nimport {\n type Agents,\n type AgentsState,\n type FrozenRecord,\n live,\n type ScoopRecord,\n} from '../agents.ts';\nimport { HOME } from '../kernel/env.ts';\nimport type { LickTarget } from '../licks/lick.ts';\nimport { SCOOPS_ROOT, workspace } from '../scoops/service.ts';\n\nexport type Answer = { code: number; out: string };\n\nexport type ConversationKind = 'cone' | 'scoop' | 'agent';\n\nexport interface FrozenCone {\n id: string;\n name: string;\n title: string;\n model: string;\n messages: number;\n frozenAt: number;\n kind: ConversationKind;\n live: boolean;\n thawedAs: string | null;\n}\n\nexport const THAWED_KIND = 'slicc.thawed';\n\nexport type Frozen = { id: string; name: string; at: number };\n\nexport interface FreezerAttach {\n harness: Harness;\n agents: Agents;\n env: Pick<ExecutionEnv, 'remove' | 'exists'>;\n title?: (transcript: string, model: string, context: Context) => Promise<string | undefined>;\n extract?: (\n conversation: number,\n tail: number,\n context: Context,\n cone: string\n ) => Promise<unknown>;\n now?: () => number;\n}\n\nexport interface FreezerRuntime {\n readonly frozen: ReplicatedState<FrozenCone[]>;\n freeze(agentId: string, context: Context): Promise<string>;\n newChat(agentId: string, context: Context): Promise<string | null>;\n thaw(id: string, context: Context): Promise<string>;\n discard(id: string, context: Context): Promise<void>;\n refresh(): Promise<readonly FrozenCone[]>;\n touch(): void;\n frozenTarget(target: LickTarget): Frozen | undefined;\n command(argv: readonly string[], caller: string | null, context: Context): Promise<Answer>;\n close(): void;\n}\n\nexport const USAGE = `usage:\n freezer list every conversation: id, kind, name, title, messages, when\n freezer show <id> a conversation as Markdown\n freezer thaw <id> continue a stopped conversation as a cone\n\nDelete a cone, or start a new conversation, from the chat toolbar or the command palette.\n`;\n\nconst TITLE_LENGTH = 60;\nexport const TOUCH_MS = 500;\n\nfunction textOf(entry: EntryRecord): string {\n return answerText(entry.model?.[0]?.content).trim();\n}\n\nexport function modelName(model: { provider: string; modelId: string } | undefined): string {\n return model ? `${model.provider}/${model.modelId}` : '';\n}\n\nexport function firstLine(entries: readonly EntryRecord[]): string {\n const first = entries.find((entry) => entry.kind === 'pi.user' && textOf(entry));\n const line = first ? (textOf(first).split('\\n')[0] as string).trim() : '';\n if (!line) return 'Untitled chat';\n return line.length > TITLE_LENGTH ? `${line.slice(0, TITLE_LENGTH - 1)}\u2026` : line;\n}\n\nfunction calls(entry: EntryRecord): string[] {\n const content = entry.model?.[0]?.content;\n if (!Array.isArray(content)) return [];\n return (content as { type: string; name?: string; arguments?: unknown }[])\n .filter((part) => part.type === 'toolCall')\n .map((part) => `- \\`${part.name}\\` ${JSON.stringify(part.arguments ?? {})}`);\n}\n\nexport function markdown(\n record: Pick<FrozenRecord, 'title' | 'name' | 'model' | 'frozenAt'>,\n entries: readonly EntryRecord[]\n): string {\n const out = [\n `# ${record.title}`,\n '',\n `${record.name} \u00B7 ${record.model} \u00B7 ${new Date(record.frozenAt).toISOString()}`,\n ];\n for (const entry of entries) {\n if (entry.kind === 'pi.user' && textOf(entry)) out.push('', '## User', '', textOf(entry));\n if (entry.kind !== 'pi.assistant') continue;\n const text = textOf(entry);\n const tools = calls(entry);\n if (!text && !tools.length) continue;\n out.push('', '## Assistant', '');\n if (text) out.push(text);\n if (tools.length) out.push(...(text ? [''] : []), ...tools);\n }\n return `${out.join('\\n')}\\n`;\n}\n\ntype Stats = Pick<FrozenCone, 'title' | 'model' | 'messages' | 'frozenAt'>;\n\nfunction counted(entries: readonly EntryRecord[]): number {\n return entries.filter((entry) => entry.kind === 'pi.user' || entry.kind === 'pi.assistant')\n .length;\n}\n\nfunction lastAt(entries: readonly EntryRecord[]): number {\n let at = 0;\n for (const entry of entries)\n for (const message of entry.model ?? []) {\n const stamp = (message as { timestamp?: unknown }).timestamp;\n if (typeof stamp === 'number' && stamp > at) at = stamp;\n }\n return at;\n}\n\nasync function statsOf(harness: Harness, id: number, context: Context): Promise<Stats> {\n const conversation = await harness.conversation(id as ConversationId, context);\n if (!conversation) return { title: firstLine([]), model: '', messages: 0, frozenAt: 0 };\n const view = await conversation.context(context);\n const agent = await conversation.agent(context);\n return {\n title: firstLine(view.entries),\n model: modelName(agent.model),\n messages: counted(view.entries),\n frozenAt: lastAt(view.entries),\n };\n}\n\nconst kindOf = (scoop: ScoopRecord): ConversationKind =>\n scoop.kind === 'sync' ? 'agent' : 'scoop';\n\nasync function rows(\n harness: Harness,\n state: Readonly<AgentsState>,\n cache: Map<number, Stats>,\n context: Context\n): Promise<FrozenCone[]> {\n const stats = async (conversation: number, stopped: boolean) => {\n const cached = stopped ? cache.get(conversation) : undefined;\n if (cached) return cached;\n const found = await statsOf(harness, conversation, context);\n if (stopped) cache.set(conversation, found);\n return found;\n };\n const out: FrozenCone[] = [];\n for (const [id, cone] of Object.entries(state.cones))\n out.push({\n id,\n name: cone.name,\n ...(await stats(cone.conversation, false)),\n kind: 'cone',\n live: true,\n thawedAs: null,\n });\n for (const [id, record] of Object.entries(state.frozen ?? {}))\n out.push({\n id,\n name: record.name,\n title: record.title,\n model: record.model,\n messages: record.messages,\n frozenAt: record.frozenAt,\n kind: 'cone',\n live: false,\n thawedAs: null,\n });\n for (const [id, scoop] of Object.entries(state.scoops)) {\n if (scoop.removed) continue;\n const running = live(scoop);\n out.push({\n id,\n name: scoop.name,\n ...(await stats(scoop.conversation, !running)),\n kind: kindOf(scoop),\n live: running,\n thawedAs: scoop.thawedAs ?? null,\n });\n }\n return out.sort((a, b) => Number(b.live) - Number(a.live) || b.frozenAt - a.frozenAt);\n}\n\nexport function thawedNote(\n kind: ConversationKind,\n name: string,\n folder: string,\n kept: boolean\n): string {\n const what = kind === 'agent' ? 'agent run' : kind;\n const place = kept\n ? `Its workspace ${folder} is still there.`\n : `Its workspace ${folder} was deleted when it stopped.`;\n return `This was ${what} ${name}'s conversation, thawed as a cone. ${place} You now work in ${HOME} as a cone, with a cone's tools.`;\n}\n\ntype Snapshot = { entries: readonly EntryRecord[]; record: Omit<FrozenRecord, 'scoops' | 'cone'> };\n\nasync function snapshot(\n conversation: Conversation,\n name: string,\n now: number,\n context: Context\n): Promise<Snapshot> {\n const view = await conversation.context(context);\n const agent = await conversation.agent(context);\n return {\n entries: view.entries,\n record: {\n name,\n conversation: conversation.id,\n title: firstLine(view.entries),\n model: modelName(agent.model),\n messages: counted(view.entries),\n frozenAt: now,\n },\n };\n}\n\nexport function frozenTarget(state: Readonly<AgentsState>, target: LickTarget): Frozen | undefined {\n const records = Object.entries(state.frozen ?? {});\n if (target.startsWith('cone:')) {\n const cone = target.slice('cone:'.length);\n if (state.cones[cone]) return undefined;\n const found = records\n .filter(([, record]) => record.cone === cone)\n .sort(([, a], [, b]) => b.frozenAt - a.frozenAt)[0];\n return found ? { id: found[0], name: found[1].name, at: found[1].frozenAt } : undefined;\n }\n const owner = state.scoops[target]?.frozen;\n const record = owner ? state.frozen?.[owner] : undefined;\n return owner && record ? { id: owner, name: record.name, at: record.frozenAt } : undefined;\n}\n\nasync function command(\n options: FreezerAttach,\n runtime: FreezerRuntime,\n argv: readonly string[],\n context: Context\n): Promise<Answer> {\n const verb = argv[0] ?? 'help';\n const listed = await runtime.refresh();\n if (verb === 'list') {\n const lines = listed.map(\n (item) =>\n `${item.id}\\t${item.kind}${item.live ? ' (live)' : ''}\\t${item.name}\\t${item.title}\\t${item.messages} messages\\t${new Date(item.frozenAt).toISOString()}`\n );\n return { code: 0, out: lines.length ? `${lines.join('\\n')}\\n` : 'no conversations\\n' };\n }\n if (verb !== 'show' && verb !== 'thaw')\n return { code: verb === 'help' || verb === '--help' ? 0 : 2, out: USAGE };\n const id = argv[1] ?? '';\n const item = listed.find((row) => row.id === id);\n if (!item) return { code: 1, out: `freezer: there is no conversation ${id}\\n` };\n if (verb === 'thaw') {\n if (item.live) return { code: 1, out: `freezer: ${item.name} is live; it needs no thawing\\n` };\n return { code: 0, out: `thawed ${id} as ${await runtime.thaw(id, context)}\\n` };\n }\n const state = options.agents.state();\n const conversationId =\n state.frozen?.[id]?.conversation ??\n state.cones[id]?.conversation ??\n state.scoops[id]?.conversation;\n const conversation = await options.harness.conversation(\n conversationId as ConversationId,\n context\n );\n const entries = conversation ? (await conversation.context(context)).entries : [];\n return { code: 0, out: markdown(item, entries) };\n}\n\nasync function freshLike(\n harness: Harness,\n conversation: Conversation,\n context: Context\n): Promise<Conversation> {\n const agent = await conversation.agent(context);\n return harness.createConversation(\n {\n ownership: { kind: 'ownerless' },\n agent: {\n model: agent.model,\n thinkingLevel: agent.thinkingLevel,\n extensions: agent.extensions,\n tools: agent.tools,\n instructions: agent.instructions ?? null,\n cwd: agent.cwd ?? null,\n },\n },\n context\n );\n}\n\nasync function activeCone(agents: Agents, context: Context): Promise<Conversation> {\n const conversation = await agents.conversation(agents.state().active, context);\n if (!conversation) throw new Error('There is no active cone.');\n return conversation;\n}\n\nasync function thawScoop(\n options: FreezerAttach & { now: () => number },\n id: string,\n scoop: ScoopRecord,\n context: Context\n): Promise<string> {\n const { harness, agents, env, now } = options;\n if (scoop.removed) throw new Error(`There is no conversation ${id}.`);\n if (live(scoop)) throw new Error(`${scoop.name} is still running; open it instead.`);\n const conversation = await harness.conversation(scoop.conversation as ConversationId, context);\n if (!conversation) throw new Error(`There is no conversation ${id}.`);\n const last = (await conversation.context(context)).entries.at(-1);\n const agent = await conversation.agent(context);\n const cone = await (await activeCone(agents, context)).agent(context);\n const created = {\n ownership: { kind: 'ownerless' as const },\n agent: {\n model: agent.model as NonNullable<typeof agent.model>,\n thinkingLevel: agent.thinkingLevel,\n extensions: cone.extensions,\n tools: cone.tools,\n instructions: cone.instructions ?? null,\n cwd: HOME,\n },\n };\n const fork = last\n ? await conversation.fork(last.id, created, context)\n : await harness.createConversation(created, context);\n const folder = workspace(scoop.folder);\n const exists = await env.exists(folder, context);\n const kept = exists.ok && exists.value;\n await fork.submit(\n {\n type: 'write',\n entry: {\n kind: THAWED_KIND,\n data: { scoop: id, name: scoop.name, kind: kindOf(scoop), workspace: folder, kept },\n model: [\n {\n role: 'user',\n content: thawedNote(kindOf(scoop), scoop.name, folder, kept),\n timestamp: now(),\n },\n ],\n },\n },\n context\n );\n const coneId = await agents.update((_tx, doc) => {\n const target = `cone-${doc.next}`;\n doc.next += 1;\n doc.cones[target] = { name: scoop.name, conversation: fork.id };\n (doc.scoops[id] as ScoopRecord).thawedAs = target;\n return target;\n }, context);\n await agents.selectCone(coneId, context);\n return coneId;\n}\n\nasync function removeScoop(\n options: FreezerAttach,\n id: string,\n scoop: ScoopRecord,\n context: Context\n): Promise<void> {\n const { agents, env } = options;\n if (live(scoop)) throw new Error(`${scoop.name} is still running; stop it first.`);\n await agents.update((_tx, doc) => {\n const entry = doc.scoops[id] as ScoopRecord;\n entry.removed = true;\n entry.gone = true;\n delete entry.frozen;\n }, context);\n await env.remove(`${SCOOPS_ROOT}/${scoop.folder}`, { recursive: true, force: true }, context);\n}\n\nfunction listing(harness: Harness, agents: Agents) {\n const frozen = replicatedState<FrozenCone[]>([]);\n const cache = new Map<number, Stats>();\n let lock: Promise<readonly FrozenCone[]> = Promise.resolve([]);\n const refresh = () => {\n lock = lock\n .catch(() => [])\n .then(async () => {\n const listed = await rows(harness, agents.state(), cache, BACKGROUND_CONTEXT);\n frozen.replace(BACKGROUND_CONTEXT, listed);\n return listed;\n });\n return lock;\n };\n const quiet = () => void refresh().catch(() => undefined);\n quiet();\n const stop = agents.onChange(quiet);\n let timer: ReturnType<typeof setTimeout> | undefined;\n const touch = () => {\n clearTimeout(timer);\n timer = setTimeout(quiet, TOUCH_MS);\n };\n const off = () => {\n clearTimeout(timer);\n stop();\n };\n return { frozen, refresh, touch, off };\n}\n\nasync function thawFrozen(agents: Agents, id: string, context: Context): Promise<string> {\n const coneId = await agents.update((_tx, doc) => {\n const record = doc.frozen?.[id];\n if (!record) throw new Error(`There is no frozen chat ${id}.`);\n const reuse = !doc.cones[record.cone];\n const target = reuse ? record.cone : `cone-${doc.next}`;\n if (!reuse) doc.next += 1;\n doc.cones[target] = { name: record.name, conversation: record.conversation };\n for (const scoop of record.scoops) {\n const entry = doc.scoops[scoop];\n if (!entry) continue;\n delete entry.frozen;\n entry.cone = target;\n }\n delete doc.frozen?.[id];\n return target;\n }, context);\n await agents.selectCone(coneId, context);\n return coneId;\n}\n\nasync function discardFrozen(options: FreezerAttach, id: string, context: Context) {\n const { agents, env } = options;\n const record = agents.state().frozen?.[id];\n if (!record) throw new Error(`There is no frozen chat ${id}.`);\n const folders = record.scoops\n .map((scoop) => agents.state().scoops[scoop]?.folder)\n .filter((folder): folder is string => Boolean(folder));\n await agents.update((_tx, doc) => {\n for (const scoop of record.scoops) {\n const entry = doc.scoops[scoop];\n if (!entry) continue;\n delete entry.frozen;\n entry.gone = true;\n }\n delete doc.frozen?.[id];\n }, context);\n for (const folder of folders)\n await env.remove(`${SCOOPS_ROOT}/${folder}`, { recursive: true, force: true }, context);\n}\n\nexport function attachFreezer(options: FreezerAttach): FreezerRuntime {\n const { harness, agents } = options;\n const now = options.now ?? Date.now;\n const { frozen, refresh, touch, off } = listing(harness, agents);\n const conversationOf = async (agentId: string, context: Context) => {\n const conversation = await agents.conversation(agentId, context);\n if (!conversation) throw new Error(`There is no cone ${agentId}.`);\n return conversation;\n };\n const prepare = async (\n conversation: Conversation,\n entries: readonly EntryRecord[],\n cone: string,\n context: Context\n ) => {\n const tail = entries.at(-1)?.id ?? 0;\n await options.extract?.(conversation.id, tail, context, cone).catch(() => undefined);\n };\n const retitle = (\n id: string,\n model: string,\n entries: readonly EntryRecord[],\n context: Context\n ) => {\n if (!options.title) return;\n const transcript = entries\n .filter((entry) => entry.kind === 'pi.user' || entry.kind === 'pi.assistant')\n .map((entry) => `${entry.kind === 'pi.user' ? 'User' : 'Agent'}: ${textOf(entry)}`)\n .join('\\n')\n .slice(0, 4000);\n void options\n .title(transcript, model, context)\n .then(async (title) => {\n const clean = title\n ?.replace(/\\s+/g, ' ')\n .replace(/^[\"'\u201C\u201D]+|[\"'\u201C\u201D]+$/g, '')\n .replace(/\\.+$/, '')\n .trim();\n if (!clean) return;\n await agents.update((_tx, doc) => {\n const record = doc.frozen?.[id];\n if (record) record.title = clean.slice(0, TITLE_LENGTH);\n }, context);\n })\n .catch(() => undefined);\n };\n const replacement = async (coneId: string, context: Context) => {\n const state = agents.state();\n const other = Object.keys(state.cones).find((id) => id !== coneId);\n if (other) return { id: other, conversation: undefined };\n const current = await conversationOf(coneId, context);\n const conversation = await harness.createConversation(\n {\n ownership: { kind: 'ownerless' },\n agent: { model: (await current.agent(context)).model },\n },\n context\n );\n return { id: `cone-${state.next}`, conversation };\n };\n const runtime: FreezerRuntime = {\n frozen,\n async freeze(agentId, context) {\n const cone = agents.state().cones[agentId];\n if (!cone) throw new Error(`There is no cone ${agentId}.`);\n const conversation = await conversationOf(agentId, context);\n const { entries, record } = await snapshot(conversation, cone.name, now(), context);\n await prepare(conversation, entries, agentId, context);\n await conversation.abort(context, { background: true }).catch(() => undefined);\n const next =\n agents.state().active === agentId ? await replacement(agentId, context) : undefined;\n const { id, scoops } = await agents.update((_tx, doc) => {\n if (!doc.cones[agentId]) throw new Error(`There is no cone ${agentId}.`);\n const frozenId = `frozen-${doc.frozenNext ?? 1}`;\n const owned = Object.entries(doc.scoops)\n .filter(([, scoop]) => scoop.cone === agentId && live(scoop))\n .map(([scoop]) => scoop);\n doc.frozenNext = (doc.frozenNext ?? 1) + 1;\n doc.frozen ??= {};\n doc.frozen[frozenId] = { ...record, cone: agentId, scoops: owned };\n delete doc.cones[agentId];\n for (const scoop of owned) (doc.scoops[scoop] as { frozen?: string }).frozen = frozenId;\n if (next?.conversation) {\n doc.cones[next.id] = { name: record.name, conversation: next.conversation.id };\n doc.next += 1;\n }\n return { id: frozenId, scoops: owned };\n }, context);\n for (const scoop of scoops)\n await (await agents.conversation(scoop, context))?.abort(context).catch(() => undefined);\n if (next) await agents.selectCone(next.id, context);\n retitle(id, record.model, entries, context);\n return id;\n },\n async newChat(agentId, context) {\n const cone = agents.state().cones[agentId];\n const scoop = agents.state().scoops[agentId];\n if (!cone && scoop && live(scoop)) {\n await (await agents.conversation(agentId, context))?.reset(undefined, context);\n return null;\n }\n if (!cone) throw new Error(`There is no cone ${agentId}.`);\n const conversation = await conversationOf(agentId, context);\n const before = (await conversation.context(context)).entries;\n if (!before.some((entry) => entry.kind === 'pi.user')) return null;\n const fresh = await freshLike(harness, conversation, context);\n await agents.setConversation(agentId, fresh, context);\n await conversation.abort(context).catch(() => undefined);\n const { entries, record } = await snapshot(conversation, cone.name, now(), context);\n await prepare(conversation, entries, agentId, context);\n const id = await agents.update((_tx, doc) => {\n const frozenId = `frozen-${doc.frozenNext ?? 1}`;\n doc.frozenNext = (doc.frozenNext ?? 1) + 1;\n doc.frozen ??= {};\n doc.frozen[frozenId] = { ...record, cone: agentId, scoops: [] };\n return frozenId;\n }, context);\n retitle(id, record.model, entries, context);\n return id;\n },\n async thaw(id, context) {\n const state = agents.state();\n if (state.cones[id]) {\n await agents.selectCone(id, context);\n return id;\n }\n const scoop = state.scoops[id];\n if (scoop) return thawScoop({ ...options, now }, id, scoop, context);\n return thawFrozen(agents, id, context);\n },\n async discard(id, context) {\n const state = agents.state();\n const scoop = state.scoops[id];\n if (scoop) return removeScoop(options, id, scoop, context);\n const cone = state.cones[id];\n if (cone) throw new Error(`${cone.name} is live; delete the cone first.`);\n return discardFrozen(options, id, context);\n },\n refresh,\n touch,\n frozenTarget: (target) => frozenTarget(agents.state(), target),\n command: (argv, _caller, context) => command(options, runtime, argv, context),\n close: () => off(),\n };\n return runtime;\n}\n"],
|
|
5
|
-
"mappings": "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",
|
|
4
|
+
"sourcesContent": ["import { type Context, type ReplicatedState, replicatedState } from '@earendil-works/chord';\nimport { BACKGROUND_CONTEXT } from '@earendil-works/chord/context';\nimport type {\n Conversation,\n ConversationId,\n EntryRecord,\n Harness,\n} from '@earendil-works/pi-durable';\nimport type { ExecutionEnv } from '@earendil-works/pi-durable/env';\nimport { answerText } from '../agent.ts';\nimport {\n type Agents,\n type AgentsState,\n type FrozenRecord,\n live,\n type ScoopRecord,\n} from '../agents.ts';\nimport { HOME } from '../kernel/env.ts';\nimport type { LickTarget } from '../licks/lick.ts';\nimport { SCOOPS_ROOT, workspace } from '../scoops/service.ts';\nimport { pinned } from '../secrets/extension.ts';\n\nexport type Answer = { code: number; out: string };\n\nexport type ConversationKind = 'cone' | 'scoop' | 'agent';\n\nexport interface FrozenCone {\n id: string;\n name: string;\n title: string;\n model: string;\n messages: number;\n frozenAt: number;\n kind: ConversationKind;\n live: boolean;\n thawedAs: string | null;\n}\n\nexport const THAWED_KIND = 'slicc.thawed';\n\nexport type Frozen = { id: string; name: string; at: number };\n\nexport interface FreezerAttach {\n harness: Harness;\n agents: Agents;\n env: Pick<ExecutionEnv, 'remove' | 'exists'>;\n title?: (transcript: string, model: string, context: Context) => Promise<string | undefined>;\n extract?: (\n conversation: number,\n tail: number,\n context: Context,\n cone: string\n ) => Promise<unknown>;\n now?: () => number;\n}\n\nexport interface FreezerRuntime {\n readonly frozen: ReplicatedState<FrozenCone[]>;\n freeze(agentId: string, context: Context): Promise<string>;\n newChat(agentId: string, context: Context): Promise<string | null>;\n thaw(id: string, context: Context): Promise<string>;\n discard(id: string, context: Context): Promise<void>;\n refresh(): Promise<readonly FrozenCone[]>;\n touch(): void;\n frozenTarget(target: LickTarget): Frozen | undefined;\n command(argv: readonly string[], caller: string | null, context: Context): Promise<Answer>;\n close(): void;\n}\n\nexport const USAGE = `usage:\n freezer list every conversation: id, kind, name, title, messages, when\n freezer show <id> a conversation as Markdown\n freezer thaw <id> continue a stopped conversation as a cone\n\nDelete a cone, or start a new conversation, from the chat toolbar or the command palette.\n`;\n\nconst TITLE_LENGTH = 60;\nexport const TOUCH_MS = 500;\n\nfunction textOf(entry: EntryRecord): string {\n return answerText(entry.model?.[0]?.content).trim();\n}\n\nexport function modelName(model: { provider: string; modelId: string } | undefined): string {\n return model ? `${model.provider}/${model.modelId}` : '';\n}\n\nexport function firstLine(entries: readonly EntryRecord[]): string {\n const first = entries.find((entry) => entry.kind === 'pi.user' && textOf(entry));\n const line = first ? (textOf(first).split('\\n')[0] as string).trim() : '';\n if (!line) return 'Untitled chat';\n return line.length > TITLE_LENGTH ? `${line.slice(0, TITLE_LENGTH - 1)}\u2026` : line;\n}\n\nfunction calls(entry: EntryRecord): string[] {\n const content = entry.model?.[0]?.content;\n if (!Array.isArray(content)) return [];\n return (content as { type: string; name?: string; arguments?: unknown }[])\n .filter((part) => part.type === 'toolCall')\n .map((part) => `- \\`${part.name}\\` ${JSON.stringify(part.arguments ?? {})}`);\n}\n\nexport function markdown(\n record: Pick<FrozenRecord, 'title' | 'name' | 'model' | 'frozenAt'>,\n entries: readonly EntryRecord[]\n): string {\n const out = [\n `# ${record.title}`,\n '',\n `${record.name} \u00B7 ${record.model} \u00B7 ${new Date(record.frozenAt).toISOString()}`,\n ];\n for (const entry of entries) {\n if (entry.kind === 'pi.user' && textOf(entry)) out.push('', '## User', '', textOf(entry));\n if (entry.kind !== 'pi.assistant') continue;\n const text = textOf(entry);\n const tools = calls(entry);\n if (!text && !tools.length) continue;\n out.push('', '## Assistant', '');\n if (text) out.push(text);\n if (tools.length) out.push(...(text ? [''] : []), ...tools);\n }\n return `${out.join('\\n')}\\n`;\n}\n\ntype Stats = Pick<FrozenCone, 'title' | 'model' | 'messages' | 'frozenAt'>;\n\nfunction counted(entries: readonly EntryRecord[]): number {\n return entries.filter((entry) => entry.kind === 'pi.user' || entry.kind === 'pi.assistant')\n .length;\n}\n\nfunction lastAt(entries: readonly EntryRecord[]): number {\n let at = 0;\n for (const entry of entries)\n for (const message of entry.model ?? []) {\n const stamp = (message as { timestamp?: unknown }).timestamp;\n if (typeof stamp === 'number' && stamp > at) at = stamp;\n }\n return at;\n}\n\nasync function statsOf(harness: Harness, id: number, context: Context): Promise<Stats> {\n const conversation = await harness.conversation(id as ConversationId, context);\n if (!conversation) return { title: firstLine([]), model: '', messages: 0, frozenAt: 0 };\n const view = await conversation.context(context);\n const agent = await conversation.agent(context);\n return {\n title: firstLine(view.entries),\n model: modelName(agent.model),\n messages: counted(view.entries),\n frozenAt: lastAt(view.entries),\n };\n}\n\nconst kindOf = (scoop: ScoopRecord): ConversationKind =>\n scoop.kind === 'sync' ? 'agent' : 'scoop';\n\nasync function rows(\n harness: Harness,\n state: Readonly<AgentsState>,\n cache: Map<number, Stats>,\n context: Context\n): Promise<FrozenCone[]> {\n const stats = async (conversation: number, stopped: boolean) => {\n const cached = stopped ? cache.get(conversation) : undefined;\n if (cached) return cached;\n const found = await statsOf(harness, conversation, context);\n if (stopped) cache.set(conversation, found);\n return found;\n };\n const out: FrozenCone[] = [];\n for (const [id, cone] of Object.entries(state.cones))\n out.push({\n id,\n name: cone.name,\n ...(await stats(cone.conversation, false)),\n kind: 'cone',\n live: true,\n thawedAs: null,\n });\n for (const [id, record] of Object.entries(state.frozen ?? {}))\n out.push({\n id,\n name: record.name,\n title: record.title,\n model: record.model,\n messages: record.messages,\n frozenAt: record.frozenAt,\n kind: 'cone',\n live: false,\n thawedAs: null,\n });\n for (const [id, scoop] of Object.entries(state.scoops)) {\n if (scoop.removed) continue;\n const running = live(scoop);\n out.push({\n id,\n name: scoop.name,\n ...(await stats(scoop.conversation, !running)),\n kind: kindOf(scoop),\n live: running,\n thawedAs: scoop.thawedAs ?? null,\n });\n }\n return out.sort((a, b) => Number(b.live) - Number(a.live) || b.frozenAt - a.frozenAt);\n}\n\nexport function thawedNote(\n kind: ConversationKind,\n name: string,\n folder: string,\n kept: boolean\n): string {\n const what = kind === 'agent' ? 'agent run' : kind;\n const place = kept\n ? `Its workspace ${folder} is still there.`\n : `Its workspace ${folder} was deleted when it stopped.`;\n return `This was ${what} ${name}'s conversation, thawed as a cone. ${place} You now work in ${HOME} as a cone, with a cone's tools.`;\n}\n\ntype Snapshot = { entries: readonly EntryRecord[]; record: Omit<FrozenRecord, 'scoops' | 'cone'> };\n\nasync function snapshot(\n conversation: Conversation,\n name: string,\n now: number,\n context: Context\n): Promise<Snapshot> {\n const view = await conversation.context(context);\n const agent = await conversation.agent(context);\n return {\n entries: view.entries,\n record: {\n name,\n conversation: conversation.id,\n title: firstLine(view.entries),\n model: modelName(agent.model),\n messages: counted(view.entries),\n frozenAt: now,\n },\n };\n}\n\nexport function frozenTarget(state: Readonly<AgentsState>, target: LickTarget): Frozen | undefined {\n const records = Object.entries(state.frozen ?? {});\n if (target.startsWith('cone:')) {\n const cone = target.slice('cone:'.length);\n if (state.cones[cone]) return undefined;\n const found = records\n .filter(([, record]) => record.cone === cone)\n .sort(([, a], [, b]) => b.frozenAt - a.frozenAt)[0];\n return found ? { id: found[0], name: found[1].name, at: found[1].frozenAt } : undefined;\n }\n const owner = state.scoops[target]?.frozen;\n const record = owner ? state.frozen?.[owner] : undefined;\n return owner && record ? { id: owner, name: record.name, at: record.frozenAt } : undefined;\n}\n\nasync function command(\n options: FreezerAttach,\n runtime: FreezerRuntime,\n argv: readonly string[],\n context: Context\n): Promise<Answer> {\n const verb = argv[0] ?? 'help';\n const listed = await runtime.refresh();\n if (verb === 'list') {\n const lines = listed.map(\n (item) =>\n `${item.id}\\t${item.kind}${item.live ? ' (live)' : ''}\\t${item.name}\\t${item.title}\\t${item.messages} messages\\t${new Date(item.frozenAt).toISOString()}`\n );\n return { code: 0, out: lines.length ? `${lines.join('\\n')}\\n` : 'no conversations\\n' };\n }\n if (verb !== 'show' && verb !== 'thaw')\n return { code: verb === 'help' || verb === '--help' ? 0 : 2, out: USAGE };\n const id = argv[1] ?? '';\n const item = listed.find((row) => row.id === id);\n if (!item) return { code: 1, out: `freezer: there is no conversation ${id}\\n` };\n if (verb === 'thaw') {\n if (item.live) return { code: 1, out: `freezer: ${item.name} is live; it needs no thawing\\n` };\n return { code: 0, out: `thawed ${id} as ${await runtime.thaw(id, context)}\\n` };\n }\n const state = options.agents.state();\n const conversationId =\n state.frozen?.[id]?.conversation ??\n state.cones[id]?.conversation ??\n state.scoops[id]?.conversation;\n const conversation = await options.harness.conversation(\n conversationId as ConversationId,\n context\n );\n const entries = conversation ? (await conversation.context(context)).entries : [];\n return { code: 0, out: markdown(item, entries) };\n}\n\nasync function freshLike(\n harness: Harness,\n conversation: Conversation,\n context: Context\n): Promise<Conversation> {\n const agent = await conversation.agent(context);\n return harness.createConversation(\n {\n ownership: { kind: 'ownerless' },\n agent: pinned({\n model: agent.model,\n thinkingLevel: agent.thinkingLevel,\n extensions: agent.extensions,\n tools: agent.tools,\n instructions: agent.instructions ?? null,\n cwd: agent.cwd ?? null,\n }),\n },\n context\n );\n}\n\nasync function activeCone(agents: Agents, context: Context): Promise<Conversation> {\n const conversation = await agents.conversation(agents.state().active, context);\n if (!conversation) throw new Error('There is no active cone.');\n return conversation;\n}\n\nasync function thawScoop(\n options: FreezerAttach & { now: () => number },\n id: string,\n scoop: ScoopRecord,\n context: Context\n): Promise<string> {\n const { harness, agents, env, now } = options;\n if (scoop.removed) throw new Error(`There is no conversation ${id}.`);\n if (live(scoop)) throw new Error(`${scoop.name} is still running; open it instead.`);\n const conversation = await harness.conversation(scoop.conversation as ConversationId, context);\n if (!conversation) throw new Error(`There is no conversation ${id}.`);\n const last = (await conversation.context(context)).entries.at(-1);\n const agent = await conversation.agent(context);\n const cone = await (await activeCone(agents, context)).agent(context);\n const created = {\n ownership: { kind: 'ownerless' as const },\n agent: pinned({\n model: agent.model as NonNullable<typeof agent.model>,\n thinkingLevel: agent.thinkingLevel,\n extensions: cone.extensions,\n tools: cone.tools,\n instructions: cone.instructions ?? null,\n cwd: HOME,\n }),\n };\n const fork = last\n ? await conversation.fork(last.id, created, context)\n : await harness.createConversation(created, context);\n const folder = workspace(scoop.folder);\n const exists = await env.exists(folder, context);\n const kept = exists.ok && exists.value;\n await fork.submit(\n {\n type: 'write',\n entry: {\n kind: THAWED_KIND,\n data: { scoop: id, name: scoop.name, kind: kindOf(scoop), workspace: folder, kept },\n model: [\n {\n role: 'user',\n content: thawedNote(kindOf(scoop), scoop.name, folder, kept),\n timestamp: now(),\n },\n ],\n },\n },\n context\n );\n const coneId = await agents.update((_tx, doc) => {\n const target = `cone-${doc.next}`;\n doc.next += 1;\n doc.cones[target] = { name: scoop.name, conversation: fork.id };\n (doc.scoops[id] as ScoopRecord).thawedAs = target;\n return target;\n }, context);\n await agents.selectCone(coneId, context);\n return coneId;\n}\n\nasync function removeScoop(\n options: FreezerAttach,\n id: string,\n scoop: ScoopRecord,\n context: Context\n): Promise<void> {\n const { agents, env } = options;\n if (live(scoop)) throw new Error(`${scoop.name} is still running; stop it first.`);\n await agents.update((_tx, doc) => {\n const entry = doc.scoops[id] as ScoopRecord;\n entry.removed = true;\n entry.gone = true;\n delete entry.frozen;\n }, context);\n await env.remove(`${SCOOPS_ROOT}/${scoop.folder}`, { recursive: true, force: true }, context);\n}\n\nfunction listing(harness: Harness, agents: Agents) {\n const frozen = replicatedState<FrozenCone[]>([]);\n const cache = new Map<number, Stats>();\n let lock: Promise<readonly FrozenCone[]> = Promise.resolve([]);\n const refresh = () => {\n lock = lock\n .catch(() => [])\n .then(async () => {\n const listed = await rows(harness, agents.state(), cache, BACKGROUND_CONTEXT);\n frozen.replace(BACKGROUND_CONTEXT, listed);\n return listed;\n });\n return lock;\n };\n const quiet = () => void refresh().catch(() => undefined);\n quiet();\n const stop = agents.onChange(quiet);\n let timer: ReturnType<typeof setTimeout> | undefined;\n const touch = () => {\n clearTimeout(timer);\n timer = setTimeout(quiet, TOUCH_MS);\n };\n const off = () => {\n clearTimeout(timer);\n stop();\n };\n return { frozen, refresh, touch, off };\n}\n\nasync function thawFrozen(agents: Agents, id: string, context: Context): Promise<string> {\n const coneId = await agents.update((_tx, doc) => {\n const record = doc.frozen?.[id];\n if (!record) throw new Error(`There is no frozen chat ${id}.`);\n const reuse = !doc.cones[record.cone];\n const target = reuse ? record.cone : `cone-${doc.next}`;\n if (!reuse) doc.next += 1;\n doc.cones[target] = { name: record.name, conversation: record.conversation };\n for (const scoop of record.scoops) {\n const entry = doc.scoops[scoop];\n if (!entry) continue;\n delete entry.frozen;\n entry.cone = target;\n }\n delete doc.frozen?.[id];\n return target;\n }, context);\n await agents.selectCone(coneId, context);\n return coneId;\n}\n\nasync function discardFrozen(options: FreezerAttach, id: string, context: Context) {\n const { agents, env } = options;\n const record = agents.state().frozen?.[id];\n if (!record) throw new Error(`There is no frozen chat ${id}.`);\n const folders = record.scoops\n .map((scoop) => agents.state().scoops[scoop]?.folder)\n .filter((folder): folder is string => Boolean(folder));\n await agents.update((_tx, doc) => {\n for (const scoop of record.scoops) {\n const entry = doc.scoops[scoop];\n if (!entry) continue;\n delete entry.frozen;\n entry.gone = true;\n }\n delete doc.frozen?.[id];\n }, context);\n for (const folder of folders)\n await env.remove(`${SCOOPS_ROOT}/${folder}`, { recursive: true, force: true }, context);\n}\n\nexport function attachFreezer(options: FreezerAttach): FreezerRuntime {\n const { harness, agents } = options;\n const now = options.now ?? Date.now;\n const { frozen, refresh, touch, off } = listing(harness, agents);\n const conversationOf = async (agentId: string, context: Context) => {\n const conversation = await agents.conversation(agentId, context);\n if (!conversation) throw new Error(`There is no cone ${agentId}.`);\n return conversation;\n };\n const prepare = async (\n conversation: Conversation,\n entries: readonly EntryRecord[],\n cone: string,\n context: Context\n ) => {\n const tail = entries.at(-1)?.id ?? 0;\n await options.extract?.(conversation.id, tail, context, cone).catch(() => undefined);\n };\n const retitle = (\n id: string,\n model: string,\n entries: readonly EntryRecord[],\n context: Context\n ) => {\n if (!options.title) return;\n const transcript = entries\n .filter((entry) => entry.kind === 'pi.user' || entry.kind === 'pi.assistant')\n .map((entry) => `${entry.kind === 'pi.user' ? 'User' : 'Agent'}: ${textOf(entry)}`)\n .join('\\n')\n .slice(0, 4000);\n void options\n .title(transcript, model, context)\n .then(async (title) => {\n const clean = title\n ?.replace(/\\s+/g, ' ')\n .replace(/^[\"'\u201C\u201D]+|[\"'\u201C\u201D]+$/g, '')\n .replace(/\\.+$/, '')\n .trim();\n if (!clean) return;\n await agents.update((_tx, doc) => {\n const record = doc.frozen?.[id];\n if (record) record.title = clean.slice(0, TITLE_LENGTH);\n }, context);\n })\n .catch(() => undefined);\n };\n const replacement = async (coneId: string, context: Context) => {\n const state = agents.state();\n const other = Object.keys(state.cones).find((id) => id !== coneId);\n if (other) return { id: other, conversation: undefined };\n const current = await conversationOf(coneId, context);\n const conversation = await harness.createConversation(\n {\n ownership: { kind: 'ownerless' },\n agent: { model: (await current.agent(context)).model },\n },\n context\n );\n return { id: `cone-${state.next}`, conversation };\n };\n const runtime: FreezerRuntime = {\n frozen,\n async freeze(agentId, context) {\n const cone = agents.state().cones[agentId];\n if (!cone) throw new Error(`There is no cone ${agentId}.`);\n const conversation = await conversationOf(agentId, context);\n const { entries, record } = await snapshot(conversation, cone.name, now(), context);\n await prepare(conversation, entries, agentId, context);\n await conversation.abort(context, { background: true }).catch(() => undefined);\n const next =\n agents.state().active === agentId ? await replacement(agentId, context) : undefined;\n const { id, scoops } = await agents.update((_tx, doc) => {\n if (!doc.cones[agentId]) throw new Error(`There is no cone ${agentId}.`);\n const frozenId = `frozen-${doc.frozenNext ?? 1}`;\n const owned = Object.entries(doc.scoops)\n .filter(([, scoop]) => scoop.cone === agentId && live(scoop))\n .map(([scoop]) => scoop);\n doc.frozenNext = (doc.frozenNext ?? 1) + 1;\n doc.frozen ??= {};\n doc.frozen[frozenId] = { ...record, cone: agentId, scoops: owned };\n delete doc.cones[agentId];\n for (const scoop of owned) (doc.scoops[scoop] as { frozen?: string }).frozen = frozenId;\n if (next?.conversation) {\n doc.cones[next.id] = { name: record.name, conversation: next.conversation.id };\n doc.next += 1;\n }\n return { id: frozenId, scoops: owned };\n }, context);\n for (const scoop of scoops)\n await (await agents.conversation(scoop, context))?.abort(context).catch(() => undefined);\n if (next) await agents.selectCone(next.id, context);\n retitle(id, record.model, entries, context);\n return id;\n },\n async newChat(agentId, context) {\n const cone = agents.state().cones[agentId];\n const scoop = agents.state().scoops[agentId];\n if (!cone && scoop && live(scoop)) {\n await (await agents.conversation(agentId, context))?.reset(undefined, context);\n return null;\n }\n if (!cone) throw new Error(`There is no cone ${agentId}.`);\n const conversation = await conversationOf(agentId, context);\n const before = (await conversation.context(context)).entries;\n if (!before.some((entry) => entry.kind === 'pi.user')) return null;\n const fresh = await freshLike(harness, conversation, context);\n await agents.setConversation(agentId, fresh, context);\n await conversation.abort(context).catch(() => undefined);\n const { entries, record } = await snapshot(conversation, cone.name, now(), context);\n await prepare(conversation, entries, agentId, context);\n const id = await agents.update((_tx, doc) => {\n const frozenId = `frozen-${doc.frozenNext ?? 1}`;\n doc.frozenNext = (doc.frozenNext ?? 1) + 1;\n doc.frozen ??= {};\n doc.frozen[frozenId] = { ...record, cone: agentId, scoops: [] };\n return frozenId;\n }, context);\n retitle(id, record.model, entries, context);\n return id;\n },\n async thaw(id, context) {\n const state = agents.state();\n if (state.cones[id]) {\n await agents.selectCone(id, context);\n return id;\n }\n const scoop = state.scoops[id];\n if (scoop) return thawScoop({ ...options, now }, id, scoop, context);\n return thawFrozen(agents, id, context);\n },\n async discard(id, context) {\n const state = agents.state();\n const scoop = state.scoops[id];\n if (scoop) return removeScoop(options, id, scoop, context);\n const cone = state.cones[id];\n if (cone) throw new Error(`${cone.name} is live; delete the cone first.`);\n return discardFrozen(options, id, context);\n },\n refresh,\n touch,\n frozenTarget: (target) => frozenTarget(agents.state(), target),\n command: (argv, _caller, context) => command(options, runtime, argv, context),\n close: () => off(),\n };\n return runtime;\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": ["record", "item"]
|
|
7
7
|
}
|
package/dist/host.js
CHANGED
|
@@ -99,6 +99,13 @@ async function follow(agent, context) {
|
|
|
99
99
|
}
|
|
100
100
|
};
|
|
101
101
|
}
|
|
102
|
+
const idleVault = replicatedState({
|
|
103
|
+
port: "none",
|
|
104
|
+
needed: false,
|
|
105
|
+
version: 0,
|
|
106
|
+
locked: "no",
|
|
107
|
+
held: 0
|
|
108
|
+
});
|
|
102
109
|
async function hostAgent(agent, options = {}) {
|
|
103
110
|
const context = options.context ?? BACKGROUND_CONTEXT;
|
|
104
111
|
const serverId = options.serverId ?? crypto.randomUUID();
|
|
@@ -134,11 +141,13 @@ async function hostAgent(agent, options = {}) {
|
|
|
134
141
|
options.memory,
|
|
135
142
|
options.freezer,
|
|
136
143
|
options.changes,
|
|
137
|
-
monitor
|
|
144
|
+
monitor,
|
|
145
|
+
options.secrets?.list
|
|
138
146
|
);
|
|
139
147
|
const remote = createRemote({
|
|
140
148
|
harness: agent.harness,
|
|
141
149
|
send: (request, using) => control.send(request, using),
|
|
150
|
+
vault: options.secrets?.vault ?? idleVault,
|
|
142
151
|
async conversation(agentId, using) {
|
|
143
152
|
if (!agentId) return agent.cone();
|
|
144
153
|
const found = await agent.agents.conversation(agentId, using);
|
|
@@ -157,7 +166,8 @@ async function hostAgent(agent, options = {}) {
|
|
|
157
166
|
memoryScopes: options.memory?.scopes ?? replicatedState([]),
|
|
158
167
|
frozen: options.freezer?.frozen ?? replicatedState([]),
|
|
159
168
|
changes: options.changes?.view ?? replicatedState({ unavailable: null, changes: [] }),
|
|
160
|
-
monitor: monitor.state
|
|
169
|
+
monitor: monitor.state,
|
|
170
|
+
vault: options.secrets?.vault ?? idleVault
|
|
161
171
|
};
|
|
162
172
|
const settings = options.settings ?? noSettings;
|
|
163
173
|
const served = (served2) => {
|
|
@@ -231,6 +241,7 @@ async function hostAgent(agent, options = {}) {
|
|
|
231
241
|
mounted.dispose();
|
|
232
242
|
for (const off of untouch) off();
|
|
233
243
|
options.freezer?.close();
|
|
244
|
+
options.secrets?.close?.();
|
|
234
245
|
await options.changes?.close(context);
|
|
235
246
|
await options.memory?.close(context);
|
|
236
247
|
await options.sprinkles?.close(context);
|
package/dist/host.js.map
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../src/host.ts"],
|
|
4
|
-
"sourcesContent": ["import {\n type Context,\n createRemoteServiceEndpoint,\n RemoteServiceProvider,\n replicatedState,\n} from '@earendil-works/chord';\nimport { BACKGROUND_CONTEXT } from '@earendil-works/chord/context';\nimport type { ConversationView } from '@earendil-works/pi-durable';\nimport {\n type RoutedServerServiceHost,\n type RoutedSessionAttachment,\n type RoutedSessionHandle,\n Server,\n type ServerHost,\n SessionNotFoundError,\n} from '@earendil-works/pi-server';\nimport type { Agent } from './agent.ts';\nimport type { ChangesView } from './changes/git.ts';\nimport type { ChangesRuntime } from './changes/index.ts';\nimport { createAgentControl, type HostLicks, type HostScoops } from './control.ts';\nimport { trackDeliveries } from './deliveries.ts';\nimport type { FreezerRuntime, FrozenCone } from './freezer/index.ts';\nimport type { UserClients } from './kernel/users.ts';\nimport { PortListener } from './listener.ts';\nimport type { McpRuntime } from './mcp/index.ts';\nimport type { MemoryEntry, MemoryScope } from './memory/format.ts';\nimport type { MemoryRuntime } from './memory/index.ts';\nimport { createMonitor, type MonitorOptions } from './monitor/index.ts';\nimport { viewControl, viewPages, viewRemote, viewSettings } from './readonly.ts';\nimport { createRemote } from './remote/host.ts';\nimport { type AgentPages, createPages, ownedPages, type Pages } from './remote/pages.ts';\nimport {\n AGENT_SESSION,\n AgentControl,\n AgentPagesService,\n AgentRemoteService,\n AgentSessions,\n AgentSettings,\n AgentTranscript,\n type Command,\n} from './services.ts';\nimport type { SkillsRuntime } from './skills/index.ts';\nimport type { SprinklesRuntime } from './sprinkles/index.ts';\nimport type { Sprinkle } from './sprinkles/kind.ts';\nimport { agentViews } from './views.ts';\nimport type { PortEndpoint } from './wire.ts';\n\nexport interface ConnectOptions {\n readOnly?: boolean;\n pages?: boolean;\n}\n\nexport interface AgentHost {\n readonly serverId: string;\n readonly agent: Agent;\n readonly users?: UserClients;\n readonly pages: Pages;\n connect(endpoint: PortEndpoint, options?: ConnectOptions): void;\n close(): Promise<void>;\n}\n\nfunction endpointFor(provider: RemoteServiceProvider): RoutedSessionAttachment {\n const endpoint = createRemoteServiceEndpoint(provider);\n return {\n invokeService: (call, publish, context) =>\n endpoint.invoke(call, (id, update) => publish(id, update, context), context),\n release: () => endpoint.dispose(),\n };\n}\n\ntype Attached = { provider: RemoteServiceProvider; release(): void };\n\nfunction sessionServices(attach: () => Attached): RoutedSessionHandle {\n return {\n attachClient() {\n const attached = attach();\n const endpoint = endpointFor(attached.provider);\n return {\n invokeService: endpoint.invokeService,\n release(context) {\n endpoint.release(context);\n attached.release();\n },\n };\n },\n close: async () => {},\n };\n}\n\nfunction serverServices(): RoutedServerServiceHost {\n return {\n attachClient(presentation) {\n const provider = new RemoteServiceProvider([{ service: AgentSessions, mode: 'singleton' }]);\n provider.provide(AgentSessions, {\n attach: (sessionId, context) => presentation.attachSession(sessionId, context),\n detach: (context) => presentation.detachSession(context),\n });\n const attachment = endpointFor(provider);\n return {\n invokeService: attachment.invokeService,\n release(context) {\n attachment.release(context);\n provider.dispose();\n },\n };\n },\n };\n}\n\nconst noSettings: AgentSettings = {\n state: replicatedState({ models: [], accounts: [] }),\n connect: async () => {\n throw new Error('this agent has no accounts');\n },\n disconnect: async () => {},\n signIn: async () => null,\n};\n\nasync function follow(agent: Agent, context: Context) {\n let attached = await agent.cone().viewState(context);\n const state = replicatedState<ConversationView>(attached.value);\n const mirror = (value: ConversationView, from: Context) => state.replace(from, value);\n let off = attached.subscribe(mirror);\n const stop = agent.onCone(async (conversation) => {\n const next = await conversation.viewState(context);\n off();\n attached.dispose();\n attached = next;\n state.replace(context, next.value);\n off = next.subscribe(mirror);\n });\n return {\n state,\n dispose() {\n stop();\n off();\n attached.dispose();\n },\n };\n}\n\nexport async function hostAgent(\n agent: Agent,\n options: {\n serverId?: string;\n context?: Context;\n settings?: AgentSettings;\n licks?: HostLicks;\n scoops?: HostScoops;\n skills?: SkillsRuntime;\n sprinkles?: SprinklesRuntime;\n memory?: MemoryRuntime;\n freezer?: FreezerRuntime;\n changes?: ChangesRuntime;\n mcp?: Pick<McpRuntime, 'close'>;\n users?: UserClients;\n monitor?: Pick<MonitorOptions, 'kernel' | 'groups' | 'users' | 'secrets'>;\n pages?: Pages;\n } = {}\n): Promise<AgentHost> {\n const context = options.context ?? BACKGROUND_CONTEXT;\n const serverId = options.serverId ?? crypto.randomUUID();\n const transcript = await follow(agent, context);\n const { state } = transcript;\n const mounted = await agentViews(agent, context);\n const touch = () => options.freezer?.touch();\n const untouch = [state.subscribe(touch), mounted.views.subscribe(touch)];\n const catalogue = () =>\n new RemoteServiceProvider([\n { service: AgentControl, mode: 'singleton' },\n { service: AgentTranscript, mode: 'singleton' },\n { service: AgentSettings, mode: 'singleton' },\n { service: AgentRemoteService, mode: 'singleton' },\n { service: AgentPagesService, mode: 'singleton' },\n ]);\n const pages = options.pages ?? createPages();\n const deliveries = trackDeliveries(agent.harness, state, context);\n const monitor = createMonitor({\n ...options.monitor,\n harness: agent.harness,\n agents: agent.agents,\n views: mounted.views,\n context,\n });\n const control = createAgentControl(\n agent.harness,\n agent,\n deliveries,\n options.licks,\n options.scoops,\n options.skills,\n options.sprinkles,\n options.memory,\n options.freezer,\n options.changes,\n monitor\n );\n const remote = createRemote({\n harness: agent.harness,\n send: (request, using) => control.send(request, using),\n async conversation(agentId, using) {\n if (!agentId) return agent.cone();\n const found = await agent.agents.conversation(agentId, using);\n if (!found) throw new Error(`There is no agent ${agentId}.`);\n return found;\n },\n });\n const transcriptService = {\n state,\n deliveries: deliveries.state,\n agents: mounted.agents,\n views: mounted.views,\n commands: options.skills?.commands ?? replicatedState<Command[]>([]),\n sprinkles: options.sprinkles?.sprinkles ?? replicatedState<Sprinkle[]>([]),\n memories: options.memory?.memories ?? replicatedState<MemoryEntry[]>([]),\n memoryScopes: options.memory?.scopes ?? replicatedState<MemoryScope[]>([]),\n frozen: options.freezer?.frozen ?? replicatedState<FrozenCone[]>([]),\n changes:\n options.changes?.view ?? replicatedState<ChangesView>({ unavailable: null, changes: [] }),\n monitor: monitor.state,\n };\n const settings = options.settings ?? noSettings;\n const served = (served: AgentPages) => {\n const made = catalogue();\n made.provide(AgentControl, control);\n made.provide(AgentTranscript, transcriptService);\n made.provide(AgentSettings, settings);\n made.provide(AgentRemoteService, remote);\n made.provide(AgentPagesService, served);\n return made;\n };\n const owned = (): Attached => {\n const mine = ownedPages(pages);\n const made = served(mine);\n return {\n provider: made,\n release() {\n made.dispose();\n mine.release();\n },\n };\n };\n const follower = served(viewPages());\n const viewer = catalogue();\n viewer.provide(AgentControl, viewControl(control));\n viewer.provide(AgentTranscript, { ...transcriptService, monitor: monitor.viewState });\n viewer.provide(AgentSettings, viewSettings(settings));\n viewer.provide(AgentRemoteService, viewRemote(remote));\n viewer.provide(AgentPagesService, viewPages());\n const shared = (services: RemoteServiceProvider) => () => ({\n provider: services,\n release: () => undefined,\n });\n const serve = async (id: string, attach: () => Attached) => {\n const host: ServerHost = {\n serverServices: serverServices(),\n async resolveSession(sessionId) {\n if (sessionId !== AGENT_SESSION)\n throw new SessionNotFoundError(`unknown session ${sessionId}`);\n return { id: sessionId };\n },\n openSession: async () => sessionServices(attach),\n };\n const listener = new PortListener(id);\n const server = await new Server(host, { serverId: id, listeners: [listener] }).start();\n return { listener, server };\n };\n const full = await serve(serverId, owned);\n const view = await serve(crypto.randomUUID(), shared(viewer));\n const linked = await serve(crypto.randomUUID(), shared(follower));\n return {\n serverId,\n agent,\n pages,\n ...(options.users ? { users: options.users } : {}),\n connect(endpoint, connectOptions) {\n const chosen = connectOptions?.readOnly\n ? view\n : connectOptions?.pages === false\n ? linked\n : full;\n chosen.listener.connect(endpoint);\n },\n async close() {\n await full.server.close();\n await view.server.close();\n await linked.server.close();\n viewer.dispose();\n follower.dispose();\n await pages.dispose();\n await monitor.dispose();\n await remote.dispose();\n deliveries.dispose();\n transcript.dispose();\n mounted.dispose();\n for (const off of untouch) off();\n options.freezer?.close();\n await options.changes?.close(context);\n await options.memory?.close(context);\n await options.sprinkles?.close(context);\n await options.skills?.close(context);\n await options.mcp?.close(context);\n await options.scoops?.runtime.close(context);\n await options.licks?.sources.close(context);\n await agent.close();\n await options.users?.close();\n },\n };\n}\n"],
|
|
5
|
-
"mappings": "AAAA;AAAA,EAEE;AAAA,EACA;AAAA,
|
|
4
|
+
"sourcesContent": ["import {\n type Context,\n createRemoteServiceEndpoint,\n RemoteServiceProvider,\n type ReplicatedState,\n replicatedState,\n} from '@earendil-works/chord';\nimport { BACKGROUND_CONTEXT } from '@earendil-works/chord/context';\nimport type { ConversationView } from '@earendil-works/pi-durable';\nimport {\n type RoutedServerServiceHost,\n type RoutedSessionAttachment,\n type RoutedSessionHandle,\n Server,\n type ServerHost,\n SessionNotFoundError,\n} from '@earendil-works/pi-server';\nimport type { Agent } from './agent.ts';\nimport type { ChangesView } from './changes/git.ts';\nimport type { ChangesRuntime } from './changes/index.ts';\nimport { createAgentControl, type HostLicks, type HostScoops } from './control.ts';\nimport { trackDeliveries } from './deliveries.ts';\nimport type { FreezerRuntime, FrozenCone } from './freezer/index.ts';\nimport type { UserClients } from './kernel/users.ts';\nimport { PortListener } from './listener.ts';\nimport type { McpRuntime } from './mcp/index.ts';\nimport type { MemoryEntry, MemoryScope } from './memory/format.ts';\nimport type { MemoryRuntime } from './memory/index.ts';\nimport { createMonitor, type MonitorOptions } from './monitor/index.ts';\nimport { viewControl, viewPages, viewRemote, viewSettings } from './readonly.ts';\nimport { createRemote } from './remote/host.ts';\nimport { type AgentPages, createPages, ownedPages, type Pages } from './remote/pages.ts';\nimport type { SecretName } from './secrets/names.ts';\nimport type { VaultState } from './secrets/vault.ts';\nimport {\n AGENT_SESSION,\n AgentControl,\n AgentPagesService,\n AgentRemoteService,\n AgentSessions,\n AgentSettings,\n AgentTranscript,\n type Command,\n} from './services.ts';\nimport type { SkillsRuntime } from './skills/index.ts';\nimport type { SprinklesRuntime } from './sprinkles/index.ts';\nimport type { Sprinkle } from './sprinkles/kind.ts';\nimport { agentViews } from './views.ts';\nimport type { PortEndpoint } from './wire.ts';\n\nexport interface ConnectOptions {\n readOnly?: boolean;\n pages?: boolean;\n}\n\nexport interface AgentHost {\n readonly serverId: string;\n readonly agent: Agent;\n readonly users?: UserClients;\n readonly pages: Pages;\n connect(endpoint: PortEndpoint, options?: ConnectOptions): void;\n close(): Promise<void>;\n}\n\nfunction endpointFor(provider: RemoteServiceProvider): RoutedSessionAttachment {\n const endpoint = createRemoteServiceEndpoint(provider);\n return {\n invokeService: (call, publish, context) =>\n endpoint.invoke(call, (id, update) => publish(id, update, context), context),\n release: () => endpoint.dispose(),\n };\n}\n\ntype Attached = { provider: RemoteServiceProvider; release(): void };\n\nfunction sessionServices(attach: () => Attached): RoutedSessionHandle {\n return {\n attachClient() {\n const attached = attach();\n const endpoint = endpointFor(attached.provider);\n return {\n invokeService: endpoint.invokeService,\n release(context) {\n endpoint.release(context);\n attached.release();\n },\n };\n },\n close: async () => {},\n };\n}\n\nfunction serverServices(): RoutedServerServiceHost {\n return {\n attachClient(presentation) {\n const provider = new RemoteServiceProvider([{ service: AgentSessions, mode: 'singleton' }]);\n provider.provide(AgentSessions, {\n attach: (sessionId, context) => presentation.attachSession(sessionId, context),\n detach: (context) => presentation.detachSession(context),\n });\n const attachment = endpointFor(provider);\n return {\n invokeService: attachment.invokeService,\n release(context) {\n attachment.release(context);\n provider.dispose();\n },\n };\n },\n };\n}\n\nconst noSettings: AgentSettings = {\n state: replicatedState({ models: [], accounts: [] }),\n connect: async () => {\n throw new Error('this agent has no accounts');\n },\n disconnect: async () => {},\n signIn: async () => null,\n};\n\nasync function follow(agent: Agent, context: Context) {\n let attached = await agent.cone().viewState(context);\n const state = replicatedState<ConversationView>(attached.value);\n const mirror = (value: ConversationView, from: Context) => state.replace(from, value);\n let off = attached.subscribe(mirror);\n const stop = agent.onCone(async (conversation) => {\n const next = await conversation.viewState(context);\n off();\n attached.dispose();\n attached = next;\n state.replace(context, next.value);\n off = next.subscribe(mirror);\n });\n return {\n state,\n dispose() {\n stop();\n off();\n attached.dispose();\n },\n };\n}\n\nexport interface HostSecrets {\n vault: ReplicatedState<VaultState>;\n list(): readonly SecretName[];\n close?(): void;\n}\n\nconst idleVault = replicatedState<VaultState>({\n port: 'none',\n needed: false,\n version: 0,\n locked: 'no',\n held: 0,\n});\n\nexport async function hostAgent(\n agent: Agent,\n options: {\n serverId?: string;\n context?: Context;\n settings?: AgentSettings;\n licks?: HostLicks;\n scoops?: HostScoops;\n skills?: SkillsRuntime;\n sprinkles?: SprinklesRuntime;\n memory?: MemoryRuntime;\n freezer?: FreezerRuntime;\n changes?: ChangesRuntime;\n mcp?: Pick<McpRuntime, 'close'>;\n users?: UserClients;\n monitor?: Pick<MonitorOptions, 'kernel' | 'groups' | 'users' | 'secrets'>;\n pages?: Pages;\n secrets?: HostSecrets;\n } = {}\n): Promise<AgentHost> {\n const context = options.context ?? BACKGROUND_CONTEXT;\n const serverId = options.serverId ?? crypto.randomUUID();\n const transcript = await follow(agent, context);\n const { state } = transcript;\n const mounted = await agentViews(agent, context);\n const touch = () => options.freezer?.touch();\n const untouch = [state.subscribe(touch), mounted.views.subscribe(touch)];\n const catalogue = () =>\n new RemoteServiceProvider([\n { service: AgentControl, mode: 'singleton' },\n { service: AgentTranscript, mode: 'singleton' },\n { service: AgentSettings, mode: 'singleton' },\n { service: AgentRemoteService, mode: 'singleton' },\n { service: AgentPagesService, mode: 'singleton' },\n ]);\n const pages = options.pages ?? createPages();\n const deliveries = trackDeliveries(agent.harness, state, context);\n const monitor = createMonitor({\n ...options.monitor,\n harness: agent.harness,\n agents: agent.agents,\n views: mounted.views,\n context,\n });\n const control = createAgentControl(\n agent.harness,\n agent,\n deliveries,\n options.licks,\n options.scoops,\n options.skills,\n options.sprinkles,\n options.memory,\n options.freezer,\n options.changes,\n monitor,\n options.secrets?.list\n );\n const remote = createRemote({\n harness: agent.harness,\n send: (request, using) => control.send(request, using),\n vault: options.secrets?.vault ?? idleVault,\n async conversation(agentId, using) {\n if (!agentId) return agent.cone();\n const found = await agent.agents.conversation(agentId, using);\n if (!found) throw new Error(`There is no agent ${agentId}.`);\n return found;\n },\n });\n const transcriptService = {\n state,\n deliveries: deliveries.state,\n agents: mounted.agents,\n views: mounted.views,\n commands: options.skills?.commands ?? replicatedState<Command[]>([]),\n sprinkles: options.sprinkles?.sprinkles ?? replicatedState<Sprinkle[]>([]),\n memories: options.memory?.memories ?? replicatedState<MemoryEntry[]>([]),\n memoryScopes: options.memory?.scopes ?? replicatedState<MemoryScope[]>([]),\n frozen: options.freezer?.frozen ?? replicatedState<FrozenCone[]>([]),\n changes:\n options.changes?.view ?? replicatedState<ChangesView>({ unavailable: null, changes: [] }),\n monitor: monitor.state,\n vault: options.secrets?.vault ?? idleVault,\n };\n const settings = options.settings ?? noSettings;\n const served = (served: AgentPages) => {\n const made = catalogue();\n made.provide(AgentControl, control);\n made.provide(AgentTranscript, transcriptService);\n made.provide(AgentSettings, settings);\n made.provide(AgentRemoteService, remote);\n made.provide(AgentPagesService, served);\n return made;\n };\n const owned = (): Attached => {\n const mine = ownedPages(pages);\n const made = served(mine);\n return {\n provider: made,\n release() {\n made.dispose();\n mine.release();\n },\n };\n };\n const follower = served(viewPages());\n const viewer = catalogue();\n viewer.provide(AgentControl, viewControl(control));\n viewer.provide(AgentTranscript, { ...transcriptService, monitor: monitor.viewState });\n viewer.provide(AgentSettings, viewSettings(settings));\n viewer.provide(AgentRemoteService, viewRemote(remote));\n viewer.provide(AgentPagesService, viewPages());\n const shared = (services: RemoteServiceProvider) => () => ({\n provider: services,\n release: () => undefined,\n });\n const serve = async (id: string, attach: () => Attached) => {\n const host: ServerHost = {\n serverServices: serverServices(),\n async resolveSession(sessionId) {\n if (sessionId !== AGENT_SESSION)\n throw new SessionNotFoundError(`unknown session ${sessionId}`);\n return { id: sessionId };\n },\n openSession: async () => sessionServices(attach),\n };\n const listener = new PortListener(id);\n const server = await new Server(host, { serverId: id, listeners: [listener] }).start();\n return { listener, server };\n };\n const full = await serve(serverId, owned);\n const view = await serve(crypto.randomUUID(), shared(viewer));\n const linked = await serve(crypto.randomUUID(), shared(follower));\n return {\n serverId,\n agent,\n pages,\n ...(options.users ? { users: options.users } : {}),\n connect(endpoint, connectOptions) {\n const chosen = connectOptions?.readOnly\n ? view\n : connectOptions?.pages === false\n ? linked\n : full;\n chosen.listener.connect(endpoint);\n },\n async close() {\n await full.server.close();\n await view.server.close();\n await linked.server.close();\n viewer.dispose();\n follower.dispose();\n await pages.dispose();\n await monitor.dispose();\n await remote.dispose();\n deliveries.dispose();\n transcript.dispose();\n mounted.dispose();\n for (const off of untouch) off();\n options.freezer?.close();\n options.secrets?.close?.();\n await options.changes?.close(context);\n await options.memory?.close(context);\n await options.sprinkles?.close(context);\n await options.skills?.close(context);\n await options.mcp?.close(context);\n await options.scoops?.runtime.close(context);\n await options.licks?.sources.close(context);\n await agent.close();\n await options.users?.close();\n },\n };\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": ["served"]
|
|
7
7
|
}
|
package/dist/kernel/env.js
CHANGED
|
@@ -3,10 +3,29 @@ import {
|
|
|
3
3
|
FileError,
|
|
4
4
|
ok
|
|
5
5
|
} from "@earendil-works/pi-durable/env";
|
|
6
|
+
import { mimeOf } from "../images/index.js";
|
|
6
7
|
import { execute } from "./exec.js";
|
|
7
8
|
import { attempt, info, KernelDirReader, SnapshotLines, SnapshotReader } from "./files.js";
|
|
8
9
|
import { dirname, normalize, resolve } from "./paths.js";
|
|
9
10
|
import { nativeWatch, pollWatch, RESCAN_MS } from "./watch.js";
|
|
11
|
+
const STREAMED_READ = 8 * 1024 * 1024;
|
|
12
|
+
const READ_CHUNK = 1024 * 1024;
|
|
13
|
+
async function scrubbedFile(scrub, bytes) {
|
|
14
|
+
if (mimeOf(bytes)) return bytes;
|
|
15
|
+
if (bytes.length <= STREAMED_READ) return (await scrub.texts([bytes]))[0];
|
|
16
|
+
const stream = scrub.stream();
|
|
17
|
+
const parts = [];
|
|
18
|
+
for (let at = 0; at < bytes.length; at += READ_CHUNK)
|
|
19
|
+
parts.push(await stream.push(bytes.subarray(at, at + READ_CHUNK)));
|
|
20
|
+
parts.push(await stream.end());
|
|
21
|
+
const all = new Uint8Array(parts.reduce((sum, part) => sum + part.length, 0));
|
|
22
|
+
let offset = 0;
|
|
23
|
+
for (const part of parts) {
|
|
24
|
+
all.set(part, offset);
|
|
25
|
+
offset += part.length;
|
|
26
|
+
}
|
|
27
|
+
return all;
|
|
28
|
+
}
|
|
10
29
|
function quote(value) {
|
|
11
30
|
return `'${value.replace(/'/g, "'\\''")}'`;
|
|
12
31
|
}
|
|
@@ -25,6 +44,8 @@ class SliccKernelEnv {
|
|
|
25
44
|
#groups;
|
|
26
45
|
#owner;
|
|
27
46
|
#exports;
|
|
47
|
+
#hooks;
|
|
48
|
+
#scrub;
|
|
28
49
|
constructor(client, options) {
|
|
29
50
|
this.#client = client;
|
|
30
51
|
this.cwd = options.cwd;
|
|
@@ -34,6 +55,12 @@ class SliccKernelEnv {
|
|
|
34
55
|
this.#groups = options.groups;
|
|
35
56
|
this.#owner = options.owner;
|
|
36
57
|
this.#exports = options.exports;
|
|
58
|
+
this.#scrub = options.scrub;
|
|
59
|
+
const scrub = options.scrub;
|
|
60
|
+
this.#hooks = {
|
|
61
|
+
...scrub ? { scrub: () => scrub.stream() } : {},
|
|
62
|
+
...options.spawn ? { spawn: options.spawn } : {}
|
|
63
|
+
};
|
|
37
64
|
}
|
|
38
65
|
#path(path) {
|
|
39
66
|
return resolve(this.cwd, path);
|
|
@@ -85,7 +112,10 @@ class SliccKernelEnv {
|
|
|
85
112
|
const stat = await this.#fs.stat(resolved);
|
|
86
113
|
if (stat.isDirectory) throw new FileError("is_directory", "Is a directory", resolved);
|
|
87
114
|
if (!stat.isFile) throw new FileError("invalid", "Not a regular file", resolved);
|
|
88
|
-
|
|
115
|
+
const bytes = await this.#fs.readFile(resolved);
|
|
116
|
+
if (!this.#scrub) return new SnapshotReader(bytes, info(resolved, stat));
|
|
117
|
+
const shown = await scrubbedFile(this.#scrub, bytes);
|
|
118
|
+
return new SnapshotReader(shown, { ...info(resolved, stat), size: shown.length });
|
|
89
119
|
});
|
|
90
120
|
}
|
|
91
121
|
writeFile(path, content, context) {
|
|
@@ -228,7 +258,16 @@ class SliccKernelEnv {
|
|
|
228
258
|
const groups = this.#groups;
|
|
229
259
|
const owner = this.#owner;
|
|
230
260
|
if (!groups || owner === void 0)
|
|
231
|
-
return execute(
|
|
261
|
+
return execute(
|
|
262
|
+
this.#client,
|
|
263
|
+
this.cwd,
|
|
264
|
+
line,
|
|
265
|
+
options,
|
|
266
|
+
context,
|
|
267
|
+
void 0,
|
|
268
|
+
void 0,
|
|
269
|
+
this.#hooks
|
|
270
|
+
).finally(ended);
|
|
232
271
|
return this.#grouped(groups, owner, line, options, context).finally(ended);
|
|
233
272
|
}
|
|
234
273
|
async #grouped(groups, owner, line, options, context) {
|
|
@@ -243,7 +282,16 @@ class SliccKernelEnv {
|
|
|
243
282
|
...pgid === void 0 ? {} : { pgid },
|
|
244
283
|
refused: (code) => groups.refused(owner, code)
|
|
245
284
|
} : void 0;
|
|
246
|
-
return execute(
|
|
285
|
+
return execute(
|
|
286
|
+
this.#client,
|
|
287
|
+
this.cwd,
|
|
288
|
+
line,
|
|
289
|
+
options,
|
|
290
|
+
context,
|
|
291
|
+
spawned,
|
|
292
|
+
join,
|
|
293
|
+
this.#hooks
|
|
294
|
+
).finally(release);
|
|
247
295
|
}
|
|
248
296
|
async cleanup(context) {
|
|
249
297
|
for (const watcher of [...this.#watchers]) await watcher.close(context);
|
|
@@ -263,9 +311,12 @@ function kernelEnvironment(client, options = {}) {
|
|
|
263
311
|
}
|
|
264
312
|
export {
|
|
265
313
|
HOME,
|
|
314
|
+
READ_CHUNK,
|
|
315
|
+
STREAMED_READ,
|
|
266
316
|
SliccKernelEnv,
|
|
267
317
|
kernelEnvironment,
|
|
268
318
|
prefixed,
|
|
269
|
-
quote
|
|
319
|
+
quote,
|
|
320
|
+
scrubbedFile
|
|
270
321
|
};
|
|
271
322
|
//# sourceMappingURL=env.js.map
|
package/dist/kernel/env.js.map
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../src/kernel/env.ts"],
|
|
4
|
-
"sourcesContent": ["import type { Context } from '@earendil-works/chord';\nimport {\n type BinaryReader,\n type DirReader,\n type ExecutionEnv,\n type ExecutionError,\n err,\n FileError,\n type FileInfo,\n type FileWatcher,\n ok,\n type Result,\n type ShellExecOptions,\n type ShellExecResult,\n type TextLineReader,\n type WatchChange,\n type WatchTarget,\n} from '@earendil-works/pi-durable/env';\nimport type { Activity } from './activity.ts';\nimport type { KernelClient, KernelProcess } from './client.ts';\nimport { execute } from './exec.ts';\nimport { attempt, info, KernelDirReader, SnapshotLines, SnapshotReader } from './files.ts';\nimport type { ProcessGroups } from './groups.ts';\nimport { dirname, normalize, resolve } from './paths.ts';\nimport { nativeWatch, type PollOptions, pollWatch, RESCAN_MS } from './watch.ts';\n\nexport interface KernelEnvOptions {\n cwd: string;\n id?: string;\n watch?: PollOptions;\n activity?: Activity;\n groups?: ProcessGroups;\n owner?: number;\n exports?: Readonly<Record<string, string>>;\n}\n\nexport function quote(value: string): string {\n return `'${value.replace(/'/g, \"'\\\\''\")}'`;\n}\n\nexport function prefixed(\n command: string,\n exports: Readonly<Record<string, string>> | undefined\n): string {\n const names = Object.keys(exports ?? {}).filter((name) => /^[A-Z_][A-Z0-9_]*$/.test(name));\n if (!names.length) return command;\n return `export ${names.map((name) => `${name}=${quote((exports as Record<string, string>)[name] as string)}`).join(' ')}; ${command}`;\n}\n\ntype FileResult<T> = Promise<Result<T, FileError>>;\n\nexport class SliccKernelEnv implements ExecutionEnv {\n readonly id: string;\n cwd: string;\n readonly #client: KernelClient;\n readonly #watchers = new Set<FileWatcher>();\n readonly #poll: PollOptions;\n readonly #activity: Activity | undefined;\n readonly #groups: ProcessGroups | undefined;\n readonly #owner: number | undefined;\n readonly #exports: Readonly<Record<string, string>> | undefined;\n\n constructor(client: KernelClient, options: KernelEnvOptions) {\n this.#client = client;\n this.cwd = options.cwd;\n this.id = options.id ?? 'slicc-kernel';\n this.#poll = options.watch ?? {};\n this.#activity = options.activity;\n this.#groups = options.groups;\n this.#owner = options.owner;\n this.#exports = options.exports;\n }\n\n #path(path: string): string {\n return resolve(this.cwd, path);\n }\n\n #written(path: string): string {\n const resolved = this.#path(path);\n this.#activity?.wrote(resolved);\n return resolved;\n }\n\n get #fs() {\n return this.#client.fs;\n }\n\n async absolutePath(path: string): FileResult<string> {\n return ok(this.#path(path));\n }\n\n async joinPath(parts: string[]): FileResult<string> {\n return ok(normalize(parts.join('/')));\n }\n\n readTextFile(path: string, context: Context): FileResult<string> {\n const resolved = this.#path(path);\n return attempt(context, resolved, () => this.#fs.readText(resolved));\n }\n\n readBinaryFile(path: string, context: Context): FileResult<Uint8Array> {\n const resolved = this.#path(path);\n return attempt(context, resolved, () => this.#fs.readFile(resolved));\n }\n\n async openTextLineReader(path: string, context: Context): FileResult<TextLineReader> {\n const text = await this.readTextFile(path, context);\n return text.ok ? ok(new SnapshotLines(text.value)) : text;\n }\n\n async readTextLines(\n path: string,\n options: { maxLines?: number } | undefined,\n context: Context\n ): FileResult<string[]> {\n if (options?.maxLines !== undefined && options.maxLines <= 0) return ok([]);\n const text = await this.readTextFile(path, context);\n if (!text.ok) return text;\n const reader = new SnapshotLines(text.value);\n const lines: string[] = [];\n for (\n let line = await reader.readLine();\n line.ok && line.value;\n line = await reader.readLine()\n ) {\n if (options?.maxLines !== undefined && lines.length >= options.maxLines) break;\n lines.push(line.value.text);\n }\n return ok(lines);\n }\n\n openBinaryReader(\n path: string,\n options: { noFollow?: boolean } | undefined,\n context: Context\n ): FileResult<BinaryReader> {\n const resolved = this.#path(path);\n return attempt(context, resolved, async () => {\n if (options?.noFollow && (await this.#fs.lstat(resolved)).isSymbolicLink) {\n throw new FileError('invalid', 'Refusing to follow a symbolic link', resolved);\n }\n const stat = await this.#fs.stat(resolved);\n if (stat.isDirectory) throw new FileError('is_directory', 'Is a directory', resolved);\n if (!stat.isFile) throw new FileError('invalid', 'Not a regular file', resolved);\n return new SnapshotReader(await this.#fs.readFile(resolved), info(resolved, stat));\n });\n }\n\n writeFile(path: string, content: string | Uint8Array, context: Context): FileResult<void> {\n const resolved = this.#written(path);\n return attempt(context, resolved, async () => {\n await this.#fs.mkdir(dirname(resolved));\n await this.#fs.writeFile(resolved, content);\n });\n }\n\n appendFile(path: string, content: string | Uint8Array, context: Context): FileResult<void> {\n const resolved = this.#written(path);\n return attempt(context, resolved, async () => {\n const before = (await this.#fs.exists(resolved))\n ? await this.#fs.readFile(resolved)\n : new Uint8Array();\n const added = typeof content === 'string' ? new TextEncoder().encode(content) : content;\n const all = new Uint8Array(before.length + added.length);\n all.set(before);\n all.set(added, before.length);\n await this.#fs.mkdir(dirname(resolved));\n await this.#fs.writeFile(resolved, all);\n });\n }\n\n truncateFile(path: string, size: number, context: Context): FileResult<void> {\n const resolved = this.#written(path);\n if (!Number.isSafeInteger(size) || size < 0) {\n return Promise.resolve(\n err(new FileError('invalid', 'File size must be a non-negative integer', resolved))\n );\n }\n return attempt(context, resolved, async () => {\n const before = await this.#fs.readFile(resolved);\n const after = new Uint8Array(size);\n after.set(before.subarray(0, size));\n await this.#fs.writeFile(resolved, after);\n });\n }\n\n flushFile(path: string, context: Context): FileResult<void> {\n const resolved = this.#path(path);\n return attempt(context, resolved, async () => {\n if ((await this.#fs.stat(resolved)).isDirectory)\n throw Object.assign(new Error('Is a directory'), { code: 'EISDIR' });\n });\n }\n\n renameFile(sourcePath: string, destinationPath: string, context: Context): FileResult<void> {\n const source = this.#written(sourcePath);\n return attempt(context, source, () => this.#fs.rename(source, this.#written(destinationPath)));\n }\n\n fileInfo(path: string, context: Context): FileResult<FileInfo> {\n const resolved = this.#path(path);\n return attempt(context, resolved, async () => info(resolved, await this.#fs.lstat(resolved)));\n }\n\n async listDir(path: string, context: Context): FileResult<FileInfo[]> {\n const reader = await this.openDirReader(path, context);\n if (!reader.ok) return reader;\n return ok(await (reader.value as KernelDirReader).rest());\n }\n\n openDirReader(path: string, context: Context): FileResult<DirReader> {\n const resolved = this.#path(path);\n return attempt(context, resolved, async () => {\n if (!(await this.#fs.stat(resolved)).isDirectory) {\n throw Object.assign(new Error('Not a directory'), { code: 'ENOTDIR' });\n }\n return new KernelDirReader(this.#fs, resolved, await this.#fs.readdir(resolved));\n });\n }\n\n watch(\n targets: readonly WatchTarget[],\n onChange: (change: WatchChange) => void,\n context: Context\n ): FileResult<FileWatcher> {\n return attempt(context, this.cwd, async () => {\n let absorb: (paths: readonly string[]) => void = () => undefined;\n const reported = (change: WatchChange) => {\n if ('paths' in change) absorb(change.paths);\n onChange(change);\n };\n const native =\n this.#poll.mode === 'polling'\n ? undefined\n : await nativeWatch(this.#fs, this.cwd, targets, reported);\n const intervalMs = native ? (this.#poll.rescanMs ?? RESCAN_MS) : this.#poll.intervalMs;\n const polled = await pollWatch(this.#fs, this.cwd, targets, onChange, {\n ...(intervalMs === undefined ? {} : { intervalMs }),\n });\n absorb = (paths) => polled.absorb(paths);\n const watcher: FileWatcher = native\n ? {\n mode: 'native',\n async close(closing: Context) {\n await native.close(closing);\n await polled.close(closing);\n },\n }\n : polled;\n this.#watchers.add(watcher);\n return {\n mode: watcher.mode,\n close: async (closing: Context) => {\n this.#watchers.delete(watcher);\n await watcher.close(closing);\n },\n };\n });\n }\n\n canonicalPath(path: string, context: Context): FileResult<string> {\n const resolved = this.#path(path);\n return attempt(context, resolved, () => this.#fs.realpath(resolved));\n }\n\n async exists(path: string, context: Context): FileResult<boolean> {\n const found = await this.fileInfo(path, context);\n if (found.ok) return ok(true);\n return found.error.code === 'not_found' ? ok(false) : found;\n }\n\n createDir(\n path: string,\n _options: { recursive?: boolean } | undefined,\n context: Context\n ): FileResult<void> {\n const resolved = this.#written(path);\n return attempt(context, resolved, () => this.#fs.mkdir(resolved));\n }\n\n remove(\n path: string,\n options: { recursive?: boolean; force?: boolean } | undefined,\n context: Context\n ): FileResult<void> {\n const resolved = this.#written(path);\n return attempt(context, resolved, async () => {\n if (!options?.recursive) {\n const stat = await this.#fs.lstat(resolved).catch((error: unknown) => {\n if (options?.force) return undefined;\n throw error;\n });\n if (stat?.isDirectory) throw Object.assign(new Error('Is a directory'), { code: 'EISDIR' });\n }\n await this.#fs.rm(resolved, { force: options?.force ?? false });\n });\n }\n\n async createTempDir(prefix: string | undefined, context: Context): FileResult<string> {\n const path = `/tmp/${prefix ?? 'tmp-'}${crypto.randomUUID()}`;\n return attempt(context, path, async () => {\n await this.#fs.mkdir(path);\n return path;\n });\n }\n\n async createTempFile(\n options: { prefix?: string; suffix?: string } | undefined,\n context: Context\n ): FileResult<string> {\n const dir = await this.createTempDir('tmp-', context);\n if (!dir.ok) return dir;\n const path = `${dir.value}/${options?.prefix ?? ''}${crypto.randomUUID()}${options?.suffix ?? ''}`;\n return attempt(context, path, async () => {\n await this.#fs.writeFile(path, '');\n return path;\n });\n }\n\n exec(\n command: string | readonly string[],\n options: ShellExecOptions | undefined,\n context: Context\n ): Promise<Result<ShellExecResult, ExecutionError>> {\n const ended = this.#activity?.began();\n const line = typeof command === 'string' ? prefixed(command, this.#exports) : command;\n const groups = this.#groups;\n const owner = this.#owner;\n if (!groups || owner === undefined)\n return execute(this.#client, this.cwd, line, options, context).finally(ended);\n return this.#grouped(groups, owner, line, options, context).finally(ended);\n }\n\n async #grouped(\n groups: ProcessGroups,\n owner: number,\n line: string | readonly string[],\n options: ShellExecOptions | undefined,\n context: Context\n ): Promise<Result<ShellExecResult, ExecutionError>> {\n for (let wait = groups.pending(owner); wait; wait = groups.pending(owner)) await wait;\n const pgid = groups.shared(owner);\n const release = pgid === undefined && groups.joins() ? groups.reserve(owner) : () => undefined;\n const spawned = (process: KernelProcess) => {\n groups.track(owner, process);\n release();\n };\n const join = groups.joins()\n ? {\n ...(pgid === undefined ? {} : { pgid }),\n refused: (code: string) => groups.refused(owner, code),\n }\n : undefined;\n return execute(this.#client, this.cwd, line, options, context, spawned, join).finally(release);\n }\n\n async cleanup(context: Context): Promise<void> {\n for (const watcher of [...this.#watchers]) await watcher.close(context);\n this.#watchers.clear();\n }\n}\n\nexport const HOME = '/home';\n\nexport type EnvTargetLike = { cwd?: string; conversationId?: number; read?: unknown };\n\nexport function kernelEnvironment(\n client: KernelClient,\n options: Omit<KernelEnvOptions, 'cwd'> & {\n identify?: (target: EnvTargetLike, context: Context) => Promise<Record<string, string>>;\n } = {}\n): (target: EnvTargetLike, context?: Context) => SliccKernelEnv | Promise<SliccKernelEnv> {\n const { identify, ...rest } = options;\n const make = (target: EnvTargetLike, exports?: Record<string, string>) =>\n new SliccKernelEnv(client, {\n ...rest,\n cwd: target.cwd ?? HOME,\n ...(target.conversationId === undefined ? {} : { owner: target.conversationId }),\n ...(exports ? { exports } : {}),\n });\n return (target, context) =>\n identify && context\n ? identify(target, context).then((exports) => make(target, exports))\n : make(target);\n}\n"],
|
|
5
|
-
"mappings": "AACA;AAAA,EAKE;AAAA,EACA;AAAA,EAGA;AAAA,OAOK;
|
|
4
|
+
"sourcesContent": ["import type { Context } from '@earendil-works/chord';\nimport {\n type BinaryReader,\n type DirReader,\n type ExecutionEnv,\n type ExecutionError,\n err,\n FileError,\n type FileInfo,\n type FileWatcher,\n ok,\n type Result,\n type ShellExecOptions,\n type ShellExecResult,\n type TextLineReader,\n type WatchChange,\n type WatchTarget,\n} from '@earendil-works/pi-durable/env';\nimport { mimeOf } from '../images/index.ts';\nimport type { Scrub } from '../secrets/scrub.ts';\nimport type { Activity } from './activity.ts';\nimport type { KernelClient, KernelProcess } from './client.ts';\nimport { type ExecHooks, execute } from './exec.ts';\nimport { attempt, info, KernelDirReader, SnapshotLines, SnapshotReader } from './files.ts';\nimport type { ProcessGroups } from './groups.ts';\nimport { dirname, normalize, resolve } from './paths.ts';\nimport { nativeWatch, type PollOptions, pollWatch, RESCAN_MS } from './watch.ts';\n\nexport interface KernelEnvOptions {\n cwd: string;\n id?: string;\n watch?: PollOptions;\n activity?: Activity;\n groups?: ProcessGroups;\n owner?: number;\n exports?: Readonly<Record<string, string>>;\n scrub?: Scrub;\n spawn?: (argv: readonly string[]) => readonly string[];\n}\n\nexport const STREAMED_READ = 8 * 1024 * 1024;\nexport const READ_CHUNK = 1024 * 1024;\n\nexport async function scrubbedFile(scrub: Scrub, bytes: Uint8Array): Promise<Uint8Array> {\n if (mimeOf(bytes)) return bytes;\n if (bytes.length <= STREAMED_READ) return (await scrub.texts([bytes]))[0] as Uint8Array;\n const stream = scrub.stream();\n const parts: Uint8Array[] = [];\n for (let at = 0; at < bytes.length; at += READ_CHUNK)\n parts.push(await stream.push(bytes.subarray(at, at + READ_CHUNK)));\n parts.push(await stream.end());\n const all = new Uint8Array(parts.reduce((sum, part) => sum + part.length, 0));\n let offset = 0;\n for (const part of parts) {\n all.set(part, offset);\n offset += part.length;\n }\n return all;\n}\n\nexport function quote(value: string): string {\n return `'${value.replace(/'/g, \"'\\\\''\")}'`;\n}\n\nexport function prefixed(\n command: string,\n exports: Readonly<Record<string, string>> | undefined\n): string {\n const names = Object.keys(exports ?? {}).filter((name) => /^[A-Z_][A-Z0-9_]*$/.test(name));\n if (!names.length) return command;\n return `export ${names.map((name) => `${name}=${quote((exports as Record<string, string>)[name] as string)}`).join(' ')}; ${command}`;\n}\n\ntype FileResult<T> = Promise<Result<T, FileError>>;\n\nexport class SliccKernelEnv implements ExecutionEnv {\n readonly id: string;\n cwd: string;\n readonly #client: KernelClient;\n readonly #watchers = new Set<FileWatcher>();\n readonly #poll: PollOptions;\n readonly #activity: Activity | undefined;\n readonly #groups: ProcessGroups | undefined;\n readonly #owner: number | undefined;\n readonly #exports: Readonly<Record<string, string>> | undefined;\n readonly #hooks: ExecHooks;\n readonly #scrub: Scrub | undefined;\n\n constructor(client: KernelClient, options: KernelEnvOptions) {\n this.#client = client;\n this.cwd = options.cwd;\n this.id = options.id ?? 'slicc-kernel';\n this.#poll = options.watch ?? {};\n this.#activity = options.activity;\n this.#groups = options.groups;\n this.#owner = options.owner;\n this.#exports = options.exports;\n this.#scrub = options.scrub;\n const scrub = options.scrub;\n this.#hooks = {\n ...(scrub ? { scrub: () => scrub.stream() } : {}),\n ...(options.spawn ? { spawn: options.spawn } : {}),\n };\n }\n\n #path(path: string): string {\n return resolve(this.cwd, path);\n }\n\n #written(path: string): string {\n const resolved = this.#path(path);\n this.#activity?.wrote(resolved);\n return resolved;\n }\n\n get #fs() {\n return this.#client.fs;\n }\n\n async absolutePath(path: string): FileResult<string> {\n return ok(this.#path(path));\n }\n\n async joinPath(parts: string[]): FileResult<string> {\n return ok(normalize(parts.join('/')));\n }\n\n readTextFile(path: string, context: Context): FileResult<string> {\n const resolved = this.#path(path);\n return attempt(context, resolved, () => this.#fs.readText(resolved));\n }\n\n readBinaryFile(path: string, context: Context): FileResult<Uint8Array> {\n const resolved = this.#path(path);\n return attempt(context, resolved, () => this.#fs.readFile(resolved));\n }\n\n async openTextLineReader(path: string, context: Context): FileResult<TextLineReader> {\n const text = await this.readTextFile(path, context);\n return text.ok ? ok(new SnapshotLines(text.value)) : text;\n }\n\n async readTextLines(\n path: string,\n options: { maxLines?: number } | undefined,\n context: Context\n ): FileResult<string[]> {\n if (options?.maxLines !== undefined && options.maxLines <= 0) return ok([]);\n const text = await this.readTextFile(path, context);\n if (!text.ok) return text;\n const reader = new SnapshotLines(text.value);\n const lines: string[] = [];\n for (\n let line = await reader.readLine();\n line.ok && line.value;\n line = await reader.readLine()\n ) {\n if (options?.maxLines !== undefined && lines.length >= options.maxLines) break;\n lines.push(line.value.text);\n }\n return ok(lines);\n }\n\n openBinaryReader(\n path: string,\n options: { noFollow?: boolean } | undefined,\n context: Context\n ): FileResult<BinaryReader> {\n const resolved = this.#path(path);\n return attempt(context, resolved, async () => {\n if (options?.noFollow && (await this.#fs.lstat(resolved)).isSymbolicLink) {\n throw new FileError('invalid', 'Refusing to follow a symbolic link', resolved);\n }\n const stat = await this.#fs.stat(resolved);\n if (stat.isDirectory) throw new FileError('is_directory', 'Is a directory', resolved);\n if (!stat.isFile) throw new FileError('invalid', 'Not a regular file', resolved);\n const bytes = await this.#fs.readFile(resolved);\n if (!this.#scrub) return new SnapshotReader(bytes, info(resolved, stat));\n const shown = await scrubbedFile(this.#scrub, bytes);\n return new SnapshotReader(shown, { ...info(resolved, stat), size: shown.length });\n });\n }\n\n writeFile(path: string, content: string | Uint8Array, context: Context): FileResult<void> {\n const resolved = this.#written(path);\n return attempt(context, resolved, async () => {\n await this.#fs.mkdir(dirname(resolved));\n await this.#fs.writeFile(resolved, content);\n });\n }\n\n appendFile(path: string, content: string | Uint8Array, context: Context): FileResult<void> {\n const resolved = this.#written(path);\n return attempt(context, resolved, async () => {\n const before = (await this.#fs.exists(resolved))\n ? await this.#fs.readFile(resolved)\n : new Uint8Array();\n const added = typeof content === 'string' ? new TextEncoder().encode(content) : content;\n const all = new Uint8Array(before.length + added.length);\n all.set(before);\n all.set(added, before.length);\n await this.#fs.mkdir(dirname(resolved));\n await this.#fs.writeFile(resolved, all);\n });\n }\n\n truncateFile(path: string, size: number, context: Context): FileResult<void> {\n const resolved = this.#written(path);\n if (!Number.isSafeInteger(size) || size < 0) {\n return Promise.resolve(\n err(new FileError('invalid', 'File size must be a non-negative integer', resolved))\n );\n }\n return attempt(context, resolved, async () => {\n const before = await this.#fs.readFile(resolved);\n const after = new Uint8Array(size);\n after.set(before.subarray(0, size));\n await this.#fs.writeFile(resolved, after);\n });\n }\n\n flushFile(path: string, context: Context): FileResult<void> {\n const resolved = this.#path(path);\n return attempt(context, resolved, async () => {\n if ((await this.#fs.stat(resolved)).isDirectory)\n throw Object.assign(new Error('Is a directory'), { code: 'EISDIR' });\n });\n }\n\n renameFile(sourcePath: string, destinationPath: string, context: Context): FileResult<void> {\n const source = this.#written(sourcePath);\n return attempt(context, source, () => this.#fs.rename(source, this.#written(destinationPath)));\n }\n\n fileInfo(path: string, context: Context): FileResult<FileInfo> {\n const resolved = this.#path(path);\n return attempt(context, resolved, async () => info(resolved, await this.#fs.lstat(resolved)));\n }\n\n async listDir(path: string, context: Context): FileResult<FileInfo[]> {\n const reader = await this.openDirReader(path, context);\n if (!reader.ok) return reader;\n return ok(await (reader.value as KernelDirReader).rest());\n }\n\n openDirReader(path: string, context: Context): FileResult<DirReader> {\n const resolved = this.#path(path);\n return attempt(context, resolved, async () => {\n if (!(await this.#fs.stat(resolved)).isDirectory) {\n throw Object.assign(new Error('Not a directory'), { code: 'ENOTDIR' });\n }\n return new KernelDirReader(this.#fs, resolved, await this.#fs.readdir(resolved));\n });\n }\n\n watch(\n targets: readonly WatchTarget[],\n onChange: (change: WatchChange) => void,\n context: Context\n ): FileResult<FileWatcher> {\n return attempt(context, this.cwd, async () => {\n let absorb: (paths: readonly string[]) => void = () => undefined;\n const reported = (change: WatchChange) => {\n if ('paths' in change) absorb(change.paths);\n onChange(change);\n };\n const native =\n this.#poll.mode === 'polling'\n ? undefined\n : await nativeWatch(this.#fs, this.cwd, targets, reported);\n const intervalMs = native ? (this.#poll.rescanMs ?? RESCAN_MS) : this.#poll.intervalMs;\n const polled = await pollWatch(this.#fs, this.cwd, targets, onChange, {\n ...(intervalMs === undefined ? {} : { intervalMs }),\n });\n absorb = (paths) => polled.absorb(paths);\n const watcher: FileWatcher = native\n ? {\n mode: 'native',\n async close(closing: Context) {\n await native.close(closing);\n await polled.close(closing);\n },\n }\n : polled;\n this.#watchers.add(watcher);\n return {\n mode: watcher.mode,\n close: async (closing: Context) => {\n this.#watchers.delete(watcher);\n await watcher.close(closing);\n },\n };\n });\n }\n\n canonicalPath(path: string, context: Context): FileResult<string> {\n const resolved = this.#path(path);\n return attempt(context, resolved, () => this.#fs.realpath(resolved));\n }\n\n async exists(path: string, context: Context): FileResult<boolean> {\n const found = await this.fileInfo(path, context);\n if (found.ok) return ok(true);\n return found.error.code === 'not_found' ? ok(false) : found;\n }\n\n createDir(\n path: string,\n _options: { recursive?: boolean } | undefined,\n context: Context\n ): FileResult<void> {\n const resolved = this.#written(path);\n return attempt(context, resolved, () => this.#fs.mkdir(resolved));\n }\n\n remove(\n path: string,\n options: { recursive?: boolean; force?: boolean } | undefined,\n context: Context\n ): FileResult<void> {\n const resolved = this.#written(path);\n return attempt(context, resolved, async () => {\n if (!options?.recursive) {\n const stat = await this.#fs.lstat(resolved).catch((error: unknown) => {\n if (options?.force) return undefined;\n throw error;\n });\n if (stat?.isDirectory) throw Object.assign(new Error('Is a directory'), { code: 'EISDIR' });\n }\n await this.#fs.rm(resolved, { force: options?.force ?? false });\n });\n }\n\n async createTempDir(prefix: string | undefined, context: Context): FileResult<string> {\n const path = `/tmp/${prefix ?? 'tmp-'}${crypto.randomUUID()}`;\n return attempt(context, path, async () => {\n await this.#fs.mkdir(path);\n return path;\n });\n }\n\n async createTempFile(\n options: { prefix?: string; suffix?: string } | undefined,\n context: Context\n ): FileResult<string> {\n const dir = await this.createTempDir('tmp-', context);\n if (!dir.ok) return dir;\n const path = `${dir.value}/${options?.prefix ?? ''}${crypto.randomUUID()}${options?.suffix ?? ''}`;\n return attempt(context, path, async () => {\n await this.#fs.writeFile(path, '');\n return path;\n });\n }\n\n exec(\n command: string | readonly string[],\n options: ShellExecOptions | undefined,\n context: Context\n ): Promise<Result<ShellExecResult, ExecutionError>> {\n const ended = this.#activity?.began();\n const line = typeof command === 'string' ? prefixed(command, this.#exports) : command;\n const groups = this.#groups;\n const owner = this.#owner;\n if (!groups || owner === undefined)\n return execute(\n this.#client,\n this.cwd,\n line,\n options,\n context,\n undefined,\n undefined,\n this.#hooks\n ).finally(ended);\n return this.#grouped(groups, owner, line, options, context).finally(ended);\n }\n\n async #grouped(\n groups: ProcessGroups,\n owner: number,\n line: string | readonly string[],\n options: ShellExecOptions | undefined,\n context: Context\n ): Promise<Result<ShellExecResult, ExecutionError>> {\n for (let wait = groups.pending(owner); wait; wait = groups.pending(owner)) await wait;\n const pgid = groups.shared(owner);\n const release = pgid === undefined && groups.joins() ? groups.reserve(owner) : () => undefined;\n const spawned = (process: KernelProcess) => {\n groups.track(owner, process);\n release();\n };\n const join = groups.joins()\n ? {\n ...(pgid === undefined ? {} : { pgid }),\n refused: (code: string) => groups.refused(owner, code),\n }\n : undefined;\n return execute(\n this.#client,\n this.cwd,\n line,\n options,\n context,\n spawned,\n join,\n this.#hooks\n ).finally(release);\n }\n\n async cleanup(context: Context): Promise<void> {\n for (const watcher of [...this.#watchers]) await watcher.close(context);\n this.#watchers.clear();\n }\n}\n\nexport const HOME = '/home';\n\nexport type EnvTargetLike = { cwd?: string; conversationId?: number; read?: unknown };\n\nexport function kernelEnvironment(\n client: KernelClient,\n options: Omit<KernelEnvOptions, 'cwd'> & {\n identify?: (target: EnvTargetLike, context: Context) => Promise<Record<string, string>>;\n } = {}\n): (target: EnvTargetLike, context?: Context) => SliccKernelEnv | Promise<SliccKernelEnv> {\n const { identify, ...rest } = options;\n const make = (target: EnvTargetLike, exports?: Record<string, string>) =>\n new SliccKernelEnv(client, {\n ...rest,\n cwd: target.cwd ?? HOME,\n ...(target.conversationId === undefined ? {} : { owner: target.conversationId }),\n ...(exports ? { exports } : {}),\n });\n return (target, context) =>\n identify && context\n ? identify(target, context).then((exports) => make(target, exports))\n : make(target);\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|