@fractary/core 0.3.2 → 0.4.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 (122) hide show
  1. package/dist/__tests__/factories.test.d.ts +5 -0
  2. package/dist/__tests__/factories.test.d.ts.map +1 -0
  3. package/dist/__tests__/factories.test.js +66 -0
  4. package/dist/__tests__/factories.test.js.map +1 -0
  5. package/dist/auth/__tests__/create-token-provider.test.d.ts +5 -0
  6. package/dist/auth/__tests__/create-token-provider.test.d.ts.map +1 -0
  7. package/dist/auth/__tests__/create-token-provider.test.js +104 -0
  8. package/dist/auth/__tests__/create-token-provider.test.js.map +1 -0
  9. package/dist/auth/__tests__/github-app-auth.test.d.ts +5 -0
  10. package/dist/auth/__tests__/github-app-auth.test.d.ts.map +1 -0
  11. package/dist/auth/__tests__/github-app-auth.test.js +293 -0
  12. package/dist/auth/__tests__/github-app-auth.test.js.map +1 -0
  13. package/dist/auth/__tests__/static-token-provider.test.d.ts +5 -0
  14. package/dist/auth/__tests__/static-token-provider.test.d.ts.map +1 -0
  15. package/dist/auth/__tests__/static-token-provider.test.js +54 -0
  16. package/dist/auth/__tests__/static-token-provider.test.js.map +1 -0
  17. package/dist/auth/github-app-auth.d.ts +109 -0
  18. package/dist/auth/github-app-auth.d.ts.map +1 -0
  19. package/dist/auth/github-app-auth.js +262 -0
  20. package/dist/auth/github-app-auth.js.map +1 -0
  21. package/dist/auth/github-app-token-provider.d.ts +59 -0
  22. package/dist/auth/github-app-token-provider.d.ts.map +1 -0
  23. package/dist/auth/github-app-token-provider.js +68 -0
  24. package/dist/auth/github-app-token-provider.js.map +1 -0
  25. package/dist/auth/index.d.ts +45 -0
  26. package/dist/auth/index.d.ts.map +1 -0
  27. package/dist/auth/index.js +74 -0
  28. package/dist/auth/index.js.map +1 -0
  29. package/dist/auth/static-token-provider.d.ts +35 -0
  30. package/dist/auth/static-token-provider.d.ts.map +1 -0
  31. package/dist/auth/static-token-provider.js +45 -0
  32. package/dist/auth/static-token-provider.js.map +1 -0
  33. package/dist/auth/types.d.ts +49 -0
  34. package/dist/auth/types.d.ts.map +1 -0
  35. package/dist/auth/types.js +8 -0
  36. package/dist/auth/types.js.map +1 -0
  37. package/dist/common/yaml-config.d.ts +10 -0
  38. package/dist/common/yaml-config.d.ts.map +1 -1
  39. package/dist/common/yaml-config.js.map +1 -1
  40. package/dist/config/__tests__/loader.test.d.ts +5 -0
  41. package/dist/config/__tests__/loader.test.d.ts.map +1 -0
  42. package/dist/config/__tests__/loader.test.js +129 -0
  43. package/dist/config/__tests__/loader.test.js.map +1 -0
  44. package/dist/config/index.d.ts +8 -0
  45. package/dist/config/index.d.ts.map +1 -0
  46. package/dist/config/index.js +27 -0
  47. package/dist/config/index.js.map +1 -0
  48. package/dist/config/loader.d.ts +126 -0
  49. package/dist/config/loader.d.ts.map +1 -0
  50. package/dist/config/loader.js +277 -0
  51. package/dist/config/loader.js.map +1 -0
  52. package/dist/docs/index.d.ts +5 -0
  53. package/dist/docs/index.d.ts.map +1 -1
  54. package/dist/docs/index.js +6 -1
  55. package/dist/docs/index.js.map +1 -1
  56. package/dist/docs/manager.d.ts +27 -0
  57. package/dist/docs/manager.d.ts.map +1 -1
  58. package/dist/docs/manager.js +168 -15
  59. package/dist/docs/manager.js.map +1 -1
  60. package/dist/docs/type-registry.d.ts +123 -0
  61. package/dist/docs/type-registry.d.ts.map +1 -0
  62. package/dist/docs/type-registry.js +393 -0
  63. package/dist/docs/type-registry.js.map +1 -0
  64. package/dist/docs/types.d.ts +93 -0
  65. package/dist/docs/types.d.ts.map +1 -1
  66. package/dist/factories.d.ts +89 -0
  67. package/dist/factories.d.ts.map +1 -0
  68. package/dist/factories.js +228 -0
  69. package/dist/factories.js.map +1 -0
  70. package/dist/file/factory.d.ts +41 -0
  71. package/dist/file/factory.d.ts.map +1 -0
  72. package/dist/file/factory.js +237 -0
  73. package/dist/file/factory.js.map +1 -0
  74. package/dist/file/gcs.d.ts +66 -0
  75. package/dist/file/gcs.d.ts.map +1 -0
  76. package/dist/file/gcs.js +226 -0
  77. package/dist/file/gcs.js.map +1 -0
  78. package/dist/file/gdrive.d.ts +78 -0
  79. package/dist/file/gdrive.d.ts.map +1 -0
  80. package/dist/file/gdrive.js +302 -0
  81. package/dist/file/gdrive.js.map +1 -0
  82. package/dist/file/index.d.ts +13 -1
  83. package/dist/file/index.d.ts.map +1 -1
  84. package/dist/file/index.js +25 -1
  85. package/dist/file/index.js.map +1 -1
  86. package/dist/file/manager.d.ts +83 -2
  87. package/dist/file/manager.d.ts.map +1 -1
  88. package/dist/file/manager.js +125 -4
  89. package/dist/file/manager.js.map +1 -1
  90. package/dist/file/r2.d.ts +56 -0
  91. package/dist/file/r2.d.ts.map +1 -0
  92. package/dist/file/r2.js +96 -0
  93. package/dist/file/r2.js.map +1 -0
  94. package/dist/file/s3.d.ts +61 -0
  95. package/dist/file/s3.d.ts.map +1 -0
  96. package/dist/file/s3.js +258 -0
  97. package/dist/file/s3.js.map +1 -0
  98. package/dist/file/types.d.ts +145 -2
  99. package/dist/file/types.d.ts.map +1 -1
  100. package/dist/index.d.ts +3 -0
  101. package/dist/index.d.ts.map +1 -1
  102. package/dist/index.js +6 -0
  103. package/dist/index.js.map +1 -1
  104. package/dist/logs/index.d.ts +1 -0
  105. package/dist/logs/index.d.ts.map +1 -1
  106. package/dist/logs/index.js +3 -1
  107. package/dist/logs/index.js.map +1 -1
  108. package/dist/logs/manager.d.ts +29 -2
  109. package/dist/logs/manager.d.ts.map +1 -1
  110. package/dist/logs/manager.js +48 -7
  111. package/dist/logs/manager.js.map +1 -1
  112. package/dist/logs/type-registry.d.ts +180 -0
  113. package/dist/logs/type-registry.d.ts.map +1 -0
  114. package/dist/logs/type-registry.js +421 -0
  115. package/dist/logs/type-registry.js.map +1 -0
  116. package/dist/logs/type-registry.test.d.ts +5 -0
  117. package/dist/logs/type-registry.test.d.ts.map +1 -0
  118. package/dist/logs/type-registry.test.js +671 -0
  119. package/dist/logs/type-registry.test.js.map +1 -0
  120. package/dist/logs/types.d.ts +2 -0
  121. package/dist/logs/types.d.ts.map +1 -1
  122. package/package.json +62 -8
