@nusoft/nuos-build-catalogue 0.10.0 → 0.10.2

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 (65) hide show
  1. package/dist/cli.d.ts +13 -0
  2. package/dist/cli.js +491 -0
  3. package/dist/commands/create.d.ts +70 -0
  4. package/dist/commands/create.js +341 -0
  5. package/dist/commands/format.d.ts +19 -0
  6. package/dist/commands/format.js +89 -0
  7. package/dist/commands/handlers.d.ts +35 -0
  8. package/dist/commands/handlers.js +132 -0
  9. package/dist/commands/init.d.ts +41 -0
  10. package/dist/commands/init.js +289 -0
  11. package/dist/commands/prompt.d.ts +44 -0
  12. package/dist/commands/prompt.js +100 -0
  13. package/dist/commands/write.d.ts +39 -0
  14. package/dist/commands/write.js +247 -0
  15. package/dist/embedder/ollama.d.ts +54 -0
  16. package/dist/embedder/ollama.js +164 -0
  17. package/dist/embedder/openai.d.ts +21 -0
  18. package/dist/embedder/openai.js +56 -0
  19. package/dist/embedder/select.d.ts +9 -0
  20. package/dist/embedder/select.js +27 -0
  21. package/dist/embedder/stub.d.ts +15 -0
  22. package/dist/embedder/stub.js +40 -0
  23. package/dist/embedder/types.d.ts +21 -0
  24. package/dist/embedder/types.js +6 -0
  25. package/dist/embedder/vertex.d.ts +41 -0
  26. package/dist/embedder/vertex.js +94 -0
  27. package/dist/indexer/chunk.d.ts +20 -0
  28. package/dist/indexer/chunk.js +196 -0
  29. package/dist/indexer/crawl.d.ts +20 -0
  30. package/dist/indexer/crawl.js +66 -0
  31. package/dist/indexer/metadata.d.ts +21 -0
  32. package/dist/indexer/metadata.js +126 -0
  33. package/dist/indexer/upsert.d.ts +26 -0
  34. package/dist/indexer/upsert.js +152 -0
  35. package/dist/migrate/parsers.d.ts +17 -0
  36. package/dist/migrate/parsers.js +123 -0
  37. package/dist/migrate/run.d.ts +22 -0
  38. package/dist/migrate/run.js +142 -0
  39. package/dist/migrate/store.d.ts +20 -0
  40. package/dist/migrate/store.js +52 -0
  41. package/dist/migrate/types.d.ts +57 -0
  42. package/dist/migrate/types.js +13 -0
  43. package/dist/regenerate/check.d.ts +11 -0
  44. package/dist/regenerate/check.js +97 -0
  45. package/dist/regenerate/diff.d.ts +18 -0
  46. package/dist/regenerate/diff.js +38 -0
  47. package/dist/regenerate/types.d.ts +52 -0
  48. package/dist/regenerate/types.js +14 -0
  49. package/dist/runtime/ac-parse.d.ts +63 -0
  50. package/dist/runtime/ac-parse.js +196 -0
  51. package/dist/runtime/markdown-edit.d.ts +53 -0
  52. package/dist/runtime/markdown-edit.js +101 -0
  53. package/dist/runtime/markdown-render.d.ts +27 -0
  54. package/dist/runtime/markdown-render.js +209 -0
  55. package/dist/runtime/mis-adapter.d.ts +35 -0
  56. package/dist/runtime/mis-adapter.js +364 -0
  57. package/dist/runtime/runtime.d.ts +20 -0
  58. package/dist/runtime/runtime.js +39 -0
  59. package/dist/search/format.d.ts +6 -0
  60. package/dist/search/format.js +23 -0
  61. package/dist/search/query.d.ts +29 -0
  62. package/dist/search/query.js +71 -0
  63. package/dist/store/open.d.ts +14 -0
  64. package/dist/store/open.js +16 -0
  65. package/package.json +3 -2
