@unlimitechcloud/devlink 1.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (186) hide show
  1. package/AGENTS.md +880 -0
  2. package/LICENSE +21 -0
  3. package/README.md +335 -0
  4. package/dist/__tests__/e2e.spec.d.ts +8 -0
  5. package/dist/__tests__/e2e.spec.d.ts.map +1 -0
  6. package/dist/__tests__/e2e.spec.js +253 -0
  7. package/dist/__tests__/e2e.spec.js.map +1 -0
  8. package/dist/__tests__/integration.spec.d.ts +8 -0
  9. package/dist/__tests__/integration.spec.d.ts.map +1 -0
  10. package/dist/__tests__/integration.spec.js +274 -0
  11. package/dist/__tests__/integration.spec.js.map +1 -0
  12. package/dist/cli.d.ts +6 -0
  13. package/dist/cli.d.ts.map +1 -0
  14. package/dist/cli.js +610 -0
  15. package/dist/cli.js.map +1 -0
  16. package/dist/commands/consumers.d.ts +37 -0
  17. package/dist/commands/consumers.d.ts.map +1 -0
  18. package/dist/commands/consumers.js +107 -0
  19. package/dist/commands/consumers.js.map +1 -0
  20. package/dist/commands/docs.d.ts +59 -0
  21. package/dist/commands/docs.d.ts.map +1 -0
  22. package/dist/commands/docs.js +262 -0
  23. package/dist/commands/docs.js.map +1 -0
  24. package/dist/commands/docs.spec.d.ts +5 -0
  25. package/dist/commands/docs.spec.d.ts.map +1 -0
  26. package/dist/commands/docs.spec.js +213 -0
  27. package/dist/commands/docs.spec.js.map +1 -0
  28. package/dist/commands/index.d.ts +13 -0
  29. package/dist/commands/index.d.ts.map +1 -0
  30. package/dist/commands/index.js +13 -0
  31. package/dist/commands/index.js.map +1 -0
  32. package/dist/commands/install.d.ts +31 -0
  33. package/dist/commands/install.d.ts.map +1 -0
  34. package/dist/commands/install.js +234 -0
  35. package/dist/commands/install.js.map +1 -0
  36. package/dist/commands/list.d.ts +22 -0
  37. package/dist/commands/list.d.ts.map +1 -0
  38. package/dist/commands/list.js +45 -0
  39. package/dist/commands/list.js.map +1 -0
  40. package/dist/commands/list.spec.d.ts +5 -0
  41. package/dist/commands/list.spec.d.ts.map +1 -0
  42. package/dist/commands/list.spec.js +95 -0
  43. package/dist/commands/list.spec.js.map +1 -0
  44. package/dist/commands/prune.d.ts +27 -0
  45. package/dist/commands/prune.d.ts.map +1 -0
  46. package/dist/commands/prune.js +74 -0
  47. package/dist/commands/prune.js.map +1 -0
  48. package/dist/commands/publish.d.ts +16 -0
  49. package/dist/commands/publish.d.ts.map +1 -0
  50. package/dist/commands/publish.js +225 -0
  51. package/dist/commands/publish.js.map +1 -0
  52. package/dist/commands/publish.spec.d.ts +5 -0
  53. package/dist/commands/publish.spec.d.ts.map +1 -0
  54. package/dist/commands/publish.spec.js +98 -0
  55. package/dist/commands/publish.spec.js.map +1 -0
  56. package/dist/commands/push.d.ts +16 -0
  57. package/dist/commands/push.d.ts.map +1 -0
  58. package/dist/commands/push.js +164 -0
  59. package/dist/commands/push.js.map +1 -0
  60. package/dist/commands/remove.d.ts +24 -0
  61. package/dist/commands/remove.d.ts.map +1 -0
  62. package/dist/commands/remove.js +80 -0
  63. package/dist/commands/remove.js.map +1 -0
  64. package/dist/commands/remove.spec.d.ts +5 -0
  65. package/dist/commands/remove.spec.d.ts.map +1 -0
  66. package/dist/commands/remove.spec.js +87 -0
  67. package/dist/commands/remove.spec.js.map +1 -0
  68. package/dist/commands/resolve.d.ts +20 -0
  69. package/dist/commands/resolve.d.ts.map +1 -0
  70. package/dist/commands/resolve.js +52 -0
  71. package/dist/commands/resolve.js.map +1 -0
  72. package/dist/commands/resolve.spec.d.ts +5 -0
  73. package/dist/commands/resolve.spec.d.ts.map +1 -0
  74. package/dist/commands/resolve.spec.js +87 -0
  75. package/dist/commands/resolve.spec.js.map +1 -0
  76. package/dist/commands/verify.d.ts +32 -0
  77. package/dist/commands/verify.d.ts.map +1 -0
  78. package/dist/commands/verify.js +127 -0
  79. package/dist/commands/verify.js.map +1 -0
  80. package/dist/config.d.ts +22 -0
  81. package/dist/config.d.ts.map +1 -0
  82. package/dist/config.js +70 -0
  83. package/dist/config.js.map +1 -0
  84. package/dist/constants.d.ts +65 -0
  85. package/dist/constants.d.ts.map +1 -0
  86. package/dist/constants.js +116 -0
  87. package/dist/constants.js.map +1 -0
  88. package/dist/constants.spec.d.ts +5 -0
  89. package/dist/constants.spec.d.ts.map +1 -0
  90. package/dist/constants.spec.js +72 -0
  91. package/dist/constants.spec.js.map +1 -0
  92. package/dist/core/index.d.ts +9 -0
  93. package/dist/core/index.d.ts.map +1 -0
  94. package/dist/core/index.js +9 -0
  95. package/dist/core/index.js.map +1 -0
  96. package/dist/core/installations.d.ts +79 -0
  97. package/dist/core/installations.d.ts.map +1 -0
  98. package/dist/core/installations.js +207 -0
  99. package/dist/core/installations.js.map +1 -0
  100. package/dist/core/installations.spec.d.ts +5 -0
  101. package/dist/core/installations.spec.d.ts.map +1 -0
  102. package/dist/core/installations.spec.js +261 -0
  103. package/dist/core/installations.spec.js.map +1 -0
  104. package/dist/core/lock.d.ts +37 -0
  105. package/dist/core/lock.d.ts.map +1 -0
  106. package/dist/core/lock.js +198 -0
  107. package/dist/core/lock.js.map +1 -0
  108. package/dist/core/lock.spec.d.ts +5 -0
  109. package/dist/core/lock.spec.d.ts.map +1 -0
  110. package/dist/core/lock.spec.js +161 -0
  111. package/dist/core/lock.spec.js.map +1 -0
  112. package/dist/core/registry.d.ts +80 -0
  113. package/dist/core/registry.d.ts.map +1 -0
  114. package/dist/core/registry.js +231 -0
  115. package/dist/core/registry.js.map +1 -0
  116. package/dist/core/registry.spec.d.ts +5 -0
  117. package/dist/core/registry.spec.d.ts.map +1 -0
  118. package/dist/core/registry.spec.js +281 -0
  119. package/dist/core/registry.spec.js.map +1 -0
  120. package/dist/core/resolver.d.ts +55 -0
  121. package/dist/core/resolver.d.ts.map +1 -0
  122. package/dist/core/resolver.js +127 -0
  123. package/dist/core/resolver.js.map +1 -0
  124. package/dist/core/resolver.spec.d.ts +5 -0
  125. package/dist/core/resolver.spec.d.ts.map +1 -0
  126. package/dist/core/resolver.spec.js +202 -0
  127. package/dist/core/resolver.spec.js.map +1 -0
  128. package/dist/core/store.d.ts +65 -0
  129. package/dist/core/store.d.ts.map +1 -0
  130. package/dist/core/store.js +245 -0
  131. package/dist/core/store.js.map +1 -0
  132. package/dist/core/store.spec.d.ts +5 -0
  133. package/dist/core/store.spec.d.ts.map +1 -0
  134. package/dist/core/store.spec.js +195 -0
  135. package/dist/core/store.spec.js.map +1 -0
  136. package/dist/formatters/flat.d.ts +41 -0
  137. package/dist/formatters/flat.d.ts.map +1 -0
  138. package/dist/formatters/flat.js +131 -0
  139. package/dist/formatters/flat.js.map +1 -0
  140. package/dist/formatters/flat.spec.d.ts +5 -0
  141. package/dist/formatters/flat.spec.d.ts.map +1 -0
  142. package/dist/formatters/flat.spec.js +130 -0
  143. package/dist/formatters/flat.spec.js.map +1 -0
  144. package/dist/formatters/index.d.ts +6 -0
  145. package/dist/formatters/index.d.ts.map +1 -0
  146. package/dist/formatters/index.js +6 -0
  147. package/dist/formatters/index.js.map +1 -0
  148. package/dist/formatters/tree.d.ts +29 -0
  149. package/dist/formatters/tree.d.ts.map +1 -0
  150. package/dist/formatters/tree.js +256 -0
  151. package/dist/formatters/tree.js.map +1 -0
  152. package/dist/formatters/tree.spec.d.ts +5 -0
  153. package/dist/formatters/tree.spec.d.ts.map +1 -0
  154. package/dist/formatters/tree.spec.js +127 -0
  155. package/dist/formatters/tree.spec.js.map +1 -0
  156. package/dist/index.d.ts +11 -0
  157. package/dist/index.d.ts.map +1 -0
  158. package/dist/index.js +13 -0
  159. package/dist/index.js.map +1 -0
  160. package/dist/installer.d.ts +13 -0
  161. package/dist/installer.d.ts.map +1 -0
  162. package/dist/installer.js +171 -0
  163. package/dist/installer.js.map +1 -0
  164. package/dist/store.d.ts +78 -0
  165. package/dist/store.d.ts.map +1 -0
  166. package/dist/store.js +344 -0
  167. package/dist/store.js.map +1 -0
  168. package/dist/types.d.ts +235 -0
  169. package/dist/types.d.ts.map +1 -0
  170. package/dist/types.js +5 -0
  171. package/dist/types.js.map +1 -0
  172. package/docs/README.md +68 -0
  173. package/docs/inspection/consumers.md +178 -0
  174. package/docs/inspection/list.md +182 -0
  175. package/docs/inspection/resolve.md +172 -0
  176. package/docs/installation/configuration.md +238 -0
  177. package/docs/installation/install.md +184 -0
  178. package/docs/maintenance/prune.md +159 -0
  179. package/docs/maintenance/remove.md +174 -0
  180. package/docs/maintenance/verify.md +174 -0
  181. package/docs/publishing/publish.md +146 -0
  182. package/docs/publishing/push.md +146 -0
  183. package/docs/store/locking.md +118 -0
  184. package/docs/store/namespaces.md +141 -0
  185. package/docs/store/structure.md +163 -0
  186. package/package.json +58 -0