@@ -0,0 +1,277 @@
1
+ "use strict";
2
+ /**
3
+ * @fractary/core - Unified Configuration Loader
4
+ *
5
+ * Builds on yaml-config.ts to provide a unified configuration object
6
+ * with integrated authentication support.
7
+ */
8
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
9
+ if (k2 === undefined) k2 = k;
10
+ var desc = Object.getOwnPropertyDescriptor(m, k);
11
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
12
+ desc = { enumerable: true, get: function() { return m[k]; } };
13
+ }
14
+ Object.defineProperty(o, k2, desc);
15
+ }) : (function(o, m, k, k2) {
16
+ if (k2 === undefined) k2 = k;
17
+ o[k2] = m[k];
18
+ }));
19
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
20
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
21
+ }) : function(o, v) {
22
+ o["default"] = v;
23
+ });
24
+ var __importStar = (this && this.__importStar) || (function () {
25
+ var ownKeys = function(o) {
26
+ ownKeys = Object.getOwnPropertyNames || function (o) {
27
+ var ar = [];
28
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
29
+ return ar;
30
+ };
31
+ return ownKeys(o);
32
+ };
33
+ return function (mod) {
34
+ if (mod && mod.__esModule) return mod;
35
+ var result = {};
36
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
37
+ __setModuleDefault(result, mod);
38
+ return result;
39
+ };
40
+ })();
41
+ Object.defineProperty(exports, "__esModule", { value: true });
42
+ exports.loadEnv = loadEnv;
43
+ exports.isEnvLoaded = isEnvLoaded;
44
+ exports.loadConfig = loadConfig;
45
+ exports.loadConfigSync = loadConfigSync;
46
+ const dotenv = __importStar(require("dotenv"));
47
+ const path = __importStar(require("path"));
48
+ const fs = __importStar(require("fs"));
49
+ const yaml_config_1 = require("../common/yaml-config");
50
+ const auth_1 = require("../auth");
51
+ const yaml_config_2 = require("../common/yaml-config");
52
+ /** Track whether loadEnv has been called */
53
+ let envLoaded = false;
54
+ /**
55
+ * Load environment variables from .env files
56
+ *
57
+ * This function explicitly loads .env files - it must be called manually
58
+ * rather than being a side effect of importing the module.
59
+ *
60
+ * Searches for .env files in the following order:
61
+ * 1. Current working directory
62
+ * 2. Project root (directory containing .fractary or .git)
63
+ *
64
+ * @param options Loading options
65
+ * @returns true if .env was loaded, false if no .env file found
66
+ *
67
+ * @example
68
+ * ```typescript
69
+ * import { loadEnv, loadConfig } from '@fractary/core';
70
+ *
71
+ * // Explicitly load .env before loading config
72
+ * loadEnv();
73
+ * const config = await loadConfig();
74
+ * ```
75
+ */
76
+ function loadEnv(options = {}) {
77
+ const { cwd = process.cwd(), force = false } = options;
78
+ // Skip if already loaded (unless force is true)
79
+ if (envLoaded && !force) {
80
+ return true;
81
+ }
82
+ // Try loading from current working directory first
83
+ const cwdEnvPath = path.join(cwd, '.env');
84
+ if (fs.existsSync(cwdEnvPath)) {
85
+ dotenv.config({ path: cwdEnvPath });
86
+ envLoaded = true;
87
+ return true;
88
+ }
89
+ // Try loading from project root
90
+ try {
91
+ const projectRoot = (0, yaml_config_2.findProjectRoot)(cwd);
92
+ const rootEnvPath = path.join(projectRoot, '.env');
93
+ if (fs.existsSync(rootEnvPath)) {
94
+ dotenv.config({ path: rootEnvPath });
95
+ envLoaded = true;
96
+ return true;
97
+ }
98
+ }
99
+ catch {
100
+ // findProjectRoot failed - that's okay
101
+ }
102
+ return false;
103
+ }
104
+ /**
105
+ * Check if environment variables have been loaded
106
+ *
107
+ * @returns true if loadEnv() has been called successfully
108
+ */
109
+ function isEnvLoaded() {
110
+ return envLoaded;
111
+ }
112
+ /**
113
+ * Extract GitHub configuration from yaml config
114
+ *
115
+ * Looks for GitHub configuration in:
116
+ * 1. work.handlers.github
117
+ * 2. repo.handlers.github
118
+ *
119
+ * @param config Raw yaml configuration
120
+ * @returns Extracted GitHub configuration or undefined
121
+ */
122
+ function extractGitHubConfig(config) {
123
+ // Try work handlers first
124
+ const workGithub = config.work?.handlers?.github;
125
+ const repoGithub = config.repo?.handlers?.github;
126
+ // Merge configurations (work takes priority for auth, repo for project info)
127
+ const github = {};
128
+ let hasConfig = false;
129
+ // Extract token
130
+ if (workGithub?.token) {
131
+ github.token = workGithub.token;
132
+ hasConfig = true;
133
+ }
134
+ else if (repoGithub?.token) {
135
+ github.token = repoGithub.token;
136
+ hasConfig = true;
137
+ }
138
+ // Extract organization
139
+ if (workGithub?.organization) {
140
+ github.organization = workGithub.organization;
141
+ hasConfig = true;
142
+ }
143
+ else if (repoGithub?.organization) {
144
+ github.organization = repoGithub.organization;
145
+ hasConfig = true;
146
+ }
147
+ // Extract project (owner/repo)
148
+ if (workGithub?.project) {
149
+ github.project = workGithub.project;
150
+ hasConfig = true;
151
+ }
152
+ else if (repoGithub?.project) {
153
+ github.project = repoGithub.project;
154
+ hasConfig = true;
155
+ }
156
+ else if (workGithub?.owner && workGithub?.repo) {
157
+ github.project = `${workGithub.owner}/${workGithub.repo}`;
158
+ hasConfig = true;
159
+ }
160
+ else if (repoGithub?.owner && repoGithub?.repo) {
161
+ github.project = `${repoGithub.owner}/${repoGithub.repo}`;
162
+ hasConfig = true;
163
+ }
164
+ // Extract GitHub App config
165
+ const appConfig = workGithub?.app || repoGithub?.app;
166
+ if (appConfig?.id && appConfig?.installation_id) {
167
+ github.app = {
168
+ id: String(appConfig.id),
169
+ installation_id: String(appConfig.installation_id),
170
+ private_key_path: appConfig.private_key_path,
171
+ private_key_env_var: appConfig.private_key_env_var,
172
+ };
173
+ hasConfig = true;
174
+ }
175
+ return hasConfig ? github : undefined;
176
+ }
177
+ /**
178
+ * Load unified configuration with authentication
179
+ *
180
+ * This function:
181
+ * 1. Loads and parses the YAML configuration
182
+ * 2. Extracts GitHub configuration from handlers
183
+ * 3. Creates a TokenProvider for authentication (if configured)
184
+ * 4. Returns a unified config object
185
+ *
186
+ * Note: dotenv should be imported at the entry point, so environment
187
+ * variables are already loaded when this function is called.
188
+ *
189
+ * @param options Configuration loading options
190
+ * @returns Loaded configuration with authentication
191
+ *
192
+ * @example
193
+ * ```typescript
194
+ * const config = await loadConfig();
195
+ *
196
+ * if (config.tokenProvider) {
197
+ * const token = await config.tokenProvider.getToken();
198
+ * // Use token for API calls
199
+ * }
200
+ * ```
201
+ */
202
+ async function loadConfig(options = {}) {
203
+ const { skipAuth = false, ...yamlOptions } = options;
204
+ // Load raw YAML configuration
205
+ const raw = (0, yaml_config_1.loadYamlConfig)(yamlOptions);
206
+ // Handle case where config file doesn't exist
207
+ if (!raw) {
208
+ return {
209
+ version: '0.0.0',
210
+ raw: { version: '0.0.0' },
211
+ };
212
+ }
213
+ // Extract GitHub configuration
214
+ const github = extractGitHubConfig(raw);
215
+ // Create token provider (unless skipped)
216
+ let tokenProvider;
217
+ if (!skipAuth && github) {
218
+ try {
219
+ const githubConfig = {
220
+ token: github.token,
221
+ organization: github.organization,
222
+ project: github.project,
223
+ app: github.app,
224
+ };
225
+ tokenProvider = (0, auth_1.createTokenProvider)(githubConfig);
226
+ }
227
+ catch {
228
+ // Token provider creation failed - that's okay, it's optional
229
+ // The user might not have configured authentication yet
230
+ }
231
+ }
232
+ return {
233
+ version: raw.version || '0.0.0',
234
+ github,
235
+ tokenProvider,
236
+ work: raw.work,
237
+ repo: raw.repo,
238
+ logs: raw.logs,
239
+ file: raw.file,
240
+ spec: raw.spec,
241
+ docs: raw.docs,
242
+ codex: raw.codex,
243
+ raw,
244
+ };
245
+ }
246
+ /**
247
+ * Load configuration synchronously (without token provider)
248
+ *
249
+ * Useful for cases where you only need the configuration data
250
+ * without authentication.
251
+ *
252
+ * @param options Configuration loading options
253
+ * @returns Loaded configuration without token provider
254
+ */
255
+ function loadConfigSync(options = {}) {
256
+ const raw = (0, yaml_config_1.loadYamlConfig)(options);
257
+ if (!raw) {
258
+ return {
259
+ version: '0.0.0',
260
+ raw: { version: '0.0.0' },
261
+ };
262
+ }
263
+ const github = extractGitHubConfig(raw);
264
+ return {
265
+ version: raw.version || '0.0.0',
266
+ github,
267
+ work: raw.work,
268
+ repo: raw.repo,
269
+ logs: raw.logs,
270
+ file: raw.file,
271
+ spec: raw.spec,
272
+ docs: raw.docs,
273
+ codex: raw.codex,
274
+ raw,
275
+ };
276
+ }
277
+ //# sourceMappingURL=loader.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"loader.js","sourceRoot":"","sources":["../../src/config/loader.ts"],"names":[],"mappings":"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"}
@@ -2,7 +2,12 @@
2
2
  * @fractary/core - Docs Module
