@ai-ecoverse/slicc-agent 3.48.1 → 3.49.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 (86) hide show
  1. package/README.md +27 -1
  2. package/bin/agent +1 -0
  3. package/dist/control.js +1 -1
  4. package/dist/control.js.map +2 -2
  5. package/dist/freezer/index.js +29 -8
  6. package/dist/freezer/index.js.map +2 -2
  7. package/dist/freezer/title.js +2 -2
  8. package/dist/freezer/title.js.map +2 -2
  9. package/dist/gelatiere/catalog.js +1 -1
  10. package/dist/gelatiere/catalog.js.map +2 -2
  11. package/dist/gelatiere/index.js +44 -21
  12. package/dist/gelatiere/index.js.map +2 -2
  13. package/dist/gelatiere/store.js +9 -5
  14. package/dist/gelatiere/store.js.map +2 -2
  15. package/dist/index.js.map +2 -2
  16. package/dist/kernel/accounts.js +141 -0
  17. package/dist/kernel/accounts.js.map +7 -0
  18. package/dist/kernel/agent-users.js +180 -0
  19. package/dist/kernel/agent-users.js.map +7 -0
  20. package/dist/kernel/env.js +9 -3
  21. package/dist/kernel/env.js.map +2 -2
  22. package/dist/kernel/users.js +16 -1
  23. package/dist/kernel/users.js.map +2 -2
  24. package/dist/layout.js +62 -0
  25. package/dist/layout.js.map +7 -0
  26. package/dist/licks/index.js.map +2 -2
  27. package/dist/licks/sources.js +69 -20
  28. package/dist/licks/sources.js.map +2 -2
  29. package/dist/main.js +70 -36
  30. package/dist/main.js.map +2 -2
  31. package/dist/mcp/index.js +5 -3
  32. package/dist/mcp/index.js.map +2 -2
  33. package/dist/mcp/paths.js +15 -0
  34. package/dist/mcp/paths.js.map +7 -0
  35. package/dist/mcp/runtime.js +16 -14
  36. package/dist/mcp/runtime.js.map +3 -3
  37. package/dist/memory/extract.js +2 -1
  38. package/dist/memory/extract.js.map +2 -2
  39. package/dist/memory/prompt.js +5 -1
  40. package/dist/memory/prompt.js.map +2 -2
  41. package/dist/memory/runtime.js +9 -1
  42. package/dist/memory/runtime.js.map +2 -2
  43. package/dist/scoops/cli.js +40 -19
  44. package/dist/scoops/cli.js.map +2 -2
  45. package/dist/scoops/extension.js +19 -15
  46. package/dist/scoops/extension.js.map +2 -2
  47. package/dist/scoops/index.js +75 -9
  48. package/dist/scoops/index.js.map +2 -2
  49. package/dist/scoops/requests.js +2 -1
  50. package/dist/scoops/requests.js.map +2 -2
  51. package/dist/scoops/service.js +45 -38
  52. package/dist/scoops/service.js.map +2 -2
  53. package/dist/scoops/sync.js +63 -13
  54. package/dist/scoops/sync.js.map +2 -2
  55. package/dist/skills/index.js +67 -22
  56. package/dist/skills/index.js.map +3 -3
  57. package/dist/sprinkles/index.js +114 -25
  58. package/dist/sprinkles/index.js.map +2 -2
  59. package/dist/sprinkles/sprinkles.js +13 -4
  60. package/dist/sprinkles/sprinkles.js.map +2 -2
  61. package/dist/types/freezer/index.d.ts +3 -1
  62. package/dist/types/freezer/title.d.ts +1 -1
  63. package/dist/types/gelatiere/index.d.ts +8 -0
  64. package/dist/types/gelatiere/store.d.ts +3 -2
  65. package/dist/types/index.d.ts +1 -1
  66. package/dist/types/kernel/accounts.d.ts +29 -0
  67. package/dist/types/kernel/agent-users.d.ts +37 -0
  68. package/dist/types/kernel/env.d.ts +6 -0
  69. package/dist/types/kernel/users.d.ts +15 -0
  70. package/dist/types/layout.d.ts +26 -0
  71. package/dist/types/licks/index.d.ts +2 -1
  72. package/dist/types/licks/sources.d.ts +11 -1
  73. package/dist/types/mcp/paths.d.ts +3 -0
  74. package/dist/types/mcp/runtime.d.ts +3 -3
  75. package/dist/types/memory/prompt.d.ts +1 -0
  76. package/dist/types/memory/runtime.d.ts +1 -0
  77. package/dist/types/scoops/cli.d.ts +5 -0
  78. package/dist/types/scoops/extension.d.ts +6 -3
  79. package/dist/types/scoops/index.d.ts +9 -0
  80. package/dist/types/scoops/requests.d.ts +2 -0
  81. package/dist/types/scoops/service.d.ts +5 -3
  82. package/dist/types/scoops/sync.d.ts +9 -6
  83. package/dist/types/skills/index.d.ts +10 -2
  84. package/dist/types/sprinkles/index.d.ts +15 -0
  85. package/dist/types/sprinkles/sprinkles.d.ts +7 -1
  86. package/package.json +2 -2
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../src/gelatiere/catalog.ts"],
4
- "sourcesContent": ["import type { Context } from '@earendil-works/chord';\nimport type { ExecutionEnv } from '@earendil-works/pi-durable/env';\nimport { redactSecrets } from '../memory/format.ts';\nimport { STORE_DIR } from './store.ts';\n\nexport const CATALOG_BASE = 'https://www.sliccy.com/skills/';\nexport const CATALOG_DIR = `${STORE_DIR}/catalog`;\nexport const PROFILE = '.welcome.json';\nexport const MAX_AGE = 12 * 60 * 60 * 1000;\nconst MAX_BYTES = 1024 * 1024;\nconst WEIGHTS = { apps: 3, tasks: 2, role: 1, purpose: 1 };\nconst REPO = /^[A-Za-z0-9][A-Za-z0-9-]{0,38}\\/[A-Za-z0-9._-]{1,100}$/;\nconst SKILL = /^[A-Za-z0-9][A-Za-z0-9 ._-]{0,79}$/;\nconst PATH = /^(?!.*\\.\\.)[A-Za-z0-9._/-]{1,200}$/;\nconst NAME = /^[a-z0-9][a-z0-9-]{0,55}$/;\n\nexport type Row = Record<string, string>;\n\nexport interface Profile {\n purpose: string;\n role: string;\n tasks: string[];\n apps: string[];\n company?: string;\n}\n\nexport interface Affinity {\n apps: string[];\n tasks: string[];\n role: string[];\n purpose: string[];\n}\n\nexport interface CatalogSkill {\n name: string;\n title: string;\n description: string;\n repo: string;\n skill?: string;\n path?: string;\n all: boolean;\n affinity: Affinity;\n boost?: number;\n}\n\nexport interface CatalogUseCase {\n name: string;\n title: string;\n description: string;\n prompt: string;\n skills: string[];\n affinity: Affinity;\n boost?: number;\n}\n\nexport type Fetcher = (url: string, init?: RequestInit) => Promise<Response>;\n\nexport type Freshness = 'fresh' | 'cached' | 'missing' | 'unavailable';\n\nexport interface Sheet {\n url: string;\n rows: Row[];\n state: Freshness;\n fetchedAt?: number;\n}\n\nfunction words(value: unknown): string[] {\n if (typeof value !== 'string') return [];\n return value\n .split(',')\n .map((part) => part.trim())\n .filter(Boolean);\n}\n\nfunction clean(value: unknown, limit: number): string {\n if (typeof value !== 'string') return '';\n return redactSecrets(value.trim()).text.slice(0, limit);\n}\n\nfunction boostOf(value: unknown): number | undefined {\n const parsed = typeof value === 'string' && value.trim() ? Number.parseFloat(value) : Number.NaN;\n return Number.isFinite(parsed) ? parsed : undefined;\n}\n\nfunction affinityOf(row: Row): Affinity {\n return {\n apps: words(row.apps),\n tasks: words(row.tasks),\n role: words(row.role),\n purpose: words(row.purpose),\n };\n}\n\nfunction nameOf(value: unknown): string | undefined {\n const name = typeof value === 'string' ? value.trim().toLowerCase() : '';\n return NAME.test(name) ? name : undefined;\n}\n\nexport function truthy(value: unknown): boolean {\n return typeof value === 'string' && ['true', '1', 'yes'].includes(value.trim().toLowerCase());\n}\n\nexport function parseSkills(rows: readonly Row[]): CatalogSkill[] {\n const out: CatalogSkill[] = [];\n for (const row of rows) {\n const name = nameOf(row.name);\n const repo = typeof row.repo === 'string' ? row.repo.trim() : '';\n const skill = typeof row.skill === 'string' ? row.skill.trim() : '';\n const path = typeof row.path === 'string' ? row.path.trim() : '';\n const all = truthy(row.installAll);\n if (!name || !REPO.test(repo)) continue;\n if (!all && !SKILL.test(skill)) continue;\n if (path && !PATH.test(path)) continue;\n const boost = boostOf(row.boost);\n out.push({\n name,\n title: clean(row.displayName, 80) || name,\n description: clean(row.description, 500),\n repo,\n ...(all ? {} : { skill }),\n ...(path ? { path } : {}),\n all,\n affinity: affinityOf(row),\n ...(boost === undefined ? {} : { boost }),\n });\n }\n return out;\n}\n\nexport function parseUseCases(rows: readonly Row[]): CatalogUseCase[] {\n const out: CatalogUseCase[] = [];\n for (const row of rows) {\n const name = nameOf(row.name);\n const prompt = clean(row.prompt, 1000);\n if (!name || !prompt) continue;\n const boost = boostOf(row.boost);\n out.push({\n name,\n title: clean(row.displayName, 80) || name,\n description: clean(row.description, 500),\n prompt,\n skills: words(row.skills),\n affinity: affinityOf(row),\n ...(boost === undefined ? {} : { boost }),\n });\n }\n return out;\n}\n\nexport function merge(base: CatalogSkill[], company: CatalogSkill[]): CatalogSkill[] {\n const names = new Set(company.map((entry) => entry.name));\n return [...base.filter((entry) => !names.has(entry.name)), ...company];\n}\n\nexport function slugifyCompany(company: unknown): string | null {\n if (typeof company !== 'string' || !company) return null;\n const slug = company\n .toLowerCase()\n .trim()\n .replace(/[^a-z0-9]+/g, '-')\n .replace(/(^-+|-+$)/g, '');\n return slug || null;\n}\n\nexport function profileOf(value: unknown): Profile | undefined {\n if (!value || typeof value !== 'object') return undefined;\n const raw = value as Record<string, unknown>;\n const list = (field: unknown) =>\n Array.isArray(field) ? field.filter((item): item is string => typeof item === 'string') : [];\n const text = (field: unknown) => (typeof field === 'string' ? field : '');\n return {\n purpose: text(raw.purpose),\n role: text(raw.role),\n tasks: list(raw.tasks),\n apps: list(raw.apps),\n ...(typeof raw.company === 'string' && raw.company ? { company: raw.company } : {}),\n };\n}\n\nexport interface Scored {\n score: number;\n reasons: string[];\n}\n\nexport function score(\n entry: { affinity: Affinity; boost?: number },\n profile: Profile | undefined\n): Scored {\n if (!profile) return { score: entry.boost ?? 1, reasons: [] };\n let total = 0;\n const reasons: string[] = [];\n const apps = entry.affinity.apps.filter((app) => profile.apps.includes(app));\n if (apps.length) {\n total += apps.length * WEIGHTS.apps;\n reasons.push(`apps(${apps.join(', ')})`);\n }\n const tasks = entry.affinity.tasks.filter((task) => profile.tasks.includes(task));\n if (tasks.length) {\n total += tasks.length * WEIGHTS.tasks;\n reasons.push(`tasks(${tasks.join(', ')})`);\n }\n if (profile.role && entry.affinity.role.includes(profile.role)) {\n total += WEIGHTS.role;\n reasons.push(`role(${profile.role})`);\n }\n if (profile.purpose && entry.affinity.purpose.includes(profile.purpose)) {\n total += WEIGHTS.purpose;\n reasons.push(`purpose(${profile.purpose})`);\n }\n return { score: total * (entry.boost ?? 1), reasons };\n}\n\nfunction rowsOf(value: unknown): Row[] | undefined {\n const data = (value as { data?: unknown } | null)?.data;\n if (!Array.isArray(data)) return undefined;\n return data.filter((row): row is Row => Boolean(row) && typeof row === 'object');\n}\n\nasync function download(\n fetcher: Fetcher,\n url: string\n): Promise<{ rows: Row[] } | 'missing' | undefined> {\n try {\n const response = await fetcher(url, { headers: { accept: 'application/json' } });\n if (response.status === 404) return 'missing';\n if (response.status !== 200) return undefined;\n const text = await response.text();\n if (text.length > MAX_BYTES) return undefined;\n const rows = rowsOf(JSON.parse(text));\n return rows ? { rows } : undefined;\n } catch {\n return undefined;\n }\n}\n\ninterface Cached {\n url: string;\n fetchedAt: number;\n rows: Row[];\n}\n\nasync function cached(\n env: Pick<ExecutionEnv, 'readTextFile'>,\n file: string,\n url: string,\n context: Context\n): Promise<Cached | undefined> {\n const read = await env.readTextFile(file, context);\n if (!read.ok) return undefined;\n try {\n const parsed = JSON.parse(read.value) as Cached;\n return parsed.url === url && typeof parsed.fetchedAt === 'number' && Array.isArray(parsed.rows)\n ? parsed\n : undefined;\n } catch {\n return undefined;\n }\n}\n\nexport interface SheetOptions {\n env: Pick<ExecutionEnv, 'readTextFile' | 'writeFile' | 'createDir'>;\n fetcher: Fetcher;\n now: number;\n refresh: boolean;\n}\n\nexport async function sheet(\n options: SheetOptions,\n url: string,\n file: string,\n context: Context\n): Promise<Sheet> {\n const { env, fetcher, now, refresh } = options;\n const kept = await cached(env, file, url, context);\n if (kept && !refresh && now - kept.fetchedAt < MAX_AGE)\n return {\n url,\n rows: kept.rows,\n state: kept.rows.length ? 'fresh' : 'missing',\n fetchedAt: kept.fetchedAt,\n };\n const got = await download(fetcher, url);\n if (got === undefined)\n return kept\n ? { url, rows: kept.rows, state: 'cached', fetchedAt: kept.fetchedAt }\n : { url, rows: [], state: 'unavailable' };\n const rows = got === 'missing' ? [] : got.rows;\n await env.createDir(CATALOG_DIR, { recursive: true }, context);\n await env.writeFile(file, `${JSON.stringify({ url, fetchedAt: now, rows })}\\n`, context);\n return { url, rows, state: got === 'missing' ? 'missing' : 'fresh', fetchedAt: now };\n}\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["import type { Context } from '@earendil-works/chord';\nimport type { ExecutionEnv } from '@earendil-works/pi-durable/env';\nimport { redactSecrets } from '../memory/format.ts';\nimport { STORE_DIR } from './store.ts';\n\nexport const CATALOG_BASE = 'https://www.sliccy.com/skills/';\nexport const CATALOG_DIR = `${STORE_DIR}/catalog`;\nexport const PROFILE = '.welcome.json';\nexport const MAX_AGE = 12 * 60 * 60 * 1000;\nconst MAX_BYTES = 1024 * 1024;\nconst WEIGHTS = { apps: 3, tasks: 2, role: 1, purpose: 1 };\nconst REPO = /^[A-Za-z0-9][A-Za-z0-9-]{0,38}\\/[A-Za-z0-9._-]{1,100}$/;\nconst SKILL = /^[A-Za-z0-9][A-Za-z0-9 ._-]{0,79}$/;\nconst PATH = /^(?!.*\\.\\.)[A-Za-z0-9._/-]{1,200}$/;\nconst NAME = /^[a-z0-9][a-z0-9-]{0,55}$/;\n\nexport type Row = Record<string, string>;\n\nexport interface Profile {\n purpose: string;\n role: string;\n tasks: string[];\n apps: string[];\n company?: string;\n}\n\nexport interface Affinity {\n apps: string[];\n tasks: string[];\n role: string[];\n purpose: string[];\n}\n\nexport interface CatalogSkill {\n name: string;\n title: string;\n description: string;\n repo: string;\n skill?: string;\n path?: string;\n all: boolean;\n affinity: Affinity;\n boost?: number;\n}\n\nexport interface CatalogUseCase {\n name: string;\n title: string;\n description: string;\n prompt: string;\n skills: string[];\n affinity: Affinity;\n boost?: number;\n}\n\nexport type Fetcher = (url: string, init?: RequestInit) => Promise<Response>;\n\nexport type Freshness = 'fresh' | 'cached' | 'missing' | 'unavailable';\n\nexport interface Sheet {\n url: string;\n rows: Row[];\n state: Freshness;\n fetchedAt?: number;\n}\n\nfunction words(value: unknown): string[] {\n if (typeof value !== 'string') return [];\n return value\n .split(',')\n .map((part) => part.trim())\n .filter(Boolean);\n}\n\nfunction clean(value: unknown, limit: number): string {\n if (typeof value !== 'string') return '';\n return redactSecrets(value.trim()).text.slice(0, limit);\n}\n\nfunction boostOf(value: unknown): number | undefined {\n const parsed = typeof value === 'string' && value.trim() ? Number.parseFloat(value) : Number.NaN;\n return Number.isFinite(parsed) ? parsed : undefined;\n}\n\nfunction affinityOf(row: Row): Affinity {\n return {\n apps: words(row.apps),\n tasks: words(row.tasks),\n role: words(row.role),\n purpose: words(row.purpose),\n };\n}\n\nfunction nameOf(value: unknown): string | undefined {\n const name = typeof value === 'string' ? value.trim().toLowerCase() : '';\n return NAME.test(name) ? name : undefined;\n}\n\nexport function truthy(value: unknown): boolean {\n return typeof value === 'string' && ['true', '1', 'yes'].includes(value.trim().toLowerCase());\n}\n\nexport function parseSkills(rows: readonly Row[]): CatalogSkill[] {\n const out: CatalogSkill[] = [];\n for (const row of rows) {\n const name = nameOf(row.name);\n const repo = typeof row.repo === 'string' ? row.repo.trim() : '';\n const skill = typeof row.skill === 'string' ? row.skill.trim() : '';\n const path = typeof row.path === 'string' ? row.path.trim() : '';\n const all = truthy(row.installAll);\n if (!name || !REPO.test(repo)) continue;\n if (!all && !SKILL.test(skill)) continue;\n if (path && !PATH.test(path)) continue;\n const boost = boostOf(row.boost);\n out.push({\n name,\n title: clean(row.displayName, 80) || name,\n description: clean(row.description, 500),\n repo,\n ...(all ? {} : { skill }),\n ...(path ? { path } : {}),\n all,\n affinity: affinityOf(row),\n ...(boost === undefined ? {} : { boost }),\n });\n }\n return out;\n}\n\nexport function parseUseCases(rows: readonly Row[]): CatalogUseCase[] {\n const out: CatalogUseCase[] = [];\n for (const row of rows) {\n const name = nameOf(row.name);\n const prompt = clean(row.prompt, 1000);\n if (!name || !prompt) continue;\n const boost = boostOf(row.boost);\n out.push({\n name,\n title: clean(row.displayName, 80) || name,\n description: clean(row.description, 500),\n prompt,\n skills: words(row.skills),\n affinity: affinityOf(row),\n ...(boost === undefined ? {} : { boost }),\n });\n }\n return out;\n}\n\nexport function merge(base: CatalogSkill[], company: CatalogSkill[]): CatalogSkill[] {\n const names = new Set(company.map((entry) => entry.name));\n return [...base.filter((entry) => !names.has(entry.name)), ...company];\n}\n\nexport function slugifyCompany(company: unknown): string | null {\n if (typeof company !== 'string' || !company) return null;\n const slug = company\n .toLowerCase()\n .trim()\n .replace(/[^a-z0-9]+/g, '-')\n .replace(/(^-+|-+$)/g, '');\n return slug || null;\n}\n\nexport function profileOf(value: unknown): Profile | undefined {\n if (!value || typeof value !== 'object') return undefined;\n const raw = value as Record<string, unknown>;\n const list = (field: unknown) =>\n Array.isArray(field) ? field.filter((item): item is string => typeof item === 'string') : [];\n const text = (field: unknown) => (typeof field === 'string' ? field : '');\n return {\n purpose: text(raw.purpose),\n role: text(raw.role),\n tasks: list(raw.tasks),\n apps: list(raw.apps),\n ...(typeof raw.company === 'string' && raw.company ? { company: raw.company } : {}),\n };\n}\n\nexport interface Scored {\n score: number;\n reasons: string[];\n}\n\nexport function score(\n entry: { affinity: Affinity; boost?: number },\n profile: Profile | undefined\n): Scored {\n if (!profile) return { score: entry.boost ?? 1, reasons: [] };\n let total = 0;\n const reasons: string[] = [];\n const apps = entry.affinity.apps.filter((app) => profile.apps.includes(app));\n if (apps.length) {\n total += apps.length * WEIGHTS.apps;\n reasons.push(`apps(${apps.join(', ')})`);\n }\n const tasks = entry.affinity.tasks.filter((task) => profile.tasks.includes(task));\n if (tasks.length) {\n total += tasks.length * WEIGHTS.tasks;\n reasons.push(`tasks(${tasks.join(', ')})`);\n }\n if (profile.role && entry.affinity.role.includes(profile.role)) {\n total += WEIGHTS.role;\n reasons.push(`role(${profile.role})`);\n }\n if (profile.purpose && entry.affinity.purpose.includes(profile.purpose)) {\n total += WEIGHTS.purpose;\n reasons.push(`purpose(${profile.purpose})`);\n }\n return { score: total * (entry.boost ?? 1), reasons };\n}\n\nfunction rowsOf(value: unknown): Row[] | undefined {\n const data = (value as { data?: unknown } | null)?.data;\n if (!Array.isArray(data)) return undefined;\n return data.filter((row): row is Row => Boolean(row) && typeof row === 'object');\n}\n\nasync function download(\n fetcher: Fetcher,\n url: string\n): Promise<{ rows: Row[] } | 'missing' | undefined> {\n try {\n const response = await fetcher(url, { headers: { accept: 'application/json' } });\n if (response.status === 404) return 'missing';\n if (response.status !== 200) return undefined;\n const text = await response.text();\n if (text.length > MAX_BYTES) return undefined;\n const rows = rowsOf(JSON.parse(text));\n return rows ? { rows } : undefined;\n } catch {\n return undefined;\n }\n}\n\ninterface Cached {\n url: string;\n fetchedAt: number;\n rows: Row[];\n}\n\nasync function cached(\n env: Pick<ExecutionEnv, 'readTextFile'>,\n file: string,\n url: string,\n context: Context\n): Promise<Cached | undefined> {\n const read = await env.readTextFile(file, context);\n if (!read.ok) return undefined;\n try {\n const parsed = JSON.parse(read.value) as Cached;\n return parsed.url === url && typeof parsed.fetchedAt === 'number' && Array.isArray(parsed.rows)\n ? parsed\n : undefined;\n } catch {\n return undefined;\n }\n}\n\nexport interface SheetOptions {\n env: Pick<ExecutionEnv, 'readTextFile' | 'writeFile' | 'createDir'>;\n fetcher: Fetcher;\n now: number;\n refresh: boolean;\n}\n\nexport async function sheet(\n options: SheetOptions,\n url: string,\n file: string,\n context: Context\n): Promise<Sheet> {\n const { env, fetcher, now, refresh } = options;\n const kept = await cached(env, file, url, context);\n if (kept && !refresh && now - kept.fetchedAt < MAX_AGE)\n return {\n url,\n rows: kept.rows,\n state: kept.rows.length ? 'fresh' : 'missing',\n fetchedAt: kept.fetchedAt,\n };\n const got = await download(fetcher, url);\n if (got === undefined)\n return kept\n ? { url, rows: kept.rows, state: 'cached', fetchedAt: kept.fetchedAt }\n : { url, rows: [], state: 'unavailable' };\n const rows = got === 'missing' ? [] : got.rows;\n await env.createDir(file.slice(0, file.lastIndexOf('/')), { recursive: true }, context);\n await env.writeFile(file, `${JSON.stringify({ url, fetchedAt: now, rows })}\\n`, context);\n return { url, rows, state: got === 'missing' ? 'missing' : 'fresh', fetchedAt: now };\n}\n"],
5
+ "mappings": "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",
6
6
  "names": []
7
7
  }
