@guiho/xdocs 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (61) hide show
  1. package/CHANGELOG.md +1 -0
  2. package/LICENSE.md +23 -0
  3. package/jsr.json +12 -0
  4. package/library/cli.d.ts +8 -0
  5. package/library/cli.d.ts.map +1 -0
  6. package/library/cli.js +97 -0
  7. package/library/commands/generate.d.ts +7 -0
  8. package/library/commands/generate.d.ts.map +1 -0
  9. package/library/commands/generate.js +122 -0
  10. package/library/commands/init.d.ts +7 -0
  11. package/library/commands/init.d.ts.map +1 -0
  12. package/library/commands/init.js +71 -0
  13. package/library/commands/list.d.ts +7 -0
  14. package/library/commands/list.d.ts.map +1 -0
  15. package/library/commands/list.js +41 -0
  16. package/library/commands/merge.d.ts +7 -0
  17. package/library/commands/merge.d.ts.map +1 -0
  18. package/library/commands/merge.js +55 -0
  19. package/library/commands/prompt.d.ts +7 -0
  20. package/library/commands/prompt.d.ts.map +1 -0
  21. package/library/commands/prompt.js +19 -0
  22. package/library/commands/scan.d.ts +7 -0
  23. package/library/commands/scan.d.ts.map +1 -0
  24. package/library/commands/scan.js +53 -0
  25. package/library/commands/tree.d.ts +7 -0
  26. package/library/commands/tree.d.ts.map +1 -0
  27. package/library/commands/tree.js +49 -0
  28. package/library/config.d.ts +24 -0
  29. package/library/config.d.ts.map +1 -0
  30. package/library/config.js +126 -0
  31. package/library/discovery.d.ts +13 -0
  32. package/library/discovery.d.ts.map +1 -0
  33. package/library/discovery.js +118 -0
  34. package/library/errors.d.ts +9 -0
  35. package/library/errors.d.ts.map +1 -0
  36. package/library/errors.js +15 -0
  37. package/library/flags.d.ts +23 -0
  38. package/library/flags.d.ts.map +1 -0
  39. package/library/flags.js +96 -0
  40. package/library/guiho-xdocs-bin.d.ts +6 -0
  41. package/library/guiho-xdocs-bin.d.ts.map +1 -0
  42. package/library/guiho-xdocs-bin.js +6 -0
  43. package/library/guiho-xdocs.d.ts +14 -0
  44. package/library/guiho-xdocs.d.ts.map +1 -0
  45. package/library/guiho-xdocs.js +21 -0
  46. package/library/help.d.ts +12 -0
  47. package/library/help.d.ts.map +1 -0
  48. package/library/help.js +165 -0
  49. package/library/metadata.d.ts +22 -0
  50. package/library/metadata.d.ts.map +1 -0
  51. package/library/metadata.js +110 -0
  52. package/library/prompts.d.ts +15 -0
  53. package/library/prompts.d.ts.map +1 -0
  54. package/library/prompts.js +49 -0
  55. package/library/tree.d.ts +13 -0
  56. package/library/tree.d.ts.map +1 -0
  57. package/library/tree.js +114 -0
  58. package/library/types.d.ts +108 -0
  59. package/library/types.d.ts.map +1 -0
  60. package/library/types.js +4 -0
  61. package/package.json +77 -0
