@ai-ecoverse/slicc-agent 6.0.12 → 6.1.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.
@@ -1,7 +1,12 @@
1
1
  import { ROOT_USER } from "../layout.js";
2
2
  import { bootLicks, LicksHostDoc } from "./boot.js";
3
3
  import { parseWebhook } from "./config.js";
4
- import { installJobs, legacyJobs, sendCommand } from "./crontab.js";
4
+ import {
5
+ installJobs,
6
+ legacyJobs,
7
+ relickJobs,
8
+ sendCommand
9
+ } from "./crontab.js";
5
10
  import { configFiles, Watches } from "./fswatch.js";
6
11
  const SLICC_DIR = ".slicc";
7
12
  function scopedTarget(target, cone) {
@@ -30,13 +35,14 @@ function configLick(error, home, cone = null) {
30
35
  source: `config:${file}`,
31
36
  title: `Invalid ${file}`,
32
37
  text,
33
- body: channel === "cron" ? "Not moved into the kernel crontab until the file is fixed; the installed crontab is unchanged.\nThe format is in the slicc-agent README." : "Ignored until the file is fixed.\nThe formats are in the slicc-agent README.",
38
+ body: error.file.endsWith("/crontab.migrated") ? "Its jobs in the kernel crontab still lack --lick=cron, so they don't fire as cron licks; add it with crontab -." : channel === "cron" ? "Not moved into the kernel crontab until the file is fixed; the installed crontab is unchanged.\nThe format is in the slicc-agent README." : "Ignored until the file is fixed.\nThe formats are in the slicc-agent README.",
34
39
  target: scopedTarget("cone", cone),
35
40
  severity: "error",
36
41
  eventId: hash(`${file}
37
42
  ${text}`)
38
43
  };
39
44
  }
