@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.
- package/CHANGELOG.md +1 -0
- package/LICENSE.md +23 -0
- package/jsr.json +12 -0
- package/library/cli.d.ts +8 -0
- package/library/cli.d.ts.map +1 -0
- package/library/cli.js +97 -0
- package/library/commands/generate.d.ts +7 -0
- package/library/commands/generate.d.ts.map +1 -0
- package/library/commands/generate.js +122 -0
- package/library/commands/init.d.ts +7 -0
- package/library/commands/init.d.ts.map +1 -0
- package/library/commands/init.js +71 -0
- package/library/commands/list.d.ts +7 -0
- package/library/commands/list.d.ts.map +1 -0
- package/library/commands/list.js +41 -0
- package/library/commands/merge.d.ts +7 -0
- package/library/commands/merge.d.ts.map +1 -0
- package/library/commands/merge.js +55 -0
- package/library/commands/prompt.d.ts +7 -0
- package/library/commands/prompt.d.ts.map +1 -0
- package/library/commands/prompt.js +19 -0
- package/library/commands/scan.d.ts +7 -0
- package/library/commands/scan.d.ts.map +1 -0
- package/library/commands/scan.js +53 -0
- package/library/commands/tree.d.ts +7 -0
- package/library/commands/tree.d.ts.map +1 -0
- package/library/commands/tree.js +49 -0
- package/library/config.d.ts +24 -0
- package/library/config.d.ts.map +1 -0
- package/library/config.js +126 -0
- package/library/discovery.d.ts +13 -0
- package/library/discovery.d.ts.map +1 -0
- package/library/discovery.js +118 -0
- package/library/errors.d.ts +9 -0
- package/library/errors.d.ts.map +1 -0
- package/library/errors.js +15 -0
- package/library/flags.d.ts +23 -0
- package/library/flags.d.ts.map +1 -0
- package/library/flags.js +96 -0
- package/library/guiho-xdocs-bin.d.ts +6 -0
- package/library/guiho-xdocs-bin.d.ts.map +1 -0
- package/library/guiho-xdocs-bin.js +6 -0
- package/library/guiho-xdocs.d.ts +14 -0
- package/library/guiho-xdocs.d.ts.map +1 -0
- package/library/guiho-xdocs.js +21 -0
- package/library/help.d.ts +12 -0
- package/library/help.d.ts.map +1 -0
- package/library/help.js +165 -0
- package/library/metadata.d.ts +22 -0
- package/library/metadata.d.ts.map +1 -0
- package/library/metadata.js +110 -0
- package/library/prompts.d.ts +15 -0
- package/library/prompts.d.ts.map +1 -0
- package/library/prompts.js +49 -0
- package/library/tree.d.ts +13 -0
- package/library/tree.d.ts.map +1 -0
- package/library/tree.js +114 -0
- package/library/types.d.ts +108 -0
- package/library/types.d.ts.map +1 -0
- package/library/types.js +4 -0
- package/package.json +77 -0
package/library/help.js
ADDED
|
@@ -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"}
|
package/library/tree.js
ADDED
|
@@ -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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"}
|
package/library/types.js
ADDED