@ai-ecoverse/slicc-agent 3.5.0 → 3.7.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 (91) hide show
  1. package/README.md +21 -4
  2. package/bin/agent +76 -0
  3. package/dist/agent.js +7 -14
  4. package/dist/agent.js.map +2 -2
  5. package/dist/agents.js +133 -0
  6. package/dist/agents.js.map +7 -0
  7. package/dist/client.js +3 -1
  8. package/dist/client.js.map +2 -2
  9. package/dist/cone.js +2 -16
  10. package/dist/cone.js.map +2 -2
  11. package/dist/control.js +68 -10
  12. package/dist/control.js.map +2 -2
  13. package/dist/host.js +11 -2
  14. package/dist/host.js.map +2 -2
  15. package/dist/kernel/env.js +49 -5
  16. package/dist/kernel/env.js.map +2 -2
  17. package/dist/kernel/exec.js +2 -1
  18. package/dist/kernel/exec.js.map +2 -2
  19. package/dist/kernel/groups.js +31 -0
  20. package/dist/kernel/groups.js.map +7 -0
  21. package/dist/kernel/watch.js +86 -0
  22. package/dist/kernel/watch.js.map +2 -2
  23. package/dist/licks/index.js +16 -1
  24. package/dist/licks/index.js.map +2 -2
  25. package/dist/licks/lick.js.map +1 -1
  26. package/dist/licks/licks.js +12 -1
  27. package/dist/licks/licks.js.map +2 -2
  28. package/dist/main.js +38 -9
  29. package/dist/main.js.map +2 -2
  30. package/dist/roles/frontmatter.js +59 -0
  31. package/dist/roles/frontmatter.js.map +7 -0
  32. package/dist/roles/roles.js +204 -0
  33. package/dist/roles/roles.js.map +7 -0
  34. package/dist/scoops/cli.js +391 -0
  35. package/dist/scoops/cli.js.map +7 -0
  36. package/dist/scoops/extension.js +301 -0
  37. package/dist/scoops/extension.js.map +7 -0
  38. package/dist/scoops/identity.js +33 -0
  39. package/dist/scoops/identity.js.map +7 -0
  40. package/dist/scoops/index.js +120 -0
  41. package/dist/scoops/index.js.map +7 -0
  42. package/dist/scoops/requests.js +136 -0
  43. package/dist/scoops/requests.js.map +7 -0
  44. package/dist/scoops/service.js +409 -0
  45. package/dist/scoops/service.js.map +7 -0
  46. package/dist/scoops/sync.js +252 -0
  47. package/dist/scoops/sync.js.map +7 -0
  48. package/dist/scoops/visible.js +15 -0
  49. package/dist/scoops/visible.js.map +7 -0
  50. package/dist/services.js.map +2 -2
  51. package/dist/spectrum/agent-port.js +137 -54
  52. package/dist/spectrum/agent-port.js.map +2 -2
  53. package/dist/spectrum/messages.js +19 -10
  54. package/dist/spectrum/messages.js.map +2 -2
  55. package/dist/types/agent.d.ts +3 -1
  56. package/dist/types/agents.d.ts +54 -0
  57. package/dist/types/client.d.ts +3 -1
  58. package/dist/types/cone.d.ts +1 -3
  59. package/dist/types/control.d.ts +7 -1
  60. package/dist/types/host.d.ts +2 -1
  61. package/dist/types/kernel/client.d.ts +13 -0
  62. package/dist/types/kernel/env.d.ts +13 -2
  63. package/dist/types/kernel/exec.d.ts +2 -2
  64. package/dist/types/kernel/groups.d.ts +7 -0
  65. package/dist/types/kernel/watch.d.ts +12 -1
  66. package/dist/types/licks/index.d.ts +5 -0
  67. package/dist/types/licks/lick.d.ts +1 -1
  68. package/dist/types/licks/licks.d.ts +2 -1
  69. package/dist/types/main.d.ts +3 -0
  70. package/dist/types/roles/frontmatter.d.ts +7 -0
  71. package/dist/types/roles/roles.d.ts +48 -0
  72. package/dist/types/scoops/cli.d.ts +66 -0
  73. package/dist/types/scoops/extension.d.ts +63 -0
  74. package/dist/types/scoops/identity.d.ts +6 -0
  75. package/dist/types/scoops/index.d.ts +37 -0
  76. package/dist/types/scoops/requests.d.ts +32 -0
  77. package/dist/types/scoops/service.d.ts +116 -0
  78. package/dist/types/scoops/sync.d.ts +22 -0
  79. package/dist/types/scoops/visible.d.ts +4 -0
  80. package/dist/types/services.d.ts +30 -0
  81. package/dist/types/spectrum/agent-port.d.ts +13 -11
  82. package/dist/types/views.d.ts +12 -0
  83. package/dist/views.js +89 -0
  84. package/dist/views.js.map +7 -0
  85. package/package.json +6 -4
  86. package/packages/vfs-root/agents/delegate.md +8 -0
  87. package/packages/vfs-root/agents/oracle.md +25 -0
  88. package/packages/vfs-root/agents/reviewer.md +23 -0
  89. package/packages/vfs-root/agents/scout.md +30 -0
  90. package/packages/vfs-root/agents/worker.md +23 -0
  91. package/packages/vfs-root/skills/agent/SKILL.md +72 -0
