@praxis-framework/seed 0.1.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 (42) hide show
  1. package/README.md +47 -0
  2. package/dist/catalog.d.ts +60 -0
  3. package/dist/catalog.d.ts.map +1 -0
  4. package/dist/catalog.js +239 -0
  5. package/dist/catalog.js.map +1 -0
  6. package/dist/index.d.ts +16 -0
  7. package/dist/index.d.ts.map +1 -0
  8. package/dist/index.js +14 -0
  9. package/dist/index.js.map +1 -0
  10. package/dist/seed.d.ts +43 -0
  11. package/dist/seed.d.ts.map +1 -0
  12. package/dist/seed.js +508 -0
  13. package/dist/seed.js.map +1 -0
  14. package/dist/template.d.ts +16 -0
  15. package/dist/template.d.ts.map +1 -0
  16. package/dist/template.js +47 -0
  17. package/dist/template.js.map +1 -0
  18. package/dist/traits.d.ts +26 -0
  19. package/dist/traits.d.ts.map +1 -0
  20. package/dist/traits.js +43 -0
  21. package/dist/traits.js.map +1 -0
  22. package/dist/types.d.ts +288 -0
  23. package/dist/types.d.ts.map +1 -0
  24. package/dist/types.js +87 -0
  25. package/dist/types.js.map +1 -0
  26. package/package.json +55 -0
  27. package/template/.env.example +8 -0
  28. package/template/CLAUDE.md +151 -0
  29. package/template/_gitignore +20 -0
  30. package/template/docker-compose.yml +44 -0
  31. package/template/escalations/README.md +51 -0
  32. package/template/lib/.gitkeep +0 -0
  33. package/template/lib/autonomy.yaml +158 -0
  34. package/template/lib/output-schemas.yaml +88 -0
  35. package/template/lib/tools.yaml +70 -0
  36. package/template/memory/README.md +51 -0
  37. package/template/memory/accounts/.gitkeep +0 -0
  38. package/template/memory/notes/.gitkeep +0 -0
  39. package/template/memory/people/.gitkeep +0 -0
  40. package/template/persona.md +75 -0
  41. package/template/verbs/escalate.md +112 -0
  42. package/template/verbs/proposed/README.md +25 -0
