@nusoft/nuos-build-catalogue 0.9.0 → 0.10.1

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 (90) hide show
  1. package/dist/cli.d.ts +13 -0
  2. package/dist/cli.js +472 -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 +5 -3
  66. package/templates/protocols/end-of-session.md +19 -0
  67. package/templates/protocols/persona-new.md +43 -0
  68. package/templates/protocols/start-of-session.md +19 -0
  69. package/templates/protocols/wu-new.md +52 -0
  70. package/templates/starter-kit/CLAUDE.md +73 -0
  71. package/templates/starter-kit/README.md +116 -0
  72. package/templates/starter-kit/docs/build/END-OF-SESSION.md +62 -0
  73. package/templates/starter-kit/docs/build/START-OF-SESSION.md +33 -0
  74. package/templates/starter-kit/docs/build/STATE.md +47 -0
  75. package/templates/starter-kit/docs/build/decisions/D001-template.md +38 -0
  76. package/templates/starter-kit/docs/build/decisions/_index.md +30 -0
  77. package/templates/starter-kit/docs/build/maps/01-template.md +126 -0
  78. package/templates/starter-kit/docs/build/maps/_index.md +63 -0
  79. package/templates/starter-kit/docs/build/open-questions/_index.md +26 -0
  80. package/templates/starter-kit/docs/build/personas/001-template.md +68 -0
  81. package/templates/starter-kit/docs/build/personas/_index.md +77 -0
  82. package/templates/starter-kit/docs/build/risks/_index.md +28 -0
  83. package/templates/starter-kit/docs/build/sessions/0000-00-00-template.md +47 -0
  84. package/templates/starter-kit/docs/build/sessions/_index.md +27 -0
  85. package/templates/starter-kit/docs/build/work-units/001-template.md +82 -0
  86. package/templates/starter-kit/docs/build/work-units/_index.md +34 -0
  87. package/templates/starter-kit/docs/contracts/_index.md +26 -0
  88. package/templates/starter-kit/docs/guides/_index.md +26 -0
  89. package/templates/starter-kit/docs/philosophy/_index.md +26 -0
  90. package/templates/starter-kit/methodfile.json +54 -0