@@ -0,0 +1,165 @@
1
+ /**
2
+ * @copyright Copyright (c) 2026 GUIHO Technologies as represented by Cristóvão GUIHO. All Rights Reserved.
3
+ */
4
+ import { readFileSync } from 'node:fs';
5
+ /** Read the package version from package.json. */
6
+ export const readPackageVersion = () => {
7
+ try {
8
+ const raw = readFileSync(new URL('../package.json', import.meta.url), 'utf8');
9
+ const pkg = JSON.parse(raw);
10
+ return typeof pkg['version'] === 'string' ? pkg['version'] : '0.0.0';
11
+ }
12
+ catch {
13
+ return '0.0.0';
14
+ }
15
+ };
16
+ /** Show the xdocs version string. */
17
+ export const showVersion = () => `xdocs ${readPackageVersion()}`;
18
+ /** Show the main help text. */
19
+ export const showHelp = () => `
20
+ xdocs - Structured documentation system for codebases
21
+
22
+ Usage: xdocs <command> [options]
23
+
24
+ Commands:
25
+ init Initialize xdocs in a project
26
+ scan Scan the project for xdocs files
27
+ generate [path] Generate documentation for a directory or the project
28
+ prompt Output a ready-made prompt for AI
29
+ merge [path] Merge xdocs files from a directory into one file
30
+ tree Display the project hierarchy tree
31
+ list [path] List files with descriptions
32
+
33
+ Global Flags:
34
+ -h, --help Show help for a command
35
+ -v, --version Show the xdocs version
36
+ --cwd <path> Run as if started in this directory
37
+ --config <path> Path to xdocs.config.toml
38
+ --verbose Show detailed output
39
+
40
+ Examples:
41
+ xdocs init
42
+ xdocs scan
43
+ xdocs generate ./src/auth
44
+ xdocs prompt --name=write
45
+ xdocs merge ./src/domain
46
+ xdocs tree
47
+ xdocs list ./src/auth
48
+ `.trim();
49
+ /** Show help for a specific command. */
50
+ export const showCommandHelp = (command) => {
51
+ const help = commandHelpMap[command];
52
+ if (help)
53
+ return help;
54
+ return `Unknown command: ${command}\n\nRun \`xdocs --help\` for available commands.`;
55
+ };
56
+ const commandHelpMap = {
57
+ init: `
58
+ xdocs init - Initialize xdocs in a project
59
+
60
+ Usage: xdocs init
61
+
62
+ Creates:
63
+ - XDOCS.md Root documentation file
64
+ - xdocs.config.toml Configuration with defaults
65
+ - Updates AGENTS.md Adds xdocs instructions for AI agents
66
+ - Installs agent skills Prompts for AI tool and skill directory
67
+
68
+ Flags:
69
+ --cwd <path> Target directory (default: current directory)
70
+ --verbose Show detailed output
71
+ `.trim(),
72
+ scan: `
73
+ xdocs scan - Scan the project for xdocs files
74
+
75
+ Usage: xdocs scan
76
+
77
+ Walks every directory and subdirectory (respecting exclude rules),
78
+ matches files against configured extensions, and reports coverage.
79
+
80
+ Flags:
81
+ --format <format> Output format: text, json (default: text)
82
+ --cwd <path> Target directory (default: current directory)
83
+ --config <path> Path to xdocs.config.toml
84
+ --verbose Show detailed output
85
+ `.trim(),
86
+ generate: `
87
+ xdocs generate - Generate documentation
88
+
89
+ Usage: xdocs generate [path]
90
+
91
+ When a path is given, generates an xdocs file for that directory/module.
92
+ When no path is given, generates documentation for the entire project.
93
+
94
+ Flags:
95
+ --output <path> Output file path
96
+ --format <format> Output format: text, markdown (default: markdown)
97
+ --cwd <path> Target directory (default: current directory)
98
+ --config <path> Path to xdocs.config.toml
99
+ --verbose Show detailed output
100
+ `.trim(),
101
+ prompt: `
102
+ xdocs prompt - Output a ready-made prompt for AI
103
+
104
+ Usage: xdocs prompt --name=<name>
105
+
106
+ Outputs a self-contained instruction prompt for an AI agent to execute
107
+ a specific xdocs task. Both flag styles are supported:
108
+ xdocs prompt --name=write
109
+ xdocs prompt --name write
110
+
111
+ Available prompts:
112
+ write How to scan a directory and write xdocs documentation
113
+ update How to update existing xdocs files after code changes
114
+ agents How to update AGENTS.md with xdocs instructions
115
+ generate How to generate comprehensive documentation
116
+
117
+ Flags:
118
+ --name <name> The prompt to output (required)
119
+ --cwd <path> Target directory (default: current directory)
120
+ --config <path> Path to xdocs.config.toml
121
+ `.trim(),
122
+ merge: `
123
+ xdocs merge - Merge xdocs files into a single file
124
+
125
+ Usage: xdocs merge [path]
126
+
127
+ Takes all xdocs files within the given directory and produces
128
+ one consolidated Markdown document.
129
+
130
+ Flags:
131
+ --output <path> Output file path (default: stdout)
132
+ --cwd <path> Target directory (default: current directory)
133
+ --config <path> Path to xdocs.config.toml
134
+ --verbose Show detailed output
135
+ `.trim(),
136
+ tree: `
137
+ xdocs tree - Display the project hierarchy tree
138
+
139
+ Usage: xdocs tree
140
+
141
+ Scans all xdocs files, reads their metadata, and assembles the
142
+ parent-child hierarchy. Shows modules only, not individual files.
143
+
144
+ Flags:
145
+ --format <format> Output format: text, markdown (default: text)
146
+ --output <path> Output file path (default: stdout)
147
+ --cwd <path> Target directory (default: current directory)
148
+ --config <path> Path to xdocs.config.toml
149
+ --verbose Show detailed output
150
+ `.trim(),
151
+ list: `
152
+ xdocs list - List files with descriptions
153
+
154
+ Usage: xdocs list [path]
155
+
156
+ Lists every file in the given scope with a short description
157
+ of its purpose, pulled from xdocs metadata.
158
+
159
+ Flags:
160
+ --format <format> Output format: text, json (default: text)
161
+ --cwd <path> Target directory (default: current directory)
162
+ --config <path> Path to xdocs.config.toml
163
+ --verbose Show detailed output
164
+ `.trim(),
165
+ };
@@ -0,0 +1,22 @@
1
+ /**
2
+ * @copyright Copyright (c) 2026 GUIHO Technologies as represented by Cristóvão GUIHO. All Rights Reserved.
3
+ */
4
+ import type { XDocsFile, XDocsMetadata } from './types.js';
5
+ /** Parse an xdocs file from disk into an XDocsFile object. */
6
+ export declare const parseXDocsFile: (filePath: string, cwd: string) => Promise<XDocsFile>;
7
+ /** Extract YAML frontmatter and body from a Markdown string. */
8
+ export declare const extractFrontmatter: (content: string) => {
9
+ frontmatter: string | null;
10
+ body: string;
11
+ };
12
+ /** Validate parsed YAML as XDocsMetadata. */
13
+ export declare const validateMetadata: (parsed: unknown) => {
14
+ valid: true;
15
+ metadata: XDocsMetadata;
16
+ errors: never[];
17
+ } | {
18
+ valid: false;
19
+ metadata: null;
20
+ errors: string[];
21
+ };
22
+ //# sourceMappingURL=metadata.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"metadata.d.ts","sourceRoot":"","sources":["../source/metadata.ts"],"names":[],"mappings":"AAAA;;GAEG;AAKH,OAAO,KAAK,EAAE,SAAS,EAAE,aAAa,EAAE,MAAM,YAAY,CAAA;AAE1D,8DAA8D;AAC9D,eAAO,MAAM,cAAc,GAAU,UAAU,MAAM,EAAE,KAAK,MAAM,KAAG,OAAO,CAAC,SAAS,CAqCrF,CAAA;AAED,gEAAgE;AAChE,eAAO,MAAM,kBAAkB,GAAI,SAAS,MAAM,KAAG;IAAE,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAiB9F,CAAA;AAED,6CAA6C;AAC7C,eAAO,MAAM,gBAAgB,GAAI,QAAQ,OAAO,KAAG;IAAE,KAAK,EAAE,IAAI,CAAC;IAAC,QAAQ,EAAE,aAAa,CAAC;IAAC,MAAM,EAAE,KAAK,EAAE,CAAA;CAAE,GAAG;IAAE,KAAK,EAAE,KAAK,CAAC;IAAC,QAAQ,EAAE,IAAI,CAAC;IAAC,MAAM,EAAE,MAAM,EAAE,CAAA;CA4D9J,CAAA"}
@@ -0,0 +1,110 @@
1
+ /**
2
+ * @copyright Copyright (c) 2026 GUIHO Technologies as represented by Cristóvão GUIHO. All Rights Reserved.
3
+ */
4
+ import { readFile } from 'node:fs/promises';
5
+ import { dirname, relative } from 'node:path';
6
+ import { parse as parseYaml } from 'yaml';
7
+ /** Parse an xdocs file from disk into an XDocsFile object. */
8
+ export const parseXDocsFile = async (filePath, cwd) => {
9
+ const content = await readFile(filePath, 'utf8');
10
+ const errors = [];
11
+ const { frontmatter, body } = extractFrontmatter(content);
12
+ let metadata = null;
13
+ if (frontmatter) {
14
+ let parsed;
15
+ try {
16
+ parsed = parseYaml(frontmatter);
17
+ }
18
+ catch (error) {
19
+ const message = error instanceof Error ? error.message : String(error);
20
+ errors.push(`Invalid YAML frontmatter: ${message}`);
21
+ }
22
+ if (parsed !== undefined && parsed !== null) {
23
+ const result = validateMetadata(parsed);
24
+ if (result.valid) {
25
+ metadata = result.metadata;
26
+ }
27
+ else {
28
+ errors.push(...result.errors);
29
+ }
30
+ }
31
+ }
32
+ return {
33
+ path: filePath,
34
+ relativePath: relative(cwd, filePath),
35
+ directory: dirname(filePath),
36
+ metadata,
37
+ body,
38
+ valid: metadata !== null && errors.length === 0,
39
+ errors,
40
+ };
41
+ };
42
+ /** Extract YAML frontmatter and body from a Markdown string. */
43
+ export const extractFrontmatter = (content) => {
44
+ const trimmed = content.trimStart();
45
+ if (!trimmed.startsWith('---')) {
46
+ return { frontmatter: null, body: content };
47
+ }
48
+ const endIndex = trimmed.indexOf('\n---', 3);
49
+ if (endIndex === -1) {
50
+ return { frontmatter: null, body: content };
51
+ }
52
+ const frontmatter = trimmed.slice(3, endIndex).trim();
53
+ const body = trimmed.slice(endIndex + 4).trim();
54
+ return { frontmatter, body };
55
+ };
56
+ /** Validate parsed YAML as XDocsMetadata. */
57
+ export const validateMetadata = (parsed) => {
58
+ if (typeof parsed !== 'object' || parsed === null || Array.isArray(parsed)) {
59
+ return { valid: false, metadata: null, errors: ['Frontmatter must be a YAML object.'] };
60
+ }
61
+ const record = parsed;
62
+ const errors = [];
63
+ if (typeof record['subject'] !== 'string' || record['subject'].length === 0) {
64
+ errors.push('Missing or invalid "subject" field. Expected a non-empty string.');
65
+ }
66
+ if (typeof record['description'] !== 'string' || record['description'].length === 0) {
67
+ errors.push('Missing or invalid "description" field. Expected a non-empty string.');
68
+ }
69
+ if (record['parent'] !== null && typeof record['parent'] !== 'string') {
70
+ errors.push('Invalid "parent" field. Expected a string or null.');
71
+ }
72
+ if (!Array.isArray(record['children'])) {
73
+ errors.push('Missing or invalid "children" field. Expected an array.');
74
+ }
75
+ else if (record['children'].some((child) => typeof child !== 'string')) {
76
+ errors.push('Invalid "children" field. All entries must be strings.');
77
+ }
78
+ if (typeof record['files'] !== 'object' || record['files'] === null || Array.isArray(record['files'])) {
79
+ errors.push('Missing or invalid "files" field. Expected an object mapping filenames to descriptions.');
80
+ }
81
+ if (!Array.isArray(record['tags'])) {
82
+ errors.push('Missing or invalid "tags" field. Expected an array of strings.');
83
+ }
84
+ else if (record['tags'].some((tag) => typeof tag !== 'string')) {
85
+ errors.push('Invalid "tags" field. All entries must be strings.');
86
+ }
87
+ if (!Array.isArray(record['flags'])) {
88
+ errors.push('Missing or invalid "flags" field. Expected an array of strings.');
89
+ }
90
+ else if (record['flags'].some((flag) => typeof flag !== 'string')) {
91
+ errors.push('Invalid "flags" field. All entries must be strings.');
92
+ }
93
+ if (errors.length > 0) {
94
+ return { valid: false, metadata: null, errors };
95
+ }
96
+ return {
97
+ valid: true,
98
+ errors: [],
99
+ metadata: {
100
+ subject: record['subject'],
101
+ description: record['description'],
102
+ parent: record['parent'] ?? null,
103
+ children: record['children'],
104
+ files: record['files'],
105
+ tags: record['tags'],
106
+ flags: record['flags'],
107
+ status: typeof record['status'] === 'string' ? record['status'] : undefined,
108
+ },
109
+ };
110
+ };
@@ -0,0 +1,15 @@
1
+ /**
2
+ * @copyright Copyright (c) 2026 GUIHO Technologies as represented by Cristóvão GUIHO. All Rights Reserved.
3
+ *
4
+ * Prompt loader. Each .md file in prompts/ is imported as text at build time
5
+ * so that `bun build --compile` embeds them in the binary. Adding a new prompt
6
+ * requires two steps: create the .md file, then add an import here.
7
+ */
8
+ import type { XDocsPrompt } from './types.js';
9
+ /** All available prompts, keyed by name. */
10
+ export declare const prompts: ReadonlyMap<string, XDocsPrompt>;
11
+ /** Get a prompt by name or return undefined. */
12
+ export declare const getPrompt: (name: string) => XDocsPrompt | undefined;
13
+ /** Get all prompt names. */
14
+ export declare const getPromptNames: () => string[];
15
+ //# sourceMappingURL=prompts.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"prompts.d.ts","sourceRoot":"","sources":["../source/prompts.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAYH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,YAAY,CAAA;AA0B7C,4CAA4C;AAC5C,eAAO,MAAM,OAAO,EAAE,WAAW,CAAC,MAAM,EAAE,WAAW,CASjD,CAAA;AAEJ,gDAAgD;AAChD,eAAO,MAAM,SAAS,GAAI,MAAM,MAAM,KAAG,WAAW,GAAG,SACpC,CAAA;AAEnB,4BAA4B;AAC5B,eAAO,MAAM,cAAc,QAAO,MAAM,EACnB,CAAA"}
@@ -0,0 +1,49 @@
1
+ /**
2
+ * @copyright Copyright (c) 2026 GUIHO Technologies as represented by Cristóvão GUIHO. All Rights Reserved.
3
+ *
4
+ * Prompt loader. Each .md file in prompts/ is imported as text at build time
5
+ * so that `bun build --compile` embeds them in the binary. Adding a new prompt
6
+ * requires two steps: create the .md file, then add an import here.
7
+ */
8
+ // @ts-expect-error -- Bun text import, no TS declaration needed
9
+ import writeRaw from '../prompts/write.md' with { type: 'text' };
10
+ // @ts-expect-error -- Bun text import, no TS declaration needed
11
+ import updateRaw from '../prompts/update.md' with { type: 'text' };
12
+ // @ts-expect-error -- Bun text import, no TS declaration needed
13
+ import agentsRaw from '../prompts/agents.md' with { type: 'text' };
14
+ // @ts-expect-error -- Bun text import, no TS declaration needed
15
+ import generateRaw from '../prompts/generate.md' with { type: 'text' };
16
+ import { extractFrontmatter } from './metadata.js';
17
+ const rawFiles = [writeRaw, updateRaw, agentsRaw, generateRaw];
18
+ /** Parse a raw prompt file into an XDocsPrompt. */
19
+ const parsePrompt = (raw) => {
20
+ const { frontmatter, body } = extractFrontmatter(raw);
21
+ if (!frontmatter) {
22
+ throw new Error('Prompt file is missing YAML frontmatter.');
23
+ }
24
+ // Lightweight parse — prompts only have `name` and `description`.
25
+ const nameMatch = frontmatter.match(/^name:\s*(.+)$/m);
26
+ const descMatch = frontmatter.match(/^description:\s*(.+)$/m);
27
+ if (!nameMatch?.[1])
28
+ throw new Error('Prompt frontmatter missing "name" field.');
29
+ if (!descMatch?.[1])
30
+ throw new Error('Prompt frontmatter missing "description" field.');
31
+ return {
32
+ name: nameMatch[1].trim(),
33
+ description: descMatch[1].trim(),
34
+ body: body.trim(),
35
+ };
36
+ };
37
+ /** All available prompts, keyed by name. */
38
+ export const prompts = (() => {
39
+ const map = new Map();
40
+ for (const raw of rawFiles) {
41
+ const prompt = parsePrompt(raw);
42
+ map.set(prompt.name, prompt);
43
+ }
44
+ return map;
45
+ })();
46
+ /** Get a prompt by name or return undefined. */
47
+ export const getPrompt = (name) => prompts.get(name);
48
+ /** Get all prompt names. */
49
+ export const getPromptNames = () => [...prompts.keys()];
@@ -0,0 +1,13 @@
1
+ /**
2
+ * @copyright Copyright (c) 2026 GUIHO Technologies as represented by Cristóvão GUIHO. All Rights Reserved.
3
+ */
4
+ import type { XDocsFile, XDocsTreeNode, XDocsTreeValidation } from './types.js';
5
+ /** Build a hierarchy tree from a list of xdocs files. */
6
+ export declare const buildTree: (files: XDocsFile[]) => XDocsTreeNode;
7
+ /** Validate tree integrity. */
8
+ export declare const validateTree: (files: XDocsFile[]) => XDocsTreeValidation;
9
+ /** Render a tree as an indented text string. */
10
+ export declare const renderTree: (node: XDocsTreeNode, indent?: number) => string;
11
+ /** Render a tree as Markdown. */
12
+ export declare const renderTreeMarkdown: (node: XDocsTreeNode, indent?: number) => string;
13
+ //# sourceMappingURL=tree.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tree.d.ts","sourceRoot":"","sources":["../source/tree.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EAAE,SAAS,EAAE,aAAa,EAAE,mBAAmB,EAAE,MAAM,YAAY,CAAA;AAE/E,yDAAyD;AACzD,eAAO,MAAM,SAAS,GAAI,OAAO,SAAS,EAAE,KAAG,aA8D9C,CAAA;AAED,+BAA+B;AAC/B,eAAO,MAAM,YAAY,GAAI,OAAO,SAAS,EAAE,KAAG,mBAmCjD,CAAA;AAED,gDAAgD;AAChD,eAAO,MAAM,UAAU,GAAI,MAAM,aAAa,EAAE,eAAU,KAAG,MAe5D,CAAA;AAED,iCAAiC;AACjC,eAAO,MAAM,kBAAkB,GAAI,MAAM,aAAa,EAAE,eAAU,KAAG,MAWpE,CAAA"}
@@ -0,0 +1,114 @@
1
+ /**
2
+ * @copyright Copyright (c) 2026 GUIHO Technologies as represented by Cristóvão GUIHO. All Rights Reserved.
3
+ */
4
+ /** Build a hierarchy tree from a list of xdocs files. */
5
+ export const buildTree = (files) => {
6
+ const nodeMap = new Map();
7
+ // Create nodes for every file with valid metadata
8
+ for (const file of files) {
9
+ if (!file.metadata)
10
+ continue;
11
+ nodeMap.set(file.metadata.subject, {
12
+ subject: file.metadata.subject,
13
+ description: file.metadata.description,
14
+ path: file.relativePath,
15
+ children: [],
16
+ });
17
+ }
18
+ // Find or create the root node
19
+ let root;
20
+ for (const file of files) {
21
+ if (!file.metadata)
22
+ continue;
23
+ if (file.metadata.parent === null) {
24
+ root = nodeMap.get(file.metadata.subject);
25
+ continue;
26
+ }
27
+ const parentNode = nodeMap.get(file.metadata.parent);
28
+ const childNode = nodeMap.get(file.metadata.subject);
29
+ if (parentNode && childNode) {
30
+ parentNode.children.push(childNode);
31
+ }
32
+ }
33
+ // Also add children declared in metadata but not yet linked
34
+ for (const file of files) {
35
+ if (!file.metadata)
36
+ continue;
37
+ const parentNode = nodeMap.get(file.metadata.subject);
38
+ if (!parentNode)
39
+ continue;
40
+ for (const childSubject of file.metadata.children) {
41
+ const childNode = nodeMap.get(childSubject);
42
+ if (childNode && !parentNode.children.includes(childNode)) {
43
+ parentNode.children.push(childNode);
44
+ }
45
+ }
46
+ }
47
+ if (!root) {
48
+ root = {
49
+ subject: '(root)',
50
+ description: 'No root xdocs file found.',
51
+ path: null,
52
+ children: [...nodeMap.values()].filter((node) => !files.some((f) => f.metadata && f.metadata.children.includes(node.subject))),
53
+ };
54
+ }
55
+ return root;
56
+ };
57
+ /** Validate tree integrity. */
58
+ export const validateTree = (files) => {
59
+ const warnings = [];
60
+ const errors = [];
61
+ const subjects = new Set();
62
+ for (const file of files) {
63
+ if (!file.metadata)
64
+ continue;
65
+ if (subjects.has(file.metadata.subject)) {
66
+ errors.push(`Duplicate subject: "${file.metadata.subject}" in ${file.relativePath}`);
67
+ }
68
+ subjects.add(file.metadata.subject);
69
+ }
70
+ for (const file of files) {
71
+ if (!file.metadata)
72
+ continue;
73
+ // Check parent references
74
+ if (file.metadata.parent !== null && !subjects.has(file.metadata.parent)) {
75
+ errors.push(`Orphan subject: "${file.metadata.subject}" references non-existent parent "${file.metadata.parent}" in ${file.relativePath}`);
76
+ }
77
+ // Check children references
78
+ for (const child of file.metadata.children) {
79
+ if (!subjects.has(child)) {
80
+ warnings.push(`Missing child: "${file.metadata.subject}" references non-existent child "${child}" in ${file.relativePath}`);
81
+ }
82
+ }
83
+ }
84
+ return {
85
+ valid: errors.length === 0,
86
+ warnings,
87
+ errors,
88
+ };
89
+ };
90
+ /** Render a tree as an indented text string. */
91
+ export const renderTree = (node, indent = 0) => {
92
+ const prefix = ' '.repeat(indent);
93
+ const lines = [];
94
+ if (indent === 0) {
95
+ lines.push(`${node.subject}`);
96
+ }
97
+ else {
98
+ lines.push(`${prefix}${node.subject}`);
99
+ }
100
+ for (const child of node.children) {
101
+ lines.push(renderTree(child, indent + 1));
102
+ }
103
+ return lines.join('\n');
104
+ };
105
+ /** Render a tree as Markdown. */
106
+ export const renderTreeMarkdown = (node, indent = 0) => {
107
+ const prefix = ' '.repeat(indent);
108
+ const lines = [];
109
+ lines.push(`${prefix}- **${node.subject}**: ${node.description}`);
110
+ for (const child of node.children) {
111
+ lines.push(renderTreeMarkdown(child, indent + 1));
112
+ }
113
+ return lines.join('\n');
114
+ };
@@ -0,0 +1,108 @@
1
+ /**
2
+ * @copyright Copyright (c) 2026 GUIHO Technologies as represented by Cristóvão GUIHO. All Rights Reserved.
3
+ */
4
+ /** Supported output formats for CLI commands. */
5
+ export type XDocsFormat = 'text' | 'json' | 'markdown';
6
+ /** AI behavior mode for documentation updates. */
7
+ export type XDocsAiMode = 'prompt' | 'auto';
8
+ /** Command names recognized by the CLI. */
9
+ export type XDocsCommand = 'init' | 'scan' | 'generate' | 'prompt' | 'merge' | 'tree' | 'list';
10
+ /** Raw configuration as parsed from xdocs.config.toml. */
11
+ export type XDocsRawConfig = Partial<{
12
+ schema: number;
13
+ extensions: Partial<{
14
+ supported: string[];
15
+ }>;
16
+ ai: Partial<{
17
+ mode: string;
18
+ }>;
19
+ scan: Partial<{
20
+ exclude: string[];
21
+ }>;
22
+ project: Partial<{
23
+ name: string;
24
+ }>;
25
+ }>;
26
+ /** Normalized, validated configuration. */
27
+ export type XDocsConfig = {
28
+ schema: 1;
29
+ cwd: string;
30
+ configPath?: string;
31
+ extensions: {
32
+ supported: string[];
33
+ };
34
+ ai: {
35
+ mode: XDocsAiMode;
36
+ };
37
+ scan: {
38
+ exclude: string[];
39
+ };
40
+ project: {
41
+ name: string;
42
+ };
43
+ };
44
+ /** YAML frontmatter metadata from an xdocs file. */
45
+ export type XDocsMetadata = {
46
+ subject: string;
47
+ description: string;
48
+ parent: string | null;
49
+ children: string[];
50
+ files: Record<string, string>;
51
+ tags: string[];
52
+ flags: string[];
53
+ status?: string;
54
+ };
55
+ /** A discovered xdocs file with its path and parsed metadata. */
56
+ export type XDocsFile = {
57
+ path: string;
58
+ relativePath: string;
59
+ directory: string;
60
+ metadata: XDocsMetadata | null;
61
+ body: string;
62
+ valid: boolean;
63
+ errors: string[];
64
+ };
65
+ /** A node in the xdocs hierarchy tree. */
66
+ export type XDocsTreeNode = {
67
+ subject: string;
68
+ description: string;
69
+ path: string | null;
70
+ children: XDocsTreeNode[];
71
+ };
72
+ /** Result of a tree integrity check. */
73
+ export type XDocsTreeValidation = {
74
+ valid: boolean;
75
+ warnings: string[];
76
+ errors: string[];
77
+ };
78
+ /** Parsed CLI arguments. */
79
+ export type XDocsParsedArgs = {
80
+ command: string | undefined;
81
+ positionals: string[];
82
+ flags: Record<string, string | boolean | string[]>;
83
+ };
84
+ /** Options passed through the CLI to command handlers. */
85
+ export type XDocsCliOptions = {
86
+ cwd: string;
87
+ config?: string;
88
+ format: XDocsFormat;
89
+ verbose: boolean;
90
+ };
91
+ /** Scan result for a single directory. */
92
+ export type XDocsScanResult = {
93
+ totalFiles: number;
94
+ totalDirectories: number;
95
+ coveredDirectories: number;
96
+ uncoveredDirectories: number;
97
+ xdocsFiles: XDocsFile[];
98
+ uncoveredPaths: string[];
99
+ };
100
+ /** Available prompt names for xdocs prompt --name. */
101
+ export type XDocsPromptName = 'write' | 'update' | 'agents' | 'generate';
102
+ /** A parsed prompt loaded from a .md file. */
103
+ export type XDocsPrompt = {
104
+ name: string;
105
+ description: string;
106
+ body: string;
107
+ };
108
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../source/types.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,4 @@
1
+ /**
2
+ * @copyright Copyright (c) 2026 GUIHO Technologies as represented by Cristóvão GUIHO. All Rights Reserved.
3
+ */
4
+ export {};