@ai-ecoverse/slicc-agent 3.14.0 → 3.16.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.
Files changed (47) hide show
  1. package/README.md +22 -6
  2. package/bin/agent +1 -1
  3. package/dist/gelatiere/index.js +307 -0
  4. package/dist/gelatiere/index.js.map +7 -0
  5. package/dist/gelatiere/store.js +122 -0
  6. package/dist/gelatiere/store.js.map +7 -0
  7. package/dist/main.js +14 -0
  8. package/dist/main.js.map +2 -2
  9. package/dist/memory/extract.js +252 -0
  10. package/dist/memory/extract.js.map +7 -0
  11. package/dist/memory/index.js +26 -2
  12. package/dist/memory/index.js.map +2 -2
  13. package/dist/memory/prompt.js.map +2 -2
  14. package/dist/memory/runtime.js +1 -1
  15. package/dist/memory/runtime.js.map +2 -2
  16. package/dist/scoops/cli.js +2 -0
  17. package/dist/scoops/cli.js.map +2 -2
  18. package/dist/scoops/index.js +6 -4
  19. package/dist/scoops/index.js.map +2 -2
  20. package/dist/scoops/requests.js +2 -1
  21. package/dist/scoops/requests.js.map +2 -2
  22. package/dist/scoops/service.js +19 -4
  23. package/dist/scoops/service.js.map +2 -2
  24. package/dist/skills/index.js +1 -0
  25. package/dist/skills/index.js.map +2 -2
  26. package/dist/sprinkles/index.js +37 -29
  27. package/dist/sprinkles/index.js.map +2 -2
  28. package/dist/sprinkles/sprinkles.js +6 -0
  29. package/dist/sprinkles/sprinkles.js.map +2 -2
  30. package/dist/types/gelatiere/index.d.ts +39 -0
  31. package/dist/types/gelatiere/store.d.ts +34 -0
  32. package/dist/types/memory/extract.d.ts +48 -0
  33. package/dist/types/memory/index.d.ts +1 -0
  34. package/dist/types/memory/prompt.d.ts +2 -0
  35. package/dist/types/memory/runtime.d.ts +3 -0
  36. package/dist/types/scoops/cli.d.ts +1 -0
  37. package/dist/types/scoops/index.d.ts +1 -0
  38. package/dist/types/scoops/requests.d.ts +1 -1
  39. package/dist/types/scoops/service.d.ts +2 -0
  40. package/dist/types/sprinkles/index.d.ts +1 -0
  41. package/dist/types/sprinkles/sprinkles.d.ts +3 -0
  42. package/package.json +3 -3
  43. package/packages/vfs-root/agents/gelatiere.md +15 -0
  44. package/packages/vfs-root/gelatiere/GELATIERE.md +19 -0
  45. package/packages/vfs-root/skills/gelatiere/SKILL.md +30 -0
  46. package/packages/vfs-root/skills/memory/SKILL.md +4 -0
  47. package/packages/vfs-root/sprinkles/suggestions.shtml +1 -1
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../src/memory/runtime.ts"],
4
- "sourcesContent": ["import {\n type Context,\n type MutableReplicatedState,\n type ReplicatedState,\n replicatedState,\n} from '@earendil-works/chord';\nimport type { ExecutionEnv, FileWatcher } from '@earendil-works/pi-durable/env';\nimport type { Agents } from '../agents.ts';\nimport type { Role } from '../roles/roles.ts';\nimport { workspace } from '../scoops/service.ts';\nimport { MEMORY_FILE, type MemoryEntry, type MemoryScope, type MemoryTag } from './format.ts';\nimport type { Host } from './prompt.ts';\nimport { MEMORY_WRITE } from './prompt.ts';\nimport {\n GLOBAL,\n MemoryFiles,\n memoryRoot,\n type Place,\n placeOf,\n ROLE_PREFIX,\n rolePlace,\n roleRoot,\n} from './store.ts';\n\nexport type Answer = { code: number; out: string };\n\nexport interface MemoryDraft {\n id?: string;\n scope: string;\n section: string;\n title: string;\n body: string;\n tag: MemoryTag | null;\n}\n\nexport interface MemoryRuntime {\n readonly memories: ReplicatedState<MemoryEntry[]>;\n readonly scopes: ReplicatedState<MemoryScope[]>;\n save(draft: MemoryDraft, context: Context): Promise<MemoryEntry>;\n remove(id: string, context: Context): Promise<boolean>;\n command(argv: readonly string[], caller: string | null, context: Context): Promise<Answer>;\n reload(context: Context): Promise<void>;\n close(context: Context): Promise<void>;\n}\n\nexport interface MemoryAttach {\n agents: Agents;\n env: ExecutionEnv;\n home: string;\n reloadMs: number;\n roles?: (context: Context) => Promise<{ roles: readonly Role[] } | undefined>;\n}\n\nexport const USAGE = `usage:\n memory show [<scope>] print a memory file (yours by default)\n memory scopes every memory scope, its entries and its file\n\nScopes: global (everyone), a cone's id, or role:<path> for a role's memory.\nAgents write memory with the ${MEMORY_WRITE} tool; the files are plain markdown you can edit.\n`;\n\ntype Listed = Place & { group?: 'cones' | 'roles'; name: string };\n\nasync function roleDirs(\n env: ExecutionEnv,\n dir: string,\n prefix: string,\n context: Context,\n depth = 0\n): Promise<string[]> {\n const listed = await env.listDir(dir, context);\n if (!listed.ok || depth > 4) return [];\n const out: string[] = [];\n for (const info of listed.value) {\n if (info.kind !== 'directory') continue;\n const path = prefix ? `${prefix}/${info.name}` : info.name;\n const found = await env.exists(`${dir}/${info.name}/${MEMORY_FILE}`, context);\n if (found.ok && found.value) out.push(path);\n out.push(...(await roleDirs(env, `${dir}/${info.name}`, path, context, depth + 1)));\n }\n return out;\n}\n\nexport async function listPlaces(options: MemoryAttach, context: Context): Promise<Listed[]> {\n const { agents, env, home } = options;\n const state = agents.state();\n const out: Listed[] = [{ ...(placeOf(home, GLOBAL) as Place), name: 'Everyone' }];\n const cones = new Set(Object.keys(state.cones));\n const stored = await env.listDir(memoryRoot(home), context);\n if (stored.ok)\n for (const info of stored.value) if (info.kind === 'directory') cones.add(info.name);\n for (const id of cones) {\n const place = placeOf(home, id);\n if (place) out.push({ ...place, group: 'cones', name: state.cones[id]?.name ?? id });\n }\n const roles = new Set(await roleDirs(env, roleRoot(home), '', context));\n const known = await options.roles?.(context).catch(() => undefined);\n for (const role of known?.roles ?? [])\n if (role.memory?.scope === 'user') roles.add(role.memory.path);\n for (const path of [...roles].sort()) {\n const place = placeOf(home, `${ROLE_PREFIX}${path}`);\n if (place) out.push({ ...place, group: 'roles', name: path.split('/').at(-1) ?? path });\n }\n return out;\n}\n\nasync function callerPlace(\n options: MemoryAttach,\n caller: string | null,\n context: Context\n): Promise<Place | { problem: string }> {\n const { agents, env, home } = options;\n const record = caller ? agents.state().scoops[caller] : undefined;\n if (record?.memory)\n return rolePlace(env, home, record.memory, record.origin ?? workspace(record.folder), context);\n const cone = caller?.startsWith('cone:') ? caller.slice('cone:'.length) : agents.activeCone();\n return placeOf(home, cone) ?? { problem: `there is no memory scope ${cone}` };\n}\n\ntype Parts = {\n options: MemoryAttach;\n files: MemoryFiles;\n memories: MutableReplicatedState<MemoryEntry[]>;\n scopes: MutableReplicatedState<MemoryScope[]>;\n reload: (context: Context) => Promise<void>;\n};\n\nfunction placeFor(home: string, scope: string): Place {\n const place = placeOf(home, scope);\n if (!place) throw new Error(`there is no memory scope ${scope}`);\n return place;\n}\n\nasync function save(parts: Parts, draft: MemoryDraft, context: Context): Promise<MemoryEntry> {\n const { files, memories, options } = parts;\n const place = placeFor(options.home, draft.scope);\n const previous = draft.id ? memories.value.find((item) => item.id === draft.id) : undefined;\n const moved = previous && previous.scope !== draft.scope;\n try {\n const written = await files.change(\n place,\n {\n kind: 'save',\n ...(previous && !moved ? { id: previous.id } : {}),\n section: draft.section,\n title: draft.title,\n body: draft.body,\n tag: draft.tag,\n },\n context\n );\n if (previous && moved)\n await files.change(\n placeFor(options.home, previous.scope),\n { kind: 'remove', id: previous.id },\n context\n );\n return written.entry as MemoryEntry;\n } finally {\n await parts.reload(context).catch(() => undefined);\n }\n}\n\nasync function command(\n parts: Parts,\n argv: readonly string[],\n caller: string | null,\n context: Context\n): Promise<Answer> {\n const { files, memories, scopes, options } = parts;\n const verb = argv[0] ?? 'help';\n if (verb === 'scopes') {\n await parts.reload(context);\n const rows = scopes.value.map((scope) => {\n const count = memories.value.filter((item) => item.scope === scope.id).length;\n const file = placeFor(options.home, scope.id).file;\n return `${scope.id}\\t${scope.label}\\t${count} entr${count === 1 ? 'y' : 'ies'}\\t${file}`;\n });\n return { code: 0, out: `${rows.join('\\n')}\\n` };\n }\n if (verb !== 'show') return { code: verb === 'help' || verb === '--help' ? 0 : 2, out: USAGE };\n const place = argv[1]\n ? (placeOf(options.home, argv[1]) ?? { problem: `there is no memory scope ${argv[1]}` })\n : await callerPlace(options, caller, context);\n if ('problem' in place) return { code: 1, out: `memory: ${place.problem}\\n` };\n const read = await files.read(place.file, context);\n return {\n code: 0,\n out: read?.text.trim()\n ? `# ${place.file}\\n\\n${read.text.trimEnd()}\\n`\n : `${place.file} is empty\\n`,\n };\n}\n\nexport async function attachMemory(\n options: MemoryAttach,\n connect: (host: Host) => void,\n context: Context\n): Promise<MemoryRuntime> {\n const { agents, env, home } = options;\n const files = new MemoryFiles(env);\n const memories = replicatedState<MemoryEntry[]>([]);\n const scopes = replicatedState<MemoryScope[]>([]);\n const reload = async (using: Context) => {\n const found = await listPlaces(options, using);\n const entries: MemoryEntry[] = [];\n for (const place of found) entries.push(...(await files.entries(place, using)));\n scopes.replace(\n using,\n found.map((place) => ({\n id: place.scope,\n label: place.name,\n ...(place.group ? { group: place.group } : {}),\n }))\n );\n memories.replace(using, entries);\n };\n const parts: Parts = { options, files, memories, scopes, reload };\n connect({ agents, env, home, files, changed: reload });\n await reload(context).catch(() => undefined);\n let timer: ReturnType<typeof setTimeout> | undefined;\n const schedule = () => {\n clearTimeout(timer);\n timer = setTimeout(() => void reload(context).catch(() => undefined), options.reloadMs);\n };\n const offCone = agents.onCone(schedule);\n const watched = await env.watch(\n [\n { path: memoryRoot(home), recursive: true },\n { path: roleRoot(home), recursive: true },\n ],\n schedule,\n context\n );\n const watcher: FileWatcher | undefined = watched.ok ? watched.value : undefined;\n return {\n memories,\n scopes,\n save: (draft, using) => save(parts, draft, using),\n async remove(id, using) {\n const entry = memories.value.find((item) => item.id === id);\n if (!entry) return false;\n const written = await files.change(\n placeFor(home, entry.scope),\n { kind: 'remove', id },\n using\n );\n await reload(using);\n return written.found;\n },\n command: (argv, caller, using) => command(parts, argv, caller, using),\n reload,\n async close(using) {\n offCone();\n clearTimeout(timer);\n await watcher?.close(using);\n },\n };\n}\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["import {\n type Context,\n type MutableReplicatedState,\n type ReplicatedState,\n replicatedState,\n} from '@earendil-works/chord';\nimport type { Harness } from '@earendil-works/pi-durable';\nimport type { ExecutionEnv, FileWatcher } from '@earendil-works/pi-durable/env';\nimport type { Agents } from '../agents.ts';\nimport type { Role } from '../roles/roles.ts';\nimport { workspace } from '../scoops/service.ts';\nimport { MEMORY_FILE, type MemoryEntry, type MemoryScope, type MemoryTag } from './format.ts';\nimport type { Host } from './prompt.ts';\nimport { MEMORY_WRITE } from './prompt.ts';\nimport {\n GLOBAL,\n MemoryFiles,\n memoryRoot,\n type Place,\n placeOf,\n ROLE_PREFIX,\n rolePlace,\n roleRoot,\n} from './store.ts';\n\nexport type Answer = { code: number; out: string };\n\nexport interface MemoryDraft {\n id?: string;\n scope: string;\n section: string;\n title: string;\n body: string;\n tag: MemoryTag | null;\n}\n\nexport interface MemoryRuntime {\n readonly memories: ReplicatedState<MemoryEntry[]>;\n readonly scopes: ReplicatedState<MemoryScope[]>;\n save(draft: MemoryDraft, context: Context): Promise<MemoryEntry>;\n remove(id: string, context: Context): Promise<boolean>;\n command(argv: readonly string[], caller: string | null, context: Context): Promise<Answer>;\n reload(context: Context): Promise<void>;\n close(context: Context): Promise<void>;\n}\n\nexport interface MemoryAttach {\n harness: Harness;\n agents: Agents;\n env: ExecutionEnv;\n home: string;\n reloadMs: number;\n idleCheckMs?: number;\n roles?: (context: Context) => Promise<{ roles: readonly Role[] } | undefined>;\n}\n\nexport const USAGE = `usage:\n memory show [<scope>] print a memory file (yours by default)\n memory scopes every memory scope, its entries and its file\n\nScopes: global (everyone), a cone's id, or role:<path> for a role's memory.\nAgents write memory with the ${MEMORY_WRITE} tool; the files are plain markdown you can edit.\n`;\n\ntype Listed = Place & { group?: 'cones' | 'roles'; name: string };\n\nasync function roleDirs(\n env: ExecutionEnv,\n dir: string,\n prefix: string,\n context: Context,\n depth = 0\n): Promise<string[]> {\n const listed = await env.listDir(dir, context);\n if (!listed.ok || depth > 4) return [];\n const out: string[] = [];\n for (const info of listed.value) {\n if (info.kind !== 'directory') continue;\n const path = prefix ? `${prefix}/${info.name}` : info.name;\n const found = await env.exists(`${dir}/${info.name}/${MEMORY_FILE}`, context);\n if (found.ok && found.value) out.push(path);\n out.push(...(await roleDirs(env, `${dir}/${info.name}`, path, context, depth + 1)));\n }\n return out;\n}\n\nexport async function listPlaces(options: MemoryAttach, context: Context): Promise<Listed[]> {\n const { agents, env, home } = options;\n const state = agents.state();\n const out: Listed[] = [{ ...(placeOf(home, GLOBAL) as Place), name: 'Everyone' }];\n const cones = new Set(Object.keys(state.cones));\n const stored = await env.listDir(memoryRoot(home), context);\n if (stored.ok)\n for (const info of stored.value) if (info.kind === 'directory') cones.add(info.name);\n for (const id of cones) {\n const place = placeOf(home, id);\n if (place) out.push({ ...place, group: 'cones', name: state.cones[id]?.name ?? id });\n }\n const roles = new Set(await roleDirs(env, roleRoot(home), '', context));\n const known = await options.roles?.(context).catch(() => undefined);\n for (const role of known?.roles ?? [])\n if (role.memory?.scope === 'user') roles.add(role.memory.path);\n for (const path of [...roles].sort()) {\n const place = placeOf(home, `${ROLE_PREFIX}${path}`);\n if (place) out.push({ ...place, group: 'roles', name: path.split('/').at(-1) ?? path });\n }\n return out;\n}\n\nasync function callerPlace(\n options: MemoryAttach,\n caller: string | null,\n context: Context\n): Promise<Place | { problem: string }> {\n const { agents, env, home } = options;\n const record = caller ? agents.state().scoops[caller] : undefined;\n if (record?.memory)\n return rolePlace(env, home, record.memory, record.origin ?? workspace(record.folder), context);\n const cone = caller?.startsWith('cone:') ? caller.slice('cone:'.length) : agents.activeCone();\n return placeOf(home, cone) ?? { problem: `there is no memory scope ${cone}` };\n}\n\ntype Parts = {\n options: MemoryAttach;\n files: MemoryFiles;\n memories: MutableReplicatedState<MemoryEntry[]>;\n scopes: MutableReplicatedState<MemoryScope[]>;\n reload: (context: Context) => Promise<void>;\n};\n\nfunction placeFor(home: string, scope: string): Place {\n const place = placeOf(home, scope);\n if (!place) throw new Error(`there is no memory scope ${scope}`);\n return place;\n}\n\nasync function save(parts: Parts, draft: MemoryDraft, context: Context): Promise<MemoryEntry> {\n const { files, memories, options } = parts;\n const place = placeFor(options.home, draft.scope);\n const previous = draft.id ? memories.value.find((item) => item.id === draft.id) : undefined;\n const moved = previous && previous.scope !== draft.scope;\n try {\n const written = await files.change(\n place,\n {\n kind: 'save',\n ...(previous && !moved ? { id: previous.id } : {}),\n section: draft.section,\n title: draft.title,\n body: draft.body,\n tag: draft.tag,\n },\n context\n );\n if (previous && moved)\n await files.change(\n placeFor(options.home, previous.scope),\n { kind: 'remove', id: previous.id },\n context\n );\n return written.entry as MemoryEntry;\n } finally {\n await parts.reload(context).catch(() => undefined);\n }\n}\n\nasync function command(\n parts: Parts,\n argv: readonly string[],\n caller: string | null,\n context: Context\n): Promise<Answer> {\n const { files, memories, scopes, options } = parts;\n const verb = argv[0] ?? 'help';\n if (verb === 'scopes') {\n await parts.reload(context);\n const rows = scopes.value.map((scope) => {\n const count = memories.value.filter((item) => item.scope === scope.id).length;\n const file = placeFor(options.home, scope.id).file;\n return `${scope.id}\\t${scope.label}\\t${count} entr${count === 1 ? 'y' : 'ies'}\\t${file}`;\n });\n return { code: 0, out: `${rows.join('\\n')}\\n` };\n }\n if (verb !== 'show') return { code: verb === 'help' || verb === '--help' ? 0 : 2, out: USAGE };\n const place = argv[1]\n ? (placeOf(options.home, argv[1]) ?? { problem: `there is no memory scope ${argv[1]}` })\n : await callerPlace(options, caller, context);\n if ('problem' in place) return { code: 1, out: `memory: ${place.problem}\\n` };\n const read = await files.read(place.file, context);\n return {\n code: 0,\n out: read?.text.trim()\n ? `# ${place.file}\\n\\n${read.text.trimEnd()}\\n`\n : `${place.file} is empty\\n`,\n };\n}\n\nexport async function attachMemory(\n options: MemoryAttach,\n connect: (host: Host) => void,\n context: Context\n): Promise<MemoryRuntime> {\n const { agents, env, home } = options;\n const files = new MemoryFiles(env);\n const memories = replicatedState<MemoryEntry[]>([]);\n const scopes = replicatedState<MemoryScope[]>([]);\n const reload = async (using: Context) => {\n const found = await listPlaces(options, using);\n const entries: MemoryEntry[] = [];\n for (const place of found) entries.push(...(await files.entries(place, using)));\n scopes.replace(\n using,\n found.map((place) => ({\n id: place.scope,\n label: place.name,\n ...(place.group ? { group: place.group } : {}),\n }))\n );\n memories.replace(using, entries);\n };\n const parts: Parts = { options, files, memories, scopes, reload };\n connect({ harness: options.harness, agents, env, home, files, changed: reload });\n await reload(context).catch(() => undefined);\n let timer: ReturnType<typeof setTimeout> | undefined;\n const schedule = () => {\n clearTimeout(timer);\n timer = setTimeout(() => void reload(context).catch(() => undefined), options.reloadMs);\n };\n const offCone = agents.onCone(schedule);\n const watched = await env.watch(\n [\n { path: memoryRoot(home), recursive: true },\n { path: roleRoot(home), recursive: true },\n ],\n schedule,\n context\n );\n const watcher: FileWatcher | undefined = watched.ok ? watched.value : undefined;\n return {\n memories,\n scopes,\n save: (draft, using) => save(parts, draft, using),\n async remove(id, using) {\n const entry = memories.value.find((item) => item.id === id);\n if (!entry) return false;\n const written = await files.change(\n placeFor(home, entry.scope),\n { kind: 'remove', id },\n using\n );\n await reload(using);\n return written.found;\n },\n command: (argv, caller, using) => command(parts, argv, caller, using),\n reload,\n async close(using) {\n offCone();\n clearTimeout(timer);\n await watcher?.close(using);\n },\n };\n}\n"],
5
+ "mappings": "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",
6
6
  "names": []
7
7
  }