3
3
  *
4
4
  * Documentation management and organization.
5
+ *
6
+ * Doc types are now stored as YAML/Markdown files in the doc-types/ directory
7
+ * at the repository root. Use DocTypeRegistry to load and access them.
5
8
  */
6
9
  export { DocsManager } from './manager';
10
+ export { DocTypeRegistry } from './type-registry';
11
+ export type { CustomDocTypeConfig, DocTypeRegistryConfig } from './type-registry';
7
12
  export * from './types';
8
13
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/docs/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,WAAW,EAAE,MAAM,WAAW,CAAC;AACxC,cAAc,SAAS,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/docs/index.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,EAAE,WAAW,EAAE,MAAM,WAAW,CAAC;AACxC,OAAO,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAC;AAClD,YAAY,EAAE,mBAAmB,EAAE,qBAAqB,EAAE,MAAM,iBAAiB,CAAC;AAClF,cAAc,SAAS,CAAC"}
@@ -3,6 +3,9 @@
3
3
  * @fractary/core - Docs Module
4
4
  *
5
5
  * Documentation management and organization.
6
+ *
7
+ * Doc types are now stored as YAML/Markdown files in the doc-types/ directory
8
+ * at the repository root. Use DocTypeRegistry to load and access them.
6
9
  */
7
10
  var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
