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.
51 lines • 2.8 kB
JavaScript
import { renderTemplate } from './prompt-template.js';
import { presetContext } from './preset-registry.js';
/**
* The default target a preset runs against (#874): the session it was launched from, falling back
* to the whole codebase when there is no session yet. A template, not a plain string — see
* {@link definePreset} for why that distinction matters.
*/
export const DEFAULT_WHAT = '${{ tf.session_name || "entire codebase" }}';
/** The `tf` a preset renders against. `presets` defaults so a template never throws. */
function tfFrom(ctx) {
return { session_name: ctx.session_name, presets: ctx.presets ?? presetContext() };
}
/**
* {@link DEFAULT_WHAT}, rendered. Exported so a caller that *labels* an agent (the CLI's log title)
* says the same thing the prompt targets, instead of keeping its own copy of the default.
*/
export function defaultWhat(ctx = {}) {
return renderTemplate(DEFAULT_WHAT, { tf: { ...tfFrom(ctx), params: {} } });
}
/**
* Define a preset (#326/#330) from the three things that actually differ between them: the
* run-kind name, the prompt template, and what the one `what` param means. Every preset has the
* identical shape, so that shape lives here once instead of in each preset file.
*
* Omitting `whatDescription` defines a **paramless** preset: the prompt scopes itself (the triage
* and PM presets read the repo's own tickets or plans), so there is no blank to fill and the
* template renders verbatim. That case used to have a second near-identical factory, and six
* further presets hand-rolled it using neither — one optional argument covers all three.
*
* A blank/omitted `what` falls back to the default, so a dashboard button runs with zero input; a
* passed value is trimmed first. The default is itself rendered (#874): `${{ }}` has always been
* JS-evaluated, but the default was the one string that never went through the evaluator, so a
* `${{ }}` inside it reached the prompt as literal text. Rendering it against the same context is
* what lets the default depend on the session the preset was launched from.
*/
export function definePreset(spec) {
const { template, what } = spec;
// Paramless: nothing to fill, so the template is the prompt.
if (what === undefined)
return { ...spec, params: [], render: () => template };
return {
...spec,
params: [{ name: 'what', default: DEFAULT_WHAT, description: what }],
render: (value, ctx = {}) => {
// The default renders with an empty `params`: it can read the session, but not itself.
const target = value?.trim() || defaultWhat(ctx);
return renderTemplate(template, { tf: { ...tfFrom(ctx), params: { what: target } } });
},
};
}
//# sourceMappingURL=preset-prompt.js.map