@@ -13,7 +13,15 @@ import {
13
13
  sheet,
14
14
  slugifyCompany
15
15
  } from "./catalog.js";
16
- import { fold, open, readStore, STORE, validate, writeStore } from "./store.js";
16
+ import {
17
+ fold,
18
+ open,
19
+ readStore,
20
+ STORE,
21
+ storeOf,
22
+ validate,
23
+ writeStore
24
+ } from "./store.js";
17
25
  const ROLE = "gelatiere";
18
26
  const SPRINKLE = "suggestions";
19
27
  const PROCEDURE = "packages/vfs-root/gelatiere/GELATIERE.md";
@@ -49,10 +57,14 @@ function row(item) {
49
57
  const state = item.takenAt ? "taken" : item.dismissedAt ? "dismissed" : "open";
50
58
  return `${item.id} ${item.kind} ${state} ${item.title}`;
51
59
  }
60
+ async function callerOf(g, context) {
61
+ return await g.options.as?.(g.caller, context) ?? { env: g.options.env, home: g.options.home };
62
+ }
52
63
  const fail = (out) => ({ code: 1, out: `gelatiere: ${out}
53
64
  ` });
54
65
  async function schedule(g, handle, context) {
55
- const { env, home } = g.options;
66
+ const { home } = g.options;
67
+ const env = g.files;
56
68
  const read = await env.readTextFile(g.crontab, context);
57
69
  const kept = (read.ok ? read.value : "").split("\n").filter((entry) => entry.trim() && !scheduleOf(entry));
58
70
  await env.createDir(`${home}/.slicc`, { recursive: true }, context);
@@ -70,7 +82,8 @@ async function sha256(text) {
70
82
  return [...new Uint8Array(digest)].map((byte) => byte.toString(16).padStart(2, "0")).join("");
71
83
  }
72
84
  async function seed(g, context, create) {
73
- const { env, assets } = g.options;
85
+ const { assets } = g.options;
86
+ const env = g.files;
74
87
  const text = assets ? await assets(PROCEDURE).catch(() => void 0) : void 0;
75
88
  if (text === void 0) return "none";
76
89
  const bundled = await sha256(text);
@@ -145,7 +158,7 @@ async function run(g, context) {
145
158
  }
146
159
  async function suggest(g, path, context) {
147
160
  if (!path) return { code: 2, out: USAGE };
148
- const read = await g.options.env.readTextFile(path, context);
161
+ const read = await (await callerOf(g, context)).env.readTextFile(path, context);
149
162
  if (!read.ok) return fail(`can't read ${path}`);
150
163
  let parsed;
151
164
  try {
@@ -154,7 +167,7 @@ async function suggest(g, path, context) {
154
167
  return fail(`${path} is not JSON (${error.message})`);
155
168
  }
156
169
  const folded = fold(await g.load(context), parsed, g.now());
157
- await writeStore(g.options.env, folded.store, context);
170
+ await writeStore(g.options.env, folded.store, context, g.store);
158
171
  const rejected = folded.rejected.map((reason) => `rejected ${reason}
159
172
  `).join("");
160
173
  return {
@@ -183,7 +196,7 @@ async function deliver(g, context) {
183
196
  title,
184
197
  body: text
185
198
  })),
186
- path: STORE
199
+ path: g.store
187
200
  };
188
201
  await g.options.licks.deliver(
189
202
  {
@@ -198,7 +211,7 @@ async function deliver(g, context) {
198
211
  );
199
212
  }
200
213
  for (const item of fresh) item.deliveredAt = g.now();
201
- if (fresh.length) await writeStore(g.options.env, store, context);
214
+ if (fresh.length) await writeStore(g.options.env, store, context, g.store);
202
215
  return {
203
216
  code: 0,
204
217
  out: `delivered ${fresh.length} to ${[...byCone.keys()].join(", ") || "nobody"}
@@ -228,7 +241,7 @@ async function skillsIn(env, home, context) {
228
241
  return found;
229
242
  }
230
243
  async function install(g, id, context) {
231
- const { env, home } = g.options;
244
+ const { env, home } = await callerOf(g, context);
232
245
  const item = (await g.load(context)).find((entry) => entry.id === id && entry.kind === "skill");
233
246
  const checked = item ? validate(item) : `there is no skill suggestion ${id}`;
234
247
  if (typeof checked === "string") return fail(checked);
@@ -261,7 +274,10 @@ ${output}` : ""}`
261
274
  };
262
275
  }
263
276
  async function profileFor(g, context) {
264
- const read = await g.options.env.readTextFile(`${g.options.home}/${PROFILE}`, context);
277
+ const read = await g.options.env.readTextFile(
278
+ `${g.options.profile ?? g.options.home}/${PROFILE}`,
279
+ context
280
+ );
265
281
  if (!read.ok) return void 0;
266
282
  try {
267
283
  return profileOf(JSON.parse(read.value));
@@ -274,7 +290,9 @@ function sourceLine(label, found) {
274
290
  return `${label}: ${found.state} (${found.url}${at})`;
275
291
  }
276
292
  async function catalog(g, argv, context) {
277
- const { env, home } = g.options;
293
+ const { env } = g.options;
294
+ const home = g.options.profile ?? g.options.home;
295
+ const mine = await callerOf(g, context);
278
296
  const base = g.options.catalog ?? CATALOG_BASE;
279
297
  const fetcher = g.options.fetch ?? ((url, init2) => globalThis.fetch(url, init2));
280
298
  const options = { env, fetcher, now: g.now(), refresh: argv.includes("--refresh") };
@@ -282,14 +300,14 @@ async function catalog(g, argv, context) {
282
300
  const slug = slugifyCompany(profile?.company);
283
301
  const company = slug && !["catalog", "use-cases"].includes(slug) ? slug : null;
284
302
  const [global, own, cases] = await Promise.all([
285
- sheet(options, `${base}catalog.json`, `${CATALOG_DIR}/catalog.json`, context),
286
- company ? sheet(options, `${base}${company}.json`, `${CATALOG_DIR}/company-${company}.json`, context) : void 0,
287
- sheet(options, `${base}use-cases.json`, `${CATALOG_DIR}/use-cases.json`, context)
303
+ sheet(options, `${base}catalog.json`, `${g.catalog}/catalog.json`, context),
304
+ company ? sheet(options, `${base}${company}.json`, `${g.catalog}/company-${company}.json`, context) : void 0,
305
+ sheet(options, `${base}use-cases.json`, `${g.catalog}/use-cases.json`, context)
288
306
  ]);
289
307
  const store = await g.load(context);
290
308
  const closed = new Set(store.filter((item) => item.dismissedAt || item.takenAt).map((i) => i.id));
291
309
  const have = /* @__PURE__ */ new Set([
292
- ...(await skillsIn(env, home, context)).keys(),
310
+ ...(await skillsIn(mine.env, mine.home, context)).keys(),
293
311
  ...(g.options.skills?.() ?? []).map((entry) => entry.name)
294
312
  ]);
295
313
  const evidence = (reasons) => `www.sliccy.com catalog: ${reasons.length ? reasons.join(", ") : "featured"}`;
@@ -354,12 +372,12 @@ async function list(g, argv, context) {
354
372
  }
355
373
  async function status(g, context) {
356
374
  const { env, agents } = g.options;
357
- const store = await readStore(env, context);
375
+ const store = await readStore(env, context, g.store);
358
376
  const handle = handleOf(agents);
359
- const read = await env.readTextFile(g.crontab, context);
377
+ const read = await g.files.readTextFile(g.crontab, context);
360
378
  const scheduled = (read.ok ? read.value : "").split("\n").map(scheduleOf).find(Boolean);
361
379
  const counts = store ? `${open(store).length} open, ${store.filter((item) => item.takenAt).length} taken, ${store.filter((item) => item.dismissedAt).length} dismissed` : "none yet";
362
- const pending = await env.readTextFile(g.pending, context);
380
+ const pending = await g.files.readTextFile(g.pending, context);
363
381
  const lines = [
364
382
  `scoop: ${handle ?? "none (gelatiere init)"}`,
365
383
  `schedule: ${scheduled ?? "none"}`,
@@ -389,7 +407,8 @@ const VERBS = {
389
407
  function attachGelatiere(options) {
390
408
  const { env, home } = options;
391
409
  const now = options.now ?? Date.now;
392
- const load = async (context) => await readStore(env, context) ?? [];
410
+ const storeFile = options.shared ? storeOf(options.shared) : STORE;
411
+ const load = async (context) => await readStore(env, context, storeFile) ?? [];
393
412
  let chain = Promise.resolve();
394
413
  const serial = (work) => {
395
414
  const next = chain.catch(() => void 0).then(work);
@@ -403,24 +422,28 @@ function attachGelatiere(options) {
403
422
  crontab: `${home}/.slicc/crontab`,
404
423
  procedure: `${home}/.pi/agent/GELATIERE.md`,
405
424
  pending: `${home}/.pi/agent/GELATIERE.new.md`,
425
+ files: options.files ?? env,
426
+ caller: null,
427
+ store: storeFile,
428
+ catalog: options.shared ? `${options.shared}/.gelatiere/catalog` : CATALOG_DIR,
406
429
  load,
407
430
  mark: (id, field, context) => serial(async () => {
408
431
  const store = await load(context);
409
432
  const item = store.find((entry) => entry.id === id);
410
433
  if (!item) return false;
411
434
  item[field] ??= now();
412
- await writeStore(env, store, context);
435
+ await writeStore(env, store, context, storeFile);
413
436
  return true;
414
437
  })
415
438
  };
416
439
  const seeded = seed(g, BACKGROUND_CONTEXT, false).catch(() => "none");
417
440
  return {
418
441
  seeded,
419
- async command(argv, _caller, context) {
442
+ async command(argv, caller, context) {
420
443
  const verb = argv[0] ?? "help";
421
444
  const handler = VERBS[verb];
422
445
  await seeded;
423
- if (handler) return handler(g, argv, context);
446
+ if (handler) return handler({ ...g, caller }, argv, context);
424
447
  return { code: verb === "help" || verb === "--help" ? 0 : 2, out: USAGE };
425
448
  },
426
449
  async intercept(action, data, context) {
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../src/gelatiere/index.ts"],
4
- "sourcesContent": ["import type { Context } from '@earendil-works/chord';\nimport { BACKGROUND_CONTEXT } from '@earendil-works/chord/context';\nimport type { ExecutionEnv } from '@earendil-works/pi-durable/env';\nimport { type Agents, live } from '../agents.ts';\nimport type { Licks } from '../licks/licks.ts';\nimport type { Roles } from '../roles/roles.ts';\nimport type { Scoops } from '../scoops/service.ts';\nimport { skillFromText } from '../skills/skills.ts';\nimport {\n CATALOG_BASE,\n CATALOG_DIR,\n type Fetcher,\n merge,\n PROFILE,\n type Profile,\n parseSkills,\n parseUseCases,\n profileOf,\n type Sheet,\n score,\n sheet,\n slugifyCompany,\n} from './catalog.ts';\nimport { fold, open, readStore, STORE, type Suggestion, validate, writeStore } from './store.ts';\n\nexport type Answer = { code: number; out: string };\n\nexport const ROLE = 'gelatiere';\nexport const SPRINKLE = 'suggestions';\nexport const PROCEDURE = 'packages/vfs-root/gelatiere/GELATIERE.md';\nexport const SCHEDULE = '0 3 * * *';\n\nexport interface GelatiereAttach {\n agents: Agents;\n licks: Licks;\n env: ExecutionEnv;\n home: string;\n scoops: Scoops;\n roles: (context: Context) => Promise<Roles>;\n assets?: (path: string) => Promise<string>;\n now?: () => number;\n fetch?: Fetcher;\n catalog?: string;\n skills?: () => readonly { name: string }[];\n}\n\nexport interface GelatiereRuntime {\n command(argv: readonly string[], caller: string | null, context: Context): Promise<Answer>;\n intercept(action: string, data: unknown, context: Context): Promise<boolean>;\n readonly seeded: Promise<Seeded>;\n}\n\nexport const USAGE = `usage:\n gelatiere init start the gelatiere scoop and its nightly crontab line\n gelatiere run ask the gelatiere for a pass now\n gelatiere suggest <file> fold a JSON array of suggestions into the store\n gelatiere deliver lick each cone with the suggestions that are new for it\n gelatiere catalog [--refresh] [--all] [--json]\n rank the www.sliccy.com skill and use-case catalog for this user\n gelatiere install <id> install a suggested skill with upskill into ~/.pi/agent/skills\n gelatiere list [--all] [--json]\n gelatiere dismiss <id> mark a suggestion as not wanted\n gelatiere status\n\nThe store is ${STORE}; the suggestions sprinkle shows it.\n`;\n\nfunction line(handle: string): string {\n return `${SCHEDULE} ${ROLE} scoop:${handle} Nightly pass: read ~/.pi/agent/GELATIERE.md and follow it.`;\n}\n\nconst JOB = new RegExp(`^((?:\\\\S+\\\\s+){4}\\\\S+|@\\\\w+)\\\\s+${ROLE}(?:\\\\s|$)`);\n\nexport function scheduleOf(entry: string): string | undefined {\n return JOB.exec(entry.trim())?.[1]?.replace(/\\s+/g, ' ');\n}\n\nfunction handleOf(agents: Agents): string | undefined {\n const found = Object.entries(agents.state().scoops).find(\n ([, record]) => record.role === ROLE && live(record)\n );\n return found?.[1].folder;\n}\n\nfunction row(item: Suggestion): string {\n const state = item.takenAt ? 'taken' : item.dismissedAt ? 'dismissed' : 'open';\n return `${item.id}\\t${item.kind}\\t${state}\\t${item.title}`;\n}\n\ntype G = {\n serial: <T>(work: () => Promise<T>) => Promise<T>;\n options: GelatiereAttach;\n now: () => number;\n crontab: string;\n procedure: string;\n pending: string;\n load: (context: Context) => Promise<Suggestion[]>;\n mark: (id: string, field: 'dismissedAt' | 'takenAt', context: Context) => Promise<boolean>;\n};\n\nconst fail = (out: string): Answer => ({ code: 1, out: `gelatiere: ${out}\\n` });\n\nasync function schedule(g: G, handle: string, context: Context): Promise<void> {\n const { env, home } = g.options;\n const read = await env.readTextFile(g.crontab, context);\n const kept = (read.ok ? read.value : '')\n .split('\\n')\n .filter((entry) => entry.trim() && !scheduleOf(entry));\n await env.createDir(`${home}/.slicc`, { recursive: true }, context);\n await env.writeFile(g.crontab, `${[...kept, line(handle)].join('\\n')}\\n`, context);\n}\n\nexport const SHIPPED = [\n '53bc19daa486dec24116d8cf0558a498d8476dc4e18874f8a3e9ccb9defb15bd',\n '1c16654b93bc01179a71ec907919f45132b2e9f1a9ac331b213655c66387b4e5',\n '3bdd8ae18831c37996413cb0277df7141fcd0dff2d056c7b7053c34f0a3beaac',\n '23a063c8156fda9fb0ffdea20172a7f64c1576d1c009a28456c095e2866fc0e9',\n];\n\nexport type Seeded = 'written' | 'updated' | 'current' | 'kept' | 'none';\n\nasync function sha256(text: string): Promise<string> {\n const digest = await crypto.subtle.digest('SHA-256', new TextEncoder().encode(text));\n return [...new Uint8Array(digest)].map((byte) => byte.toString(16).padStart(2, '0')).join('');\n}\n\nasync function seed(g: G, context: Context, create: boolean): Promise<Seeded> {\n const { env, assets } = g.options;\n const text = assets ? await assets(PROCEDURE).catch(() => undefined) : undefined;\n if (text === undefined) return 'none';\n const bundled = await sha256(text);\n const marker = `${g.procedure}.sha256`;\n const must = (result: { ok: boolean; error?: { message: string } }) => {\n if (!result.ok) throw new Error(result.error?.message ?? 'write failed');\n };\n const write = async (state: Seeded): Promise<Seeded> => {\n must(await env.writeFile(g.procedure, text, context));\n must(await env.writeFile(marker, `${bundled}\\n`, context));\n must(await env.remove(g.pending, { force: true }, context));\n return state;\n };\n const read = await env.readTextFile(g.procedure, context);\n if (!read.ok) return create ? write('written') : 'none';\n const mine = await sha256(read.value);\n if (mine === bundled) return write('current');\n const last = await env.readTextFile(marker, context);\n if ((last.ok && last.value.trim() === mine) || SHIPPED.includes(mine)) return write('updated');\n must(await env.writeFile(g.pending, text, context));\n return 'kept';\n}\n\nasync function init(g: G, context: Context): Promise<Answer> {\n const { options } = g;\n await seed(g, context, true);\n let handle = handleOf(options.agents);\n if (!handle) {\n const roles = await options.roles(context);\n const role = roles.roles.find((entry) => entry.name === ROLE);\n if (!role) return fail('the gelatiere role is missing');\n const spawned = await options.scoops.spawn(\n {\n cone: 'cone',\n kind: 'async',\n name: ROLE,\n role,\n prompts: [],\n target: null,\n fromAgent: false,\n request: `gelatiere-init-${g.now()}`,\n limits: roles.limits,\n },\n context\n );\n if (spawned.code !== 0) return { code: 1, out: `gelatiere: ${spawned.out}` };\n handle = spawned.out.trim();\n }\n await schedule(g, handle, context);\n return {\n code: 0,\n out: `the gelatiere is scoop ${handle}; it runs at ${SCHEDULE} (crontab) and with gelatiere run, following ${g.procedure}\\n`,\n };\n}\n\nasync function run(g: G, context: Context): Promise<Answer> {\n const handle = handleOf(g.options.agents);\n if (!handle) return fail('there is no gelatiere yet; run gelatiere init');\n await g.options.licks.deliver(\n {\n channel: 'sprinkle',\n source: 'sprinkle:gelatiere',\n title: 'Gelatiere',\n text: 'run',\n body: `Run a pass now: read ${g.procedure} and follow it.`,\n target: `scoop:${handle}`,\n },\n context\n );\n return { code: 0, out: `asked scoop ${handle} for a pass\\n` };\n}\n\nasync function suggest(g: G, path: string | undefined, context: Context): Promise<Answer> {\n if (!path) return { code: 2, out: USAGE };\n const read = await g.options.env.readTextFile(path, context);\n if (!read.ok) return fail(`can't read ${path}`);\n let parsed: unknown;\n try {\n parsed = JSON.parse(read.value);\n } catch (error) {\n return fail(`${path} is not JSON (${(error as Error).message})`);\n }\n const folded = fold(await g.load(context), parsed, g.now());\n await writeStore(g.options.env, folded.store, context);\n const rejected = folded.rejected.map((reason) => `rejected ${reason}\\n`).join('');\n return {\n code: 0,\n out: `added ${folded.added}, updated ${folded.updated}, rejected ${folded.rejected.length}\\n${rejected}`,\n };\n}\n\nasync function deliver(g: G, context: Context): Promise<Answer> {\n const store = await g.load(context);\n const fresh = open(store).filter((item) => !item.deliveredAt);\n const cones = Object.keys(g.options.agents.state().cones);\n const byCone = new Map<string, Suggestion[]>();\n for (const item of fresh) {\n const named = (item.cones ?? []).filter((cone) => cones.includes(cone));\n for (const cone of named.length ? named : [g.options.agents.activeCone()])\n byCone.set(cone, [...(byCone.get(cone) ?? []), item]);\n }\n for (const [cone, items] of byCone) {\n const body = {\n added: items.length,\n open: open(store).length,\n suggestions: items.map(({ id, kind, title, body: text }) => ({\n id,\n kind,\n title,\n body: text,\n })),\n path: STORE,\n };\n await g.options.licks.deliver(\n {\n channel: 'sprinkle',\n source: `sprinkle:${SPRINKLE}`,\n title: 'Suggestions',\n text: 'gelatiere-suggestions',\n body: JSON.stringify(body, null, 2),\n target: `cone:${cone}`,\n },\n context\n );\n }\n for (const item of fresh) item.deliveredAt = g.now();\n if (fresh.length) await writeStore(g.options.env, store, context);\n return {\n code: 0,\n out: `delivered ${fresh.length} to ${[...byCone.keys()].join(', ') || 'nobody'}\\n`,\n };\n}\n\nexport const INSTALLER = 'https://raw.githubusercontent.com/ai-ecoverse/gh-upskill/main/install.sh';\n\nexport function upskillScript(\n repo: string,\n skill: string | undefined,\n where: { path?: string; all?: boolean } = {}\n): string {\n const from = where.path ? ` --path '${where.path}'` : '';\n const which = where.all ? ' --all' : ` --skill '${skill}'`;\n return [\n 'bin=\"${PNPM_HOME:-$HOME/.local/share/pnpm}/bin\"',\n `{ command -v upskill >/dev/null 2>&1 || curl -fsSL ${INSTALLER} | bash -s -- --bin-dir \"$bin\"; }`,\n `upskill '${repo}'${from}${which} --dest-path \"$HOME/.pi/agent/skills\"`,\n ].join(' && ');\n}\n\nasync function skillsIn(\n env: ExecutionEnv,\n home: string,\n context: Context\n): Promise<Map<string, string>> {\n const root = `${home}/.pi/agent/skills`;\n const found = new Map<string, string>();\n const listed = await env.listDir(root, context);\n for (const info of listed.ok ? listed.value : []) {\n const path = `${root}/${info.name}/SKILL.md`;\n const read = await env.readTextFile(path, context);\n const name = read.ok ? skillFromText(read.value, path, 'user').skills[0]?.name : undefined;\n if (name) found.set(name, path);\n }\n return found;\n}\n\nasync function install(g: G, id: string, context: Context): Promise<Answer> {\n const { env, home } = g.options;\n const item = (await g.load(context)).find((entry) => entry.id === id && entry.kind === 'skill');\n const checked = item ? validate(item) : `there is no skill suggestion ${id}`;\n if (typeof checked === 'string') return fail(checked);\n const { skill, repo, path, all } = checked as Suggestion & { repo: string };\n const what = all ? `the skills${path ? ` in ${path}` : ''}` : (skill as string);\n const before = await skillsIn(env, home, context);\n const existing = skill ? before.get(skill) : undefined;\n if (!all && existing) return fail(`${skill} is already installed in ${existing}`);\n const lines: string[] = [];\n const ran = await env.exec(\n upskillScript(repo, skill, { ...(path ? { path } : {}), ...(all ? { all } : {}) }),\n { cwd: home, onOutput: (text) => void lines.push(text) },\n context\n );\n const output = lines.join('').trim().split('\\n').slice(-8).join('\\n');\n const after = await skillsIn(env, home, context);\n const added = all\n ? [...after].filter(([name, at]) => before.get(name) !== at)\n : [...after].filter(([name]) => name === skill);\n if (!ran.ok || ran.value.exitCode !== 0 || !added.length)\n return fail(\n `upskill couldn't install ${what} from github.com/${repo}${output ? `:\\n${output}` : ''}`\n );\n await g.mark(id, 'takenAt', context);\n const names = added.map(([name]) => name).sort();\n return {\n code: 0,\n out: all\n ? `installed ${names.join(', ')} in ${home}/.pi/agent/skills; ${names.map((name) => `/skill:${name}`).join(', ')} once the skills reload\\n`\n : `installed ${skill} in ${added[0]?.[1]}; it is /skill:${skill} once the skills reload\\n`,\n };\n}\n\ninterface Candidate {\n id: string;\n kind: 'skill' | 'use-case';\n title: string;\n body: string;\n evidence: string;\n score: number;\n skill?: string;\n repo?: string;\n path?: string;\n all?: boolean;\n prompt?: string;\n skills?: string[];\n}\n\nasync function profileFor(g: G, context: Context): Promise<Profile | undefined> {\n const read = await g.options.env.readTextFile(`${g.options.home}/${PROFILE}`, context);\n if (!read.ok) return undefined;\n try {\n return profileOf(JSON.parse(read.value));\n } catch {\n return undefined;\n }\n}\n\nfunction sourceLine(label: string, found: Sheet): string {\n const at = found.fetchedAt ? `, fetched ${new Date(found.fetchedAt).toISOString()}` : '';\n return `${label}: ${found.state} (${found.url}${at})`;\n}\n\nasync function catalog(g: G, argv: readonly string[], context: Context): Promise<Answer> {\n const { env, home } = g.options;\n const base = g.options.catalog ?? CATALOG_BASE;\n const fetcher: Fetcher = g.options.fetch ?? ((url, init) => globalThis.fetch(url, init));\n const options = { env, fetcher, now: g.now(), refresh: argv.includes('--refresh') };\n const profile = await profileFor(g, context);\n const slug = slugifyCompany(profile?.company);\n const company = slug && !['catalog', 'use-cases'].includes(slug) ? slug : null;\n const [global, own, cases] = await Promise.all([\n sheet(options, `${base}catalog.json`, `${CATALOG_DIR}/catalog.json`, context),\n company\n ? sheet(options, `${base}${company}.json`, `${CATALOG_DIR}/company-${company}.json`, context)\n : undefined,\n sheet(options, `${base}use-cases.json`, `${CATALOG_DIR}/use-cases.json`, context),\n ]);\n const store = await g.load(context);\n const closed = new Set(store.filter((item) => item.dismissedAt || item.takenAt).map((i) => i.id));\n const have = new Set([\n ...(await skillsIn(env, home, context)).keys(),\n ...(g.options.skills?.() ?? []).map((entry) => entry.name),\n ]);\n const evidence = (reasons: string[]) =>\n `www.sliccy.com catalog: ${reasons.length ? reasons.join(', ') : 'featured'}`;\n const skills: Candidate[] = merge(parseSkills(global.rows), parseSkills(own?.rows ?? []))\n .filter((entry) => !entry.skill || !have.has(entry.skill))\n .map((entry) => {\n const ranked = score(entry, profile);\n return {\n id: `catalog-${entry.name}`,\n kind: 'skill',\n title: entry.title,\n body: entry.description || entry.title,\n evidence: evidence(ranked.reasons),\n score: ranked.score,\n ...(entry.skill ? { skill: entry.skill } : {}),\n repo: entry.repo,\n ...(entry.path ? { path: entry.path } : {}),\n ...(entry.all ? { all: true } : {}),\n };\n });\n const uses: Candidate[] = parseUseCases(cases.rows).map((entry) => {\n const ranked = score(entry, profile);\n return {\n id: `catalog-use-${entry.name}`,\n kind: 'use-case',\n title: entry.title,\n body: entry.description || entry.title,\n evidence: evidence(ranked.reasons),\n score: ranked.score,\n prompt: entry.prompt,\n ...(entry.skills.length ? { skills: entry.skills } : {}),\n };\n });\n const all = argv.includes('--all');\n const ranked = [...skills, ...uses]\n .filter((item) => !closed.has(item.id) && (all || item.score > 0))\n .sort((a, b) => b.score - a.score || a.id.localeCompare(b.id));\n const sources = [\n sourceLine('skills', global),\n ...(own ? [sourceLine(`company ${company}`, own)] : []),\n sourceLine('use cases', cases),\n ];\n const who = profile\n ? `profile: ${home}/${PROFILE} (${[profile.role, profile.purpose].filter(Boolean).join(', ') || 'empty'})`\n : `profile: none (${home}/${PROFILE}); ranked by boost only`;\n if (argv.includes('--json'))\n return {\n code: 0,\n out: `${JSON.stringify({ sources, profile: Boolean(profile), candidates: ranked }, null, 2)}\\n`,\n };\n const rows = ranked.map(\n (item) => `${item.score}\\t${item.id}\\t${item.kind}\\t${item.title}\\t${item.evidence}`\n );\n return {\n code: 0,\n out: `${[...sources, who, ...(rows.length ? rows : ['no catalog entries match'])].join('\\n')}\\n`,\n };\n}\n\nasync function list(g: G, argv: readonly string[], context: Context): Promise<Answer> {\n const store = await g.load(context);\n const shown = argv.includes('--all') ? store : open(store);\n if (argv.includes('--json')) return { code: 0, out: `${JSON.stringify(shown, null, 2)}\\n` };\n return { code: 0, out: shown.length ? `${shown.map(row).join('\\n')}\\n` : 'no suggestions\\n' };\n}\n\nasync function status(g: G, context: Context): Promise<Answer> {\n const { env, agents } = g.options;\n const store = await readStore(env, context);\n const handle = handleOf(agents);\n const read = await env.readTextFile(g.crontab, context);\n const scheduled = (read.ok ? read.value : '').split('\\n').map(scheduleOf).find(Boolean);\n const counts = store\n ? `${open(store).length} open, ${store.filter((item) => item.takenAt).length} taken, ${store.filter((item) => item.dismissedAt).length} dismissed`\n : 'none yet';\n const pending = await env.readTextFile(g.pending, context);\n const lines = [\n `scoop: ${handle ?? 'none (gelatiere init)'}`,\n `schedule: ${scheduled ?? 'none'}`,\n `store: ${counts}`,\n ...(pending.ok\n ? [\n `procedure: ${g.procedure} has your edits, so it was kept; the new built-in one is ${g.pending}`,\n ]\n : []),\n ];\n return { code: 0, out: `${lines.join('\\n')}\\n` };\n}\n\nasync function dismiss(g: G, id: string, context: Context): Promise<Answer> {\n return (await g.mark(id, 'dismissedAt', context))\n ? { code: 0, out: `dismissed ${id}\\n` }\n : fail(`there is no suggestion ${id}`);\n}\n\nconst VERBS: Record<string, (g: G, argv: readonly string[], context: Context) => Promise<Answer>> =\n {\n init: (g, _argv, context) => init(g, context),\n run: (g, _argv, context) => run(g, context),\n suggest: (g, argv, context) => g.serial(() => suggest(g, argv[1], context)),\n deliver: (g, _argv, context) => g.serial(() => deliver(g, context)),\n install: (g, argv, context) => install(g, argv[1] ?? '', context),\n catalog: (g, argv, context) => catalog(g, argv, context),\n list: (g, argv, context) => list(g, argv, context),\n status: (g, _argv, context) => status(g, context),\n dismiss: (g, argv, context) => dismiss(g, argv[1] ?? '', context),\n };\n\nexport function attachGelatiere(options: GelatiereAttach): GelatiereRuntime {\n const { env, home } = options;\n const now = options.now ?? Date.now;\n const load = async (context: Context) => (await readStore(env, context)) ?? [];\n let chain: Promise<unknown> = Promise.resolve();\n const serial = <T>(work: () => Promise<T>): Promise<T> => {\n const next = chain.catch(() => undefined).then(work);\n chain = next;\n return next;\n };\n const g: G = {\n serial,\n options,\n now,\n crontab: `${home}/.slicc/crontab`,\n procedure: `${home}/.pi/agent/GELATIERE.md`,\n pending: `${home}/.pi/agent/GELATIERE.new.md`,\n load,\n mark: (id, field, context) =>\n serial(async () => {\n const store = await load(context);\n const item = store.find((entry) => entry.id === id);\n if (!item) return false;\n item[field] ??= now();\n await writeStore(env, store, context);\n return true;\n }),\n };\n const seeded = seed(g, BACKGROUND_CONTEXT, false).catch((): Seeded => 'none');\n return {\n seeded,\n async command(argv, _caller, context) {\n const verb = argv[0] ?? 'help';\n const handler = VERBS[verb];\n await seeded;\n if (handler) return handler(g, argv, context);\n return { code: verb === 'help' || verb === '--help' ? 0 : 2, out: USAGE };\n },\n async intercept(action, data, context) {\n const id = String((data as { id?: unknown } | null)?.id ?? '');\n if (action === 'gelatiere-dismiss') {\n await g.mark(id, 'dismissedAt', context);\n return true;\n }\n if (action === 'gelatiere-install' || action === 'gelatiere-try')\n await g.mark(id, 'takenAt', context);\n return false;\n },\n };\n}\n\nexport function lateGelatiere() {\n let runtime: GelatiereRuntime | undefined;\n return {\n async intercept(\n id: string,\n payload: { action: string; data: unknown },\n context: Context\n ): Promise<boolean> {\n return id === SPRINKLE && runtime !== undefined\n ? runtime.intercept(payload.action, payload.data, context)\n : false;\n },\n command(argv: readonly string[], caller: string | null, context: Context): Promise<Answer> {\n return runtime\n ? runtime.command(argv, caller, context)\n : Promise.resolve({ code: 1, out: 'gelatiere: not ready yet\\n' });\n },\n attach(options: GelatiereAttach): GelatiereRuntime {\n runtime = attachGelatiere(options);\n return runtime;\n },\n };\n}\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["import type { Context } from '@earendil-works/chord';\nimport { BACKGROUND_CONTEXT } from '@earendil-works/chord/context';\nimport type { ExecutionEnv } from '@earendil-works/pi-durable/env';\nimport { type Agents, live } from '../agents.ts';\nimport type { Licks } from '../licks/licks.ts';\nimport type { Roles } from '../roles/roles.ts';\nimport type { Scoops } from '../scoops/service.ts';\nimport { skillFromText } from '../skills/skills.ts';\nimport {\n CATALOG_BASE,\n CATALOG_DIR,\n type Fetcher,\n merge,\n PROFILE,\n type Profile,\n parseSkills,\n parseUseCases,\n profileOf,\n type Sheet,\n score,\n sheet,\n slugifyCompany,\n} from './catalog.ts';\nimport {\n fold,\n open,\n readStore,\n STORE,\n type Suggestion,\n storeOf,\n validate,\n writeStore,\n} from './store.ts';\n\nexport type Answer = { code: number; out: string };\n\nexport const ROLE = 'gelatiere';\nexport const SPRINKLE = 'suggestions';\nexport const PROCEDURE = 'packages/vfs-root/gelatiere/GELATIERE.md';\nexport const SCHEDULE = '0 3 * * *';\n\nexport interface GelatiereAttach {\n agents: Agents;\n licks: Licks;\n env: ExecutionEnv;\n home: string;\n scoops: Scoops;\n roles: (context: Context) => Promise<Roles>;\n assets?: (path: string) => Promise<string>;\n now?: () => number;\n fetch?: Fetcher;\n catalog?: string;\n skills?: () => readonly { name: string }[];\n files?: ExecutionEnv;\n profile?: string;\n shared?: string;\n as?: (caller: string | null, context: Context) => Promise<Caller | undefined>;\n}\n\nexport interface Caller {\n env: ExecutionEnv;\n home: string;\n}\n\nexport interface GelatiereRuntime {\n command(argv: readonly string[], caller: string | null, context: Context): Promise<Answer>;\n intercept(action: string, data: unknown, context: Context): Promise<boolean>;\n readonly seeded: Promise<Seeded>;\n}\n\nexport const USAGE = `usage:\n gelatiere init start the gelatiere scoop and its nightly crontab line\n gelatiere run ask the gelatiere for a pass now\n gelatiere suggest <file> fold a JSON array of suggestions into the store\n gelatiere deliver lick each cone with the suggestions that are new for it\n gelatiere catalog [--refresh] [--all] [--json]\n rank the www.sliccy.com skill and use-case catalog for this user\n gelatiere install <id> install a suggested skill with upskill into ~/.pi/agent/skills\n gelatiere list [--all] [--json]\n gelatiere dismiss <id> mark a suggestion as not wanted\n gelatiere status\n\nThe store is ${STORE}; the suggestions sprinkle shows it.\n`;\n\nfunction line(handle: string): string {\n return `${SCHEDULE} ${ROLE} scoop:${handle} Nightly pass: read ~/.pi/agent/GELATIERE.md and follow it.`;\n}\n\nconst JOB = new RegExp(`^((?:\\\\S+\\\\s+){4}\\\\S+|@\\\\w+)\\\\s+${ROLE}(?:\\\\s|$)`);\n\nexport function scheduleOf(entry: string): string | undefined {\n return JOB.exec(entry.trim())?.[1]?.replace(/\\s+/g, ' ');\n}\n\nfunction handleOf(agents: Agents): string | undefined {\n const found = Object.entries(agents.state().scoops).find(\n ([, record]) => record.role === ROLE && live(record)\n );\n return found?.[1].folder;\n}\n\nfunction row(item: Suggestion): string {\n const state = item.takenAt ? 'taken' : item.dismissedAt ? 'dismissed' : 'open';\n return `${item.id}\\t${item.kind}\\t${state}\\t${item.title}`;\n}\n\ntype G = {\n serial: <T>(work: () => Promise<T>) => Promise<T>;\n options: GelatiereAttach;\n now: () => number;\n crontab: string;\n procedure: string;\n pending: string;\n load: (context: Context) => Promise<Suggestion[]>;\n mark: (id: string, field: 'dismissedAt' | 'takenAt', context: Context) => Promise<boolean>;\n files: ExecutionEnv;\n caller: string | null;\n store: string;\n catalog: string;\n};\n\nasync function callerOf(g: G, context: Context): Promise<Caller> {\n return (await g.options.as?.(g.caller, context)) ?? { env: g.options.env, home: g.options.home };\n}\n\nconst fail = (out: string): Answer => ({ code: 1, out: `gelatiere: ${out}\\n` });\n\nasync function schedule(g: G, handle: string, context: Context): Promise<void> {\n const { home } = g.options;\n const env = g.files;\n const read = await env.readTextFile(g.crontab, context);\n const kept = (read.ok ? read.value : '')\n .split('\\n')\n .filter((entry) => entry.trim() && !scheduleOf(entry));\n await env.createDir(`${home}/.slicc`, { recursive: true }, context);\n await env.writeFile(g.crontab, `${[...kept, line(handle)].join('\\n')}\\n`, context);\n}\n\nexport const SHIPPED = [\n '53bc19daa486dec24116d8cf0558a498d8476dc4e18874f8a3e9ccb9defb15bd',\n '1c16654b93bc01179a71ec907919f45132b2e9f1a9ac331b213655c66387b4e5',\n '3bdd8ae18831c37996413cb0277df7141fcd0dff2d056c7b7053c34f0a3beaac',\n '23a063c8156fda9fb0ffdea20172a7f64c1576d1c009a28456c095e2866fc0e9',\n];\n\nexport type Seeded = 'written' | 'updated' | 'current' | 'kept' | 'none';\n\nasync function sha256(text: string): Promise<string> {\n const digest = await crypto.subtle.digest('SHA-256', new TextEncoder().encode(text));\n return [...new Uint8Array(digest)].map((byte) => byte.toString(16).padStart(2, '0')).join('');\n}\n\nasync function seed(g: G, context: Context, create: boolean): Promise<Seeded> {\n const { assets } = g.options;\n const env = g.files;\n const text = assets ? await assets(PROCEDURE).catch(() => undefined) : undefined;\n if (text === undefined) return 'none';\n const bundled = await sha256(text);\n const marker = `${g.procedure}.sha256`;\n const must = (result: { ok: boolean; error?: { message: string } }) => {\n if (!result.ok) throw new Error(result.error?.message ?? 'write failed');\n };\n const write = async (state: Seeded): Promise<Seeded> => {\n must(await env.writeFile(g.procedure, text, context));\n must(await env.writeFile(marker, `${bundled}\\n`, context));\n must(await env.remove(g.pending, { force: true }, context));\n return state;\n };\n const read = await env.readTextFile(g.procedure, context);\n if (!read.ok) return create ? write('written') : 'none';\n const mine = await sha256(read.value);\n if (mine === bundled) return write('current');\n const last = await env.readTextFile(marker, context);\n if ((last.ok && last.value.trim() === mine) || SHIPPED.includes(mine)) return write('updated');\n must(await env.writeFile(g.pending, text, context));\n return 'kept';\n}\n\nasync function init(g: G, context: Context): Promise<Answer> {\n const { options } = g;\n await seed(g, context, true);\n let handle = handleOf(options.agents);\n if (!handle) {\n const roles = await options.roles(context);\n const role = roles.roles.find((entry) => entry.name === ROLE);\n if (!role) return fail('the gelatiere role is missing');\n const spawned = await options.scoops.spawn(\n {\n cone: 'cone',\n kind: 'async',\n name: ROLE,\n role,\n prompts: [],\n target: null,\n fromAgent: false,\n request: `gelatiere-init-${g.now()}`,\n limits: roles.limits,\n },\n context\n );\n if (spawned.code !== 0) return { code: 1, out: `gelatiere: ${spawned.out}` };\n handle = spawned.out.trim();\n }\n await schedule(g, handle, context);\n return {\n code: 0,\n out: `the gelatiere is scoop ${handle}; it runs at ${SCHEDULE} (crontab) and with gelatiere run, following ${g.procedure}\\n`,\n };\n}\n\nasync function run(g: G, context: Context): Promise<Answer> {\n const handle = handleOf(g.options.agents);\n if (!handle) return fail('there is no gelatiere yet; run gelatiere init');\n await g.options.licks.deliver(\n {\n channel: 'sprinkle',\n source: 'sprinkle:gelatiere',\n title: 'Gelatiere',\n text: 'run',\n body: `Run a pass now: read ${g.procedure} and follow it.`,\n target: `scoop:${handle}`,\n },\n context\n );\n return { code: 0, out: `asked scoop ${handle} for a pass\\n` };\n}\n\nasync function suggest(g: G, path: string | undefined, context: Context): Promise<Answer> {\n if (!path) return { code: 2, out: USAGE };\n const read = await (await callerOf(g, context)).env.readTextFile(path, context);\n if (!read.ok) return fail(`can't read ${path}`);\n let parsed: unknown;\n try {\n parsed = JSON.parse(read.value);\n } catch (error) {\n return fail(`${path} is not JSON (${(error as Error).message})`);\n }\n const folded = fold(await g.load(context), parsed, g.now());\n await writeStore(g.options.env, folded.store, context, g.store);\n const rejected = folded.rejected.map((reason) => `rejected ${reason}\\n`).join('');\n return {\n code: 0,\n out: `added ${folded.added}, updated ${folded.updated}, rejected ${folded.rejected.length}\\n${rejected}`,\n };\n}\n\nasync function deliver(g: G, context: Context): Promise<Answer> {\n const store = await g.load(context);\n const fresh = open(store).filter((item) => !item.deliveredAt);\n const cones = Object.keys(g.options.agents.state().cones);\n const byCone = new Map<string, Suggestion[]>();\n for (const item of fresh) {\n const named = (item.cones ?? []).filter((cone) => cones.includes(cone));\n for (const cone of named.length ? named : [g.options.agents.activeCone()])\n byCone.set(cone, [...(byCone.get(cone) ?? []), item]);\n }\n for (const [cone, items] of byCone) {\n const body = {\n added: items.length,\n open: open(store).length,\n suggestions: items.map(({ id, kind, title, body: text }) => ({\n id,\n kind,\n title,\n body: text,\n })),\n path: g.store,\n };\n await g.options.licks.deliver(\n {\n channel: 'sprinkle',\n source: `sprinkle:${SPRINKLE}`,\n title: 'Suggestions',\n text: 'gelatiere-suggestions',\n body: JSON.stringify(body, null, 2),\n target: `cone:${cone}`,\n },\n context\n );\n }\n for (const item of fresh) item.deliveredAt = g.now();\n if (fresh.length) await writeStore(g.options.env, store, context, g.store);\n return {\n code: 0,\n out: `delivered ${fresh.length} to ${[...byCone.keys()].join(', ') || 'nobody'}\\n`,\n };\n}\n\nexport const INSTALLER = 'https://raw.githubusercontent.com/ai-ecoverse/gh-upskill/main/install.sh';\n\nexport function upskillScript(\n repo: string,\n skill: string | undefined,\n where: { path?: string; all?: boolean } = {}\n): string {\n const from = where.path ? ` --path '${where.path}'` : '';\n const which = where.all ? ' --all' : ` --skill '${skill}'`;\n return [\n 'bin=\"${PNPM_HOME:-$HOME/.local/share/pnpm}/bin\"',\n `{ command -v upskill >/dev/null 2>&1 || curl -fsSL ${INSTALLER} | bash -s -- --bin-dir \"$bin\"; }`,\n `upskill '${repo}'${from}${which} --dest-path \"$HOME/.pi/agent/skills\"`,\n ].join(' && ');\n}\n\nasync function skillsIn(\n env: ExecutionEnv,\n home: string,\n context: Context\n): Promise<Map<string, string>> {\n const root = `${home}/.pi/agent/skills`;\n const found = new Map<string, string>();\n const listed = await env.listDir(root, context);\n for (const info of listed.ok ? listed.value : []) {\n const path = `${root}/${info.name}/SKILL.md`;\n const read = await env.readTextFile(path, context);\n const name = read.ok ? skillFromText(read.value, path, 'user').skills[0]?.name : undefined;\n if (name) found.set(name, path);\n }\n return found;\n}\n\nasync function install(g: G, id: string, context: Context): Promise<Answer> {\n const { env, home } = await callerOf(g, context);\n const item = (await g.load(context)).find((entry) => entry.id === id && entry.kind === 'skill');\n const checked = item ? validate(item) : `there is no skill suggestion ${id}`;\n if (typeof checked === 'string') return fail(checked);\n const { skill, repo, path, all } = checked as Suggestion & { repo: string };\n const what = all ? `the skills${path ? ` in ${path}` : ''}` : (skill as string);\n const before = await skillsIn(env, home, context);\n const existing = skill ? before.get(skill) : undefined;\n if (!all && existing) return fail(`${skill} is already installed in ${existing}`);\n const lines: string[] = [];\n const ran = await env.exec(\n upskillScript(repo, skill, { ...(path ? { path } : {}), ...(all ? { all } : {}) }),\n { cwd: home, onOutput: (text) => void lines.push(text) },\n context\n );\n const output = lines.join('').trim().split('\\n').slice(-8).join('\\n');\n const after = await skillsIn(env, home, context);\n const added = all\n ? [...after].filter(([name, at]) => before.get(name) !== at)\n : [...after].filter(([name]) => name === skill);\n if (!ran.ok || ran.value.exitCode !== 0 || !added.length)\n return fail(\n `upskill couldn't install ${what} from github.com/${repo}${output ? `:\\n${output}` : ''}`\n );\n await g.mark(id, 'takenAt', context);\n const names = added.map(([name]) => name).sort();\n return {\n code: 0,\n out: all\n ? `installed ${names.join(', ')} in ${home}/.pi/agent/skills; ${names.map((name) => `/skill:${name}`).join(', ')} once the skills reload\\n`\n : `installed ${skill} in ${added[0]?.[1]}; it is /skill:${skill} once the skills reload\\n`,\n };\n}\n\ninterface Candidate {\n id: string;\n kind: 'skill' | 'use-case';\n title: string;\n body: string;\n evidence: string;\n score: number;\n skill?: string;\n repo?: string;\n path?: string;\n all?: boolean;\n prompt?: string;\n skills?: string[];\n}\n\nasync function profileFor(g: G, context: Context): Promise<Profile | undefined> {\n const read = await g.options.env.readTextFile(\n `${g.options.profile ?? g.options.home}/${PROFILE}`,\n context\n );\n if (!read.ok) return undefined;\n try {\n return profileOf(JSON.parse(read.value));\n } catch {\n return undefined;\n }\n}\n\nfunction sourceLine(label: string, found: Sheet): string {\n const at = found.fetchedAt ? `, fetched ${new Date(found.fetchedAt).toISOString()}` : '';\n return `${label}: ${found.state} (${found.url}${at})`;\n}\n\nasync function catalog(g: G, argv: readonly string[], context: Context): Promise<Answer> {\n const { env } = g.options;\n const home = g.options.profile ?? g.options.home;\n const mine = await callerOf(g, context);\n const base = g.options.catalog ?? CATALOG_BASE;\n const fetcher: Fetcher = g.options.fetch ?? ((url, init) => globalThis.fetch(url, init));\n const options = { env, fetcher, now: g.now(), refresh: argv.includes('--refresh') };\n const profile = await profileFor(g, context);\n const slug = slugifyCompany(profile?.company);\n const company = slug && !['catalog', 'use-cases'].includes(slug) ? slug : null;\n const [global, own, cases] = await Promise.all([\n sheet(options, `${base}catalog.json`, `${g.catalog}/catalog.json`, context),\n company\n ? sheet(options, `${base}${company}.json`, `${g.catalog}/company-${company}.json`, context)\n : undefined,\n sheet(options, `${base}use-cases.json`, `${g.catalog}/use-cases.json`, context),\n ]);\n const store = await g.load(context);\n const closed = new Set(store.filter((item) => item.dismissedAt || item.takenAt).map((i) => i.id));\n const have = new Set([\n ...(await skillsIn(mine.env, mine.home, context)).keys(),\n ...(g.options.skills?.() ?? []).map((entry) => entry.name),\n ]);\n const evidence = (reasons: string[]) =>\n `www.sliccy.com catalog: ${reasons.length ? reasons.join(', ') : 'featured'}`;\n const skills: Candidate[] = merge(parseSkills(global.rows), parseSkills(own?.rows ?? []))\n .filter((entry) => !entry.skill || !have.has(entry.skill))\n .map((entry) => {\n const ranked = score(entry, profile);\n return {\n id: `catalog-${entry.name}`,\n kind: 'skill',\n title: entry.title,\n body: entry.description || entry.title,\n evidence: evidence(ranked.reasons),\n score: ranked.score,\n ...(entry.skill ? { skill: entry.skill } : {}),\n repo: entry.repo,\n ...(entry.path ? { path: entry.path } : {}),\n ...(entry.all ? { all: true } : {}),\n };\n });\n const uses: Candidate[] = parseUseCases(cases.rows).map((entry) => {\n const ranked = score(entry, profile);\n return {\n id: `catalog-use-${entry.name}`,\n kind: 'use-case',\n title: entry.title,\n body: entry.description || entry.title,\n evidence: evidence(ranked.reasons),\n score: ranked.score,\n prompt: entry.prompt,\n ...(entry.skills.length ? { skills: entry.skills } : {}),\n };\n });\n const all = argv.includes('--all');\n const ranked = [...skills, ...uses]\n .filter((item) => !closed.has(item.id) && (all || item.score > 0))\n .sort((a, b) => b.score - a.score || a.id.localeCompare(b.id));\n const sources = [\n sourceLine('skills', global),\n ...(own ? [sourceLine(`company ${company}`, own)] : []),\n sourceLine('use cases', cases),\n ];\n const who = profile\n ? `profile: ${home}/${PROFILE} (${[profile.role, profile.purpose].filter(Boolean).join(', ') || 'empty'})`\n : `profile: none (${home}/${PROFILE}); ranked by boost only`;\n if (argv.includes('--json'))\n return {\n code: 0,\n out: `${JSON.stringify({ sources, profile: Boolean(profile), candidates: ranked }, null, 2)}\\n`,\n };\n const rows = ranked.map(\n (item) => `${item.score}\\t${item.id}\\t${item.kind}\\t${item.title}\\t${item.evidence}`\n );\n return {\n code: 0,\n out: `${[...sources, who, ...(rows.length ? rows : ['no catalog entries match'])].join('\\n')}\\n`,\n };\n}\n\nasync function list(g: G, argv: readonly string[], context: Context): Promise<Answer> {\n const store = await g.load(context);\n const shown = argv.includes('--all') ? store : open(store);\n if (argv.includes('--json')) return { code: 0, out: `${JSON.stringify(shown, null, 2)}\\n` };\n return { code: 0, out: shown.length ? `${shown.map(row).join('\\n')}\\n` : 'no suggestions\\n' };\n}\n\nasync function status(g: G, context: Context): Promise<Answer> {\n const { env, agents } = g.options;\n const store = await readStore(env, context, g.store);\n const handle = handleOf(agents);\n const read = await g.files.readTextFile(g.crontab, context);\n const scheduled = (read.ok ? read.value : '').split('\\n').map(scheduleOf).find(Boolean);\n const counts = store\n ? `${open(store).length} open, ${store.filter((item) => item.takenAt).length} taken, ${store.filter((item) => item.dismissedAt).length} dismissed`\n : 'none yet';\n const pending = await g.files.readTextFile(g.pending, context);\n const lines = [\n `scoop: ${handle ?? 'none (gelatiere init)'}`,\n `schedule: ${scheduled ?? 'none'}`,\n `store: ${counts}`,\n ...(pending.ok\n ? [\n `procedure: ${g.procedure} has your edits, so it was kept; the new built-in one is ${g.pending}`,\n ]\n : []),\n ];\n return { code: 0, out: `${lines.join('\\n')}\\n` };\n}\n\nasync function dismiss(g: G, id: string, context: Context): Promise<Answer> {\n return (await g.mark(id, 'dismissedAt', context))\n ? { code: 0, out: `dismissed ${id}\\n` }\n : fail(`there is no suggestion ${id}`);\n}\n\nconst VERBS: Record<string, (g: G, argv: readonly string[], context: Context) => Promise<Answer>> =\n {\n init: (g, _argv, context) => init(g, context),\n run: (g, _argv, context) => run(g, context),\n suggest: (g, argv, context) => g.serial(() => suggest(g, argv[1], context)),\n deliver: (g, _argv, context) => g.serial(() => deliver(g, context)),\n install: (g, argv, context) => install(g, argv[1] ?? '', context),\n catalog: (g, argv, context) => catalog(g, argv, context),\n list: (g, argv, context) => list(g, argv, context),\n status: (g, _argv, context) => status(g, context),\n dismiss: (g, argv, context) => dismiss(g, argv[1] ?? '', context),\n };\n\nexport function attachGelatiere(options: GelatiereAttach): GelatiereRuntime {\n const { env, home } = options;\n const now = options.now ?? Date.now;\n const storeFile = options.shared ? storeOf(options.shared) : STORE;\n const load = async (context: Context) => (await readStore(env, context, storeFile)) ?? [];\n let chain: Promise<unknown> = Promise.resolve();\n const serial = <T>(work: () => Promise<T>): Promise<T> => {\n const next = chain.catch(() => undefined).then(work);\n chain = next;\n return next;\n };\n const g: G = {\n serial,\n options,\n now,\n crontab: `${home}/.slicc/crontab`,\n procedure: `${home}/.pi/agent/GELATIERE.md`,\n pending: `${home}/.pi/agent/GELATIERE.new.md`,\n files: options.files ?? env,\n caller: null,\n store: storeFile,\n catalog: options.shared ? `${options.shared}/.gelatiere/catalog` : CATALOG_DIR,\n load,\n mark: (id, field, context) =>\n serial(async () => {\n const store = await load(context);\n const item = store.find((entry) => entry.id === id);\n if (!item) return false;\n item[field] ??= now();\n await writeStore(env, store, context, storeFile);\n return true;\n }),\n };\n const seeded = seed(g, BACKGROUND_CONTEXT, false).catch((): Seeded => 'none');\n return {\n seeded,\n async command(argv, caller, context) {\n const verb = argv[0] ?? 'help';\n const handler = VERBS[verb];\n await seeded;\n if (handler) return handler({ ...g, caller }, argv, context);\n return { code: verb === 'help' || verb === '--help' ? 0 : 2, out: USAGE };\n },\n async intercept(action, data, context) {\n const id = String((data as { id?: unknown } | null)?.id ?? '');\n if (action === 'gelatiere-dismiss') {\n await g.mark(id, 'dismissedAt', context);\n return true;\n }\n if (action === 'gelatiere-install' || action === 'gelatiere-try')\n await g.mark(id, 'takenAt', context);\n return false;\n },\n };\n}\n\nexport function lateGelatiere() {\n let runtime: GelatiereRuntime | undefined;\n return {\n async intercept(\n id: string,\n payload: { action: string; data: unknown },\n context: Context\n ): Promise<boolean> {\n return id === SPRINKLE && runtime !== undefined\n ? runtime.intercept(payload.action, payload.data, context)\n : false;\n },\n command(argv: readonly string[], caller: string | null, context: Context): Promise<Answer> {\n return runtime\n ? runtime.command(argv, caller, context)\n : Promise.resolve({ code: 1, out: 'gelatiere: not ready yet\\n' });\n },\n attach(options: GelatiereAttach): GelatiereRuntime {\n runtime = attachGelatiere(options);\n return runtime;\n },\n };\n}\n"],
5
+ "mappings": "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",
6
6
  "names": ["init", "ranked"]
7
7
  }
@@ -111,8 +111,11 @@ function fold(store, candidates, now) {
111
111
  function open(store) {
112
112
  return store.filter((item) => !item.dismissedAt && !item.takenAt);
113
113
  }
114
- async function readStore(env, context) {
115
- const read = await env.readTextFile(STORE, context);
114
+ function storeOf(shared) {
115
+ return `${shared}/.gelatiere/suggestions.json`;
116
+ }
117
+ async function readStore(env, context, file = STORE) {
118
+ const read = await env.readTextFile(file, context);
116
119
  if (!read.ok) return null;
117
120
  try {
118
121
  const parsed = JSON.parse(read.value);
@@ -123,9 +126,9 @@ async function readStore(env, context) {
123
126
  return [];
124
127
  }
125
128
  }
126
- async function writeStore(env, store, context) {
127
- await env.createDir(STORE_DIR, { recursive: true }, context);
128
- const written = await env.writeFile(STORE, `${JSON.stringify(store, null, 2)}
129
+ async function writeStore(env, store, context, file = STORE) {
130
+ await env.createDir(file.slice(0, file.lastIndexOf("/")), { recursive: true }, context);
131
+ const written = await env.writeFile(file, `${JSON.stringify(store, null, 2)}
129
132
  `, context);
130
133
  if (!written.ok) throw new Error(written.error.message);
131
134
  }
@@ -138,6 +141,7 @@ export {
138
141
  open,
139
142
  readStore,
140
143
  repoOf,
144
+ storeOf,
141
145
  validate,
142
146
  writeStore
143
147
  };
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../src/gelatiere/store.ts"],
4
- "sourcesContent": ["import type { Context } from '@earendil-works/chord';\nimport type { ExecutionEnv } from '@earendil-works/pi-durable/env';\nimport { redactSecrets } from '../memory/format.ts';\nimport { SUGGESTIONS_DIR, SUGGESTIONS_STORE } from '../sprinkles/sprinkles.ts';\n\nexport const STORE_DIR = SUGGESTIONS_DIR;\nexport const STORE = SUGGESTIONS_STORE;\nexport const KINDS = ['skill', 'use-case', 'tip', 'skill-idea', 'issue'] as const;\nexport const MAX_OPEN = 50;\nconst PROMPTED = new Set<Kind>(['use-case', 'skill-idea', 'issue']);\n\nexport type Kind = (typeof KINDS)[number];\n\nexport interface Suggestion {\n id: string;\n kind: Kind;\n title: string;\n body: string;\n evidence?: string;\n skill?: string;\n repo?: string;\n path?: string;\n all?: boolean;\n install?: string;\n prompt?: string;\n url?: string;\n cones: string[];\n createdAt: number;\n deliveredAt?: number;\n dismissedAt?: number;\n takenAt?: number;\n}\n\nconst ID = /^[a-z0-9][a-z0-9-]{0,63}$/;\nconst CONE = /^[a-z0-9][a-z0-9._-]{0,63}$/;\nconst REPO = /^[A-Za-z0-9][A-Za-z0-9-]{0,38}\\/[A-Za-z0-9._-]{1,100}$/;\nconst SKILL = /^[A-Za-z0-9][A-Za-z0-9 ._-]{0,79}$/;\nconst PATH = /^(?!.*\\.\\.)[A-Za-z0-9._/-]{1,200}$/;\n\nfunction text(value: unknown, limit: number): string | undefined {\n if (typeof value !== 'string') return undefined;\n const clean = redactSecrets(value.trim()).text;\n return clean ? clean.slice(0, limit) : undefined;\n}\n\nexport function repoOf(source: unknown): string | undefined {\n if (typeof source !== 'string') return undefined;\n const found = /^https:\\/\\/raw\\.githubusercontent\\.com\\/([^/\\s]+)\\/([^/\\s]+)\\//.exec(\n source.trim()\n );\n return found ? `${found[1]}/${found[2]}` : undefined;\n}\n\nfunction origin(skill: string | undefined, repo: string | undefined, where: Where): string {\n if (where.all)\n return `all skills${where.path ? ` in ${where.path}` : ''} from github.com/${repo}`;\n return `${skill} from github.com/${repo}`;\n}\n\ntype Where = { path?: string; all?: boolean };\n\nfunction kindProblem(\n kind: Kind,\n skill: string | undefined,\n repo: string | undefined,\n prompt: string | undefined,\n where: Where = {}\n): string | undefined {\n if (kind === 'skill' && where.path !== undefined && !PATH.test(where.path))\n return 'a skill path must be a plain folder in the repo';\n if (kind === 'skill' && !where.all && (!skill || !SKILL.test(skill)))\n return 'a skill needs its name (letters, digits, spaces, . _ -)';\n if (kind === 'skill' && (!repo || !REPO.test(repo)))\n return 'a skill needs its repo, a GitHub owner/repo';\n if (PROMPTED.has(kind) && !prompt) return `a ${kind} needs its prompt`;\n return undefined;\n}\n\nfunction shapeProblem(url: string | undefined, cones: string[]): string | undefined {\n if (url !== undefined && !/^https:\\/\\/[^\\s\"'<>]+$/.test(url)) return 'url must be https';\n if (cones.some((cone) => !CONE.test(cone))) return 'cones must be cone ids';\n return undefined;\n}\n\nexport function validate(candidate: unknown): Suggestion | string {\n if (!candidate || typeof candidate !== 'object') return 'not an object';\n const item = candidate as Record<string, unknown>;\n const id = typeof item.id === 'string' ? item.id : '';\n if (!ID.test(id)) return `id \"${String(item.id)}\" must be 1\u201364 of a-z, 0-9 and -`;\n if (!KINDS.includes(item.kind as Kind)) return `${id}: kind must be one of ${KINDS.join(', ')}`;\n const title = text(item.title, 120);\n const body = text(item.body, 600);\n if (!title || !body) return `${id}: needs a title and a body`;\n const skill = typeof item.skill === 'string' ? item.skill.trim() : undefined;\n const repo = typeof item.repo === 'string' ? item.repo.trim() : repoOf(item.source);\n const url = typeof item.url === 'string' ? item.url.trim() : undefined;\n const cones = Array.isArray(item.cones)\n ? item.cones.filter((cone): cone is string => typeof cone === 'string')\n : [];\n const evidence = text(item.evidence, 300);\n const prompt = text(item.prompt, 1000);\n const path = typeof item.path === 'string' && item.path.trim() ? item.path.trim() : undefined;\n const where: Where = { ...(path ? { path } : {}), ...(item.all === true ? { all: true } : {}) };\n const problem =\n kindProblem(item.kind as Kind, skill, repo, prompt, where) ?? shapeProblem(url, cones);\n if (problem) return `${id}: ${problem}`;\n const installs =\n item.kind === 'skill'\n ? {\n ...(where.all ? {} : { skill }),\n repo,\n ...where,\n install: origin(skill, repo, where),\n }\n : {};\n return {\n id,\n kind: item.kind as Kind,\n title,\n body,\n ...(evidence ? { evidence } : {}),\n ...installs,\n ...(prompt ? { prompt } : {}),\n ...(url ? { url } : {}),\n cones,\n createdAt: 0,\n };\n}\n\nexport function fold(\n store: readonly Suggestion[],\n candidates: unknown,\n now: number\n): { store: Suggestion[]; added: number; updated: number; rejected: string[] } {\n const next = store.map((item) => ({ ...item }));\n const rejected: string[] = [];\n let added = 0;\n let updated = 0;\n if (!Array.isArray(candidates))\n return { store: next, added, updated, rejected: ['not a JSON array'] };\n for (const candidate of candidates) {\n const checked = validate(candidate);\n if (typeof checked === 'string') {\n rejected.push(checked);\n continue;\n }\n const at = next.findIndex((item) => item.id === checked.id);\n const old = next[at];\n if (old) {\n if (old.dismissedAt || old.takenAt) continue;\n next[at] = { ...checked, createdAt: old.createdAt };\n updated++;\n } else if (open(next).length >= MAX_OPEN)\n rejected.push(`${checked.id}: ${MAX_OPEN} suggestions are already open`);\n else {\n next.push({ ...checked, createdAt: now });\n added++;\n }\n }\n return { store: next, added, updated, rejected };\n}\n\nexport function open(store: readonly Suggestion[]): Suggestion[] {\n return store.filter((item) => !item.dismissedAt && !item.takenAt);\n}\n\nexport async function readStore(\n env: Pick<ExecutionEnv, 'readTextFile'>,\n context: Context\n): Promise<Suggestion[] | null> {\n const read = await env.readTextFile(STORE, context);\n if (!read.ok) return null;\n try {\n const parsed = JSON.parse(read.value) as unknown;\n return Array.isArray(parsed)\n ? parsed.filter(\n (item): item is Suggestion =>\n Boolean(item) && typeof item === 'object' && typeof (item as Suggestion).id === 'string'\n )\n : [];\n } catch {\n return [];\n }\n}\n\nexport async function writeStore(\n env: Pick<ExecutionEnv, 'writeFile' | 'createDir'>,\n store: readonly Suggestion[],\n context: Context\n): Promise<void> {\n await env.createDir(STORE_DIR, { recursive: true }, context);\n const written = await env.writeFile(STORE, `${JSON.stringify(store, null, 2)}\\n`, context);\n if (!written.ok) throw new Error(written.error.message);\n}\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["import type { Context } from '@earendil-works/chord';\nimport type { ExecutionEnv } from '@earendil-works/pi-durable/env';\nimport { redactSecrets } from '../memory/format.ts';\nimport { SUGGESTIONS_DIR, SUGGESTIONS_STORE } from '../sprinkles/sprinkles.ts';\n\nexport const STORE_DIR = SUGGESTIONS_DIR;\nexport const STORE = SUGGESTIONS_STORE;\nexport const KINDS = ['skill', 'use-case', 'tip', 'skill-idea', 'issue'] as const;\nexport const MAX_OPEN = 50;\nconst PROMPTED = new Set<Kind>(['use-case', 'skill-idea', 'issue']);\n\nexport type Kind = (typeof KINDS)[number];\n\nexport interface Suggestion {\n id: string;\n kind: Kind;\n title: string;\n body: string;\n evidence?: string;\n skill?: string;\n repo?: string;\n path?: string;\n all?: boolean;\n install?: string;\n prompt?: string;\n url?: string;\n cones: string[];\n createdAt: number;\n deliveredAt?: number;\n dismissedAt?: number;\n takenAt?: number;\n}\n\nconst ID = /^[a-z0-9][a-z0-9-]{0,63}$/;\nconst CONE = /^[a-z0-9][a-z0-9._-]{0,63}$/;\nconst REPO = /^[A-Za-z0-9][A-Za-z0-9-]{0,38}\\/[A-Za-z0-9._-]{1,100}$/;\nconst SKILL = /^[A-Za-z0-9][A-Za-z0-9 ._-]{0,79}$/;\nconst PATH = /^(?!.*\\.\\.)[A-Za-z0-9._/-]{1,200}$/;\n\nfunction text(value: unknown, limit: number): string | undefined {\n if (typeof value !== 'string') return undefined;\n const clean = redactSecrets(value.trim()).text;\n return clean ? clean.slice(0, limit) : undefined;\n}\n\nexport function repoOf(source: unknown): string | undefined {\n if (typeof source !== 'string') return undefined;\n const found = /^https:\\/\\/raw\\.githubusercontent\\.com\\/([^/\\s]+)\\/([^/\\s]+)\\//.exec(\n source.trim()\n );\n return found ? `${found[1]}/${found[2]}` : undefined;\n}\n\nfunction origin(skill: string | undefined, repo: string | undefined, where: Where): string {\n if (where.all)\n return `all skills${where.path ? ` in ${where.path}` : ''} from github.com/${repo}`;\n return `${skill} from github.com/${repo}`;\n}\n\ntype Where = { path?: string; all?: boolean };\n\nfunction kindProblem(\n kind: Kind,\n skill: string | undefined,\n repo: string | undefined,\n prompt: string | undefined,\n where: Where = {}\n): string | undefined {\n if (kind === 'skill' && where.path !== undefined && !PATH.test(where.path))\n return 'a skill path must be a plain folder in the repo';\n if (kind === 'skill' && !where.all && (!skill || !SKILL.test(skill)))\n return 'a skill needs its name (letters, digits, spaces, . _ -)';\n if (kind === 'skill' && (!repo || !REPO.test(repo)))\n return 'a skill needs its repo, a GitHub owner/repo';\n if (PROMPTED.has(kind) && !prompt) return `a ${kind} needs its prompt`;\n return undefined;\n}\n\nfunction shapeProblem(url: string | undefined, cones: string[]): string | undefined {\n if (url !== undefined && !/^https:\\/\\/[^\\s\"'<>]+$/.test(url)) return 'url must be https';\n if (cones.some((cone) => !CONE.test(cone))) return 'cones must be cone ids';\n return undefined;\n}\n\nexport function validate(candidate: unknown): Suggestion | string {\n if (!candidate || typeof candidate !== 'object') return 'not an object';\n const item = candidate as Record<string, unknown>;\n const id = typeof item.id === 'string' ? item.id : '';\n if (!ID.test(id)) return `id \"${String(item.id)}\" must be 1\u201364 of a-z, 0-9 and -`;\n if (!KINDS.includes(item.kind as Kind)) return `${id}: kind must be one of ${KINDS.join(', ')}`;\n const title = text(item.title, 120);\n const body = text(item.body, 600);\n if (!title || !body) return `${id}: needs a title and a body`;\n const skill = typeof item.skill === 'string' ? item.skill.trim() : undefined;\n const repo = typeof item.repo === 'string' ? item.repo.trim() : repoOf(item.source);\n const url = typeof item.url === 'string' ? item.url.trim() : undefined;\n const cones = Array.isArray(item.cones)\n ? item.cones.filter((cone): cone is string => typeof cone === 'string')\n : [];\n const evidence = text(item.evidence, 300);\n const prompt = text(item.prompt, 1000);\n const path = typeof item.path === 'string' && item.path.trim() ? item.path.trim() : undefined;\n const where: Where = { ...(path ? { path } : {}), ...(item.all === true ? { all: true } : {}) };\n const problem =\n kindProblem(item.kind as Kind, skill, repo, prompt, where) ?? shapeProblem(url, cones);\n if (problem) return `${id}: ${problem}`;\n const installs =\n item.kind === 'skill'\n ? {\n ...(where.all ? {} : { skill }),\n repo,\n ...where,\n install: origin(skill, repo, where),\n }\n : {};\n return {\n id,\n kind: item.kind as Kind,\n title,\n body,\n ...(evidence ? { evidence } : {}),\n ...installs,\n ...(prompt ? { prompt } : {}),\n ...(url ? { url } : {}),\n cones,\n createdAt: 0,\n };\n}\n\nexport function fold(\n store: readonly Suggestion[],\n candidates: unknown,\n now: number\n): { store: Suggestion[]; added: number; updated: number; rejected: string[] } {\n const next = store.map((item) => ({ ...item }));\n const rejected: string[] = [];\n let added = 0;\n let updated = 0;\n if (!Array.isArray(candidates))\n return { store: next, added, updated, rejected: ['not a JSON array'] };\n for (const candidate of candidates) {\n const checked = validate(candidate);\n if (typeof checked === 'string') {\n rejected.push(checked);\n continue;\n }\n const at = next.findIndex((item) => item.id === checked.id);\n const old = next[at];\n if (old) {\n if (old.dismissedAt || old.takenAt) continue;\n next[at] = { ...checked, createdAt: old.createdAt };\n updated++;\n } else if (open(next).length >= MAX_OPEN)\n rejected.push(`${checked.id}: ${MAX_OPEN} suggestions are already open`);\n else {\n next.push({ ...checked, createdAt: now });\n added++;\n }\n }\n return { store: next, added, updated, rejected };\n}\n\nexport function open(store: readonly Suggestion[]): Suggestion[] {\n return store.filter((item) => !item.dismissedAt && !item.takenAt);\n}\n\nexport function storeOf(shared: string): string {\n return `${shared}/.gelatiere/suggestions.json`;\n}\n\nexport async function readStore(\n env: Pick<ExecutionEnv, 'readTextFile'>,\n context: Context,\n file = STORE\n): Promise<Suggestion[] | null> {\n const read = await env.readTextFile(file, context);\n if (!read.ok) return null;\n try {\n const parsed = JSON.parse(read.value) as unknown;\n return Array.isArray(parsed)\n ? parsed.filter(\n (item): item is Suggestion =>\n Boolean(item) && typeof item === 'object' && typeof (item as Suggestion).id === 'string'\n )\n : [];\n } catch {\n return [];\n }\n}\n\nexport async function writeStore(\n env: Pick<ExecutionEnv, 'writeFile' | 'createDir'>,\n store: readonly Suggestion[],\n context: Context,\n file = STORE\n): Promise<void> {\n await env.createDir(file.slice(0, file.lastIndexOf('/')), { recursive: true }, context);\n const written = await env.writeFile(file, `${JSON.stringify(store, null, 2)}\\n`, context);\n if (!written.ok) throw new Error(written.error.message);\n}\n"],
5
+ "mappings": "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",
6
6
  "names": []
7
7
  }
package/dist/index.js.map CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../src/index.ts"],
4
- "sourcesContent": ["export {\n ADOBE,\n ADOBE_PROXY,\n type AdobeConfig,\n type AdobeModelInfo,\n adobeClassifiers,\n adobeConfig,\n adobeModel,\n adobeProvider,\n adobeUsage,\n type Budget,\n} from './adobe.ts';\nexport { type Agent, type AgentOptions, answerText, openAgent } from './agent.ts';\nexport {\n FILE_LIMIT,\n IMAGE_LIMIT,\n type SendAttachment,\n type ShownAttachment,\n splitUser,\n TOTAL_LIMIT,\n userParts,\n} from './attachments.ts';\nexport { type AgentConnection, connectAgent } from './client.ts';\nexport { createAgentControl } from './control.ts';\nexport { CREDENTIALS_DATABASE, EncryptedCredentialStore } from './credentials.ts';\nexport { type AgentHost, type ConnectOptions, hostAgent } from './host.ts';\nexport type {\n KernelClient,\n KernelFs,\n KernelProcess,\n KernelStat,\n SpawnOptions,\n} from './kernel/client.ts';\nexport { HOME, type KernelEnvOptions, kernelEnvironment, SliccKernelEnv } from './kernel/env.ts';\nexport {\n adminOver,\n type KernelAdmin,\n type KernelUser,\n type KernelUsers,\n serveAdmin,\n type UserClient,\n type UserClients,\n type UserConnect,\n type UserSpec,\n userClients,\n} from './kernel/users.ts';\nexport { PortListener } from './listener.ts';\nexport {\n type AgentWorkerOptions,\n type AgentWorkerScope,\n type KernelAttach,\n runAgentWorker,\n} from './main.ts';\nexport {\n type Loopback,\n type Transport,\n type TransportResponse,\n transportFetch,\n} from './net.ts';\nexport {\n AGENT_LOCK,\n type AgentOwner,\n type AgentWorker,\n type KernelSource,\n type OwnerOptions,\n startAgent,\n} from './owner.ts';\nexport { applyPatches, patchServerAccept } from './patches.ts';\nexport { SliccPrompt, sliccPrompt } from './prompt.ts';\nexport {\n type AgentPages,\n createPages,\n type PageBatch,\n type PageCaller,\n type PageRequest,\n type PageResult,\n type Pages,\n type PagesOpened,\n type PageTab,\n} from './remote/pages.ts';\nexport {\n type AccountState,\n AGENT_SESSION,\n AgentControl,\n AgentPagesService,\n AgentSessions,\n AgentSettings,\n type AgentSettingsChange,\n AgentTranscript,\n type BudgetState,\n type ModelChoice,\n type OperationError,\n type PromptResult,\n type SendMode,\n type SendRequest,\n type SendResponse,\n type SettingsState,\n type SignIn,\n} from './services.ts';\nexport {\n BEDROCK,\n createAgentSettings,\n createSliccModels,\n DEFAULT_MODEL,\n DEFAULT_REGIONS,\n sliccProviders,\n withDefaultRegions,\n} from './settings.ts';\nexport {\n AGENT_DIRECTORY,\n type OpfsSqliteOptions,\n openMemorySqliteStorage,\n openOpfsSqliteStorage,\n WasmSqliteDatabase,\n} from './sqlite.ts';\nexport { type SystemFacts, systemSection } from './system.ts';\nexport { UPLOADS, type Uploads, upload } from './uploads.ts';\nexport { PortChannel, type PortEndpoint, withUnrefTimers } from './wire.ts';\nexport {\n type KernelPorts,\n kernelPort,\n kernelPorts,\n serveConnections,\n type WorkerScope,\n} from './worker.ts';\n"],
5
- "mappings": "AAAA;AAAA,EACE;AAAA,EACA;AAAA,EAGA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OAEK;AACP,SAAwC,YAAY,iBAAiB;AACrE;AAAA,EACE;AAAA,EACA;AAAA,EAGA;AAAA,EACA;AAAA,EACA;AAAA,OACK;AACP,SAA+B,oBAAoB;AACnD,SAAS,0BAA0B;AACnC,SAAS,sBAAsB,gCAAgC;AAC/D,SAA8C,iBAAiB;AAQ/D,SAAS,MAA6B,mBAAmB,sBAAsB;AAC/E;AAAA,EACE;AAAA,EAIA;AAAA,EAKA;AAAA,OACK;AACP,SAAS,oBAAoB;AAC7B;AAAA,EAIE;AAAA,OACK;AACP;AAAA,EAIE;AAAA,OACK;AACP;AAAA,EACE;AAAA,EAKA;AAAA,OACK;AACP,SAAS,cAAc,yBAAyB;AAChD,SAAS,aAAa,mBAAmB;AACzC;AAAA,EAEE;AAAA,OAQK;AACP;AAAA,EAEE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EAEA;AAAA,OAUK;AACP;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OACK;AACP;AAAA,EACE;AAAA,EAEA;AAAA,EACA;AAAA,EACA;AAAA,OACK;AACP,SAA2B,qBAAqB;AAChD,SAAS,SAAuB,cAAc;AAC9C,SAAS,aAAgC,uBAAuB;AAChE;AAAA,EAEE;AAAA,EACA;AAAA,EACA;AAAA,OAEK;",
4
+ "sourcesContent": ["export {\n ADOBE,\n ADOBE_PROXY,\n type AdobeConfig,\n type AdobeModelInfo,\n adobeClassifiers,\n adobeConfig,\n adobeModel,\n adobeProvider,\n adobeUsage,\n type Budget,\n} from './adobe.ts';\nexport { type Agent, type AgentOptions, answerText, openAgent } from './agent.ts';\nexport {\n FILE_LIMIT,\n IMAGE_LIMIT,\n type SendAttachment,\n type ShownAttachment,\n splitUser,\n TOTAL_LIMIT,\n userParts,\n} from './attachments.ts';\nexport { type AgentConnection, connectAgent } from './client.ts';\nexport { createAgentControl } from './control.ts';\nexport { CREDENTIALS_DATABASE, EncryptedCredentialStore } from './credentials.ts';\nexport { type AgentHost, type ConnectOptions, hostAgent } from './host.ts';\nexport type {\n KernelClient,\n KernelFs,\n KernelProcess,\n KernelStat,\n SpawnOptions,\n} from './kernel/client.ts';\nexport { HOME, type KernelEnvOptions, kernelEnvironment, SliccKernelEnv } from './kernel/env.ts';\nexport {\n adminOver,\n type KernelAdmin,\n type KernelGroup,\n type KernelGroups,\n type KernelUser,\n type KernelUsers,\n serveAdmin,\n type UserClient,\n type UserClients,\n type UserConnect,\n type UserSpec,\n userClients,\n} from './kernel/users.ts';\nexport { PortListener } from './listener.ts';\nexport {\n type AgentWorkerOptions,\n type AgentWorkerScope,\n type KernelAttach,\n runAgentWorker,\n} from './main.ts';\nexport {\n type Loopback,\n type Transport,\n type TransportResponse,\n transportFetch,\n} from './net.ts';\nexport {\n AGENT_LOCK,\n type AgentOwner,\n type AgentWorker,\n type KernelSource,\n type OwnerOptions,\n startAgent,\n} from './owner.ts';\nexport { applyPatches, patchServerAccept } from './patches.ts';\nexport { SliccPrompt, sliccPrompt } from './prompt.ts';\nexport {\n type AgentPages,\n createPages,\n type PageBatch,\n type PageCaller,\n type PageRequest,\n type PageResult,\n type Pages,\n type PagesOpened,\n type PageTab,\n} from './remote/pages.ts';\nexport {\n type AccountState,\n AGENT_SESSION,\n AgentControl,\n AgentPagesService,\n AgentSessions,\n AgentSettings,\n type AgentSettingsChange,\n AgentTranscript,\n type BudgetState,\n type ModelChoice,\n type OperationError,\n type PromptResult,\n type SendMode,\n type SendRequest,\n type SendResponse,\n type SettingsState,\n type SignIn,\n} from './services.ts';\nexport {\n BEDROCK,\n createAgentSettings,\n createSliccModels,\n DEFAULT_MODEL,\n DEFAULT_REGIONS,\n sliccProviders,\n withDefaultRegions,\n} from './settings.ts';\nexport {\n AGENT_DIRECTORY,\n type OpfsSqliteOptions,\n openMemorySqliteStorage,\n openOpfsSqliteStorage,\n WasmSqliteDatabase,\n} from './sqlite.ts';\nexport { type SystemFacts, systemSection } from './system.ts';\nexport { UPLOADS, type Uploads, upload } from './uploads.ts';\nexport { PortChannel, type PortEndpoint, withUnrefTimers } from './wire.ts';\nexport {\n type KernelPorts,\n kernelPort,\n kernelPorts,\n serveConnections,\n type WorkerScope,\n} from './worker.ts';\n"],
5
+ "mappings": "AAAA;AAAA,EACE;AAAA,EACA;AAAA,EAGA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OAEK;AACP,SAAwC,YAAY,iBAAiB;AACrE;AAAA,EACE;AAAA,EACA;AAAA,EAGA;AAAA,EACA;AAAA,EACA;AAAA,OACK;AACP,SAA+B,oBAAoB;AACnD,SAAS,0BAA0B;AACnC,SAAS,sBAAsB,gCAAgC;AAC/D,SAA8C,iBAAiB;AAQ/D,SAAS,MAA6B,mBAAmB,sBAAsB;AAC/E;AAAA,EACE;AAAA,EAMA;AAAA,EAKA;AAAA,OACK;AACP,SAAS,oBAAoB;AAC7B;AAAA,EAIE;AAAA,OACK;AACP;AAAA,EAIE;AAAA,OACK;AACP;AAAA,EACE;AAAA,EAKA;AAAA,OACK;AACP,SAAS,cAAc,yBAAyB;AAChD,SAAS,aAAa,mBAAmB;AACzC;AAAA,EAEE;AAAA,OAQK;AACP;AAAA,EAEE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EAEA;AAAA,OAUK;AACP;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OACK;AACP;AAAA,EACE;AAAA,EAEA;AAAA,EACA;AAAA,EACA;AAAA,OACK;AACP,SAA2B,qBAAqB;AAChD,SAAS,SAAuB,cAAc;AAC9C,SAAS,aAAgC,uBAAuB;AAChE;AAAA,EAEE;AAAA,EACA;AAAA,EACA;AAAA,OAEK;",
6
6
  "names": []
7
7
  }