package/README.md ADDED
@@ -0,0 +1,47 @@
1
+ # @praxis-framework/seed
2
+
3
+ Role-scaffolding library that powers [`@praxis-framework/cli`](https://www.npmjs.com/package/@praxis-framework/cli)'s `init` command.
4
+
5
+ Given a validated role definition, `seedRole()` writes a populated [praxis-framework](https://github.com/steveworley/praxis-framework) role into a target directory: `persona.md`, `CLAUDE.md`, `verbs/`, `lib/`, `memory/`, `escalations/`, and `output/`.
6
+
7
+ ## Who should use this
8
+
9
+ Most operators should reach for [`@praxis-framework/cli`](https://www.npmjs.com/package/@praxis-framework/cli) instead — it wraps this library in an interactive wizard and handles input collection, validation feedback, and git integration. The CLI is the supported entry point.
10
+
11
+ This package is published separately so the framework's dashboard can also call `seedRole()` directly from its in-browser setup flow. If you're building tooling on top of praxis and need programmatic scaffolding, import from here. Otherwise use the CLI.
12
+
13
+ ## Install
14
+
15
+ ```bash
16
+ npm install @praxis-framework/seed
17
+ ```
18
+
19
+ ## Usage
20
+
21
+ ```ts
22
+ import { seedRole, type SeedInput } from '@praxis-framework/seed';
23
+
24
+ const input: SeedInput = {
25
+ organisation: { name: 'Acme', size: 'small' },
26
+ role_definition: {
27
+ role_name: 'sales-lead',
28
+ one_sentence_purpose: 'drives outbound on Acme\'s flagship product',
29
+ },
30
+ voice_traits: [{ trait: 'direct', qualifiers: ['short sentences, no hedging'] }],
31
+ capabilities: ['drafts cold-outreach emails'],
32
+ inhibitions: ['never quote prices without sign-off'],
33
+ initial_verbs: [{ slug: 'draft-cold-emails', description: ['compose an outreach email per prospect'] }],
34
+ tools: [],
35
+ };
36
+
37
+ const result = await seedRole(input, '/path/to/new-role');
38
+ console.log(result.filesWritten);
39
+ ```
40
+
41
+ `SeedInput` is validated with Zod; invalid input throws `SeedError` with `code: 'INVALID_INPUT'`. Refer to the source in [`src/types.ts`](./src/types.ts) for the full schema.
42
+
43
+ If the target directory isn't already a git repository, `seedRole()` runs `git init --initial-branch=main` before writing any files. Existing repos are left untouched — the seed never re-inits or renames the operator's chosen default branch. Commits are the caller's responsibility.
44
+
45
+ ## License
46
+
47
+ MIT — see [LICENSE](https://github.com/steveworley/praxis-framework/blob/main/LICENSE).
@@ -0,0 +1,60 @@
1
+ /**
2
+ * Tools-catalog parsing and writing for the seed package.
3
+ *
4
+ * The framework template ships a single `template/lib/tools.yaml` listing
5
+ * every capability a role can opt into. When seeding a role we don't want to
6
+ * copy the catalog wholesale — the seeded `lib/tools.yaml` should contain
7
+ * only the tools enabled for *this* role: every always-available built-in
8
+ * (bash, edit, log) plus any optional capability the operator selected via
9
+ * the wizard.
10
+ *
11
+ * Parser shape mirrors `cli/src/lib/catalog.ts` so the two packages stay in
12
+ * sync. The seed package can't depend on the CLI (the dashboard imports the
13
+ * seed package and we don't want to drag CLI code in), so the parser is
14
+ * duplicated here. If a third caller appears, lift this into a shared module.
15
+ */
16
+ export type CatalogFieldValue = string | number | boolean | null | string[];
17
+ export type CatalogEntry = Record<string, CatalogFieldValue>;
18
+ export type RawCatalog = Record<string, CatalogEntry>;
19
+ /**
20
+ * Parse a `tools.yaml` payload into `{ capabilityName: { fieldKey: value } }`.
21
+ *
22
+ * Supported shape — the same as the framework catalog ships today:
23
+ *
24
+ * capabilities:
25
+ * bash:
26
+ * description: "..."
27
+ * transport_options: [native]
28
+ * default_transport: native
29
+ * always_available: true
30
+ * mcp:slack:
31
+ * description: "..."
32
+ * transport_options: [stdio, sse, url]
33
+ * default_transport: stdio
34
+ * default_auth_env: SLACK_MCP_TOKEN
35
+ * docker_image: praxis/mcp-slack:latest
36
+ *
37
+ * Comments and blank lines are skipped at any depth. Unknown YAML constructs
38
+ * are skipped rather than failing — strict validation is the catalog
39
+ * loader's job (the seed package only needs to filter and re-emit).
40
+ */
41
+ export declare function parseToolsYaml(text: string): RawCatalog;
42
+ /**
43
+ * Read the framework catalog and return the entries enabled for a seeded
44
+ * role: every built-in (`always_available: true`) plus any optional
45
+ * capability whose name appears in `selectedTools`. Selected names with no
46
+ * matching catalog entry are silently dropped — the wizard validates against
47
+ * the catalog upstream, so unknown names here are an invariant violation
48
+ * we'd rather not propagate into the seeded file.
49
+ *
50
+ * Throws `SeedError('TEMPLATE_MISSING')` when the template's tools.yaml
51
+ * isn't readable.
52
+ */
53
+ export declare function buildSeededCatalog(templateRoot: string, selectedTools: readonly string[]): Promise<RawCatalog>;
54
+ /**
55
+ * Render a filtered catalog back to YAML matching the framework template's
56
+ * shape. Header comment is short — operators read the framework's catalog
57
+ * for the schema; the seeded file is just the activated subset.
58
+ */
59
+ export declare function renderToolsYaml(catalog: RawCatalog): string;
60
+ //# sourceMappingURL=catalog.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"catalog.d.ts","sourceRoot":"","sources":["../src/catalog.ts"],"names":[],"mappings":"AAKA;;;;;;;;;;;;;;GAcG;AAEH,MAAM,MAAM,iBAAiB,GAAG,MAAM,GAAG,MAAM,GAAG,OAAO,GAAG,IAAI,GAAG,MAAM,EAAE,CAAC;AAC5E,MAAM,MAAM,YAAY,GAAG,MAAM,CAAC,MAAM,EAAE,iBAAiB,CAAC,CAAC;AAC7D,MAAM,MAAM,UAAU,GAAG,MAAM,CAAC,MAAM,EAAE,YAAY,CAAC,CAAC;AAEtD;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,GAAG,UAAU,CA+DvD;AAgDD;;;;;;;;;;GAUG;AACH,wBAAsB,kBAAkB,CACtC,YAAY,EAAE,MAAM,EACpB,aAAa,EAAE,SAAS,MAAM,EAAE,GAC/B,OAAO,CAAC,UAAU,CAAC,CAuBrB;AAED;;;;GAIG;AACH,wBAAgB,eAAe,CAAC,OAAO,EAAE,UAAU,GAAG,MAAM,CAmC3D"}
@@ -0,0 +1,239 @@
1
+ import fs from 'node:fs/promises';
2
+ import path from 'node:path';
3
+ import { SeedError } from './types.js';
4
+ /**
5
+ * Parse a `tools.yaml` payload into `{ capabilityName: { fieldKey: value } }`.
6
+ *
7
+ * Supported shape — the same as the framework catalog ships today:
8
+ *
9
+ * capabilities:
10
+ * bash:
11
+ * description: "..."
12
+ * transport_options: [native]
13
+ * default_transport: native
14
+ * always_available: true
15
+ * mcp:slack:
16
+ * description: "..."
17
+ * transport_options: [stdio, sse, url]
18
+ * default_transport: stdio
19
+ * default_auth_env: SLACK_MCP_TOKEN
20
+ * docker_image: praxis/mcp-slack:latest
21
+ *
22
+ * Comments and blank lines are skipped at any depth. Unknown YAML constructs
23
+ * are skipped rather than failing — strict validation is the catalog
24
+ * loader's job (the seed package only needs to filter and re-emit).
25
+ */
26
+ export function parseToolsYaml(text) {
27
+ const lines = text.split('\n');
28
+ const out = {};
29
+ let i = 0;
30
+ let inCapabilities = false;
31
+ let currentCap = null;
32
+ let currentCapIndent = 0;
33
+ while (i < lines.length) {
34
+ const raw = lines[i] ?? '';
35
+ const trimmed = raw.trim();
36
+ if (trimmed.length === 0 || trimmed.startsWith('#')) {
37
+ i += 1;
38
+ continue;
39
+ }
40
+ if (!inCapabilities) {
41
+ if (/^capabilities\s*:\s*$/.test(trimmed)) {
42
+ inCapabilities = true;
43
+ }
44
+ i += 1;
45
+ continue;
46
+ }
47
+ const leading = raw.length - raw.trimStart().length;
48
+ // A new top-level key (zero indent) ends the capabilities block.
49
+ if (leading === 0 && /:\s*$/.test(trimmed)) {
50
+ break;
51
+ }
52
+ // Capability header: `<name>:` at the first indent level under
53
+ // `capabilities:`. Names may contain colons (e.g. `mcp:slack`), so we
54
+ // strip only the trailing `:` separator.
55
+ const isHeaderLine = trimmed.endsWith(':') && !trimmed.startsWith('-');
56
+ if (isHeaderLine && (currentCap === null || leading <= currentCapIndent)) {
57
+ const name = trimmed.slice(0, -1).trim();
58
+ if (name.length > 0) {
59
+ currentCap = name;
60
+ currentCapIndent = leading;
61
+ out[name] = {};
62
+ i += 1;
63
+ continue;
64
+ }
65
+ }
66
+ if (currentCap !== null && leading > currentCapIndent) {
67
+ const fieldMatch = /^\s*([A-Za-z_][A-Za-z0-9_]*)\s*:\s*(.*)$/.exec(raw);
68
+ if (fieldMatch) {
69
+ const key = (fieldMatch[1] ?? '').trim();
70
+ const rest = (fieldMatch[2] ?? '').trim();
71
+ out[currentCap][key] = parseScalar(rest);
72
+ }
73
+ i += 1;
74
+ continue;
75
+ }
76
+ i += 1;
77
+ }
78
+ return out;
79
+ }
80
+ function parseScalar(raw) {
81
+ const value = raw.trim();
82
+ if (value.length === 0)
83
+ return null;
84
+ if (value === 'null' || value === '~')
85
+ return null;
86
+ if (value === 'true')
87
+ return true;
88
+ if (value === 'false')
89
+ return false;
90
+ if (value.startsWith('[') && value.endsWith(']')) {
91
+ const inner = value.slice(1, -1).trim();
92
+ if (inner.length === 0)
93
+ return [];
94
+ return inner.split(',').map((part) => stripQuotes(part.trim()));
95
+ }
96
+ if (/^-?\d+$/.test(value)) {
97
+ const n = Number.parseInt(value, 10);
98
+ if (Number.isFinite(n))
99
+ return n;
100
+ }
101
+ return stripQuotes(value);
102
+ }
103
+ function stripQuotes(value) {
104
+ if (value.length < 2)
105
+ return value;
106
+ const first = value[0];
107
+ const last = value[value.length - 1];
108
+ if ((first === '"' && last === '"') || (first === "'" && last === "'")) {
109
+ return value.slice(1, -1);
110
+ }
111
+ return value;
112
+ }
113
+ /**
114
+ * Field-emit order for each capability. Matches the order the framework
115
+ * catalog uses today so the seeded file is visually familiar to operators.
116
+ * Fields not in this list (if any future schema additions slip through) are
117
+ * appended in insertion order at the end.
118
+ */
119
+ const FIELD_ORDER = [
120
+ 'description',
121
+ 'transport_options',
122
+ 'default_transport',
123
+ 'always_available',
124
+ 'default_auth_env',
125
+ 'docker_image',
126
+ ];
127
+ /**
128
+ * Read the framework catalog and return the entries enabled for a seeded
129
+ * role: every built-in (`always_available: true`) plus any optional
130
+ * capability whose name appears in `selectedTools`. Selected names with no
131
+ * matching catalog entry are silently dropped — the wizard validates against
132
+ * the catalog upstream, so unknown names here are an invariant violation
133
+ * we'd rather not propagate into the seeded file.
134
+ *
135
+ * Throws `SeedError('TEMPLATE_MISSING')` when the template's tools.yaml
136
+ * isn't readable.
137
+ */
138
+ export async function buildSeededCatalog(templateRoot, selectedTools) {
139
+ const catalogPath = path.join(templateRoot, 'lib', 'tools.yaml');
140
+ let text;
141
+ try {
142
+ text = await fs.readFile(catalogPath, 'utf-8');
143
+ }
144
+ catch (e) {
145
+ const cause = e instanceof Error ? e.message : String(e);
146
+ throw new SeedError(`Failed to read template catalog ${catalogPath}: ${cause}`, 'TEMPLATE_MISSING');
147
+ }
148
+ const full = parseToolsYaml(text);
149
+ const selected = new Set(selectedTools);
150
+ const out = {};
151
+ for (const [name, entry] of Object.entries(full)) {
152
+ const isBuiltin = entry['always_available'] === true;
153
+ if (isBuiltin || selected.has(name)) {
154
+ out[name] = entry;
155
+ }
156
+ }
157
+ return out;
158
+ }
159
+ /**
160
+ * Render a filtered catalog back to YAML matching the framework template's
161
+ * shape. Header comment is short — operators read the framework's catalog
162
+ * for the schema; the seeded file is just the activated subset.
163
+ */
164
+ export function renderToolsYaml(catalog) {
165
+ const lines = [];
166
+ lines.push('# Tools enabled for this role.');
167
+ lines.push('#');
168
+ lines.push("# Mirrors the framework catalog at <framework>/template/lib/tools.yaml,");
169
+ lines.push('# filtered to the always-available built-ins plus any optional capabilities');
170
+ lines.push("# the operator selected during `praxis init`. To enable another tool, add");
171
+ lines.push('# its entry from the framework catalog here.');
172
+ lines.push('');
173
+ lines.push('capabilities:');
174
+ const names = Object.keys(catalog);
175
+ for (const name of names) {
176
+ const entry = catalog[name] ?? {};
177
+ lines.push(` ${name}:`);
178
+ const seen = new Set();
179
+ for (const key of FIELD_ORDER) {
180
+ if (key in entry) {
181
+ seen.add(key);
182
+ lines.push(` ${key}: ${formatYamlValue(entry[key])}`);
183
+ }
184
+ }
185
+ // Trail with any fields not in the canonical order.
186
+ for (const [key, value] of Object.entries(entry)) {
187
+ if (seen.has(key))
188
+ continue;
189
+ lines.push(` ${key}: ${formatYamlValue(value)}`);
190
+ }
191
+ lines.push('');
192
+ }
193
+ // Trim the trailing blank line so file ends with one newline.
194
+ while (lines.length > 0 && lines[lines.length - 1] === '') {
195
+ lines.pop();
196
+ }
197
+ return `${lines.join('\n')}\n`;
198
+ }
199
+ function formatYamlValue(value) {
200
+ if (value === null)
201
+ return 'null';
202
+ if (value === true)
203
+ return 'true';
204
+ if (value === false)
205
+ return 'false';
206
+ if (typeof value === 'number')
207
+ return String(value);
208
+ if (Array.isArray(value)) {
209
+ if (value.length === 0)
210
+ return '[]';
211
+ return `[${value.map((v) => formatYamlScalar(v)).join(', ')}]`;
212
+ }
213
+ return formatYamlScalar(value);
214
+ }
215
+ /**
216
+ * Quote a string scalar when bare emission would change its meaning to a
217
+ * parser: reserved literals (`true` / `false` / `null` / `~`), integer-shaped
218
+ * values, leading/trailing whitespace, or characters that introduce YAML
219
+ * structure (`#`, `{`, `[`, `,`, `&`, `*`, `!`, `|`, `>`, `'`, `"`, `%`, `@`,
220
+ * backtick) at the start of the value. Mid-value `:` and `/` are safe in
221
+ * block scalars and would force every docker-image string to be quoted, so
222
+ * we leave those bare to match the framework catalog's existing style.
223
+ */
224
+ function formatYamlScalar(value) {
225
+ if (value.length === 0)
226
+ return '""';
227
+ const first = value[0] ?? '';
228
+ if (value === 'true' ||
229
+ value === 'false' ||
230
+ value === 'null' ||
231
+ value === '~' ||
232
+ /^-?\d+$/.test(value) ||
233
+ value !== value.trim() ||
234
+ '#{}[],&*!|>\'"%@`'.includes(first)) {
235
+ return `"${value.replace(/\\/g, '\\\\').replace(/"/g, '\\"')}"`;
236
+ }
237
+ return value;
238
+ }
239
+ //# sourceMappingURL=catalog.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"catalog.js","sourceRoot":"","sources":["../src/catalog.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,16 @@
1
+ /**
2
+ * @praxis-framework/seed — shared role-seeding logic.
3
+ *
4
+ * The dashboard's setup wizard and the CLI's `praxis init` both call
5
+ * `seedRole(input, targetPath, options?)` to materialise a populated
6
+ * praxis role from the framework template. The function performs only
7
+ * file IO; callers layer their own concerns (git commits, approval flows,
8
+ * UI feedback) on top.
9
+ */
10
+ export { seedRole, injectPersona, injectClaudeDescription, injectVerbsTable } from './seed.js';
11
+ export { resolveTemplatePath } from './template.js';
12
+ export { TRAIT_LIBRARY, findTrait } from './traits.js';
13
+ export type { TraitEntry } from './traits.js';
14
+ export { SeedVerbSchema, SeedInputSchema, OrganisationSchema, RoleDefinitionSchema, VoiceTraitSchema, SeedError, } from './types.js';
15
+ export type { SeedVerb, SeedInput, SeedOptions, SeedResult, Organisation, RoleDefinition, VoiceTrait, } from './types.js';
16
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,EAAE,QAAQ,EAAE,aAAa,EAAE,uBAAuB,EAAE,gBAAgB,EAAE,MAAM,WAAW,CAAC;AAC/F,OAAO,EAAE,mBAAmB,EAAE,MAAM,eAAe,CAAC;AACpD,OAAO,EAAE,aAAa,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AACvD,YAAY,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAC9C,OAAO,EACL,cAAc,EACd,eAAe,EACf,kBAAkB,EAClB,oBAAoB,EACpB,gBAAgB,EAChB,SAAS,GACV,MAAM,YAAY,CAAC;AACpB,YAAY,EACV,QAAQ,EACR,SAAS,EACT,WAAW,EACX,UAAU,EACV,YAAY,EACZ,cAAc,EACd,UAAU,GACX,MAAM,YAAY,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,14 @@
1
+ /**
2
+ * @praxis-framework/seed — shared role-seeding logic.
3
+ *
4
+ * The dashboard's setup wizard and the CLI's `praxis init` both call
5
+ * `seedRole(input, targetPath, options?)` to materialise a populated
6
+ * praxis role from the framework template. The function performs only
7
+ * file IO; callers layer their own concerns (git commits, approval flows,
8
+ * UI feedback) on top.
9
+ */
10
+ export { seedRole, injectPersona, injectClaudeDescription, injectVerbsTable } from './seed.js';
11
+ export { resolveTemplatePath } from './template.js';
12
+ export { TRAIT_LIBRARY, findTrait } from './traits.js';
13
+ export { SeedVerbSchema, SeedInputSchema, OrganisationSchema, RoleDefinitionSchema, VoiceTraitSchema, SeedError, } from './types.js';
14
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,EAAE,QAAQ,EAAE,aAAa,EAAE,uBAAuB,EAAE,gBAAgB,EAAE,MAAM,WAAW,CAAC;AAC/F,OAAO,EAAE,mBAAmB,EAAE,MAAM,eAAe,CAAC;AACpD,OAAO,EAAE,aAAa,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AAEvD,OAAO,EACL,cAAc,EACd,eAAe,EACf,kBAAkB,EAClB,oBAAoB,EACpB,gBAAgB,EAChB,SAAS,GACV,MAAM,YAAY,CAAC"}
package/dist/seed.d.ts ADDED
@@ -0,0 +1,43 @@
1
+ import { type SeedVerb, type SeedInput, type SeedOptions, type SeedResult } from './types.js';
2
+ /**
3
+ * Seed a praxis role from the framework template into `targetPath`.
4
+ *
5
+ * The seed owns one repo concern: if `targetPath` isn't already a git
6
+ * repository, it runs `git init --initial-branch=main` before writing
7
+ * any files. Existing repos are left alone (no branch rename, no
8
+ * re-init). Beyond that, the seed performs only file IO — no commits,
9
+ * no environment side-effects beyond writing into the target. Callers
10
+ * (dashboard, CLI) layer their own commit / approval / cleanup behaviour
11
+ * around the result.
12
+ */
13
+ export declare function seedRole(rawInput: SeedInput, targetPath: string, options?: SeedOptions): Promise<SeedResult>;
14
+ /**
15
+ * Replace the CLAUDE.md placeholder one-liner with the operator's role
16
+ * description.
17
+ */
18
+ export declare function injectClaudeDescription(body: string, description: string): string;
19
+ /**
20
+ * Replace the verbs-table placeholder row in CLAUDE.md with one row per
21
+ * operator-supplied verb. The framework template ships the table with
22
+ * `Persona` and `Escalate` rows already in place plus a single
23
+ * `_(add your role's verbs here)_` placeholder row; this function deletes
24
+ * the placeholder and appends one row per captured verb in the order they
25
+ * were captured.
26
+ *
27
+ * Columns: `Verb` (slug, prettified bold) / `File` (path to the stub) /
28
+ * `Input Stage` (always `<unset>` — the wizard does not capture this yet) /
29
+ * `Output Stage` (first description bullet, or `<unset>` when the operator
30
+ * left description empty).
31
+ *
32
+ * If the placeholder row is absent (e.g. the template has been customised),
33
+ * the body is returned unchanged — losing the operator's verbs from the
34
+ * manual is bad, but mangling a customised manual is worse.
35
+ */
36
+ export declare function injectVerbsTable(body: string, verbs: readonly SeedVerb[]): string;
37
+ /**
38
+ * Inject operator-supplied content into the persona template, replacing
39
+ * placeholder section bodies under known section headings. Exported for
40
+ * testing.
41
+ */
42
+ export declare function injectPersona(body: string, input: SeedInput): string;
43
+ //# sourceMappingURL=seed.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"seed.d.ts","sourceRoot":"","sources":["../src/seed.ts"],"names":[],"mappings":"AAQA,OAAO,EAIL,KAAK,QAAQ,EACb,KAAK,SAAS,EACd,KAAK,WAAW,EAChB,KAAK,UAAU,EAEhB,MAAM,YAAY,CAAC;AAgFpB;;;;;;;;;;GAUG;AACH,wBAAsB,QAAQ,CAC5B,QAAQ,EAAE,SAAS,EACnB,UAAU,EAAE,MAAM,EAClB,OAAO,GAAE,WAAgB,GACxB,OAAO,CAAC,UAAU,CAAC,CAkJrB;AAuCD;;;GAGG;AACH,wBAAgB,uBAAuB,CAAC,IAAI,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,GAAG,MAAM,CAEjF;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,SAAS,QAAQ,EAAE,GAAG,MAAM,CAkBjF;AAED;;;;GAIG;AACH,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,SAAS,GAAG,MAAM,CA2CpE"}