mirror of
https://github.com/hanzoai/app.git
synced 2026-10-31 18:04:19 +00:00
useAgentShelf is the + menu's Agents: the org's agents with the default cast filling in, the cast first, each by its face; a pick seats it in the open conversation or lets it out. Create agent and Browse personas open the New agent sheet through make(), drawn by AgentMaker; Manage agents is Dev's Customize > Agents. The Shelf types copy @hanzo/build's plus.tsx until build publishes them. The default cast is every member @hanzo/personas publishes as the team, read from the package's team/ directory rather than a list kept here. The sheet starts from any of the package's 1,042 figures: the name, the PERSONA.md prompt word for word, and a face to draw. The build writes the roster to assets/personas, so it is fetched when the list opens. A face is drawn by zen-image, named on every call (the endpoint refuses a call with none, so Draw never worked); Create draws one when no picture was chosen, and Regenerate draws again.
57 lines
2.9 KiB
JavaScript
57 lines
2.9 KiB
JavaScript
// What the rooms read from @hanzo/personas, from the pinned package.
|
|
//
|
|
// The core team: each member as markdown (team/<id>.md), written to
|
|
// src/team.gen.ts as strings, so no host needs an asset loader. Every member
|
|
// the package publishes is in it: ORDER is only the order the crew is drawn in,
|
|
// and a member it does not name comes after, in the package's order.
|
|
//
|
|
// The figures: the roster under personas/, for "Start from a persona". Written
|
|
// to assets/personas/ (a build product, ignored by git): index.json lists every
|
|
// figure, and <slug>.md is a figure's PERSONA.md where one is written. A host
|
|
// serves assets/ at its root, so the list is fetched when it is opened and a
|
|
// figure's prompt when it is picked; neither weighs on a bundle.
|
|
import { existsSync, mkdirSync, readdirSync, readFileSync, rmSync, writeFileSync } from 'node:fs'
|
|
import { createRequire } from 'node:module'
|
|
import { dirname, join } from 'node:path'
|
|
import { fileURLToPath } from 'node:url'
|
|
|
|
const require = createRequire(import.meta.url)
|
|
const root = dirname(require.resolve('@hanzo/personas/team.js'))
|
|
const here = join(dirname(fileURLToPath(import.meta.url)), '..')
|
|
const { version } = JSON.parse(readFileSync(join(root, 'package.json'), 'utf8'))
|
|
|
|
const ORDER = ['dev', 'des', 'vi', 'feynman', 'einstein', 'nora', 'maya', 'leo']
|
|
const published = readdirSync(join(root, 'team'))
|
|
.filter((f) => f.endsWith('.md'))
|
|
.map((f) => f.slice(0, -3))
|
|
.sort()
|
|
const ids = [...ORDER, ...published.filter((id) => !ORDER.includes(id))]
|
|
const body = ids.map((id) => ` ${id}: ${JSON.stringify(readFileSync(join(root, 'team', `${id}.md`), 'utf8'))},`).join('\n')
|
|
writeFileSync(
|
|
join(here, 'src', 'team.gen.ts'),
|
|
`// Generated by scripts/team.mjs from @hanzo/personas ${version}. Do not edit.\n` +
|
|
`export const FILES = {\n${body}\n} as const\n`,
|
|
)
|
|
console.log(`team: ${ids.length} members from @hanzo/personas ${version}`)
|
|
|
|
// A PERSONA.md's front matter field, or undefined.
|
|
const field = (md, key) => new RegExp(`^${key}:\\s*(.+)$`, 'm').exec(md.split(/^---$/m)[1] ?? '')?.[1].trim()
|
|
|
|
const out = join(here, 'assets', 'personas')
|
|
rmSync(out, { recursive: true, force: true })
|
|
mkdirSync(out, { recursive: true })
|
|
const figures = readdirSync(join(root, 'personas'))
|
|
.sort()
|
|
.map((slug) => {
|
|
const dir = join(root, 'personas', slug)
|
|
const { name, category } = JSON.parse(readFileSync(join(dir, 'profile.json'), 'utf8'))
|
|
const at = join(dir, 'PERSONA.md')
|
|
if (!existsSync(at)) return { slug, name, category }
|
|
const md = readFileSync(at, 'utf8')
|
|
writeFileSync(join(out, `${slug}.md`), md)
|
|
const based = field(md, 'based_on')
|
|
return { slug, name, category, called: field(md, 'name'), about: field(md, 'description'), ...(based ? { based } : {}) }
|
|
})
|
|
writeFileSync(join(out, 'index.json'), JSON.stringify(figures))
|
|
console.log(`figures: ${figures.length}, ${figures.filter((f) => f.called).length} with a PERSONA.md`)
|