@ai-ecoverse/slicc-agent 6.18.6 → 6.18.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/freezer/index.js +2 -1
- package/dist/freezer/index.js.map +2 -2
- package/dist/freezer/v6-journal.js +196 -0
- package/dist/freezer/v6-journal.js.map +7 -0
- package/dist/freezer/v6-place.js +1 -6
- package/dist/freezer/v6-place.js.map +2 -2
- package/dist/freezer/v6-write.js +14 -40
- package/dist/freezer/v6-write.js.map +2 -2
- package/dist/freezer/v6.js +45 -10
- package/dist/freezer/v6.js.map +2 -2
- package/dist/types/freezer/index.d.ts +1 -0
- package/dist/types/freezer/v6-journal.d.ts +39 -0
- package/dist/types/freezer/v6-write.d.ts +4 -3
- package/dist/types/freezer/v6.d.ts +3 -0
- package/package.json +4 -4
package/dist/freezer/index.js
CHANGED
|
@@ -499,6 +499,7 @@ function importing(options, now, refresh) {
|
|
|
499
499
|
}) : void 0;
|
|
500
500
|
return {
|
|
501
501
|
importing: importer?.progress ?? replicatedState(IDLE),
|
|
502
|
+
swept: importer?.swept ?? Promise.resolve(),
|
|
502
503
|
importProfile: async (source, choices, context) => importer ? importer.run(source, choices, context).then(async (result) => {
|
|
503
504
|
if (result.done) await refresh();
|
|
504
505
|
return result;
|
|
@@ -648,7 +649,7 @@ function attachFreezer(options) {
|
|
|
648
649
|
refresh,
|
|
649
650
|
touch,
|
|
650
651
|
frozenTarget: (target) => frozenTarget(agents.state(), target),
|
|
651
|
-
command: (argv, _caller, context, asker) => command(options, runtime, argv, context, asker),
|
|
652
|
+
command: (argv, _caller, context, asker) => runtime.swept.then(() => command(options, runtime, argv, context, asker)),
|
|
652
653
|
close: () => off()
|
|
653
654
|
};
|
|
654
655
|
return runtime;
|
|
@@ -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 ConeRecord,\n type FrozenRecord,\n live,\n type ScoopRecord,\n} from '../agents.ts';\nimport { HOME } from '../kernel/env.ts';\nimport { resolve } from '../kernel/paths.ts';\nimport { type Layout, LEGACY, ROOT_HOME, ROOT_USER } from '../layout.ts';\nimport type { LickTarget } from '../licks/lick.ts';\nimport { copyAgent, SELECTION, storedAgent } from '../selection.ts';\nimport { cleanTitle, TITLE_TURNS, titleDue } from '../titles/extension.ts';\nimport { scrubTranscript } from '../titles/generate.ts';\nimport {\n createImporter,\n IDLE,\n type ImportDeps,\n type ImportProgress,\n type ImportResult,\n type ImportSource,\n V6_KIND,\n} from './v6.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 v6?: true;\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 cancelTitle?: (agentId: string) => void;\n now?: () => number;\n layout?: Layout;\n imports?: Omit<ImportDeps, 'agents' | 'layout' | 'now'>;\n}\n\nexport type Asker = { user: string | null; cwd: string };\n\nexport interface FreezerRuntime {\n readonly frozen: ReplicatedState<FrozenCone[]>;\n readonly importing: ReplicatedState<ImportProgress>;\n importProfile(\n source: ImportSource,\n options: { again?: boolean; preview?: boolean },\n context: Context\n ): Promise<ImportResult>;\n cancelImport(): void;\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(\n argv: readonly string[],\n caller: string | null,\n context: Context,\n asker?: Asker\n ): 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 freezer import [--again] [--preview] <zip>\n import a SLICC 6 profile export as frozen cones (root only)\n freezer import --in-place [--again] [--preview] <dir>\n import SLICC 6's directory form on this origin, moving its files\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\nfunction said(entry: EntryRecord, role: 'user' | 'assistant'): boolean {\n if (entry.kind === V6_KIND) return entry.model?.[0]?.role === role;\n return entry.kind === `pi.${role}`;\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) => said(entry, '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 (said(entry, 'user') && textOf(entry)) out.push('', '## User', '', textOf(entry));\n if (!said(entry, '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) => said(entry, 'user') || said(entry, 'assistant')).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\ntype Inspected = { stats: Stats; entries: readonly EntryRecord[] };\n\nasync function inspect(harness: Harness, id: number, context: Context): Promise<Inspected> {\n const conversation = await harness.conversation(id as ConversationId, context);\n if (!conversation)\n return { stats: { title: firstLine([]), model: '', messages: 0, frozenAt: 0 }, entries: [] };\n const view = await conversation.context(context);\n const agent = await conversation.agent(context);\n return {\n stats: {\n title: firstLine(view.entries),\n model: modelName(agent.model),\n messages: counted(view.entries),\n frozenAt: lastAt(view.entries),\n },\n entries: view.entries,\n };\n}\n\ntype Titled = Pick<ConeRecord, 'conversation' | 'title' | 'titled'>;\n\ntype Seen = (id: string, record: Titled, entries: readonly EntryRecord[], model: string) => void;\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 seen?: Seen\n): Promise<FrozenCone[]> {\n const stopped = async (conversation: number) => {\n const cached = cache.get(conversation);\n if (cached) return cached;\n const found = (await inspect(harness, conversation, context)).stats;\n cache.set(conversation, found);\n return found;\n };\n const ended = async (id: string, record: Titled) => {\n const stats = await stopped(record.conversation);\n if (seen && (record.titled ?? 0) < (TITLE_TURNS.at(-1) as number)) {\n const { entries } = await inspect(harness, record.conversation, context);\n seen(id, record, entries, stats.model);\n }\n return { ...stats, ...(record.title ? { title: record.title } : {}) };\n };\n const running = async (record: Titled) => {\n const { stats } = await inspect(harness, record.conversation, context);\n return { ...stats, ...(record.title ? { title: record.title } : {}) };\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 running(cone)),\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 ...(record.v6 ? { v6: true as const } : {}),\n });\n for (const [id, scoop] of Object.entries(state.scoops)) {\n if (scoop.removed) continue;\n const on = live(scoop);\n out.push({\n id,\n name: scoop.name,\n ...(on ? await running(scoop) : await ended(id, scoop)),\n kind: kindOf(scoop),\n live: on,\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 home = HOME\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 title?: string\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: 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 importCommand(\n runtime: FreezerRuntime,\n args: readonly string[],\n asker: Asker | undefined,\n context: Context\n): Promise<Answer> {\n if (asker?.user && asker.user !== ROOT_USER)\n return { code: 1, out: 'freezer: only root can import; run sudo freezer import\\n' };\n const flags = args.filter((arg) => arg.startsWith('--'));\n const paths = args.filter((arg) => !arg.startsWith('--'));\n const known = ['--again', '--preview', '--in-place'];\n if (paths.length !== 1 || flags.some((flag) => !known.includes(flag)))\n return { code: 2, out: USAGE };\n const path = resolve(asker?.cwd ?? ROOT_HOME, paths[0] as string);\n const result = await runtime.importProfile(\n flags.includes('--in-place') ? { inPlace: path } : { path },\n { again: flags.includes('--again'), preview: flags.includes('--preview') },\n context\n );\n return result.error\n ? { code: 1, out: `freezer: ${result.error}\\n` }\n : { code: 0, out: result.line };\n}\n\nasync function command(\n options: FreezerAttach,\n runtime: FreezerRuntime,\n argv: readonly string[],\n context: Context,\n asker?: Asker\n): Promise<Answer> {\n const verb = argv[0] ?? 'help';\n if (verb === 'import') return importCommand(runtime, argv.slice(1), asker, context);\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 init = copyAgent(await storedAgent(harness, conversation.id, context));\n return harness.createConversation({ ownership: { kind: 'ownerless' }, init }, context);\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 const layout = options.layout ?? LEGACY;\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 storedAgent(harness, (await activeCone(agents, context)).id, 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 ...(layout.users ? {} : { cwd: HOME }),\n },\n init: copyAgent(cone, SELECTION),\n };\n const fork = last\n ? await conversation.fork(last.id, created, context)\n : await harness.createConversation(created, context);\n const folder = layout.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(\n kindOf(scoop),\n scoop.name,\n folder,\n kept,\n layout.users ? 'your own home' : HOME\n ),\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] = {\n name: scoop.name,\n conversation: fork.id,\n ...(scoop.title ? { title: scoop.title, titled: scoop.titled as number } : {}),\n };\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(\n (options.layout ?? LEGACY).scoopRoot(scoop.folder),\n {\n recursive: true,\n force: true,\n },\n context\n );\n}\n\nfunction listing(harness: Harness, agents: Agents, seen: Seen | undefined) {\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, seen);\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\nexport function v6Note(home: string, record: Pick<FrozenRecord, 'name' | 'v6'>): string {\n const suffix = record.v6?.suffix ?? '';\n return `This was ${record.name}, a conversation imported from SLICC 6, thawed as a cone. SLICC 6's /workspace is now ~/workspace${suffix} (${home}/workspace${suffix}), and its scoops' files are in ${home}/scoops${suffix}. Paths in the conversation above are SLICC 6's.`;\n}\n\nasync function forkV6(\n options: FreezerAttach & { now: () => number },\n record: FrozenRecord,\n context: Context\n): Promise<Conversation> {\n const { harness, agents } = options;\n const layout = options.layout ?? LEGACY;\n const conversation = await harness.conversation(record.conversation as ConversationId, context);\n if (!conversation) throw new Error(`There is no conversation for ${record.name}.`);\n const last = (await conversation.context(context)).entries.at(-1);\n const cone = await activeCone(agents, context);\n const agent = await cone.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 ...(layout.users ? {} : { cwd: HOME }),\n },\n init: copyAgent(await storedAgent(harness, cone.id, context), SELECTION),\n };\n const fork = last\n ? await conversation.fork(last.id, created, context)\n : await harness.createConversation(created, context);\n const home = `/home/${record.cone}`;\n await fork.submit(\n {\n type: 'write',\n entry: {\n kind: THAWED_KIND,\n data: {\n v6: true,\n name: record.name,\n kind: 'cone',\n workspace: `${home}/workspace${record.v6?.suffix ?? ''}`,\n kept: true,\n },\n model: [{ role: 'user', content: v6Note(home, record), timestamp: options.now() }],\n },\n },\n context\n );\n return fork;\n}\n\nasync function thawInto(\n options: FreezerAttach & { now: () => number },\n runtime: Pick<FreezerRuntime, 'newChat'>,\n id: string,\n context: Context\n): Promise<string> {\n const { agents } = options;\n const record = agents.state().frozen?.[id] as FrozenRecord;\n const fork = await forkV6(options, record, context);\n await runtime.newChat(record.cone, context);\n await agents.setConversation(record.cone, fork, context);\n await agents.update((_tx, doc) => {\n const cone = doc.cones[record.cone] as ConeRecord;\n cone.title = record.title;\n cone.titled = TITLE_TURNS.at(-1) as number;\n for (const scoop of record.scoops) {\n const entry = doc.scoops[scoop];\n if (!entry) continue;\n delete entry.frozen;\n entry.cone = record.cone;\n }\n delete doc.frozen?.[id];\n }, context);\n await agents.selectCone(record.cone, context);\n return record.cone;\n}\n\nasync function thawFrozen(\n options: FreezerAttach & { now: () => number },\n runtime: Pick<FreezerRuntime, 'newChat'>,\n id: string,\n context: Context\n): Promise<string> {\n const { agents } = options;\n const found = agents.state().frozen?.[id];\n if (found?.v6 && agents.state().cones[found.cone]) return thawInto(options, runtime, id, context);\n const fork = found?.v6 ? await forkV6(options, found, context) : undefined;\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] = {\n name: record.name,\n conversation: fork?.id ?? record.conversation,\n title: record.title,\n titled: TITLE_TURNS.at(-1) as number,\n };\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(\n (options.layout ?? LEGACY).scoopRoot(folder),\n {\n recursive: true,\n force: true,\n },\n context\n );\n}\n\nfunction titling(options: FreezerAttach) {\n const { agents } = options;\n const pending = new Set<string>();\n const last = TITLE_TURNS.at(-1) as number;\n const named = (entries: readonly EntryRecord[], model: string, context: Context) =>\n scrubTranscript(entries)\n .then((transcript) =>\n (options.title as NonNullable<FreezerAttach['title']>)(transcript, model, context)\n )\n .then(cleanTitle)\n .catch(() => undefined);\n const write = (id: string, titled: Titled, title: string | undefined) =>\n agents\n .update((_tx, doc) => {\n const record = doc.scoops[id];\n if (record?.conversation !== titled.conversation || (record.titled ?? 0) >= last) return;\n record.titled = last;\n if (title) record.title = title;\n }, BACKGROUND_CONTEXT)\n .catch(() => undefined);\n const seen: Seen = (id, seenAs, entries, model) => {\n const titled = agents.state().scoops[id];\n if (titled?.conversation !== seenAs.conversation || pending.has(id)) return;\n if (titleDue(titled, entries, true) === undefined) {\n void write(id, titled, undefined);\n return;\n }\n pending.add(id);\n void named(entries, model, BACKGROUND_CONTEXT)\n .then((title) => write(id, titled, title))\n .finally(() => pending.delete(id));\n };\n return { named, seen };\n}\n\nfunction importing(\n options: FreezerAttach,\n now: () => number,\n refresh: () => Promise<unknown>\n): Pick<FreezerRuntime, 'importing' | 'importProfile' | 'cancelImport'> {\n const importer = options.imports\n ? createImporter({\n ...options.imports,\n agents: options.agents,\n layout: options.layout ?? LEGACY,\n now,\n })\n : undefined;\n return {\n importing: importer?.progress ?? replicatedState<ImportProgress>(IDLE),\n importProfile: async (source, choices, context) =>\n importer\n ? importer.run(source, choices, context).then(async (result) => {\n if (result.done) await refresh();\n return result;\n })\n : {\n done: false,\n preview: null,\n cones: [],\n report: null,\n text: '',\n line: '',\n error: 'this agent imports nothing',\n },\n cancelImport: () => importer?.cancel(),\n };\n}\n\nexport function attachFreezer(options: FreezerAttach): FreezerRuntime {\n const { harness, agents } = options;\n const now = options.now ?? Date.now;\n const { named, seen } = titling(options);\n const { frozen, refresh, touch, off } = listing(\n harness,\n agents,\n options.title ? seen : undefined\n );\n\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 void named(entries, model, context)\n .then(async (title) => {\n if (!title) return;\n await agents.update((_tx, doc) => {\n const record = doc.frozen?.[id];\n if (record) record.title = title;\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 ...importing(options, now, refresh),\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(\n conversation,\n cone.name,\n now(),\n context,\n cone.title\n );\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 options.cancelTitle?.(agentId);\n await (await agents.conversation(agentId, context))?.reset(undefined, context);\n await agents.update((_tx, doc) => {\n const record = doc.scoops[agentId] as ScoopRecord;\n delete record.title;\n delete record.titled;\n }, 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 const title = cone.title;\n if (!before.some((entry) => said(entry, '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, title);\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({ ...options, now }, runtime, 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, asker) => command(options, runtime, argv, context, asker),\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 ConeRecord,\n type FrozenRecord,\n live,\n type ScoopRecord,\n} from '../agents.ts';\nimport { HOME } from '../kernel/env.ts';\nimport { resolve } from '../kernel/paths.ts';\nimport { type Layout, LEGACY, ROOT_HOME, ROOT_USER } from '../layout.ts';\nimport type { LickTarget } from '../licks/lick.ts';\nimport { copyAgent, SELECTION, storedAgent } from '../selection.ts';\nimport { cleanTitle, TITLE_TURNS, titleDue } from '../titles/extension.ts';\nimport { scrubTranscript } from '../titles/generate.ts';\nimport {\n createImporter,\n IDLE,\n type ImportDeps,\n type ImportProgress,\n type ImportResult,\n type ImportSource,\n V6_KIND,\n} from './v6.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 v6?: true;\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 cancelTitle?: (agentId: string) => void;\n now?: () => number;\n layout?: Layout;\n imports?: Omit<ImportDeps, 'agents' | 'layout' | 'now'>;\n}\n\nexport type Asker = { user: string | null; cwd: string };\n\nexport interface FreezerRuntime {\n readonly frozen: ReplicatedState<FrozenCone[]>;\n readonly importing: ReplicatedState<ImportProgress>;\n readonly swept: Promise<void>;\n importProfile(\n source: ImportSource,\n options: { again?: boolean; preview?: boolean },\n context: Context\n ): Promise<ImportResult>;\n cancelImport(): void;\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(\n argv: readonly string[],\n caller: string | null,\n context: Context,\n asker?: Asker\n ): 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 freezer import [--again] [--preview] <zip>\n import a SLICC 6 profile export as frozen cones (root only)\n freezer import --in-place [--again] [--preview] <dir>\n import SLICC 6's directory form on this origin, moving its files\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\nfunction said(entry: EntryRecord, role: 'user' | 'assistant'): boolean {\n if (entry.kind === V6_KIND) return entry.model?.[0]?.role === role;\n return entry.kind === `pi.${role}`;\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) => said(entry, '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 (said(entry, 'user') && textOf(entry)) out.push('', '## User', '', textOf(entry));\n if (!said(entry, '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) => said(entry, 'user') || said(entry, 'assistant')).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\ntype Inspected = { stats: Stats; entries: readonly EntryRecord[] };\n\nasync function inspect(harness: Harness, id: number, context: Context): Promise<Inspected> {\n const conversation = await harness.conversation(id as ConversationId, context);\n if (!conversation)\n return { stats: { title: firstLine([]), model: '', messages: 0, frozenAt: 0 }, entries: [] };\n const view = await conversation.context(context);\n const agent = await conversation.agent(context);\n return {\n stats: {\n title: firstLine(view.entries),\n model: modelName(agent.model),\n messages: counted(view.entries),\n frozenAt: lastAt(view.entries),\n },\n entries: view.entries,\n };\n}\n\ntype Titled = Pick<ConeRecord, 'conversation' | 'title' | 'titled'>;\n\ntype Seen = (id: string, record: Titled, entries: readonly EntryRecord[], model: string) => void;\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 seen?: Seen\n): Promise<FrozenCone[]> {\n const stopped = async (conversation: number) => {\n const cached = cache.get(conversation);\n if (cached) return cached;\n const found = (await inspect(harness, conversation, context)).stats;\n cache.set(conversation, found);\n return found;\n };\n const ended = async (id: string, record: Titled) => {\n const stats = await stopped(record.conversation);\n if (seen && (record.titled ?? 0) < (TITLE_TURNS.at(-1) as number)) {\n const { entries } = await inspect(harness, record.conversation, context);\n seen(id, record, entries, stats.model);\n }\n return { ...stats, ...(record.title ? { title: record.title } : {}) };\n };\n const running = async (record: Titled) => {\n const { stats } = await inspect(harness, record.conversation, context);\n return { ...stats, ...(record.title ? { title: record.title } : {}) };\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 running(cone)),\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 ...(record.v6 ? { v6: true as const } : {}),\n });\n for (const [id, scoop] of Object.entries(state.scoops)) {\n if (scoop.removed) continue;\n const on = live(scoop);\n out.push({\n id,\n name: scoop.name,\n ...(on ? await running(scoop) : await ended(id, scoop)),\n kind: kindOf(scoop),\n live: on,\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 home = HOME\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 title?: string\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: 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 importCommand(\n runtime: FreezerRuntime,\n args: readonly string[],\n asker: Asker | undefined,\n context: Context\n): Promise<Answer> {\n if (asker?.user && asker.user !== ROOT_USER)\n return { code: 1, out: 'freezer: only root can import; run sudo freezer import\\n' };\n const flags = args.filter((arg) => arg.startsWith('--'));\n const paths = args.filter((arg) => !arg.startsWith('--'));\n const known = ['--again', '--preview', '--in-place'];\n if (paths.length !== 1 || flags.some((flag) => !known.includes(flag)))\n return { code: 2, out: USAGE };\n const path = resolve(asker?.cwd ?? ROOT_HOME, paths[0] as string);\n const result = await runtime.importProfile(\n flags.includes('--in-place') ? { inPlace: path } : { path },\n { again: flags.includes('--again'), preview: flags.includes('--preview') },\n context\n );\n return result.error\n ? { code: 1, out: `freezer: ${result.error}\\n` }\n : { code: 0, out: result.line };\n}\n\nasync function command(\n options: FreezerAttach,\n runtime: FreezerRuntime,\n argv: readonly string[],\n context: Context,\n asker?: Asker\n): Promise<Answer> {\n const verb = argv[0] ?? 'help';\n if (verb === 'import') return importCommand(runtime, argv.slice(1), asker, context);\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 init = copyAgent(await storedAgent(harness, conversation.id, context));\n return harness.createConversation({ ownership: { kind: 'ownerless' }, init }, context);\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 const layout = options.layout ?? LEGACY;\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 storedAgent(harness, (await activeCone(agents, context)).id, 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 ...(layout.users ? {} : { cwd: HOME }),\n },\n init: copyAgent(cone, SELECTION),\n };\n const fork = last\n ? await conversation.fork(last.id, created, context)\n : await harness.createConversation(created, context);\n const folder = layout.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(\n kindOf(scoop),\n scoop.name,\n folder,\n kept,\n layout.users ? 'your own home' : HOME\n ),\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] = {\n name: scoop.name,\n conversation: fork.id,\n ...(scoop.title ? { title: scoop.title, titled: scoop.titled as number } : {}),\n };\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(\n (options.layout ?? LEGACY).scoopRoot(scoop.folder),\n {\n recursive: true,\n force: true,\n },\n context\n );\n}\n\nfunction listing(harness: Harness, agents: Agents, seen: Seen | undefined) {\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, seen);\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\nexport function v6Note(home: string, record: Pick<FrozenRecord, 'name' | 'v6'>): string {\n const suffix = record.v6?.suffix ?? '';\n return `This was ${record.name}, a conversation imported from SLICC 6, thawed as a cone. SLICC 6's /workspace is now ~/workspace${suffix} (${home}/workspace${suffix}), and its scoops' files are in ${home}/scoops${suffix}. Paths in the conversation above are SLICC 6's.`;\n}\n\nasync function forkV6(\n options: FreezerAttach & { now: () => number },\n record: FrozenRecord,\n context: Context\n): Promise<Conversation> {\n const { harness, agents } = options;\n const layout = options.layout ?? LEGACY;\n const conversation = await harness.conversation(record.conversation as ConversationId, context);\n if (!conversation) throw new Error(`There is no conversation for ${record.name}.`);\n const last = (await conversation.context(context)).entries.at(-1);\n const cone = await activeCone(agents, context);\n const agent = await cone.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 ...(layout.users ? {} : { cwd: HOME }),\n },\n init: copyAgent(await storedAgent(harness, cone.id, context), SELECTION),\n };\n const fork = last\n ? await conversation.fork(last.id, created, context)\n : await harness.createConversation(created, context);\n const home = `/home/${record.cone}`;\n await fork.submit(\n {\n type: 'write',\n entry: {\n kind: THAWED_KIND,\n data: {\n v6: true,\n name: record.name,\n kind: 'cone',\n workspace: `${home}/workspace${record.v6?.suffix ?? ''}`,\n kept: true,\n },\n model: [{ role: 'user', content: v6Note(home, record), timestamp: options.now() }],\n },\n },\n context\n );\n return fork;\n}\n\nasync function thawInto(\n options: FreezerAttach & { now: () => number },\n runtime: Pick<FreezerRuntime, 'newChat'>,\n id: string,\n context: Context\n): Promise<string> {\n const { agents } = options;\n const record = agents.state().frozen?.[id] as FrozenRecord;\n const fork = await forkV6(options, record, context);\n await runtime.newChat(record.cone, context);\n await agents.setConversation(record.cone, fork, context);\n await agents.update((_tx, doc) => {\n const cone = doc.cones[record.cone] as ConeRecord;\n cone.title = record.title;\n cone.titled = TITLE_TURNS.at(-1) as number;\n for (const scoop of record.scoops) {\n const entry = doc.scoops[scoop];\n if (!entry) continue;\n delete entry.frozen;\n entry.cone = record.cone;\n }\n delete doc.frozen?.[id];\n }, context);\n await agents.selectCone(record.cone, context);\n return record.cone;\n}\n\nasync function thawFrozen(\n options: FreezerAttach & { now: () => number },\n runtime: Pick<FreezerRuntime, 'newChat'>,\n id: string,\n context: Context\n): Promise<string> {\n const { agents } = options;\n const found = agents.state().frozen?.[id];\n if (found?.v6 && agents.state().cones[found.cone]) return thawInto(options, runtime, id, context);\n const fork = found?.v6 ? await forkV6(options, found, context) : undefined;\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] = {\n name: record.name,\n conversation: fork?.id ?? record.conversation,\n title: record.title,\n titled: TITLE_TURNS.at(-1) as number,\n };\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(\n (options.layout ?? LEGACY).scoopRoot(folder),\n {\n recursive: true,\n force: true,\n },\n context\n );\n}\n\nfunction titling(options: FreezerAttach) {\n const { agents } = options;\n const pending = new Set<string>();\n const last = TITLE_TURNS.at(-1) as number;\n const named = (entries: readonly EntryRecord[], model: string, context: Context) =>\n scrubTranscript(entries)\n .then((transcript) =>\n (options.title as NonNullable<FreezerAttach['title']>)(transcript, model, context)\n )\n .then(cleanTitle)\n .catch(() => undefined);\n const write = (id: string, titled: Titled, title: string | undefined) =>\n agents\n .update((_tx, doc) => {\n const record = doc.scoops[id];\n if (record?.conversation !== titled.conversation || (record.titled ?? 0) >= last) return;\n record.titled = last;\n if (title) record.title = title;\n }, BACKGROUND_CONTEXT)\n .catch(() => undefined);\n const seen: Seen = (id, seenAs, entries, model) => {\n const titled = agents.state().scoops[id];\n if (titled?.conversation !== seenAs.conversation || pending.has(id)) return;\n if (titleDue(titled, entries, true) === undefined) {\n void write(id, titled, undefined);\n return;\n }\n pending.add(id);\n void named(entries, model, BACKGROUND_CONTEXT)\n .then((title) => write(id, titled, title))\n .finally(() => pending.delete(id));\n };\n return { named, seen };\n}\n\nfunction importing(\n options: FreezerAttach,\n now: () => number,\n refresh: () => Promise<unknown>\n): Pick<FreezerRuntime, 'importing' | 'swept' | 'importProfile' | 'cancelImport'> {\n const importer = options.imports\n ? createImporter({\n ...options.imports,\n agents: options.agents,\n layout: options.layout ?? LEGACY,\n now,\n })\n : undefined;\n return {\n importing: importer?.progress ?? replicatedState<ImportProgress>(IDLE),\n swept: importer?.swept ?? Promise.resolve(),\n importProfile: async (source, choices, context) =>\n importer\n ? importer.run(source, choices, context).then(async (result) => {\n if (result.done) await refresh();\n return result;\n })\n : {\n done: false,\n preview: null,\n cones: [],\n report: null,\n text: '',\n line: '',\n error: 'this agent imports nothing',\n },\n cancelImport: () => importer?.cancel(),\n };\n}\n\nexport function attachFreezer(options: FreezerAttach): FreezerRuntime {\n const { harness, agents } = options;\n const now = options.now ?? Date.now;\n const { named, seen } = titling(options);\n const { frozen, refresh, touch, off } = listing(\n harness,\n agents,\n options.title ? seen : undefined\n );\n\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 void named(entries, model, context)\n .then(async (title) => {\n if (!title) return;\n await agents.update((_tx, doc) => {\n const record = doc.frozen?.[id];\n if (record) record.title = title;\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 ...importing(options, now, refresh),\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(\n conversation,\n cone.name,\n now(),\n context,\n cone.title\n );\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 options.cancelTitle?.(agentId);\n await (await agents.conversation(agentId, context))?.reset(undefined, context);\n await agents.update((_tx, doc) => {\n const record = doc.scoops[agentId] as ScoopRecord;\n delete record.title;\n delete record.titled;\n }, 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 const title = cone.title;\n if (!before.some((entry) => said(entry, '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, title);\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({ ...options, now }, runtime, 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, asker) =>\n runtime.swept.then(() => command(options, runtime, argv, context, asker)),\n close: () => off(),\n };\n return runtime;\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": ["record", "item"]
|
|
7
7
|
}
|
|
@@ -0,0 +1,196 @@
|
|
|
1
|
+
import { BACKGROUND_CONTEXT } from "@earendil-works/chord/context";
|
|
2
|
+
import { homeOf } from "../kernel/accounts.js";
|
|
3
|
+
import { quote } from "../kernel/env.js";
|
|
4
|
+
import { writeTable } from "../licks/crontab.js";
|
|
5
|
+
import { IMPORTS_DIR } from "./paths.js";
|
|
6
|
+
import { DIRECTORY_ROOT } from "./v6-schema.js";
|
|
7
|
+
import { ImportError } from "./zip.js";
|
|
8
|
+
const HEADER = "journal.json";
|
|
9
|
+
const STEPS = "journal";
|
|
10
|
+
const encoder = new TextEncoder();
|
|
11
|
+
const decoder = new TextDecoder();
|
|
12
|
+
const text = (value) => typeof value === "string" && value.startsWith("/");
|
|
13
|
+
const backup = (value) => value === null || text(value);
|
|
14
|
+
function stepOf(value) {
|
|
15
|
+
const step = value;
|
|
16
|
+
if (typeof step !== "object" || step === null) return void 0;
|
|
17
|
+
if (text(step.made)) return step;
|
|
18
|
+
if (text(step.file) && backup(step.backup)) return step;
|
|
19
|
+
if (text(step.moved) && text(step.to)) return step;
|
|
20
|
+
if (typeof step.cron === "string" && backup(step.backup)) return step;
|
|
21
|
+
return void 0;
|
|
22
|
+
}
|
|
23
|
+
function headerOf(value) {
|
|
24
|
+
const header = value;
|
|
25
|
+
return typeof header?.key === "string" && typeof header.at === "number" && Array.isArray(header.cones) && header.cones.every((cone) => typeof cone === "string" && /^cone-\d+$/.test(cone)) && (header.source === null || header.source?.startsWith(`${DIRECTORY_ROOT}/`)) ? header : void 0;
|
|
26
|
+
}
|
|
27
|
+
const UNREAD = /* @__PURE__ */ Symbol("unread");
|
|
28
|
+
const ABSENT = /* @__PURE__ */ new Set(["not_found", "not_directory"]);
|
|
29
|
+
async function jsonIn(env, path) {
|
|
30
|
+
const read = await env.readTextFile(path, BACKGROUND_CONTEXT);
|
|
31
|
+
if (!read.ok) return await exists(env, path) === false ? void 0 : UNREAD;
|
|
32
|
+
try {
|
|
33
|
+
return JSON.parse(read.value);
|
|
34
|
+
} catch {
|
|
35
|
+
return void 0;
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
async function stepsIn(env, dir) {
|
|
39
|
+
const listed = await env.listDir(`${dir}/${STEPS}`, BACKGROUND_CONTEXT);
|
|
40
|
+
if (!listed.ok) return void 0;
|
|
41
|
+
const numbers = listed.value.map((item) => /^(\d+)\.json$/.exec(item.name)?.[1]).filter((name) => name !== void 0).map(Number).sort((a, b) => a - b);
|
|
42
|
+
const steps = [];
|
|
43
|
+
for (const n of numbers) {
|
|
44
|
+
const value = await jsonIn(env, `${dir}/${STEPS}/${n}.json`);
|
|
45
|
+
if (value === UNREAD) return void 0;
|
|
46
|
+
const step = stepOf(value);
|
|
47
|
+
if (step) steps.push(step);
|
|
48
|
+
}
|
|
49
|
+
return steps;
|
|
50
|
+
}
|
|
51
|
+
async function exists(env, path) {
|
|
52
|
+
const found = await env.exists(path, BACKGROUND_CONTEXT);
|
|
53
|
+
if (found.ok) return found.value;
|
|
54
|
+
return ABSENT.has(found.error.code) ? false : void 0;
|
|
55
|
+
}
|
|
56
|
+
async function bytesOf(env, path) {
|
|
57
|
+
if (path === null) return null;
|
|
58
|
+
const read = await env.readBinaryFile(path, BACKGROUND_CONTEXT);
|
|
59
|
+
return read.ok ? read.value : null;
|
|
60
|
+
}
|
|
61
|
+
const done = (result) => result.ok;
|
|
62
|
+
async function gone(env, path, recursive = true) {
|
|
63
|
+
const removed = await env.remove(path, { recursive, force: true }, BACKGROUND_CONTEXT);
|
|
64
|
+
return removed.ok || await exists(env, path) === false;
|
|
65
|
+
}
|
|
66
|
+
async function undoStep(deps, step, owners) {
|
|
67
|
+
const { env } = deps;
|
|
68
|
+
if ("made" in step) return gone(env, step.made);
|
|
69
|
+
if ("file" in step) {
|
|
70
|
+
if (step.backup === null) return gone(env, step.file, false);
|
|
71
|
+
const old2 = await bytesOf(env, step.backup);
|
|
72
|
+
return old2 !== null && done(await env.writeFile(step.file, old2, BACKGROUND_CONTEXT));
|
|
73
|
+
}
|
|
74
|
+
if ("moved" in step) {
|
|
75
|
+
const there = await exists(env, step.moved);
|
|
76
|
+
const to = await exists(env, step.to);
|
|
77
|
+
if (there === void 0 || to === void 0) return false;
|
|
78
|
+
if (!there && !to) return true;
|
|
79
|
+
const back = there || done(await env.renameFile(step.to, step.moved, BACKGROUND_CONTEXT));
|
|
80
|
+
if (back && step.mode) owners.set(step.mode, [...owners.get(step.mode) ?? [], step.moved]);
|
|
81
|
+
return back;
|
|
82
|
+
}
|
|
83
|
+
if (step.backup === null)
|
|
84
|
+
return done(await env.exec(`crontab -u ${quote(step.cron)} -r`, void 0, BACKGROUND_CONTEXT));
|
|
85
|
+
const old = await bytesOf(env, step.backup);
|
|
86
|
+
return old !== null && (await writeTable(env, step.cron, decoder.decode(old), BACKGROUND_CONTEXT)).code === 0;
|
|
87
|
+
}
|
|
88
|
+
async function chownAll(env, owners) {
|
|
89
|
+
let all = true;
|
|
90
|
+
for (const [both, paths] of owners) {
|
|
91
|
+
const [owner, mode] = both.split(" ");
|
|
92
|
+
for (let at = 0; at < paths.length; at += 200) {
|
|
93
|
+
const list = paths.slice(at, at + 200).map(quote).join(" ");
|
|
94
|
+
const ran = await env.exec(
|
|
95
|
+
`chown ${quote(owner)} -- ${list} && chmod ${quote(mode)} -- ${list}`,
|
|
96
|
+
void 0,
|
|
97
|
+
BACKGROUND_CONTEXT
|
|
98
|
+
);
|
|
99
|
+
all = all && ran.ok && ran.value.exitCode === 0;
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
return all;
|
|
103
|
+
}
|
|
104
|
+
function named(state, cone) {
|
|
105
|
+
return state.cones[cone] !== void 0 || Object.values(state.frozen ?? {}).some((record) => record.cone === cone);
|
|
106
|
+
}
|
|
107
|
+
const fails = () => false;
|
|
108
|
+
async function removeCone(deps, cone) {
|
|
109
|
+
const user = await deps.users?.remove(cone).then(() => true, fails) ?? true;
|
|
110
|
+
const home = await gone(deps.env, homeOf(cone)).catch(fails);
|
|
111
|
+
return user && home;
|
|
112
|
+
}
|
|
113
|
+
async function undo(deps, header, steps) {
|
|
114
|
+
const owners = /* @__PURE__ */ new Map();
|
|
115
|
+
let all = true;
|
|
116
|
+
for (const step of [...steps].reverse())
|
|
117
|
+
all = await undoStep(deps, step, owners).catch(fails) && all;
|
|
118
|
+
all = await chownAll(deps.env, owners).catch(fails) && all;
|
|
119
|
+
for (const cone of header.cones)
|
|
120
|
+
if (!named(deps.state(), cone)) all = await removeCone(deps, cone) && all;
|
|
121
|
+
return all;
|
|
122
|
+
}
|
|
123
|
+
async function settle(deps, dir) {
|
|
124
|
+
const value = await jsonIn(deps.env, `${dir}/${HEADER}`);
|
|
125
|
+
if (value === UNREAD) return false;
|
|
126
|
+
const header = headerOf(value);
|
|
127
|
+
if (!header) return true;
|
|
128
|
+
if (deps.state().imports?.[header.key]?.at !== header.at) {
|
|
129
|
+
const steps = await stepsIn(deps.env, dir);
|
|
130
|
+
return steps !== void 0 && undo(deps, header, steps);
|
|
131
|
+
}
|
|
132
|
+
if (!header.source) return true;
|
|
133
|
+
return gone(deps.env, header.source);
|
|
134
|
+
}
|
|
135
|
+
async function sweep(deps) {
|
|
136
|
+
const listed = await deps.env.listDir(IMPORTS_DIR, BACKGROUND_CONTEXT);
|
|
137
|
+
if (!listed.ok) return await exists(deps.env, IMPORTS_DIR) === false ? [] : [IMPORTS_DIR];
|
|
138
|
+
const kept = [];
|
|
139
|
+
for (const item of listed.value) {
|
|
140
|
+
if (item.kind !== "directory") continue;
|
|
141
|
+
const dir = `${IMPORTS_DIR}/${item.name}`;
|
|
142
|
+
if (!(await settle(deps, dir) && await gone(deps.env, dir))) kept.push(dir);
|
|
143
|
+
}
|
|
144
|
+
return kept;
|
|
145
|
+
}
|
|
146
|
+
class Journal {
|
|
147
|
+
#deps;
|
|
148
|
+
#dir;
|
|
149
|
+
#steps = [];
|
|
150
|
+
#header;
|
|
151
|
+
#next = 0;
|
|
152
|
+
constructor(deps, dir) {
|
|
153
|
+
this.#deps = deps;
|
|
154
|
+
this.#dir = dir;
|
|
155
|
+
}
|
|
156
|
+
async #write(path, bytes, context) {
|
|
157
|
+
const written = await this.#deps.env.writeFile(path, bytes, context);
|
|
158
|
+
if (!written.ok) throw new ImportError(`couldn't write ${path}: ${written.error.message}`);
|
|
159
|
+
}
|
|
160
|
+
async open(header, context) {
|
|
161
|
+
const made = await this.#deps.env.createDir(
|
|
162
|
+
`${this.#dir}/${STEPS}`,
|
|
163
|
+
{ recursive: true },
|
|
164
|
+
context
|
|
165
|
+
);
|
|
166
|
+
if (!made.ok) throw new ImportError(`couldn't write ${this.#dir}: ${made.error.message}`);
|
|
167
|
+
await this.#write(`${this.#dir}/${HEADER}`, JSON.stringify(header), context);
|
|
168
|
+
this.#header = header;
|
|
169
|
+
}
|
|
170
|
+
async backup(bytes, context) {
|
|
171
|
+
const path = `${this.#dir}/${STEPS}/${this.#next++}`;
|
|
172
|
+
await this.#write(path, typeof bytes === "string" ? encoder.encode(bytes) : bytes, context);
|
|
173
|
+
return path;
|
|
174
|
+
}
|
|
175
|
+
async log(step, context) {
|
|
176
|
+
await this.#write(`${this.#dir}/${STEPS}/${this.#next++}.json`, JSON.stringify(step), context);
|
|
177
|
+
this.#steps.push(step);
|
|
178
|
+
}
|
|
179
|
+
async rollback() {
|
|
180
|
+
return this.#header ? undo(this.#deps, this.#header, this.#steps) : true;
|
|
181
|
+
}
|
|
182
|
+
async close() {
|
|
183
|
+
await this.#deps.env.remove(`${this.#dir}/${HEADER}`, { force: true }, BACKGROUND_CONTEXT);
|
|
184
|
+
await this.#deps.env.remove(
|
|
185
|
+
`${this.#dir}/${STEPS}`,
|
|
186
|
+
{ recursive: true, force: true },
|
|
187
|
+
BACKGROUND_CONTEXT
|
|
188
|
+
);
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
export {
|
|
192
|
+
Journal,
|
|
193
|
+
sweep,
|
|
194
|
+
undo
|
|
195
|
+
};
|
|
196
|
+
//# sourceMappingURL=v6-journal.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../src/freezer/v6-journal.ts"],
|
|
4
|
+
"sourcesContent": ["import type { Context } from '@earendil-works/chord';\nimport { BACKGROUND_CONTEXT } from '@earendil-works/chord/context';\nimport type { ExecutionEnv } from '@earendil-works/pi-durable/env';\nimport type { AgentsState } from '../agents.ts';\nimport { homeOf } from '../kernel/accounts.ts';\nimport { quote } from '../kernel/env.ts';\nimport type { KernelUsers } from '../kernel/users.ts';\nimport { writeTable } from '../licks/crontab.ts';\nimport { IMPORTS_DIR } from './paths.ts';\nimport { DIRECTORY_ROOT } from './v6-schema.ts';\nimport { ImportError } from './zip.ts';\n\nexport type Step =\n | { made: string }\n | { file: string; backup: string | null }\n | { moved: string; to: string; mode: string | null }\n | { cron: string; backup: string | null };\n\nexport type Header = { key: string; at: number; cones: string[]; source: string | null };\n\nexport type Undoing = {\n env: ExecutionEnv;\n users?: Pick<KernelUsers, 'remove'> | undefined;\n state: () => Readonly<AgentsState>;\n};\n\nconst HEADER = 'journal.json';\nconst STEPS = 'journal';\nconst encoder = new TextEncoder();\nconst decoder = new TextDecoder();\n\nconst text = (value: unknown) => typeof value === 'string' && value.startsWith('/');\nconst backup = (value: unknown) => value === null || text(value);\n\nfunction stepOf(value: unknown): Step | undefined {\n const step = value as Record<string, unknown> | null;\n if (typeof step !== 'object' || step === null) return undefined;\n if (text(step.made)) return step as Step;\n if (text(step.file) && backup(step.backup)) return step as Step;\n if (text(step.moved) && text(step.to)) return step as Step;\n if (typeof step.cron === 'string' && backup(step.backup)) return step as Step;\n return undefined;\n}\n\nfunction headerOf(value: unknown): Header | undefined {\n const header = value as Partial<Header> | null;\n return typeof header?.key === 'string' &&\n typeof header.at === 'number' &&\n Array.isArray(header.cones) &&\n header.cones.every((cone) => typeof cone === 'string' && /^cone-\\d+$/.test(cone)) &&\n (header.source === null || header.source?.startsWith(`${DIRECTORY_ROOT}/`))\n ? (header as Header)\n : undefined;\n}\n\nconst UNREAD = Symbol('unread');\nconst ABSENT = new Set(['not_found', 'not_directory']);\n\nasync function jsonIn(env: ExecutionEnv, path: string): Promise<unknown> {\n const read = await env.readTextFile(path, BACKGROUND_CONTEXT);\n if (!read.ok) return (await exists(env, path)) === false ? undefined : UNREAD;\n try {\n return JSON.parse(read.value);\n } catch {\n return undefined;\n }\n}\n\nasync function stepsIn(env: ExecutionEnv, dir: string): Promise<Step[] | undefined> {\n const listed = await env.listDir(`${dir}/${STEPS}`, BACKGROUND_CONTEXT);\n if (!listed.ok) return undefined;\n const numbers = listed.value\n .map((item) => /^(\\d+)\\.json$/.exec(item.name)?.[1])\n .filter((name): name is string => name !== undefined)\n .map(Number)\n .sort((a, b) => a - b);\n const steps: Step[] = [];\n for (const n of numbers) {\n const value = await jsonIn(env, `${dir}/${STEPS}/${n}.json`);\n if (value === UNREAD) return undefined;\n const step = stepOf(value);\n if (step) steps.push(step);\n }\n return steps;\n}\n\nasync function exists(env: ExecutionEnv, path: string): Promise<boolean | undefined> {\n const found = await env.exists(path, BACKGROUND_CONTEXT);\n if (found.ok) return found.value;\n return ABSENT.has(found.error.code) ? false : undefined;\n}\n\nasync function bytesOf(env: ExecutionEnv, path: string | null): Promise<Uint8Array | null> {\n if (path === null) return null;\n const read = await env.readBinaryFile(path, BACKGROUND_CONTEXT);\n return read.ok ? read.value : null;\n}\n\nconst done = (result: { ok: boolean }) => result.ok;\n\nasync function gone(env: ExecutionEnv, path: string, recursive = true): Promise<boolean> {\n const removed = await env.remove(path, { recursive, force: true }, BACKGROUND_CONTEXT);\n return removed.ok || (await exists(env, path)) === false;\n}\n\nasync function undoStep(deps: Undoing, step: Step, owners: Map<string, string[]>) {\n const { env } = deps;\n if ('made' in step) return gone(env, step.made);\n if ('file' in step) {\n if (step.backup === null) return gone(env, step.file, false);\n const old = await bytesOf(env, step.backup);\n return old !== null && done(await env.writeFile(step.file, old, BACKGROUND_CONTEXT));\n }\n if ('moved' in step) {\n const there = await exists(env, step.moved);\n const to = await exists(env, step.to);\n if (there === undefined || to === undefined) return false;\n if (!there && !to) return true;\n const back = there || done(await env.renameFile(step.to, step.moved, BACKGROUND_CONTEXT));\n if (back && step.mode) owners.set(step.mode, [...(owners.get(step.mode) ?? []), step.moved]);\n return back;\n }\n if (step.backup === null)\n return done(await env.exec(`crontab -u ${quote(step.cron)} -r`, undefined, BACKGROUND_CONTEXT));\n const old = await bytesOf(env, step.backup);\n return (\n old !== null &&\n (await writeTable(env, step.cron, decoder.decode(old), BACKGROUND_CONTEXT)).code === 0\n );\n}\n\nasync function chownAll(env: ExecutionEnv, owners: Map<string, string[]>) {\n let all = true;\n for (const [both, paths] of owners) {\n const [owner, mode] = both.split(' ') as [string, string];\n for (let at = 0; at < paths.length; at += 200) {\n const list = paths\n .slice(at, at + 200)\n .map(quote)\n .join(' ');\n const ran = await env.exec(\n `chown ${quote(owner)} -- ${list} && chmod ${quote(mode)} -- ${list}`,\n undefined,\n BACKGROUND_CONTEXT\n );\n all = all && ran.ok && ran.value.exitCode === 0;\n }\n }\n return all;\n}\n\nfunction named(state: Readonly<AgentsState>, cone: string): boolean {\n return (\n state.cones[cone] !== undefined ||\n Object.values(state.frozen ?? {}).some((record) => record.cone === cone)\n );\n}\n\nconst fails = () => false;\n\nasync function removeCone(deps: Undoing, cone: string) {\n const user = (await deps.users?.remove(cone).then(() => true, fails)) ?? true;\n const home = await gone(deps.env, homeOf(cone)).catch(fails);\n return user && home;\n}\n\nexport async function undo(deps: Undoing, header: Header, steps: readonly Step[]) {\n const owners = new Map<string, string[]>();\n let all = true;\n for (const step of [...steps].reverse())\n all = (await undoStep(deps, step, owners).catch(fails)) && all;\n all = (await chownAll(deps.env, owners).catch(fails)) && all;\n for (const cone of header.cones)\n if (!named(deps.state(), cone)) all = (await removeCone(deps, cone)) && all;\n return all;\n}\n\nasync function settle(deps: Undoing, dir: string) {\n const value = await jsonIn(deps.env, `${dir}/${HEADER}`);\n if (value === UNREAD) return false;\n const header = headerOf(value);\n if (!header) return true;\n if (deps.state().imports?.[header.key]?.at !== header.at) {\n const steps = await stepsIn(deps.env, dir);\n return steps !== undefined && undo(deps, header, steps);\n }\n if (!header.source) return true;\n return gone(deps.env, header.source);\n}\n\nexport async function sweep(deps: Undoing): Promise<string[]> {\n const listed = await deps.env.listDir(IMPORTS_DIR, BACKGROUND_CONTEXT);\n if (!listed.ok) return (await exists(deps.env, IMPORTS_DIR)) === false ? [] : [IMPORTS_DIR];\n const kept: string[] = [];\n for (const item of listed.value) {\n if (item.kind !== 'directory') continue;\n const dir = `${IMPORTS_DIR}/${item.name}`;\n if (!((await settle(deps, dir)) && (await gone(deps.env, dir)))) kept.push(dir);\n }\n return kept;\n}\n\nexport class Journal {\n readonly #deps: Undoing;\n readonly #dir: string;\n readonly #steps: Step[] = [];\n #header: Header | undefined;\n #next = 0;\n\n constructor(deps: Undoing, dir: string) {\n this.#deps = deps;\n this.#dir = dir;\n }\n\n async #write(path: string, bytes: Uint8Array | string, context: Context) {\n const written = await this.#deps.env.writeFile(path, bytes, context);\n if (!written.ok) throw new ImportError(`couldn't write ${path}: ${written.error.message}`);\n }\n\n async open(header: Header, context: Context): Promise<void> {\n const made = await this.#deps.env.createDir(\n `${this.#dir}/${STEPS}`,\n { recursive: true },\n context\n );\n if (!made.ok) throw new ImportError(`couldn't write ${this.#dir}: ${made.error.message}`);\n await this.#write(`${this.#dir}/${HEADER}`, JSON.stringify(header), context);\n this.#header = header;\n }\n\n async backup(bytes: Uint8Array | string, context: Context): Promise<string> {\n const path = `${this.#dir}/${STEPS}/${this.#next++}`;\n await this.#write(path, typeof bytes === 'string' ? encoder.encode(bytes) : bytes, context);\n return path;\n }\n\n async log(step: Step, context: Context): Promise<void> {\n await this.#write(`${this.#dir}/${STEPS}/${this.#next++}.json`, JSON.stringify(step), context);\n this.#steps.push(step);\n }\n\n async rollback(): Promise<boolean> {\n return this.#header ? undo(this.#deps, this.#header, this.#steps) : true;\n }\n\n async close(): Promise<void> {\n await this.#deps.env.remove(`${this.#dir}/${HEADER}`, { force: true }, BACKGROUND_CONTEXT);\n await this.#deps.env.remove(\n `${this.#dir}/${STEPS}`,\n { recursive: true, force: true },\n BACKGROUND_CONTEXT\n );\n }\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
|
+
"names": ["old"]
|
|
7
|
+
}
|
package/dist/freezer/v6-place.js
CHANGED
|
@@ -30,12 +30,7 @@ async function staged(run, zip) {
|
|
|
30
30
|
async function prepare(run, unit) {
|
|
31
31
|
if (run.ready.has(unit)) return;
|
|
32
32
|
run.ready.add(unit);
|
|
33
|
-
const { users, layout
|
|
34
|
-
if (unit.fresh)
|
|
35
|
-
run.writer.later(async () => {
|
|
36
|
-
await users?.remove(unit.cone).catch(() => false);
|
|
37
|
-
await env.remove(unit.home, { recursive: true, force: true }, BACKGROUND_CONTEXT);
|
|
38
|
-
});
|
|
33
|
+
const { users, layout } = run.deps;
|
|
39
34
|
if (layout.users && users) await users.add(coneSpec(unit.cone));
|
|
40
35
|
}
|
|
41
36
|
async function envOf(run, unit) {
|