@ai-ecoverse/slicc-agent 6.4.4 → 6.5.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 +25 -1
- package/dist/client.js +1 -0
- package/dist/client.js.map +2 -2
- package/dist/control.js +16 -2
- package/dist/control.js.map +2 -2
- package/dist/freezer/index.js +8 -4
- package/dist/freezer/index.js.map +2 -2
- package/dist/freezer/paths.js +5 -0
- package/dist/freezer/paths.js.map +7 -0
- package/dist/freezer/v6-place.js +316 -8
- package/dist/freezer/v6-place.js.map +3 -3
- package/dist/freezer/v6-write.js +94 -1
- package/dist/freezer/v6-write.js.map +2 -2
- package/dist/freezer/v6.js +119 -30
- package/dist/freezer/v6.js.map +3 -3
- package/dist/host.js +2 -0
- package/dist/host.js.map +2 -2
- package/dist/kernel/agent-users.js +2 -1
- package/dist/kernel/agent-users.js.map +2 -2
- package/dist/licks/crontab.js +2 -1
- package/dist/licks/crontab.js.map +2 -2
- package/dist/licks/sources.js +1 -0
- package/dist/licks/sources.js.map +2 -2
- package/dist/main.js +5 -2
- package/dist/main.js.map +2 -2
- package/dist/services.js +3 -0
- package/dist/services.js.map +2 -2
- package/dist/spectrum/agent-port.js +15 -3
- package/dist/spectrum/agent-port.js.map +2 -2
- package/dist/spectrum/import-port.js +93 -0
- package/dist/spectrum/import-port.js.map +7 -0
- package/dist/types/client.d.ts +2 -0
- package/dist/types/control.d.ts +3 -1
- package/dist/types/freezer/paths.d.ts +1 -0
- package/dist/types/freezer/v6-place.d.ts +12 -0
- package/dist/types/freezer/v6-write.d.ts +16 -0
- package/dist/types/freezer/v6.d.ts +31 -4
- package/dist/types/licks/crontab.d.ts +7 -0
- package/dist/types/services.d.ts +12 -2
- package/dist/types/spectrum/agent-port.d.ts +8 -1
- package/dist/types/spectrum/import-port.d.ts +21 -0
- package/package.json +1 -1
|
@@ -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\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 if (paths.length !== 1 || flags.some((flag) => flag !== '--again' && flag !== '--preview'))\n return { code: 2, out: USAGE };\n const result = await runtime.importProfile(\n { path: resolve(asker?.cwd ?? ROOT_HOME, paths[0] as string) },\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.text };\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): 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)\n : {\n done: false,\n preview: null,\n cones: [],\n report: null,\n text: '',\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),\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 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\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 if (paths.length !== 1 || flags.some((flag) => flag !== '--again' && flag !== '--preview'))\n return { code: 2, out: USAGE };\n const result = await runtime.importProfile(\n { path: resolve(asker?.cwd ?? ROOT_HOME, paths[0] as string) },\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": "AAAA,SAA6C,uBAAuB;AACpE,SAAS,0BAA0B;AAQnC,SAAS,kBAAkB;AAC3B;AAAA,EAKE;AAAA,OAEK;AACP,SAAS,YAAY;AACrB,SAAS,eAAe;AACxB,SAAsB,QAAQ,WAAW,iBAAiB;AAE1D,SAAS,WAAW,WAAW,mBAAmB;AAClD,SAAS,YAAY,aAAa,gBAAgB;AAClD,SAAS,uBAAuB;AAChC;AAAA,EACE;AAAA,EACA;AAAA,EAKA;AAAA,OACK;AAmBA,MAAM,cAAc;AAgDpB,MAAM,QAAQ;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAUrB,MAAM,eAAe;AACd,MAAM,WAAW;AAExB,SAAS,OAAO,OAA4B;AAC1C,SAAO,WAAW,MAAM,QAAQ,CAAC,GAAG,OAAO,EAAE,KAAK;AACpD;AAEA,SAAS,KAAK,OAAoB,MAAqC;AACrE,MAAI,MAAM,SAAS,QAAS,QAAO,MAAM,QAAQ,CAAC,GAAG,SAAS;AAC9D,SAAO,MAAM,SAAS,MAAM,IAAI;AAClC;AAEO,SAAS,UAAU,OAAkE;AAC1F,SAAO,QAAQ,GAAG,MAAM,QAAQ,IAAI,MAAM,OAAO,KAAK;AACxD;AAEO,SAAS,UAAU,SAAyC;AACjE,QAAM,QAAQ,QAAQ,KAAK,CAAC,UAAU,KAAK,OAAO,MAAM,KAAK,OAAO,KAAK,CAAC;AAC1E,QAAM,OAAO,QAAS,OAAO,KAAK,EAAE,MAAM,IAAI,EAAE,CAAC,EAAa,KAAK,IAAI;AACvE,MAAI,CAAC,KAAM,QAAO;AAClB,SAAO,KAAK,SAAS,eAAe,GAAG,KAAK,MAAM,GAAG,eAAe,CAAC,CAAC,WAAM;AAC9E;AAEA,SAAS,MAAM,OAA8B;AAC3C,QAAM,UAAU,MAAM,QAAQ,CAAC,GAAG;AAClC,MAAI,CAAC,MAAM,QAAQ,OAAO,EAAG,QAAO,CAAC;AACrC,SAAQ,QACL,OAAO,CAAC,SAAS,KAAK,SAAS,UAAU,EACzC,IAAI,CAAC,SAAS,OAAO,KAAK,IAAI,MAAM,KAAK,UAAU,KAAK,aAAa,CAAC,CAAC,CAAC,EAAE;AAC/E;AAEO,SAAS,SACd,QACA,SACQ;AACR,QAAM,MAAM;AAAA,IACV,KAAK,OAAO,KAAK;AAAA,IACjB;AAAA,IACA,GAAG,OAAO,IAAI,SAAM,OAAO,KAAK,SAAM,IAAI,KAAK,OAAO,QAAQ,EAAE,YAAY,CAAC;AAAA,EAC/E;AACA,aAAW,SAAS,SAAS;AAC3B,QAAI,KAAK,OAAO,MAAM,KAAK,OAAO,KAAK,EAAG,KAAI,KAAK,IAAI,WAAW,IAAI,OAAO,KAAK,CAAC;AACnF,QAAI,CAAC,KAAK,OAAO,WAAW,EAAG;AAC/B,UAAM,OAAO,OAAO,KAAK;AACzB,UAAM,QAAQ,MAAM,KAAK;AACzB,QAAI,CAAC,QAAQ,CAAC,MAAM,OAAQ;AAC5B,QAAI,KAAK,IAAI,gBAAgB,EAAE;AAC/B,QAAI,KAAM,KAAI,KAAK,IAAI;AACvB,QAAI,MAAM,OAAQ,KAAI,KAAK,GAAI,OAAO,CAAC,EAAE,IAAI,CAAC,GAAI,GAAG,KAAK;AAAA,EAC5D;AACA,SAAO,GAAG,IAAI,KAAK,IAAI,CAAC;AAAA;AAC1B;AAIA,SAAS,QAAQ,SAAyC;AACxD,SAAO,QAAQ,OAAO,CAAC,UAAU,KAAK,OAAO,MAAM,KAAK,KAAK,OAAO,WAAW,CAAC,EAAE;AACpF;AAEA,SAAS,OAAO,SAAyC;AACvD,MAAI,KAAK;AACT,aAAW,SAAS;AAClB,eAAW,WAAW,MAAM,SAAS,CAAC,GAAG;AACvC,YAAM,QAAS,QAAoC;AACnD,UAAI,OAAO,UAAU,YAAY,QAAQ,GAAI,MAAK;AAAA,IACpD;AACF,SAAO;AACT;AAIA,eAAe,QAAQ,SAAkB,IAAY,SAAsC;AACzF,QAAM,eAAe,MAAM,QAAQ,aAAa,IAAsB,OAAO;AAC7E,MAAI,CAAC;AACH,WAAO,EAAE,OAAO,EAAE,OAAO,UAAU,CAAC,CAAC,GAAG,OAAO,IAAI,UAAU,GAAG,UAAU,EAAE,GAAG,SAAS,CAAC,EAAE;AAC7F,QAAM,OAAO,MAAM,aAAa,QAAQ,OAAO;AAC/C,QAAM,QAAQ,MAAM,aAAa,MAAM,OAAO;AAC9C,SAAO;AAAA,IACL,OAAO;AAAA,MACL,OAAO,UAAU,KAAK,OAAO;AAAA,MAC7B,OAAO,UAAU,MAAM,KAAK;AAAA,MAC5B,UAAU,QAAQ,KAAK,OAAO;AAAA,MAC9B,UAAU,OAAO,KAAK,OAAO;AAAA,IAC/B;AAAA,IACA,SAAS,KAAK;AAAA,EAChB;AACF;AAMA,MAAM,SAAS,CAAC,UACd,MAAM,SAAS,SAAS,UAAU;AAEpC,eAAe,KACb,SACA,OACA,OACA,SACA,MACuB;AACvB,QAAM,UAAU,OAAO,iBAAyB;AAC9C,UAAM,SAAS,MAAM,IAAI,YAAY;AACrC,QAAI,OAAQ,QAAO;AACnB,UAAM,SAAS,MAAM,QAAQ,SAAS,cAAc,OAAO,GAAG;AAC9D,UAAM,IAAI,cAAc,KAAK;AAC7B,WAAO;AAAA,EACT;AACA,QAAM,QAAQ,OAAO,IAAY,WAAmB;AAClD,UAAM,QAAQ,MAAM,QAAQ,OAAO,YAAY;AAC/C,QAAI,SAAS,OAAO,UAAU,KAAM,YAAY,GAAG,EAAE,GAAc;AACjE,YAAM,EAAE,QAAQ,IAAI,MAAM,QAAQ,SAAS,OAAO,cAAc,OAAO;AACvE,WAAK,IAAI,QAAQ,SAAS,MAAM,KAAK;AAAA,IACvC;AACA,WAAO,EAAE,GAAG,OAAO,GAAI,OAAO,QAAQ,EAAE,OAAO,OAAO,MAAM,IAAI,CAAC,EAAG;AAAA,EACtE;AACA,QAAM,UAAU,OAAO,WAAmB;AACxC,UAAM,EAAE,MAAM,IAAI,MAAM,QAAQ,SAAS,OAAO,cAAc,OAAO;AACrE,WAAO,EAAE,GAAG,OAAO,GAAI,OAAO,QAAQ,EAAE,OAAO,OAAO,MAAM,IAAI,CAAC,EAAG;AAAA,EACtE;AACA,QAAM,MAAoB,CAAC;AAC3B,aAAW,CAAC,IAAI,IAAI,KAAK,OAAO,QAAQ,MAAM,KAAK;AACjD,QAAI,KAAK;AAAA,MACP;AAAA,MACA,MAAM,KAAK;AAAA,MACX,GAAI,MAAM,QAAQ,IAAI;AAAA,MACtB,MAAM;AAAA,MACN,MAAM;AAAA,MACN,UAAU;AAAA,IACZ,CAAC;AACH,aAAW,CAAC,IAAI,MAAM,KAAK,OAAO,QAAQ,MAAM,UAAU,CAAC,CAAC;AAC1D,QAAI,KAAK;AAAA,MACP;AAAA,MACA,MAAM,OAAO;AAAA,MACb,OAAO,OAAO;AAAA,MACd,OAAO,OAAO;AAAA,MACd,UAAU,OAAO;AAAA,MACjB,UAAU,OAAO;AAAA,MACjB,MAAM;AAAA,MACN,MAAM;AAAA,MACN,UAAU;AAAA,MACV,GAAI,OAAO,KAAK,EAAE,IAAI,KAAc,IAAI,CAAC;AAAA,IAC3C,CAAC;AACH,aAAW,CAAC,IAAI,KAAK,KAAK,OAAO,QAAQ,MAAM,MAAM,GAAG;AACtD,QAAI,MAAM,QAAS;AACnB,UAAM,KAAK,KAAK,KAAK;AACrB,QAAI,KAAK;AAAA,MACP;AAAA,MACA,MAAM,MAAM;AAAA,MACZ,GAAI,KAAK,MAAM,QAAQ,KAAK,IAAI,MAAM,MAAM,IAAI,KAAK;AAAA,MACrD,MAAM,OAAO,KAAK;AAAA,MAClB,MAAM;AAAA,MACN,UAAU,MAAM,YAAY;AAAA,IAC9B,CAAC;AAAA,EACH;AACA,SAAO,IAAI,KAAK,CAAC,GAAG,MAAM,OAAO,EAAE,IAAI,IAAI,OAAO,EAAE,IAAI,KAAK,EAAE,WAAW,EAAE,QAAQ;AACtF;AAEO,SAAS,WACd,MACA,MACA,QACA,MACA,OAAO,MACC;AACR,QAAM,OAAO,SAAS,UAAU,cAAc;AAC9C,QAAM,QAAQ,OACV,iBAAiB,MAAM,qBACvB,iBAAiB,MAAM;AAC3B,SAAO,YAAY,IAAI,IAAI,IAAI,sCAAsC,KAAK,oBAAoB,IAAI;AACpG;AAIA,eAAe,SACb,cACA,MACA,KACA,SACA,OACmB;AACnB,QAAM,OAAO,MAAM,aAAa,QAAQ,OAAO;AAC/C,QAAM,QAAQ,MAAM,aAAa,MAAM,OAAO;AAC9C,SAAO;AAAA,IACL,SAAS,KAAK;AAAA,IACd,QAAQ;AAAA,MACN;AAAA,MACA,cAAc,aAAa;AAAA,MAC3B,OAAO,SAAS,UAAU,KAAK,OAAO;AAAA,MACtC,OAAO,UAAU,MAAM,KAAK;AAAA,MAC5B,UAAU,QAAQ,KAAK,OAAO;AAAA,MAC9B,UAAU;AAAA,IACZ;AAAA,EACF;AACF;AAEO,SAAS,aAAa,OAA8B,QAAwC;AACjG,QAAM,UAAU,OAAO,QAAQ,MAAM,UAAU,CAAC,CAAC;AACjD,MAAI,OAAO,WAAW,OAAO,GAAG;AAC9B,UAAM,OAAO,OAAO,MAAM,QAAQ,MAAM;AACxC,QAAI,MAAM,MAAM,IAAI,EAAG,QAAO;AAC9B,UAAM,QAAQ,QACX,OAAO,CAAC,CAAC,EAAEA,OAAM,MAAMA,QAAO,SAAS,IAAI,EAC3C,KAAK,CAAC,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,MAAM,EAAE,WAAW,EAAE,QAAQ,EAAE,CAAC;AACpD,WAAO,QAAQ,EAAE,IAAI,MAAM,CAAC,GAAG,MAAM,MAAM,CAAC,EAAE,MAAM,IAAI,MAAM,CAAC,EAAE,SAAS,IAAI;AAAA,EAChF;AACA,QAAM,QAAQ,MAAM,OAAO,MAAM,GAAG;AACpC,QAAM,SAAS,QAAQ,MAAM,SAAS,KAAK,IAAI;AAC/C,SAAO,SAAS,SAAS,EAAE,IAAI,OAAO,MAAM,OAAO,MAAM,IAAI,OAAO,SAAS,IAAI;AACnF;AAEA,eAAe,cACb,SACA,MACA,OACA,SACiB;AACjB,MAAI,OAAO,QAAQ,MAAM,SAAS;AAChC,WAAO,EAAE,MAAM,GAAG,KAAK,2DAA2D;AACpF,QAAM,QAAQ,KAAK,OAAO,CAAC,QAAQ,IAAI,WAAW,IAAI,CAAC;AACvD,QAAM,QAAQ,KAAK,OAAO,CAAC,QAAQ,CAAC,IAAI,WAAW,IAAI,CAAC;AACxD,MAAI,MAAM,WAAW,KAAK,MAAM,KAAK,CAAC,SAAS,SAAS,aAAa,SAAS,WAAW;AACvF,WAAO,EAAE,MAAM,GAAG,KAAK,MAAM;AAC/B,QAAM,SAAS,MAAM,QAAQ;AAAA,IAC3B,EAAE,MAAM,QAAQ,OAAO,OAAO,WAAW,MAAM,CAAC,CAAW,EAAE;AAAA,IAC7D,EAAE,OAAO,MAAM,SAAS,SAAS,GAAG,SAAS,MAAM,SAAS,WAAW,EAAE;AAAA,IACzE;AAAA,EACF;AACA,SAAO,OAAO,QACV,EAAE,MAAM,GAAG,KAAK,YAAY,OAAO,KAAK;AAAA,EAAK,IAC7C,EAAE,MAAM,GAAG,KAAK,OAAO,KAAK;AAClC;AAEA,eAAe,QACb,SACA,SACA,MACA,SACA,OACiB;AACjB,QAAM,OAAO,KAAK,CAAC,KAAK;AACxB,MAAI,SAAS,SAAU,QAAO,cAAc,SAAS,KAAK,MAAM,CAAC,GAAG,OAAO,OAAO;AAClF,QAAM,SAAS,MAAM,QAAQ,QAAQ;AACrC,MAAI,SAAS,QAAQ;AACnB,UAAM,QAAQ,OAAO;AAAA,MACnB,CAACC,UACC,GAAGA,MAAK,EAAE,IAAKA,MAAK,IAAI,GAAGA,MAAK,OAAO,YAAY,EAAE,IAAKA,MAAK,IAAI,IAAKA,MAAK,KAAK,IAAKA,MAAK,QAAQ,aAAc,IAAI,KAAKA,MAAK,QAAQ,EAAE,YAAY,CAAC;AAAA,IAC3J;AACA,WAAO,EAAE,MAAM,GAAG,KAAK,MAAM,SAAS,GAAG,MAAM,KAAK,IAAI,CAAC;AAAA,IAAO,qBAAqB;AAAA,EACvF;AACA,MAAI,SAAS,UAAU,SAAS;AAC9B,WAAO,EAAE,MAAM,SAAS,UAAU,SAAS,WAAW,IAAI,GAAG,KAAK,MAAM;AAC1E,QAAM,KAAK,KAAK,CAAC,KAAK;AACtB,QAAM,OAAO,OAAO,KAAK,CAAC,QAAQ,IAAI,OAAO,EAAE;AAC/C,MAAI,CAAC,KAAM,QAAO,EAAE,MAAM,GAAG,KAAK,qCAAqC,EAAE;AAAA,EAAK;AAC9E,MAAI,SAAS,QAAQ;AACnB,QAAI,KAAK,KAAM,QAAO,EAAE,MAAM,GAAG,KAAK,YAAY,KAAK,IAAI;AAAA,EAAkC;AAC7F,WAAO,EAAE,MAAM,GAAG,KAAK,UAAU,EAAE,OAAO,MAAM,QAAQ,KAAK,IAAI,OAAO,CAAC;AAAA,EAAK;AAAA,EAChF;AACA,QAAM,QAAQ,QAAQ,OAAO,MAAM;AACnC,QAAM,iBACJ,MAAM,SAAS,EAAE,GAAG,gBACpB,MAAM,MAAM,EAAE,GAAG,gBACjB,MAAM,OAAO,EAAE,GAAG;AACpB,QAAM,eAAe,MAAM,QAAQ,QAAQ;AAAA,IACzC;AAAA,IACA;AAAA,EACF;AACA,QAAM,UAAU,gBAAgB,MAAM,aAAa,QAAQ,OAAO,GAAG,UAAU,CAAC;AAChF,SAAO,EAAE,MAAM,GAAG,KAAK,SAAS,MAAM,OAAO,EAAE;AACjD;AAEA,eAAe,UACb,SACA,cACA,SACuB;AACvB,QAAM,OAAO,UAAU,MAAM,YAAY,SAAS,aAAa,IAAI,OAAO,CAAC;AAC3E,SAAO,QAAQ,mBAAmB,EAAE,WAAW,EAAE,MAAM,YAAY,GAAG,KAAK,GAAG,OAAO;AACvF;AAEA,eAAe,WAAW,QAAgB,SAAyC;AACjF,QAAM,eAAe,MAAM,OAAO,aAAa,OAAO,MAAM,EAAE,QAAQ,OAAO;AAC7E,MAAI,CAAC,aAAc,OAAM,IAAI,MAAM,0BAA0B;AAC7D,SAAO;AACT;AAEA,eAAe,UACb,SACA,IACA,OACA,SACiB;AACjB,QAAM,EAAE,SAAS,QAAQ,KAAK,IAAI,IAAI;AACtC,QAAM,SAAS,QAAQ,UAAU;AACjC,MAAI,MAAM,QAAS,OAAM,IAAI,MAAM,4BAA4B,EAAE,GAAG;AACpE,MAAI,KAAK,KAAK,EAAG,OAAM,IAAI,MAAM,GAAG,MAAM,IAAI,qCAAqC;AACnF,QAAM,eAAe,MAAM,QAAQ,aAAa,MAAM,cAAgC,OAAO;AAC7F,MAAI,CAAC,aAAc,OAAM,IAAI,MAAM,4BAA4B,EAAE,GAAG;AACpE,QAAM,QAAQ,MAAM,aAAa,QAAQ,OAAO,GAAG,QAAQ,GAAG,EAAE;AAChE,QAAM,QAAQ,MAAM,aAAa,MAAM,OAAO;AAC9C,QAAM,OAAO,MAAM,YAAY,UAAU,MAAM,WAAW,QAAQ,OAAO,GAAG,IAAI,OAAO;AACvF,QAAM,UAAU;AAAA,IACd,WAAW,EAAE,MAAM,YAAqB;AAAA,IACxC,OAAO;AAAA,MACL,OAAO,MAAM;AAAA,MACb,eAAe,MAAM;AAAA,MACrB,GAAI,OAAO,QAAQ,CAAC,IAAI,EAAE,KAAK,KAAK;AAAA,IACtC;AAAA,IACA,MAAM,UAAU,MAAM,SAAS;AAAA,EACjC;AACA,QAAM,OAAO,OACT,MAAM,aAAa,KAAK,KAAK,IAAI,SAAS,OAAO,IACjD,MAAM,QAAQ,mBAAmB,SAAS,OAAO;AACrD,QAAM,SAAS,OAAO,UAAU,MAAM,MAAM;AAC5C,QAAM,SAAS,MAAM,IAAI,OAAO,QAAQ,OAAO;AAC/C,QAAM,OAAO,OAAO,MAAM,OAAO;AACjC,QAAM,KAAK;AAAA,IACT;AAAA,MACE,MAAM;AAAA,MACN,OAAO;AAAA,QACL,MAAM;AAAA,QACN,MAAM,EAAE,OAAO,IAAI,MAAM,MAAM,MAAM,MAAM,OAAO,KAAK,GAAG,WAAW,QAAQ,KAAK;AAAA,QAClF,OAAO;AAAA,UACL;AAAA,YACE,MAAM;AAAA,YACN,SAAS;AAAA,cACP,OAAO,KAAK;AAAA,cACZ,MAAM;AAAA,cACN;AAAA,cACA;AAAA,cACA,OAAO,QAAQ,kBAAkB;AAAA,YACnC;AAAA,YACA,WAAW,IAAI;AAAA,UACjB;AAAA,QACF;AAAA,MACF;AAAA,IACF;AAAA,IACA;AAAA,EACF;AACA,QAAM,SAAS,MAAM,OAAO,OAAO,CAAC,KAAK,QAAQ;AAC/C,UAAM,SAAS,QAAQ,IAAI,IAAI;AAC/B,QAAI,QAAQ;AACZ,QAAI,MAAM,MAAM,IAAI;AAAA,MAClB,MAAM,MAAM;AAAA,MACZ,cAAc,KAAK;AAAA,MACnB,GAAI,MAAM,QAAQ,EAAE,OAAO,MAAM,OAAO,QAAQ,MAAM,OAAiB,IAAI,CAAC;AAAA,IAC9E;AACA,IAAC,IAAI,OAAO,EAAE,EAAkB,WAAW;AAC3C,WAAO;AAAA,EACT,GAAG,OAAO;AACV,QAAM,OAAO,WAAW,QAAQ,OAAO;AACvC,SAAO;AACT;AAEA,eAAe,YACb,SACA,IACA,OACA,SACe;AACf,QAAM,EAAE,QAAQ,IAAI,IAAI;AACxB,MAAI,KAAK,KAAK,EAAG,OAAM,IAAI,MAAM,GAAG,MAAM,IAAI,mCAAmC;AACjF,QAAM,OAAO,OAAO,CAAC,KAAK,QAAQ;AAChC,UAAM,QAAQ,IAAI,OAAO,EAAE;AAC3B,UAAM,UAAU;AAChB,UAAM,OAAO;AACb,WAAO,MAAM;AAAA,EACf,GAAG,OAAO;AACV,QAAM,IAAI;AAAA,KACP,QAAQ,UAAU,QAAQ,UAAU,MAAM,MAAM;AAAA,IACjD;AAAA,MACE,WAAW;AAAA,MACX,OAAO;AAAA,IACT;AAAA,IACA;AAAA,EACF;AACF;AAEA,SAAS,QAAQ,SAAkB,QAAgB,MAAwB;AACzE,QAAM,SAAS,gBAA8B,CAAC,CAAC;AAC/C,QAAM,QAAQ,oBAAI,IAAmB;AACrC,MAAI,OAAuC,QAAQ,QAAQ,CAAC,CAAC;AAC7D,QAAM,UAAU,MAAM;AACpB,WAAO,KACJ,MAAM,MAAM,CAAC,CAAC,EACd,KAAK,YAAY;AAChB,YAAM,SAAS,MAAM,KAAK,SAAS,OAAO,MAAM,GAAG,OAAO,oBAAoB,IAAI;AAClF,aAAO,QAAQ,oBAAoB,MAAM;AACzC,aAAO;AAAA,IACT,CAAC;AACH,WAAO;AAAA,EACT;AACA,QAAM,QAAQ,MAAM,KAAK,QAAQ,EAAE,MAAM,MAAM,MAAS;AACxD,QAAM;AACN,QAAM,OAAO,OAAO,SAAS,KAAK;AAClC,MAAI;AACJ,QAAM,QAAQ,MAAM;AAClB,iBAAa,KAAK;AAClB,YAAQ,WAAW,OAAO,QAAQ;AAAA,EACpC;AACA,QAAM,MAAM,MAAM;AAChB,iBAAa,KAAK;AAClB,SAAK;AAAA,EACP;AACA,SAAO,EAAE,QAAQ,SAAS,OAAO,IAAI;AACvC;AAEO,SAAS,OAAO,MAAc,QAAmD;AACtF,QAAM,SAAS,OAAO,IAAI,UAAU;AACpC,SAAO,YAAY,OAAO,IAAI,oGAAoG,MAAM,KAAK,IAAI,aAAa,MAAM,mCAAmC,IAAI,UAAU,MAAM;AAC7N;AAEA,eAAe,OACb,SACA,QACA,SACuB;AACvB,QAAM,EAAE,SAAS,OAAO,IAAI;AAC5B,QAAM,SAAS,QAAQ,UAAU;AACjC,QAAM,eAAe,MAAM,QAAQ,aAAa,OAAO,cAAgC,OAAO;AAC9F,MAAI,CAAC,aAAc,OAAM,IAAI,MAAM,gCAAgC,OAAO,IAAI,GAAG;AACjF,QAAM,QAAQ,MAAM,aAAa,QAAQ,OAAO,GAAG,QAAQ,GAAG,EAAE;AAChE,QAAM,OAAO,MAAM,WAAW,QAAQ,OAAO;AAC7C,QAAM,QAAQ,MAAM,KAAK,MAAM,OAAO;AACtC,QAAM,UAAU;AAAA,IACd,WAAW,EAAE,MAAM,YAAqB;AAAA,IACxC,OAAO;AAAA,MACL,OAAO,MAAM;AAAA,MACb,eAAe,MAAM;AAAA,MACrB,GAAI,OAAO,QAAQ,CAAC,IAAI,EAAE,KAAK,KAAK;AAAA,IACtC;AAAA,IACA,MAAM,UAAU,MAAM,YAAY,SAAS,KAAK,IAAI,OAAO,GAAG,SAAS;AAAA,EACzE;AACA,QAAM,OAAO,OACT,MAAM,aAAa,KAAK,KAAK,IAAI,SAAS,OAAO,IACjD,MAAM,QAAQ,mBAAmB,SAAS,OAAO;AACrD,QAAM,OAAO,SAAS,OAAO,IAAI;AACjC,QAAM,KAAK;AAAA,IACT;AAAA,MACE,MAAM;AAAA,MACN,OAAO;AAAA,QACL,MAAM;AAAA,QACN,MAAM;AAAA,UACJ,IAAI;AAAA,UACJ,MAAM,OAAO;AAAA,UACb,MAAM;AAAA,UACN,WAAW,GAAG,IAAI,aAAa,OAAO,IAAI,UAAU,EAAE;AAAA,UACtD,MAAM;AAAA,QACR;AAAA,QACA,OAAO,CAAC,EAAE,MAAM,QAAQ,SAAS,OAAO,MAAM,MAAM,GAAG,WAAW,QAAQ,IAAI,EAAE,CAAC;AAAA,MACnF;AAAA,IACF;AAAA,IACA;AAAA,EACF;AACA,SAAO;AACT;AAEA,eAAe,SACb,SACA,SACA,IACA,SACiB;AACjB,QAAM,EAAE,OAAO,IAAI;AACnB,QAAM,SAAS,OAAO,MAAM,EAAE,SAAS,EAAE;AACzC,QAAM,OAAO,MAAM,OAAO,SAAS,QAAQ,OAAO;AAClD,QAAM,QAAQ,QAAQ,OAAO,MAAM,OAAO;AAC1C,QAAM,OAAO,gBAAgB,OAAO,MAAM,MAAM,OAAO;AACvD,QAAM,OAAO,OAAO,CAAC,KAAK,QAAQ;AAChC,UAAM,OAAO,IAAI,MAAM,OAAO,IAAI;AAClC,SAAK,QAAQ,OAAO;AACpB,SAAK,SAAS,YAAY,GAAG,EAAE;AAC/B,eAAW,SAAS,OAAO,QAAQ;AACjC,YAAM,QAAQ,IAAI,OAAO,KAAK;AAC9B,UAAI,CAAC,MAAO;AACZ,aAAO,MAAM;AACb,YAAM,OAAO,OAAO;AAAA,IACtB;AACA,WAAO,IAAI,SAAS,EAAE;AAAA,EACxB,GAAG,OAAO;AACV,QAAM,OAAO,WAAW,OAAO,MAAM,OAAO;AAC5C,SAAO,OAAO;AAChB;AAEA,eAAe,WACb,SACA,SACA,IACA,SACiB;AACjB,QAAM,EAAE,OAAO,IAAI;AACnB,QAAM,QAAQ,OAAO,MAAM,EAAE,SAAS,EAAE;AACxC,MAAI,OAAO,MAAM,OAAO,MAAM,EAAE,MAAM,MAAM,IAAI,EAAG,QAAO,SAAS,SAAS,SAAS,IAAI,OAAO;AAChG,QAAM,OAAO,OAAO,KAAK,MAAM,OAAO,SAAS,OAAO,OAAO,IAAI;AACjE,QAAM,SAAS,MAAM,OAAO,OAAO,CAAC,KAAK,QAAQ;AAC/C,UAAM,SAAS,IAAI,SAAS,EAAE;AAC9B,QAAI,CAAC,OAAQ,OAAM,IAAI,MAAM,2BAA2B,EAAE,GAAG;AAC7D,UAAM,QAAQ,CAAC,IAAI,MAAM,OAAO,IAAI;AACpC,UAAM,SAAS,QAAQ,OAAO,OAAO,QAAQ,IAAI,IAAI;AACrD,QAAI,CAAC,MAAO,KAAI,QAAQ;AACxB,QAAI,MAAM,MAAM,IAAI;AAAA,MAClB,MAAM,OAAO;AAAA,MACb,cAAc,MAAM,MAAM,OAAO;AAAA,MACjC,OAAO,OAAO;AAAA,MACd,QAAQ,YAAY,GAAG,EAAE;AAAA,IAC3B;AACA,eAAW,SAAS,OAAO,QAAQ;AACjC,YAAM,QAAQ,IAAI,OAAO,KAAK;AAC9B,UAAI,CAAC,MAAO;AACZ,aAAO,MAAM;AACb,YAAM,OAAO;AAAA,IACf;AACA,WAAO,IAAI,SAAS,EAAE;AACtB,WAAO;AAAA,EACT,GAAG,OAAO;AACV,QAAM,OAAO,WAAW,QAAQ,OAAO;AACvC,SAAO;AACT;AAEA,eAAe,cAAc,SAAwB,IAAY,SAAkB;AACjF,QAAM,EAAE,QAAQ,IAAI,IAAI;AACxB,QAAM,SAAS,OAAO,MAAM,EAAE,SAAS,EAAE;AACzC,MAAI,CAAC,OAAQ,OAAM,IAAI,MAAM,2BAA2B,EAAE,GAAG;AAC7D,QAAM,UAAU,OAAO,OACpB,IAAI,CAAC,UAAU,OAAO,MAAM,EAAE,OAAO,KAAK,GAAG,MAAM,EACnD,OAAO,CAAC,WAA6B,QAAQ,MAAM,CAAC;AACvD,QAAM,OAAO,OAAO,CAAC,KAAK,QAAQ;AAChC,eAAW,SAAS,OAAO,QAAQ;AACjC,YAAM,QAAQ,IAAI,OAAO,KAAK;AAC9B,UAAI,CAAC,MAAO;AACZ,aAAO,MAAM;AACb,YAAM,OAAO;AAAA,IACf;AACA,WAAO,IAAI,SAAS,EAAE;AAAA,EACxB,GAAG,OAAO;AACV,aAAW,UAAU;AACnB,UAAM,IAAI;AAAA,OACP,QAAQ,UAAU,QAAQ,UAAU,MAAM;AAAA,MAC3C;AAAA,QACE,WAAW;AAAA,QACX,OAAO;AAAA,MACT;AAAA,MACA;AAAA,IACF;AACJ;AAEA,SAAS,QAAQ,SAAwB;AACvC,QAAM,EAAE,OAAO,IAAI;AACnB,QAAM,UAAU,oBAAI,IAAY;AAChC,QAAM,OAAO,YAAY,GAAG,EAAE;AAC9B,QAAM,QAAQ,CAAC,SAAiC,OAAe,YAC7D,gBAAgB,OAAO,EACpB;AAAA,IAAK,CAAC,eACJ,QAAQ,MAA8C,YAAY,OAAO,OAAO;AAAA,EACnF,EACC,KAAK,UAAU,EACf,MAAM,MAAM,MAAS;AAC1B,QAAM,QAAQ,CAAC,IAAY,QAAgB,UACzC,OACG,OAAO,CAAC,KAAK,QAAQ;AACpB,UAAM,SAAS,IAAI,OAAO,EAAE;AAC5B,QAAI,QAAQ,iBAAiB,OAAO,iBAAiB,OAAO,UAAU,MAAM,KAAM;AAClF,WAAO,SAAS;AAChB,QAAI,MAAO,QAAO,QAAQ;AAAA,EAC5B,GAAG,kBAAkB,EACpB,MAAM,MAAM,MAAS;AAC1B,QAAM,OAAa,CAAC,IAAI,QAAQ,SAAS,UAAU;AACjD,UAAM,SAAS,OAAO,MAAM,EAAE,OAAO,EAAE;AACvC,QAAI,QAAQ,iBAAiB,OAAO,gBAAgB,QAAQ,IAAI,EAAE,EAAG;AACrE,QAAI,SAAS,QAAQ,SAAS,IAAI,MAAM,QAAW;AACjD,WAAK,MAAM,IAAI,QAAQ,MAAS;AAChC;AAAA,IACF;AACA,YAAQ,IAAI,EAAE;AACd,SAAK,MAAM,SAAS,OAAO,kBAAkB,EAC1C,KAAK,CAAC,UAAU,MAAM,IAAI,QAAQ,KAAK,CAAC,EACxC,QAAQ,MAAM,QAAQ,OAAO,EAAE,CAAC;AAAA,EACrC;AACA,SAAO,EAAE,OAAO,KAAK;AACvB;AAEA,SAAS,UACP,SACA,KACA,SACsE;AACtE,QAAM,WAAW,QAAQ,UACrB,eAAe;AAAA,IACb,GAAG,QAAQ;AAAA,IACX,QAAQ,QAAQ;AAAA,IAChB,QAAQ,QAAQ,UAAU;AAAA,IAC1B;AAAA,EACF,CAAC,IACD;AACJ,SAAO;AAAA,IACL,WAAW,UAAU,YAAY,gBAAgC,IAAI;AAAA,IACrE,eAAe,OAAO,QAAQ,SAAS,YACrC,WACI,SAAS,IAAI,QAAQ,SAAS,OAAO,EAAE,KAAK,OAAO,WAAW;AAC5D,UAAI,OAAO,KAAM,OAAM,QAAQ;AAC/B,aAAO;AAAA,IACT,CAAC,IACD;AAAA,MACE,MAAM;AAAA,MACN,SAAS;AAAA,MACT,OAAO,CAAC;AAAA,MACR,QAAQ;AAAA,MACR,MAAM;AAAA,MACN,MAAM;AAAA,MACN,OAAO;AAAA,IACT;AAAA,IACN,cAAc,MAAM,UAAU,OAAO;AAAA,EACvC;AACF;AAEO,SAAS,cAAc,SAAwC;AACpE,QAAM,EAAE,SAAS,OAAO,IAAI;AAC5B,QAAM,MAAM,QAAQ,OAAO,KAAK;AAChC,QAAM,EAAE,OAAO,KAAK,IAAI,QAAQ,OAAO;AACvC,QAAM,EAAE,QAAQ,SAAS,OAAO,IAAI,IAAI;AAAA,IACtC;AAAA,IACA;AAAA,IACA,QAAQ,QAAQ,OAAO;AAAA,EACzB;AAEA,QAAM,iBAAiB,OAAO,SAAiB,YAAqB;AAClE,UAAM,eAAe,MAAM,OAAO,aAAa,SAAS,OAAO;AAC/D,QAAI,CAAC,aAAc,OAAM,IAAI,MAAM,oBAAoB,OAAO,GAAG;AACjE,WAAO;AAAA,EACT;AACA,QAAM,UAAU,OACd,cACA,SACA,MACA,YACG;AACH,UAAM,OAAO,QAAQ,GAAG,EAAE,GAAG,MAAM;AACnC,UAAM,QAAQ,UAAU,aAAa,IAAI,MAAM,SAAS,IAAI,EAAE,MAAM,MAAM,MAAS;AAAA,EACrF;AACA,QAAM,UAAU,CACd,IACA,OACA,SACA,YACG;AACH,QAAI,CAAC,QAAQ,MAAO;AACpB,SAAK,MAAM,SAAS,OAAO,OAAO,EAC/B,KAAK,OAAO,UAAU;AACrB,UAAI,CAAC,MAAO;AACZ,YAAM,OAAO,OAAO,CAAC,KAAK,QAAQ;AAChC,cAAM,SAAS,IAAI,SAAS,EAAE;AAC9B,YAAI,OAAQ,QAAO,QAAQ;AAAA,MAC7B,GAAG,OAAO;AAAA,IACZ,CAAC,EACA,MAAM,MAAM,MAAS;AAAA,EAC1B;AACA,QAAM,cAAc,OAAO,QAAgB,YAAqB;AAC9D,UAAM,QAAQ,OAAO,MAAM;AAC3B,UAAM,QAAQ,OAAO,KAAK,MAAM,KAAK,EAAE,KAAK,CAAC,OAAO,OAAO,MAAM;AACjE,QAAI,MAAO,QAAO,EAAE,IAAI,OAAO,cAAc,OAAU;AACvD,UAAM,UAAU,MAAM,eAAe,QAAQ,OAAO;AACpD,UAAM,eAAe,MAAM,QAAQ;AAAA,MACjC;AAAA,QACE,WAAW,EAAE,MAAM,YAAY;AAAA,QAC/B,OAAO,EAAE,QAAQ,MAAM,QAAQ,MAAM,OAAO,GAAG,MAAM;AAAA,MACvD;AAAA,MACA;AAAA,IACF;AACA,WAAO,EAAE,IAAI,QAAQ,MAAM,IAAI,IAAI,aAAa;AAAA,EAClD;AACA,QAAM,UAA0B;AAAA,IAC9B;AAAA,IACA,GAAG,UAAU,SAAS,KAAK,OAAO;AAAA,IAClC,MAAM,OAAO,SAAS,SAAS;AAC7B,YAAM,OAAO,OAAO,MAAM,EAAE,MAAM,OAAO;AACzC,UAAI,CAAC,KAAM,OAAM,IAAI,MAAM,oBAAoB,OAAO,GAAG;AACzD,YAAM,eAAe,MAAM,eAAe,SAAS,OAAO;AAC1D,YAAM,EAAE,SAAS,OAAO,IAAI,MAAM;AAAA,QAChC;AAAA,QACA,KAAK;AAAA,QACL,IAAI;AAAA,QACJ;AAAA,QACA,KAAK;AAAA,MACP;AACA,YAAM,QAAQ,cAAc,SAAS,SAAS,OAAO;AACrD,YAAM,aAAa,MAAM,SAAS,EAAE,YAAY,KAAK,CAAC,EAAE,MAAM,MAAM,MAAS;AAC7E,YAAM,OACJ,OAAO,MAAM,EAAE,WAAW,UAAU,MAAM,YAAY,SAAS,OAAO,IAAI;AAC5E,YAAM,EAAE,IAAI,OAAO,IAAI,MAAM,OAAO,OAAO,CAAC,KAAK,QAAQ;AACvD,YAAI,CAAC,IAAI,MAAM,OAAO,EAAG,OAAM,IAAI,MAAM,oBAAoB,OAAO,GAAG;AACvE,cAAM,WAAW,UAAU,IAAI,cAAc,CAAC;AAC9C,cAAM,QAAQ,OAAO,QAAQ,IAAI,MAAM,EACpC,OAAO,CAAC,CAAC,EAAE,KAAK,MAAM,MAAM,SAAS,WAAW,KAAK,KAAK,CAAC,EAC3D,IAAI,CAAC,CAAC,KAAK,MAAM,KAAK;AACzB,YAAI,cAAc,IAAI,cAAc,KAAK;AACzC,YAAI,WAAW,CAAC;AAChB,YAAI,OAAO,QAAQ,IAAI,EAAE,GAAG,QAAQ,MAAM,SAAS,QAAQ,MAAM;AACjE,eAAO,IAAI,MAAM,OAAO;AACxB,mBAAW,SAAS,MAAO,CAAC,IAAI,OAAO,KAAK,EAA0B,SAAS;AAC/E,YAAI,MAAM,cAAc;AACtB,cAAI,MAAM,KAAK,EAAE,IAAI,EAAE,MAAM,OAAO,MAAM,cAAc,KAAK,aAAa,GAAG;AAC7E,cAAI,QAAQ;AAAA,QACd;AACA,eAAO,EAAE,IAAI,UAAU,QAAQ,MAAM;AAAA,MACvC,GAAG,OAAO;AACV,iBAAW,SAAS;AAClB,eAAO,MAAM,OAAO,aAAa,OAAO,OAAO,IAAI,MAAM,OAAO,EAAE,MAAM,MAAM,MAAS;AACzF,UAAI,KAAM,OAAM,OAAO,WAAW,KAAK,IAAI,OAAO;AAClD,cAAQ,IAAI,OAAO,OAAO,SAAS,OAAO;AAC1C,aAAO;AAAA,IACT;AAAA,IACA,MAAM,QAAQ,SAAS,SAAS;AAC9B,YAAM,OAAO,OAAO,MAAM,EAAE,MAAM,OAAO;AACzC,YAAM,QAAQ,OAAO,MAAM,EAAE,OAAO,OAAO;AAC3C,UAAI,CAAC,QAAQ,SAAS,KAAK,KAAK,GAAG;AACjC,gBAAQ,cAAc,OAAO;AAC7B,eAAO,MAAM,OAAO,aAAa,SAAS,OAAO,IAAI,MAAM,QAAW,OAAO;AAC7E,cAAM,OAAO,OAAO,CAAC,KAAK,QAAQ;AAChC,gBAAMD,UAAS,IAAI,OAAO,OAAO;AACjC,iBAAOA,QAAO;AACd,iBAAOA,QAAO;AAAA,QAChB,GAAG,OAAO;AACV,eAAO;AAAA,MACT;AACA,UAAI,CAAC,KAAM,OAAM,IAAI,MAAM,oBAAoB,OAAO,GAAG;AACzD,YAAM,eAAe,MAAM,eAAe,SAAS,OAAO;AAC1D,YAAM,UAAU,MAAM,aAAa,QAAQ,OAAO,GAAG;AACrD,YAAM,QAAQ,KAAK;AACnB,UAAI,CAAC,OAAO,KAAK,CAAC,UAAU,KAAK,OAAO,MAAM,CAAC,EAAG,QAAO;AACzD,YAAM,QAAQ,MAAM,UAAU,SAAS,cAAc,OAAO;AAC5D,YAAM,OAAO,gBAAgB,SAAS,OAAO,OAAO;AACpD,YAAM,aAAa,MAAM,OAAO,EAAE,MAAM,MAAM,MAAS;AACvD,YAAM,EAAE,SAAS,OAAO,IAAI,MAAM,SAAS,cAAc,KAAK,MAAM,IAAI,GAAG,SAAS,KAAK;AACzF,YAAM,QAAQ,cAAc,SAAS,SAAS,OAAO;AACrD,YAAM,KAAK,MAAM,OAAO,OAAO,CAAC,KAAK,QAAQ;AAC3C,cAAM,WAAW,UAAU,IAAI,cAAc,CAAC;AAC9C,YAAI,cAAc,IAAI,cAAc,KAAK;AACzC,YAAI,WAAW,CAAC;AAChB,YAAI,OAAO,QAAQ,IAAI,EAAE,GAAG,QAAQ,MAAM,SAAS,QAAQ,CAAC,EAAE;AAC9D,eAAO;AAAA,MACT,GAAG,OAAO;AACV,cAAQ,IAAI,OAAO,OAAO,SAAS,OAAO;AAC1C,aAAO;AAAA,IACT;AAAA,IACA,MAAM,KAAK,IAAI,SAAS;AACtB,YAAM,QAAQ,OAAO,MAAM;AAC3B,UAAI,MAAM,MAAM,EAAE,GAAG;AACnB,cAAM,OAAO,WAAW,IAAI,OAAO;AACnC,eAAO;AAAA,MACT;AACA,YAAM,QAAQ,MAAM,OAAO,EAAE;AAC7B,UAAI,MAAO,QAAO,UAAU,EAAE,GAAG,SAAS,IAAI,GAAG,IAAI,OAAO,OAAO;AACnE,aAAO,WAAW,EAAE,GAAG,SAAS,IAAI,GAAG,SAAS,IAAI,OAAO;AAAA,IAC7D;AAAA,IACA,MAAM,QAAQ,IAAI,SAAS;AACzB,YAAM,QAAQ,OAAO,MAAM;AAC3B,YAAM,QAAQ,MAAM,OAAO,EAAE;AAC7B,UAAI,MAAO,QAAO,YAAY,SAAS,IAAI,OAAO,OAAO;AACzD,YAAM,OAAO,MAAM,MAAM,EAAE;AAC3B,UAAI,KAAM,OAAM,IAAI,MAAM,GAAG,KAAK,IAAI,kCAAkC;AACxE,aAAO,cAAc,SAAS,IAAI,OAAO;AAAA,IAC3C;AAAA,IACA;AAAA,IACA;AAAA,IACA,cAAc,CAAC,WAAW,aAAa,OAAO,MAAM,GAAG,MAAM;AAAA,IAC7D,SAAS,CAAC,MAAM,SAAS,SAAS,UAAU,QAAQ,SAAS,SAAS,MAAM,SAAS,KAAK;AAAA,IAC1F,OAAO,MAAM,IAAI;AAAA,EACnB;AACA,SAAO;AACT;",
|
|
6
6
|
"names": ["record", "item"]
|
|
7
7
|
}
|
package/dist/freezer/v6-place.js
CHANGED
|
@@ -1,8 +1,22 @@
|
|
|
1
1
|
import { BACKGROUND_CONTEXT } from "@earendil-works/chord/context";
|
|
2
2
|
import { coneSpec } from "../kernel/accounts.js";
|
|
3
3
|
import { ROOT_HOME } from "../layout.js";
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
4
|
+
import { memoryRoot } from "../memory/store.js";
|
|
5
|
+
import { GLOBAL_DIR } from "../skills/index.js";
|
|
6
|
+
import { validateName } from "../skills/skills.js";
|
|
7
|
+
import {
|
|
8
|
+
accountsSplit,
|
|
9
|
+
textOf,
|
|
10
|
+
whereOf
|
|
11
|
+
} from "./v6.js";
|
|
12
|
+
import { lickName, skillName } from "./v6-schema.js";
|
|
13
|
+
import {
|
|
14
|
+
installCrons,
|
|
15
|
+
ownTree,
|
|
16
|
+
remember,
|
|
17
|
+
same,
|
|
18
|
+
userSection
|
|
19
|
+
} from "./v6-write.js";
|
|
6
20
|
import { ImportError } from "./zip.js";
|
|
7
21
|
const V6_ROOT = `${ROOT_HOME}/v6`;
|
|
8
22
|
async function staged(run, zip) {
|
|
@@ -27,7 +41,7 @@ async function envOf(run, unit) {
|
|
|
27
41
|
if (!env) throw new ImportError(`there is no kernel user ${unit.cone} to write its files as`);
|
|
28
42
|
return env;
|
|
29
43
|
}
|
|
30
|
-
async function putIn(run, unit, root, rest,
|
|
44
|
+
async function putIn(run, unit, root, rest, source) {
|
|
31
45
|
if (unit) await prepare(run, unit);
|
|
32
46
|
const env = await envOf(run, unit);
|
|
33
47
|
let fresh = run.fresh.get(root);
|
|
@@ -37,7 +51,8 @@ async function putIn(run, unit, root, rest, zip) {
|
|
|
37
51
|
}
|
|
38
52
|
if (unit?.fresh) unit.roots.add(root);
|
|
39
53
|
const path = `${root}/${rest}`;
|
|
40
|
-
await run.writer.put(path, await staged(run, zip), fresh, env);
|
|
54
|
+
await run.writer.put(path, "zip" in source ? await staged(run, source.zip) : source, fresh, env);
|
|
55
|
+
if ("zip" in source && !run.notes.placed.has(source.zip)) run.notes.placed.set(source.zip, path);
|
|
41
56
|
}
|
|
42
57
|
const clean = (name) => name.replace(/[^A-Za-z0-9._-]+/g, "_").slice(-80) || "file";
|
|
43
58
|
function targets(run, maps, where, zip) {
|
|
@@ -46,6 +61,17 @@ function targets(run, maps, where, zip) {
|
|
|
46
61
|
const root = where.kind === "cone" ? `${unit.home}/workspace${unit.suffix}` : `${unit.home}/scoops${unit.suffix}/${where.folder}`;
|
|
47
62
|
return [[unit, root, where.rest]];
|
|
48
63
|
}
|
|
64
|
+
if (where.kind === "sprinkle") {
|
|
65
|
+
if (!maps.primary)
|
|
66
|
+
run.notes.skipped.push(`the sprinkle ${where.folder}: there is no cone to put it in`);
|
|
67
|
+
return maps.primary ? [
|
|
68
|
+
[
|
|
69
|
+
maps.primary,
|
|
70
|
+
`${maps.primary.home}/sprinkles/${lickName(where.folder, "sprinkle")}`,
|
|
71
|
+
where.rest
|
|
72
|
+
]
|
|
73
|
+
] : [];
|
|
74
|
+
}
|
|
49
75
|
if (where.kind !== "attachment") return [];
|
|
50
76
|
return run.parsed.units.flatMap(
|
|
51
77
|
(unit) => (unit.doc?.attachments ?? []).filter((item) => item.present && item.path === zip).map((item) => {
|
|
@@ -55,6 +81,167 @@ function targets(run, maps, where, zip) {
|
|
|
55
81
|
})
|
|
56
82
|
);
|
|
57
83
|
}
|
|
84
|
+
function sprinkleCalls(run, name, bytes) {
|
|
85
|
+
const found = [...new TextDecoder().decode(bytes).matchAll(/\bslicc\.([A-Za-z_$][\w$]*)/g)].map((match) => `slicc.${match[1]}`).filter((call) => call !== "slicc.lick");
|
|
86
|
+
if (!found.length) return;
|
|
87
|
+
const known = run.notes.sprinkles.get(name) ?? /* @__PURE__ */ new Set();
|
|
88
|
+
for (const call of found) known.add(call);
|
|
89
|
+
run.notes.sprinkles.set(name, known);
|
|
90
|
+
}
|
|
91
|
+
async function alike(run, dir, six, rests) {
|
|
92
|
+
for (const rest of rests) {
|
|
93
|
+
const old = await run.writer.env.readBinaryFile(`${dir}/${rest}`, run.writer.context);
|
|
94
|
+
if (!old.ok || !same(old.value, await staged(run, `skills/${six}/${rest}`))) return false;
|
|
95
|
+
}
|
|
96
|
+
return true;
|
|
97
|
+
}
|
|
98
|
+
async function placeSkills(run, skills, primary) {
|
|
99
|
+
const seen = /* @__PURE__ */ new Set();
|
|
100
|
+
for (const [six, rests] of skills) {
|
|
101
|
+
const name = skillName(six);
|
|
102
|
+
if (!name || validateName(name).length || seen.has(name)) {
|
|
103
|
+
run.notes.skipped.push(
|
|
104
|
+
`the skill ${six}: its name doesn't fit seven's rule (a-z, 0-9 and -)`
|
|
105
|
+
);
|
|
106
|
+
continue;
|
|
107
|
+
}
|
|
108
|
+
seen.add(name);
|
|
109
|
+
const global = `${GLOBAL_DIR}/${name}`;
|
|
110
|
+
const exists = await run.writer.exists(global);
|
|
111
|
+
if (exists && await alike(run, global, six, rests)) {
|
|
112
|
+
run.notes.lines.push(`the skill ${name}: already in ${GLOBAL_DIR}`);
|
|
113
|
+
continue;
|
|
114
|
+
}
|
|
115
|
+
const own = primary && exists ? `${primary.home}/.pi/agent/skills/${name}` : void 0;
|
|
116
|
+
if (exists && !own) {
|
|
117
|
+
run.notes.skipped.push(`the skill ${name}: ${GLOBAL_DIR} has another skill of that name`);
|
|
118
|
+
continue;
|
|
119
|
+
}
|
|
120
|
+
for (const rest of rests)
|
|
121
|
+
await putIn(run, own ? primary : null, own ?? global, rest, {
|
|
122
|
+
zip: `skills/${six}/${rest}`
|
|
123
|
+
});
|
|
124
|
+
if (own)
|
|
125
|
+
run.notes.shadowed.push(
|
|
126
|
+
`the skill ${name}: ${GLOBAL_DIR} has another skill of that name, so SLICC 6's copy is in ${own}, for ${primary.cone} only`
|
|
127
|
+
);
|
|
128
|
+
else run.notes.lines.push(`the skill ${name}, for every agent, in ${global}`);
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
async function placeMemory(run) {
|
|
132
|
+
const root = memoryRoot(run.deps.memoryHome);
|
|
133
|
+
const { data, units } = run.parsed;
|
|
134
|
+
const places = [
|
|
135
|
+
{ name: "memory/global.md", file: `${root}/MEMORY.md`, rest: `${V6_ROOT}/memory/global.md` },
|
|
136
|
+
...units.filter((unit) => unit.memory).map((unit) => ({
|
|
137
|
+
name: unit.memory,
|
|
138
|
+
file: `${root}/${unit.cone}/MEMORY.md`,
|
|
139
|
+
rest: `${V6_ROOT}/memory/${unit.cone}.md`
|
|
140
|
+
}))
|
|
141
|
+
];
|
|
142
|
+
for (const place2 of places) {
|
|
143
|
+
const bytes = data.get(place2.name);
|
|
144
|
+
const done = bytes ? await remember(run.writer, place2.file, textOf(bytes, place2.name), {
|
|
145
|
+
file: place2.rest,
|
|
146
|
+
date: run.date
|
|
147
|
+
}) : "none";
|
|
148
|
+
if (done === "merged")
|
|
149
|
+
run.notes.lines.push(`memory, under "Imported from SLICC 6 (${run.date})", in ${place2.file}`);
|
|
150
|
+
if (done === "aside")
|
|
151
|
+
run.notes.lines.push(`memory, in ${place2.rest}: ${place2.file} has no room left for it`);
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
function earlier(run, unit, name) {
|
|
155
|
+
const found = Object.entries(run.deps.agents.state().scoops).filter(
|
|
156
|
+
([, record]) => record.cone === unit.cone && record.name === name && !record.removed
|
|
157
|
+
);
|
|
158
|
+
return found.at(-1)?.[0];
|
|
159
|
+
}
|
|
160
|
+
function router(run, maps) {
|
|
161
|
+
return (folder) => {
|
|
162
|
+
const cone = folder ? maps.byFolder.get(folder) : void 0;
|
|
163
|
+
if (cone) return [cone, "cone"];
|
|
164
|
+
const owner = folder ? maps.owners.get(folder) : void 0;
|
|
165
|
+
const scoop = owner?.scoops.find((item) => item.six === folder);
|
|
166
|
+
const target = owner && scoop ? owner.record ? `scoop:${scoop.folder}` : earlier(run, owner, scoop.name) : void 0;
|
|
167
|
+
if (owner && target) return [owner, target];
|
|
168
|
+
const unit = owner ?? maps.primary;
|
|
169
|
+
return unit ? [unit, "cone"] : void 0;
|
|
170
|
+
};
|
|
171
|
+
}
|
|
172
|
+
const FIELD = "[0-9A-Za-z*,/-]+";
|
|
173
|
+
const SCHEDULE = new RegExp(
|
|
174
|
+
`^(@(yearly|annually|monthly|weekly|daily|midnight|hourly|reboot)|${FIELD}( ${FIELD}){4})$`
|
|
175
|
+
);
|
|
176
|
+
const flat = (text) => text.replace(/\s+/g, " ").trim();
|
|
177
|
+
async function placeLicks(run, maps) {
|
|
178
|
+
const { licks } = run.parsed;
|
|
179
|
+
const route = router(run, maps);
|
|
180
|
+
const crons = /* @__PURE__ */ new Map();
|
|
181
|
+
const add = (found, line) => {
|
|
182
|
+
const why = !SCHEDULE.test(line.schedule) ? `"${line.schedule}" is not a cron schedule` : !found && "there is no cone to send it to";
|
|
183
|
+
if (why) run.notes.skipped.push(`the cron ${line.name}: ${why}`);
|
|
184
|
+
else if (found)
|
|
185
|
+
crons.set(found[0], [...crons.get(found[0]) ?? [], { ...line, target: found[1] }]);
|
|
186
|
+
};
|
|
187
|
+
for (const [at, task] of licks.crontasks.entries())
|
|
188
|
+
add(route(task.targetFolder), {
|
|
189
|
+
name: lickName(task.name, `v6-cron-${at + 1}`),
|
|
190
|
+
schedule: flat(task.cron),
|
|
191
|
+
message: "",
|
|
192
|
+
...task.filter ? { filter: task.filter } : {}
|
|
193
|
+
});
|
|
194
|
+
for (const [at, task] of licks.tasks.entries()) {
|
|
195
|
+
if (task.scheduleType === "cron")
|
|
196
|
+
add(route(task.groupFolder), {
|
|
197
|
+
name: `v6-task-${at + 1}`,
|
|
198
|
+
schedule: flat(task.scheduleValue),
|
|
199
|
+
message: flat(task.prompt)
|
|
200
|
+
});
|
|
201
|
+
else
|
|
202
|
+
run.notes.tasks.push(
|
|
203
|
+
`${task.scheduleType} ${task.scheduleValue}: ${flat(task.prompt).slice(0, 80)}`
|
|
204
|
+
);
|
|
205
|
+
}
|
|
206
|
+
for (const [unit, list] of crons) {
|
|
207
|
+
await prepare(run, unit);
|
|
208
|
+
const user = run.deps.layout.users ? unit.cone : "root";
|
|
209
|
+
const count = await installCrons(run.writer, user, list, run.date);
|
|
210
|
+
if (count) run.notes.crons.push(`${count} in crontab -u ${user}`);
|
|
211
|
+
}
|
|
212
|
+
for (const [at, hook] of licks.webhooks.entries()) {
|
|
213
|
+
const found = route(hook.targetFolder);
|
|
214
|
+
const name = lickName(hook.name, `v6-webhook-${at + 1}`);
|
|
215
|
+
if (!found) run.notes.skipped.push(`the webhook ${name}: there is no cone to send it to`);
|
|
216
|
+
if (!found) continue;
|
|
217
|
+
const root = `${found[0].home}/.slicc/webhooks`;
|
|
218
|
+
await putIn(
|
|
219
|
+
run,
|
|
220
|
+
found[0],
|
|
221
|
+
root,
|
|
222
|
+
`${name}.json.v6`,
|
|
223
|
+
new TextEncoder().encode(`${JSON.stringify({ target: found[1] }, null, 2)}
|
|
224
|
+
`)
|
|
225
|
+
);
|
|
226
|
+
run.notes.webhooks.push(`${root}/${name}.json.v6`);
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
async function placeGit(run) {
|
|
230
|
+
const name = run.opened.manifest.gitconfig;
|
|
231
|
+
const bytes = name ? run.parsed.data.get(name) : void 0;
|
|
232
|
+
const section = bytes ? userSection(textOf(bytes, name)) : "";
|
|
233
|
+
if (!section) return;
|
|
234
|
+
const file = `${ROOT_HOME}/.gitconfig`;
|
|
235
|
+
const read = await run.writer.env.readTextFile(file, run.writer.context);
|
|
236
|
+
const before = read.ok ? read.value.trimEnd() : "";
|
|
237
|
+
if (/^\s*\[user\]/im.test(before)) {
|
|
238
|
+
run.notes.skipped.push(`SLICC 6's git [user]: ${file} already has one`);
|
|
239
|
+
return;
|
|
240
|
+
}
|
|
241
|
+
await run.writer.put(file, `${before ? `${before}
|
|
242
|
+
` : ""}${section}`, false);
|
|
243
|
+
run.notes.lines.push(`your git name and email, in ${file}`);
|
|
244
|
+
}
|
|
58
245
|
async function place(run) {
|
|
59
246
|
const { manifest } = run.opened;
|
|
60
247
|
const units = run.parsed.units;
|
|
@@ -66,21 +253,142 @@ async function place(run) {
|
|
|
66
253
|
(unit) => unit.scoops.filter((scoop) => scoop.six).map((scoop) => [scoop.six, unit])
|
|
67
254
|
)
|
|
68
255
|
);
|
|
69
|
-
const maps = {
|
|
256
|
+
const maps = {
|
|
257
|
+
byFolder,
|
|
258
|
+
owners,
|
|
259
|
+
primary: byFolder.get("cone") ?? units.find((unit) => unit.six !== null)
|
|
260
|
+
};
|
|
261
|
+
const skills = /* @__PURE__ */ new Map();
|
|
70
262
|
const later = [];
|
|
71
263
|
for (const [at, file] of manifest.files.entries()) {
|
|
72
264
|
const where = whereOf(manifest, file.path);
|
|
265
|
+
if (where.kind === "skill")
|
|
266
|
+
skills.set(where.folder, [...skills.get(where.folder) ?? [], where.rest]);
|
|
73
267
|
if (where.kind === "home-user") later.push([file.path, where.rest]);
|
|
268
|
+
if (where.kind === "sprinkle") sprinkleCalls(run, where.folder, await staged(run, file.path));
|
|
74
269
|
for (const [unit, root, rest] of targets(run, maps, where, file.path))
|
|
75
|
-
await putIn(run, unit, root, rest, file.path);
|
|
270
|
+
await putIn(run, unit, root, rest, { zip: file.path });
|
|
76
271
|
run.show("writing", at + 1, manifest.files.length);
|
|
77
272
|
}
|
|
78
|
-
|
|
273
|
+
await placeSkills(run, skills, maps.primary);
|
|
274
|
+
await placeMemory(run);
|
|
275
|
+
await placeLicks(run, maps);
|
|
276
|
+
await placeGit(run);
|
|
277
|
+
for (const [zip, rest] of later) await putIn(run, null, `${V6_ROOT}/home-user`, rest, { zip });
|
|
79
278
|
if (run.deps.layout.users)
|
|
80
279
|
for (const unit of units) await ownTree(run.writer, unit.cone, unit.home, unit.roots);
|
|
81
280
|
}
|
|
281
|
+
const WHY = {
|
|
282
|
+
env: "environment file, often holds keys",
|
|
283
|
+
pem: "PEM file, may be a private key",
|
|
284
|
+
"git-credentials": "git credentials in plain text",
|
|
285
|
+
npmrc: "npm config, may hold an auth token",
|
|
286
|
+
"slicc-oauth": "SLICC 6 OAuth state"
|
|
287
|
+
};
|
|
288
|
+
const NEVER = {
|
|
289
|
+
"secrets-env": "~/.slicc/secrets.env, which stays on the host",
|
|
290
|
+
"github-token": "the GitHub token",
|
|
291
|
+
"mcp-tokens": "MCP tokens",
|
|
292
|
+
"chrome-storage": "the extension's chrome.storage secrets"
|
|
293
|
+
};
|
|
294
|
+
const bullets = (items, none) => (items.length ? items : [none]).map((item) => `- ${item}`);
|
|
295
|
+
function nextSteps(run, mounts) {
|
|
296
|
+
const { manifest } = run.opened;
|
|
297
|
+
const { notes } = run;
|
|
298
|
+
const sprinkles = [...notes.sprinkles].map(
|
|
299
|
+
([name, calls]) => `${name} (${[...calls].join(", ")})`
|
|
300
|
+
);
|
|
301
|
+
return [
|
|
302
|
+
"Re-enter your keys and logins in Settings.",
|
|
303
|
+
...mounts.length ? [`Mount these folders again: ${mounts.join(", ")}.`] : [],
|
|
304
|
+
...manifest.mcp?.length ? [
|
|
305
|
+
`Add these MCP servers again: ${manifest.mcp.map((item) => `${item.name} (${item.url})`).join(", ")}.`
|
|
306
|
+
] : [],
|
|
307
|
+
...notes.crons.length ? [
|
|
308
|
+
`Turn crons on with sudo crontab -u <user> -e: remove the leading "# " from a job's two lines.`
|
|
309
|
+
] : [],
|
|
310
|
+
...notes.webhooks.length ? [
|
|
311
|
+
"Turn a webhook on by renaming <name>.json.v6 to <name>.json, then point its sender at seven's webhook URL."
|
|
312
|
+
] : [],
|
|
313
|
+
...sprinkles.length ? [
|
|
314
|
+
`These sprinkles call SLICC APIs other than slicc.lick and may need edits: ${sprinkles.join(", ")}.`
|
|
315
|
+
] : []
|
|
316
|
+
];
|
|
317
|
+
}
|
|
318
|
+
async function reportOf(run, made) {
|
|
319
|
+
const { manifest } = run.opened;
|
|
320
|
+
const { notes, date, parsed } = run;
|
|
321
|
+
const recorded = parsed.units.filter((unit) => unit.record);
|
|
322
|
+
const imported = [
|
|
323
|
+
...recorded.map(
|
|
324
|
+
(unit, at) => `${unit.title}: frozen cone ${made[at]}, home ${unit.home}${unit.suffix ? `, new files in ${unit.home}/workspace${unit.suffix}` : ""}${unit.scoops.length ? `, with ${unit.scoops.map((scoop) => scoop.name).join(", ")}` : ""}`
|
|
325
|
+
),
|
|
326
|
+
...notes.lines,
|
|
327
|
+
...notes.crons.map((line) => `crons, imported off: ${line}`),
|
|
328
|
+
...notes.webhooks.map((path) => `a webhook, imported off: ${path}`)
|
|
329
|
+
];
|
|
330
|
+
const mounts = manifest.skipped.filter((item) => item.reason === "mount").map((item) => item.path);
|
|
331
|
+
const skipped = [
|
|
332
|
+
...manifest.skipped.map((item) => `${item.path}: ${item.reason}`),
|
|
333
|
+
...parsed.units.filter((unit) => !unit.record).map((unit) => `${unit.title}: unchanged since the last import`),
|
|
334
|
+
...notes.skipped,
|
|
335
|
+
...notes.shadowed,
|
|
336
|
+
...notes.tasks.map((task) => `a SLICC 6 task that cron can't express: ${task}`)
|
|
337
|
+
];
|
|
338
|
+
const flagged = manifest.flagged.map(
|
|
339
|
+
(item) => `| ${notes.placed.get(item.path) ?? item.path} | ${item.size} B | ${WHY[item.rule]} |`
|
|
340
|
+
);
|
|
341
|
+
const split = accountsSplit(manifest.providers, run.deps.providers);
|
|
342
|
+
const providers = [
|
|
343
|
+
...split.again.map((id) => `${split.nameOf(id)}: re-enter in Settings`),
|
|
344
|
+
...split.missing.map((id) => `${split.nameOf(id)}: SLICC 7 has no such provider`)
|
|
345
|
+
];
|
|
346
|
+
const never = (manifest.secrets ?? []).map((name) => NEVER[name] ?? name);
|
|
347
|
+
const part = manifest.part ? `, part ${manifest.part.index} of ${manifest.part.of}` : "";
|
|
348
|
+
const text = [
|
|
349
|
+
`# SLICC 6 import, ${date}`,
|
|
350
|
+
"",
|
|
351
|
+
`From ${manifest.producer.origin} (SLICC ${manifest.producer.slicc}), exported ${manifest.createdAt}, export ${manifest.exportId}${part}.`,
|
|
352
|
+
"",
|
|
353
|
+
"## Imported",
|
|
354
|
+
"",
|
|
355
|
+
...bullets(imported, "nothing new"),
|
|
356
|
+
"",
|
|
357
|
+
"## Skipped",
|
|
358
|
+
"",
|
|
359
|
+
...bullets(skipped, "nothing"),
|
|
360
|
+
"",
|
|
361
|
+
...flagged.length ? [
|
|
362
|
+
"## Review these files",
|
|
363
|
+
"",
|
|
364
|
+
"| Path | Size | Why |",
|
|
365
|
+
"| --- | --- | --- |",
|
|
366
|
+
...flagged,
|
|
367
|
+
"",
|
|
368
|
+
"Delete or move these if you don't need them here.",
|
|
369
|
+
""
|
|
370
|
+
] : [],
|
|
371
|
+
"## Re-enter in Settings",
|
|
372
|
+
"",
|
|
373
|
+
...bullets(providers, "no providers"),
|
|
374
|
+
...never.length ? ["", `These never move: ${never.join(", ")}.`] : [],
|
|
375
|
+
"",
|
|
376
|
+
"## Next steps",
|
|
377
|
+
"",
|
|
378
|
+
...nextSteps(run, mounts).map((step) => `- ${step}`),
|
|
379
|
+
""
|
|
380
|
+
].join("\n");
|
|
381
|
+
let file = `${ROOT_HOME}/v6-import-${date}.md`;
|
|
382
|
+
for (let n = 2; await run.writer.exists(file); n++)
|
|
383
|
+
file = `${ROOT_HOME}/v6-import-${date}-${n}.md`;
|
|
384
|
+
const written = await run.writer.env.writeFile(file, text, BACKGROUND_CONTEXT);
|
|
385
|
+
if (!written.ok)
|
|
386
|
+
throw new ImportError(`couldn't write the report ${file}: ${written.error.message}`);
|
|
387
|
+
return file;
|
|
388
|
+
}
|
|
82
389
|
export {
|
|
83
390
|
V6_ROOT,
|
|
84
|
-
place
|
|
391
|
+
place,
|
|
392
|
+
reportOf
|
|
85
393
|
};
|
|
86
394
|
//# sourceMappingURL=v6-place.js.map
|