framework
Version:
The (AI) Framework: turnkey, zero-config AI orchestration that wraps a coding-agent CLI (Claude Code) as a black box and takes you from an idea to a running app. Vite for AI.
142 lines • 10.3 kB
JavaScript
import { definePreset } from './preset-prompt.js';
import { PRESETS_DRAIN_QUEUE, PRESETS_MAINTAINABILITY, PRESETS_MAINTENANCE, PRESETS_MARKET_RESEARCH, PRESETS_PLAN_TICKETS, PRESETS_READABILITY, PRESETS_RESEARCH, PRESETS_SECURITY_AUDIT, PRESETS_SUGGEST_NEW_FEATURES, PRESETS_SUGGEST_NEW_TICKETS, PRESETS_SUGGEST_TICKETS_TO_WORK_ON, PRESETS_TRIAGE_CONSENSUAL, PRESETS_TRIAGE_QUICK, PRESETS_UPDATE_TICKETS, PRESETS_UX, } from './prompts.generated.js';
/**
* Every preset, in one table.
*
* Each of these used to be a file of its own whose whole body was one `definePreset` call (or a
* hand-rolled equivalent) plus four alias exports — 56 exported names for 14 objects, with the
* same four doc comments copied down the directory. What actually varies between them is two or
* three values, which is what a row is.
*
* The prompt text itself is not here: it ships in `prompts/presets/<stem>.md` and reaches this
* table through the generated constants, so a prompt is edited as prose in one place.
*
* Pure by construction (no `node:*`), so the dashboard can render any preset in the browser (#520).
*/
export const presets = {
/**
* [Research] (#331): the problem-variability review, shipped as a direct prompt (see
* `runPrompt`) rather than a build agent — research reviews existing code, so it skips the
* scope -> build scaffolding. `showMultiSelect()` + `<AWAIT>` becomes a live turn-boundary
* gate (#339/#340) the dashboard resolves.
*/
research: definePreset({ name: 'research', template: PRESETS_RESEARCH, what: 'What to measure problem variability of', label: 'Research' }),
/**
* [Maintainability] (#361): deliberately minimal, so its performance can be judged before a
* more explicit prompt is written. Keep it in sync with the issue rather than growing it here.
*/
maintainability: definePreset({ name: 'maintainability', template: PRESETS_MAINTAINABILITY, what: 'What to refactor for maintainability', label: 'Maintainability' }),
/** [Readability] (#360): the reader's-eye pass — seams, altitude, and one commit per refactor. */
readability: definePreset({ name: 'readability', template: PRESETS_READABILITY, what: 'What to refactor for readability', label: 'Readability' }),
/** [Security audit] (#461). */
securityAudit: definePreset({ name: 'security-audit', template: PRESETS_SECURITY_AUDIT, what: 'What to security-audit', label: 'Security audit' }),
/**
* [UX (auto)] (#962, replacing #472's gated prompt): rate every UI flow, then fix the low
* scorers. Unattended by design — it ends in work rather than in `<AWAIT>`, so an agent started
* from it finishes on its own. A gated sibling that offers its ratings as choices is #962's
* stated follow-up and belongs beside this row, not inside it.
*/
ux: definePreset({ name: 'ux', template: PRESETS_UX, what: 'What to review the UX of', label: 'UX (auto)' }),
/**
* [Maintenance] (#881/#882): the periodic codebase sweep. Note `${{ }}` fragments cannot nest (the
* scanner stops at the first `}}`), which is why its target is a plain blank.
*/
maintenance: definePreset({ name: 'maintenance', template: PRESETS_MAINTENANCE, what: 'What to analyze for refactor opportunities', label: 'Maintenance', tooltip: 'Queue maintainability + security work per codebase subset (TODO_AGENTS.md)' }),
// ---- Paramless: each of these scopes itself to the repo's own tickets, plans or queue, so
// there is no blank for a user to fill.
/**
* [Market research] (#694). Its prompt defines `<SESSION_NAME>` itself rather than reading
* `${{ tf.session_name }}`: it is launched from the launcher, where no session exists yet.
*/
marketResearch: definePreset({ name: 'market-research', template: PRESETS_MARKET_RESEARCH, label: 'Market research' }),
/**
* [Update from GitHub] (#1208, #1501): the one GitHub sync. It resumes from the
* `lastImportedAt` in `tickets/meta.json` and reconciles rather than refilling — an existing
* ticket is edited in place, keeping the `.plan.md` written against it, and a
* closed issue's ticket goes. An empty `tickets/` is its first-import branch: every open issue
* comes across, which is why the separate import preset could go (#1501).
*
* The timestamp is read by the agent out of the repo rather than rendered into the prompt: the
* file travels in the same commit as the tickets it describes, so an agent whose work never landed
* cannot leave behind a stamp claiming those issues were imported.
*
* Marked {@link PresetSpec.newAgent}: syncing is repo work, not a reply, so it opens its own
* session rather than appending to whichever one the user happens to be reading.
*/
updateTickets: definePreset({ name: 'update-tickets', template: PRESETS_UPDATE_TICKETS, label: 'Update from GitHub', newAgent: true, tooltip: 'Bring `tickets/` up to date with the GitHub issues. An empty `tickets/` gets a full first import.' }),
/** [Plan tickets] (#685): turn tickets into costed plans. */
planTickets: definePreset({ name: 'plan-tickets', template: PRESETS_PLAN_TICKETS, label: 'Plan tickets (aka spike)', tooltip: 'Turn `tickets/*.md` into costed plans (`tickets/*.plan.md`)' }),
/** [Suggest new tickets] (#462/#683): the dashboard prefills this one line and the user edits it freely. */
suggestNewTickets: definePreset({ name: 'suggest-new-tickets', template: PRESETS_SUGGEST_NEW_TICKETS, label: 'Suggest new tickets' }),
/**
* [Suggest new features] (#1109): the product-inward, generative corner of the PM cluster. It
* studies what the product does today and proposes net-new features as tickets in `tickets/`.
* Distinct from its neighbours: `suggestNewTickets` echoes a line the human types,
* `marketResearch` looks outward at the market, and `suggestTicketsToWorkOn` picks from tickets
* that already exist. Autonomous rather than gated — a proposal is a reviewable ticket, so the
* human triages later instead of approving mid-run, which also keeps it usable unattended.
*/
suggestNewFeatures: definePreset({ name: 'suggest-new-features', template: PRESETS_SUGGEST_NEW_FEATURES, label: 'Suggest new features', tooltip: 'Propose net-new features as tickets in `tickets/`' }),
/**
* [Suggest tickets to work on] (#698): the gated sibling of the triage pair. It ends in
* `<AWAIT>`, so it is deliberately kept out of {@link AUTO_PM_JOBS} — firing it unattended
* would wedge an agent against a human who is not there.
*/
suggestTicketsToWorkOn: definePreset({ name: 'suggest-tickets-to-work-on', template: PRESETS_SUGGEST_TICKETS_TO_WORK_ON, label: 'Suggest tickets to work on', tooltip: 'Add tickets to queue (TODO_AGENTS.md)' }),
/** [Drain queue] (#855): work the entries already on `TODO_AGENTS.md`. */
drainQueue: definePreset({ name: 'drain-queue', template: PRESETS_DRAIN_QUEUE, label: 'Spin up agents working on the AI queue', tooltip: 'Work the entries already on the queue (TODO_AGENTS.md)' }),
/**
* [Do quick-win work] (#891) and [Do consensual work] (#892): read `tickets/*.md`, pick the ones
* matching one filter, and append them to `TODO_AGENTS.md` — how the queue refills itself from
* the ticket backlog. The pair splits on cost, and the split is the point: both are consensual
* (zero open questions, zero variability), so neither needs a human, and they differ only in
* whether the work is cheap. Keeping them apart lets the rotation queue the cheap batch and the
* significant batch on separate turns rather than in one indiscriminate sweep.
*
* Each prompt pins its own `<SESSION_NAME>` and aborts when `tf-<SESSION_NAME>`
* already exists. That collision guard is what makes them safe to fire on a schedule: a triage
* still in flight owns the branch, so the next firing does nothing instead of triaging twice.
*/
triageQuick: definePreset({ name: 'triage-quick', template: PRESETS_TRIAGE_QUICK, label: 'Add quick-win work to AI Queue', tooltip: 'Add `tickets/*.md` to queue (TODO_AGENTS.md), only quick-win and consensual tickets' }),
triageConsensual: definePreset({ name: 'triage-consensual', template: PRESETS_TRIAGE_CONSENSUAL, label: 'Add consensual work to AI Queue', tooltip: 'Add `tickets/*.md` to queue (TODO_AGENTS.md), only significant (no quick-wins) and consensual tickets' }),
};
/**
* Whether a prompt is the one that takes work OFF the queue (#1117).
*
* The daemon knows a drain by the `drains` flag on its job; an agent started by hand arrives as bare
* prompt text with no such marking, so the text is all there is to recognise it by. Compared
* against the rendered preset rather than against a copy of its words, so rewording the preset
* cannot leave this behind — that drift would show up only as a lane on the Overview quietly
* staying empty, which is the kind of bug nobody reports.
*
* Deliberately exact: a prompt that merely mentions the queue is not a drain, and mistaking one
* for the other would name a ticket as being implemented by an agent doing something else entirely.
*/
export function drainsQueue(prompt) {
return prompt.trim() === presets.drainQueue.render().trim();
}
/**
* The presets the launcher offers, in the order it shows them.
*
* One list rather than a `launcher: true` flag on each row: membership and order are the same
* decision, and a flag would have stated half of it while the order lived somewhere else. It is
* also the answer to "which presets are user-facing" — `drainQueue` is absent because only the
* daemon fires it, which previously had nothing marking it internal.
*/
export const LAUNCHER_PRESETS = [
presets.research,
presets.readability,
presets.maintainability,
presets.securityAudit,
presets.ux,
presets.suggestNewTickets,
presets.suggestNewFeatures,
presets.suggestTicketsToWorkOn,
presets.planTickets,
presets.marketResearch,
presets.updateTickets,
presets.maintenance,
presets.triageQuick,
presets.triageConsensual,
];
//# sourceMappingURL=preset-catalog.js.map