@@ -0,0 +1,107 @@
1
+ /**
2
+ * Consumers Command - Listar proyectos consumidores
3
+ */
4
+ import { withStoreLock } from "../core/lock.js";
5
+ import { readInstallations, writeInstallations, getConsumers, getConsumersByNamespace, getAllProjects, getProject, pruneDeadProjects, } from "../core/installations.js";
6
+ import { formatConsumersTree } from "../formatters/tree.js";
7
+ import { formatConsumersFlat } from "../formatters/flat.js";
8
+ /**
9
+ * Get consumers info
10
+ */
11
+ export async function getConsumersInfo(options = {}) {
12
+ const installations = await readInstallations();
13
+ let pruned;
14
+ // Handle prune option
15
+ if (options.prune) {
16
+ pruned = await withStoreLock(async () => {
17
+ const removed = await pruneDeadProjects(installations);
18
+ if (removed.length > 0) {
19
+ await writeInstallations(installations);
20
+ }
21
+ return removed;
22
+ });
23
+ }
24
+ const consumers = [];
25
+ if (options.package) {
26
+ // Filter by package
27
+ const packageConsumers = getConsumers(installations, options.package, {
28
+ namespace: options.namespace,
29
+ });
30
+ for (const { projectPath, info } of packageConsumers) {
31
+ consumers.push({
32
+ projectPath,
33
+ packages: [{
34
+ name: options.package,
35
+ version: info.version,
36
+ namespace: info.namespace,
37
+ }],
38
+ });
39
+ }
40
+ }
41
+ else if (options.namespace) {
42
+ // Filter by namespace
43
+ const nsConsumers = getConsumersByNamespace(installations, options.namespace);
44
+ for (const { projectPath, packages } of nsConsumers) {
45
+ consumers.push({
46
+ projectPath,
47
+ packages: Object.entries(packages).map(([name, info]) => ({
48
+ name,
49
+ version: info.version,
50
+ namespace: info.namespace,
51
+ })),
52
+ });
53
+ }
54
+ }
55
+ else {
56
+ // All consumers
57
+ const projects = getAllProjects(installations);
58
+ for (const projectPath of projects) {
59
+ const project = getProject(installations, projectPath);
60
+ if (!project)
61
+ continue;
62
+ consumers.push({
63
+ projectPath,
64
+ packages: Object.entries(project.packages).map(([name, info]) => ({
65
+ name,
66
+ version: info.version,
67
+ namespace: info.namespace,
68
+ })),
69
+ });
70
+ }
71
+ }
72
+ return { consumers, pruned };
73
+ }
74
+ /**
75
+ * Format consumers output
76
+ */
77
+ export async function listConsumers(options = {}) {
78
+ const { consumers, pruned } = await getConsumersInfo(options);
79
+ let output;
80
+ if (options.flat) {
81
+ output = formatConsumersFlat(consumers);
82
+ }
83
+ else {
84
+ output = formatConsumersTree(consumers);
85
+ }
86
+ if (pruned && pruned.length > 0) {
87
+ output += `\n\n🧹 Pruned ${pruned.length} dead project(s):\n`;
88
+ for (const p of pruned) {
89
+ output += ` - ${p}\n`;
90
+ }
91
+ }
92
+ return output;
93
+ }
94
+ /**
95
+ * CLI handler for consumers command
96
+ */
97
+ export async function handleConsumers(args) {
98
+ try {
99
+ const output = await listConsumers(args);
100
+ console.log(output);
101
+ }
102
+ catch (error) {
103
+ console.error(`✗ Consumers failed: ${error.message}`);
104
+ process.exit(1);
105
+ }
106
+ }
107
+ //# sourceMappingURL=consumers.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"consumers.js","sourceRoot":"","sources":["../../src/commands/consumers.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,59 @@
1
+ /**
2
+ * Docs Command - Display embedded documentation
3
+ */
4
+ export interface DocEntry {
5
+ name: string;
6
+ path: string;
7
+ type: "file" | "directory";
8
+ children?: DocEntry[];
9
+ }
10
+ /**
11
+ * Get the docs directory path (relative to package root)
12
+ */
13
+ export declare function getDocsPath(): string;
14
+ /**
15
+ * Get the AGENTS.md path
16
+ */
17
+ export declare function getAgentsPath(): string;
18
+ /**
19
+ * Normalize a path for comparison (lowercase, no .md extension)
20
+ */
21
+ export declare function normalizePath(p: string): string;
22
+ /**
23
+ * Build documentation tree from filesystem
24
+ */
25
+ export declare function buildDocTree(dirPath: string, relativePath?: string): DocEntry[];
26
+ /**
27
+ * Find a document by path (case insensitive)
28
+ */
29
+ export declare function findDocument(tree: DocEntry[], searchPath: string): {
30
+ entry: DocEntry;
31
+ fullPath: string;
32
+ } | null;
33
+ /**
34
+ * Format the documentation tree for display
35
+ */
36
+ export declare function formatTree(entries: DocEntry[], prefix?: string): string;
37
+ /**
38
+ * Format directory listing
39
+ */
40
+ export declare function formatDirectoryListing(entry: DocEntry): string;
41
+ /**
42
+ * Read and return document content
43
+ */
44
+ export declare function readDocument(docPath: string, docsDir?: string): string | null;
45
+ /**
46
+ * Read AGENTS.md
47
+ */
48
+ export declare function readAgents(agentsPath?: string): string | null;
49
+ /**
50
+ * Main docs command handler
51
+ */
52
+ export declare function handleDocs(args: {
53
+ document?: string;
54
+ }): Promise<void>;
55
+ /**
56
+ * Print docs help
57
+ */
58
+ export declare function printDocsHelp(): void;
59
+ //# sourceMappingURL=docs.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"docs.d.ts","sourceRoot":"","sources":["../../src/commands/docs.ts"],"names":[],"mappings":"AAAA;;GAEG;AAUH,MAAM,WAAW,QAAQ;IACvB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,GAAG,WAAW,CAAC;IAC3B,QAAQ,CAAC,EAAE,QAAQ,EAAE,CAAC;CACvB;AAED;;GAEG;AACH,wBAAgB,WAAW,IAAI,MAAM,CAGpC;AAED;;GAEG;AACH,wBAAgB,aAAa,IAAI,MAAM,CAEtC;AAED;;GAEG;AACH,wBAAgB,aAAa,CAAC,CAAC,EAAE,MAAM,GAAG,MAAM,CAE/C;AAED;;GAEG;AACH,wBAAgB,YAAY,CAAC,OAAO,EAAE,MAAM,EAAE,YAAY,GAAE,MAAW,GAAG,QAAQ,EAAE,CAoCnF;AAED;;GAEG;AACH,wBAAgB,YAAY,CAC1B,IAAI,EAAE,QAAQ,EAAE,EAChB,UAAU,EAAE,MAAM,GACjB;IAAE,KAAK,EAAE,QAAQ,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAA;CAAE,GAAG,IAAI,CA+B9C;AAED;;GAEG;AACH,wBAAgB,UAAU,CAAC,OAAO,EAAE,QAAQ,EAAE,EAAE,MAAM,GAAE,MAAW,GAAG,MAAM,CAoB3E;AAED;;GAEG;AACH,wBAAgB,sBAAsB,CAAC,KAAK,EAAE,QAAQ,GAAG,MAAM,CAoB9D;AAED;;GAEG;AACH,wBAAgB,YAAY,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAS7E;AAED;;GAEG;AACH,wBAAgB,UAAU,CAAC,UAAU,CAAC,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAO7D;AAED;;GAEG;AACH,wBAAsB,UAAU,CAAC,IAAI,EAAE;IAAE,QAAQ,CAAC,EAAE,MAAM,CAAA;CAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAsE3E;AAED;;GAEG;AACH,wBAAgB,aAAa,IAAI,IAAI,CA2BpC"}
@@ -0,0 +1,262 @@
1
+ /**
2
+ * Docs Command - Display embedded documentation
3
+ */
4
+ import fs from "fs";
5
+ import path from "path";
6
+ import { fileURLToPath } from "url";
7
+ const __filename = fileURLToPath(import.meta.url);
8
+ const __dirname = path.dirname(__filename);
9
+ /**
10
+ * Get the docs directory path (relative to package root)
11
+ */
12
+ export function getDocsPath() {
13
+ // From dist/commands/docs.js, go up to package root
14
+ return path.resolve(__dirname, "../../docs");
15
+ }
16
+ /**
17
+ * Get the AGENTS.md path
18
+ */
19
+ export function getAgentsPath() {
20
+ return path.resolve(__dirname, "../../AGENTS.md");
21
+ }
22
+ /**
23
+ * Normalize a path for comparison (lowercase, no .md extension)
24
+ */
25
+ export function normalizePath(p) {
26
+ return p.toLowerCase().replace(/\.md$/, "").replace(/\\/g, "/");
27
+ }
28
+ /**
29
+ * Build documentation tree from filesystem
30
+ */
31
+ export function buildDocTree(dirPath, relativePath = "") {
32
+ const entries = [];
33
+ try {
34
+ const items = fs.readdirSync(dirPath, { withFileTypes: true });
35
+ for (const item of items) {
36
+ if (item.name.startsWith("."))
37
+ continue;
38
+ const itemPath = path.join(dirPath, item.name);
39
+ const relPath = relativePath ? `${relativePath}/${item.name}` : item.name;
40
+ if (item.isDirectory()) {
41
+ entries.push({
42
+ name: item.name,
43
+ path: relPath,
44
+ type: "directory",
45
+ children: buildDocTree(itemPath, relPath),
46
+ });
47
+ }
48
+ else if (item.name.endsWith(".md")) {
49
+ entries.push({
50
+ name: item.name.replace(/\.md$/, ""),
51
+ path: relPath.replace(/\.md$/, ""),
52
+ type: "file",
53
+ });
54
+ }
55
+ }
56
+ }
57
+ catch {
58
+ // Directory doesn't exist or can't be read
59
+ }
60
+ return entries.sort((a, b) => {
61
+ // Directories first, then files
62
+ if (a.type !== b.type)
63
+ return a.type === "directory" ? -1 : 1;
64
+ return a.name.localeCompare(b.name);
65
+ });
66
+ }
67
+ /**
68
+ * Find a document by path (case insensitive)
69
+ */
70
+ export function findDocument(tree, searchPath) {
71
+ const normalized = normalizePath(searchPath);
72
+ const parts = normalized.split("/").filter(Boolean);
73
+ let current = tree;
74
+ let currentPath = "";
75
+ for (let i = 0; i < parts.length; i++) {
76
+ const part = parts[i];
77
+ const isLast = i === parts.length - 1;
78
+ const found = current.find((e) => normalizePath(e.name) === part);
79
+ if (!found)
80
+ return null;
81
+ currentPath = currentPath ? `${currentPath}/${found.name}` : found.name;
82
+ if (isLast) {
83
+ return { entry: found, fullPath: currentPath };
84
+ }
85
+ if (found.type === "directory" && found.children) {
86
+ current = found.children;
87
+ }
88
+ else {
89
+ return null;
90
+ }
91
+ }
92
+ return null;
93
+ }
94
+ /**
95
+ * Format the documentation tree for display
96
+ */
97
+ export function formatTree(entries, prefix = "") {
98
+ const lines = [];
99
+ for (let i = 0; i < entries.length; i++) {
100
+ const entry = entries[i];
101
+ const isLast = i === entries.length - 1;
102
+ const connector = isLast ? "└── " : "├── ";
103
+ const childPrefix = isLast ? " " : "│ ";
104
+ if (entry.type === "directory") {
105
+ lines.push(`${prefix}${connector}${entry.name}/`);
106
+ if (entry.children && entry.children.length > 0) {
107
+ lines.push(formatTree(entry.children, prefix + childPrefix));
108
+ }
109
+ }
110
+ else {
111
+ lines.push(`${prefix}${connector}${entry.name}`);
112
+ }
113
+ }
114
+ return lines.join("\n");
115
+ }
116
+ /**
117
+ * Format directory listing
118
+ */
119
+ export function formatDirectoryListing(entry) {
120
+ const lines = [];
121
+ lines.push(`📁 ${entry.path}/\n`);
122
+ if (entry.children && entry.children.length > 0) {
123
+ lines.push("Documents:");
124
+ for (const child of entry.children) {
125
+ if (child.type === "file") {
126
+ lines.push(` ${child.name}`);
127
+ }
128
+ else {
129
+ lines.push(` ${child.name}/`);
130
+ }
131
+ }
132
+ lines.push("");
133
+ lines.push(`Usage: devlink docs ${entry.path}/<document>`);
134
+ }
135
+ else {
136
+ lines.push("(empty directory)");
137
+ }
138
+ return lines.join("\n");
139
+ }
140
+ /**
141
+ * Read and return document content
142
+ */
143
+ export function readDocument(docPath, docsDir) {
144
+ const dir = docsDir || getDocsPath();
145
+ const fullPath = path.join(dir, docPath + ".md");
146
+ try {
147
+ return fs.readFileSync(fullPath, "utf-8");
148
+ }
149
+ catch {
150
+ return null;
151
+ }
152
+ }
153
+ /**
154
+ * Read AGENTS.md
155
+ */
156
+ export function readAgents(agentsPath) {
157
+ const filePath = agentsPath || getAgentsPath();
158
+ try {
159
+ return fs.readFileSync(filePath, "utf-8");
160
+ }
161
+ catch {
162
+ return null;
163
+ }
164
+ }
165
+ /**
166
+ * Main docs command handler
167
+ */
168
+ export async function handleDocs(args) {
169
+ const docsDir = getDocsPath();
170
+ const tree = buildDocTree(docsDir);
171
+ // Add AGENTS.md as a special top-level entry
172
+ const fullTree = [
173
+ { name: "agents", path: "agents", type: "file" },
174
+ ...tree,
175
+ ];
176
+ // No argument: show full tree
177
+ if (!args.document) {
178
+ console.log(`
179
+ 📚 DevLink Documentation
180
+
181
+ ${formatTree(fullTree)}
182
+
183
+ Usage:
184
+ devlink docs <document> Show document content
185
+ devlink docs <directory> List documents in directory
186
+
187
+ Examples:
188
+ devlink docs agents AI agent guide (comprehensive)
189
+ devlink docs store List store documents
190
+ devlink docs store/namespaces Show namespaces documentation
191
+ `);
192
+ return;
193
+ }
194
+ const searchPath = args.document;
195
+ const normalizedSearch = normalizePath(searchPath);
196
+ // Special case: agents
197
+ if (normalizedSearch === "agents" || normalizedSearch === "agent" || normalizedSearch === "ai") {
198
+ const content = readAgents();
199
+ if (content) {
200
+ console.log(content);
201
+ return;
202
+ }
203
+ console.error("Error: AGENTS.md not found");
204
+ process.exit(1);
205
+ }
206
+ // Search in tree
207
+ const result = findDocument(tree, searchPath);
208
+ if (!result) {
209
+ console.error(`Document not found: ${searchPath}`);
210
+ console.error("");
211
+ console.error("Available documents:");
212
+ console.error(formatTree(fullTree));
213
+ process.exit(1);
214
+ }
215
+ const { entry, fullPath } = result;
216
+ if (entry.type === "directory") {
217
+ // Show directory listing
218
+ console.log(formatDirectoryListing(entry));
219
+ return;
220
+ }
221
+ // Read and display file
222
+ const content = readDocument(fullPath);
223
+ if (content) {
224
+ console.log(content);
225
+ }
226
+ else {
227
+ console.error(`Error: Could not read ${fullPath}.md`);
228
+ process.exit(1);
229
+ }
230
+ }
231
+ /**
232
+ * Print docs help
233
+ */
234
+ export function printDocsHelp() {
235
+ console.log(`
236
+ devlink docs - Display embedded documentation
237
+
238
+ USAGE
239
+ devlink docs [document]
240
+
241
+ DESCRIPTION
242
+ Access DevLink documentation directly from the command line.
243
+ Without arguments, shows the documentation tree.
244
+ With a document path, displays that document's content.
245
+ With a directory path, lists documents in that directory.
246
+
247
+ ARGUMENTS
248
+ [document] Document or directory path (case insensitive, .md optional)
249
+
250
+ EXAMPLES
251
+ devlink docs Show documentation tree
252
+ devlink docs agents AI agent guide (comprehensive)
253
+ devlink docs store List store documents
254
+ devlink docs store/namespaces Show namespaces documentation
255
+ devlink docs STORE/NAMESPACES Same (case insensitive)
256
+ devlink docs publishing/push Show push command documentation
257
+
258
+ SPECIAL DOCUMENTS
259
+ agents Complete self-contained guide for AI agents
260
+ `);
261
+ }
262
+ //# sourceMappingURL=docs.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"docs.js","sourceRoot":"","sources":["../../src/commands/docs.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,5 @@
1
+ /**
2
+ * Docs Command - Unit tests
3
+ */
4
+ export {};
5
+ //# sourceMappingURL=docs.spec.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"docs.spec.d.ts","sourceRoot":"","sources":["../../src/commands/docs.spec.ts"],"names":[],"mappings":"AAAA;;GAEG"}
@@ -0,0 +1,213 @@
1
+ /**
2
+ * Docs Command - Unit tests
3
+ */
4
+ import { describe, it, expect, beforeEach, afterEach } from "vitest";
5
+ import fs from "fs/promises";
6
+ import path from "path";
7
+ import os from "os";
8
+ import { normalizePath, buildDocTree, findDocument, formatTree, formatDirectoryListing, readDocument, readAgents, } from "./docs.js";
9
+ const TEST_DOCS_PATH = path.join(os.tmpdir(), "devlink-docs-test-" + Date.now());
10
+ describe("Docs Command", () => {
11
+ beforeEach(async () => {
12
+ // Create test documentation structure
13
+ await fs.mkdir(TEST_DOCS_PATH, { recursive: true });
14
+ // Create directories
15
+ await fs.mkdir(path.join(TEST_DOCS_PATH, "store"), { recursive: true });
16
+ await fs.mkdir(path.join(TEST_DOCS_PATH, "publishing"), { recursive: true });
17
+ await fs.mkdir(path.join(TEST_DOCS_PATH, "empty-dir"), { recursive: true });
18
+ // Create files
19
+ await fs.writeFile(path.join(TEST_DOCS_PATH, "README.md"), "# Documentation Index\n\nWelcome to docs.");
20
+ await fs.writeFile(path.join(TEST_DOCS_PATH, "store", "structure.md"), "# Store Structure\n\nThe store is located at ~/.devlink");
21
+ await fs.writeFile(path.join(TEST_DOCS_PATH, "store", "namespaces.md"), "# Namespaces\n\nNamespaces provide isolation.");
22
+ await fs.writeFile(path.join(TEST_DOCS_PATH, "publishing", "publish.md"), "# Publish Command\n\nPublish packages to the store.");
23
+ // Create AGENTS.md
24
+ await fs.writeFile(path.join(TEST_DOCS_PATH, "AGENTS.md"), "# Agent Guide\n\nComplete guide for AI agents.");
25
+ });
26
+ afterEach(async () => {
27
+ await fs.rm(TEST_DOCS_PATH, { recursive: true, force: true });
28
+ });
29
+ describe("normalizePath", () => {
30
+ it("should convert to lowercase", () => {
31
+ expect(normalizePath("STORE/NAMESPACES")).toBe("store/namespaces");
32
+ });
33
+ it("should remove .md extension", () => {
34
+ expect(normalizePath("store/namespaces.md")).toBe("store/namespaces");
35
+ });
36
+ it("should normalize backslashes", () => {
37
+ expect(normalizePath("store\\namespaces")).toBe("store/namespaces");
38
+ });
39
+ it("should handle combined cases", () => {
40
+ expect(normalizePath("STORE\\NAMESPACES.MD")).toBe("store/namespaces");
41
+ });
42
+ });
43
+ describe("buildDocTree", () => {
44
+ it("should build tree from directory", () => {
45
+ const tree = buildDocTree(TEST_DOCS_PATH);
46
+ // Should have directories first, then files
47
+ expect(tree.length).toBeGreaterThan(0);
48
+ // Find store directory
49
+ const storeDir = tree.find(e => e.name === "store");
50
+ expect(storeDir).toBeDefined();
51
+ expect(storeDir?.type).toBe("directory");
52
+ expect(storeDir?.children?.length).toBe(2);
53
+ });
54
+ it("should sort directories before files", () => {
55
+ const tree = buildDocTree(TEST_DOCS_PATH);
56
+ // First entries should be directories
57
+ const firstDir = tree.findIndex(e => e.type === "directory");
58
+ const firstFile = tree.findIndex(e => e.type === "file");
59
+ if (firstDir !== -1 && firstFile !== -1) {
60
+ expect(firstDir).toBeLessThan(firstFile);
61
+ }
62
+ });
63
+ it("should exclude hidden files", async () => {
64
+ await fs.writeFile(path.join(TEST_DOCS_PATH, ".hidden.md"), "hidden");
65
+ const tree = buildDocTree(TEST_DOCS_PATH);
66
+ const hidden = tree.find(e => e.name === ".hidden");
67
+ expect(hidden).toBeUndefined();
68
+ });
69
+ it("should only include .md files", async () => {
70
+ await fs.writeFile(path.join(TEST_DOCS_PATH, "test.txt"), "text file");
71
+ const tree = buildDocTree(TEST_DOCS_PATH);
72
+ const txtFile = tree.find(e => e.name === "test");
73
+ expect(txtFile).toBeUndefined();
74
+ });
75
+ it("should handle empty directories", () => {
76
+ const tree = buildDocTree(TEST_DOCS_PATH);
77
+ const emptyDir = tree.find(e => e.name === "empty-dir");
78
+ expect(emptyDir).toBeDefined();
79
+ expect(emptyDir?.children).toEqual([]);
80
+ });
81
+ it("should return empty array for non-existent directory", () => {
82
+ const tree = buildDocTree("/non/existent/path");
83
+ expect(tree).toEqual([]);
84
+ });
85
+ });
86
+ describe("findDocument", () => {
87
+ it("should find file by exact path", () => {
88
+ const tree = buildDocTree(TEST_DOCS_PATH);
89
+ const result = findDocument(tree, "store/structure");
90
+ expect(result).not.toBeNull();
91
+ expect(result?.entry.name).toBe("structure");
92
+ expect(result?.entry.type).toBe("file");
93
+ });
94
+ it("should find file case insensitively", () => {
95
+ const tree = buildDocTree(TEST_DOCS_PATH);
96
+ const result = findDocument(tree, "STORE/STRUCTURE");
97
+ expect(result).not.toBeNull();
98
+ expect(result?.entry.name).toBe("structure");
99
+ });
100
+ it("should find directory", () => {
101
+ const tree = buildDocTree(TEST_DOCS_PATH);
102
+ const result = findDocument(tree, "store");
103
+ expect(result).not.toBeNull();
104
+ expect(result?.entry.type).toBe("directory");
105
+ });
106
+ it("should return null for non-existent path", () => {
107
+ const tree = buildDocTree(TEST_DOCS_PATH);
108
+ const result = findDocument(tree, "nonexistent/path");
109
+ expect(result).toBeNull();
110
+ });
111
+ it("should handle path with .md extension", () => {
112
+ const tree = buildDocTree(TEST_DOCS_PATH);
113
+ const result = findDocument(tree, "store/structure.md");
114
+ expect(result).not.toBeNull();
115
+ expect(result?.entry.name).toBe("structure");
116
+ });
117
+ });
118
+ describe("formatTree", () => {
119
+ it("should format tree with connectors", () => {
120
+ const entries = [
121
+ { name: "dir", path: "dir", type: "directory", children: [] },
122
+ { name: "file", path: "file", type: "file" },
123
+ ];
124
+ const output = formatTree(entries);
125
+ expect(output).toContain("├── dir/");
126
+ expect(output).toContain("└── file");
127
+ });
128
+ it("should format nested directories", () => {
129
+ const entries = [
130
+ {
131
+ name: "parent",
132
+ path: "parent",
133
+ type: "directory",
134
+ children: [
135
+ { name: "child", path: "parent/child", type: "file" },
136
+ ],
137
+ },
138
+ ];
139
+ const output = formatTree(entries);
140
+ expect(output).toContain("└── parent/");
141
+ expect(output).toContain("└── child");
142
+ });
143
+ it("should handle empty array", () => {
144
+ const output = formatTree([]);
145
+ expect(output).toBe("");
146
+ });
147
+ });
148
+ describe("formatDirectoryListing", () => {
149
+ it("should format directory with children", () => {
150
+ const entry = {
151
+ name: "store",
152
+ path: "store",
153
+ type: "directory",
154
+ children: [
155
+ { name: "structure", path: "store/structure", type: "file" },
156
+ { name: "namespaces", path: "store/namespaces", type: "file" },
157
+ ],
158
+ };
159
+ const output = formatDirectoryListing(entry);
160
+ expect(output).toContain("📁 store/");
161
+ expect(output).toContain("Documents:");
162
+ expect(output).toContain("structure");
163
+ expect(output).toContain("namespaces");
164
+ expect(output).toContain("Usage: devlink docs store/<document>");
165
+ });
166
+ it("should handle empty directory", () => {
167
+ const entry = {
168
+ name: "empty",
169
+ path: "empty",
170
+ type: "directory",
171
+ children: [],
172
+ };
173
+ const output = formatDirectoryListing(entry);
174
+ expect(output).toContain("(empty directory)");
175
+ });
176
+ it("should show subdirectories with trailing slash", () => {
177
+ const entry = {
178
+ name: "parent",
179
+ path: "parent",
180
+ type: "directory",
181
+ children: [
182
+ { name: "subdir", path: "parent/subdir", type: "directory", children: [] },
183
+ ],
184
+ };
185
+ const output = formatDirectoryListing(entry);
186
+ expect(output).toContain("subdir/");
187
+ });
188
+ });
189
+ describe("readDocument", () => {
190
+ it("should read document content", () => {
191
+ const content = readDocument("store/structure", TEST_DOCS_PATH);
192
+ expect(content).not.toBeNull();
193
+ expect(content).toContain("# Store Structure");
194
+ });
195
+ it("should return null for non-existent document", () => {
196
+ const content = readDocument("nonexistent", TEST_DOCS_PATH);
197
+ expect(content).toBeNull();
198
+ });
199
+ });
200
+ describe("readAgents", () => {
201
+ it("should read AGENTS.md content", () => {
202
+ const agentsPath = path.join(TEST_DOCS_PATH, "AGENTS.md");
203
+ const content = readAgents(agentsPath);
204
+ expect(content).not.toBeNull();
205
+ expect(content).toContain("# Agent Guide");
206
+ });
207
+ it("should return null for non-existent file", () => {
208
+ const content = readAgents("/nonexistent/AGENTS.md");
209
+ expect(content).toBeNull();
210
+ });
211
+ });
212
+ });
213
+ //# sourceMappingURL=docs.spec.js.map