45
+ const UNVERIFIED = "verified: false (the gateway couldn't check this request's signature)";
40
46
  function webhookLick(name, entry, delivery) {
41
47
  const payload = typeof delivery.body === "string" ? delivery.body : JSON.stringify(delivery.body, null, 2);
42
48
  const headers = Object.entries(delivery.headers ?? {}).map(([key, value]) => `${key}: ${value}`).join("\n");
@@ -45,7 +51,7 @@ function webhookLick(name, entry, delivery) {
45
51
  source: name,
46
52
  title: name,
47
53
  text: entry.message || `Webhook ${name} received a request`,
48
- body: [headers, payload].filter(Boolean).join("\n\n"),
54
+ body: [delivery.verified === false ? UNVERIFIED : "", headers, payload].filter(Boolean).join("\n\n"),
49
55
  target: entry.target,
50
56
  coalesce: false,
51
57
  ...delivery.id ? { eventId: delivery.id } : {},
@@ -84,6 +90,7 @@ function createLickSources(options) {
84
90
  return found;
85
91
  };
86
92
  let webhooks = /* @__PURE__ */ new Map();
93
+ const relicked = /* @__PURE__ */ new Set();
87
94
  let control;
88
95
  let controlled = "";
89
96
  let reconcileTimer;
@@ -101,7 +108,7 @@ function createLickSources(options) {
101
108
  const errors = [];
102
109
  const hooks = /* @__PURE__ */ new Map();
103
110
  for (const place of places) {
104
- const crontab = await migrate(place, context);
111
+ const crontab = [...await relick(place, context), ...await migrate(place, context)];
105
112
  const watchErrors = await watchesOf(place).reconcile(`${place.dir}/watches`, context);
106
113
  const found = await webhooksIn(files, `${place.dir}/webhooks`, context);
107
114
  for (const entry of found.entries.values()) {
@@ -121,21 +128,43 @@ function createLickSources(options) {
121
128
  await deliver(configLick(error, place.home, place.cone), context);
122
129
  await watchControl(places, context);
123
130
  }
131
+ function byUser(place, jobs) {
132
+ const users = /* @__PURE__ */ new Map();
133
+ for (const job of jobs) {
134
+ const user = options.cronUser?.(job.target, place) ?? place.cone ?? ROOT_USER;
135
+ users.set(user, [...users.get(user) ?? [], job]);
136
+ }
137
+ return users;
138
+ }
139
+ async function relick(place, context) {
140
+ if (relicked.has(place.dir)) return [];
141
+ relicked.add(place.dir);
142
+ const file = `${place.dir}/crontab.migrated`;
143
+ const text = await files.read(file, context);
144
+ if (text === void 0) return [];
145
+ const errors = [];
146
+ for (const [user, list] of byUser(place, legacyJobs(text).jobs))
147
+ for (const problem of await relickJobs(env, user, list, context))
148
+ errors.push({ file, ...problem });
149
+ return errors;
150
+ }
124
151
  async function migrate(place, context) {
125
152
  const file = `${place.dir}/crontab`;
126
153
  const text = await files.read(file, context);
127
- if (text === void 0) return [];
154
+ if (!text?.trim()) return [];
128
155
  const { jobs, problems } = legacyJobs(text);
129
156
  if (problems.length) return problems.map((problem) => ({ file, ...problem }));
130
157
  const users = /* @__PURE__ */ new Map();
131
- for (const job of jobs) {
132
- const user = options.cronUser?.(job.target, place) ?? place.cone ?? ROOT_USER;
133
- const command = sendCommand(job.target, job.message);
134
- users.set(user, [
135
- ...users.get(user) ?? [],
136
- { name: job.name, schedule: job.schedule, command, line: job.line }
137
- ]);
138
- }
158
+ for (const [user, list] of byUser(place, jobs))
159
+ users.set(
160
+ user,
161
+ list.map((job) => ({
162
+ name: job.name,
163
+ schedule: job.schedule,
164
+ command: sendCommand(job.target, job.message),
165
+ line: job.line
166
+ }))
167
+ );
139
168
  const errors = [];
140
169
  for (const [user, list] of users)
141
170
  for (const problem of await installJobs(env, user, list, context))
@@ -205,6 +234,7 @@ function createLickSources(options) {
205
234
  }
206
235
  export {
207
236
  SLICC_DIR,
237
+ UNVERIFIED,
208
238
  configLick,
209
239
  createLickSources,
210
240
  hash,
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../src/licks/sources.ts"],
4
- "sourcesContent": ["import type { Context } from '@earendil-works/chord';\nimport type { Conversation, Harness, TaskId } from '@earendil-works/pi-durable';\nimport type { ExecutionEnv, FileWatcher } from '@earendil-works/pi-durable/env';\nimport type { Activity } from '../kernel/activity.ts';\nimport { ROOT_USER } from '../layout.ts';\nimport { type BootFacts, bootLicks, LicksHostDoc } from './boot.ts';\nimport { type ConfigError, parseWebhook, type WebhookEntry } from './config.ts';\nimport { type CronJob, installJobs, legacyJobs, sendCommand } from './crontab.ts';\nimport { type ConfigFiles, configFiles, Watches } from './fswatch.ts';\nimport type { LickChannel, LickTarget } from './lick.ts';\nimport type { LickEvent, Licks } from './licks.ts';\n\nexport const SLICC_DIR = '.slicc';\n\nexport interface LickSourcesOptions {\n harness: Harness;\n root: Conversation;\n cone: () => Conversation;\n env: ExecutionEnv;\n home: string;\n licks: Licks;\n flushEvery?: number;\n activity?: Activity;\n dirs?: () => readonly LickDir[] | Promise<readonly LickDir[]>;\n cronUser?: (target: LickTarget, place: LickDir) => string | undefined;\n}\n\nexport interface LickDir {\n dir: string;\n home: string;\n cone: string | null;\n env?: ExecutionEnv;\n}\n\nexport function scopedTarget(target: LickTarget, cone: string | null): LickTarget {\n return cone && target === 'cone' ? (`cone:${cone}` as LickTarget) : target;\n}\n\nexport function scopedName(name: string, cone: string | null): string {\n return cone ? `${cone}:${name}` : name;\n}\n\nfunction scoped<T extends { name: string; target: LickTarget }>(entry: T, cone: string | null): T {\n return { ...entry, name: scopedName(entry.name, cone), target: scopedTarget(entry.target, cone) };\n}\n\nexport interface WebhookDelivery {\n id?: string;\n headers?: Record<string, string>;\n body: unknown;\n}\n\nexport interface LickSources {\n start(context: Context): Promise<void>;\n reconcile(context: Context): Promise<void>;\n boot(facts: BootFacts, context: Context): Promise<void>;\n webhook(name: string, delivery: WebhookDelivery, context: Context): Promise<boolean>;\n close(context: Context): Promise<void>;\n}\n\nexport function hash(text: string): string {\n let value = 2166136261;\n for (let at = 0; at < text.length; at++) value = Math.imul(value ^ text.charCodeAt(at), 16777619);\n return (value >>> 0).toString(36);\n}\n\nexport function shortPath(path: string, home: string): string {\n return path === home || path.startsWith(`${home}/`) ? `~${path.slice(home.length)}` : path;\n}\n\nexport function configLick(\n error: ConfigError,\n home: string,\n cone: string | null = null\n): LickEvent {\n const file = shortPath(error.file, home);\n const channel: LickChannel = error.file.includes('/watches/')\n ? 'fswatch'\n : error.file.includes('/webhooks/')\n ? 'webhook'\n : 'cron';\n const text = `${error.line ? `line ${error.line}: ` : ''}${error.error}`;\n return {\n channel,\n source: `config:${file}`,\n title: `Invalid ${file}`,\n text,\n body:\n channel === 'cron'\n ? 'Not moved into the kernel crontab until the file is fixed; the installed crontab is unchanged.\\nThe format is in the slicc-agent README.'\n : 'Ignored until the file is fixed.\\nThe formats are in the slicc-agent README.',\n target: scopedTarget('cone', cone),\n severity: 'error',\n eventId: hash(`${file}\\n${text}`),\n };\n}\n\nexport function webhookLick(\n name: string,\n entry: WebhookEntry,\n delivery: WebhookDelivery\n): LickEvent {\n const payload =\n typeof delivery.body === 'string' ? delivery.body : JSON.stringify(delivery.body, null, 2);\n const headers = Object.entries(delivery.headers ?? {})\n .map(([key, value]) => `${key}: ${value}`)\n .join('\\n');\n return {\n channel: 'webhook',\n source: name,\n title: name,\n text: entry.message || `Webhook ${name} received a request`,\n body: [headers, payload].filter(Boolean).join('\\n\\n'),\n target: entry.target,\n coalesce: false,\n ...(delivery.id ? { eventId: delivery.id } : {}),\n ...(entry.triage ? { triage: entry.triage } : {}),\n };\n}\n\nasync function webhooksIn(\n files: ConfigFiles,\n dir: string,\n context: Context\n): Promise<{ entries: Map<string, WebhookEntry>; errors: ConfigError[] }> {\n const errors: ConfigError[] = [];\n const into = new Map<string, WebhookEntry>();\n for (const name of await files.list(dir, context)) {\n const file = `${dir}/${name}`;\n const json = await files.read(file, context);\n if (json === undefined) continue;\n try {\n const entry = parseWebhook(file, json);\n into.set(entry.name, entry);\n } catch (error) {\n errors.push({ file, error: (error as Error).message });\n }\n }\n return { entries: into, errors };\n}\n\nexport function createLickSources(options: LickSourcesOptions): LickSources {\n const { harness, env, licks, home } = options;\n const files = configFiles(env);\n const deliver = (event: LickEvent, context: Context) => licks.deliver(event, context);\n const dirsOf = options.dirs ?? (() => [{ dir: `${home}/${SLICC_DIR}`, home, cone: null }]);\n const watching = new Map<string, Watches>();\n const watchesOf = (place: LickDir) => {\n let found = watching.get(place.dir);\n if (!found) {\n const retarget = (event: LickEvent, context: Context) =>\n deliver({ ...event, target: scopedTarget(event.target, place.cone) }, context);\n found = new Watches(place.env ?? env, retarget, place.home, options.activity);\n watching.set(place.dir, found);\n }\n return found;\n };\n let webhooks = new Map<string, WebhookEntry>();\n let control: FileWatcher | undefined;\n let controlled = '';\n let reconcileTimer: ReturnType<typeof setTimeout> | undefined;\n let flushTimer: ReturnType<typeof setInterval> | undefined;\n let closed = false;\n let lock: Promise<unknown> = Promise.resolve();\n const serial = <T>(operation: () => Promise<T>): Promise<T> => {\n const run = lock.then(operation, operation);\n lock = run.catch(() => undefined);\n return run;\n };\n\n async function reconcileNow(context: Context): Promise<void> {\n if (closed) return;\n const places = await dirsOf();\n const errors: { error: ConfigError; place: LickDir }[] = [];\n const hooks = new Map<string, WebhookEntry>();\n for (const place of places) {\n const crontab = await migrate(place, context);\n const watchErrors = await watchesOf(place).reconcile(`${place.dir}/watches`, context);\n const found = await webhooksIn(files, `${place.dir}/webhooks`, context);\n for (const entry of found.entries.values()) {\n const named = scoped(entry, place.cone);\n hooks.set(named.name, named);\n }\n for (const error of [...crontab, ...watchErrors, ...found.errors])\n errors.push({ error, place });\n }\n for (const [dir, watches] of [...watching])\n if (!places.some((place) => place.dir === dir)) {\n watching.delete(dir);\n await watches.close(context);\n }\n webhooks = hooks;\n for (const { error, place } of errors)\n await deliver(configLick(error, place.home, place.cone), context);\n await watchControl(places, context);\n }\n\n async function migrate(place: LickDir, context: Context): Promise<ConfigError[]> {\n const file = `${place.dir}/crontab`;\n const text = await files.read(file, context);\n if (text === undefined) return [];\n const { jobs, problems } = legacyJobs(text);\n if (problems.length) return problems.map((problem) => ({ file, ...problem }));\n const users = new Map<string, CronJob[]>();\n for (const job of jobs) {\n const user = options.cronUser?.(job.target, place) ?? place.cone ?? ROOT_USER;\n const command = sendCommand(job.target, job.message);\n users.set(user, [\n ...(users.get(user) ?? []),\n { name: job.name, schedule: job.schedule, command, line: job.line },\n ]);\n }\n const errors: ConfigError[] = [];\n for (const [user, list] of users)\n for (const problem of await installJobs(env, user, list, context))\n errors.push({ file, ...problem });\n if (errors.length) return errors;\n await env.writeFile(`${file}.migrated`, text, context);\n await env.remove(file, { force: true }, context);\n return [];\n }\n\n async function retire(context: Context): Promise<void> {\n const stored = (await harness.snapshot(LicksHostDoc, context))?.cron ?? {};\n const records = Object.values(stored);\n if (!records.length) return;\n for (const record of records)\n await harness.abortTask(record.task as TaskId, context).catch(() => undefined);\n await harness.commit(async (tx) => {\n (await tx.doc(LicksHostDoc)).cron = {};\n }, context);\n }\n\n async function watchControl(places: readonly LickDir[], context: Context): Promise<void> {\n const key = places.map((place) => place.dir).join('\\n');\n if (key === controlled || closed) return;\n controlled = key;\n await control?.close(context);\n const result = await env.watch(\n places.map((place) => ({ path: place.dir, recursive: true })),\n () => scheduleReconcile(context),\n context\n );\n control = result.ok ? result.value : undefined;\n }\n\n const reconcile = (context: Context) => serial(() => reconcileNow(context));\n\n function scheduleReconcile(context: Context): void {\n clearTimeout(reconcileTimer);\n reconcileTimer = setTimeout(() => {\n void reconcile(context).catch(() => undefined);\n }, 300);\n }\n\n async function flushIfWaiting(context: Context): Promise<void> {\n if (await licks.pending(context)) await licks.flush(context);\n }\n\n return {\n async start(context) {\n await licks.flush(context);\n await retire(context);\n await reconcile(context);\n flushTimer = setInterval(() => {\n void flushIfWaiting(context).catch(() => undefined);\n }, options.flushEvery ?? 2000);\n },\n reconcile,\n boot: (facts, context) => bootLicks(harness, options.cone(), deliver, facts, context),\n async webhook(name, delivery, context) {\n const entry = webhooks.get(name);\n if (!entry) return false;\n await deliver(webhookLick(name, entry, delivery), context);\n return true;\n },\n async close(context) {\n closed = true;\n clearTimeout(reconcileTimer);\n clearInterval(flushTimer);\n await control?.close(context);\n for (const watches of watching.values()) await watches.close(context);\n },\n };\n}\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["import type { Context } from '@earendil-works/chord';\nimport type { Conversation, Harness, TaskId } from '@earendil-works/pi-durable';\nimport type { ExecutionEnv, FileWatcher } from '@earendil-works/pi-durable/env';\nimport type { Activity } from '../kernel/activity.ts';\nimport { ROOT_USER } from '../layout.ts';\nimport { type BootFacts, bootLicks, LicksHostDoc } from './boot.ts';\nimport { type ConfigError, parseWebhook, type WebhookEntry } from './config.ts';\nimport {\n type CronJob,\n installJobs,\n type LegacyJob,\n legacyJobs,\n relickJobs,\n sendCommand,\n} from './crontab.ts';\nimport { type ConfigFiles, configFiles, Watches } from './fswatch.ts';\nimport type { LickChannel, LickTarget } from './lick.ts';\nimport type { LickEvent, Licks } from './licks.ts';\n\nexport const SLICC_DIR = '.slicc';\n\nexport interface LickSourcesOptions {\n harness: Harness;\n root: Conversation;\n cone: () => Conversation;\n env: ExecutionEnv;\n home: string;\n licks: Licks;\n flushEvery?: number;\n activity?: Activity;\n dirs?: () => readonly LickDir[] | Promise<readonly LickDir[]>;\n cronUser?: (target: LickTarget, place: LickDir) => string | undefined;\n}\n\nexport interface LickDir {\n dir: string;\n home: string;\n cone: string | null;\n env?: ExecutionEnv;\n}\n\nexport function scopedTarget(target: LickTarget, cone: string | null): LickTarget {\n return cone && target === 'cone' ? (`cone:${cone}` as LickTarget) : target;\n}\n\nexport function scopedName(name: string, cone: string | null): string {\n return cone ? `${cone}:${name}` : name;\n}\n\nfunction scoped<T extends { name: string; target: LickTarget }>(entry: T, cone: string | null): T {\n return { ...entry, name: scopedName(entry.name, cone), target: scopedTarget(entry.target, cone) };\n}\n\nexport interface WebhookDelivery {\n id?: string;\n headers?: Record<string, string>;\n body: unknown;\n verified?: boolean;\n}\n\nexport interface LickSources {\n start(context: Context): Promise<void>;\n reconcile(context: Context): Promise<void>;\n boot(facts: BootFacts, context: Context): Promise<void>;\n webhook(name: string, delivery: WebhookDelivery, context: Context): Promise<boolean>;\n close(context: Context): Promise<void>;\n}\n\nexport function hash(text: string): string {\n let value = 2166136261;\n for (let at = 0; at < text.length; at++) value = Math.imul(value ^ text.charCodeAt(at), 16777619);\n return (value >>> 0).toString(36);\n}\n\nexport function shortPath(path: string, home: string): string {\n return path === home || path.startsWith(`${home}/`) ? `~${path.slice(home.length)}` : path;\n}\n\nexport function configLick(\n error: ConfigError,\n home: string,\n cone: string | null = null\n): LickEvent {\n const file = shortPath(error.file, home);\n const channel: LickChannel = error.file.includes('/watches/')\n ? 'fswatch'\n : error.file.includes('/webhooks/')\n ? 'webhook'\n : 'cron';\n const text = `${error.line ? `line ${error.line}: ` : ''}${error.error}`;\n return {\n channel,\n source: `config:${file}`,\n title: `Invalid ${file}`,\n text,\n body: error.file.endsWith('/crontab.migrated')\n ? \"Its jobs in the kernel crontab still lack --lick=cron, so they don't fire as cron licks; add it with crontab -.\"\n : channel === 'cron'\n ? 'Not moved into the kernel crontab until the file is fixed; the installed crontab is unchanged.\\nThe format is in the slicc-agent README.'\n : 'Ignored until the file is fixed.\\nThe formats are in the slicc-agent README.',\n target: scopedTarget('cone', cone),\n severity: 'error',\n eventId: hash(`${file}\\n${text}`),\n };\n}\n\nexport const UNVERIFIED = \"verified: false (the gateway couldn't check this request's signature)\";\n\nexport function webhookLick(\n name: string,\n entry: WebhookEntry,\n delivery: WebhookDelivery\n): LickEvent {\n const payload =\n typeof delivery.body === 'string' ? delivery.body : JSON.stringify(delivery.body, null, 2);\n const headers = Object.entries(delivery.headers ?? {})\n .map(([key, value]) => `${key}: ${value}`)\n .join('\\n');\n return {\n channel: 'webhook',\n source: name,\n title: name,\n text: entry.message || `Webhook ${name} received a request`,\n body: [delivery.verified === false ? UNVERIFIED : '', headers, payload]\n .filter(Boolean)\n .join('\\n\\n'),\n target: entry.target,\n coalesce: false,\n ...(delivery.id ? { eventId: delivery.id } : {}),\n ...(entry.triage ? { triage: entry.triage } : {}),\n };\n}\n\nasync function webhooksIn(\n files: ConfigFiles,\n dir: string,\n context: Context\n): Promise<{ entries: Map<string, WebhookEntry>; errors: ConfigError[] }> {\n const errors: ConfigError[] = [];\n const into = new Map<string, WebhookEntry>();\n for (const name of await files.list(dir, context)) {\n const file = `${dir}/${name}`;\n const json = await files.read(file, context);\n if (json === undefined) continue;\n try {\n const entry = parseWebhook(file, json);\n into.set(entry.name, entry);\n } catch (error) {\n errors.push({ file, error: (error as Error).message });\n }\n }\n return { entries: into, errors };\n}\n\nexport function createLickSources(options: LickSourcesOptions): LickSources {\n const { harness, env, licks, home } = options;\n const files = configFiles(env);\n const deliver = (event: LickEvent, context: Context) => licks.deliver(event, context);\n const dirsOf = options.dirs ?? (() => [{ dir: `${home}/${SLICC_DIR}`, home, cone: null }]);\n const watching = new Map<string, Watches>();\n const watchesOf = (place: LickDir) => {\n let found = watching.get(place.dir);\n if (!found) {\n const retarget = (event: LickEvent, context: Context) =>\n deliver({ ...event, target: scopedTarget(event.target, place.cone) }, context);\n found = new Watches(place.env ?? env, retarget, place.home, options.activity);\n watching.set(place.dir, found);\n }\n return found;\n };\n let webhooks = new Map<string, WebhookEntry>();\n const relicked = new Set<string>();\n let control: FileWatcher | undefined;\n let controlled = '';\n let reconcileTimer: ReturnType<typeof setTimeout> | undefined;\n let flushTimer: ReturnType<typeof setInterval> | undefined;\n let closed = false;\n let lock: Promise<unknown> = Promise.resolve();\n const serial = <T>(operation: () => Promise<T>): Promise<T> => {\n const run = lock.then(operation, operation);\n lock = run.catch(() => undefined);\n return run;\n };\n\n async function reconcileNow(context: Context): Promise<void> {\n if (closed) return;\n const places = await dirsOf();\n const errors: { error: ConfigError; place: LickDir }[] = [];\n const hooks = new Map<string, WebhookEntry>();\n for (const place of places) {\n const crontab = [...(await relick(place, context)), ...(await migrate(place, context))];\n const watchErrors = await watchesOf(place).reconcile(`${place.dir}/watches`, context);\n const found = await webhooksIn(files, `${place.dir}/webhooks`, context);\n for (const entry of found.entries.values()) {\n const named = scoped(entry, place.cone);\n hooks.set(named.name, named);\n }\n for (const error of [...crontab, ...watchErrors, ...found.errors])\n errors.push({ error, place });\n }\n for (const [dir, watches] of [...watching])\n if (!places.some((place) => place.dir === dir)) {\n watching.delete(dir);\n await watches.close(context);\n }\n webhooks = hooks;\n for (const { error, place } of errors)\n await deliver(configLick(error, place.home, place.cone), context);\n await watchControl(places, context);\n }\n\n function byUser(place: LickDir, jobs: readonly LegacyJob[]): Map<string, LegacyJob[]> {\n const users = new Map<string, LegacyJob[]>();\n for (const job of jobs) {\n const user = options.cronUser?.(job.target, place) ?? place.cone ?? ROOT_USER;\n users.set(user, [...(users.get(user) ?? []), job]);\n }\n return users;\n }\n\n async function relick(place: LickDir, context: Context): Promise<ConfigError[]> {\n if (relicked.has(place.dir)) return [];\n relicked.add(place.dir);\n const file = `${place.dir}/crontab.migrated`;\n const text = await files.read(file, context);\n if (text === undefined) return [];\n const errors: ConfigError[] = [];\n for (const [user, list] of byUser(place, legacyJobs(text).jobs))\n for (const problem of await relickJobs(env, user, list, context))\n errors.push({ file, ...problem });\n return errors;\n }\n\n async function migrate(place: LickDir, context: Context): Promise<ConfigError[]> {\n const file = `${place.dir}/crontab`;\n const text = await files.read(file, context);\n if (!text?.trim()) return [];\n const { jobs, problems } = legacyJobs(text);\n if (problems.length) return problems.map((problem) => ({ file, ...problem }));\n const users = new Map<string, CronJob[]>();\n for (const [user, list] of byUser(place, jobs))\n users.set(\n user,\n list.map((job) => ({\n name: job.name,\n schedule: job.schedule,\n command: sendCommand(job.target, job.message),\n line: job.line,\n }))\n );\n const errors: ConfigError[] = [];\n for (const [user, list] of users)\n for (const problem of await installJobs(env, user, list, context))\n errors.push({ file, ...problem });\n if (errors.length) return errors;\n await env.writeFile(`${file}.migrated`, text, context);\n await env.remove(file, { force: true }, context);\n return [];\n }\n\n async function retire(context: Context): Promise<void> {\n const stored = (await harness.snapshot(LicksHostDoc, context))?.cron ?? {};\n const records = Object.values(stored);\n if (!records.length) return;\n for (const record of records)\n await harness.abortTask(record.task as TaskId, context).catch(() => undefined);\n await harness.commit(async (tx) => {\n (await tx.doc(LicksHostDoc)).cron = {};\n }, context);\n }\n\n async function watchControl(places: readonly LickDir[], context: Context): Promise<void> {\n const key = places.map((place) => place.dir).join('\\n');\n if (key === controlled || closed) return;\n controlled = key;\n await control?.close(context);\n const result = await env.watch(\n places.map((place) => ({ path: place.dir, recursive: true })),\n () => scheduleReconcile(context),\n context\n );\n control = result.ok ? result.value : undefined;\n }\n\n const reconcile = (context: Context) => serial(() => reconcileNow(context));\n\n function scheduleReconcile(context: Context): void {\n clearTimeout(reconcileTimer);\n reconcileTimer = setTimeout(() => {\n void reconcile(context).catch(() => undefined);\n }, 300);\n }\n\n async function flushIfWaiting(context: Context): Promise<void> {\n if (await licks.pending(context)) await licks.flush(context);\n }\n\n return {\n async start(context) {\n await licks.flush(context);\n await retire(context);\n await reconcile(context);\n flushTimer = setInterval(() => {\n void flushIfWaiting(context).catch(() => undefined);\n }, options.flushEvery ?? 2000);\n },\n reconcile,\n boot: (facts, context) => bootLicks(harness, options.cone(), deliver, facts, context),\n async webhook(name, delivery, context) {\n const entry = webhooks.get(name);\n if (!entry) return false;\n await deliver(webhookLick(name, entry, delivery), context);\n return true;\n },\n async close(context) {\n closed = true;\n clearTimeout(reconcileTimer);\n clearInterval(flushTimer);\n await control?.close(context);\n for (const watches of watching.values()) await watches.close(context);\n },\n };\n}\n"],
5
+ "mappings": "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",
6
6
  "names": []
7
7
  }
package/dist/main.js CHANGED
@@ -324,10 +324,8 @@ async function start(scope, ports, options, vault) {
324
324
  ...people ? { dirs: () => people.lickDirs(), cronUser: people.cronUser.bind(people) } : {}
325
325
  });
326
326
  await sources.start(BACKGROUND_CONTEXT);
327
- await sources.boot(
328
- { version: facts.version, boot: await kernelBoot(client) },
329
- BACKGROUND_CONTEXT
330
- );
327
+ const booted = { version: facts.version, boot: await kernelBoot(client) };
328
+ await sources.boot(booted, BACKGROUND_CONTEXT);
331
329
  const skillsRuntime = await skills.attach(
332
330
  {
333
331
  env: home,
@@ -409,6 +407,7 @@ async function start(scope, ports, options, vault) {
409
407
  freezer: freezer.command,
410
408
  models: modelsOfAgent(agent, settings, models, vault),
411
409
  panel: pages.command,
410
+ webhook: sources.webhook,
412
411
  mcp: mcp.direct,
413
412
  ...options.assets ? { assets: options.assets } : {}
414
413
  },
package/dist/main.js.map CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../src/main.ts"],
4
- "sourcesContent": ["import { attachKernel } from '@ai-ecoverse/slicc-kernel';\nimport { BACKGROUND_CONTEXT } from '@earendil-works/chord/context';\nimport type { Provider } from '@earendil-works/pi-ai';\nimport type { Models } from '@earendil-works/pi-ai/models';\nimport {\n createRegistry,\n type ModelRef,\n type Storage,\n type ToolRegistration,\n} from '@earendil-works/pi-durable';\nimport { CodingTools } from '@earendil-works/pi-durable/tools';\nimport { type Agent, type AgentOptions, openAgent } from './agent.ts';\nimport {\n type ApprovalJudge,\n approvalJudge,\n judgeModelOf,\n judgeSpender,\n ownerIntent,\n seedPolicy,\n verdictRecorder,\n} from './approvals/index.ts';\nimport { browserGuard } from './browser/guard.ts';\nimport { attachChanges, CHANGES_MS } from './changes/index.ts';\nimport {\n codemodeExtension,\n codemodeTool,\n disabledBySettings,\n locateWasm,\n sandboxFactory,\n} from './codemode/index.ts';\nimport { attachFreezer } from './freezer/index.ts';\nimport { lateGelatiere } from './gelatiere/index.ts';\nimport { type AgentHost, hostAgent } from './host.ts';\nimport { imageReads } from './images/index.ts';\nimport { createActivity } from './kernel/activity.ts';\nimport { agentUsers, warnSupport } from './kernel/agent-users.ts';\nimport type { KernelClient } from './kernel/client.ts';\nimport { HOME, kernelEnvironment, SliccKernelEnv } from './kernel/env.ts';\nimport { processGroups } from './kernel/groups.ts';\nimport { adminOver, type UserClient, type UserClients, userClients } from './kernel/users.ts';\nimport { AGENT_DIR, ROOT_HOME } from './layout.ts';\nimport { setupLicks } from './licks/index.ts';\nimport { lickTriage } from './licks/triage.ts';\nimport { type McpAccounts, setupMcp } from './mcp/index.ts';\nimport type { MemoryEntry } from './memory/format.ts';\nimport { setupMemory } from './memory/index.ts';\nimport { modelsCommand } from './models/index.ts';\nimport { pageOnly, type Transport, transportFetch } from './net.ts';\nimport { sliccPrompt } from './prompt.ts';\nimport { createPages } from './remote/pages.ts';\nimport { identity } from './scoops/identity.ts';\nimport { type Assets, packageAssets, type ScoopsRuntime, setupScoops } from './scoops/index.ts';\nimport { vaultCredentials } from './secrets/credentials.ts';\nimport {\n BEDROCK_ENDPOINTS,\n type ModelBases,\n modelRoute,\n vaultEndpoints,\n} from './secrets/endpoints.ts';\nimport { secretsExtension, shellGrants } from './secrets/extension.ts';\nimport { grantFetch, mcpFetch, vaultFetch } from './secrets/fetch.ts';\nimport { keysMoved, type Wiped, wipeLegacy } from './secrets/legacy.ts';\nimport { secretNames } from './secrets/names.ts';\nimport { type VaultRecords, vaultRecords } from './secrets/records.ts';\nimport { scrubWith } from './secrets/scrub.ts';\nimport { fileStore, type PlainStore } from './secrets/store.ts';\nimport { listenVault, Vault, WAITING_MS } from './secrets/vault.ts';\nimport { type Choosable, unfreeze, unfreezeCreated } from './selection.ts';\nimport {\n BEDROCK,\n createAgentSettings,\n createSliccModels,\n providerFields,\n resolveDefaultModel,\n sliccProviders,\n} from './settings.ts';\nimport { RELOAD_MS, setupSkills } from './skills/index.ts';\nimport { setupSprinkles } from './sprinkles/index.ts';\nimport { openOpfsSqliteStorage } from './sqlite.ts';\nimport {\n agentVersion,\n browserConnected,\n commandsOnPath,\n kernelBoot,\n transportName,\n} from './system.ts';\nimport { titlesExtension } from './titles/extension.ts';\nimport { labeler, settingsText, titler } from './titles/generate.ts';\nimport { attachLabels } from './titles/labels.ts';\nimport { type KernelPorts, kernelPorts, serveConnections, type WorkerScope } from './worker.ts';\n\nexport interface AgentWorkerScope extends WorkerScope {\n fetch: typeof fetch;\n location: { origin: string };\n}\n\nexport type KernelAttach = (port: MessagePort) => Promise<KernelClient & { transport: Transport }>;\n\nexport interface AgentWorkerOptions {\n model?: ModelRef;\n providers?: Provider[];\n attach?: KernelAttach;\n store?: () => Promise<PlainStore>;\n storage?: () => Promise<Storage>;\n assets?: Assets;\n codemodeWasm?: () => Promise<WebAssembly.Module | undefined>;\n codemodeWorker?: string | URL;\n catalog?: string;\n users?: boolean;\n mcpRedirect?: string;\n approvalMs?: number;\n}\n\nexport function usersOf(\n admin: MessagePort | undefined,\n wanted: boolean | undefined,\n attach: KernelAttach\n): UserClients | undefined {\n if (!admin) return undefined;\n if (wanted === false) {\n admin.close();\n return undefined;\n }\n return userClients(adminOver(admin), attach as (port: MessagePort) => Promise<UserClient>);\n}\n\nexport const STORE_DIR = '/.slicc';\nexport const ACCOUNTS_FILE = `${STORE_DIR}/accounts.json`;\n\nasync function attached(ports: Promise<KernelPorts>, options: AgentWorkerOptions) {\n const wiped = await wipeLegacy();\n const attach: KernelAttach = options.attach ?? attachKernel;\n const { kernel, admin } = await ports;\n const client = await attach(kernel);\n const users = usersOf(admin, options.users, attach);\n await warnSupport(users, client, options.users);\n const home = new SliccKernelEnv(client, { cwd: HOME });\n await privateStore(home);\n return {\n client,\n users,\n home,\n wiped,\n at: { home: HOME, ...(users ? { agentDir: AGENT_DIR } : {}) },\n };\n}\n\nfunction privateStore(env: SliccKernelEnv): Promise<unknown> {\n return env.exec(`mkdir -p ${STORE_DIR} && chmod 700 ${STORE_DIR}`, undefined, BACKGROUND_CONTEXT);\n}\n\nasync function codemodeTools(\n client: KernelClient,\n options: AgentWorkerOptions,\n native: typeof fetch,\n extra: Parameters<typeof codemodeTool>[0]['extra'],\n dir = `${HOME}/.pi/agent`\n) {\n const settings = await client.fs.readFile(`${dir}/settings.json`).catch(() => undefined);\n if (disabledBySettings(settings === undefined ? undefined : new TextDecoder().decode(settings)))\n return [];\n const sandbox = sandboxFactory(\n options.codemodeWasm ?? (() => locateWasm(native, new URL(import.meta.url))),\n options.codemodeWorker\n );\n return [\n codemodeTool({ declared: CodingTools.tools as readonly ToolRegistration[], sandbox, extra }),\n ];\n}\n\nexport function seesImages(models: Pick<Models, 'getModel'>, ref: ModelRef | undefined): boolean {\n const found = ref && models.getModel(ref.provider, ref.modelId);\n return found ? found.input.includes('image') : true;\n}\n\nexport const MCP_CALLBACK = '/oauth/mcp-callback';\n\nasync function openUnfrozen(\n options: AgentWorkerOptions,\n { choosable: chosen }: { choosable: Choosable },\n base: Omit<AgentOptions, 'storage' | 'beforeResume' | 'conversationCreated'>\n): Promise<Agent> {\n const storage = await (options.storage ?? (() => openOpfsSqliteStorage()))();\n return openAgent({\n ...base,\n storage,\n conversationCreated: unfreezeCreated(chosen),\n beforeResume: (harness, using) => unfreeze(harness, storage, chosen, using),\n });\n}\n\nasync function secretsFor(home: SliccKernelEnv, vault: Vault) {\n scrubWith(vault);\n const names = secretNames(home, vault);\n await names.refresh(BACKGROUND_CONTEXT);\n return names;\n}\n\nexport function modelBases(\n providers: readonly Provider[],\n models: Pick<ReturnType<typeof createSliccModels>, 'getModels'>\n): ModelBases[] {\n return providers.map((provider) => ({\n provider: provider.id,\n urls: [\n ...new Set(\n [\n provider.baseUrl,\n ...models.getModels(provider.id).map((model) => model.baseUrl),\n ...(provider.id === BEDROCK ? BEDROCK_ENDPOINTS : []),\n ].filter((url): url is string => typeof url === 'string' && url !== '')\n ),\n ],\n }));\n}\n\nfunction mcpVault(\n vault: Vault,\n made: { store: PlainStore; records: VaultRecords; endpoints: ReturnType<typeof vaultEndpoints> }\n) {\n const { store, records, endpoints } = made;\n return {\n store,\n vault: {\n records,\n fetch: (server: string, base: typeof fetch) => mcpFetch(vault, base, server),\n grant: (server: string, base: typeof fetch) => grantFetch(vault, server, base),\n servers: endpoints.servers,\n token: endpoints.token,\n },\n };\n}\n\nfunction hostSecrets(\n vault: Vault,\n names: Awaited<ReturnType<typeof secretsFor>>,\n parts: readonly { close(): void }[]\n) {\n return {\n vault: vault.state,\n list: () => names.state.value,\n close: () => {\n for (const part of parts) part.close();\n },\n };\n}\n\nasync function modelsOf(\n scope: AgentWorkerScope,\n options: AgentWorkerOptions,\n given: { vault: Vault; home: SliccKernelEnv; transport: typeof fetch; version: string }\n) {\n const { vault, home, transport, version } = given;\n const store = await (options.store ?? (async () => fileStore(home, ACCOUNTS_FILE)))();\n const records = vaultRecords(vault);\n const loaded = records.refresh(BACKGROUND_CONTEXT).catch(() => undefined);\n const providers = options.providers ?? sliccProviders(version);\n const fields = await providerFields(store, providers);\n const credentials = vaultCredentials(records, fields.env);\n const models = createSliccModels(credentials, providers);\n const bases = () => modelBases(providers, models);\n scope.fetch = vaultFetch(\n vault,\n transport,\n modelRoute(bases, () => records.state.value)\n );\n const endpoints = vaultEndpoints(vault);\n void endpoints.models(bases()).catch(() => undefined);\n const defaultModel = async () => {\n await Promise.race([loaded, new Promise((resolve) => setTimeout(resolve, WAITING_MS))]);\n return resolveDefaultModel(credentials, providers, models);\n };\n return { store, records, providers, fields, models, bases, endpoints, defaultModel };\n}\n\nfunction baseRegistry(facts: Awaited<ReturnType<typeof factsOf>>, origin: string) {\n const registry = createRegistry();\n registry.install(CodingTools);\n registry.install(browserGuard([origin]));\n registry.install(sliccPrompt(facts));\n const read = (CodingTools.tools as readonly ToolRegistration[]).find(\n (tool) => tool.name === 'read'\n ) as ToolRegistration;\n registry.install(imageReads(read));\n return registry;\n}\n\nasync function factsOf(client: KernelClient & { transport: Transport }, native: typeof fetch) {\n return {\n version: await agentVersion((url) => native(url)),\n commands: await commandsOnPath(client),\n transport: transportName(client.transport),\n browser: await browserConnected(client),\n };\n}\n\nfunction routeFetch(scope: AgentWorkerScope, client: KernelClient & { transport: Transport }) {\n const native = scope.fetch.bind(scope);\n const loopback = client.loopbackFetch?.bind(client);\n const transport = transportFetch(client.transport, scope.location.origin, native, loopback);\n scope.fetch = transport;\n return { native, transport };\n}\n\nasync function prepare(\n scope: AgentWorkerScope,\n kernel: { client: KernelClient & { transport: Transport }; home: SliccKernelEnv; vault: Vault },\n options: AgentWorkerOptions\n) {\n const names = await secretsFor(kernel.home, kernel.vault);\n const { native, transport } = routeFetch(scope, kernel.client);\n const facts = await factsOf(kernel.client, native);\n const made = await modelsOf(scope, options, {\n vault: kernel.vault,\n home: kernel.home,\n transport,\n version: facts.version,\n });\n return {\n names,\n native,\n transport,\n facts,\n ...made,\n registry: baseRegistry(facts, scope.location.origin),\n };\n}\n\nfunction modelsOfAgent(\n agent: Agent,\n settings: Awaited<ReturnType<typeof createAgentSettings>>,\n catalog: Models,\n vault: Vault\n) {\n const locked = () => vault.state.value.locked !== 'no';\n return modelsCommand({ agents: agent.agents, settings, catalog, locked });\n}\n\nasync function settingsOf(\n made: Awaited<ReturnType<typeof modelsOf>>,\n mcp: McpAccounts,\n moved: { agent: Agent; vault: Vault; wiped: Wiped }\n) {\n const { models, records, fields, providers, bases, endpoints } = made;\n const keys = await keysMoved(moved.agent.harness, { records, vault: moved.vault }, moved.wiped);\n const settings = await createAgentSettings(models, { records, fields }, providers, {\n mcp,\n moved: keys,\n });\n settings.state.subscribe(() => void endpoints.models(bases()).catch(() => undefined));\n return settings;\n}\n\nasync function setupApprovals(\n models: Models,\n home: SliccKernelEnv,\n at: { home: string; agentDir?: string },\n agent: Agent,\n stored: { readonly value: readonly MemoryEntry[] | undefined },\n options: Pick<AgentWorkerOptions, 'approvalMs'>\n) {\n const memories = () => stored.value;\n const { approvalMs } = options;\n await seedPolicy(home, BACKGROUND_CONTEXT).catch(() => false);\n const settings = settingsText(home, HOME, at.agentDir);\n const intent = ownerIntent({ env: home, agents: agent.agents, memories });\n const judge: ApprovalJudge = {\n judge: approvalJudge({\n models,\n model: async (context) => judgeModelOf(await settings(context)),\n intent,\n spend: judgeSpender((agentId, context) => agent.agents.conversation(agentId, context)),\n }),\n record: verdictRecorder((agentId, context) => agent.agents.conversation(agentId, context)),\n };\n return { judge, intent, ...(approvalMs ? { approvalMs } : {}) };\n}\n\nfunction setupTitles(\n registry: ReturnType<typeof createRegistry>,\n models: Models,\n home: SliccKernelEnv,\n at: { home: string; agentDir?: string },\n opened: () => Agent | undefined\n) {\n const settings = settingsText(home, HOME, at.agentDir);\n const titleFn = titler(models, settings);\n const titles = titlesExtension({\n agents: () => opened()?.agents,\n harness: () => opened()?.harness,\n title: () => titleFn,\n });\n registry.install(titles.extension);\n return { titleFn, cancel: titles.cancel, label: labeler(models, settings) };\n}\n\nasync function start(\n scope: AgentWorkerScope,\n ports: Promise<KernelPorts>,\n options: AgentWorkerOptions,\n vault: Vault\n): Promise<AgentHost> {\n const { client, users, home, at, wiped } = await attached(ports, options);\n const ready = await prepare(scope, { client, home, vault }, options);\n const { names, native, transport, facts, models, registry, records, endpoints } = ready;\n const memory = setupMemory(registry);\n const coding = CodingTools.tools as readonly ToolRegistration[];\n const mcp = setupMcp(registry);\n const codemode = await codemodeTools(client, options, native, mcp.codemode, at.agentDir);\n registry.install(codemodeExtension(codemode));\n const licks = setupLicks(registry);\n licks.licks.triage(lickTriage(models));\n const scoops = setupScoops(registry, licks.licks, [...coding, ...codemode, ...memory.tools]);\n const skills = setupSkills(registry, licks.licks);\n registry.install(secretsExtension({ names, vault }));\n const titles = setupTitles(registry, models, home, at, () => opened);\n const [activity, groups] = [createActivity(), processGroups(client)];\n const model = options.model ?? (await ready.defaultModel());\n let opened: Agent | undefined;\n const people = users ? agentUsers(users, client, home, () => opened?.agents) : undefined;\n const environment = kernelEnvironment(client, {\n activity,\n groups,\n identify: identity(() => opened?.agents, model),\n scrub: vault,\n spawn: shellGrants(names),\n ...(people ? { route: people.route } : {}),\n });\n const agent = await openUnfrozen(options, scoops, { models, model, registry, env: environment });\n opened = agent;\n await people?.start(agent.agents);\n const sources = licks.attach(agent, {\n env: home,\n home: HOME,\n activity,\n ...(people ? { dirs: () => people.lickDirs(), cronUser: people.cronUser.bind(people) } : {}),\n });\n await sources.start(BACKGROUND_CONTEXT);\n await sources.boot(\n { version: facts.version, boot: await kernelBoot(client) },\n BACKGROUND_CONTEXT\n );\n const skillsRuntime = await skills.attach(\n {\n env: home,\n ...at,\n assets: options.assets ?? packageAssets(),\n reloadMs: RELOAD_MS,\n ...(people ? { people: people.people } : {}),\n },\n BACKGROUND_CONTEXT\n );\n const mcpRuntime = await mcp.attach(\n {\n env: home,\n ...at,\n ...mcpVault(vault, ready),\n licks: licks.licks,\n fetch: transport,\n version: facts.version,\n reloadMs: RELOAD_MS,\n codemode: codemode.length > 0,\n cors: pageOnly(client.transport),\n redirect: options.mcpRedirect ?? new URL(MCP_CALLBACK, scope.location.origin).href,\n },\n BACKGROUND_CONTEXT\n );\n const gelatiere = lateGelatiere();\n const sprinkles = await setupSprinkles().attach(\n {\n intercept: gelatiere.intercept,\n harness: agent.harness,\n agents: agent.agents,\n licks: licks.licks,\n env: home,\n assets: options.assets ?? packageAssets(),\n reloadMs: RELOAD_MS,\n ...(people?.sprinkles() ?? {}),\n },\n BACKGROUND_CONTEXT\n );\n people?.follow([sources, skillsRuntime, sprinkles]);\n let roles: ScoopsRuntime | undefined;\n const memoryRuntime = await memory.attach(\n {\n harness: agent.harness,\n agents: agent.agents,\n env: home,\n ...at,\n ...(people ? { home: ROOT_HOME } : {}),\n reloadMs: RELOAD_MS,\n roles: async (using) => roles?.roles(using),\n },\n BACKGROUND_CONTEXT\n );\n const freezer = attachFreezer({\n harness: agent.harness,\n agents: agent.agents,\n env: home,\n extract: memory.extract,\n title: titles.titleFn,\n cancelTitle: titles.cancel,\n ...(people ? { layout: people.layout } : {}),\n });\n licks.licks.guard(freezer.frozenTarget);\n const settings = await settingsOf(ready, mcpRuntime, { agent, vault, wiped });\n const pages = createPages({ claim: sprinkles.claim });\n const runtime = await scoops.attach(\n {\n harness: agent.harness,\n agents: agent.agents,\n groups,\n env: home,\n envOf: async (conversationId, context) => environment({ conversationId }, context),\n ...at,\n ...(people\n ? { layout: people.layout, spools: people.spools, enforced: people.enforced }\n : {}),\n alive: alive(client),\n reads: skillsRuntime.dirs,\n memory: memoryRuntime.command,\n gelatiere: gelatiere.command,\n freezer: freezer.command,\n models: modelsOfAgent(agent, settings, models, vault),\n panel: pages.command,\n mcp: mcp.direct,\n ...(options.assets ? { assets: options.assets } : {}),\n },\n BACKGROUND_CONTEXT\n );\n roles = runtime;\n gelatiere.attach({\n agents: agent.agents,\n licks: licks.licks,\n env: home,\n home: HOME,\n ...(await people?.gelatiere(home)),\n scoops: scoops.scoops,\n roles: runtime.roles,\n assets: options.assets ?? packageAssets(),\n fetch: scope.fetch,\n skills: skillsRuntime.skills,\n ...(options.catalog ? { catalog: options.catalog } : {}),\n });\n await memoryRuntime.reload(BACKGROUND_CONTEXT).catch(() => undefined);\n return hostAgent(agent, {\n ...(await setupApprovals(models, home, at, agent, memoryRuntime.memories, options)),\n settings,\n licks: { licks: licks.licks, sources },\n scoops: { scoops: scoops.scoops, runtime },\n skills: skillsRuntime,\n sprinkles,\n memory: memoryRuntime,\n freezer,\n changes: attachChanges({ agents: agent.agents, env: home, reloadMs: CHANGES_MS }),\n pages,\n labels: await attachLabels({ ...agent, label: titles.label, vault: vault.state }),\n mcp: mcpRuntime,\n ...(users ? { users } : {}),\n secrets: hostSecrets(vault, names, [names, records, endpoints]),\n uploads: {\n env: environment,\n sees: (ref) => seesImages(models, ref),\n },\n monitor: {\n kernel: client,\n groups,\n ...(users ? { users: () => users.users.list() } : {}),\n },\n });\n}\n\nexport function alive(client: KernelClient) {\n return async (pid: number): Promise<boolean> => {\n if (!client.ps) return true;\n return (await client.ps()).some((process) => process.pid === pid);\n };\n}\n\nexport function runAgentWorker(\n scope: AgentWorkerScope,\n options: AgentWorkerOptions = {}\n): Promise<AgentHost> {\n const vault = new Vault();\n listenVault(scope, vault);\n const host = start(scope, kernelPorts(scope), options, vault);\n host.catch(() => undefined);\n serveConnections(scope, host);\n return host;\n}\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["import { attachKernel } from '@ai-ecoverse/slicc-kernel';\nimport { BACKGROUND_CONTEXT } from '@earendil-works/chord/context';\nimport type { Provider } from '@earendil-works/pi-ai';\nimport type { Models } from '@earendil-works/pi-ai/models';\nimport {\n createRegistry,\n type ModelRef,\n type Storage,\n type ToolRegistration,\n} from '@earendil-works/pi-durable';\nimport { CodingTools } from '@earendil-works/pi-durable/tools';\nimport { type Agent, type AgentOptions, openAgent } from './agent.ts';\nimport {\n type ApprovalJudge,\n approvalJudge,\n judgeModelOf,\n judgeSpender,\n ownerIntent,\n seedPolicy,\n verdictRecorder,\n} from './approvals/index.ts';\nimport { browserGuard } from './browser/guard.ts';\nimport { attachChanges, CHANGES_MS } from './changes/index.ts';\nimport {\n codemodeExtension,\n codemodeTool,\n disabledBySettings,\n locateWasm,\n sandboxFactory,\n} from './codemode/index.ts';\nimport { attachFreezer } from './freezer/index.ts';\nimport { lateGelatiere } from './gelatiere/index.ts';\nimport { type AgentHost, hostAgent } from './host.ts';\nimport { imageReads } from './images/index.ts';\nimport { createActivity } from './kernel/activity.ts';\nimport { agentUsers, warnSupport } from './kernel/agent-users.ts';\nimport type { KernelClient } from './kernel/client.ts';\nimport { HOME, kernelEnvironment, SliccKernelEnv } from './kernel/env.ts';\nimport { processGroups } from './kernel/groups.ts';\nimport { adminOver, type UserClient, type UserClients, userClients } from './kernel/users.ts';\nimport { AGENT_DIR, ROOT_HOME } from './layout.ts';\nimport { setupLicks } from './licks/index.ts';\nimport { lickTriage } from './licks/triage.ts';\nimport { type McpAccounts, setupMcp } from './mcp/index.ts';\nimport type { MemoryEntry } from './memory/format.ts';\nimport { setupMemory } from './memory/index.ts';\nimport { modelsCommand } from './models/index.ts';\nimport { pageOnly, type Transport, transportFetch } from './net.ts';\nimport { sliccPrompt } from './prompt.ts';\nimport { createPages } from './remote/pages.ts';\nimport { identity } from './scoops/identity.ts';\nimport { type Assets, packageAssets, type ScoopsRuntime, setupScoops } from './scoops/index.ts';\nimport { vaultCredentials } from './secrets/credentials.ts';\nimport {\n BEDROCK_ENDPOINTS,\n type ModelBases,\n modelRoute,\n vaultEndpoints,\n} from './secrets/endpoints.ts';\nimport { secretsExtension, shellGrants } from './secrets/extension.ts';\nimport { grantFetch, mcpFetch, vaultFetch } from './secrets/fetch.ts';\nimport { keysMoved, type Wiped, wipeLegacy } from './secrets/legacy.ts';\nimport { secretNames } from './secrets/names.ts';\nimport { type VaultRecords, vaultRecords } from './secrets/records.ts';\nimport { scrubWith } from './secrets/scrub.ts';\nimport { fileStore, type PlainStore } from './secrets/store.ts';\nimport { listenVault, Vault, WAITING_MS } from './secrets/vault.ts';\nimport { type Choosable, unfreeze, unfreezeCreated } from './selection.ts';\nimport {\n BEDROCK,\n createAgentSettings,\n createSliccModels,\n providerFields,\n resolveDefaultModel,\n sliccProviders,\n} from './settings.ts';\nimport { RELOAD_MS, setupSkills } from './skills/index.ts';\nimport { setupSprinkles } from './sprinkles/index.ts';\nimport { openOpfsSqliteStorage } from './sqlite.ts';\nimport {\n agentVersion,\n browserConnected,\n commandsOnPath,\n kernelBoot,\n transportName,\n} from './system.ts';\nimport { titlesExtension } from './titles/extension.ts';\nimport { labeler, settingsText, titler } from './titles/generate.ts';\nimport { attachLabels } from './titles/labels.ts';\nimport { type KernelPorts, kernelPorts, serveConnections, type WorkerScope } from './worker.ts';\n\nexport interface AgentWorkerScope extends WorkerScope {\n fetch: typeof fetch;\n location: { origin: string };\n}\n\nexport type KernelAttach = (port: MessagePort) => Promise<KernelClient & { transport: Transport }>;\n\nexport interface AgentWorkerOptions {\n model?: ModelRef;\n providers?: Provider[];\n attach?: KernelAttach;\n store?: () => Promise<PlainStore>;\n storage?: () => Promise<Storage>;\n assets?: Assets;\n codemodeWasm?: () => Promise<WebAssembly.Module | undefined>;\n codemodeWorker?: string | URL;\n catalog?: string;\n users?: boolean;\n mcpRedirect?: string;\n approvalMs?: number;\n}\n\nexport function usersOf(\n admin: MessagePort | undefined,\n wanted: boolean | undefined,\n attach: KernelAttach\n): UserClients | undefined {\n if (!admin) return undefined;\n if (wanted === false) {\n admin.close();\n return undefined;\n }\n return userClients(adminOver(admin), attach as (port: MessagePort) => Promise<UserClient>);\n}\n\nexport const STORE_DIR = '/.slicc';\nexport const ACCOUNTS_FILE = `${STORE_DIR}/accounts.json`;\n\nasync function attached(ports: Promise<KernelPorts>, options: AgentWorkerOptions) {\n const wiped = await wipeLegacy();\n const attach: KernelAttach = options.attach ?? attachKernel;\n const { kernel, admin } = await ports;\n const client = await attach(kernel);\n const users = usersOf(admin, options.users, attach);\n await warnSupport(users, client, options.users);\n const home = new SliccKernelEnv(client, { cwd: HOME });\n await privateStore(home);\n return {\n client,\n users,\n home,\n wiped,\n at: { home: HOME, ...(users ? { agentDir: AGENT_DIR } : {}) },\n };\n}\n\nfunction privateStore(env: SliccKernelEnv): Promise<unknown> {\n return env.exec(`mkdir -p ${STORE_DIR} && chmod 700 ${STORE_DIR}`, undefined, BACKGROUND_CONTEXT);\n}\n\nasync function codemodeTools(\n client: KernelClient,\n options: AgentWorkerOptions,\n native: typeof fetch,\n extra: Parameters<typeof codemodeTool>[0]['extra'],\n dir = `${HOME}/.pi/agent`\n) {\n const settings = await client.fs.readFile(`${dir}/settings.json`).catch(() => undefined);\n if (disabledBySettings(settings === undefined ? undefined : new TextDecoder().decode(settings)))\n return [];\n const sandbox = sandboxFactory(\n options.codemodeWasm ?? (() => locateWasm(native, new URL(import.meta.url))),\n options.codemodeWorker\n );\n return [\n codemodeTool({ declared: CodingTools.tools as readonly ToolRegistration[], sandbox, extra }),\n ];\n}\n\nexport function seesImages(models: Pick<Models, 'getModel'>, ref: ModelRef | undefined): boolean {\n const found = ref && models.getModel(ref.provider, ref.modelId);\n return found ? found.input.includes('image') : true;\n}\n\nexport const MCP_CALLBACK = '/oauth/mcp-callback';\n\nasync function openUnfrozen(\n options: AgentWorkerOptions,\n { choosable: chosen }: { choosable: Choosable },\n base: Omit<AgentOptions, 'storage' | 'beforeResume' | 'conversationCreated'>\n): Promise<Agent> {\n const storage = await (options.storage ?? (() => openOpfsSqliteStorage()))();\n return openAgent({\n ...base,\n storage,\n conversationCreated: unfreezeCreated(chosen),\n beforeResume: (harness, using) => unfreeze(harness, storage, chosen, using),\n });\n}\n\nasync function secretsFor(home: SliccKernelEnv, vault: Vault) {\n scrubWith(vault);\n const names = secretNames(home, vault);\n await names.refresh(BACKGROUND_CONTEXT);\n return names;\n}\n\nexport function modelBases(\n providers: readonly Provider[],\n models: Pick<ReturnType<typeof createSliccModels>, 'getModels'>\n): ModelBases[] {\n return providers.map((provider) => ({\n provider: provider.id,\n urls: [\n ...new Set(\n [\n provider.baseUrl,\n ...models.getModels(provider.id).map((model) => model.baseUrl),\n ...(provider.id === BEDROCK ? BEDROCK_ENDPOINTS : []),\n ].filter((url): url is string => typeof url === 'string' && url !== '')\n ),\n ],\n }));\n}\n\nfunction mcpVault(\n vault: Vault,\n made: { store: PlainStore; records: VaultRecords; endpoints: ReturnType<typeof vaultEndpoints> }\n) {\n const { store, records, endpoints } = made;\n return {\n store,\n vault: {\n records,\n fetch: (server: string, base: typeof fetch) => mcpFetch(vault, base, server),\n grant: (server: string, base: typeof fetch) => grantFetch(vault, server, base),\n servers: endpoints.servers,\n token: endpoints.token,\n },\n };\n}\n\nfunction hostSecrets(\n vault: Vault,\n names: Awaited<ReturnType<typeof secretsFor>>,\n parts: readonly { close(): void }[]\n) {\n return {\n vault: vault.state,\n list: () => names.state.value,\n close: () => {\n for (const part of parts) part.close();\n },\n };\n}\n\nasync function modelsOf(\n scope: AgentWorkerScope,\n options: AgentWorkerOptions,\n given: { vault: Vault; home: SliccKernelEnv; transport: typeof fetch; version: string }\n) {\n const { vault, home, transport, version } = given;\n const store = await (options.store ?? (async () => fileStore(home, ACCOUNTS_FILE)))();\n const records = vaultRecords(vault);\n const loaded = records.refresh(BACKGROUND_CONTEXT).catch(() => undefined);\n const providers = options.providers ?? sliccProviders(version);\n const fields = await providerFields(store, providers);\n const credentials = vaultCredentials(records, fields.env);\n const models = createSliccModels(credentials, providers);\n const bases = () => modelBases(providers, models);\n scope.fetch = vaultFetch(\n vault,\n transport,\n modelRoute(bases, () => records.state.value)\n );\n const endpoints = vaultEndpoints(vault);\n void endpoints.models(bases()).catch(() => undefined);\n const defaultModel = async () => {\n await Promise.race([loaded, new Promise((resolve) => setTimeout(resolve, WAITING_MS))]);\n return resolveDefaultModel(credentials, providers, models);\n };\n return { store, records, providers, fields, models, bases, endpoints, defaultModel };\n}\n\nfunction baseRegistry(facts: Awaited<ReturnType<typeof factsOf>>, origin: string) {\n const registry = createRegistry();\n registry.install(CodingTools);\n registry.install(browserGuard([origin]));\n registry.install(sliccPrompt(facts));\n const read = (CodingTools.tools as readonly ToolRegistration[]).find(\n (tool) => tool.name === 'read'\n ) as ToolRegistration;\n registry.install(imageReads(read));\n return registry;\n}\n\nasync function factsOf(client: KernelClient & { transport: Transport }, native: typeof fetch) {\n return {\n version: await agentVersion((url) => native(url)),\n commands: await commandsOnPath(client),\n transport: transportName(client.transport),\n browser: await browserConnected(client),\n };\n}\n\nfunction routeFetch(scope: AgentWorkerScope, client: KernelClient & { transport: Transport }) {\n const native = scope.fetch.bind(scope);\n const loopback = client.loopbackFetch?.bind(client);\n const transport = transportFetch(client.transport, scope.location.origin, native, loopback);\n scope.fetch = transport;\n return { native, transport };\n}\n\nasync function prepare(\n scope: AgentWorkerScope,\n kernel: { client: KernelClient & { transport: Transport }; home: SliccKernelEnv; vault: Vault },\n options: AgentWorkerOptions\n) {\n const names = await secretsFor(kernel.home, kernel.vault);\n const { native, transport } = routeFetch(scope, kernel.client);\n const facts = await factsOf(kernel.client, native);\n const made = await modelsOf(scope, options, {\n vault: kernel.vault,\n home: kernel.home,\n transport,\n version: facts.version,\n });\n return {\n names,\n native,\n transport,\n facts,\n ...made,\n registry: baseRegistry(facts, scope.location.origin),\n };\n}\n\nfunction modelsOfAgent(\n agent: Agent,\n settings: Awaited<ReturnType<typeof createAgentSettings>>,\n catalog: Models,\n vault: Vault\n) {\n const locked = () => vault.state.value.locked !== 'no';\n return modelsCommand({ agents: agent.agents, settings, catalog, locked });\n}\n\nasync function settingsOf(\n made: Awaited<ReturnType<typeof modelsOf>>,\n mcp: McpAccounts,\n moved: { agent: Agent; vault: Vault; wiped: Wiped }\n) {\n const { models, records, fields, providers, bases, endpoints } = made;\n const keys = await keysMoved(moved.agent.harness, { records, vault: moved.vault }, moved.wiped);\n const settings = await createAgentSettings(models, { records, fields }, providers, {\n mcp,\n moved: keys,\n });\n settings.state.subscribe(() => void endpoints.models(bases()).catch(() => undefined));\n return settings;\n}\n\nasync function setupApprovals(\n models: Models,\n home: SliccKernelEnv,\n at: { home: string; agentDir?: string },\n agent: Agent,\n stored: { readonly value: readonly MemoryEntry[] | undefined },\n options: Pick<AgentWorkerOptions, 'approvalMs'>\n) {\n const memories = () => stored.value;\n const { approvalMs } = options;\n await seedPolicy(home, BACKGROUND_CONTEXT).catch(() => false);\n const settings = settingsText(home, HOME, at.agentDir);\n const intent = ownerIntent({ env: home, agents: agent.agents, memories });\n const judge: ApprovalJudge = {\n judge: approvalJudge({\n models,\n model: async (context) => judgeModelOf(await settings(context)),\n intent,\n spend: judgeSpender((agentId, context) => agent.agents.conversation(agentId, context)),\n }),\n record: verdictRecorder((agentId, context) => agent.agents.conversation(agentId, context)),\n };\n return { judge, intent, ...(approvalMs ? { approvalMs } : {}) };\n}\n\nfunction setupTitles(\n registry: ReturnType<typeof createRegistry>,\n models: Models,\n home: SliccKernelEnv,\n at: { home: string; agentDir?: string },\n opened: () => Agent | undefined\n) {\n const settings = settingsText(home, HOME, at.agentDir);\n const titleFn = titler(models, settings);\n const titles = titlesExtension({\n agents: () => opened()?.agents,\n harness: () => opened()?.harness,\n title: () => titleFn,\n });\n registry.install(titles.extension);\n return { titleFn, cancel: titles.cancel, label: labeler(models, settings) };\n}\n\nasync function start(\n scope: AgentWorkerScope,\n ports: Promise<KernelPorts>,\n options: AgentWorkerOptions,\n vault: Vault\n): Promise<AgentHost> {\n const { client, users, home, at, wiped } = await attached(ports, options);\n const ready = await prepare(scope, { client, home, vault }, options);\n const { names, native, transport, facts, models, registry, records, endpoints } = ready;\n const memory = setupMemory(registry);\n const coding = CodingTools.tools as readonly ToolRegistration[];\n const mcp = setupMcp(registry);\n const codemode = await codemodeTools(client, options, native, mcp.codemode, at.agentDir);\n registry.install(codemodeExtension(codemode));\n const licks = setupLicks(registry);\n licks.licks.triage(lickTriage(models));\n const scoops = setupScoops(registry, licks.licks, [...coding, ...codemode, ...memory.tools]);\n const skills = setupSkills(registry, licks.licks);\n registry.install(secretsExtension({ names, vault }));\n const titles = setupTitles(registry, models, home, at, () => opened);\n const [activity, groups] = [createActivity(), processGroups(client)];\n const model = options.model ?? (await ready.defaultModel());\n let opened: Agent | undefined;\n const people = users ? agentUsers(users, client, home, () => opened?.agents) : undefined;\n const environment = kernelEnvironment(client, {\n activity,\n groups,\n identify: identity(() => opened?.agents, model),\n scrub: vault,\n spawn: shellGrants(names),\n ...(people ? { route: people.route } : {}),\n });\n const agent = await openUnfrozen(options, scoops, { models, model, registry, env: environment });\n opened = agent;\n await people?.start(agent.agents);\n const sources = licks.attach(agent, {\n env: home,\n home: HOME,\n activity,\n ...(people ? { dirs: () => people.lickDirs(), cronUser: people.cronUser.bind(people) } : {}),\n });\n await sources.start(BACKGROUND_CONTEXT);\n const booted = { version: facts.version, boot: await kernelBoot(client) };\n await sources.boot(booted, BACKGROUND_CONTEXT);\n const skillsRuntime = await skills.attach(\n {\n env: home,\n ...at,\n assets: options.assets ?? packageAssets(),\n reloadMs: RELOAD_MS,\n ...(people ? { people: people.people } : {}),\n },\n BACKGROUND_CONTEXT\n );\n const mcpRuntime = await mcp.attach(\n {\n env: home,\n ...at,\n ...mcpVault(vault, ready),\n licks: licks.licks,\n fetch: transport,\n version: facts.version,\n reloadMs: RELOAD_MS,\n codemode: codemode.length > 0,\n cors: pageOnly(client.transport),\n redirect: options.mcpRedirect ?? new URL(MCP_CALLBACK, scope.location.origin).href,\n },\n BACKGROUND_CONTEXT\n );\n const gelatiere = lateGelatiere();\n const sprinkles = await setupSprinkles().attach(\n {\n intercept: gelatiere.intercept,\n harness: agent.harness,\n agents: agent.agents,\n licks: licks.licks,\n env: home,\n assets: options.assets ?? packageAssets(),\n reloadMs: RELOAD_MS,\n ...(people?.sprinkles() ?? {}),\n },\n BACKGROUND_CONTEXT\n );\n people?.follow([sources, skillsRuntime, sprinkles]);\n let roles: ScoopsRuntime | undefined;\n const memoryRuntime = await memory.attach(\n {\n harness: agent.harness,\n agents: agent.agents,\n env: home,\n ...at,\n ...(people ? { home: ROOT_HOME } : {}),\n reloadMs: RELOAD_MS,\n roles: async (using) => roles?.roles(using),\n },\n BACKGROUND_CONTEXT\n );\n const freezer = attachFreezer({\n harness: agent.harness,\n agents: agent.agents,\n env: home,\n extract: memory.extract,\n title: titles.titleFn,\n cancelTitle: titles.cancel,\n ...(people ? { layout: people.layout } : {}),\n });\n licks.licks.guard(freezer.frozenTarget);\n const settings = await settingsOf(ready, mcpRuntime, { agent, vault, wiped });\n const pages = createPages({ claim: sprinkles.claim });\n const runtime = await scoops.attach(\n {\n harness: agent.harness,\n agents: agent.agents,\n groups,\n env: home,\n envOf: async (conversationId, context) => environment({ conversationId }, context),\n ...at,\n ...(people\n ? { layout: people.layout, spools: people.spools, enforced: people.enforced }\n : {}),\n alive: alive(client),\n reads: skillsRuntime.dirs,\n memory: memoryRuntime.command,\n gelatiere: gelatiere.command,\n freezer: freezer.command,\n models: modelsOfAgent(agent, settings, models, vault),\n panel: pages.command,\n webhook: sources.webhook,\n mcp: mcp.direct,\n ...(options.assets ? { assets: options.assets } : {}),\n },\n BACKGROUND_CONTEXT\n );\n roles = runtime;\n gelatiere.attach({\n agents: agent.agents,\n licks: licks.licks,\n env: home,\n home: HOME,\n ...(await people?.gelatiere(home)),\n scoops: scoops.scoops,\n roles: runtime.roles,\n assets: options.assets ?? packageAssets(),\n fetch: scope.fetch,\n skills: skillsRuntime.skills,\n ...(options.catalog ? { catalog: options.catalog } : {}),\n });\n await memoryRuntime.reload(BACKGROUND_CONTEXT).catch(() => undefined);\n return hostAgent(agent, {\n ...(await setupApprovals(models, home, at, agent, memoryRuntime.memories, options)),\n settings,\n licks: { licks: licks.licks, sources },\n scoops: { scoops: scoops.scoops, runtime },\n skills: skillsRuntime,\n sprinkles,\n memory: memoryRuntime,\n freezer,\n changes: attachChanges({ agents: agent.agents, env: home, reloadMs: CHANGES_MS }),\n pages,\n labels: await attachLabels({ ...agent, label: titles.label, vault: vault.state }),\n mcp: mcpRuntime,\n ...(users ? { users } : {}),\n secrets: hostSecrets(vault, names, [names, records, endpoints]),\n uploads: {\n env: environment,\n sees: (ref) => seesImages(models, ref),\n },\n monitor: {\n kernel: client,\n groups,\n ...(users ? { users: () => users.users.list() } : {}),\n },\n });\n}\n\nexport function alive(client: KernelClient) {\n return async (pid: number): Promise<boolean> => {\n if (!client.ps) return true;\n return (await client.ps()).some((process) => process.pid === pid);\n };\n}\n\nexport function runAgentWorker(\n scope: AgentWorkerScope,\n options: AgentWorkerOptions = {}\n): Promise<AgentHost> {\n const vault = new Vault();\n listenVault(scope, vault);\n const host = start(scope, kernelPorts(scope), options, vault);\n host.catch(() => undefined);\n serveConnections(scope, host);\n return host;\n}\n"],
5
+ "mappings": "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",
6
6
  "names": []
7
7
  }
@@ -3,6 +3,9 @@ import { CONE_PREFIX } from "../kernel/accounts.js";
3
3
  import { resolve } from "../kernel/paths.js";
4
4
  import { agentOfUser, LEGACY, ROOT_USER } from "../layout.js";
5
5
  import { cronLick } from "../licks/crontab.js";
6
+ import { webhookDelivery } from "../licks/events.js";
7
+ import { LICK_CHANNELS } from "../licks/lick.js";
8
+ import { scopedName } from "../licks/sources.js";
6
9
  import { findRole } from "../roles/roles.js";
7
10
  import { findScoop, modelOf } from "./service.js";
8
11
  import { cancelSync, detachSync, runSync } from "./sync.js";
@@ -17,6 +20,7 @@ const USAGE = `usage:
17
20
  agent <cwd> <allowed-commands> <prompt> the same as a synchronous run, in v6's form
18
21
  agent list [--agents] | status <handle> | rename <handle> <name>
19
22
  agent send <handle> [--follow-up] (<message> | --file <path> | -)
23
+ agent send <target> --lick=<cron|webhook> [--source <name>] (<message> | --file <path> | -)
20
24
  agent send parent <note> from a scoop: a progress note to its cone
21
25
  agent wait <handle>... [--timeout <seconds>] [--notify]
22
26
  agent stop <handle>
@@ -276,9 +280,8 @@ async function send(deps, request, who, context) {
276
280
  context
277
281
  );
278
282
  }
279
- function cronTarget(deps, request) {
283
+ function cronTarget(deps, request, name) {
280
284
  const state = deps.agents.state();
281
- const name = request.argv[1] ?? "";
282
285
  if (!name) return fail("send needs cone or a scoop handle", 2);
283
286
  const user = request.user && request.user !== ROOT_USER ? request.user : void 0;
284
287
  const own = user ? agentOfUser(state, user) : void 0;
@@ -293,17 +296,71 @@ function cronTarget(deps, request) {
293
296
  if (name === "cone") return home;
294
297
  return findScoop(state, name, cone)?.[0] ?? home;
295
298
  }
296
- async function cronSend(deps, request, run, context) {
297
- if (!deps.licks) return fail("licks are not available in this agent");
298
- const parsed = flags(request.argv.slice(2), ["--file"]);
299
- const unknown = [...parsed.switches].find((flag) => flag !== "--follow-up");
300
- if (unknown) return fail(`unknown option ${unknown}`, 2);
301
- const target = cronTarget(deps, request);
299
+ const PROCESS_LICKS = ["cron", "webhook"];
300
+ function expanded(argv) {
301
+ return argv.flatMap((arg) => {
302
+ const at = arg.indexOf("=");
303
+ const name = arg.slice(0, at);
304
+ return at > 0 && (name === "--lick" || name === "--source") ? [name, arg.slice(at + 1)] : [arg];
305
+ });
306
+ }
307
+ function refusedChannel(channel) {
308
+ const own = LICK_CHANNELS.includes(channel);
309
+ const what = own ? `--lick=${channel} is the agent's own channel` : `there is no lick channel "${channel}"`;
310
+ return fail(
311
+ `${what}; a process may send ${PROCESS_LICKS.map((name) => `--lick=${name}`).join(" or ")}`,
312
+ 2
313
+ );
314
+ }
315
+ async function cronSend(deps, licks, request, parsed, context) {
316
+ if (!request.cron)
317
+ return fail("--lick=cron only works inside a cron job, which sets SLICC_CRON_JOB");
318
+ if (last(parsed, "--source") !== void 0)
319
+ return fail("--source is for --lick=webhook; a cron lick is named by its job's # name:", 2);
320
+ const target = cronTarget(deps, request, parsed.rest[0] ?? "");
302
321
  if (isAnswer(target)) return target;
303
- const text = (await message(deps, parsed, request, context)).trim();
304
- await deps.licks.deliver(cronLick(run, target, text), context);
322
+ const text = (await message(deps, unnamed(parsed), request, context)).trim();
323
+ await licks.deliver(cronLick(request.cron, target, text), context);
305
324
  return ok("");
306
325
  }
326
+ function webhookScope(deps, request) {
327
+ const user = request.user && request.user !== ROOT_USER ? request.user : void 0;
328
+ if (!user) return null;
329
+ const own = agentOfUser(deps.agents.state(), user);
330
+ if (!own) return fail(`${user} is no cone or scoop`);
331
+ if (own.startsWith("scoop:")) return fail("a scoop can't send webhook licks; its cone can");
332
+ return own.slice(CONE_PREFIX.length);
333
+ }
334
+ async function webhookSend(deps, request, parsed, context) {
335
+ if (!deps.webhook) return fail("webhooks are not available in this agent");
336
+ const source = last(parsed, "--source");
337
+ if (!source)
338
+ return fail("--lick=webhook needs --source <name>, for ~/.slicc/webhooks/<name>.json", 2);
339
+ if (parsed.rest[0] !== "cone")
340
+ return fail("a webhook lick goes to the cone: agent send cone --lick=webhook \u2026", 2);
341
+ const scope = webhookScope(deps, request);
342
+ if (isAnswer(scope)) return scope;
343
+ const text = await message(deps, unnamed(parsed), request, context);
344
+ if (!text.trim()) return fail("send needs a message, --file or -", 2);
345
+ const delivered = await deps.webhook(
346
+ scopedName(source, scope),
347
+ webhookDelivery(text.trimEnd()),
348
+ context
349
+ );
350
+ return delivered ? ok("") : fail(`there is no webhook ${source}; add ~/.slicc/webhooks/${source}.json`);
351
+ }
352
+ function unnamed(parsed) {
353
+ return { ...parsed, rest: parsed.rest.slice(1) };
354
+ }
355
+ async function lickSend(deps, request, context) {
356
+ const parsed = flags(request.argv.slice(1), ["--file", "--lick", "--source"]);
357
+ const unknown = [...parsed.switches][0];
358
+ if (unknown) return fail(`unknown option ${unknown}`, 2);
359
+ const channel = last(parsed, "--lick") ?? "";
360
+ if (!PROCESS_LICKS.includes(channel)) return refusedChannel(channel);
361
+ if (!deps.licks) return fail("licks are not available in this agent");
362
+ return channel === "cron" ? cronSend(deps, deps.licks, request, parsed, context) : webhookSend(deps, request, parsed, context);
363
+ }
307
364
  async function latest(deps, record, context) {
308
365
  const dir = deps.layout.reports(record.folder, record.cone);
309
366
  const listed = await deps.env.listDir(dir, context);
@@ -453,8 +510,9 @@ function createCli(options) {
453
510
  },
454
511
  async run(request, context) {
455
512
  try {
456
- if (request.cron && request.as === "agent" && request.argv[0] === "send")
457
- return await cronSend(deps, request, request.cron, context);
513
+ const argv = expanded(request.argv);
514
+ if (request.as === "agent" && argv[0] === "send" && argv.includes("--lick"))
515
+ return await lickSend(deps, { ...request, argv }, context);
458
516
  return await dispatch(deps, request, callerOf(options.agents, request), context);
459
517
  } catch (error) {
460
518
  return fail(error.message);