package/dist/cli.d.ts ADDED
@@ -0,0 +1,13 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * nuos-catalogue CLI — index and search the build catalogue.
4
+ *
5
+ * Subcommands:
6
+ * index [--force] [--dry-run]
7
+ * search "<query>" [--kind=...] [--status=...] [--limit=N] [--json]
8
+ * info
9
+ *
10
+ * Implementation note — uses minimist-free arg parsing to keep deps lean.
11
+ * If we need richer parsing later, swap in commander/yargs.
12
+ */
13
+ export {};
package/dist/cli.js ADDED
@@ -0,0 +1,472 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * nuos-catalogue CLI — index and search the build catalogue.
4
+ *
5
+ * Subcommands:
6
+ * index [--force] [--dry-run]
7
+ * search "<query>" [--kind=...] [--status=...] [--limit=N] [--json]
8
+ * info
9
+ *
10
+ * Implementation note — uses minimist-free arg parsing to keep deps lean.
11
+ * If we need richer parsing later, swap in commander/yargs.
12
+ */
13
+ import path from 'node:path';
14
+ import { fileURLToPath } from 'node:url';
15
+ import { selectEmbedderFromEnv } from './embedder/select.js';
16
+ import { openStore } from './store/open.js';
17
+ import { runIndex } from './indexer/upsert.js';
18
+ import { runSearch } from './search/query.js';
19
+ import { formatHumanReadable, formatJson } from './search/format.js';
20
+ import { runMigrate } from './migrate/run.js';
21
+ import { openWorkflowStore } from './migrate/store.js';
22
+ import { listRegister, showRecord, commandToRegister, listAcrossRegisters, } from './commands/handlers.js';
23
+ import { runRegenerate } from './regenerate/check.js';
24
+ import { createBuildCatalogueRuntime } from './runtime/runtime.js';
25
+ import { cmdWuAdvance, cmdWuTick, cmdDecisionSupersede, cmdQuestionResolve, } from './commands/write.js';
26
+ import { cmdWuCreate, cmdDecisionCreate, cmdQuestionCreate, cmdPersonaCreate, } from './commands/create.js';
27
+ import { openPrompt } from './commands/prompt.js';
28
+ import { cmdInit, cmdInstallProtocols } from './commands/init.js';
29
+ const __filename = fileURLToPath(import.meta.url);
30
+ const PACKAGE_ROOT = path.resolve(path.dirname(__filename), '..');
31
+ // Defaults resolve in this order: env var > flag-supplied > package-relative
32
+ // fallback. The package-relative fallback only makes sense when running
33
+ // against the nuos catalogue as a sibling (the original WU 110 use case);
34
+ // for any other consumer (Sensight, NuTutor, etc.) the env vars or the
35
+ // per-command flags are the right path. CLAUDE.md guidance for adopters:
36
+ // set NUOS_CATALOGUE_BUILD_ROOT and NUOS_CATALOGUE_WORKFLOWS in your
37
+ // shell profile.
38
+ const DEFAULT_CATALOGUE_ROOT = process.env.NUOS_CATALOGUE_ROOT ?? path.resolve(PACKAGE_ROOT, '../nuos/docs');
39
+ const DEFAULT_BUILD_ROOT = process.env.NUOS_CATALOGUE_BUILD_ROOT ?? path.resolve(PACKAGE_ROOT, '../nuos/docs/build');
40
+ const DEFAULT_INDEX_DIR = process.env.NUOS_CATALOGUE_INDEX_DIR ?? path.resolve(PACKAGE_ROOT, '.nuos-catalogue');
41
+ const DEFAULT_INDEX_PATH = path.join(DEFAULT_INDEX_DIR, 'index.nv');
42
+ const DEFAULT_HASH_PATH = path.join(DEFAULT_INDEX_DIR, 'hashes.json');
43
+ const DEFAULT_WORKFLOWS_PATH = process.env.NUOS_CATALOGUE_WORKFLOWS ?? path.join(DEFAULT_INDEX_DIR, 'workflows.json');
44
+ function parseArgs(argv) {
45
+ const [command, ...rest] = argv;
46
+ const positional = [];
47
+ const flags = {};
48
+ for (const a of rest) {
49
+ if (a.startsWith('--')) {
50
+ const eq = a.indexOf('=');
51
+ if (eq >= 0) {
52
+ flags[a.slice(2, eq)] = a.slice(eq + 1);
53
+ }
54
+ else {
55
+ flags[a.slice(2)] = true;
56
+ }
57
+ }
58
+ else {
59
+ positional.push(a);
60
+ }
61
+ }
62
+ return { command: command ?? 'help', positional, flags };
63
+ }
64
+ async function cmdIndex(flags) {
65
+ const catalogueRoot = String(flags['catalogue'] ?? DEFAULT_CATALOGUE_ROOT);
66
+ const indexPath = String(flags['index'] ?? DEFAULT_INDEX_PATH);
67
+ const hashPath = String(flags['hash-file'] ?? DEFAULT_HASH_PATH);
68
+ const embedder = await selectEmbedderFromEnv();
69
+ const store = await openStore({ storagePath: indexPath, dimensions: embedder.dimensions });
70
+ console.log(`indexing ${catalogueRoot}`);
71
+ console.log(` embedder: ${embedder.modelId} (${embedder.dimensions} dims)`);
72
+ console.log(` index file: ${indexPath}`);
73
+ try {
74
+ const report = await runIndex({
75
+ catalogueRoot,
76
+ hashFilePath: hashPath,
77
+ store,
78
+ embedder,
79
+ force: Boolean(flags['force']),
80
+ dryRun: Boolean(flags['dry-run']),
81
+ });
82
+ console.log(`\n${report.indexed} indexed, ${report.updated} updated, ${report.deleted} deleted, ` +
83
+ `${report.unchanged} unchanged, ${report.chunks} chunks embedded, ` +
84
+ `${(report.durationMs / 1000).toFixed(2)}s`);
85
+ }
86
+ finally {
87
+ // Unload-after-use commitment — see Embedder.dispose() docs.
88
+ await embedder.dispose();
89
+ }
90
+ }
91
+ async function cmdSearch(positional, flags) {
92
+ const query = positional.join(' ');
93
+ if (!query) {
94
+ console.error('Usage: nuos-catalogue search "<query>" [--kind=...] [--status=...] [--limit=N] [--json]');
95
+ process.exit(2);
96
+ }
97
+ const indexPath = String(flags['index'] ?? DEFAULT_INDEX_PATH);
98
+ const embedder = await selectEmbedderFromEnv();
99
+ const store = await openStore({ storagePath: indexPath, dimensions: embedder.dimensions });
100
+ const limit = flags['limit'] ? Number(flags['limit']) : 10;
101
+ const kind = flags['kind'] ? String(flags['kind']) : undefined;
102
+ const status = flags['status'] ? String(flags['status']) : undefined;
103
+ const asJson = Boolean(flags['json']);
104
+ try {
105
+ const { hits, embedMs, searchMs } = await runSearch(store, embedder, {
106
+ query,
107
+ limit,
108
+ kind,
109
+ status,
110
+ });
111
+ if (asJson) {
112
+ console.log(formatJson(hits));
113
+ }
114
+ else {
115
+ console.log(`# query: ${query}`);
116
+ console.log(`# embed ${embedMs}ms · search ${searchMs}ms · ${hits.length} hits\n`);
117
+ console.log(formatHumanReadable(hits));
118
+ }
119
+ }
120
+ finally {
121
+ // Unload-after-use commitment — see Embedder.dispose() docs.
122
+ await embedder.dispose();
123
+ }
124
+ }
125
+ async function cmdMigrate(flags) {
126
+ const buildRoot = String(flags['build-root'] ?? DEFAULT_BUILD_ROOT);
127
+ const workflowsPath = String(flags['workflows'] ?? DEFAULT_WORKFLOWS_PATH);
128
+ const dryRun = Boolean(flags['dry-run']);
129
+ console.log(`migrating ${buildRoot}`);
130
+ console.log(` workflows file: ${workflowsPath}`);
131
+ if (dryRun)
132
+ console.log(' (dry run — nothing will be written)');
133
+ const store = await openWorkflowStore(workflowsPath);
134
+ const report = await runMigrate({ catalogueRoot: buildRoot, store, dryRun });
135
+ console.log('');
136
+ console.log(`scanned: ${report.scanned}`);
137
+ console.log(`migrated: ${report.migrated}`);
138
+ console.log(`skipped: ${report.skipped} (already in workflow store)`);
139
+ console.log('by register:');
140
+ for (const [register, counts] of Object.entries(report.byRegister)) {
141
+ console.log(` ${register.padEnd(15)} scanned=${counts.scanned} migrated=${counts.migrated} skipped=${counts.skipped}`);
142
+ }
143
+ if (report.conflicts.length > 0) {
144
+ console.log('');
145
+ console.log(`⚠ ${report.conflicts.length} handle conflict${report.conflicts.length === 1 ? '' : 's'} — multiple source files share the same handle:`);
146
+ for (const c of report.conflicts) {
147
+ console.log(` ${c.handle}`);
148
+ console.log(` kept: ${c.winnerSourcePath}`);
149
+ console.log(` dropped: ${c.loserSourcePath}`);
150
+ }
151
+ console.log('');
152
+ console.log(' Resolve by renaming the conflicting files (e.g. give them distinct number prefixes) then re-run migrate.');
153
+ }
154
+ console.log(`(${(report.durationMs / 1000).toFixed(2)}s)`);
155
+ }
156
+ async function cmdRegisterDispatch(command, positional, flags) {
157
+ const register = commandToRegister(command);
158
+ if (!register) {
159
+ console.error(`unknown register command: ${command}`);
160
+ process.exit(2);
161
+ }
162
+ const action = positional[0];
163
+ const workflowsPath = String(flags['workflows'] ?? DEFAULT_WORKFLOWS_PATH);
164
+ const buildRoot = String(flags['build-root'] ?? DEFAULT_BUILD_ROOT);
165
+ const store = await openWorkflowStore(workflowsPath);
166
+ const asJson = Boolean(flags['json']);
167
+ switch (action) {
168
+ case 'list':
169
+ case undefined: {
170
+ const status = flags['status'] ? String(flags['status']) : undefined;
171
+ const limit = flags['limit'] ? Number(flags['limit']) : undefined;
172
+ const result = listRegister(store, register, { asJson, status, limit });
173
+ console.log(result.output);
174
+ process.exit(result.exitCode);
175
+ break;
176
+ }
177
+ case 'show': {
178
+ const handle = positional[1];
179
+ if (!handle) {
180
+ console.error(`Usage: nuos-catalogue ${command} show <handle> [--json]`);
181
+ process.exit(2);
182
+ }
183
+ const result = showRecord(store, register, handle, { asJson });
184
+ console.log(result.output);
185
+ process.exit(result.exitCode);
186
+ break;
187
+ }
188
+ case 'advance': {
189
+ if (command !== 'wu') {
190
+ console.error(`'advance' is a wu subcommand only`);
191
+ process.exit(2);
192
+ }
193
+ const runtime = createBuildCatalogueRuntime({ store, catalogueRoot: buildRoot });
194
+ const result = await cmdWuAdvance(store, runtime, {
195
+ handle: positional[1],
196
+ to: flags['to'] ? String(flags['to']) : undefined,
197
+ reason: flags['reason'] ? String(flags['reason']) : undefined,
198
+ });
199
+ console.log(result.output);
200
+ process.exit(result.exitCode);
201
+ break;
202
+ }
203
+ case 'tick': {
204
+ if (command !== 'wu') {
205
+ console.error(`'tick' is a wu subcommand only`);
206
+ process.exit(2);
207
+ }
208
+ const runtime = createBuildCatalogueRuntime({ store, catalogueRoot: buildRoot });
209
+ const result = await cmdWuTick(store, runtime, {
210
+ handle: positional[1],
211
+ index: flags['index'] !== undefined ? Number(flags['index']) : undefined,
212
+ evidence: flags['evidence'] ? String(flags['evidence']) : undefined,
213
+ });
214
+ console.log(result.output);
215
+ process.exit(result.exitCode);
216
+ break;
217
+ }
218
+ case 'supersede': {
219
+ if (command !== 'decision') {
220
+ console.error(`'supersede' is a decision subcommand only`);
221
+ process.exit(2);
222
+ }
223
+ const runtime = createBuildCatalogueRuntime({ store, catalogueRoot: buildRoot });
224
+ const result = await cmdDecisionSupersede(store, runtime, {
225
+ target: positional[1],
226
+ by: flags['by'] ? String(flags['by']) : undefined,
227
+ reason: flags['reason'] ? String(flags['reason']) : undefined,
228
+ });
229
+ console.log(result.output);
230
+ process.exit(result.exitCode);
231
+ break;
232
+ }
233
+ case 'resolve': {
234
+ if (command !== 'question') {
235
+ console.error(`'resolve' is a question subcommand only`);
236
+ process.exit(2);
237
+ }
238
+ const runtime = createBuildCatalogueRuntime({ store, catalogueRoot: buildRoot });
239
+ const result = await cmdQuestionResolve(store, runtime, {
240
+ qHandle: positional[1],
241
+ by: flags['by'] ? String(flags['by']) : undefined,
242
+ reason: flags['reason'] ? String(flags['reason']) : undefined,
243
+ });
244
+ console.log(result.output);
245
+ process.exit(result.exitCode);
246
+ break;
247
+ }
248
+ case 'create': {
249
+ const runtime = createBuildCatalogueRuntime({ store, catalogueRoot: buildRoot });
250
+ const prompt = openPrompt();
251
+ try {
252
+ let result;
253
+ switch (command) {
254
+ case 'wu':
255
+ result = await cmdWuCreate(store, runtime, prompt);
256
+ break;
257
+ case 'decision':
258
+ result = await cmdDecisionCreate(store, runtime, prompt);
259
+ break;
260
+ case 'question':
261
+ result = await cmdQuestionCreate(store, runtime, prompt);
262
+ break;
263
+ case 'persona':
264
+ result = await cmdPersonaCreate(store, runtime, prompt);
265
+ break;
266
+ default:
267
+ console.error(`'create' is not a subcommand of ${command}`);
268
+ process.exit(2);
269
+ }
270
+ console.log(result.output);
271
+ process.exit(result.exitCode);
272
+ }
273
+ finally {
274
+ prompt.close();
275
+ }
276
+ break;
277
+ }
278
+ default:
279
+ console.error(`unknown ${command} action: ${action}`);
280
+ process.exit(2);
281
+ }
282
+ }
283
+ async function cmdRegenerate(flags) {
284
+ const buildRoot = String(flags['build-root'] ?? DEFAULT_BUILD_ROOT);
285
+ const workflowsPath = String(flags['workflows'] ?? DEFAULT_WORKFLOWS_PATH);
286
+ const write = Boolean(flags['write']);
287
+ const showDiffs = Boolean(flags['diff']);
288
+ const registerFilter = flags['register'] ? String(flags['register']) : undefined;
289
+ const store = await openWorkflowStore(workflowsPath);
290
+ if (store.list().length === 0) {
291
+ console.log('workflow store is empty — run `nuos-catalogue migrate` first');
292
+ process.exit(2);
293
+ }
294
+ console.log(`regenerate-check ${buildRoot}`);
295
+ console.log(` workflows file: ${workflowsPath}`);
296
+ if (write)
297
+ console.log(' --write mode: source files will be overwritten with stored canonical form');
298
+ if (registerFilter)
299
+ console.log(` register filter: ${registerFilter}`);
300
+ const report = await runRegenerate({ catalogueRoot: buildRoot, store, registerFilter, write });
301
+ console.log('');
302
+ console.log(`scanned: ${report.total}`);
303
+ console.log(`identical: ${report.identical}`);
304
+ console.log(`differs: ${report.differs}`);
305
+ console.log(`missing: ${report.missing}`);
306
+ console.log(`unreadable: ${report.unreadable}`);
307
+ console.log('by register:');
308
+ for (const [register, counts] of Object.entries(report.byRegister)) {
309
+ if (counts.total === 0)
310
+ continue;
311
+ console.log(` ${register.padEnd(15)} total=${counts.total} identical=${counts.identical} differs=${counts.differs} missing=${counts.missing}`);
312
+ }
313
+ if (report.drifted.length > 0) {
314
+ console.log('');
315
+ console.log(`⚠ ${report.drifted.length} drifted record${report.drifted.length === 1 ? '' : 's'}:`);
316
+ for (const d of report.drifted) {
317
+ if (d.kind === 'differs') {
318
+ const tag = write ? '[overwritten]' : '[differs]';
319
+ console.log(` ${tag.padEnd(14)} ${d.handle.padEnd(10)} ${d.sourcePath} (+${d.linesAdded}/-${d.linesRemoved} lines, ${d.byteDelta} bytes)`);
320
+ }
321
+ else if (d.kind === 'missing-source') {
322
+ console.log(` [missing] ${d.handle.padEnd(10)} ${d.sourcePath}`);
323
+ }
324
+ else if (d.kind === 'unreadable-source') {
325
+ console.log(` [unreadable] ${d.handle.padEnd(10)} ${d.sourcePath} (${d.errorMessage})`);
326
+ }
327
+ }
328
+ if (showDiffs && !write) {
329
+ console.log('');
330
+ console.log('(use --write to overwrite source files with the stored canonical form; --diff is line-count only in Mode 1)');
331
+ }
332
+ }
333
+ console.log(`(${(report.durationMs / 1000).toFixed(2)}s)`);
334
+ process.exit(report.differs > 0 || report.missing > 0 ? 1 : 0);
335
+ }
336
+ async function cmdSummary(flags) {
337
+ const workflowsPath = String(flags['workflows'] ?? DEFAULT_WORKFLOWS_PATH);
338
+ const store = await openWorkflowStore(workflowsPath);
339
+ const { byRegister, total } = listAcrossRegisters(store);
340
+ if (Boolean(flags['json'])) {
341
+ console.log(JSON.stringify({ total, byRegister }, null, 2));
342
+ return;
343
+ }
344
+ console.log(`workflow store: ${workflowsPath}`);
345
+ console.log(`total records: ${total}`);
346
+ console.log('by register:');
347
+ for (const [register, count] of Object.entries(byRegister)) {
348
+ console.log(` ${register.padEnd(15)} ${count}`);
349
+ }
350
+ }
351
+ function cmdHelp() {
352
+ console.log(`nuos-catalogue — NuOS build-catalogue tooling (WU 110, WU 111)
353
+
354
+ Usage:
355
+ nuos-catalogue init [--name=X --tagline="Y" --domain=Z --role=consumer --yes]
356
+ (interactive bootstrap of docs/build/, methodfile.json, .claude/commands/<protocols>, CLAUDE.md, .gitignore overrides; refuses if docs/build/ already exists)
357
+ nuos-catalogue install-protocols
358
+ (refresh .claude/commands/<protocols> from this CLI's bundled canonical bodies)
359
+
360
+ nuos-catalogue index [--force] [--dry-run] [--catalogue=<dir>]
361
+ nuos-catalogue search "<query>" [--kind=<file_kind>] [--status=<s>] [--limit=N] [--json]
362
+ nuos-catalogue migrate [--build-root=<dir>] [--workflows=<file>] [--dry-run]
363
+ nuos-catalogue regenerate [--register=<r>] [--diff] [--write] [--build-root=<dir>] [--workflows=<file>]
364
+
365
+ nuos-catalogue summary [--json]
366
+ nuos-catalogue wu list [--status=<s>] [--limit=N] [--json]
367
+ nuos-catalogue wu show <handle> [--json]
368
+ nuos-catalogue wu create (interactive — multi-step prompts)
369
+ nuos-catalogue wu advance <handle> --to=<status> [--reason="..."]
370
+ nuos-catalogue wu tick <handle> --index=N --evidence="..."
371
+ nuos-catalogue decision list [--status=<s>] [--limit=N] [--json]
372
+ nuos-catalogue decision show <handle> [--json]
373
+ nuos-catalogue decision create (interactive)
374
+ nuos-catalogue decision supersede <target> --by=<superseding> [--reason="..."]
375
+ nuos-catalogue question list [--status=<s>] [--limit=N] [--json]
376
+ nuos-catalogue question show <handle> [--json]
377
+ nuos-catalogue question create (interactive)
378
+ nuos-catalogue question resolve <q-handle> --by=<d-handle> [--reason="..."]
379
+ nuos-catalogue persona list [--limit=N] [--json]
380
+ nuos-catalogue persona show <handle> [--json]
381
+ nuos-catalogue persona create (interactive — seven dimensions + acid-test per D046)
382
+
383
+ nuos-catalogue help
384
+
385
+ Handles accepted: canonical (wu-111, D046, Q009, P001) or friendly
386
+ (WU 111, 111, D45, Q9). Unambiguous integers ("111" under "wu show")
387
+ are normalised to the canonical form.
388
+
389
+ Environment:
390
+ NUOS_CATALOGUE_BUILD_ROOT default for --build-root (the catalogue's docs/build/ dir)
391
+ NUOS_CATALOGUE_WORKFLOWS default for --workflows (the JSON workflow store path)
392
+ NUOS_CATALOGUE_ROOT default for --catalogue (semantic-search index source)
393
+ NUOS_CATALOGUE_INDEX_DIR default parent dir for index.nv + workflows.json
394
+ NUOS_CATALOGUE_EMBEDDER vertex | openai | stub (default: vertex)
395
+ GOOGLE_CLOUD_PROJECT required for vertex
396
+ GOOGLE_CLOUD_LOCATION optional (default: us-central1)
397
+ OPENAI_API_KEY required for openai
398
+ `);
399
+ }
400
+ async function main() {
401
+ const args = parseArgs(process.argv.slice(2));
402
+ switch (args.command) {
403
+ case 'index':
404
+ await cmdIndex(args.flags);
405
+ break;
406
+ case 'search':
407
+ await cmdSearch(args.positional, args.flags);
408
+ break;
409
+ case 'init': {
410
+ const prompt = openPrompt();
411
+ try {
412
+ const result = await cmdInit(prompt, {
413
+ cwd: process.cwd(),
414
+ name: args.flags['name'] ? String(args.flags['name']) : undefined,
415
+ tagline: args.flags['tagline'] ? String(args.flags['tagline']) : undefined,
416
+ domain: args.flags['domain'] ? String(args.flags['domain']) : undefined,
417
+ role: args.flags['role'] ? String(args.flags['role']) : undefined,
418
+ nonInteractive: Boolean(args.flags['yes']),
419
+ });
420
+ if (result.output)
421
+ console.log(result.output);
422
+ process.exit(result.exitCode);
423
+ }
424
+ finally {
425
+ prompt.close();
426
+ }
427
+ break;
428
+ }
429
+ case 'install-protocols': {
430
+ const prompt = openPrompt();
431
+ try {
432
+ const result = await cmdInstallProtocols(prompt, { cwd: process.cwd() });
433
+ if (result.output)
434
+ console.log(result.output);
435
+ process.exit(result.exitCode);
436
+ }
437
+ finally {
438
+ prompt.close();
439
+ }
440
+ break;
441
+ }
442
+ case 'migrate':
443
+ await cmdMigrate(args.flags);
444
+ break;
445
+ case 'regenerate':
446
+ await cmdRegenerate(args.flags);
447
+ break;
448
+ case 'summary':
449
+ await cmdSummary(args.flags);
450
+ break;
451
+ case 'wu':
452
+ case 'decision':
453
+ case 'question':
454
+ case 'persona':
455
+ await cmdRegisterDispatch(args.command, args.positional, args.flags);
456
+ break;
457
+ case 'help':
458
+ case '--help':
459
+ case '-h':
460
+ case undefined:
461
+ cmdHelp();
462
+ break;
463
+ default:
464
+ console.error(`unknown command: ${args.command}`);
465
+ cmdHelp();
466
+ process.exit(2);
467
+ }
468
+ }
469
+ main().catch((err) => {
470
+ console.error(err instanceof Error ? err.stack ?? err.message : err);
471
+ process.exit(1);
472
+ });
@@ -0,0 +1,70 @@
1
+ /**
2
+ * Phase H part 3 — interactive create commands.
3
+ *
4
+ * Four commands: `wu create`, `decision create`, `question create`,
5
+ * `persona create`. Each walks the operator through the relevant
6
+ * register's protocol body (per `scripts/protocols/wu-new.md` etc.)
7
+ * and drives the workflow lifecycle to commit.
8
+ *
9
+ * Capture-builders are split out as pure functions so tests can verify
10
+ * the typed-payload shape without exercising readline. The interactive
11
+ * shell (`cmdWu*Create`) prompts, calls the builder, and drives the
12
+ * runtime.
13
+ */
14
+ import type { NuFlowRuntime, CaptureInput } from '@nusoft/nuflow';
15
+ import type { WorkflowStore } from '../migrate/store.js';
16
+ import type { MigratedRecord, Register } from '../migrate/types.js';
17
+ import { type Prompt } from './prompt.js';
18
+ export interface CreateHandlerResult {
19
+ output: string;
20
+ exitCode: number;
21
+ }
22
+ export declare function existingNumbersForRegister(store: WorkflowStore, register: Register): readonly number[];
23
+ export declare function cmdDecisionCreate(store: WorkflowStore, runtime: NuFlowRuntime, prompt: Prompt): Promise<CreateHandlerResult>;
24
+ export declare function cmdQuestionCreate(store: WorkflowStore, runtime: NuFlowRuntime, prompt: Prompt): Promise<CreateHandlerResult>;
25
+ export declare function cmdPersonaCreate(store: WorkflowStore, runtime: NuFlowRuntime, prompt: Prompt): Promise<CreateHandlerResult>;
26
+ export declare function cmdWuCreate(store: WorkflowStore, runtime: NuFlowRuntime, prompt: Prompt): Promise<CreateHandlerResult>;
27
+ export interface DecisionCreateInputs {
28
+ title: string;
29
+ context: string;
30
+ decision: string;
31
+ consequences: string;
32
+ alternativesConsidered?: string;
33
+ }
34
+ export declare function buildDecisionCreateCapture(store: WorkflowStore, inputs: DecisionCreateInputs): CaptureInput;
35
+ export interface QuestionCreateInputs {
36
+ title: string;
37
+ whyItMatters: string;
38
+ options?: string;
39
+ evidenceNeeded?: string;
40
+ blocks?: readonly string[];
41
+ }
42
+ export declare function buildQuestionCreateCapture(store: WorkflowStore, inputs: QuestionCreateInputs): CaptureInput;
43
+ export interface PersonaCreateInputs {
44
+ title: string;
45
+ identity: string;
46
+ reality: string;
47
+ psychology: string;
48
+ trigger: string;
49
+ history: string;
50
+ success: string;
51
+ constraints: string;
52
+ acidTest: string;
53
+ }
54
+ export declare function buildPersonaCreateCapture(store: WorkflowStore, inputs: PersonaCreateInputs): CaptureInput;
55
+ export interface WuCreateInputs {
56
+ title: string;
57
+ kind: 'feature' | 'infrastructure' | 'spike' | 'remediation';
58
+ phase?: string;
59
+ dependsOn?: readonly string[];
60
+ blocks?: readonly string[];
61
+ personaRef?: string;
62
+ trigger?: string;
63
+ walkthrough?: string;
64
+ acceptanceCriteria?: readonly string[];
65
+ contractsProduced: readonly string[];
66
+ contractsConsumed: readonly string[];
67
+ approach?: string;
68
+ }
69
+ export declare function buildWuCreateCapture(store: WorkflowStore, inputs: WuCreateInputs): CaptureInput;
70
+ export type { MigratedRecord };