@aopslab/domain-tooling-docman 0.1.4

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.
package/dist/tools.js ADDED
@@ -0,0 +1,926 @@
1
+ import { buildDocmanDomainCapabilityManifest as buildDocmanDomainCapabilityManifestFromKit, buildDocmanHostRouteProjection as buildDocmanHostRouteProjectionFromKit, clearDocmanKitEnvConfigCache, clearDocmanKitOperationCaches, listDocmanOperationSpecs as listDocmanOperationSpecsFromKit, parseDocmanToolInput, runDocmanKitOperationById, } from '@aopslab/domain-kit-docman';
2
+ import { DOCMAN_TOOL_SPECS } from '@aopslab/domain-ops-docman/specs';
3
+ const DEFAULT_DOCMAN_SCOPE_ID = '00000000-0000-4000-8000-000000000000';
4
+ const DOCMAN_MANIFEST_ARTIFACTS = [
5
+ {
6
+ id: 'dcm',
7
+ title: 'Domain Capability Manifest',
8
+ summary: 'Canonical capability source derived from Docman kit contracts, docs, policies, and schemas.',
9
+ canonicalRole: 'canonical',
10
+ },
11
+ {
12
+ id: 'routes',
13
+ title: 'Host Route Projection',
14
+ summary: 'HTTP route projection derived from the canonical DCM.',
15
+ canonicalRole: 'projection',
16
+ },
17
+ {
18
+ id: 'agent',
19
+ title: 'Agent Tool Manifest',
20
+ summary: 'Agent-oriented tool descriptor projection derived from DCM docs, aliases, and policy.',
21
+ canonicalRole: 'projection',
22
+ },
23
+ {
24
+ id: 'cli',
25
+ title: 'CLI Projection',
26
+ summary: 'Derived command/help projection for standalone CLI users and local agents. DCM remains canonical.',
27
+ canonicalRole: 'projection',
28
+ },
29
+ {
30
+ id: 'host-registration',
31
+ aliases: ['hrm'],
32
+ title: 'Host Registration Manifest',
33
+ summary: 'AOPS/runtime registration payload. HRM is not a capability source.',
34
+ canonicalRole: 'registration',
35
+ },
36
+ {
37
+ id: 'ops',
38
+ aliases: ['operations'],
39
+ title: 'Operation Specs',
40
+ summary: 'Resolved shared operation specs and contract args used by tooling/CLI surfaces.',
41
+ canonicalRole: 'list',
42
+ },
43
+ ];
44
+ function normalizeIdentifier(value) {
45
+ return String(value ?? '').trim().toLowerCase().replace(/^\/+/, '');
46
+ }
47
+ function normalizeOperationId(value) {
48
+ return normalizeIdentifier(value)
49
+ .replace(/^operations\//, '')
50
+ .replace(/^api\/docman\/operations\//, '')
51
+ .replace(/\//g, '.')
52
+ .replace(/\.+/g, '.')
53
+ .replace(/^docman\./, '');
54
+ }
55
+ function normalizeNonEmptyString(value) {
56
+ if (typeof value !== 'string')
57
+ return undefined;
58
+ const normalized = value.trim();
59
+ return normalized.length > 0 ? normalized : undefined;
60
+ }
61
+ function toOperationPath(operationId) {
62
+ return `operations/${operationId.replace(/\./g, '/')}`;
63
+ }
64
+ function toGatewayToolId(operationId) {
65
+ return `docman.${operationId}`;
66
+ }
67
+ function toLocalFallbackToolId(operationId) {
68
+ return `docman-${operationId.replace(/\./g, '-')}`;
69
+ }
70
+ function buildAliases(spec) {
71
+ const aliases = new Set();
72
+ const opId = normalizeOperationId(spec.operationId);
73
+ const gatewayToolId = toGatewayToolId(opId);
74
+ const localToolId = normalizeIdentifier(spec.toolId);
75
+ aliases.add(opId);
76
+ aliases.add(gatewayToolId);
77
+ aliases.add(localToolId);
78
+ aliases.add(toLocalFallbackToolId(opId));
79
+ aliases.add(toOperationPath(opId));
80
+ aliases.add('/' + toOperationPath(opId));
81
+ return [...aliases];
82
+ }
83
+ function buildOperationAliasIndex(specs) {
84
+ const index = new Map();
85
+ for (const spec of specs) {
86
+ for (const alias of buildAliases(spec)) {
87
+ index.set(normalizeIdentifier(alias), spec.operationId);
88
+ }
89
+ }
90
+ return index;
91
+ }
92
+ function toOperationMap(specs) {
93
+ return new Map(specs.map((spec) => [normalizeOperationId(spec.operationId), spec]));
94
+ }
95
+ function toOperationRefMap(manifest) {
96
+ return new Map(manifest.capabilities.operations.map((operation) => [normalizeOperationId(operation.operationId), operation]));
97
+ }
98
+ function toRouteMap(routes) {
99
+ return new Map(routes.map((route) => [normalizeOperationId(route.operation), route]));
100
+ }
101
+ function toRecord(input) {
102
+ if (!input || typeof input !== 'object' || Array.isArray(input))
103
+ return {};
104
+ return input;
105
+ }
106
+ function toStringList(value) {
107
+ if (!Array.isArray(value))
108
+ return [];
109
+ return value
110
+ .map((entry) => String(entry ?? '').trim())
111
+ .filter(Boolean);
112
+ }
113
+ function mergeStringLists(...groups) {
114
+ const merged = new Set();
115
+ for (const group of groups) {
116
+ if (!group)
117
+ continue;
118
+ for (const entry of group) {
119
+ const normalized = String(entry ?? '').trim();
120
+ if (!normalized)
121
+ continue;
122
+ merged.add(normalized);
123
+ }
124
+ }
125
+ return [...merged];
126
+ }
127
+ function toKebabCase(value) {
128
+ return value
129
+ .replace(/([a-z0-9])([A-Z])/g, '$1-$2')
130
+ .replace(/[_\s.]+/g, '-')
131
+ .toLowerCase();
132
+ }
133
+ function appendSection(target, title, lines) {
134
+ const normalized = lines.map((line) => String(line ?? '').trimEnd()).filter(Boolean);
135
+ if (normalized.length === 0)
136
+ return;
137
+ target.push({ title, lines: normalized });
138
+ }
139
+ function buildExampleValueHint(option) {
140
+ const name = String(option.name ?? '').trim();
141
+ const type = String(option.type ?? '').trim().toLowerCase();
142
+ if (type === 'json') {
143
+ if (name === 'filter')
144
+ return '\'{}\'';
145
+ if (name === 'options')
146
+ return '\'{"limit":5}\'';
147
+ if (name === 'data')
148
+ return '\'{"...":"..."}\'';
149
+ if (name === 'patch')
150
+ return '\'{"...":"..."}\'';
151
+ return '\'{}\'';
152
+ }
153
+ if (type === 'number')
154
+ return '1';
155
+ if (type === 'boolean')
156
+ return 'true';
157
+ return String(option.valueHint ?? `<${name || 'value'}>`).trim();
158
+ }
159
+ function buildOptionLabel(option) {
160
+ const flag = String(option.flag ?? '').trim();
161
+ const valueHint = String(option.valueHint ?? '').trim();
162
+ if (!flag)
163
+ return '';
164
+ const withValue = valueHint ? `${flag} ${valueHint}` : flag;
165
+ return option.required ? `${withValue} (required)` : withValue;
166
+ }
167
+ function buildSugarUsage(commandSpec) {
168
+ const tokens = [...commandSpec.command];
169
+ for (const option of commandSpec.options ?? []) {
170
+ const label = buildOptionLabel(option);
171
+ if (!label)
172
+ continue;
173
+ tokens.push(option.required ? label.replace(' (required)', '') : `[${label}]`);
174
+ }
175
+ tokens.push('[--help]');
176
+ return tokens.join(' ');
177
+ }
178
+ function buildSugarExample(commandSpec) {
179
+ const tokens = [...commandSpec.command];
180
+ const options = [...(commandSpec.options ?? [])];
181
+ const selected = options.filter((option) => option.required);
182
+ if (selected.length === 0) {
183
+ const filterOption = options.find((option) => option.name === 'filter');
184
+ if (filterOption)
185
+ selected.push(filterOption);
186
+ }
187
+ for (const option of selected) {
188
+ if (!option.flag)
189
+ continue;
190
+ tokens.push(option.flag);
191
+ if (option.type !== 'boolean') {
192
+ tokens.push(buildExampleValueHint(option));
193
+ }
194
+ }
195
+ return tokens.join(' ');
196
+ }
197
+ function buildOperationArgRows(spec, commandSpec) {
198
+ if (commandSpec && (commandSpec.options?.length ?? 0) > 0) {
199
+ return (commandSpec.options ?? []).map((option) => {
200
+ const label = buildOptionLabel(option);
201
+ const details = [
202
+ option.description ? String(option.description).trim() : '',
203
+ option.type ? `type=${option.type}` : '',
204
+ ].filter(Boolean);
205
+ return details.length > 0 ? `${label} ${details.join('; ')}` : label;
206
+ });
207
+ }
208
+ return spec.args.map((arg) => {
209
+ const flag = `--${toKebabCase(arg.name)}`;
210
+ const label = arg.optional ? `${flag} <${arg.name}>` : `${flag} <${arg.name}> (required)`;
211
+ return `${label} Contract arg`;
212
+ });
213
+ }
214
+ function buildCommonRuntimeHelpRows(includeNoHook) {
215
+ const rows = [
216
+ '--repo-url <repo-url> Override runtime repo URL for this invocation',
217
+ '--scope-id <id> Override scope id for this invocation',
218
+ '--tenant-id <uuid> Override tenant id for this invocation',
219
+ '--execution-mode <host|tooling> Force host or tooling execution mode',
220
+ '--host-config <path> Resolve runtime env from an explicit host config file',
221
+ '--log-level <level> Override log level for this invocation',
222
+ '--help Show command help without executing the command',
223
+ ];
224
+ if (includeNoHook)
225
+ rows.splice(rows.length - 1, 0, '--no-hook Generated sugar only; bypass alias hook adaptation');
226
+ return rows;
227
+ }
228
+ function findCommandSpecForOperation(operationId) {
229
+ const localFallbackToolId = toLocalFallbackToolId(normalizeOperationId(operationId));
230
+ return DOCMAN_TOOL_SPECS.find((spec) => String(spec.id ?? '').trim().toLowerCase() === localFallbackToolId);
231
+ }
232
+ function createCommandDescriptor(input) {
233
+ return {
234
+ id: input.id,
235
+ kind: input.kind,
236
+ title: input.title,
237
+ command: input.command,
238
+ aliases: [...new Set((input.aliases ?? []).map((entry) => String(entry ?? '').trim()).filter(Boolean))],
239
+ ...(input.summary ? { summary: input.summary } : {}),
240
+ ...(input.operationId ? { operationId: input.operationId } : {}),
241
+ ...(input.toolId ? { toolId: input.toolId } : {}),
242
+ ...(input.localToolId ? { localToolId: input.localToolId } : {}),
243
+ sections: input.sections,
244
+ };
245
+ }
246
+ function buildRootCommandDescriptor() {
247
+ const sections = [];
248
+ appendSection(sections, 'IMPORTANT NOTICE', [
249
+ 'This is a beta CLI. Do not point it at production Docman databases unless you already have backups and rollback procedures.',
250
+ 'For AI-agent experiments, strongly prefer a temporary or non-production repo URL first.',
251
+ ]);
252
+ appendSection(sections, 'Purpose', [
253
+ 'docman-cli is a standalone Docman runtime for document graphs, versions, sections, pages, snippets, embeds, compose/render flows, and manifest-driven CRUD/operation execution.',
254
+ 'It can run directly against PostgreSQL or SQLite, persist local CLI config under ~/.aops/docman.config.json, default to ~/.aops/docman.aops.sqlite when no Docman-specific repo source is configured, and expose the same manifest surface to AOPS when needed.',
255
+ ]);
256
+ appendSection(sections, 'Standalone usage', [
257
+ '1. If no Docman repo source is set, docman auto-uses ~/.aops/docman.aops.sqlite.',
258
+ '2. Inspect tools, ops, or manifest before mutating data.',
259
+ '3. Prefer canonical tool / op calls when the exact contract matters.',
260
+ '4. Generated sugar is useful for short CRUD flows; use --no-hook to bypass alias hooks.',
261
+ '5. Generic AOPS_PG_URL / DEV_PG_URL env values do not override standalone default sqlite.',
262
+ ]);
263
+ appendSection(sections, 'AOPS alternative', [
264
+ '1. If AOPS is installed, register Docman from `docman manifest host-registration`.',
265
+ '2. Typical path: `aops-cli host register --from-command \'docman manifest host-registration\'`.',
266
+ '3. Discover via `aops-cli agent tools --domain docman --workspace-name Default` or `GET /api/agent/tools?domain=docman`.',
267
+ '4. Read tool detail first when discovery/docs/examples matter, then invoke through `aops-cli agent invoke ...` or `POST /api/agent/tools/<toolId>/invoke`.',
268
+ '5. Prefer AOPS-first when you want shared discovery, auth, host diagnostics, or routing.',
269
+ '6. Canonical content owner is `scopeId`; AOPS `workspace-name` / `project-id` values are resolver helpers.',
270
+ ]);
271
+ appendSection(sections, 'Usage', [
272
+ 'docman <command> [subcommand] [--options]',
273
+ 'docman <command> --help',
274
+ 'docman help <command> [subcommand]',
275
+ 'docman --version',
276
+ ]);
277
+ appendSection(sections, 'Core commands', [
278
+ 'docman tools',
279
+ 'docman ops',
280
+ 'docman manifest [dcm|routes|agent|cli|host-registration|ops]',
281
+ 'docman manifest get <artifact> [--path <dot.path>]',
282
+ 'docman manifest show <artifact> [--path <dot.path>]',
283
+ 'docman config show',
284
+ 'docman config set --repo-url <repo-url>',
285
+ 'docman version',
286
+ 'docman tool --id <tool-or-operation-id> --input <json|@file>',
287
+ 'docman op <operation-or-tool-id> [--input <json|@file>] [--arg value]',
288
+ 'Not: op/operation/run raw-canonical moddur; hooklar default olarak BYPASS edilir.',
289
+ ]);
290
+ appendSection(sections, 'Generated sugar commands (manifest-driven aliases)', [
291
+ 'docman <resource> <action> [--flags]',
292
+ 'or directly: docman <operation.id> [--flags]',
293
+ ]);
294
+ appendSection(sections, 'Runtime options', [
295
+ '--repo-url <repo-url> (precedence: flag -> DOCMAN_REPO_URL/DOCMAN_SQLITE_URL/DOCMAN_PG_URL -> ~/.aops/docman.config.json -> aops config -> default ~/.aops/docman.aops.sqlite)',
296
+ `--scope-id <id> (default: ${DEFAULT_DOCMAN_SCOPE_ID})`,
297
+ '--tenant-id <uuid> (default: DEFAULT_TENANT_AS_UUID_STRING)',
298
+ '--execution-mode <host|tooling> (default: host)',
299
+ '--host-config <path> (opsiyonel; single-domain host config. yoksa local resolver kullanilir)',
300
+ '--no-hook (generated sugar komutlarinda domain hooklarini kapatir)',
301
+ '--log-level <level> (default: LOG_LEVEL env)',
302
+ '--help',
303
+ ]);
304
+ appendSection(sections, 'Typical repo-url patterns', [
305
+ '--repo-url postgres://user:pass@host:5432/dbname',
306
+ '--repo-url file:/absolute/path/docman.sqlite',
307
+ 'no --repo-url => varsayilan sqlite (~/.aops/docman.aops.sqlite; exact path icin: docman config show)',
308
+ 'export DOCMAN_PG_URL=postgres://user:pass@host:5432/dbname',
309
+ 'export DOCMAN_SQLITE_URL=file:/absolute/path/docman.sqlite',
310
+ `docman config set --repo-url file:/absolute/path/docman.sqlite --scope-id ${DEFAULT_DOCMAN_SCOPE_ID}`,
311
+ 'For temporary AI-agent trials, prefer an isolated database or local sqlite file.',
312
+ ]);
313
+ appendSection(sections, 'Common AI-agent scenarios', [
314
+ 'inspect catalog and examples before mutate',
315
+ 'persist one safe repo-url once, then reuse docman without repeating --repo-url',
316
+ 'create/list/get documents and versions',
317
+ 'compose or render markdown from an existing document version',
318
+ 'exercise hooks for convenience, then fall back to canonical op/tool when needed',
319
+ 'inspect detailed command help generated from DCM/contract docs before invoke',
320
+ 'inspect DCM/CLI/HRM artifacts via `manifest get` or `manifest show` before autonomous invoke',
321
+ ]);
322
+ appendSection(sections, 'Examples', [
323
+ 'docman config show',
324
+ 'docman config set --help',
325
+ 'docman document list --help',
326
+ 'docman op docman.document.compose.fetch --help',
327
+ 'docman manifest cli',
328
+ 'docman manifest get dcm --path docs.operations.document.list',
329
+ 'docman manifest show hrm',
330
+ 'docman document list --filter \'{}\' # default local sqlite if no repo source is configured',
331
+ `docman config set --repo-url postgres://user:pass@host:5432/docman --scope-id ${DEFAULT_DOCMAN_SCOPE_ID}`,
332
+ `docman config set --repo-url file:/tmp/docman.sqlite --scope-id ${DEFAULT_DOCMAN_SCOPE_ID}`,
333
+ 'docman tool --id docman.document.list --input \'{"filter":{},"options":{"limit":5}}\'',
334
+ 'docman op docman.document.list --input \'{"filter":{},"options":{"limit":5}}\'',
335
+ 'docman document list --filter \'{}\' --options \'{"limit":5}\'',
336
+ 'docman tool --id docman.document.create --input \'{"data":{"documentUid":"DOC-001","title":"Sample","status":"draft","visibility":"internal"}}\'',
337
+ 'docman document get --document-id <id> # hook alias',
338
+ 'docman document get --document-id <id> --no-hook # hook disabled => requires --id',
339
+ 'docman op docman.document.compose.fetch --document-version-id <id>',
340
+ 'docman op docman.document.compose.fetch --input \'{"documentVersionId":"<id>","pageNumber":1}\'',
341
+ ]);
342
+ return createCommandDescriptor({
343
+ id: 'docman',
344
+ kind: 'root',
345
+ title: 'docman-cli',
346
+ command: ['docman'],
347
+ aliases: ['docman', 'help'],
348
+ summary: 'Standalone Docman CLI runtime and manifest browser.',
349
+ sections,
350
+ });
351
+ }
352
+ function buildConfigCommandDescriptors() {
353
+ const commonAliases = ['config'];
354
+ const configSections = [];
355
+ appendSection(configSections, 'Usage', [
356
+ 'docman config show',
357
+ 'docman config set --repo-url <repo-url>',
358
+ 'docman config --help',
359
+ ]);
360
+ appendSection(configSections, 'Subcommands', [
361
+ 'show Inspect stored/default/effective runtime config',
362
+ 'set Persist CLI defaults under ~/.aops/docman.config.json',
363
+ ]);
364
+ appendSection(configSections, 'Examples', [
365
+ 'docman config show',
366
+ `docman config set --repo-url file:/tmp/docman.sqlite --scope-id ${DEFAULT_DOCMAN_SCOPE_ID}`,
367
+ ]);
368
+ const showSections = [];
369
+ appendSection(showSections, 'Usage', ['docman config show', 'docman config show --help']);
370
+ appendSection(showSections, 'Purpose', [
371
+ 'Display stored CLI config, resolved defaults, and effective runtime values without mutating anything.',
372
+ 'Output includes defaultSqlitePath/defaultSqliteRepoUrl when standalone fallback is active.',
373
+ ]);
374
+ appendSection(showSections, 'Fields', [
375
+ 'configPath / exists / stored Stored CLI config under ~/.aops/docman.config.json',
376
+ 'defaults.aopsConfigRepoUrl Repo URL discovered from ~/.aops/aops.config.json when present',
377
+ 'defaults.defaultSqlitePath / defaultSqliteRepoUrl Standalone fallback target under ~/.aops/',
378
+ 'effective.* Final runtime values and their sources',
379
+ ]);
380
+ appendSection(showSections, 'Examples', ['docman config show']);
381
+ const setSections = [];
382
+ appendSection(setSections, 'Usage', [
383
+ 'docman config set [--repo-url <repo-url>] [--scope-id <id>] [--tenant-id <uuid>]',
384
+ 'docman config set [--execution-mode <host|tooling>] [--host-config <path>] [--log-level <level>]',
385
+ 'docman config set --help',
386
+ ]);
387
+ appendSection(setSections, 'Purpose', [
388
+ 'Persist CLI defaults under ~/.aops/docman.config.json.',
389
+ 'Only provided keys are updated; omitted keys stay unchanged.',
390
+ ]);
391
+ appendSection(setSections, 'Options', [
392
+ '--repo-url <repo-url> Persist PostgreSQL or SQLite repo URL',
393
+ '--scope-id <id> Persist default scope id',
394
+ '--tenant-id <uuid> Persist default tenant id',
395
+ '--execution-mode <host|tooling> Persist default execution mode',
396
+ '--host-config <path> Persist explicit host config path',
397
+ '--log-level <level> Persist default log level',
398
+ '--help Show command help without writing config',
399
+ ]);
400
+ appendSection(setSections, 'Examples', [
401
+ `docman config set --repo-url file:/tmp/docman.sqlite --scope-id ${DEFAULT_DOCMAN_SCOPE_ID} --execution-mode host`,
402
+ 'docman config set --repo-url postgresql://host:5432/docman --execution-mode tooling',
403
+ ]);
404
+ return [
405
+ createCommandDescriptor({
406
+ id: 'config',
407
+ kind: 'static',
408
+ title: 'docman config',
409
+ command: ['docman', 'config'],
410
+ aliases: commonAliases,
411
+ summary: 'Inspect or persist standalone CLI config.',
412
+ sections: configSections,
413
+ }),
414
+ createCommandDescriptor({
415
+ id: 'config.show',
416
+ kind: 'static',
417
+ title: 'docman config show',
418
+ command: ['docman', 'config', 'show'],
419
+ aliases: ['config show'],
420
+ summary: 'Display stored/default/effective runtime config.',
421
+ sections: showSections,
422
+ }),
423
+ createCommandDescriptor({
424
+ id: 'config.set',
425
+ kind: 'static',
426
+ title: 'docman config set',
427
+ command: ['docman', 'config', 'set'],
428
+ aliases: ['config set'],
429
+ summary: 'Persist standalone CLI defaults.',
430
+ sections: setSections,
431
+ }),
432
+ ];
433
+ }
434
+ function buildManifestCommandDescriptors() {
435
+ const manifestSections = [];
436
+ appendSection(manifestSections, 'Usage', [
437
+ 'docman manifest [all|dcm|routes|agent|cli|host-registration|ops]',
438
+ 'docman manifest get <artifact> [--path <dot.path>]',
439
+ 'docman manifest show <artifact> [--path <dot.path>]',
440
+ 'docman manifest --help',
441
+ ]);
442
+ appendSection(manifestSections, 'Subcommands', [
443
+ 'all Emit dcm + routes + agent + cli + host-registration + operations',
444
+ 'dcm Emit Domain Capability Manifest; canonical capability source',
445
+ 'routes Emit host route projection derived from DCM',
446
+ 'agent Emit agent-oriented tool descriptor manifest',
447
+ 'cli Emit derived CLI projection/help manifest',
448
+ 'host-registration Emit installed host registration payload (HRM; runtime registration only)',
449
+ 'ops Emit shared operation spec list',
450
+ 'get Extract raw JSON from a manifest artifact or a sub-path',
451
+ 'show Render a manifest artifact or a sub-path as human-readable text',
452
+ ]);
453
+ appendSection(manifestSections, 'Artifacts', DOCMAN_MANIFEST_ARTIFACTS.map((artifact) => {
454
+ const aliasLabel = artifact.aliases?.length ? ` (aliases: ${artifact.aliases.join(', ')})` : '';
455
+ return `${artifact.id}${aliasLabel} ${artifact.summary}`;
456
+ }));
457
+ const dcmSections = [];
458
+ appendSection(dcmSections, 'Usage', ['docman manifest dcm', 'docman manifest dcm --help']);
459
+ appendSection(dcmSections, 'Purpose', [
460
+ 'Emit Docman Domain Capability Manifest (DCM).',
461
+ 'DCM is the canonical capability source; CLI/agent/routes are derived projections.',
462
+ ]);
463
+ appendSection(dcmSections, 'Typical Consumers', [
464
+ 'CLI contextual help',
465
+ 'AOPS discovery and tool projection',
466
+ 'Agent-side contract/schema inspection',
467
+ ]);
468
+ const routesSections = [];
469
+ appendSection(routesSections, 'Usage', ['docman manifest routes', 'docman manifest routes --help']);
470
+ appendSection(routesSections, 'Purpose', [
471
+ 'Emit host route projection derived from the Docman manifest.',
472
+ 'Useful when you want HTTP method/pattern visibility for each operation.',
473
+ ]);
474
+ const agentSections = [];
475
+ appendSection(agentSections, 'Usage', ['docman manifest agent', 'docman manifest agent --help']);
476
+ appendSection(agentSections, 'Purpose', [
477
+ 'Emit agent-oriented tool descriptor list derived from DCM docs, aliases, routes, and policy.',
478
+ 'Useful for discovery surfaces that need tool ids, aliases, notes, examples, and schema refs.',
479
+ ]);
480
+ const cliSections = [];
481
+ appendSection(cliSections, 'Usage', ['docman manifest cli', 'docman manifest cli --help']);
482
+ appendSection(cliSections, 'Purpose', [
483
+ 'Emit the derived CLI projection used by standalone help, manifest show/get, and local agent browse flows.',
484
+ 'This is a read-only projection. DCM remains the canonical source of truth.',
485
+ ]);
486
+ const hrmSections = [];
487
+ appendSection(hrmSections, 'Usage', ['docman manifest host-registration', 'docman manifest host-registration --help']);
488
+ appendSection(hrmSections, 'Purpose', [
489
+ 'Emit installed-host registration payload for AOPS host registration.',
490
+ 'HRM is runtime registration metadata; it is not a second capability source.',
491
+ 'Typical path: aops-cli host register --from-command \'docman manifest host-registration\'',
492
+ ]);
493
+ const opsSections = [];
494
+ appendSection(opsSections, 'Usage', ['docman manifest ops', 'docman manifest ops --help']);
495
+ appendSection(opsSections, 'Purpose', [
496
+ 'Emit the shared resolved operation spec list that powers tooling/CLI projection.',
497
+ 'Use when you want raw operation summaries, args, and examples without the wider DCM envelope.',
498
+ ]);
499
+ const getSections = [];
500
+ appendSection(getSections, 'Usage', [
501
+ 'docman manifest get <artifact>',
502
+ 'docman manifest get <artifact> --path <dot.path>',
503
+ 'docman manifest get dcm --path docs.operations.document.list',
504
+ 'docman manifest get cli --path commandsById.document.list',
505
+ ]);
506
+ appendSection(getSections, 'Purpose', [
507
+ 'Print raw JSON from a selected manifest artifact or sub-path.',
508
+ 'Dot paths support dotted map keys such as docs.operations.document.list or commandsById.config.set.',
509
+ ]);
510
+ const showSections = [];
511
+ appendSection(showSections, 'Usage', [
512
+ 'docman manifest show <artifact>',
513
+ 'docman manifest show <artifact> --path <dot.path>',
514
+ 'docman manifest show hrm',
515
+ 'docman manifest show dcm --path docs.operations.document.list',
516
+ ]);
517
+ appendSection(showSections, 'Purpose', [
518
+ 'Render a selected manifest artifact or sub-path as human-readable text.',
519
+ 'Useful for humans and AI agents that need to inspect summaries, notes, examples, and command sections before invoke.',
520
+ ]);
521
+ return [
522
+ createCommandDescriptor({
523
+ id: 'manifest',
524
+ kind: 'static',
525
+ title: 'docman manifest',
526
+ command: ['docman', 'manifest'],
527
+ aliases: ['manifest'],
528
+ summary: 'Browse canonical and derived Docman manifests.',
529
+ sections: manifestSections,
530
+ }),
531
+ createCommandDescriptor({
532
+ id: 'manifest.dcm',
533
+ kind: 'static',
534
+ title: 'docman manifest dcm',
535
+ command: ['docman', 'manifest', 'dcm'],
536
+ aliases: ['manifest dcm'],
537
+ summary: 'Emit canonical Docman DCM.',
538
+ sections: dcmSections,
539
+ }),
540
+ createCommandDescriptor({
541
+ id: 'manifest.routes',
542
+ kind: 'static',
543
+ title: 'docman manifest routes',
544
+ command: ['docman', 'manifest', 'routes'],
545
+ aliases: ['manifest routes'],
546
+ summary: 'Emit host route projection.',
547
+ sections: routesSections,
548
+ }),
549
+ createCommandDescriptor({
550
+ id: 'manifest.agent',
551
+ kind: 'static',
552
+ title: 'docman manifest agent',
553
+ command: ['docman', 'manifest', 'agent'],
554
+ aliases: ['manifest agent'],
555
+ summary: 'Emit agent tool projection.',
556
+ sections: agentSections,
557
+ }),
558
+ createCommandDescriptor({
559
+ id: 'manifest.cli',
560
+ kind: 'static',
561
+ title: 'docman manifest cli',
562
+ command: ['docman', 'manifest', 'cli'],
563
+ aliases: ['manifest cli'],
564
+ summary: 'Emit derived CLI projection.',
565
+ sections: cliSections,
566
+ }),
567
+ createCommandDescriptor({
568
+ id: 'manifest.host-registration',
569
+ kind: 'static',
570
+ title: 'docman manifest host-registration',
571
+ command: ['docman', 'manifest', 'host-registration'],
572
+ aliases: ['manifest host-registration', 'manifest hrm'],
573
+ summary: 'Emit host registration payload.',
574
+ sections: hrmSections,
575
+ }),
576
+ createCommandDescriptor({
577
+ id: 'manifest.ops',
578
+ kind: 'static',
579
+ title: 'docman manifest ops',
580
+ command: ['docman', 'manifest', 'ops'],
581
+ aliases: ['manifest ops', 'manifest operations'],
582
+ summary: 'Emit shared operation spec list.',
583
+ sections: opsSections,
584
+ }),
585
+ createCommandDescriptor({
586
+ id: 'manifest.get',
587
+ kind: 'static',
588
+ title: 'docman manifest get',
589
+ command: ['docman', 'manifest', 'get'],
590
+ aliases: ['manifest get'],
591
+ summary: 'Extract raw JSON from a manifest artifact.',
592
+ sections: getSections,
593
+ }),
594
+ createCommandDescriptor({
595
+ id: 'manifest.show',
596
+ kind: 'static',
597
+ title: 'docman manifest show',
598
+ command: ['docman', 'manifest', 'show'],
599
+ aliases: ['manifest show'],
600
+ summary: 'Render a manifest artifact as text.',
601
+ sections: showSections,
602
+ }),
603
+ ];
604
+ }
605
+ function buildToolsCommandDescriptor() {
606
+ const sections = [];
607
+ appendSection(sections, 'Usage', ['docman tools', 'docman tools --help']);
608
+ appendSection(sections, 'Purpose', [
609
+ 'List Docman tool descriptors used by AOPS/agent discovery.',
610
+ 'Each item includes tool id, aliases, summary, notes, examples, policy, route, and schema refs.',
611
+ ]);
612
+ appendSection(sections, 'Follow-up', [
613
+ 'Use docman tool --id <toolId> --help for command-level invoke guidance.',
614
+ 'Use docman manifest agent for the full agent manifest payload.',
615
+ ]);
616
+ return createCommandDescriptor({
617
+ id: 'tools',
618
+ kind: 'static',
619
+ title: 'docman tools',
620
+ command: ['docman', 'tools'],
621
+ aliases: ['tools'],
622
+ summary: 'List agent-facing Docman tool descriptors.',
623
+ sections,
624
+ });
625
+ }
626
+ function buildOpsCommandDescriptor() {
627
+ const sections = [];
628
+ appendSection(sections, 'Usage', ['docman ops', 'docman ops --help']);
629
+ appendSection(sections, 'Purpose', [
630
+ 'List canonical Docman operation specs resolved from the shared contract surface.',
631
+ 'Use when you want to inspect operation ids before invoking via docman op or docman tool.',
632
+ ]);
633
+ appendSection(sections, 'Follow-up', [
634
+ 'Use docman op <operationId> --help for per-operation details.',
635
+ 'Use docman manifest dcm for summaries/examples/contracts.',
636
+ ]);
637
+ return createCommandDescriptor({
638
+ id: 'ops',
639
+ kind: 'static',
640
+ title: 'docman ops',
641
+ command: ['docman', 'ops'],
642
+ aliases: ['ops'],
643
+ summary: 'List canonical Docman operation specs.',
644
+ sections,
645
+ });
646
+ }
647
+ function buildToolCommandDescriptor() {
648
+ const sections = [];
649
+ appendSection(sections, 'Usage', [
650
+ 'docman tool --id <tool-or-operation-id> --input <json|@file>',
651
+ 'docman tool --id docman.document.list --help',
652
+ 'docman tool --help',
653
+ ]);
654
+ appendSection(sections, 'Purpose', [
655
+ 'Invoke the exact canonical contract with an explicit JSON input payload.',
656
+ 'This is the safest CLI surface when examples/docs/contracts matter.',
657
+ ]);
658
+ appendSection(sections, 'Options', [
659
+ '--id <tool-or-operation-id> Accepts tool id, local alias, or operation id',
660
+ '--input <json|@file> Exact operation input payload as inline JSON or @file',
661
+ ...buildCommonRuntimeHelpRows(false),
662
+ ]);
663
+ return createCommandDescriptor({
664
+ id: 'tool',
665
+ kind: 'static',
666
+ title: 'docman tool',
667
+ command: ['docman', 'tool'],
668
+ aliases: ['tool', 'invoke'],
669
+ summary: 'Invoke canonical Docman operations by explicit JSON input.',
670
+ sections,
671
+ });
672
+ }
673
+ function buildOpCommandDescriptor() {
674
+ const sections = [];
675
+ appendSection(sections, 'Usage', [
676
+ 'docman op <operation-or-tool-id> [--input <json|@file>] [--arg value]',
677
+ 'docman op docman.document.list --help',
678
+ 'docman op --help',
679
+ ]);
680
+ appendSection(sections, 'Purpose', [
681
+ 'Invoke canonical operations directly by operation id or tool id.',
682
+ 'Raw op/operation/run mode bypasses generated sugar hooks by default.',
683
+ ]);
684
+ appendSection(sections, 'Options', [
685
+ '--input <json|@file> Exact operation input payload',
686
+ 'Or provide generated flags that match operation args, such as --id or --document-version-id',
687
+ ...buildCommonRuntimeHelpRows(false),
688
+ ]);
689
+ return createCommandDescriptor({
690
+ id: 'op',
691
+ kind: 'static',
692
+ title: 'docman op',
693
+ command: ['docman', 'op'],
694
+ aliases: ['op', 'operation', 'run'],
695
+ summary: 'Invoke canonical Docman operations directly.',
696
+ sections,
697
+ });
698
+ }
699
+ function buildVersionCommandDescriptor() {
700
+ const sections = [];
701
+ appendSection(sections, 'Usage', ['docman --version', 'docman version']);
702
+ appendSection(sections, 'Purpose', ['Print the installed @aopslab/domain-cli-docman package version and exit.']);
703
+ return createCommandDescriptor({
704
+ id: 'version',
705
+ kind: 'static',
706
+ title: 'docman version',
707
+ command: ['docman', 'version'],
708
+ aliases: ['version', '--version'],
709
+ summary: 'Print the installed CLI package version.',
710
+ sections,
711
+ });
712
+ }
713
+ function buildOperationCommandDescriptor(spec, manifest, routeMap) {
714
+ const normalizedOperationId = normalizeOperationId(spec.operationId);
715
+ const fullOperationId = toGatewayToolId(normalizedOperationId);
716
+ const localFallbackToolId = toLocalFallbackToolId(normalizedOperationId);
717
+ const gatewayToolId = toGatewayToolId(normalizedOperationId);
718
+ const operationDoc = toRecord(toRecord(toRecord(manifest.docs).operations)[normalizedOperationId]);
719
+ const route = routeMap.get(normalizedOperationId);
720
+ const commandSpec = findCommandSpecForOperation(spec.operationId);
721
+ const tags = mergeStringLists(spec.tags, toStringList(operationDoc.tags));
722
+ const examples = mergeStringLists(spec.examples, toStringList(operationDoc.examples)).slice(0, 2);
723
+ const notes = mergeStringLists(spec.docs?.notes, toStringList(operationDoc.notes));
724
+ const antiPatterns = mergeStringLists(spec.docs?.antiPatterns, toStringList(operationDoc.antiPatterns));
725
+ const preconditions = mergeStringLists(spec.docs?.preconditions, toStringList(operationDoc.preconditions));
726
+ const postconditions = mergeStringLists(spec.docs?.postconditions, toStringList(operationDoc.postconditions));
727
+ const summary = normalizeNonEmptyString(operationDoc.summary)
728
+ ?? normalizeNonEmptyString(spec.summary)
729
+ ?? normalizeNonEmptyString(route?.summary)
730
+ ?? fullOperationId;
731
+ const summaryLines = mergeStringLists([summary], commandSpec?.description && commandSpec.description !== summary ? [commandSpec.description] : undefined);
732
+ const usageLines = [
733
+ ...(commandSpec ? [buildSugarUsage(commandSpec)] : []),
734
+ `docman op ${fullOperationId} [--input <json|@file>] [--arg value] [--help]`,
735
+ `docman tool --id ${gatewayToolId} --input <json|@file> [--help]`,
736
+ ];
737
+ const sections = [];
738
+ appendSection(sections, 'Summary', summaryLines);
739
+ appendSection(sections, 'Identity', [
740
+ `operation: ${fullOperationId}`,
741
+ `tool id: ${gatewayToolId}`,
742
+ `local alias: ${localFallbackToolId}`,
743
+ spec.sideEffect ? `side effect: ${spec.sideEffect}` : '',
744
+ tags.length > 0 ? `tags: ${tags.join(', ')}` : '',
745
+ ]);
746
+ appendSection(sections, 'Usage', usageLines);
747
+ appendSection(sections, 'Host Route', route ? [`${route.method} ${route.pattern}`] : ['No host route projection found']);
748
+ appendSection(sections, 'Arguments', [
749
+ ...buildOperationArgRows(spec, commandSpec),
750
+ ...buildCommonRuntimeHelpRows(Boolean(commandSpec)),
751
+ ]);
752
+ const exampleLines = [];
753
+ if (commandSpec) {
754
+ exampleLines.push(buildSugarExample(commandSpec));
755
+ }
756
+ for (const example of examples) {
757
+ exampleLines.push(`docman op ${fullOperationId} --input '${example}'`);
758
+ exampleLines.push(`docman tool --id ${gatewayToolId} --input '${example}'`);
759
+ }
760
+ appendSection(sections, 'Examples', exampleLines);
761
+ appendSection(sections, 'Notes', notes);
762
+ appendSection(sections, 'Preconditions', preconditions);
763
+ appendSection(sections, 'Postconditions', postconditions);
764
+ appendSection(sections, 'Anti-Patterns', antiPatterns);
765
+ const capabilityOperation = manifest.capabilities.operations.find((operation) => normalizeOperationId(operation.operationId) === normalizedOperationId);
766
+ appendSection(sections, 'Schema Refs', [
767
+ capabilityOperation?.inputSchemaRef ? `input: ${capabilityOperation.inputSchemaRef}` : '',
768
+ capabilityOperation?.outputSchemaRef ? `output: ${capabilityOperation.outputSchemaRef}` : '',
769
+ ]);
770
+ appendSection(sections, 'Source', [
771
+ 'Generated from Docman DCM docs, shared contract args/examples, host route projection, and CLI sugar specs.',
772
+ ]);
773
+ const aliases = new Set([
774
+ normalizedOperationId,
775
+ fullOperationId,
776
+ gatewayToolId,
777
+ localFallbackToolId,
778
+ toOperationPath(normalizedOperationId),
779
+ '/' + toOperationPath(normalizedOperationId),
780
+ ]);
781
+ if (commandSpec) {
782
+ aliases.add(commandSpec.command.join(' '));
783
+ aliases.add(commandSpec.command.slice(1).join(' '));
784
+ }
785
+ return createCommandDescriptor({
786
+ id: normalizedOperationId,
787
+ kind: 'operation',
788
+ title: commandSpec ? commandSpec.command.join(' ') : fullOperationId,
789
+ command: commandSpec?.command ?? ['docman', fullOperationId],
790
+ aliases: [...aliases],
791
+ summary,
792
+ operationId: fullOperationId,
793
+ toolId: gatewayToolId,
794
+ localToolId: localFallbackToolId,
795
+ sections,
796
+ });
797
+ }
798
+ export function listDocmanToolingOperations(options) {
799
+ return listDocmanOperationSpecsFromKit(options).map((spec) => ({ ...spec }));
800
+ }
801
+ export function getDocmanOperationSpecById(identifier, options) {
802
+ const specs = listDocmanToolingOperations(options);
803
+ const aliases = buildOperationAliasIndex(specs);
804
+ const operationId = aliases.get(normalizeIdentifier(identifier));
805
+ if (!operationId)
806
+ return null;
807
+ const map = toOperationMap(specs);
808
+ return map.get(normalizeOperationId(operationId)) ?? null;
809
+ }
810
+ export function resolveDocmanOperationIdByToolId(identifier, options) {
811
+ const specs = listDocmanToolingOperations(options);
812
+ const aliases = buildOperationAliasIndex(specs);
813
+ const operationId = aliases.get(normalizeIdentifier(identifier));
814
+ return operationId ? normalizeOperationId(operationId) : null;
815
+ }
816
+ export function resolveDocmanToolIdByOperationId(operationId, options) {
817
+ const spec = getDocmanOperationSpecById(operationId, options);
818
+ if (!spec)
819
+ return null;
820
+ return toGatewayToolId(normalizeOperationId(spec.operationId));
821
+ }
822
+ export function listDocmanToolingTools(options) {
823
+ const manifest = buildDocmanDomainCapabilityManifestFromKit({
824
+ includeDocs: true,
825
+ refresh: options?.refresh,
826
+ });
827
+ const docsByOperation = manifest.docs?.operations ?? {};
828
+ const policyByOperation = manifest.policies?.operations ?? {};
829
+ const operationRefMap = toOperationRefMap(manifest);
830
+ const routeMap = toRouteMap(buildDocmanHostRouteProjectionFromKit({ refresh: options?.refresh }));
831
+ const specs = listDocmanToolingOperations(options);
832
+ const tools = [];
833
+ for (const spec of specs) {
834
+ const operationId = normalizeOperationId(spec.operationId);
835
+ const op = operationRefMap.get(operationId);
836
+ const doc = docsByOperation[operationId];
837
+ const route = routeMap.get(operationId);
838
+ const aliases = buildAliases(spec);
839
+ tools.push({
840
+ toolId: toGatewayToolId(operationId),
841
+ localToolId: spec.toolId,
842
+ domain: 'docman',
843
+ operationId,
844
+ title: op?.title ?? spec.summary,
845
+ summary: doc?.summary ?? spec.summary ?? op?.title,
846
+ sideEffect: op?.sideEffect,
847
+ tags: op?.tags,
848
+ inputSchemaRef: op?.inputSchemaRef,
849
+ outputSchemaRef: op?.outputSchemaRef,
850
+ policy: policyByOperation[operationId],
851
+ aliases,
852
+ notes: mergeStringLists(spec.docs?.notes, toStringList(doc?.notes)),
853
+ examples: mergeStringLists(spec.examples, toStringList(doc?.examples)),
854
+ ...(route ? { route: { method: route.method, pattern: route.pattern } } : {}),
855
+ });
856
+ }
857
+ return tools.sort((left, right) => left.operationId.localeCompare(right.operationId));
858
+ }
859
+ export function buildDocmanAgentManifest(options) {
860
+ return {
861
+ kind: 'docman-agent-manifest',
862
+ version: 'v1',
863
+ domain: 'docman',
864
+ generatedAt: new Date().toISOString(),
865
+ tools: listDocmanToolingTools(options),
866
+ };
867
+ }
868
+ export function buildDocmanCliProjection(options) {
869
+ const manifest = buildDocmanDomainCapabilityManifestFromKit({
870
+ includeDocs: true,
871
+ refresh: options?.refresh,
872
+ });
873
+ const routes = buildDocmanHostRouteProjectionFromKit({ refresh: options?.refresh });
874
+ const routeMap = toRouteMap(routes);
875
+ const operations = listDocmanToolingOperations(options);
876
+ const commands = [
877
+ buildRootCommandDescriptor(),
878
+ ...buildConfigCommandDescriptors(),
879
+ ...buildManifestCommandDescriptors(),
880
+ buildToolsCommandDescriptor(),
881
+ buildOpsCommandDescriptor(),
882
+ buildToolCommandDescriptor(),
883
+ buildOpCommandDescriptor(),
884
+ buildVersionCommandDescriptor(),
885
+ ...operations.map((spec) => buildOperationCommandDescriptor(spec, manifest, routeMap)),
886
+ ];
887
+ return {
888
+ kind: 'docman-cli-projection',
889
+ version: 'v1',
890
+ domain: 'docman',
891
+ generatedAt: new Date().toISOString(),
892
+ sourceOfTruth: {
893
+ canonical: 'dcm',
894
+ notes: [
895
+ 'DCM remains the single canonical capability source.',
896
+ 'CLI/help/agent/routes are derived projections and should not drift from DCM/contract metadata.',
897
+ 'HRM is runtime registration metadata only; it is not a capability source.',
898
+ ],
899
+ },
900
+ artifacts: DOCMAN_MANIFEST_ARTIFACTS.map((artifact) => ({ ...artifact })),
901
+ commands,
902
+ commandsById: Object.fromEntries(commands.map((command) => [command.id, command])),
903
+ };
904
+ }
905
+ export async function runDocmanOperationById(operationId, input = {}, options) {
906
+ const spec = getDocmanOperationSpecById(operationId, options);
907
+ if (!spec) {
908
+ throw new Error(`unknown_docman_operation:${operationId}`);
909
+ }
910
+ const normalizedInput = toRecord(input);
911
+ const parsedInput = parseDocmanToolInput(spec.operationId, normalizedInput);
912
+ return runDocmanKitOperationById(spec.operationId, parsedInput);
913
+ }
914
+ export async function runDocmanToolById(identifier, input = {}, options) {
915
+ const operationId = resolveDocmanOperationIdByToolId(identifier, options);
916
+ if (!operationId) {
917
+ throw new Error(`unknown_docman_tool_or_operation:${identifier}`);
918
+ }
919
+ return runDocmanOperationById(operationId, input, options);
920
+ }
921
+ export function clearDocmanToolingRuntimeCaches() {
922
+ clearDocmanKitEnvConfigCache();
923
+ clearDocmanKitOperationCaches();
924
+ }
925
+ export const buildDocmanDomainCapabilityManifest = buildDocmanDomainCapabilityManifestFromKit;
926
+ export const buildDocmanHostRouteProjection = buildDocmanHostRouteProjectionFromKit;