@@ -0,0 +1,289 @@
1
+ /**
2
+ * `nuos-catalogue init` — bootstrap a new project's catalogue.
3
+ *
4
+ * Single command that does what was previously a six-step manual scaffold:
5
+ * 1. mkdir docs/build/ + copy starter-kit content
6
+ * 2. Substitute {{PROJECT_NAME}} / {{PROJECT_TAGLINE}} / {{TODAY}} in
7
+ * STATE.md and methodfile.json
8
+ * 3. Copy the four protocols into .claude/commands/ (preserving
9
+ * existing files)
10
+ * 4. Append a "Build catalogue (NuOS Build Method)" section to
11
+ * CLAUDE.md (creating it if missing; preserving existing content)
12
+ * 5. Update .gitignore: !docs/build/ override (if `build/` is present
13
+ * anywhere, the catalogue would otherwise be silently ignored —
14
+ * same gotcha caught at nuos Session 53); ignore .nuos-catalogue/
15
+ * per D047
16
+ * 6. Run a first migrate to verify
17
+ *
18
+ * Companion command: `install-protocols` refreshes just step 3 from the
19
+ * canonical bodies bundled in this CLI package.
20
+ */
21
+ import { mkdir, readFile, writeFile, copyFile, readdir, access } from 'node:fs/promises';
22
+ import { existsSync, constants } from 'node:fs';
23
+ import path from 'node:path';
24
+ import { fileURLToPath } from 'node:url';
25
+ import { askUntilValid, validate } from './prompt.js';
26
+ const __filename = fileURLToPath(import.meta.url);
27
+ const PACKAGE_ROOT = path.resolve(path.dirname(__filename), '..', '..');
28
+ const TEMPLATES_ROOT = path.resolve(PACKAGE_ROOT, 'templates');
29
+ const PROTOCOL_FILES = [
30
+ 'start-of-session.md',
31
+ 'end-of-session.md',
32
+ 'wu-new.md',
33
+ 'persona-new.md',
34
+ ];
35
+ export async function cmdInit(prompt, options = {}) {
36
+ const cwd = options.cwd ?? process.cwd();
37
+ const today = new Date().toISOString().slice(0, 10);
38
+ // Refuse if docs/build/ already exists — this is a one-shot bootstrap.
39
+ if (existsSync(path.join(cwd, 'docs', 'build'))) {
40
+ return {
41
+ output: `nuos-catalogue init: docs/build/ already exists at ${cwd}. Refusing to clobber. If you want to refresh the protocols only, use \`nuos-catalogue install-protocols\` instead.`,
42
+ exitCode: 1,
43
+ };
44
+ }
45
+ // Verify templates are bundled with this CLI install.
46
+ if (!existsSync(TEMPLATES_ROOT)) {
47
+ return {
48
+ output: `nuos-catalogue init: bundled templates not found at ${TEMPLATES_ROOT}. The CLI install is incomplete; reinstall the package.`,
49
+ exitCode: 1,
50
+ };
51
+ }
52
+ // Gather inputs.
53
+ const projectDefault = path.basename(cwd);
54
+ let name = options.name;
55
+ let tagline = options.tagline;
56
+ let domain = options.domain;
57
+ let role = options.role;
58
+ if (!options.nonInteractive) {
59
+ prompt.print('Initialising a NuOS Build Method catalogue.');
60
+ prompt.print('');
61
+ if (!name) {
62
+ name = await askUntilValid(prompt, `Project name [${projectDefault}]: `, (v) => (v.trim().length === 0 ? null : null) // empty allowed; default applied below
63
+ );
64
+ if (!name.trim())
65
+ name = projectDefault;
66
+ }
67
+ if (!tagline) {
68
+ tagline = await askUntilValid(prompt, 'One-sentence tagline (what this project is): ', (v) => validate.nonEmpty(v, 'tagline'));
69
+ }
70
+ if (!domain) {
71
+ domain = (await prompt.ask('Domain (e.g. example.com; empty for none): ')).trim() || 'n/a';
72
+ }
73
+ if (!role) {
74
+ role = await prompt.askChoice('Project role?', ['consumer', 'standalone', 'harness']);
75
+ }
76
+ const confirm = await prompt.confirm(`About to create docs/build/, methodfile.json, .claude/commands/<protocols>, append to CLAUDE.md, update .gitignore, and run first migrate. Proceed?`, true);
77
+ if (!confirm) {
78
+ return { output: 'init cancelled by operator.', exitCode: 1 };
79
+ }
80
+ }
81
+ else {
82
+ if (!name)
83
+ name = projectDefault;
84
+ if (!tagline)
85
+ tagline = '';
86
+ if (!domain)
87
+ domain = 'n/a';
88
+ if (!role)
89
+ role = 'consumer';
90
+ }
91
+ const subs = {
92
+ '{{PROJECT_NAME}}': name,
93
+ '{{PROJECT_TAGLINE}}': tagline,
94
+ '{{PROJECT_DOMAIN}}': domain,
95
+ '{{PROJECT_ROLE}}': role,
96
+ '{{TODAY}}': today,
97
+ };
98
+ const log = [];
99
+ const log_line = (msg) => {
100
+ log.push(msg);
101
+ prompt.print(msg);
102
+ };
103
+ // Step 1: docs/build/ scaffold from starter-kit
104
+ log_line(' · creating docs/build/ from bundled starter-kit');
105
+ await copyDirWithSubstitution(path.join(TEMPLATES_ROOT, 'starter-kit', 'docs', 'build'), path.join(cwd, 'docs', 'build'), subs);
106
+ // Step 2: methodfile.json at repo root
107
+ log_line(' · writing methodfile.json at repo root');
108
+ const methodfileSrc = await readFile(path.join(TEMPLATES_ROOT, 'starter-kit', 'methodfile.json'), 'utf8');
109
+ await writeFile(path.join(cwd, 'methodfile.json'), substitute(methodfileSrc, subs), 'utf8');
110
+ // Step 3: copy protocols into .claude/commands/
111
+ const claudeCommandsDir = path.join(cwd, '.claude', 'commands');
112
+ await mkdir(claudeCommandsDir, { recursive: true });
113
+ for (const protocol of PROTOCOL_FILES) {
114
+ const dest = path.join(claudeCommandsDir, protocol);
115
+ const existed = existsSync(dest);
116
+ await copyFile(path.join(TEMPLATES_ROOT, 'protocols', protocol), dest);
117
+ log_line(` · ${existed ? 'overwrote' : 'installed'} .claude/commands/${protocol}`);
118
+ }
119
+ // Step 4: CLAUDE.md
120
+ const claudeMdPath = path.join(cwd, 'CLAUDE.md');
121
+ const catalogueSection = renderCatalogueSection(name);
122
+ if (existsSync(claudeMdPath)) {
123
+ const existing = await readFile(claudeMdPath, 'utf8');
124
+ if (existing.includes('## Build catalogue (NuOS Build Method)')) {
125
+ log_line(' · CLAUDE.md already mentions the catalogue; not appending');
126
+ }
127
+ else {
128
+ const trailing = existing.endsWith('\n') ? '' : '\n';
129
+ await writeFile(claudeMdPath, `${existing}${trailing}\n${catalogueSection}\n`, 'utf8');
130
+ log_line(' · appended Build catalogue section to CLAUDE.md');
131
+ }
132
+ }
133
+ else {
134
+ const stub = `# ${name} — Project Bootstrap\n\n${catalogueSection}\n`;
135
+ await writeFile(claudeMdPath, stub, 'utf8');
136
+ log_line(' · created CLAUDE.md with Build catalogue section');
137
+ }
138
+ // Step 5: .gitignore
139
+ const gitignorePath = path.join(cwd, '.gitignore');
140
+ await ensureGitignoreEntries(gitignorePath, log_line);
141
+ prompt.print('');
142
+ prompt.print(`✅ Catalogue initialised at ${path.join(cwd, 'docs/build')}`);
143
+ prompt.print('');
144
+ prompt.print('Next steps:');
145
+ prompt.print(' 1. Set env vars in your shell profile so the CLI knows where this catalogue lives:');
146
+ prompt.print(` export NUOS_CATALOGUE_BUILD_ROOT="${path.join(cwd, 'docs/build')}"`);
147
+ prompt.print(` export NUOS_CATALOGUE_WORKFLOWS="${path.join(cwd, '.nuos-catalogue/workflows.json')}"`);
148
+ prompt.print(' 2. Edit docs/build/STATE.md to describe the actual current state of this project.');
149
+ prompt.print(' 3. File the first WU: `nuos-catalogue wu create`');
150
+ prompt.print('');
151
+ prompt.print('To refresh protocols only later (without re-running init): `nuos-catalogue install-protocols`');
152
+ return { output: '', exitCode: 0 };
153
+ }
154
+ export async function cmdInstallProtocols(prompt, options = {}) {
155
+ const cwd = options.cwd ?? process.cwd();
156
+ if (!existsSync(TEMPLATES_ROOT)) {
157
+ return {
158
+ output: `nuos-catalogue install-protocols: bundled templates not found at ${TEMPLATES_ROOT}.`,
159
+ exitCode: 1,
160
+ };
161
+ }
162
+ const claudeCommandsDir = path.join(cwd, '.claude', 'commands');
163
+ await mkdir(claudeCommandsDir, { recursive: true });
164
+ const lines = [];
165
+ for (const protocol of PROTOCOL_FILES) {
166
+ const src = path.join(TEMPLATES_ROOT, 'protocols', protocol);
167
+ const dest = path.join(claudeCommandsDir, protocol);
168
+ let action = 'created';
169
+ if (existsSync(dest)) {
170
+ const [srcContent, destContent] = await Promise.all([
171
+ readFile(src, 'utf8'),
172
+ readFile(dest, 'utf8'),
173
+ ]);
174
+ action = srcContent === destContent ? 'unchanged' : 'updated';
175
+ }
176
+ if (action !== 'unchanged') {
177
+ await copyFile(src, dest);
178
+ }
179
+ lines.push(` ${action.padEnd(10)} .claude/commands/${protocol}`);
180
+ }
181
+ prompt.print(`Refreshing protocols at ${claudeCommandsDir}:`);
182
+ for (const l of lines)
183
+ prompt.print(l);
184
+ return { output: '', exitCode: 0 };
185
+ }
186
+ // ---------------------------------------------------------------------------
187
+ // Helpers
188
+ // ---------------------------------------------------------------------------
189
+ function substitute(content, subs) {
190
+ let result = content;
191
+ for (const [key, value] of Object.entries(subs)) {
192
+ result = result.split(key).join(value);
193
+ }
194
+ return result;
195
+ }
196
+ async function copyDirWithSubstitution(src, dest, subs) {
197
+ await mkdir(dest, { recursive: true });
198
+ const entries = await readdir(src, { withFileTypes: true });
199
+ for (const entry of entries) {
200
+ const entryName = entry.name;
201
+ const srcPath = path.join(src, entryName);
202
+ const destPath = path.join(dest, entryName);
203
+ if (entry.isDirectory()) {
204
+ await copyDirWithSubstitution(srcPath, destPath, subs);
205
+ }
206
+ else if (entry.isFile()) {
207
+ const content = await readFile(srcPath, 'utf8');
208
+ await writeFile(destPath, substitute(content, subs), 'utf8');
209
+ }
210
+ }
211
+ }
212
+ async function ensureGitignoreEntries(gitignorePath, log_line) {
213
+ let existing = '';
214
+ try {
215
+ await access(gitignorePath, constants.F_OK);
216
+ existing = await readFile(gitignorePath, 'utf8');
217
+ }
218
+ catch {
219
+ // No .gitignore — we'll create one with just the catalogue rules.
220
+ }
221
+ const additions = [];
222
+ const hasUnanchoredBuild = /(?:^|\n)\s*build\/\s*(?:\n|$)/.test(existing);
223
+ const hasOverride = /!docs\/build\/(?:\*\*)?/.test(existing);
224
+ const hasNuosCatalogueIgnore = /^\s*\.nuos-catalogue\//m.test(existing);
225
+ if (hasUnanchoredBuild && !hasOverride) {
226
+ additions.push('', '# Override: docs/build/ is the NuOS Build Method catalogue, NOT a build artefact.', '# The unanchored `build/` rule above matches it; this negation pattern keeps the', '# catalogue tracked. Same gotcha caught at nuos Session 53.', '!docs/build/', '!docs/build/**');
227
+ }
228
+ if (!hasNuosCatalogueIgnore) {
229
+ additions.push('', '# NuOS Build Method catalogue — local workflow store (per nuos D047).', '# Markdown is canonical in Mode 1; the JSON store is regenerated by', '# `nuos-catalogue migrate` and does not need to live in git.', '.nuos-catalogue/');
230
+ }
231
+ if (additions.length === 0) {
232
+ log_line(' · .gitignore already has the catalogue entries; nothing to add');
233
+ return;
234
+ }
235
+ const trailing = existing.endsWith('\n') || existing.length === 0 ? '' : '\n';
236
+ const newContent = `${existing}${trailing}${additions.join('\n')}\n`;
237
+ await writeFile(gitignorePath, newContent, 'utf8');
238
+ log_line(existing.length === 0
239
+ ? ' · created .gitignore with catalogue rules'
240
+ : ' · appended catalogue rules to .gitignore');
241
+ }
242
+ function renderCatalogueSection(projectName) {
243
+ return `## Build catalogue (NuOS Build Method)
244
+
245
+ This repo runs **the NuOS Build Method**. The catalogue lives at [docs/build/](docs/build/) and tracks work units, decisions, open questions, personas, sessions, and risks.
246
+
247
+ ### At the start of every session
248
+
249
+ Run \`/start-of-session\` (or follow [docs/build/START-OF-SESSION.md](docs/build/START-OF-SESSION.md)).
250
+
251
+ ### At the end of every session
252
+
253
+ Run \`/end-of-session\`. **Without it, work is lost.**
254
+
255
+ ### Daily use via the CLI
256
+
257
+ Set these env vars in your shell profile so commands work without flags:
258
+
259
+ \`\`\`bash
260
+ export NUOS_CATALOGUE_BUILD_ROOT="$(pwd)/docs/build"
261
+ export NUOS_CATALOGUE_WORKFLOWS="$(pwd)/.nuos-catalogue/workflows.json"
262
+ \`\`\`
263
+
264
+ Then:
265
+
266
+ \`\`\`bash
267
+ nuos-catalogue wu create # interactive — file a new WU
268
+ nuos-catalogue wu list # what's in flight
269
+ nuos-catalogue wu advance <handle> --to=in_progress
270
+ nuos-catalogue wu tick <handle> --index=N --evidence="commit abc123"
271
+ nuos-catalogue decision create
272
+ nuos-catalogue question create
273
+ nuos-catalogue regenerate # check store-vs-disk drift
274
+ nuos-catalogue summary # totals by register
275
+ \`\`\`
276
+
277
+ To refresh the protocol bodies later (after a CLI upgrade):
278
+
279
+ \`\`\`bash
280
+ nuos-catalogue install-protocols
281
+ \`\`\`
282
+
283
+ ### What never to do
284
+
285
+ - Never make architectural decisions without recording them in \`docs/build/decisions/\`
286
+ - Never start work outside the active work unit without recording why
287
+ - Never skip end-of-session
288
+ - Never modify a committed \`accepted\` decision file (use \`decision supersede\` instead)`;
289
+ }
@@ -0,0 +1,44 @@
1
+ /**
2
+ * readline-based prompt helpers for interactive CLI commands.
3
+ *
4
+ * Built on node:readline/promises (no new deps). The prompt object
5
+ * carries an open readline interface; callers are responsible for
6
+ * closing it via `prompt.close()` when done. The pattern is:
7
+ *
8
+ * const p = openPrompt();
9
+ * try {
10
+ * const title = await p.ask('Title: ');
11
+ * // ...
12
+ * } finally {
13
+ * p.close();
14
+ * }
15
+ *
16
+ * Tests substitute a mock implementation by injecting a Prompt object
17
+ * directly to the create handlers; the readline-backed openPrompt is
18
+ * only invoked from the CLI shell.
19
+ */
20
+ export interface Prompt {
21
+ ask(question: string): Promise<string>;
22
+ askMultiline(question: string, sentinel?: string): Promise<string>;
23
+ askChoice(question: string, choices: string[]): Promise<string>;
24
+ confirm(question: string, defaultYes?: boolean): Promise<boolean>;
25
+ print(line: string): void;
26
+ close(): void;
27
+ }
28
+ export declare function openPrompt(): Prompt;
29
+ /**
30
+ * Validation helpers that return `null` when valid, error string when not.
31
+ */
32
+ export declare const validate: {
33
+ nonEmpty(value: string, fieldName: string): string | null;
34
+ matches(value: string, pattern: RegExp, fieldName: string, hint?: string): string | null;
35
+ };
36
+ /**
37
+ * Repeatedly ask a question until validation passes. Validators can
38
+ * return null (valid) or an error string (invalid; will be shown and
39
+ * the question re-asked).
40
+ */
41
+ export declare function askUntilValid(p: Prompt, question: string, validator: (value: string) => string | null, options?: {
42
+ multiline?: boolean;
43
+ sentinel?: string;
44
+ }): Promise<string>;
@@ -0,0 +1,100 @@
1
+ /**
2
+ * readline-based prompt helpers for interactive CLI commands.
3
+ *
4
+ * Built on node:readline/promises (no new deps). The prompt object
5
+ * carries an open readline interface; callers are responsible for
6
+ * closing it via `prompt.close()` when done. The pattern is:
7
+ *
8
+ * const p = openPrompt();
9
+ * try {
10
+ * const title = await p.ask('Title: ');
11
+ * // ...
12
+ * } finally {
13
+ * p.close();
14
+ * }
15
+ *
16
+ * Tests substitute a mock implementation by injecting a Prompt object
17
+ * directly to the create handlers; the readline-backed openPrompt is
18
+ * only invoked from the CLI shell.
19
+ */
20
+ import { createInterface } from 'node:readline/promises';
21
+ import { stdin, stdout } from 'node:process';
22
+ export function openPrompt() {
23
+ const rl = createInterface({ input: stdin, output: stdout });
24
+ return {
25
+ async ask(question) {
26
+ return (await rl.question(question)).trim();
27
+ },
28
+ async askMultiline(question, sentinel = '.') {
29
+ stdout.write(`${question}\n (end with a single line containing only "${sentinel}")\n`);
30
+ const lines = [];
31
+ while (true) {
32
+ const line = await rl.question('');
33
+ if (line.trim() === sentinel)
34
+ break;
35
+ lines.push(line);
36
+ }
37
+ return lines.join('\n').trim();
38
+ },
39
+ async askChoice(question, choices) {
40
+ const numbered = choices.map((c, i) => ` ${i + 1}. ${c}`).join('\n');
41
+ while (true) {
42
+ const answer = (await rl.question(`${question}\n${numbered}\nChoose (1–${choices.length}): `)).trim();
43
+ const idx = parseInt(answer, 10);
44
+ if (Number.isInteger(idx) && idx >= 1 && idx <= choices.length) {
45
+ return choices[idx - 1];
46
+ }
47
+ // Allow typing the choice text directly.
48
+ const direct = choices.find((c) => c.toLowerCase() === answer.toLowerCase());
49
+ if (direct)
50
+ return direct;
51
+ stdout.write(`(unrecognised — try a number 1–${choices.length} or the choice text)\n`);
52
+ }
53
+ },
54
+ async confirm(question, defaultYes = true) {
55
+ const suffix = defaultYes ? '[Y/n]' : '[y/N]';
56
+ const answer = (await rl.question(`${question} ${suffix} `)).trim().toLowerCase();
57
+ if (answer === '')
58
+ return defaultYes;
59
+ return answer === 'y' || answer === 'yes';
60
+ },
61
+ print(line) {
62
+ stdout.write(`${line}\n`);
63
+ },
64
+ close() {
65
+ rl.close();
66
+ },
67
+ };
68
+ }
69
+ /**
70
+ * Validation helpers that return `null` when valid, error string when not.
71
+ */
72
+ export const validate = {
73
+ nonEmpty(value, fieldName) {
74
+ if (value.trim().length === 0)
75
+ return `${fieldName} must be non-empty`;
76
+ return null;
77
+ },
78
+ matches(value, pattern, fieldName, hint) {
79
+ if (!pattern.test(value)) {
80
+ return `${fieldName} did not match expected pattern${hint ? ` (${hint})` : ''}`;
81
+ }
82
+ return null;
83
+ },
84
+ };
85
+ /**
86
+ * Repeatedly ask a question until validation passes. Validators can
87
+ * return null (valid) or an error string (invalid; will be shown and
88
+ * the question re-asked).
89
+ */
90
+ export async function askUntilValid(p, question, validator, options = {}) {
91
+ while (true) {
92
+ const value = options.multiline
93
+ ? await p.askMultiline(question, options.sentinel)
94
+ : await p.ask(question);
95
+ const error = validator(value);
96
+ if (!error)
97
+ return value;
98
+ p.print(`(${error})`);
99
+ }
100
+ }
@@ -0,0 +1,39 @@
1
+ /**
2
+ * Phase H part 2 — flag-driven write commands.
3
+ *
4
+ * Each handler:
5
+ * 1. Validates the flags
6
+ * 2. Looks up the target record from the store
7
+ * 3. Builds a typed `CaptureInput` for the relevant workflow
8
+ * 4. Drives the NuFlow lifecycle through the runtime
9
+ * 5. Reports the result
10
+ *
11
+ * No interactive prompts; flag-driven only. Interactive `create`
12
+ * commands are deferred (Phase H part 3).
13
+ */
14
+ import type { NuFlowRuntime } from '@nusoft/nuflow';
15
+ import type { WorkflowStore } from '../migrate/store.js';
16
+ export interface WriteHandlerResult {
17
+ output: string;
18
+ exitCode: number;
19
+ }
20
+ export declare function cmdWuAdvance(store: WorkflowStore, runtime: NuFlowRuntime, args: {
21
+ handle?: string;
22
+ to?: string;
23
+ reason?: string;
24
+ }): Promise<WriteHandlerResult>;
25
+ export declare function cmdWuTick(store: WorkflowStore, runtime: NuFlowRuntime, args: {
26
+ handle?: string;
27
+ index?: number;
28
+ evidence?: string;
29
+ }): Promise<WriteHandlerResult>;
30
+ export declare function cmdDecisionSupersede(store: WorkflowStore, runtime: NuFlowRuntime, args: {
31
+ target?: string;
32
+ by?: string;
33
+ reason?: string;
34
+ }): Promise<WriteHandlerResult>;
35
+ export declare function cmdQuestionResolve(store: WorkflowStore, runtime: NuFlowRuntime, args: {
36
+ qHandle?: string;
37
+ by?: string;
38
+ reason?: string;
39
+ }): Promise<WriteHandlerResult>;