@@ -335,6 +335,8 @@ async function dispatch(deps, request, who, context) {
335
335
  return deps.sprinkle ? deps.sprinkle(request.argv, who.id, context) : fail("sprinkles are not available in this agent");
336
336
  if (request.as === "memory")
337
337
  return deps.memory ? deps.memory(request.argv, who.id, context) : fail("memory is not available in this agent");
338
+ if (request.as === "gelatiere")
339
+ return deps.gelatiere ? deps.gelatiere(request.argv, who.id, context) : fail("the gelatiere is not available in this agent");
338
340
  const first = request.argv[0] ?? "";
339
341
  const verb = VERBS[first];
340
342
  if (verb) return verb(deps, request, who, context);
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../src/scoops/cli.ts"],
4
- "sourcesContent": ["import type { Context } from '@earendil-works/chord';\nimport type { Harness } from '@earendil-works/pi-durable';\nimport type { ExecutionEnv } from '@earendil-works/pi-durable/env';\nimport type { Agents } from '../agents.ts';\nimport { resolve } from '../kernel/paths.ts';\nimport { findRole, type Roles } from '../roles/roles.ts';\nimport type { Request, Runner } from './requests.ts';\nimport { type Answer, findScoop, modelOf, SCOOPS_ROOT, type Scoops } from './service.ts';\nimport { cancelSync, detachSync, runSync, type SyncState } from './sync.ts';\n\nexport const DEFAULT_WAIT_S = 30;\nexport const MAX_DEPTH = 3;\nexport const RUN_DIR = '/var/lib/slicc/agent/scoops';\n\nexport const THINKING = new Set(['off', 'minimal', 'low', 'medium', 'high', 'xhigh']);\nconst EFFORT: Record<string, string> = { low: 'low', medium: 'medium', high: 'high', max: 'xhigh' };\n\nexport const USAGE = `usage:\n agent [options] (--prompt <text> | --file <path> | -)... run a scoop, wait, print its answer\n agent --async [options] (--prompt <text> | --file <path> | -)... start a scoop, print its handle\n agent <cwd> <allowed-commands> <prompt> the same as a synchronous run, in v6's form\n agent list [--agents] | status <handle> | rename <handle> <name>\n agent send <handle> [--follow-up] (<message> | --file <path> | -)\n agent send parent <note> from a scoop: a progress note to its cone\n agent wait <handle>... [--timeout <seconds>] [--notify]\n agent stop <handle>\n\noptions:\n --name <name> --agent <role> --model <provider/model> --thinking <level> | --effort <low|medium|high|max>\n --tools <a,b> --read-only <path,path> --system-prompt <text> | --system-prompt-file <path>\n --background-after <seconds> --persist-session | --no-persist-session\n\nA synchronous run removes the scoop's folder afterwards. Its transcript is archived in\n/tmp/agent-sessions/<handle>.md, in /home/sessions/<handle>.md with --persist-session, or nowhere\nwith --no-persist-session. subagent is the same command: subagent spawn = agent --async.\n`;\n\nexport interface CliOptions {\n env: ExecutionEnv;\n harness: Harness;\n agents: Agents;\n scoops: Scoops;\n roles: () => Promise<Roles>;\n alive?: (pid: number) => Promise<boolean>;\n now?: () => number;\n sprinkle?: (argv: readonly string[], caller: string | null, context: Context) => Promise<Answer>;\n memory?: (argv: readonly string[], caller: string | null, context: Context) => Promise<Answer>;\n}\n\nexport type Deps = CliOptions & { now: () => number; sync: SyncState };\n\nexport interface Caller {\n id: string | null;\n cone: string;\n fromAgent: boolean;\n scoop: string | null;\n depth: number;\n}\n\nexport type Flags = { values: Map<string, string[]>; switches: Set<string>; rest: string[] };\n\nexport const ok = (out: string): Answer => ({ code: 0, out });\nexport const fail = (out: string, code = 1): Answer => ({ code, out: `agent: ${out}\\n` });\n\nexport function isAnswer(value: unknown): value is Answer {\n return typeof value === 'object' && value !== null && 'code' in value && 'out' in value;\n}\n\nexport function flags(argv: readonly string[], withValue: readonly string[]): Flags {\n const values = new Map<string, string[]>();\n const switches = new Set<string>();\n const rest: string[] = [];\n for (let at = 0; at < argv.length; at++) {\n const arg = argv[at] as string;\n if (withValue.includes(arg)) {\n const value = argv[at + 1];\n if (value === undefined) throw new Error(`${arg} needs a value`);\n values.set(arg, [...(values.get(arg) ?? []), value]);\n at++;\n } else if (arg.startsWith('--')) switches.add(arg);\n else rest.push(arg);\n }\n return { values, switches, rest };\n}\n\nexport function last(parsed: Flags, flag: string): string | undefined {\n return parsed.values.get(flag)?.at(-1);\n}\n\nexport function callerOf(agents: Agents, request: Request): Caller {\n const state = agents.state();\n if (request.caller.startsWith('cone:') && state.cones[request.caller.slice(5)]) {\n const cone = request.caller.slice(5);\n return { id: `cone:${cone}`, cone, fromAgent: true, scoop: null, depth: 0 };\n }\n const record = request.caller.startsWith('scoop:') ? state.scoops[request.caller] : undefined;\n if (record)\n return {\n id: request.caller,\n cone: record.cone,\n fromAgent: true,\n scoop: request.caller,\n depth: record.depth,\n };\n return { id: null, cone: agents.activeCone(), fromAgent: false, scoop: null, depth: 0 };\n}\n\nexport async function readText(\n deps: Deps,\n value: string,\n request: Request,\n context: Context\n): Promise<string> {\n const read = await deps.env.readTextFile(resolve(request.cwd, value), context);\n if (!read.ok) throw new Error(`can't read ${value}: ${read.error.message}`);\n return read.value;\n}\n\nexport async function prompts(\n deps: Deps,\n argv: readonly string[],\n request: Request,\n context: Context\n) {\n const out: string[] = [];\n for (let at = 0; at < argv.length; at++) {\n const arg = argv[at];\n if (arg === '--prompt') out.push(argv[++at] ?? '');\n else if (arg === '--file') out.push(await readText(deps, argv[++at] ?? '', request, context));\n else if (arg === '-') out.push(request.stdin);\n }\n return out.filter((prompt) => prompt.trim());\n}\n\nexport type Choice = {\n model?: { provider: string; modelId: string };\n thinking?: string;\n tools?: string[];\n};\n\nfunction toolList(listed: string | undefined): string[] | undefined {\n if (listed === undefined || listed === 'auto' || listed === 'full') return undefined;\n return listed\n .split(',')\n .map((tool) => tool.trim())\n .filter(Boolean);\n}\n\nexport function choices(parsed: Flags): Choice | Answer {\n const provider = last(parsed, '--provider');\n const modelText = last(parsed, '--model');\n const model = modelText\n ? provider\n ? { provider, modelId: modelText }\n : modelOf(modelText)\n : undefined;\n if (modelText && !model)\n return fail('--model needs provider/model, or --provider with --model', 2);\n const effort = last(parsed, '--effort');\n if (effort && !EFFORT[effort]) return fail('--effort must be low, medium, high or max', 2);\n const thinking = last(parsed, '--thinking') ?? (effort ? EFFORT[effort] : undefined);\n if (thinking && !THINKING.has(thinking))\n return fail(`--thinking must be one of ${[...THINKING].join(', ')}`, 2);\n if (last(parsed, '--tools') === 'output')\n return fail('--tools output needs --schema-b64, which is not supported in SLICC yet', 2);\n const tools = toolList(last(parsed, '--tools'));\n return {\n ...(model ? { model } : {}),\n ...(thinking ? { thinking } : {}),\n ...(tools ? { tools } : {}),\n };\n}\n\nexport async function role(deps: Deps, parsed: Flags) {\n const roles = await deps.roles();\n const name = last(parsed, '--agent');\n const found = name ? findRole(roles.roles, name) : undefined;\n if (name && !found)\n return {\n roles,\n error: fail(`there is no agent role ${name}; \\`agent list --agents\\` shows them`),\n };\n return { roles, role: found };\n}\n\nfunction handle(deps: Deps, who: Caller, name: string | undefined) {\n return name ? findScoop(deps.agents.state(), name, who.fromAgent ? who.cone : null) : undefined;\n}\n\nconst ASYNC_VALUES = [\n '--name',\n '--agent',\n '--provider',\n '--model',\n '--thinking',\n '--effort',\n '--tools',\n '--prompt',\n '--file',\n];\nconst ASYNC_SWITCHES = new Set(['--async', '--no-extensions', '--no-skills', '--no-context-files']);\nconst UNSUPPORTED = new Set([\n '--no-prompt-templates',\n '--session',\n '--resume',\n '--image',\n '--no-escalate',\n '--minimal',\n '--usage',\n '--schema-b64',\n '--cwd',\n]);\n\nexport function unsupported(argv: readonly string[]): Answer | undefined {\n const found = argv.find((arg) => UNSUPPORTED.has(arg) || arg.startsWith('--image='));\n return found ? fail(`${found} is not supported in SLICC yet`, 2) : undefined;\n}\n\nasync function spawnAsync(\n deps: Deps,\n request: Request,\n who: Caller,\n argv: readonly string[],\n context: Context\n) {\n if (who.scoop) return fail('a scoop cannot start async scoops; run agent without --async');\n const refused = unsupported(argv);\n if (refused) return refused;\n const parsed = flags(argv, ASYNC_VALUES);\n const unknown = [...parsed.switches].find((flag) => !ASYNC_SWITCHES.has(flag));\n if (unknown) return fail(`unknown option ${unknown}`, 2);\n const given = await prompts(deps, argv, request, context);\n if (!given.length) return fail('--async needs at least one --prompt, --file or -', 2);\n const chosen = choices(parsed);\n if (isAnswer(chosen)) return chosen;\n const found = await role(deps, parsed);\n if (found.error) return found.error;\n return deps.scoops.spawn(\n {\n cone: who.cone,\n kind: 'async',\n name: last(parsed, '--name') ?? found.role?.name ?? 'scoop',\n ...(found.role ? { role: found.role } : {}),\n ...(chosen.model ? { model: chosen.model } : {}),\n ...(chosen.thinking ? { thinking: chosen.thinking as never } : {}),\n ...(chosen.tools ? { tools: chosen.tools } : {}),\n prompts: given,\n origin: request.cwd,\n fromAgent: who.fromAgent,\n request: request.id,\n limits: found.roles.limits,\n },\n context\n );\n}\n\nasync function listAgents(deps: Deps): Promise<Answer> {\n const roles = await deps.roles();\n const lines = roles.roles.map(\n (entry) =>\n `${entry.name}\\t${entry.source}\\t${entry.description}${entry.aliases.length ? ` (also ${entry.aliases.join(', ')})` : ''}`\n );\n return ok(\n `${[\n ...lines,\n '',\n 'Agent files are read from the built-in roles, installed packages (pi-subagents.agents) and ~/.pi/agent/agents.',\n \"A project's .pi/agents folder is read only once the folder is trusted, which SLICC doesn't support yet.\",\n ...roles.warnings.map((warning) => `warning: ${warning}`),\n ].join('\\n')}\\n`\n );\n}\n\nasync function list(deps: Deps, request: Request, who: Caller, context: Context): Promise<Answer> {\n if (request.argv.includes('--agents')) return listAgents(deps);\n const rows = await deps.scoops.list(who.cone, context);\n if (!rows.length) return ok('no scoops\\n');\n return ok(\n `${rows.map((row) => `${row.folder}\\t${row.name}\\t${row.role ?? '-'}\\t${row.busy ? 'working' : 'idle'}`).join('\\n')}\\n`\n );\n}\n\nasync function status(\n deps: Deps,\n request: Request,\n who: Caller,\n context: Context\n): Promise<Answer> {\n const found = handle(deps, who, request.argv[1]);\n if (!found) return fail(`there is no scoop ${request.argv[1] ?? ''}`.trim());\n const [, record] = found;\n const busy = await deps.scoops.busy(record.conversation, context);\n return ok(\n `${[\n `handle: ${record.folder}`,\n `name: ${record.name}`,\n `role: ${record.role ?? '-'}`,\n `kind: ${record.kind}`,\n `state: ${busy ? 'working' : 'idle'}`,\n `folder: ${SCOOPS_ROOT}/${record.folder}`,\n `reports: ${SCOOPS_ROOT}/${record.folder}/reports`,\n ].join('\\n')}\\n`\n );\n}\n\nasync function message(\n deps: Deps,\n parsed: Flags,\n request: Request,\n context: Context\n): Promise<string> {\n const file = last(parsed, '--file');\n if (file) return readText(deps, file, request, context);\n return parsed.rest.includes('-') ? request.stdin : parsed.rest.join(' ');\n}\n\nasync function send(deps: Deps, request: Request, who: Caller, context: Context): Promise<Answer> {\n const parsed = flags(request.argv.slice(2), ['--file']);\n const unknown = [...parsed.switches].find((flag) => flag !== '--follow-up');\n if (unknown) return fail(`unknown option ${unknown}`, 2);\n const text = await message(deps, parsed, request, context);\n if (!text.trim()) return fail('send needs a message, --file or -', 2);\n if (request.argv[1] === 'parent') {\n if (!who.scoop) return fail('only a scoop has a parent to send to');\n return deps.scoops.note(who.scoop, text, context);\n }\n if (who.scoop) return fail('a scoop can only send to its parent');\n const found = handle(deps, who, request.argv[1]);\n if (!found) return fail(`there is no scoop ${request.argv[1] ?? ''}`.trim());\n const followUp = parsed.switches.has('--follow-up');\n return deps.scoops.feed(\n found[0],\n text,\n { fromAgent: who.fromAgent, request: request.id, followUp, target: who.id },\n context\n );\n}\n\nasync function latest(deps: Deps, folder: string, context: Context): Promise<string> {\n const dir = `${SCOOPS_ROOT}/${folder}/reports`;\n const listed = await deps.env.listDir(dir, context);\n if (!listed.ok || !listed.value.length) return '(no answer yet)';\n const newest = [...listed.value].sort(\n (a, b) => Number.parseInt(b.name, 10) - Number.parseInt(a.name, 10)\n )[0];\n const read = await deps.env.readTextFile(`${dir}/${newest?.name}`, context);\n return read.ok ? read.value.trimEnd() : '(no answer yet)';\n}\n\nfunction waitTargets(deps: Deps, who: Caller, rest: readonly string[]): string[] | Answer {\n if (!rest.length) return fail('wait needs at least one handle', 2);\n const missing = rest.filter((name) => !handle(deps, who, name));\n if (missing.length) return fail(`there is no scoop ${missing.join(', ')}`);\n return rest.map((name) => (handle(deps, who, name) as [string, unknown])[0]);\n}\n\nasync function block(\n deps: Deps,\n ids: string[],\n seconds: number,\n context: Context\n): Promise<Answer> {\n const deadline = deps.now() + seconds * 1000;\n let open = await deps.scoops.working(ids, context);\n while (open.length && deps.now() < deadline) {\n await new Promise((done) => setTimeout(done, 200));\n open = await deps.scoops.working(ids, context);\n }\n const state = deps.agents.state();\n const sections: string[] = [];\n for (const id of ids) {\n const record = state.scoops[id];\n if (record)\n sections.push(\n `## ${record.folder}${open.includes(id) ? ' (still working)' : ''}\\n${await latest(deps, record.folder, context)}`\n );\n }\n const body = `${sections.join('\\n\\n')}\\n`;\n if (!open.length) return ok(body);\n const still = open.map((id) => state.scoops[id]?.folder).join(', ');\n return { code: 1, out: `${body}agent: timed out after ${seconds}s; still working: ${still}\\n` };\n}\n\nasync function wait(deps: Deps, request: Request, who: Caller, context: Context): Promise<Answer> {\n const parsed = flags(request.argv.slice(1), ['--timeout']);\n const unknown = [...parsed.switches].find((flag) => flag !== '--notify');\n if (unknown) return fail(`unknown option ${unknown}`, 2);\n const seconds = Number(last(parsed, '--timeout') ?? DEFAULT_WAIT_S);\n if (!Number.isInteger(seconds) || seconds <= 0)\n return fail('--timeout must be a positive whole number of seconds', 2);\n const ids = waitTargets(deps, who, parsed.rest);\n if (isAnswer(ids)) return ids;\n if (!parsed.switches.has('--notify')) return block(deps, ids, seconds, context);\n if (!who.fromAgent || who.scoop)\n return fail('wait --notify is for a cone; a terminal waits with agent wait');\n await deps.scoops.notifyWhenDone(who.cone, ids, deps.now() + seconds * 1000, context);\n return ok(`you'll get one scoop-wait lick when ${ids.length > 1 ? 'they are' : 'it is'} done\\n`);\n}\n\nasync function stop(deps: Deps, request: Request, who: Caller, context: Context): Promise<Answer> {\n if (who.scoop) return fail('a scoop cannot stop scoops');\n const found = handle(deps, who, request.argv[1]);\n if (!found) return fail(`there is no scoop ${request.argv[1] ?? ''}`.trim());\n return deps.scoops.stop(found[0], who.fromAgent, context);\n}\n\nasync function rename(\n deps: Deps,\n request: Request,\n who: Caller,\n context: Context\n): Promise<Answer> {\n if (who.scoop) return fail('a scoop cannot rename scoops');\n const found = handle(deps, who, request.argv[1]);\n if (!found) return fail(`there is no scoop ${request.argv[1] ?? ''}`.trim());\n return deps.scoops.rename(found[0], request.argv.slice(2).join(' '), context);\n}\n\ntype Verb = (deps: Deps, request: Request, who: Caller, context: Context) => Promise<Answer>;\n\nconst help: Verb = async () => ok(USAGE);\n\nconst VERBS: Record<string, Verb> = {\n list,\n status,\n send,\n wait,\n stop,\n rename,\n help,\n '--help': help,\n '-h': help,\n __cancel: (deps, request, _who, context) => cancelSync(deps, request.argv[1] ?? '', context),\n __detach: (deps, request, _who, context) => detachSync(deps, request.argv[1] ?? '', context),\n};\n\nasync function dispatch(\n deps: Deps,\n request: Request,\n who: Caller,\n context: Context\n): Promise<Answer> {\n if (request.as === 'sprinkle')\n return deps.sprinkle\n ? deps.sprinkle(request.argv, who.id, context)\n : fail('sprinkles are not available in this agent');\n if (request.as === 'memory')\n return deps.memory\n ? deps.memory(request.argv, who.id, context)\n : fail('memory is not available in this agent');\n const first = request.argv[0] ?? '';\n const verb = VERBS[first];\n if (verb) return verb(deps, request, who, context);\n if (request.as === 'subagent') {\n if (first === 'spawn') return spawnAsync(deps, request, who, request.argv.slice(1), context);\n return { code: 2, out: USAGE };\n }\n if (!request.argv.length) return { code: 2, out: USAGE };\n if (request.argv.includes('--async'))\n return spawnAsync(deps, request, who, request.argv, context);\n return runSync(deps, request, who, context);\n}\n\nconst BLOCKING = new Set([\n 'wait',\n 'list',\n 'status',\n 'help',\n '--help',\n '-h',\n '__cancel',\n '__detach',\n]);\n\nexport function createCli(options: CliOptions): Runner {\n const deps: Deps = { ...options, now: options.now ?? Date.now, sync: { pending: new Map() } };\n return {\n blocking(request) {\n const first = request.argv[0] ?? '';\n if (BLOCKING.has(first)) return true;\n return request.as === 'agent' && !VERBS[first] && !request.argv.includes('--async');\n },\n async run(request, context) {\n try {\n return await dispatch(deps, request, callerOf(options.agents, request), context);\n } catch (error) {\n return fail((error as Error).message);\n }\n },\n };\n}\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["import type { Context } from '@earendil-works/chord';\nimport type { Harness } from '@earendil-works/pi-durable';\nimport type { ExecutionEnv } from '@earendil-works/pi-durable/env';\nimport type { Agents } from '../agents.ts';\nimport { resolve } from '../kernel/paths.ts';\nimport { findRole, type Roles } from '../roles/roles.ts';\nimport type { Request, Runner } from './requests.ts';\nimport { type Answer, findScoop, modelOf, SCOOPS_ROOT, type Scoops } from './service.ts';\nimport { cancelSync, detachSync, runSync, type SyncState } from './sync.ts';\n\nexport const DEFAULT_WAIT_S = 30;\nexport const MAX_DEPTH = 3;\nexport const RUN_DIR = '/var/lib/slicc/agent/scoops';\n\nexport const THINKING = new Set(['off', 'minimal', 'low', 'medium', 'high', 'xhigh']);\nconst EFFORT: Record<string, string> = { low: 'low', medium: 'medium', high: 'high', max: 'xhigh' };\n\nexport const USAGE = `usage:\n agent [options] (--prompt <text> | --file <path> | -)... run a scoop, wait, print its answer\n agent --async [options] (--prompt <text> | --file <path> | -)... start a scoop, print its handle\n agent <cwd> <allowed-commands> <prompt> the same as a synchronous run, in v6's form\n agent list [--agents] | status <handle> | rename <handle> <name>\n agent send <handle> [--follow-up] (<message> | --file <path> | -)\n agent send parent <note> from a scoop: a progress note to its cone\n agent wait <handle>... [--timeout <seconds>] [--notify]\n agent stop <handle>\n\noptions:\n --name <name> --agent <role> --model <provider/model> --thinking <level> | --effort <low|medium|high|max>\n --tools <a,b> --read-only <path,path> --system-prompt <text> | --system-prompt-file <path>\n --background-after <seconds> --persist-session | --no-persist-session\n\nA synchronous run removes the scoop's folder afterwards. Its transcript is archived in\n/tmp/agent-sessions/<handle>.md, in /home/sessions/<handle>.md with --persist-session, or nowhere\nwith --no-persist-session. subagent is the same command: subagent spawn = agent --async.\n`;\n\nexport interface CliOptions {\n env: ExecutionEnv;\n harness: Harness;\n agents: Agents;\n scoops: Scoops;\n roles: () => Promise<Roles>;\n alive?: (pid: number) => Promise<boolean>;\n now?: () => number;\n sprinkle?: (argv: readonly string[], caller: string | null, context: Context) => Promise<Answer>;\n memory?: (argv: readonly string[], caller: string | null, context: Context) => Promise<Answer>;\n gelatiere?: (argv: readonly string[], caller: string | null, context: Context) => Promise<Answer>;\n}\n\nexport type Deps = CliOptions & { now: () => number; sync: SyncState };\n\nexport interface Caller {\n id: string | null;\n cone: string;\n fromAgent: boolean;\n scoop: string | null;\n depth: number;\n}\n\nexport type Flags = { values: Map<string, string[]>; switches: Set<string>; rest: string[] };\n\nexport const ok = (out: string): Answer => ({ code: 0, out });\nexport const fail = (out: string, code = 1): Answer => ({ code, out: `agent: ${out}\\n` });\n\nexport function isAnswer(value: unknown): value is Answer {\n return typeof value === 'object' && value !== null && 'code' in value && 'out' in value;\n}\n\nexport function flags(argv: readonly string[], withValue: readonly string[]): Flags {\n const values = new Map<string, string[]>();\n const switches = new Set<string>();\n const rest: string[] = [];\n for (let at = 0; at < argv.length; at++) {\n const arg = argv[at] as string;\n if (withValue.includes(arg)) {\n const value = argv[at + 1];\n if (value === undefined) throw new Error(`${arg} needs a value`);\n values.set(arg, [...(values.get(arg) ?? []), value]);\n at++;\n } else if (arg.startsWith('--')) switches.add(arg);\n else rest.push(arg);\n }\n return { values, switches, rest };\n}\n\nexport function last(parsed: Flags, flag: string): string | undefined {\n return parsed.values.get(flag)?.at(-1);\n}\n\nexport function callerOf(agents: Agents, request: Request): Caller {\n const state = agents.state();\n if (request.caller.startsWith('cone:') && state.cones[request.caller.slice(5)]) {\n const cone = request.caller.slice(5);\n return { id: `cone:${cone}`, cone, fromAgent: true, scoop: null, depth: 0 };\n }\n const record = request.caller.startsWith('scoop:') ? state.scoops[request.caller] : undefined;\n if (record)\n return {\n id: request.caller,\n cone: record.cone,\n fromAgent: true,\n scoop: request.caller,\n depth: record.depth,\n };\n return { id: null, cone: agents.activeCone(), fromAgent: false, scoop: null, depth: 0 };\n}\n\nexport async function readText(\n deps: Deps,\n value: string,\n request: Request,\n context: Context\n): Promise<string> {\n const read = await deps.env.readTextFile(resolve(request.cwd, value), context);\n if (!read.ok) throw new Error(`can't read ${value}: ${read.error.message}`);\n return read.value;\n}\n\nexport async function prompts(\n deps: Deps,\n argv: readonly string[],\n request: Request,\n context: Context\n) {\n const out: string[] = [];\n for (let at = 0; at < argv.length; at++) {\n const arg = argv[at];\n if (arg === '--prompt') out.push(argv[++at] ?? '');\n else if (arg === '--file') out.push(await readText(deps, argv[++at] ?? '', request, context));\n else if (arg === '-') out.push(request.stdin);\n }\n return out.filter((prompt) => prompt.trim());\n}\n\nexport type Choice = {\n model?: { provider: string; modelId: string };\n thinking?: string;\n tools?: string[];\n};\n\nfunction toolList(listed: string | undefined): string[] | undefined {\n if (listed === undefined || listed === 'auto' || listed === 'full') return undefined;\n return listed\n .split(',')\n .map((tool) => tool.trim())\n .filter(Boolean);\n}\n\nexport function choices(parsed: Flags): Choice | Answer {\n const provider = last(parsed, '--provider');\n const modelText = last(parsed, '--model');\n const model = modelText\n ? provider\n ? { provider, modelId: modelText }\n : modelOf(modelText)\n : undefined;\n if (modelText && !model)\n return fail('--model needs provider/model, or --provider with --model', 2);\n const effort = last(parsed, '--effort');\n if (effort && !EFFORT[effort]) return fail('--effort must be low, medium, high or max', 2);\n const thinking = last(parsed, '--thinking') ?? (effort ? EFFORT[effort] : undefined);\n if (thinking && !THINKING.has(thinking))\n return fail(`--thinking must be one of ${[...THINKING].join(', ')}`, 2);\n if (last(parsed, '--tools') === 'output')\n return fail('--tools output needs --schema-b64, which is not supported in SLICC yet', 2);\n const tools = toolList(last(parsed, '--tools'));\n return {\n ...(model ? { model } : {}),\n ...(thinking ? { thinking } : {}),\n ...(tools ? { tools } : {}),\n };\n}\n\nexport async function role(deps: Deps, parsed: Flags) {\n const roles = await deps.roles();\n const name = last(parsed, '--agent');\n const found = name ? findRole(roles.roles, name) : undefined;\n if (name && !found)\n return {\n roles,\n error: fail(`there is no agent role ${name}; \\`agent list --agents\\` shows them`),\n };\n return { roles, role: found };\n}\n\nfunction handle(deps: Deps, who: Caller, name: string | undefined) {\n return name ? findScoop(deps.agents.state(), name, who.fromAgent ? who.cone : null) : undefined;\n}\n\nconst ASYNC_VALUES = [\n '--name',\n '--agent',\n '--provider',\n '--model',\n '--thinking',\n '--effort',\n '--tools',\n '--prompt',\n '--file',\n];\nconst ASYNC_SWITCHES = new Set(['--async', '--no-extensions', '--no-skills', '--no-context-files']);\nconst UNSUPPORTED = new Set([\n '--no-prompt-templates',\n '--session',\n '--resume',\n '--image',\n '--no-escalate',\n '--minimal',\n '--usage',\n '--schema-b64',\n '--cwd',\n]);\n\nexport function unsupported(argv: readonly string[]): Answer | undefined {\n const found = argv.find((arg) => UNSUPPORTED.has(arg) || arg.startsWith('--image='));\n return found ? fail(`${found} is not supported in SLICC yet`, 2) : undefined;\n}\n\nasync function spawnAsync(\n deps: Deps,\n request: Request,\n who: Caller,\n argv: readonly string[],\n context: Context\n) {\n if (who.scoop) return fail('a scoop cannot start async scoops; run agent without --async');\n const refused = unsupported(argv);\n if (refused) return refused;\n const parsed = flags(argv, ASYNC_VALUES);\n const unknown = [...parsed.switches].find((flag) => !ASYNC_SWITCHES.has(flag));\n if (unknown) return fail(`unknown option ${unknown}`, 2);\n const given = await prompts(deps, argv, request, context);\n if (!given.length) return fail('--async needs at least one --prompt, --file or -', 2);\n const chosen = choices(parsed);\n if (isAnswer(chosen)) return chosen;\n const found = await role(deps, parsed);\n if (found.error) return found.error;\n return deps.scoops.spawn(\n {\n cone: who.cone,\n kind: 'async',\n name: last(parsed, '--name') ?? found.role?.name ?? 'scoop',\n ...(found.role ? { role: found.role } : {}),\n ...(chosen.model ? { model: chosen.model } : {}),\n ...(chosen.thinking ? { thinking: chosen.thinking as never } : {}),\n ...(chosen.tools ? { tools: chosen.tools } : {}),\n prompts: given,\n origin: request.cwd,\n fromAgent: who.fromAgent,\n request: request.id,\n limits: found.roles.limits,\n },\n context\n );\n}\n\nasync function listAgents(deps: Deps): Promise<Answer> {\n const roles = await deps.roles();\n const lines = roles.roles.map(\n (entry) =>\n `${entry.name}\\t${entry.source}\\t${entry.description}${entry.aliases.length ? ` (also ${entry.aliases.join(', ')})` : ''}`\n );\n return ok(\n `${[\n ...lines,\n '',\n 'Agent files are read from the built-in roles, installed packages (pi-subagents.agents) and ~/.pi/agent/agents.',\n \"A project's .pi/agents folder is read only once the folder is trusted, which SLICC doesn't support yet.\",\n ...roles.warnings.map((warning) => `warning: ${warning}`),\n ].join('\\n')}\\n`\n );\n}\n\nasync function list(deps: Deps, request: Request, who: Caller, context: Context): Promise<Answer> {\n if (request.argv.includes('--agents')) return listAgents(deps);\n const rows = await deps.scoops.list(who.cone, context);\n if (!rows.length) return ok('no scoops\\n');\n return ok(\n `${rows.map((row) => `${row.folder}\\t${row.name}\\t${row.role ?? '-'}\\t${row.busy ? 'working' : 'idle'}`).join('\\n')}\\n`\n );\n}\n\nasync function status(\n deps: Deps,\n request: Request,\n who: Caller,\n context: Context\n): Promise<Answer> {\n const found = handle(deps, who, request.argv[1]);\n if (!found) return fail(`there is no scoop ${request.argv[1] ?? ''}`.trim());\n const [, record] = found;\n const busy = await deps.scoops.busy(record.conversation, context);\n return ok(\n `${[\n `handle: ${record.folder}`,\n `name: ${record.name}`,\n `role: ${record.role ?? '-'}`,\n `kind: ${record.kind}`,\n `state: ${busy ? 'working' : 'idle'}`,\n `folder: ${SCOOPS_ROOT}/${record.folder}`,\n `reports: ${SCOOPS_ROOT}/${record.folder}/reports`,\n ].join('\\n')}\\n`\n );\n}\n\nasync function message(\n deps: Deps,\n parsed: Flags,\n request: Request,\n context: Context\n): Promise<string> {\n const file = last(parsed, '--file');\n if (file) return readText(deps, file, request, context);\n return parsed.rest.includes('-') ? request.stdin : parsed.rest.join(' ');\n}\n\nasync function send(deps: Deps, request: Request, who: Caller, context: Context): Promise<Answer> {\n const parsed = flags(request.argv.slice(2), ['--file']);\n const unknown = [...parsed.switches].find((flag) => flag !== '--follow-up');\n if (unknown) return fail(`unknown option ${unknown}`, 2);\n const text = await message(deps, parsed, request, context);\n if (!text.trim()) return fail('send needs a message, --file or -', 2);\n if (request.argv[1] === 'parent') {\n if (!who.scoop) return fail('only a scoop has a parent to send to');\n return deps.scoops.note(who.scoop, text, context);\n }\n if (who.scoop) return fail('a scoop can only send to its parent');\n const found = handle(deps, who, request.argv[1]);\n if (!found) return fail(`there is no scoop ${request.argv[1] ?? ''}`.trim());\n const followUp = parsed.switches.has('--follow-up');\n return deps.scoops.feed(\n found[0],\n text,\n { fromAgent: who.fromAgent, request: request.id, followUp, target: who.id },\n context\n );\n}\n\nasync function latest(deps: Deps, folder: string, context: Context): Promise<string> {\n const dir = `${SCOOPS_ROOT}/${folder}/reports`;\n const listed = await deps.env.listDir(dir, context);\n if (!listed.ok || !listed.value.length) return '(no answer yet)';\n const newest = [...listed.value].sort(\n (a, b) => Number.parseInt(b.name, 10) - Number.parseInt(a.name, 10)\n )[0];\n const read = await deps.env.readTextFile(`${dir}/${newest?.name}`, context);\n return read.ok ? read.value.trimEnd() : '(no answer yet)';\n}\n\nfunction waitTargets(deps: Deps, who: Caller, rest: readonly string[]): string[] | Answer {\n if (!rest.length) return fail('wait needs at least one handle', 2);\n const missing = rest.filter((name) => !handle(deps, who, name));\n if (missing.length) return fail(`there is no scoop ${missing.join(', ')}`);\n return rest.map((name) => (handle(deps, who, name) as [string, unknown])[0]);\n}\n\nasync function block(\n deps: Deps,\n ids: string[],\n seconds: number,\n context: Context\n): Promise<Answer> {\n const deadline = deps.now() + seconds * 1000;\n let open = await deps.scoops.working(ids, context);\n while (open.length && deps.now() < deadline) {\n await new Promise((done) => setTimeout(done, 200));\n open = await deps.scoops.working(ids, context);\n }\n const state = deps.agents.state();\n const sections: string[] = [];\n for (const id of ids) {\n const record = state.scoops[id];\n if (record)\n sections.push(\n `## ${record.folder}${open.includes(id) ? ' (still working)' : ''}\\n${await latest(deps, record.folder, context)}`\n );\n }\n const body = `${sections.join('\\n\\n')}\\n`;\n if (!open.length) return ok(body);\n const still = open.map((id) => state.scoops[id]?.folder).join(', ');\n return { code: 1, out: `${body}agent: timed out after ${seconds}s; still working: ${still}\\n` };\n}\n\nasync function wait(deps: Deps, request: Request, who: Caller, context: Context): Promise<Answer> {\n const parsed = flags(request.argv.slice(1), ['--timeout']);\n const unknown = [...parsed.switches].find((flag) => flag !== '--notify');\n if (unknown) return fail(`unknown option ${unknown}`, 2);\n const seconds = Number(last(parsed, '--timeout') ?? DEFAULT_WAIT_S);\n if (!Number.isInteger(seconds) || seconds <= 0)\n return fail('--timeout must be a positive whole number of seconds', 2);\n const ids = waitTargets(deps, who, parsed.rest);\n if (isAnswer(ids)) return ids;\n if (!parsed.switches.has('--notify')) return block(deps, ids, seconds, context);\n if (!who.fromAgent || who.scoop)\n return fail('wait --notify is for a cone; a terminal waits with agent wait');\n await deps.scoops.notifyWhenDone(who.cone, ids, deps.now() + seconds * 1000, context);\n return ok(`you'll get one scoop-wait lick when ${ids.length > 1 ? 'they are' : 'it is'} done\\n`);\n}\n\nasync function stop(deps: Deps, request: Request, who: Caller, context: Context): Promise<Answer> {\n if (who.scoop) return fail('a scoop cannot stop scoops');\n const found = handle(deps, who, request.argv[1]);\n if (!found) return fail(`there is no scoop ${request.argv[1] ?? ''}`.trim());\n return deps.scoops.stop(found[0], who.fromAgent, context);\n}\n\nasync function rename(\n deps: Deps,\n request: Request,\n who: Caller,\n context: Context\n): Promise<Answer> {\n if (who.scoop) return fail('a scoop cannot rename scoops');\n const found = handle(deps, who, request.argv[1]);\n if (!found) return fail(`there is no scoop ${request.argv[1] ?? ''}`.trim());\n return deps.scoops.rename(found[0], request.argv.slice(2).join(' '), context);\n}\n\ntype Verb = (deps: Deps, request: Request, who: Caller, context: Context) => Promise<Answer>;\n\nconst help: Verb = async () => ok(USAGE);\n\nconst VERBS: Record<string, Verb> = {\n list,\n status,\n send,\n wait,\n stop,\n rename,\n help,\n '--help': help,\n '-h': help,\n __cancel: (deps, request, _who, context) => cancelSync(deps, request.argv[1] ?? '', context),\n __detach: (deps, request, _who, context) => detachSync(deps, request.argv[1] ?? '', context),\n};\n\nasync function dispatch(\n deps: Deps,\n request: Request,\n who: Caller,\n context: Context\n): Promise<Answer> {\n if (request.as === 'sprinkle')\n return deps.sprinkle\n ? deps.sprinkle(request.argv, who.id, context)\n : fail('sprinkles are not available in this agent');\n if (request.as === 'memory')\n return deps.memory\n ? deps.memory(request.argv, who.id, context)\n : fail('memory is not available in this agent');\n if (request.as === 'gelatiere')\n return deps.gelatiere\n ? deps.gelatiere(request.argv, who.id, context)\n : fail('the gelatiere is not available in this agent');\n const first = request.argv[0] ?? '';\n const verb = VERBS[first];\n if (verb) return verb(deps, request, who, context);\n if (request.as === 'subagent') {\n if (first === 'spawn') return spawnAsync(deps, request, who, request.argv.slice(1), context);\n return { code: 2, out: USAGE };\n }\n if (!request.argv.length) return { code: 2, out: USAGE };\n if (request.argv.includes('--async'))\n return spawnAsync(deps, request, who, request.argv, context);\n return runSync(deps, request, who, context);\n}\n\nconst BLOCKING = new Set([\n 'wait',\n 'list',\n 'status',\n 'help',\n '--help',\n '-h',\n '__cancel',\n '__detach',\n]);\n\nexport function createCli(options: CliOptions): Runner {\n const deps: Deps = { ...options, now: options.now ?? Date.now, sync: { pending: new Map() } };\n return {\n blocking(request) {\n const first = request.argv[0] ?? '';\n if (BLOCKING.has(first)) return true;\n return request.as === 'agent' && !VERBS[first] && !request.argv.includes('--async');\n },\n async run(request, context) {\n try {\n return await dispatch(deps, request, callerOf(options.agents, request), context);\n } catch (error) {\n return fail((error as Error).message);\n }\n },\n };\n}\n"],
5
+ "mappings": "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",
6
6
  "names": []
7
7
  }
@@ -4,7 +4,7 @@ import { createCli, RUN_DIR } from "./cli.js";
4
4
  import { guardExtension, scoopsExtension, scoopTasks } from "./extension.js";
5
5
  import { controlPlane } from "./requests.js";
6
6
  import { createScoops } from "./service.js";
7
- const BUILTIN_ROLES = ["scout", "worker", "reviewer", "oracle", "delegate"];
7
+ const BUILTIN_ROLES = ["scout", "worker", "reviewer", "oracle", "delegate", "gelatiere"];
8
8
  const PNPM_HOME = "/home/.local/share/pnpm";
9
9
  function packageAssets(base = new URL("../../", import.meta.url)) {
10
10
  return async (path) => {
@@ -13,7 +13,7 @@ function packageAssets(base = new URL("../../", import.meta.url)) {
13
13
  return response.text();
14
14
  };
15
15
  }
16
- const COMMANDS = ["agent", "subagent", "sprinkle", "memory"];
16
+ const COMMANDS = ["agent", "subagent", "sprinkle", "memory", "gelatiere"];
17
17
  async function install(env, script, pnpmHome, context) {
18
18
  await env.createDir(`${pnpmHome}/bin`, { recursive: true }, context);
19
19
  for (const name of COMMANDS) {
@@ -65,7 +65,8 @@ function setupScoops(registry, licks, fileTools = []) {
65
65
  licks,
66
66
  tools: fileTools,
67
67
  groups,
68
- reads: options.reads
68
+ reads: options.reads,
69
+ files: env
69
70
  });
70
71
  const builtin = async () => {
71
72
  const out = [];
@@ -105,7 +106,8 @@ function setupScoops(registry, licks, fileTools = []) {
105
106
  roles: () => roles(context),
106
107
  ...options.alive ? { alive: options.alive } : {},
107
108
  ...options.sprinkle ? { sprinkle: options.sprinkle } : {},
108
- ...options.memory ? { memory: options.memory } : {}
109
+ ...options.memory ? { memory: options.memory } : {},
110
+ ...options.gelatiere ? { gelatiere: options.gelatiere } : {}
109
111
  });
110
112
  const plane = controlPlane(env, cli, {
111
113
  ...options.controlDir ? { dir: options.controlDir } : {},
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../src/scoops/index.ts"],
4
- "sourcesContent": ["import type { Context } from '@earendil-works/chord';\nimport type { Harness, Registry, ToolRegistration } from '@earendil-works/pi-durable';\nimport type { ExecutionEnv } from '@earendil-works/pi-durable/env';\nimport { type Agents, live } from '../agents.ts';\nimport type { ProcessGroups } from '../kernel/groups.ts';\nimport type { Licks } from '../licks/licks.ts';\nimport { DEFAULT_LIMITS, loadRoles, packageDirs, type Roles } from '../roles/roles.ts';\nimport { type CliOptions, createCli, RUN_DIR } from './cli.ts';\nimport { guardExtension, scoopsExtension, scoopTasks } from './extension.ts';\nimport { type ControlPlane, controlPlane } from './requests.ts';\nimport { createScoops, type Scoops, type ScoopsHost } from './service.ts';\n\nexport const BUILTIN_ROLES = ['scout', 'worker', 'reviewer', 'oracle', 'delegate'];\nexport const PNPM_HOME = '/home/.local/share/pnpm';\n\nexport type Assets = (path: string) => Promise<string>;\n\nexport function packageAssets(base: URL = new URL('../../', import.meta.url)): Assets {\n return async (path) => {\n const response = await fetch(new URL(path, base));\n if (!response.ok) throw new Error(`${path}: ${response.status}`);\n return response.text();\n };\n}\n\nexport interface AttachOptions {\n harness: Harness;\n agents: Agents;\n groups: ProcessGroups;\n env: ExecutionEnv;\n home: string;\n assets?: Assets;\n pnpmHome?: string;\n controlDir?: string;\n sweepEvery?: number;\n alive?: (pid: number) => Promise<boolean>;\n reads: () => readonly string[];\n sprinkle?: CliOptions['sprinkle'];\n memory?: CliOptions['memory'];\n}\n\nexport interface ScoopsRuntime {\n roles(context: Context): Promise<Roles>;\n plane: ControlPlane;\n close(context: Context): Promise<void>;\n}\n\nexport interface ScoopsSetup {\n scoops: Scoops;\n attach(options: AttachOptions, context: Context): Promise<ScoopsRuntime>;\n}\n\nexport const COMMANDS = ['agent', 'subagent', 'sprinkle', 'memory'];\n\nasync function install(env: ExecutionEnv, script: string, pnpmHome: string, context: Context) {\n await env.createDir(`${pnpmHome}/bin`, { recursive: true }, context);\n for (const name of COMMANDS) {\n const path = `${pnpmHome}/bin/${name}`;\n await env.writeFile(path, script, context);\n await env.exec(['chmod', '+x', path], undefined, context);\n }\n}\n\nfunction mirror(agents: Agents, env: ExecutionEnv) {\n return async (context: Context) => {\n for (const [id, record] of Object.entries(agents.state().scoops)) {\n const state = record.gone ? 'gone' : live(record) ? 'live' : 'stopped';\n const metadata = {\n handle: record.folder,\n id,\n name: record.name,\n role: record.role,\n cone: record.cone,\n state,\n };\n await env.writeFile(\n `${RUN_DIR}/${record.folder}/metadata.json`,\n `${JSON.stringify(metadata, null, 2)}\\n`,\n context\n );\n }\n };\n}\n\nexport function setupScoops(\n registry: Registry,\n licks: Licks,\n fileTools: readonly ToolRegistration[] = []\n): ScoopsSetup {\n let bind: (host: ScoopsHost) => void = () => undefined;\n const host = new Promise<ScoopsHost>((resolve) => {\n bind = resolve;\n });\n const lookup = () => host;\n const tasks = scoopTasks(lookup);\n const scoops = createScoops(host, () => tasks);\n let cached: Roles = { roles: [], warnings: [], limits: { ...DEFAULT_LIMITS } };\n registry.install(scoopsExtension(tasks));\n registry.install(guardExtension(lookup, fileTools));\n return {\n scoops,\n async attach(options, context) {\n const { harness, agents, groups, env, home } = options;\n const assets = options.assets ?? packageAssets();\n bind({\n harness,\n agents,\n licks,\n tools: fileTools,\n groups,\n reads: options.reads,\n });\n const builtin = async () => {\n const out: { path: string; text: string }[] = [];\n for (const name of BUILTIN_ROLES) {\n const path = `packages/vfs-root/agents/${name}.md`;\n out.push({ path: `builtin:${name}`, text: await assets(path) });\n }\n return out;\n };\n const roles = async (using: Context) => {\n cached = await loadRoles(\n {\n files: env,\n builtin,\n dirs: [\n ...(await packageDirs(env, '/node_modules', using)).map((dir) => ({\n source: 'package' as const,\n dir,\n })),\n { source: 'user', dir: `${home}/.pi/agent/agents` },\n ],\n settingsPath: `${home}/.pi/agent/settings.json`,\n },\n using\n );\n return cached;\n };\n await roles(context).catch(() => cached);\n const script = await assets('bin/agent').catch(() => undefined);\n if (script)\n await install(env, script, options.pnpmHome ?? PNPM_HOME, context).catch(() => undefined);\n const cli = createCli({\n env,\n harness,\n agents,\n scoops,\n roles: () => roles(context),\n ...(options.alive ? { alive: options.alive } : {}),\n ...(options.sprinkle ? { sprinkle: options.sprinkle } : {}),\n ...(options.memory ? { memory: options.memory } : {}),\n });\n const plane = controlPlane(env, cli, {\n ...(options.controlDir ? { dir: options.controlDir } : {}),\n ...(options.sweepEvery ? { sweepEvery: options.sweepEvery } : {}),\n mirror: mirror(agents, env),\n });\n await plane.start(context);\n return { roles, plane, close: (using) => plane.close(using) };\n },\n };\n}\n\nexport type { Rewound, Scoops } from './service.ts';\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["import type { Context } from '@earendil-works/chord';\nimport type { Harness, Registry, ToolRegistration } from '@earendil-works/pi-durable';\nimport type { ExecutionEnv } from '@earendil-works/pi-durable/env';\nimport { type Agents, live } from '../agents.ts';\nimport type { ProcessGroups } from '../kernel/groups.ts';\nimport type { Licks } from '../licks/licks.ts';\nimport { DEFAULT_LIMITS, loadRoles, packageDirs, type Roles } from '../roles/roles.ts';\nimport { type CliOptions, createCli, RUN_DIR } from './cli.ts';\nimport { guardExtension, scoopsExtension, scoopTasks } from './extension.ts';\nimport { type ControlPlane, controlPlane } from './requests.ts';\nimport { createScoops, type Scoops, type ScoopsHost } from './service.ts';\n\nexport const BUILTIN_ROLES = ['scout', 'worker', 'reviewer', 'oracle', 'delegate', 'gelatiere'];\nexport const PNPM_HOME = '/home/.local/share/pnpm';\n\nexport type Assets = (path: string) => Promise<string>;\n\nexport function packageAssets(base: URL = new URL('../../', import.meta.url)): Assets {\n return async (path) => {\n const response = await fetch(new URL(path, base));\n if (!response.ok) throw new Error(`${path}: ${response.status}`);\n return response.text();\n };\n}\n\nexport interface AttachOptions {\n harness: Harness;\n agents: Agents;\n groups: ProcessGroups;\n env: ExecutionEnv;\n home: string;\n assets?: Assets;\n pnpmHome?: string;\n controlDir?: string;\n sweepEvery?: number;\n alive?: (pid: number) => Promise<boolean>;\n reads: () => readonly string[];\n sprinkle?: CliOptions['sprinkle'];\n memory?: CliOptions['memory'];\n gelatiere?: CliOptions['gelatiere'];\n}\n\nexport interface ScoopsRuntime {\n roles(context: Context): Promise<Roles>;\n plane: ControlPlane;\n close(context: Context): Promise<void>;\n}\n\nexport interface ScoopsSetup {\n scoops: Scoops;\n attach(options: AttachOptions, context: Context): Promise<ScoopsRuntime>;\n}\n\nexport const COMMANDS = ['agent', 'subagent', 'sprinkle', 'memory', 'gelatiere'];\n\nasync function install(env: ExecutionEnv, script: string, pnpmHome: string, context: Context) {\n await env.createDir(`${pnpmHome}/bin`, { recursive: true }, context);\n for (const name of COMMANDS) {\n const path = `${pnpmHome}/bin/${name}`;\n await env.writeFile(path, script, context);\n await env.exec(['chmod', '+x', path], undefined, context);\n }\n}\n\nfunction mirror(agents: Agents, env: ExecutionEnv) {\n return async (context: Context) => {\n for (const [id, record] of Object.entries(agents.state().scoops)) {\n const state = record.gone ? 'gone' : live(record) ? 'live' : 'stopped';\n const metadata = {\n handle: record.folder,\n id,\n name: record.name,\n role: record.role,\n cone: record.cone,\n state,\n };\n await env.writeFile(\n `${RUN_DIR}/${record.folder}/metadata.json`,\n `${JSON.stringify(metadata, null, 2)}\\n`,\n context\n );\n }\n };\n}\n\nexport function setupScoops(\n registry: Registry,\n licks: Licks,\n fileTools: readonly ToolRegistration[] = []\n): ScoopsSetup {\n let bind: (host: ScoopsHost) => void = () => undefined;\n const host = new Promise<ScoopsHost>((resolve) => {\n bind = resolve;\n });\n const lookup = () => host;\n const tasks = scoopTasks(lookup);\n const scoops = createScoops(host, () => tasks);\n let cached: Roles = { roles: [], warnings: [], limits: { ...DEFAULT_LIMITS } };\n registry.install(scoopsExtension(tasks));\n registry.install(guardExtension(lookup, fileTools));\n return {\n scoops,\n async attach(options, context) {\n const { harness, agents, groups, env, home } = options;\n const assets = options.assets ?? packageAssets();\n bind({\n harness,\n agents,\n licks,\n tools: fileTools,\n groups,\n reads: options.reads,\n files: env,\n });\n const builtin = async () => {\n const out: { path: string; text: string }[] = [];\n for (const name of BUILTIN_ROLES) {\n const path = `packages/vfs-root/agents/${name}.md`;\n out.push({ path: `builtin:${name}`, text: await assets(path) });\n }\n return out;\n };\n const roles = async (using: Context) => {\n cached = await loadRoles(\n {\n files: env,\n builtin,\n dirs: [\n ...(await packageDirs(env, '/node_modules', using)).map((dir) => ({\n source: 'package' as const,\n dir,\n })),\n { source: 'user', dir: `${home}/.pi/agent/agents` },\n ],\n settingsPath: `${home}/.pi/agent/settings.json`,\n },\n using\n );\n return cached;\n };\n await roles(context).catch(() => cached);\n const script = await assets('bin/agent').catch(() => undefined);\n if (script)\n await install(env, script, options.pnpmHome ?? PNPM_HOME, context).catch(() => undefined);\n const cli = createCli({\n env,\n harness,\n agents,\n scoops,\n roles: () => roles(context),\n ...(options.alive ? { alive: options.alive } : {}),\n ...(options.sprinkle ? { sprinkle: options.sprinkle } : {}),\n ...(options.memory ? { memory: options.memory } : {}),\n ...(options.gelatiere ? { gelatiere: options.gelatiere } : {}),\n });\n const plane = controlPlane(env, cli, {\n ...(options.controlDir ? { dir: options.controlDir } : {}),\n ...(options.sweepEvery ? { sweepEvery: options.sweepEvery } : {}),\n mirror: mirror(agents, env),\n });\n await plane.start(context);\n return { roles, plane, close: (using) => plane.close(using) };\n },\n };\n}\n\nexport type { Rewound, Scoops } from './service.ts';\n"],
5
+ "mappings": "AAGA,SAAsB,YAAY;AAGlC,SAAS,gBAAgB,WAAW,mBAA+B;AACnE,SAA0B,WAAW,eAAe;AACpD,SAAS,gBAAgB,iBAAiB,kBAAkB;AAC5D,SAA4B,oBAAoB;AAChD,SAAS,oBAAkD;AAEpD,MAAM,gBAAgB,CAAC,SAAS,UAAU,YAAY,UAAU,YAAY,WAAW;AACvF,MAAM,YAAY;AAIlB,SAAS,cAAc,OAAY,IAAI,IAAI,UAAU,YAAY,GAAG,GAAW;AACpF,SAAO,OAAO,SAAS;AACrB,UAAM,WAAW,MAAM,MAAM,IAAI,IAAI,MAAM,IAAI,CAAC;AAChD,QAAI,CAAC,SAAS,GAAI,OAAM,IAAI,MAAM,GAAG,IAAI,KAAK,SAAS,MAAM,EAAE;AAC/D,WAAO,SAAS,KAAK;AAAA,EACvB;AACF;AA8BO,MAAM,WAAW,CAAC,SAAS,YAAY,YAAY,UAAU,WAAW;AAE/E,eAAe,QAAQ,KAAmB,QAAgB,UAAkB,SAAkB;AAC5F,QAAM,IAAI,UAAU,GAAG,QAAQ,QAAQ,EAAE,WAAW,KAAK,GAAG,OAAO;AACnE,aAAW,QAAQ,UAAU;AAC3B,UAAM,OAAO,GAAG,QAAQ,QAAQ,IAAI;AACpC,UAAM,IAAI,UAAU,MAAM,QAAQ,OAAO;AACzC,UAAM,IAAI,KAAK,CAAC,SAAS,MAAM,IAAI,GAAG,QAAW,OAAO;AAAA,EAC1D;AACF;AAEA,SAAS,OAAO,QAAgB,KAAmB;AACjD,SAAO,OAAO,YAAqB;AACjC,eAAW,CAAC,IAAI,MAAM,KAAK,OAAO,QAAQ,OAAO,MAAM,EAAE,MAAM,GAAG;AAChE,YAAM,QAAQ,OAAO,OAAO,SAAS,KAAK,MAAM,IAAI,SAAS;AAC7D,YAAM,WAAW;AAAA,QACf,QAAQ,OAAO;AAAA,QACf;AAAA,QACA,MAAM,OAAO;AAAA,QACb,MAAM,OAAO;AAAA,QACb,MAAM,OAAO;AAAA,QACb;AAAA,MACF;AACA,YAAM,IAAI;AAAA,QACR,GAAG,OAAO,IAAI,OAAO,MAAM;AAAA,QAC3B,GAAG,KAAK,UAAU,UAAU,MAAM,CAAC,CAAC;AAAA;AAAA,QACpC;AAAA,MACF;AAAA,IACF;AAAA,EACF;AACF;AAEO,SAAS,YACd,UACA,OACA,YAAyC,CAAC,GAC7B;AACb,MAAI,OAAmC,MAAM;AAC7C,QAAM,OAAO,IAAI,QAAoB,CAAC,YAAY;AAChD,WAAO;AAAA,EACT,CAAC;AACD,QAAM,SAAS,MAAM;AACrB,QAAM,QAAQ,WAAW,MAAM;AAC/B,QAAM,SAAS,aAAa,MAAM,MAAM,KAAK;AAC7C,MAAI,SAAgB,EAAE,OAAO,CAAC,GAAG,UAAU,CAAC,GAAG,QAAQ,EAAE,GAAG,eAAe,EAAE;AAC7E,WAAS,QAAQ,gBAAgB,KAAK,CAAC;AACvC,WAAS,QAAQ,eAAe,QAAQ,SAAS,CAAC;AAClD,SAAO;AAAA,IACL;AAAA,IACA,MAAM,OAAO,SAAS,SAAS;AAC7B,YAAM,EAAE,SAAS,QAAQ,QAAQ,KAAK,KAAK,IAAI;AAC/C,YAAM,SAAS,QAAQ,UAAU,cAAc;AAC/C,WAAK;AAAA,QACH;AAAA,QACA;AAAA,QACA;AAAA,QACA,OAAO;AAAA,QACP;AAAA,QACA,OAAO,QAAQ;AAAA,QACf,OAAO;AAAA,MACT,CAAC;AACD,YAAM,UAAU,YAAY;AAC1B,cAAM,MAAwC,CAAC;AAC/C,mBAAW,QAAQ,eAAe;AAChC,gBAAM,OAAO,4BAA4B,IAAI;AAC7C,cAAI,KAAK,EAAE,MAAM,WAAW,IAAI,IAAI,MAAM,MAAM,OAAO,IAAI,EAAE,CAAC;AAAA,QAChE;AACA,eAAO;AAAA,MACT;AACA,YAAM,QAAQ,OAAO,UAAmB;AACtC,iBAAS,MAAM;AAAA,UACb;AAAA,YACE,OAAO;AAAA,YACP;AAAA,YACA,MAAM;AAAA,cACJ,IAAI,MAAM,YAAY,KAAK,iBAAiB,KAAK,GAAG,IAAI,CAAC,SAAS;AAAA,gBAChE,QAAQ;AAAA,gBACR;AAAA,cACF,EAAE;AAAA,cACF,EAAE,QAAQ,QAAQ,KAAK,GAAG,IAAI,oBAAoB;AAAA,YACpD;AAAA,YACA,cAAc,GAAG,IAAI;AAAA,UACvB;AAAA,UACA;AAAA,QACF;AACA,eAAO;AAAA,MACT;AACA,YAAM,MAAM,OAAO,EAAE,MAAM,MAAM,MAAM;AACvC,YAAM,SAAS,MAAM,OAAO,WAAW,EAAE,MAAM,MAAM,MAAS;AAC9D,UAAI;AACF,cAAM,QAAQ,KAAK,QAAQ,QAAQ,YAAY,WAAW,OAAO,EAAE,MAAM,MAAM,MAAS;AAC1F,YAAM,MAAM,UAAU;AAAA,QACpB;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA,OAAO,MAAM,MAAM,OAAO;AAAA,QAC1B,GAAI,QAAQ,QAAQ,EAAE,OAAO,QAAQ,MAAM,IAAI,CAAC;AAAA,QAChD,GAAI,QAAQ,WAAW,EAAE,UAAU,QAAQ,SAAS,IAAI,CAAC;AAAA,QACzD,GAAI,QAAQ,SAAS,EAAE,QAAQ,QAAQ,OAAO,IAAI,CAAC;AAAA,QACnD,GAAI,QAAQ,YAAY,EAAE,WAAW,QAAQ,UAAU,IAAI,CAAC;AAAA,MAC9D,CAAC;AACD,YAAM,QAAQ,aAAa,KAAK,KAAK;AAAA,QACnC,GAAI,QAAQ,aAAa,EAAE,KAAK,QAAQ,WAAW,IAAI,CAAC;AAAA,QACxD,GAAI,QAAQ,aAAa,EAAE,YAAY,QAAQ,WAAW,IAAI,CAAC;AAAA,QAC/D,QAAQ,OAAO,QAAQ,GAAG;AAAA,MAC5B,CAAC;AACD,YAAM,MAAM,MAAM,OAAO;AACzB,aAAO,EAAE,OAAO,OAAO,OAAO,CAAC,UAAU,MAAM,MAAM,KAAK,EAAE;AAAA,IAC9D;AAAA,EACF;AACF;",
6
6
  "names": []
7
7
  }
@@ -1,6 +1,7 @@
1
1
  const CONTROL_DIR = "/var/lib/slicc/agent/requests";
2
2
  const PROTOCOL = "slicc-agent/1";
3
3
  const STALE_MS = 10 * 6e4;
4
+ const COMMAND_NAMES = /* @__PURE__ */ new Set(["subagent", "sprinkle", "memory", "gelatiere"]);
4
5
  const HEADER = 6;
5
6
  function parseRequest(id, bytes) {
6
7
  const decoder = new TextDecoder();
@@ -25,7 +26,7 @@ function parseRequest(id, bytes) {
25
26
  const process = Number(pid);
26
27
  return {
27
28
  id,
28
- as: as === "subagent" || as === "sprinkle" || as === "memory" ? as : "agent",
29
+ as: COMMAND_NAMES.has(as) ? as : "agent",
29
30
  caller,
30
31
  cwd: cwd || "/",
31
32
  pid: Number.isInteger(process) && process > 0 ? process : null,
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../src/scoops/requests.ts"],
4
- "sourcesContent": ["import type { Context } from '@earendil-works/chord';\nimport type { ExecutionEnv, FileWatcher } from '@earendil-works/pi-durable/env';\nimport type { Answer } from './service.ts';\n\nexport const CONTROL_DIR = '/var/lib/slicc/agent/requests';\nexport const PROTOCOL = 'slicc-agent/1';\nexport const STALE_MS = 10 * 60_000;\n\nexport interface Request {\n id: string;\n as: 'agent' | 'subagent' | 'sprinkle' | 'memory';\n caller: string;\n cwd: string;\n pid: number | null;\n argv: string[];\n stdin: string;\n}\n\nconst HEADER = 6;\n\nexport function parseRequest(id: string, bytes: Uint8Array): Request | undefined {\n const decoder = new TextDecoder();\n const fields: string[] = [];\n let at = 0;\n while (fields.length < HEADER) {\n const end = bytes.indexOf(0, at);\n if (end < 0) return undefined;\n fields.push(decoder.decode(bytes.subarray(at, end)));\n at = end + 1;\n }\n const [version, as, caller, cwd, pid, count] = fields;\n const argc = Number(count);\n if (version !== PROTOCOL || !Number.isInteger(argc) || argc < 0) return undefined;\n const argv: string[] = [];\n while (argv.length < argc) {\n const end = bytes.indexOf(0, at);\n if (end < 0) return undefined;\n argv.push(decoder.decode(bytes.subarray(at, end)));\n at = end + 1;\n }\n const process = Number(pid);\n return {\n id,\n as: as === 'subagent' || as === 'sprinkle' || as === 'memory' ? as : 'agent',\n caller: caller as string,\n cwd: cwd || '/',\n pid: Number.isInteger(process) && process > 0 ? process : null,\n argv,\n stdin: decoder.decode(bytes.subarray(at)),\n };\n}\n\nexport interface Runner {\n run(request: Request, context: Context): Promise<Answer>;\n blocking(request: Request): boolean;\n}\n\nexport interface ControlPlane {\n start(context: Context): Promise<void>;\n sweep(context: Context): Promise<void>;\n close(context: Context): Promise<void>;\n}\n\nexport interface PlaneOptions {\n dir?: string;\n now?: () => number;\n sweepEvery?: number;\n mirror?: (context: Context) => Promise<void>;\n}\n\nexport function controlPlane(\n env: ExecutionEnv,\n runner: Runner,\n options: PlaneOptions = {}\n): ControlPlane {\n const dir = options.dir ?? CONTROL_DIR;\n const requests = `${dir}/in`;\n const responses = `${dir}/out`;\n const now = options.now ?? Date.now;\n const handled = new Set<string>();\n let watcher: FileWatcher | undefined;\n let timer: ReturnType<typeof setInterval> | undefined;\n let lock: Promise<unknown> = Promise.resolve();\n const serial = <T>(operation: () => Promise<T>): Promise<T> => {\n const next = lock.then(operation, operation);\n lock = next.catch(() => undefined);\n return next;\n };\n\n async function answer(id: string, result: Answer, context: Context) {\n await env.writeFile(`${responses}/${id}.out`, result.out, context);\n await env.writeFile(`${responses}/${id}.code`, String(result.code), context);\n await env.remove(`${requests}/${id}`, { force: true }, context);\n await env.remove(`${responses}/${id}.ack`, { force: true }, context);\n await options.mirror?.(context).catch(() => undefined);\n }\n\n async function handle(id: string, context: Context) {\n if (handled.has(id)) return;\n handled.add(id);\n try {\n const bytes = await env.readBinaryFile(`${requests}/${id}`, context);\n if (!bytes.ok) return;\n await env.writeFile(`${responses}/${id}.ack`, '', context);\n const request = parseRequest(id, bytes.value);\n if (!request) {\n await answer(\n id,\n { code: 2, out: 'agent: this request is not understood; update the agent command\\n' },\n context\n );\n return;\n }\n const result = runner.blocking(request)\n ? await runner.run(request, context)\n : await serial(() => runner.run(request, context));\n await answer(id, result, context);\n } finally {\n handled.delete(id);\n }\n }\n\n async function scan(context: Context) {\n const listed = await env.listDir(requests, context);\n if (!listed.ok) return;\n for (const entry of listed.value.sort((a, b) => a.name.localeCompare(b.name)))\n if (entry.kind === 'file' && !entry.name.startsWith('.'))\n void handle(entry.name, context).catch(() => undefined);\n }\n\n async function sweep(context: Context) {\n for (const folder of [requests, responses]) {\n const listed = await env.listDir(folder, context);\n if (!listed.ok) continue;\n for (const entry of listed.value) {\n const stale = now() - entry.mtimeMs > STALE_MS;\n const removable = folder === responses || entry.name.startsWith('.tmp-');\n if (stale && removable)\n await env.remove(`${folder}/${entry.name}`, { force: true }, context);\n }\n }\n }\n\n return {\n async start(context) {\n await env.createDir(requests, { recursive: true }, context);\n await env.createDir(responses, { recursive: true }, context);\n const leftovers = await env.listDir(requests, context);\n if (leftovers.ok)\n for (const entry of leftovers.value)\n if (entry.name.startsWith('.tmp-'))\n await env.remove(`${requests}/${entry.name}`, { force: true }, context);\n await sweep(context);\n const watched = await env.watch(\n [{ path: requests }],\n () => void scan(context).catch(() => undefined),\n context\n );\n if (watched.ok) watcher = watched.value;\n await scan(context);\n timer = setInterval(\n () => void sweep(context).catch(() => undefined),\n options.sweepEvery ?? 60_000\n );\n },\n sweep,\n async close(context) {\n clearInterval(timer);\n await watcher?.close(context);\n await lock;\n },\n };\n}\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["import type { Context } from '@earendil-works/chord';\nimport type { ExecutionEnv, FileWatcher } from '@earendil-works/pi-durable/env';\nimport type { Answer } from './service.ts';\n\nexport const CONTROL_DIR = '/var/lib/slicc/agent/requests';\nexport const PROTOCOL = 'slicc-agent/1';\nexport const STALE_MS = 10 * 60_000;\nconst COMMAND_NAMES = new Set(['subagent', 'sprinkle', 'memory', 'gelatiere']);\n\nexport interface Request {\n id: string;\n as: 'agent' | 'subagent' | 'sprinkle' | 'memory' | 'gelatiere';\n caller: string;\n cwd: string;\n pid: number | null;\n argv: string[];\n stdin: string;\n}\n\nconst HEADER = 6;\n\nexport function parseRequest(id: string, bytes: Uint8Array): Request | undefined {\n const decoder = new TextDecoder();\n const fields: string[] = [];\n let at = 0;\n while (fields.length < HEADER) {\n const end = bytes.indexOf(0, at);\n if (end < 0) return undefined;\n fields.push(decoder.decode(bytes.subarray(at, end)));\n at = end + 1;\n }\n const [version, as, caller, cwd, pid, count] = fields;\n const argc = Number(count);\n if (version !== PROTOCOL || !Number.isInteger(argc) || argc < 0) return undefined;\n const argv: string[] = [];\n while (argv.length < argc) {\n const end = bytes.indexOf(0, at);\n if (end < 0) return undefined;\n argv.push(decoder.decode(bytes.subarray(at, end)));\n at = end + 1;\n }\n const process = Number(pid);\n return {\n id,\n as: COMMAND_NAMES.has(as as string) ? (as as Request['as']) : 'agent',\n caller: caller as string,\n cwd: cwd || '/',\n pid: Number.isInteger(process) && process > 0 ? process : null,\n argv,\n stdin: decoder.decode(bytes.subarray(at)),\n };\n}\n\nexport interface Runner {\n run(request: Request, context: Context): Promise<Answer>;\n blocking(request: Request): boolean;\n}\n\nexport interface ControlPlane {\n start(context: Context): Promise<void>;\n sweep(context: Context): Promise<void>;\n close(context: Context): Promise<void>;\n}\n\nexport interface PlaneOptions {\n dir?: string;\n now?: () => number;\n sweepEvery?: number;\n mirror?: (context: Context) => Promise<void>;\n}\n\nexport function controlPlane(\n env: ExecutionEnv,\n runner: Runner,\n options: PlaneOptions = {}\n): ControlPlane {\n const dir = options.dir ?? CONTROL_DIR;\n const requests = `${dir}/in`;\n const responses = `${dir}/out`;\n const now = options.now ?? Date.now;\n const handled = new Set<string>();\n let watcher: FileWatcher | undefined;\n let timer: ReturnType<typeof setInterval> | undefined;\n let lock: Promise<unknown> = Promise.resolve();\n const serial = <T>(operation: () => Promise<T>): Promise<T> => {\n const next = lock.then(operation, operation);\n lock = next.catch(() => undefined);\n return next;\n };\n\n async function answer(id: string, result: Answer, context: Context) {\n await env.writeFile(`${responses}/${id}.out`, result.out, context);\n await env.writeFile(`${responses}/${id}.code`, String(result.code), context);\n await env.remove(`${requests}/${id}`, { force: true }, context);\n await env.remove(`${responses}/${id}.ack`, { force: true }, context);\n await options.mirror?.(context).catch(() => undefined);\n }\n\n async function handle(id: string, context: Context) {\n if (handled.has(id)) return;\n handled.add(id);\n try {\n const bytes = await env.readBinaryFile(`${requests}/${id}`, context);\n if (!bytes.ok) return;\n await env.writeFile(`${responses}/${id}.ack`, '', context);\n const request = parseRequest(id, bytes.value);\n if (!request) {\n await answer(\n id,\n { code: 2, out: 'agent: this request is not understood; update the agent command\\n' },\n context\n );\n return;\n }\n const result = runner.blocking(request)\n ? await runner.run(request, context)\n : await serial(() => runner.run(request, context));\n await answer(id, result, context);\n } finally {\n handled.delete(id);\n }\n }\n\n async function scan(context: Context) {\n const listed = await env.listDir(requests, context);\n if (!listed.ok) return;\n for (const entry of listed.value.sort((a, b) => a.name.localeCompare(b.name)))\n if (entry.kind === 'file' && !entry.name.startsWith('.'))\n void handle(entry.name, context).catch(() => undefined);\n }\n\n async function sweep(context: Context) {\n for (const folder of [requests, responses]) {\n const listed = await env.listDir(folder, context);\n if (!listed.ok) continue;\n for (const entry of listed.value) {\n const stale = now() - entry.mtimeMs > STALE_MS;\n const removable = folder === responses || entry.name.startsWith('.tmp-');\n if (stale && removable)\n await env.remove(`${folder}/${entry.name}`, { force: true }, context);\n }\n }\n }\n\n return {\n async start(context) {\n await env.createDir(requests, { recursive: true }, context);\n await env.createDir(responses, { recursive: true }, context);\n const leftovers = await env.listDir(requests, context);\n if (leftovers.ok)\n for (const entry of leftovers.value)\n if (entry.name.startsWith('.tmp-'))\n await env.remove(`${requests}/${entry.name}`, { force: true }, context);\n await sweep(context);\n const watched = await env.watch(\n [{ path: requests }],\n () => void scan(context).catch(() => undefined),\n context\n );\n if (watched.ok) watcher = watched.value;\n await scan(context);\n timer = setInterval(\n () => void sweep(context).catch(() => undefined),\n options.sweepEvery ?? 60_000\n );\n },\n sweep,\n async close(context) {\n clearInterval(timer);\n await watcher?.close(context);\n await lock;\n },\n };\n}\n"],
5
+ "mappings": "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",
6
6
  "names": []
7
7
  }
@@ -252,7 +252,7 @@ async function stopFeeds(core, scoop, keep, context) {
252
252
  return dropped.length;
253
253
  }
254
254
  async function stop(core, id, fromAgent, context) {
255
- const { agents } = await core.host;
255
+ const { agents, files } = await core.host;
256
256
  const record = agents.state().scoops[id];
257
257
  if (!record || !live(record)) return missing(id);
258
258
  await stopFeeds(core, id, async () => false, context);
@@ -261,9 +261,15 @@ async function stop(core, id, fromAgent, context) {
261
261
  await agents.update((_tx, state) => {
262
262
  state.scoops[id].dropped = mark;
263
263
  }, context);
264
+ const removed = await files?.remove(
265
+ workspace(record.folder),
266
+ { recursive: true, force: true },
267
+ context
268
+ );
269
+ const folder = removed?.ok ? `removed ${workspace(record.folder)}` : `kept ${workspace(record.folder)}`;
264
270
  return {
265
271
  code: 0,
266
- out: `stopped ${record.folder}; its transcript is kept, and its files stay in ${SCOOPS_ROOT}/${record.folder}
272
+ out: `stopped ${record.folder}; its transcript is kept, ${folder}, and its reports stay in ${SCOOPS_ROOT}/${record.folder}/reports
267
273
  `
268
274
  };
269
275
  }
@@ -279,8 +285,14 @@ async function rename(core, id, name, context) {
279
285
  return { code: 0, out: `${record.folder} is now called ${wanted}
280
286
  ` };
281
287
  }
288
+ async function resetWorkspace(files, folder, context) {
289
+ if (!files) return true;
290
+ const cleared = await files.remove(workspace(folder), { recursive: true, force: true }, context);
291
+ if (!cleared.ok) return false;
292
+ return (await files.createDir(workspace(folder), { recursive: true }, context)).ok;
293
+ }
282
294
  async function rewindOne(core, coneId, id, record, seen, result, context) {
283
- const { harness, licks } = await core.host;
295
+ const { harness, licks, files } = await core.host;
284
296
  if (!await seen(record.created)) {
285
297
  if (live(record)) {
286
298
  await stopFeeds(core, id, async () => false, context);
@@ -291,7 +303,10 @@ async function rewindOne(core, coneId, id, record, seen, result, context) {
291
303
  }
292
304
  if (record.dropped !== null) {
293
305
  if (await seen(record.dropped)) return void 0;
294
- result.restored.push(record.name);
306
+ const reset = await resetWorkspace(files, record.folder, context);
307
+ result.restored.push(
308
+ reset ? record.name : `${record.name} (its working folder could not be reset)`
309
+ );
295
310
  return { dropped: null };
296
311
  }
297
312
  const withdrawn = await stopFeeds(core, id, (entry) => seen(entry.created), context);