* `kild room ` — the room demo. Opens a room of predefined participants * (`--participants orchestrator,worker,reviewer`; default `orchestrator,worker`), * posts the goal to the first one, and streams every message. With `--worktree * ` the whole room shares one `kild/ ` tree (pa
(goal: string)
| 188 | |
| 189 | const known = (await loadProjects()).map((p) => p.name); |
| 190 | throw new Error( |
| 191 | `unknown project: ${values.project} — not registered, and ${asPath} is not a directory.` + |
| 192 | (known.length ? ` Registered: ${known.join(', ')}.` : '') + |
| 193 | ' Pass a path, or register it with `kild project add <name> <path>`.', |
| 194 | ); |
| 195 | } |
| 196 | |
| 197 | /** `kild persona <ls|show>` — the reusable persona definitions the project ships. */ |
| 198 | async function persona(action: string | undefined, args: string[]): Promise<void> { |
| 199 | const projectPath = await resolveProjectFlag(); |
| 200 | if (action === 'ls') { |
| 201 | const personas = await listPersonas(projectPath); |
| 202 | if (json) return void console.log(JSON.stringify(personas, null, 2)); |
| 203 | for (const p of personas) console.log(p.name); |
| 204 | } else if (action === 'show') { |
| 205 | const [name] = args; |
| 206 | if (!name) throw new Error('usage: kild persona show <name>'); |
| 207 | const found = (await listPersonas(projectPath)).find((p) => p.name === name); |
| 208 | if (!found) throw new Error(`no such persona: ${name}`); |
| 209 | if (json) console.log(JSON.stringify(found, null, 2)); |
| 210 | else if (found.systemPrompt) console.log(found.systemPrompt); |
| 211 | else console.error(`(persona '${name}' uses pi's default prompt)`); |
| 212 | } else { |
| 213 | throw new Error('usage: kild persona <ls|show>'); |
| 214 | } |
| 215 | } |
| 216 | |
| 217 | async function engineRunning(): Promise<boolean> { |
| 218 | return fetch(`${ENGINE}/api/health`) |
| 219 | .then((r) => r.ok) |
| 220 | .catch(() => false); |
| 221 | } |
| 222 | |
| 223 | async function run(prompt: string): Promise<void> { |
| 224 | if (!prompt) throw new Error('usage: kild run <prompt…>'); |
| 225 | // If the engine is up, run THROUGH it so the session shows up in UI clients; |
| 226 | // otherwise run the agent in-process so the CLI works standalone. |
| 227 | return (await engineRunning()) ? runViaEngine(prompt) : runViaAgent(prompt); |
| 228 | } |
| 229 | |
| 230 | /** `kild agents` — list live agents. */ |
| 231 | async function agentsList(): Promise<void> { |
| 232 | const agents = await listAgents(); |
| 233 | if (json) return void console.log(JSON.stringify(agents, null, 2)); |
| 234 | if (agents.length === 0) return void console.error('no live agents'); |
| 235 | for (const a of agents) { |
| 236 | console.log(`${a.id}\t${a.persona ?? GENERAL_PERSONA}${a.model ? ` (${a.model})` : ''}`); |
| 237 | } |
| 238 | } |
| 239 | |
| 240 | /** |
| 241 | * `kild new <goal>` — opens a kild of agents (`--agents a,b,c`, each a |
| 242 | * persona from the project's own personas; with none, one `general` agent), sends the goal |
| 243 | * to the agents named by `--to`, and streams every message. With |
| 244 | * `--worktree <name>` the whole kild shares one `kild/<name>` tree (agents attach to it). |
| 245 | * You can keep typing to send more messages to the same recipients. |
| 246 | * The run ends when the kild does: an agent stops it with its `stop` tool |
| 247 | * after the final report, or Ctrl-C is the kill switch — it stops the kild |
no test coverage detected