@@ -0,0 +1,301 @@
1
+ import {
2
+ AssistantEntry,
3
+ defineExtension,
4
+ defineTask,
5
+ section,
6
+ wrapTool
7
+ } from "@earendil-works/pi-durable";
8
+ import { answerText } from "../agent.js";
9
+ import { AgentsDoc, live } from "../agents.js";
10
+ import { HOME } from "../kernel/env.js";
11
+ import { normalize, resolve } from "../kernel/paths.js";
12
+ import { SCOOPS_ROOT, ScoopWorkDoc, workspace } from "./service.js";
13
+ const PREVIEW = 1e3;
14
+ const ADVERTISED = 16;
15
+ function scoopFacts(record) {
16
+ return [
17
+ `You are the scoop "${record.name}"${record.role ? ` (role: ${record.role})` : ""}, a helper agent working for a cone. Messages come from the cone or from the user at a terminal; your final answer goes back to whoever asked, so end every task with a complete answer.`,
18
+ `Work in ${workspace(record.folder)}. Your read, write and edit tools only reach ${SCOOPS_ROOT}/${record.folder} and /tmp, and read ${HOME}.`,
19
+ "Your bash is not confined: it sees the whole file system and every process. Stay in your folder anyway, and change nothing outside it unless the request says so.",
20
+ "You may run `agent` synchronously for a bounded side task (calls nest at most three deep), but you cannot start asynchronous scoops (`agent --async`, `subagent spawn`)."
21
+ ].join("\n");
22
+ }
23
+ function lines(text) {
24
+ return text ? text.split("\n").length : 0;
25
+ }
26
+ function reportLick(record, id, report, route = {}) {
27
+ const status = report.failed ? report.failed === "aborted" ? "stopped" : "failed" : "completed";
28
+ const label = `${record.name} (${record.role ?? "scoop"})`;
29
+ const preview = report.text.length > PREVIEW ? `${report.text.slice(0, PREVIEW)}\u2026` : report.text;
30
+ const where = report.path ? `Output: ${report.path} (${lines(report.text)} lines)` : null;
31
+ const reason = report.failed && report.failed !== "aborted" ? `Reason: ${report.failed}` : null;
32
+ return {
33
+ channel: route.channel ?? "scoop-notify",
34
+ source: id,
35
+ title: label,
36
+ text: `[scoop ${record.name} (${record.role ?? "scoop"}) ${status}]`,
37
+ body: [where, reason, preview].filter(Boolean).join("\n\n"),
38
+ target: route.target ?? `cone:${record.cone}`,
39
+ ...report.failed && report.failed !== "aborted" ? { severity: "warn" } : {}
40
+ };
41
+ }
42
+ function waitTask(lookup) {
43
+ return defineTask({
44
+ name: "slicc.scoop-wait",
45
+ version: 1,
46
+ initial: () => ({ phase: "start" }),
47
+ phases: {
48
+ async start(task, runtime, context) {
49
+ await runtime.commit(async (tx) => {
50
+ (await tx.doc(ScoopWorkDoc)).waits[String(task.id)] = {
51
+ scoops: task.input.scoops,
52
+ done: {},
53
+ cone: task.input.cone
54
+ };
55
+ return { status: "running", checkpoint: { phase: "watch" } };
56
+ }, context);
57
+ },
58
+ async watch(task, runtime, context) {
59
+ const { agents, licks } = await lookup();
60
+ const key = String(task.id);
61
+ for (; ; ) {
62
+ const work = await runtime.snapshot(ScoopWorkDoc, context);
63
+ const state = work?.waits[key];
64
+ if (!state) break;
65
+ const feeding = new Set(Object.values(work?.feeds ?? {}).map((feed) => feed.scoop));
66
+ const open = state.scoops.filter((id) => !(id in state.done) && feeding.has(id));
67
+ const expired = runtime.now() >= task.input.deadline;
68
+ if (open.length && !expired) {
69
+ await runtime.sleep(Math.min(runtime.now() + 300, task.input.deadline), context);
70
+ continue;
71
+ }
72
+ const names = (id) => agents.state().scoops[id]?.name ?? id;
73
+ const body = state.scoops.map(
74
+ (id) => open.includes(id) ? `## ${names(id)}
75
+ (still working when the wait timed out)` : `## ${names(id)}
76
+ ${state.done[id] ?? "(nothing was running)"}`
77
+ );
78
+ await licks.deliver(
79
+ {
80
+ channel: "scoop-wait",
81
+ source: key,
82
+ title: `Waited for ${state.scoops.map(names).join(", ")}`,
83
+ text: open.length ? `${state.scoops.length - open.length} of ${state.scoops.length} done; timed out waiting for ${open.map(names).join(", ")}` : `All ${state.scoops.length} done`,
84
+ body: body.join("\n\n"),
85
+ target: `cone:${state.cone}`,
86
+ coalesce: false,
87
+ eventId: `wait:${key}`
88
+ },
89
+ context
90
+ );
91
+ break;
92
+ }
93
+ await runtime.commit(async (tx) => {
94
+ delete (await tx.doc(ScoopWorkDoc)).waits[key];
95
+ return { status: "terminal", outcome: { status: "completed", result: null } };
96
+ }, context);
97
+ }
98
+ },
99
+ abort: (task, runtime, context) => runtime.commit(async (tx) => {
100
+ delete (await tx.doc(ScoopWorkDoc)).waits[String(task.id)];
101
+ return { status: "terminal", outcome: { status: "aborted" } };
102
+ }, context)
103
+ });
104
+ }
105
+ function scoopTasks(lookup) {
106
+ const anchor = defineTask({
107
+ name: "slicc.scoop-anchor",
108
+ version: 1,
109
+ initial: () => ({ phase: "done" }),
110
+ phases: {
111
+ done: (_task, runtime, context) => runtime.commit(
112
+ () => ({ status: "terminal", outcome: { status: "completed", result: null } }),
113
+ context
114
+ )
115
+ },
116
+ abort: (_task, runtime, context) => runtime.commit(() => ({ status: "terminal", outcome: { status: "aborted" } }), context)
117
+ });
118
+ const reporter = defineTask({
119
+ name: "slicc.scoop-reporter",
120
+ version: 1,
121
+ initial: () => ({ phase: "deliver" }),
122
+ phases: {
123
+ async deliver(task, runtime, context) {
124
+ const { agents } = await lookup();
125
+ const record = agents.state().scoops[task.input.scoop];
126
+ const handle = record && live(record) ? await runtime.conversation(record.conversation, context) : void 0;
127
+ if (!handle) {
128
+ await runtime.commit(async (tx) => {
129
+ delete (await tx.doc(ScoopWorkDoc)).feeds[String(task.id)];
130
+ return {
131
+ status: "terminal",
132
+ outcome: {
133
+ status: "completed",
134
+ result: { text: "", failed: "the scoop is gone", path: null }
135
+ }
136
+ };
137
+ }, context);
138
+ return;
139
+ }
140
+ const requestId = task.input.request ? `subagent:${task.input.request}` : `feed:${task.id}`;
141
+ const submission = await handle.submit(
142
+ {
143
+ type: "input",
144
+ content: task.input.prompt,
145
+ whenBusy: task.input.followUp ? "followUp" : "steer",
146
+ requestId
147
+ },
148
+ context
149
+ );
150
+ const settled = await submission.wait(context);
151
+ await runtime.commit(async (tx) => {
152
+ if (settled.status !== "done" || settled.type !== "input")
153
+ return {
154
+ status: "running",
155
+ checkpoint: {
156
+ phase: "report",
157
+ text: "",
158
+ failed: String(settled.reason)
159
+ }
160
+ };
161
+ const answer = await tx.entry(AssistantEntry, settled.answer);
162
+ return {
163
+ status: "running",
164
+ checkpoint: {
165
+ phase: "report",
166
+ text: answerText(answer?.model?.[0]?.content),
167
+ failed: null
168
+ }
169
+ };
170
+ }, context);
171
+ },
172
+ async report(task, runtime, context) {
173
+ const { agents, licks } = await lookup();
174
+ const id = task.input.scoop;
175
+ const record = agents.state().scoops[id];
176
+ const { text, failed } = task.state.checkpoint;
177
+ const path = record && text ? `${SCOOPS_ROOT}/${record.folder}/reports/${task.id}.md` : null;
178
+ if (path)
179
+ await (await runtime.env(context))?.writeFile(
180
+ path,
181
+ text.endsWith("\n") ? text : `${text}
182
+ `,
183
+ context
184
+ );
185
+ const work = await runtime.snapshot(ScoopWorkDoc, context);
186
+ const entry = work?.feeds[String(task.id)];
187
+ const waiting = (wait) => wait.scoops.includes(id) && !(id in wait.done);
188
+ const folded = Object.values(work?.waits ?? {}).some(waiting);
189
+ const route = { target: entry.target, channel: entry.channel };
190
+ if (!folded && record && entry.report && failed !== "aborted")
191
+ await licks.deliver(
192
+ {
193
+ ...reportLick(record, id, { text, failed, path }, route),
194
+ eventId: `report:${task.id}`
195
+ },
196
+ context
197
+ );
198
+ await runtime.commit(async (tx) => {
199
+ const work2 = await tx.doc(ScoopWorkDoc);
200
+ for (const wait of Object.values(work2.waits))
201
+ if (waiting(wait))
202
+ wait.done[id] = failed ? `stopped: ${failed}` : `${path ? `Output: ${path}
203
+ ` : ""}${text || "(no text)"}`;
204
+ delete work2.feeds[String(task.id)];
205
+ return {
206
+ status: "terminal",
207
+ outcome: { status: "completed", result: { text, failed, path } }
208
+ };
209
+ }, context);
210
+ }
211
+ },
212
+ abort: (task, runtime, context) => runtime.commit(async (tx) => {
213
+ delete (await tx.doc(ScoopWorkDoc)).feeds[String(task.id)];
214
+ return { status: "terminal", outcome: { status: "aborted" } };
215
+ }, context)
216
+ });
217
+ return { anchor, reporter, wait: waitTask(lookup) };
218
+ }
219
+ async function whose(input, context) {
220
+ const state = await input.read.snapshot(AgentsDoc, context);
221
+ const scoop = Object.values(state?.scoops ?? {}).find(
222
+ (record) => record.conversation === input.conversationId
223
+ );
224
+ const cone = Object.values(state?.cones ?? {}).some(
225
+ (record) => record.conversation === input.conversationId
226
+ );
227
+ return { scoop, cone };
228
+ }
229
+ function rolesSection(roles) {
230
+ const shown = roles.slice(0, ADVERTISED);
231
+ return [
232
+ "Roles for `subagent spawn --agent <role>`:",
233
+ ...shown.map(
234
+ (role) => `- ${role.name}${role.aliases.length ? ` (also ${role.aliases.join(", ")})` : ""}: ${role.description}`
235
+ ),
236
+ ...roles.length > shown.length ? [`\u2026 and ${roles.length - shown.length} more; \`subagent list --agents\` shows them all.`] : []
237
+ ].join("\n");
238
+ }
239
+ function scoopsExtension(tasks, sections) {
240
+ return defineExtension({
241
+ name: "slicc-scoops",
242
+ tasks: [tasks.anchor, tasks.reporter, tasks.wait],
243
+ sections: [
244
+ section("scoop", async (input, context) => {
245
+ const { scoop } = await whose(input, context);
246
+ return scoop ? scoopFacts(scoop) : void 0;
247
+ }),
248
+ section("subagent", async (input, context) => {
249
+ const { cone } = await whose(input, context);
250
+ if (!cone) return void 0;
251
+ return [sections.skill(), rolesSection(sections.roles())].filter(Boolean).join("\n\n");
252
+ })
253
+ ]
254
+ });
255
+ }
256
+ const WRITES = /* @__PURE__ */ new Set(["write", "edit"]);
257
+ function allowed(record, coneCwd, path, writing) {
258
+ const own = `${SCOOPS_ROOT}/${record.folder}`;
259
+ const write = [own, "/tmp", ...record.roots?.write ?? []];
260
+ const roots = writing ? write : [...write, coneCwd, ...record.roots?.read ?? []];
261
+ return roots.some((root) => path === root || path.startsWith(`${root === "/" ? "" : root}/`));
262
+ }
263
+ function refusal(value) {
264
+ return { content: [{ type: "text", text: value }], isError: true };
265
+ }
266
+ function guardExtension(lookup, tools) {
267
+ const wraps = tools.filter((tool) => tool.name === "read" || WRITES.has(tool.name)).map(
268
+ (tool) => wrapTool(tool, (inner) => ({
269
+ ...inner,
270
+ async execute(args, api, context) {
271
+ const { agents } = await lookup();
272
+ const record = Object.values(agents.state().scoops).find(
273
+ (scoop) => scoop.conversation === api.conversationId
274
+ );
275
+ if (!record) return inner.execute(args, api, context);
276
+ const path = String(args.path);
277
+ let target = normalize(resolve(workspace(record.folder), path));
278
+ const canonical = await api.env?.canonicalPath(target, context);
279
+ if (canonical?.ok) target = canonical.value;
280
+ if (allowed(record, HOME, target, WRITES.has(inner.name)))
281
+ return inner.execute(args, api, context);
282
+ return refusal(
283
+ `${target} is outside this scoop's folders. ${inner.name} reaches ${SCOOPS_ROOT}/${record.folder} and /tmp${WRITES.has(inner.name) ? "" : `, and reads ${HOME}`}.`
284
+ );
285
+ }
286
+ }))
287
+ );
288
+ return defineExtension({ name: "slicc-scoop-guard", wraps });
289
+ }
290
+ export {
291
+ PREVIEW,
292
+ allowed,
293
+ guardExtension,
294
+ reportLick,
295
+ rolesSection,
296
+ scoopFacts,
297
+ scoopTasks,
298
+ scoopsExtension,
299
+ waitTask
300
+ };
301
+ //# sourceMappingURL=extension.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../src/scoops/extension.ts"],
4
+ "sourcesContent": ["import type { Context } from '@earendil-works/chord';\nimport {\n AssistantEntry,\n type ConversationId,\n defineExtension,\n defineTask,\n type Extension,\n type PromptInput,\n section,\n type ToolRegistration,\n wrapTool,\n} from '@earendil-works/pi-durable';\nimport { answerText } from '../agent.ts';\nimport { AgentsDoc, live, type ScoopRecord } from '../agents.ts';\nimport { HOME } from '../kernel/env.ts';\nimport { normalize, resolve } from '../kernel/paths.ts';\nimport type { LickEvent } from '../licks/licks.ts';\nimport type { Role } from '../roles/roles.ts';\nimport { type Feed, SCOOPS_ROOT, type ScoopsHost, ScoopWorkDoc, workspace } from './service.ts';\n\nexport const PREVIEW = 1000;\nconst ADVERTISED = 16;\n\ntype Lookup = () => Promise<ScoopsHost>;\n\nexport function scoopFacts(record: Pick<ScoopRecord, 'name' | 'folder' | 'role'>): string {\n return [\n `You are the scoop \"${record.name}\"${record.role ? ` (role: ${record.role})` : ''}, a helper agent working for a cone. Messages come from the cone or from the user at a terminal; your final answer goes back to whoever asked, so end every task with a complete answer.`,\n `Work in ${workspace(record.folder)}. Your read, write and edit tools only reach ${SCOOPS_ROOT}/${record.folder} and /tmp, and read ${HOME}.`,\n 'Your bash is not confined: it sees the whole file system and every process. Stay in your folder anyway, and change nothing outside it unless the request says so.',\n 'You may run `agent` synchronously for a bounded side task (calls nest at most three deep), but you cannot start asynchronous scoops (`agent --async`, `subagent spawn`).',\n ].join('\\n');\n}\n\nfunction lines(text: string): number {\n return text ? text.split('\\n').length : 0;\n}\n\nexport type ReportResult = { text: string; failed: string | null; path: string | null };\n\nexport function reportLick(\n record: ScoopRecord,\n id: string,\n report: ReportResult,\n route: { target?: string | null; channel?: 'scoop-notify' | 'bash' } = {}\n): LickEvent {\n const status = report.failed ? (report.failed === 'aborted' ? 'stopped' : 'failed') : 'completed';\n const label = `${record.name} (${record.role ?? 'scoop'})`;\n const preview = report.text.length > PREVIEW ? `${report.text.slice(0, PREVIEW)}\u2026` : report.text;\n const where = report.path ? `Output: ${report.path} (${lines(report.text)} lines)` : null;\n const reason = report.failed && report.failed !== 'aborted' ? `Reason: ${report.failed}` : null;\n return {\n channel: route.channel ?? 'scoop-notify',\n source: id,\n title: label,\n text: `[scoop ${record.name} (${record.role ?? 'scoop'}) ${status}]`,\n body: [where, reason, preview].filter(Boolean).join('\\n\\n'),\n target: (route.target ?? `cone:${record.cone}`) as LickEvent['target'],\n ...(report.failed && report.failed !== 'aborted' ? { severity: 'warn' as const } : {}),\n };\n}\n\nexport function waitTask(lookup: Lookup) {\n type WaitInput = { scoops: string[]; cone: string; deadline: number };\n\n return defineTask<WaitInput, { phase: 'start' } | { phase: 'watch' }, null>({\n name: 'slicc.scoop-wait',\n version: 1,\n initial: () => ({ phase: 'start' }),\n phases: {\n async start(task, runtime, context) {\n await runtime.commit(async (tx) => {\n (await tx.doc(ScoopWorkDoc)).waits[String(task.id)] = {\n scoops: task.input.scoops,\n done: {},\n cone: task.input.cone,\n };\n return { status: 'running', checkpoint: { phase: 'watch' } };\n }, context);\n },\n async watch(task, runtime, context) {\n const { agents, licks } = await lookup();\n const key = String(task.id);\n for (;;) {\n const work = await runtime.snapshot(ScoopWorkDoc, context);\n const state = work?.waits[key];\n if (!state) break;\n const feeding = new Set(Object.values(work?.feeds ?? {}).map((feed) => feed.scoop));\n const open = state.scoops.filter((id) => !(id in state.done) && feeding.has(id));\n const expired = runtime.now() >= task.input.deadline;\n if (open.length && !expired) {\n await runtime.sleep(Math.min(runtime.now() + 300, task.input.deadline), context);\n continue;\n }\n const names = (id: string) => agents.state().scoops[id]?.name ?? id;\n const body = state.scoops.map((id) =>\n open.includes(id)\n ? `## ${names(id)}\\n(still working when the wait timed out)`\n : `## ${names(id)}\\n${state.done[id] ?? '(nothing was running)'}`\n );\n await licks.deliver(\n {\n channel: 'scoop-wait',\n source: key,\n title: `Waited for ${state.scoops.map(names).join(', ')}`,\n text: open.length\n ? `${state.scoops.length - open.length} of ${state.scoops.length} done; timed out waiting for ${open.map(names).join(', ')}`\n : `All ${state.scoops.length} done`,\n body: body.join('\\n\\n'),\n target: `cone:${state.cone}`,\n coalesce: false,\n eventId: `wait:${key}`,\n },\n context\n );\n break;\n }\n await runtime.commit(async (tx) => {\n delete (await tx.doc(ScoopWorkDoc)).waits[key];\n return { status: 'terminal', outcome: { status: 'completed', result: null } };\n }, context);\n },\n },\n abort: (task, runtime, context) =>\n runtime.commit(async (tx) => {\n delete (await tx.doc(ScoopWorkDoc)).waits[String(task.id)];\n return { status: 'terminal', outcome: { status: 'aborted' } };\n }, context),\n });\n}\n\nexport function scoopTasks(lookup: Lookup) {\n const anchor = defineTask<null, { phase: 'done' }, null>({\n name: 'slicc.scoop-anchor',\n version: 1,\n initial: () => ({ phase: 'done' }),\n phases: {\n done: (_task, runtime, context) =>\n runtime.commit(\n () => ({ status: 'terminal', outcome: { status: 'completed', result: null } }),\n context\n ),\n },\n abort: (_task, runtime, context) =>\n runtime.commit(() => ({ status: 'terminal', outcome: { status: 'aborted' } }), context),\n });\n\n type ReporterInput = {\n scoop: string;\n prompt: string;\n followUp?: boolean;\n request?: string;\n };\n type ReporterState =\n | { phase: 'deliver' }\n | { phase: 'report'; text: string; failed: string | null };\n\n const reporter = defineTask<ReporterInput, ReporterState, ReportResult>({\n name: 'slicc.scoop-reporter',\n version: 1,\n initial: () => ({ phase: 'deliver' }),\n phases: {\n async deliver(task, runtime, context) {\n const { agents } = await lookup();\n const record = agents.state().scoops[task.input.scoop];\n const handle =\n record && live(record)\n ? await runtime.conversation(record.conversation as ConversationId, context)\n : undefined;\n if (!handle) {\n await runtime.commit(async (tx) => {\n delete (await tx.doc(ScoopWorkDoc)).feeds[String(task.id)];\n return {\n status: 'terminal',\n outcome: {\n status: 'completed',\n result: { text: '', failed: 'the scoop is gone', path: null },\n },\n };\n }, context);\n return;\n }\n const requestId = task.input.request ? `subagent:${task.input.request}` : `feed:${task.id}`;\n const submission = await handle.submit(\n {\n type: 'input',\n content: task.input.prompt,\n whenBusy: task.input.followUp ? 'followUp' : 'steer',\n requestId,\n },\n context\n );\n const settled = await submission.wait(context);\n await runtime.commit(async (tx) => {\n if (settled.status !== 'done' || settled.type !== 'input')\n return {\n status: 'running',\n checkpoint: {\n phase: 'report',\n text: '',\n failed: String(settled.reason),\n },\n };\n const answer = await tx.entry(AssistantEntry, settled.answer);\n return {\n status: 'running',\n checkpoint: {\n phase: 'report',\n text: answerText(answer?.model?.[0]?.content),\n failed: null,\n },\n };\n }, context);\n },\n async report(task, runtime, context) {\n const { agents, licks } = await lookup();\n const id = task.input.scoop;\n const record = agents.state().scoops[id];\n const { text, failed } = task.state.checkpoint;\n const path =\n record && text ? `${SCOOPS_ROOT}/${record.folder}/reports/${task.id}.md` : null;\n if (path)\n await (await runtime.env(context))?.writeFile(\n path,\n text.endsWith('\\n') ? text : `${text}\\n`,\n context\n );\n const work = await runtime.snapshot(ScoopWorkDoc, context);\n const entry = work?.feeds[String(task.id)] as Feed;\n const waiting = (wait: { scoops: string[]; done: Record<string, string> }) =>\n wait.scoops.includes(id) && !(id in wait.done);\n const folded = Object.values(work?.waits ?? {}).some(waiting);\n const route = { target: entry.target, channel: entry.channel };\n if (!folded && record && entry.report && failed !== 'aborted')\n await licks.deliver(\n {\n ...reportLick(record, id, { text, failed, path }, route),\n eventId: `report:${task.id}`,\n },\n context\n );\n await runtime.commit(async (tx) => {\n const work = await tx.doc(ScoopWorkDoc);\n for (const wait of Object.values(work.waits))\n if (waiting(wait))\n wait.done[id] = failed\n ? `stopped: ${failed}`\n : `${path ? `Output: ${path}\\n` : ''}${text || '(no text)'}`;\n delete work.feeds[String(task.id)];\n return {\n status: 'terminal',\n outcome: { status: 'completed', result: { text, failed, path } },\n };\n }, context);\n },\n },\n abort: (task, runtime, context) =>\n runtime.commit(async (tx) => {\n delete (await tx.doc(ScoopWorkDoc)).feeds[String(task.id)];\n return { status: 'terminal', outcome: { status: 'aborted' } };\n }, context),\n });\n\n return { anchor, reporter, wait: waitTask(lookup) };\n}\n\nasync function whose(input: PromptInput, context: Context) {\n const state = await input.read.snapshot(AgentsDoc, context);\n const scoop = Object.values(state?.scoops ?? {}).find(\n (record) => record.conversation === input.conversationId\n );\n const cone = Object.values(state?.cones ?? {}).some(\n (record) => record.conversation === input.conversationId\n );\n return { scoop, cone };\n}\n\nexport function rolesSection(roles: readonly Role[]): string {\n const shown = roles.slice(0, ADVERTISED);\n return [\n 'Roles for `subagent spawn --agent <role>`:',\n ...shown.map(\n (role) =>\n `- ${role.name}${role.aliases.length ? ` (also ${role.aliases.join(', ')})` : ''}: ${role.description}`\n ),\n ...(roles.length > shown.length\n ? [`\u2026 and ${roles.length - shown.length} more; \\`subagent list --agents\\` shows them all.`]\n : []),\n ].join('\\n');\n}\n\nexport interface ScoopSections {\n roles(): readonly Role[];\n skill(): string;\n}\n\nexport function scoopsExtension(\n tasks: ReturnType<typeof scoopTasks>,\n sections: ScoopSections\n): Extension {\n return defineExtension({\n name: 'slicc-scoops',\n tasks: [tasks.anchor, tasks.reporter, tasks.wait],\n sections: [\n section('scoop', async (input, context) => {\n const { scoop } = await whose(input, context);\n return scoop ? scoopFacts(scoop) : undefined;\n }),\n section('subagent', async (input, context) => {\n const { cone } = await whose(input, context);\n if (!cone) return undefined;\n return [sections.skill(), rolesSection(sections.roles())].filter(Boolean).join('\\n\\n');\n }),\n ],\n });\n}\n\nconst WRITES = new Set(['write', 'edit']);\n\nexport function allowed(\n record: Pick<ScoopRecord, 'folder'> & { roots?: ScoopRecord['roots'] },\n coneCwd: string,\n path: string,\n writing: boolean\n): boolean {\n const own = `${SCOOPS_ROOT}/${record.folder}`;\n const write = [own, '/tmp', ...(record.roots?.write ?? [])];\n const roots = writing ? write : [...write, coneCwd, ...(record.roots?.read ?? [])];\n return roots.some((root) => path === root || path.startsWith(`${root === '/' ? '' : root}/`));\n}\n\nfunction refusal(value: string) {\n return { content: [{ type: 'text' as const, text: value }], isError: true };\n}\n\nexport function guardExtension(lookup: Lookup, tools: readonly ToolRegistration[]): Extension {\n const wraps = tools\n .filter((tool) => tool.name === 'read' || WRITES.has(tool.name))\n .map((tool) =>\n wrapTool(tool, (inner) => ({\n ...inner,\n async execute(args, api, context) {\n const { agents } = await lookup();\n const record = Object.values(agents.state().scoops).find(\n (scoop) => scoop.conversation === api.conversationId\n );\n if (!record) return inner.execute(args, api, context);\n const path = String((args as { path: unknown }).path);\n let target = normalize(resolve(workspace(record.folder), path));\n const canonical = await api.env?.canonicalPath(target, context);\n if (canonical?.ok) target = canonical.value;\n if (allowed(record, HOME, target, WRITES.has(inner.name)))\n return inner.execute(args, api, context);\n return refusal(\n `${target} is outside this scoop's folders. ${inner.name} reaches ${SCOOPS_ROOT}/${record.folder} and /tmp${WRITES.has(inner.name) ? '' : `, and reads ${HOME}`}.`\n );\n },\n }))\n );\n return defineExtension({ name: 'slicc-scoop-guard', wraps });\n}\n"],
5
+ "mappings": "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",
6
+ "names": ["work"]
7
+ }
@@ -0,0 +1,33 @@
1
+ import {
2
+ AgentDoc
3
+ } from "@earendil-works/pi-durable";
4
+ function callerOf(agents, conversation) {
5
+ if (!agents || conversation === void 0) return void 0;
6
+ const state = agents.state();
7
+ const cone = Object.entries(state.cones).find(
8
+ ([, record]) => record.conversation === conversation
9
+ )?.[0];
10
+ if (cone) return `cone:${cone}`;
11
+ return Object.entries(state.scoops).find(
12
+ ([, record]) => record.conversation === conversation
13
+ )?.[0];
14
+ }
15
+ function identity(agents, fallback) {
16
+ return async (target, context) => {
17
+ const out = {};
18
+ const caller = callerOf(agents(), target.conversationId);
19
+ if (caller) out.SLICC_AGENT = caller;
20
+ const read = target.read;
21
+ const stored = read && target.conversationId !== void 0 ? await read.snapshot(AgentDoc, target.conversationId, context) : void 0;
22
+ const model = stored?.model ?? fallback;
23
+ out.PI_PROVIDER = model.provider;
24
+ out.PI_MODEL = model.modelId;
25
+ out.PI_REASONING_LEVEL = stored?.thinkingLevel ?? "off";
26
+ return out;
27
+ };
28
+ }
29
+ export {
30
+ callerOf,
31
+ identity
32
+ };
33
+ //# sourceMappingURL=identity.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../src/scoops/identity.ts"],
4
+ "sourcesContent": ["import type { Context } from '@earendil-works/chord';\nimport {\n AgentDoc,\n type ConversationId,\n type DocumentReader,\n type ModelRef,\n} from '@earendil-works/pi-durable';\nimport type { Agents } from '../agents.ts';\nimport type { EnvTargetLike } from '../kernel/env.ts';\n\nexport function callerOf(\n agents: Agents | undefined,\n conversation: number | undefined\n): string | undefined {\n if (!agents || conversation === undefined) return undefined;\n const state = agents.state();\n const cone = Object.entries(state.cones).find(\n ([, record]) => record.conversation === conversation\n )?.[0];\n if (cone) return `cone:${cone}`;\n return Object.entries(state.scoops).find(\n ([, record]) => record.conversation === conversation\n )?.[0];\n}\n\nexport function identity(agents: () => Agents | undefined, fallback: ModelRef) {\n return async (target: EnvTargetLike, context: Context): Promise<Record<string, string>> => {\n const out: Record<string, string> = {};\n const caller = callerOf(agents(), target.conversationId);\n if (caller) out.SLICC_AGENT = caller;\n const read = target.read as DocumentReader | undefined;\n const stored =\n read && target.conversationId !== undefined\n ? await read.snapshot(AgentDoc, target.conversationId as ConversationId, context)\n : undefined;\n const model = stored?.model ?? fallback;\n out.PI_PROVIDER = model.provider;\n out.PI_MODEL = model.modelId;\n out.PI_REASONING_LEVEL = stored?.thinkingLevel ?? 'off';\n return out;\n };\n}\n"],
5
+ "mappings": "AACA;AAAA,EACE;AAAA,OAIK;AAIA,SAAS,SACd,QACA,cACoB;AACpB,MAAI,CAAC,UAAU,iBAAiB,OAAW,QAAO;AAClD,QAAM,QAAQ,OAAO,MAAM;AAC3B,QAAM,OAAO,OAAO,QAAQ,MAAM,KAAK,EAAE;AAAA,IACvC,CAAC,CAAC,EAAE,MAAM,MAAM,OAAO,iBAAiB;AAAA,EAC1C,IAAI,CAAC;AACL,MAAI,KAAM,QAAO,QAAQ,IAAI;AAC7B,SAAO,OAAO,QAAQ,MAAM,MAAM,EAAE;AAAA,IAClC,CAAC,CAAC,EAAE,MAAM,MAAM,OAAO,iBAAiB;AAAA,EAC1C,IAAI,CAAC;AACP;AAEO,SAAS,SAAS,QAAkC,UAAoB;AAC7E,SAAO,OAAO,QAAuB,YAAsD;AACzF,UAAM,MAA8B,CAAC;AACrC,UAAM,SAAS,SAAS,OAAO,GAAG,OAAO,cAAc;AACvD,QAAI,OAAQ,KAAI,cAAc;AAC9B,UAAM,OAAO,OAAO;AACpB,UAAM,SACJ,QAAQ,OAAO,mBAAmB,SAC9B,MAAM,KAAK,SAAS,UAAU,OAAO,gBAAkC,OAAO,IAC9E;AACN,UAAM,QAAQ,QAAQ,SAAS;AAC/B,QAAI,cAAc,MAAM;AACxB,QAAI,WAAW,MAAM;AACrB,QAAI,qBAAqB,QAAQ,iBAAiB;AAClD,WAAO;AAAA,EACT;AACF;",
6
+ "names": []
7
+ }
@@ -0,0 +1,120 @@
1
+ import { live } from "../agents.js";
2
+ import { DEFAULT_LIMITS, loadRoles, packageDirs } from "../roles/roles.js";
3
+ import { createCli, RUN_DIR } from "./cli.js";
4
+ import { guardExtension, scoopsExtension, scoopTasks } from "./extension.js";
5
+ import { controlPlane } from "./requests.js";
6
+ import { createScoops } from "./service.js";
7
+ const BUILTIN_ROLES = ["scout", "worker", "reviewer", "oracle", "delegate"];
8
+ const PNPM_HOME = "/home/.local/share/pnpm";
9
+ function packageAssets(base = new URL("../../", import.meta.url)) {
10
+ return async (path) => {
11
+ const response = await fetch(new URL(path, base));
12
+ if (!response.ok) throw new Error(`${path}: ${response.status}`);
13
+ return response.text();
14
+ };
15
+ }
16
+ const COMMANDS = ["agent", "subagent"];
17
+ async function install(env, script, pnpmHome, context) {
18
+ await env.createDir(`${pnpmHome}/bin`, { recursive: true }, context);
19
+ for (const name of COMMANDS) {
20
+ const path = `${pnpmHome}/bin/${name}`;
21
+ await env.writeFile(path, script, context);
22
+ await env.exec(["chmod", "+x", path], void 0, context);
23
+ }
24
+ }
25
+ function mirror(agents, env) {
26
+ return async (context) => {
27
+ for (const [id, record] of Object.entries(agents.state().scoops)) {
28
+ const state = record.gone ? "gone" : live(record) ? "live" : "stopped";
29
+ const metadata = {
30
+ handle: record.folder,
31
+ id,
32
+ name: record.name,
33
+ role: record.role,
34
+ cone: record.cone,
35
+ state
36
+ };
37
+ await env.writeFile(
38
+ `${RUN_DIR}/${record.folder}/metadata.json`,
39
+ `${JSON.stringify(metadata, null, 2)}
40
+ `,
41
+ context
42
+ );
43
+ }
44
+ };
45
+ }
46
+ function setupScoops(registry, licks, fileTools = []) {
47
+ let bind = () => void 0;
48
+ const host = new Promise((resolve) => {
49
+ bind = resolve;
50
+ });
51
+ const lookup = () => host;
52
+ const tasks = scoopTasks(lookup);
53
+ const scoops = createScoops(host, () => tasks);
54
+ let cached = { roles: [], warnings: [], limits: { ...DEFAULT_LIMITS } };
55
+ let skill = "";
56
+ registry.install(scoopsExtension(tasks, { roles: () => cached.roles, skill: () => skill }));
57
+ registry.install(guardExtension(lookup, fileTools));
58
+ return {
59
+ scoops,
60
+ async attach(options, context) {
61
+ const { harness, agents, groups, env, home } = options;
62
+ const assets = options.assets ?? packageAssets();
63
+ bind({ harness, agents, licks, tools: fileTools, ...groups ? { groups } : {} });
64
+ const builtin = async () => {
65
+ const out = [];
66
+ for (const name of BUILTIN_ROLES) {
67
+ const path = `packages/vfs-root/agents/${name}.md`;
68
+ out.push({ path: `builtin:${name}`, text: await assets(path) });
69
+ }
70
+ return out;
71
+ };
72
+ const roles = async (using) => {
73
+ cached = await loadRoles(
74
+ {
75
+ files: env,
76
+ builtin,
77
+ dirs: [
78
+ ...(await packageDirs(env, "/node_modules", using)).map((dir) => ({
79
+ source: "package",
80
+ dir
81
+ })),
82
+ { source: "user", dir: `${home}/.pi/agent/agents` }
83
+ ],
84
+ settingsPath: `${home}/.pi/agent/settings.json`
85
+ },
86
+ using
87
+ );
88
+ return cached;
89
+ };
90
+ skill = (await assets("packages/vfs-root/skills/agent/SKILL.md").catch(() => "")).replace(/^---[\s\S]*?---\n/, "").trim();
91
+ await roles(context).catch(() => cached);
92
+ const script = await assets("bin/agent").catch(() => void 0);
93
+ if (script)
94
+ await install(env, script, options.pnpmHome ?? PNPM_HOME, context).catch(() => void 0);
95
+ const cli = createCli({
96
+ env,
97
+ harness,
98
+ agents,
99
+ scoops,
100
+ roles: () => roles(context),
101
+ ...options.alive ? { alive: options.alive } : {}
102
+ });
103
+ const plane = controlPlane(env, cli, {
104
+ ...options.controlDir ? { dir: options.controlDir } : {},
105
+ ...options.sweepEvery ? { sweepEvery: options.sweepEvery } : {},
106
+ mirror: mirror(agents, env)
107
+ });
108
+ await plane.start(context);
109
+ return { roles, plane, close: (using) => plane.close(using) };
110
+ }
111
+ };
112
+ }
113
+ export {
114
+ BUILTIN_ROLES,
115
+ COMMANDS,
116
+ PNPM_HOME,
117
+ packageAssets,
118
+ setupScoops
119
+ };
120
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 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 { 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}\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'];\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 let skill = '';\n registry.install(scoopsExtension(tasks, { roles: () => cached.roles, skill: () => skill }));\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({ harness, agents, licks, tools: fileTools, ...(groups ? { groups } : {}) });\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 skill = (await assets('packages/vfs-root/skills/agent/SKILL.md').catch(() => ''))\n .replace(/^---[\\s\\S]*?---\\n/, '')\n .trim();\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 });\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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",
6
+ "names": []
7
+ }