8
11
  if (k2 === undefined) k2 = k;
@@ -19,8 +22,10 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) {
19
22
  for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
20
23
  };
21
24
  Object.defineProperty(exports, "__esModule", { value: true });
22
- exports.DocsManager = void 0;
25
+ exports.DocTypeRegistry = exports.DocsManager = void 0;
23
26
  var manager_1 = require("./manager");
24
27
  Object.defineProperty(exports, "DocsManager", { enumerable: true, get: function () { return manager_1.DocsManager; } });
28
+ var type_registry_1 = require("./type-registry");
29
+ Object.defineProperty(exports, "DocTypeRegistry", { enumerable: true, get: function () { return type_registry_1.DocTypeRegistry; } });
25
30
  __exportStar(require("./types"), exports);
26
31
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/docs/index.ts"],"names":[],"mappings":";AAAA;;;;GAIG;;;;;;;;;;;;;;;;;AAEH,qCAAwC;AAA/B,sGAAA,WAAW,OAAA;AACpB,0CAAwB"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/docs/index.ts"],"names":[],"mappings":";AAAA;;;;;;;GAOG;;;;;;;;;;;;;;;;;AAEH,qCAAwC;AAA/B,sGAAA,WAAW,OAAA;AACpB,iDAAkD;AAAzC,gHAAA,eAAe,OAAA;AAExB,0CAAwB"}
@@ -10,25 +10,52 @@ import { Doc, DocFormat, DocMetadata, DocSearchQuery, DocsManagerConfig } from '
10
10
  export declare class DocsManager {
11
11
  private docsDir;
12
12
  private defaultFormat;
13
+ private metadataMode;
13
14
  constructor(config: DocsManagerConfig);
14
15
  private ensureDir;
15
16
  private getDocPath;
16
17
  private getMetadataPath;
17
18
  private getFileExtension;
19
+ /**
20
+ * Determine the effective metadata mode for a document format
21
+ * Frontmatter only makes sense for markdown files
22
+ */
23
+ private getEffectiveMetadataMode;
24
+ /**
25
+ * Parse frontmatter from markdown content
26
+ */
27
+ private parseFrontmatter;
28
+ /**
29
+ * Write frontmatter to markdown content
30
+ */
31
+ private writeFrontmatter;
32
+ /**
33
+ * Extract body content from content that may have frontmatter
34
+ */
35
+ private extractBody;
18
36
  /**
19
37
  * Create a new document
38
+ * @param id - Document identifier
39
+ * @param content - Document body content (without frontmatter)
40
+ * @param metadata - Document metadata
41
+ * @param format - Document format (default: markdown)
20
42
  */
21
43
  createDoc(id: string, content: string, metadata: DocMetadata, format?: DocFormat): Promise<Doc>;
22
44
  /**
23
45
  * Get a document by ID
46
+ * Supports both frontmatter and sidecar metadata modes
24
47
  */
25
48
  getDoc(id: string): Promise<Doc | null>;
26
49
  /**
27
50
  * Update a document
51
+ * @param id - Document identifier
52
+ * @param content - New body content (without frontmatter)
53
+ * @param metadata - Metadata fields to update (merged with existing)
28
54
  */
29
55
  updateDoc(id: string, content: string, metadata?: Partial<DocMetadata>): Promise<Doc | null>;
30
56
  /**
31
57
  * Delete a document
58
+ * Removes both the document file and any sidecar metadata file if it exists
32
59
  */
33
60
  deleteDoc(id: string): Promise<boolean>;
34
61
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"manager.d.ts","sourceRoot":"","sources":["../../src/docs/manager.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAKH,OAAO,EACL,GAAG,EACH,SAAS,EACT,WAAW,EACX,cAAc,EACd,iBAAiB,EAClB,MAAM,SAAS,CAAC;AAEjB;;GAEG;AACH,qBAAa,WAAW;IACtB,OAAO,CAAC,OAAO,CAAS;IACxB,OAAO,CAAC,aAAa,CAAY;gBAErB,MAAM,EAAE,iBAAiB;IAMrC,OAAO,CAAC,SAAS;IAMjB,OAAO,CAAC,UAAU;IAKlB,OAAO,CAAC,eAAe;IAIvB,OAAO,CAAC,gBAAgB;IAUxB;;OAEG;IACG,SAAS,CACb,EAAE,EAAE,MAAM,EACV,OAAO,EAAE,MAAM,EACf,QAAQ,EAAE,WAAW,EACrB,MAAM,CAAC,EAAE,SAAS,GACjB,OAAO,CAAC,GAAG,CAAC;IA2Bf;;OAEG;IACG,MAAM,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,GAAG,GAAG,IAAI,CAAC;IA6B7C;;OAEG;IACG,SAAS,CACb,EAAE,EAAE,MAAM,EACV,OAAO,EAAE,MAAM,EACf,QAAQ,CAAC,EAAE,OAAO,CAAC,WAAW,CAAC,GAC9B,OAAO,CAAC,GAAG,GAAG,IAAI,CAAC;IA2BtB;;OAEG;IACG,SAAS,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAoB7C;;OAEG;IACG,QAAQ,IAAI,OAAO,CAAC,GAAG,EAAE,CAAC;IA4BhC;;OAEG;IACG,UAAU,CAAC,KAAK,EAAE,cAAc,GAAG,OAAO,CAAC,GAAG,EAAE,CAAC;IAsDvD;;OAEG;IACG,SAAS,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;CAI9C"}
1
+ {"version":3,"file":"manager.d.ts","sourceRoot":"","sources":["../../src/docs/manager.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAKH,OAAO,EACL,GAAG,EACH,SAAS,EACT,WAAW,EACX,cAAc,EACd,iBAAiB,EAElB,MAAM,SAAS,CAAC;AAUjB;;GAEG;AACH,qBAAa,WAAW;IACtB,OAAO,CAAC,OAAO,CAAS;IACxB,OAAO,CAAC,aAAa,CAAY;IACjC,OAAO,CAAC,YAAY,CAAe;gBAEvB,MAAM,EAAE,iBAAiB;IAOrC,OAAO,CAAC,SAAS;IAMjB,OAAO,CAAC,UAAU;IAKlB,OAAO,CAAC,eAAe;IAIvB,OAAO,CAAC,gBAAgB;IAUxB;;;OAGG;IACH,OAAO,CAAC,wBAAwB;IAOhC;;OAEG;IACH,OAAO,CAAC,gBAAgB;IAiDxB;;OAEG;IACH,OAAO,CAAC,gBAAgB;IAuCxB;;OAEG;IACH,OAAO,CAAC,WAAW;IAKnB;;;;;;OAMG;IACG,SAAS,CACb,EAAE,EAAE,MAAM,EACV,OAAO,EAAE,MAAM,EACf,QAAQ,EAAE,WAAW,EACrB,MAAM,CAAC,EAAE,SAAS,GACjB,OAAO,CAAC,GAAG,CAAC;IAmCf;;;OAGG;IACG,MAAM,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,GAAG,GAAG,IAAI,CAAC;IAwC7C;;;;;OAKG;IACG,SAAS,CACb,EAAE,EAAE,MAAM,EACV,OAAO,EAAE,MAAM,EACf,QAAQ,CAAC,EAAE,OAAO,CAAC,WAAW,CAAC,GAC9B,OAAO,CAAC,GAAG,GAAG,IAAI,CAAC;IAsCtB;;;OAGG;IACG,SAAS,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAqB7C;;OAEG;IACG,QAAQ,IAAI,OAAO,CAAC,GAAG,EAAE,CAAC;IA4BhC;;OAEG;IACG,UAAU,CAAC,KAAK,EAAE,cAAc,GAAG,OAAO,CAAC,GAAG,EAAE,CAAC;IA2DvD;;OAEG;IACG,SAAS,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;CAI9C"}
@@ -48,9 +48,11 @@ const yaml = __importStar(require("js-yaml"));
48
48
  class DocsManager {
49
49
  docsDir;
50
50
  defaultFormat;
51
+ metadataMode;
51
52
  constructor(config) {
52
53
  this.docsDir = config.docsDir;
53
54
  this.defaultFormat = config.defaultFormat || 'markdown';
55
+ this.metadataMode = config.metadataMode || 'frontmatter';
54
56
  this.ensureDir(this.docsDir);
55
57
  }
56
58
  ensureDir(dirPath) {
@@ -74,26 +76,144 @@ class DocsManager {
74
76
  };
75
77
  return extensions[format];
76
78
  }
79
+ /**
80
+ * Determine the effective metadata mode for a document format
81
+ * Frontmatter only makes sense for markdown files
82
+ */
83
+ getEffectiveMetadataMode(format) {
84
+ if (format !== 'markdown') {
85
+ return 'sidecar';
86
+ }
87
+ return this.metadataMode;
88
+ }
89
+ /**
90
+ * Parse frontmatter from markdown content
91
+ */
92
+ parseFrontmatter(content) {
93
+ const frontmatterRegex = /^---\r?\n([\s\S]*?)\r?\n---\r?\n([\s\S]*)$/;
94
+ const match = content.match(frontmatterRegex);
95
+ if (!match) {
96
+ // No frontmatter found, return content as-is with minimal metadata
97
+ return {
98
+ metadata: { title: '' },
99
+ body: content,
100
+ };
101
+ }
102
+ const frontmatterContent = match[1];
103
+ const body = match[2];
104
+ let metadata;
105
+ try {
106
+ const parsed = yaml.load(frontmatterContent);
107
+ metadata = {
108
+ title: parsed.title || '',
109
+ description: parsed.description,
110
+ authors: parsed.authors,
111
+ tags: parsed.tags,
112
+ docType: parsed.docType,
113
+ status: parsed.status,
114
+ version: parsed.version,
115
+ };
116
+ // Parse dates
117
+ if (parsed.createdAt) {
118
+ metadata.createdAt = new Date(parsed.createdAt);
119
+ }
120
+ if (parsed.updatedAt) {
121
+ metadata.updatedAt = new Date(parsed.updatedAt);
122
+ }
123
+ // Copy any additional fields
124
+ for (const [key, value] of Object.entries(parsed)) {
125
+ if (!(key in metadata)) {
126
+ metadata[key] = value;
127
+ }
128
+ }
129
+ }
130
+ catch {
131
+ metadata = { title: '' };
132
+ }
133
+ return { metadata, body };
134
+ }
135
+ /**
136
+ * Write frontmatter to markdown content
137
+ */
138
+ writeFrontmatter(metadata, body) {
139
+ // Prepare metadata object for YAML serialization
140
+ const yamlMetadata = {};
141
+ // Add standard fields
142
+ if (metadata.title)
143
+ yamlMetadata.title = metadata.title;
144
+ if (metadata.description)
145
+ yamlMetadata.description = metadata.description;
146
+ if (metadata.authors && metadata.authors.length > 0)
147
+ yamlMetadata.authors = metadata.authors;
148
+ if (metadata.tags && metadata.tags.length > 0)
149
+ yamlMetadata.tags = metadata.tags;
150
+ if (metadata.docType)
151
+ yamlMetadata.docType = metadata.docType;
152
+ if (metadata.status)
153
+ yamlMetadata.status = metadata.status;
154
+ if (metadata.version)
155
+ yamlMetadata.version = metadata.version;
156
+ // Add dates
157
+ if (metadata.createdAt) {
158
+ yamlMetadata.createdAt = metadata.createdAt instanceof Date
159
+ ? metadata.createdAt.toISOString()
160
+ : metadata.createdAt;
161
+ }
162
+ if (metadata.updatedAt) {
163
+ yamlMetadata.updatedAt = metadata.updatedAt instanceof Date
164
+ ? metadata.updatedAt.toISOString()
165
+ : metadata.updatedAt;
166
+ }
167
+ // Add any additional custom fields
168
+ for (const [key, value] of Object.entries(metadata)) {
169
+ if (value !== undefined &&
170
+ !['title', 'description', 'authors', 'tags', 'docType', 'status', 'version', 'createdAt', 'updatedAt'].includes(key)) {
171
+ yamlMetadata[key] = value;
172
+ }
173
+ }
174
+ const frontmatter = yaml.dump(yamlMetadata, { lineWidth: -1 });
175
+ return `---\n${frontmatter}---\n\n${body}`;
176
+ }
177
+ /**
178
+ * Extract body content from content that may have frontmatter
179
+ */
180
+ extractBody(content) {
181
+ const result = this.parseFrontmatter(content);
182
+ return result.body;
183
+ }
77
184
  /**
78
185
  * Create a new document
186
+ * @param id - Document identifier
187
+ * @param content - Document body content (without frontmatter)
188
+ * @param metadata - Document metadata
189
+ * @param format - Document format (default: markdown)
79
190
  */
80
191
  async createDoc(id, content, metadata, format) {
81
192
  const docFormat = format || this.defaultFormat;
82
193
  const docPath = this.getDocPath(id, docFormat);
83
- const metaPath = this.getMetadataPath(id);
194
+ const effectiveMode = this.getEffectiveMetadataMode(docFormat);
84
195
  // Add timestamps
85
196
  const fullMetadata = {
86
197
  ...metadata,
87
198
  createdAt: metadata.createdAt || new Date(),
88
199
  updatedAt: new Date(),
89
200
  };
90
- // Write content
91
- fs.writeFileSync(docPath, content, 'utf-8');
92
- // Write metadata
93
- fs.writeFileSync(metaPath, yaml.dump(fullMetadata), 'utf-8');
201
+ // Extract body content in case content already has frontmatter
202
+ const bodyContent = this.extractBody(content);
203
+ if (effectiveMode === 'frontmatter') {
204
+ // Write content with embedded frontmatter
205
+ const fullContent = this.writeFrontmatter(fullMetadata, bodyContent);
206
+ fs.writeFileSync(docPath, fullContent, 'utf-8');
207
+ }
208
+ else {
209
+ // Sidecar mode: separate content and metadata files
210
+ const metaPath = this.getMetadataPath(id);
211
+ fs.writeFileSync(docPath, bodyContent, 'utf-8');
212
+ fs.writeFileSync(metaPath, yaml.dump(fullMetadata), 'utf-8');
213
+ }
94
214
  return {
95
215
  id,
96
- content,
216
+ content: bodyContent,
97
217
  format: docFormat,
98
218
  metadata: fullMetadata,
99
219
  path: docPath,
@@ -101,6 +221,7 @@ class DocsManager {
101
221
  }
102
222
  /**
103
223
  * Get a document by ID
224
+ * Supports both frontmatter and sidecar metadata modes
104
225
  */
105
226
  async getDoc(id) {
106
227
  // Try to find the doc with any format
@@ -108,12 +229,24 @@ class DocsManager {
108
229
  for (const format of formats) {
109
230
  const docPath = this.getDocPath(id, format);
110
231
  if (fs.existsSync(docPath)) {
111
- const content = fs.readFileSync(docPath, 'utf-8');
112
- const metaPath = this.getMetadataPath(id);
232
+ const rawContent = fs.readFileSync(docPath, 'utf-8');
233
+ const effectiveMode = this.getEffectiveMetadataMode(format);
113
234
  let metadata = { title: id };
114
- if (fs.existsSync(metaPath)) {
115
- const metaContent = fs.readFileSync(metaPath, 'utf-8');
116
- metadata = yaml.load(metaContent);
235
+ let content;
236
+ if (effectiveMode === 'frontmatter') {
237
+ // Parse frontmatter from content
238
+ const result = this.parseFrontmatter(rawContent);
239
+ metadata = result.metadata.title ? result.metadata : { ...metadata, ...result.metadata };
240
+ content = result.body;
241
+ }
242
+ else {
243
+ // Sidecar mode: check for .meta.yaml file
244
+ content = rawContent;
245
+ const metaPath = this.getMetadataPath(id);
246
+ if (fs.existsSync(metaPath)) {
247
+ const metaContent = fs.readFileSync(metaPath, 'utf-8');
248
+ metadata = yaml.load(metaContent);
249
+ }
117
250
  }
118
251
  return {
119
252
  id,
@@ -128,6 +261,9 @@ class DocsManager {
128
261
  }
129
262
  /**
130
263
  * Update a document
264
+ * @param id - Document identifier
265
+ * @param content - New body content (without frontmatter)
266
+ * @param metadata - Metadata fields to update (merged with existing)
131
267
  */
132
268
  async updateDoc(id, content, metadata) {
133
269
  const existingDoc = await this.getDoc(id);
@@ -140,12 +276,23 @@ class DocsManager {
140
276
  updatedAt: new Date(),
141
277
  };
142
278
  const docPath = this.getDocPath(id, existingDoc.format);
143
- const metaPath = this.getMetadataPath(id);
144
- fs.writeFileSync(docPath, content, 'utf-8');
145
- fs.writeFileSync(metaPath, yaml.dump(updatedMetadata), 'utf-8');
279
+ const effectiveMode = this.getEffectiveMetadataMode(existingDoc.format);
280
+ // Extract body content in case content already has frontmatter
281
+ const bodyContent = this.extractBody(content);
282
+ if (effectiveMode === 'frontmatter') {
283
+ // Write content with embedded frontmatter
284
+ const fullContent = this.writeFrontmatter(updatedMetadata, bodyContent);
285
+ fs.writeFileSync(docPath, fullContent, 'utf-8');
286
+ }
287
+ else {
288
+ // Sidecar mode: separate content and metadata files
289
+ const metaPath = this.getMetadataPath(id);
290
+ fs.writeFileSync(docPath, bodyContent, 'utf-8');
291
+ fs.writeFileSync(metaPath, yaml.dump(updatedMetadata), 'utf-8');
292
+ }
146
293
  return {
147
294
  id,
148
- content,
295
+ content: bodyContent,
149
296
  format: existingDoc.format,
150
297
  metadata: updatedMetadata,
151
298
  path: docPath,
@@ -153,6 +300,7 @@ class DocsManager {
153
300
  }
154
301
  /**
155
302
  * Delete a document
303
+ * Removes both the document file and any sidecar metadata file if it exists
156
304
  */
157
305
  async deleteDoc(id) {
158
306
  const doc = await this.getDoc(id);
@@ -164,6 +312,7 @@ class DocsManager {
164
312
  if (fs.existsSync(docPath)) {
165
313
  fs.unlinkSync(docPath);
166
314
  }
315
+ // Also delete sidecar metadata file if it exists (for backward compatibility)
167
316
  if (fs.existsSync(metaPath)) {
168
317
  fs.unlinkSync(metaPath);
169
318
  }
@@ -216,6 +365,10 @@ class DocsManager {
216
365
  if (query.author) {
217
366
  results = results.filter((doc) => doc.metadata.authors?.includes(query.author));
218
367
  }
368
+ // Filter by docType
369
+ if (query.docType) {
370
+ results = results.filter((doc) => doc.metadata.docType === query.docType);
371
+ }
219
372
  // Filter by date range
220
373
  if (query.dateRange) {
221
374
  results = results.filter((doc) => {