@context-forge/core 0.1.1 → 0.3.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 (158) hide show
  1. package/README.md +12 -1
  2. package/dist/config/ConfigKeys.d.ts +9 -0
  3. package/dist/config/ConfigKeys.d.ts.map +1 -0
  4. package/dist/config/ConfigKeys.js +24 -0
  5. package/dist/config/ConfigKeys.js.map +1 -0
  6. package/dist/config/ConfigManager.d.ts +18 -0
  7. package/dist/config/ConfigManager.d.ts.map +1 -0
  8. package/dist/config/ConfigManager.js +129 -0
  9. package/dist/config/ConfigManager.js.map +1 -0
  10. package/dist/config/configPaths.d.ts +5 -0
  11. package/dist/config/configPaths.d.ts.map +1 -0
  12. package/dist/config/configPaths.js +11 -0
  13. package/dist/config/configPaths.js.map +1 -0
  14. package/dist/config/index.d.ts +4 -0
  15. package/dist/config/index.d.ts.map +1 -0
  16. package/dist/config/index.js +4 -0
  17. package/dist/config/index.js.map +1 -0
  18. package/dist/guides/GuideDetector.d.ts +20 -0
  19. package/dist/guides/GuideDetector.d.ts.map +1 -0
  20. package/dist/guides/GuideDetector.js +142 -0
  21. package/dist/guides/GuideDetector.js.map +1 -0
  22. package/dist/guides/GuideManager.d.ts +21 -0
  23. package/dist/guides/GuideManager.d.ts.map +1 -0
  24. package/dist/guides/GuideManager.js +88 -0
  25. package/dist/guides/GuideManager.js.map +1 -0
  26. package/dist/guides/gitExec.d.ts +15 -0
  27. package/dist/guides/gitExec.d.ts.map +1 -0
  28. package/dist/guides/gitExec.js +39 -0
  29. package/dist/guides/gitExec.js.map +1 -0
  30. package/dist/guides/index.d.ts +4 -0
  31. package/dist/guides/index.d.ts.map +1 -0
  32. package/dist/guides/index.js +5 -0
  33. package/dist/guides/index.js.map +1 -0
  34. package/dist/guides/strategies/CloneStrategy.d.ts +7 -0
  35. package/dist/guides/strategies/CloneStrategy.d.ts.map +1 -0
  36. package/dist/guides/strategies/CloneStrategy.js +80 -0
  37. package/dist/guides/strategies/CloneStrategy.js.map +1 -0
  38. package/dist/guides/strategies/SubmoduleStrategy.d.ts +7 -0
  39. package/dist/guides/strategies/SubmoduleStrategy.d.ts.map +1 -0
  40. package/dist/guides/strategies/SubmoduleStrategy.js +74 -0
  41. package/dist/guides/strategies/SubmoduleStrategy.js.map +1 -0
  42. package/dist/guides/strategies/TarballStrategy.d.ts +19 -0
  43. package/dist/guides/strategies/TarballStrategy.d.ts.map +1 -0
  44. package/dist/guides/strategies/TarballStrategy.js +118 -0
  45. package/dist/guides/strategies/TarballStrategy.js.map +1 -0
  46. package/dist/guides/types.d.ts +44 -0
  47. package/dist/guides/types.d.ts.map +1 -0
  48. package/dist/guides/types.js +7 -0
  49. package/dist/guides/types.js.map +1 -0
  50. package/dist/index.d.ts +3 -0
  51. package/dist/index.d.ts.map +1 -1
  52. package/dist/index.js +4 -0
  53. package/dist/index.js.map +1 -1
  54. package/dist/introspection/ArtifactIntrospector.d.ts +20 -0
  55. package/dist/introspection/ArtifactIntrospector.d.ts.map +1 -0
  56. package/dist/introspection/ArtifactIntrospector.js +140 -0
  57. package/dist/introspection/ArtifactIntrospector.js.map +1 -0
  58. package/dist/introspection/FutureWorkCollector.d.ts +7 -0
  59. package/dist/introspection/FutureWorkCollector.d.ts.map +1 -0
  60. package/dist/introspection/FutureWorkCollector.js +116 -0
  61. package/dist/introspection/FutureWorkCollector.js.map +1 -0
  62. package/dist/introspection/ProjectModelBuilder.d.ts +32 -0
  63. package/dist/introspection/ProjectModelBuilder.d.ts.map +1 -0
  64. package/dist/introspection/ProjectModelBuilder.js +321 -0
  65. package/dist/introspection/ProjectModelBuilder.js.map +1 -0
  66. package/dist/introspection/index.d.ts +4 -0
  67. package/dist/introspection/index.d.ts.map +1 -0
  68. package/dist/introspection/index.js +5 -0
  69. package/dist/introspection/index.js.map +1 -0
  70. package/dist/introspection/interfaces.d.ts +18 -0
  71. package/dist/introspection/interfaces.d.ts.map +1 -0
  72. package/dist/introspection/interfaces.js +2 -0
  73. package/dist/introspection/interfaces.js.map +1 -0
  74. package/dist/introspection/parsers/documentDetector.d.ts +12 -0
  75. package/dist/introspection/parsers/documentDetector.d.ts.map +1 -0
  76. package/dist/introspection/parsers/documentDetector.js +66 -0
  77. package/dist/introspection/parsers/documentDetector.js.map +1 -0
  78. package/dist/introspection/parsers/frontmatterParser.d.ts +8 -0
  79. package/dist/introspection/parsers/frontmatterParser.d.ts.map +1 -0
  80. package/dist/introspection/parsers/frontmatterParser.js +43 -0
  81. package/dist/introspection/parsers/frontmatterParser.js.map +1 -0
  82. package/dist/introspection/parsers/futureWorkParser.d.ts +8 -0
  83. package/dist/introspection/parsers/futureWorkParser.d.ts.map +1 -0
  84. package/dist/introspection/parsers/futureWorkParser.js +75 -0
  85. package/dist/introspection/parsers/futureWorkParser.js.map +1 -0
  86. package/dist/introspection/parsers/slicePlanParser.d.ts +8 -0
  87. package/dist/introspection/parsers/slicePlanParser.d.ts.map +1 -0
  88. package/dist/introspection/parsers/slicePlanParser.js +51 -0
  89. package/dist/introspection/parsers/slicePlanParser.js.map +1 -0
  90. package/dist/introspection/parsers/statusNormalizer.d.ts +4 -0
  91. package/dist/introspection/parsers/statusNormalizer.d.ts.map +1 -0
  92. package/dist/introspection/parsers/statusNormalizer.js +23 -0
  93. package/dist/introspection/parsers/statusNormalizer.js.map +1 -0
  94. package/dist/introspection/parsers/taskFileParser.d.ts +13 -0
  95. package/dist/introspection/parsers/taskFileParser.d.ts.map +1 -0
  96. package/dist/introspection/parsers/taskFileParser.js +66 -0
  97. package/dist/introspection/parsers/taskFileParser.js.map +1 -0
  98. package/dist/introspection/types.d.ts +178 -0
  99. package/dist/introspection/types.d.ts.map +1 -0
  100. package/dist/introspection/types.js +2 -0
  101. package/dist/introspection/types.js.map +1 -0
  102. package/dist/node.d.ts +11 -0
  103. package/dist/node.d.ts.map +1 -1
  104. package/dist/node.js +15 -0
  105. package/dist/node.js.map +1 -1
  106. package/dist/schema/projectSchema.d.ts +54 -0
  107. package/dist/schema/projectSchema.d.ts.map +1 -0
  108. package/dist/schema/projectSchema.js +131 -0
  109. package/dist/schema/projectSchema.js.map +1 -0
  110. package/dist/schema/resolveFileByIndex.d.ts +11 -0
  111. package/dist/schema/resolveFileByIndex.d.ts.map +1 -0
  112. package/dist/schema/resolveFileByIndex.js +53 -0
  113. package/dist/schema/resolveFileByIndex.js.map +1 -0
  114. package/dist/services/ContextGenerator.d.ts.map +1 -1
  115. package/dist/services/ContextGenerator.js +3 -5
  116. package/dist/services/ContextGenerator.js.map +1 -1
  117. package/dist/services/ContextIntegrator.d.ts.map +1 -1
  118. package/dist/services/ContextIntegrator.js +10 -14
  119. package/dist/services/ContextIntegrator.js.map +1 -1
  120. package/dist/services/ContextTemplateEngine.d.ts.map +1 -1
  121. package/dist/services/ContextTemplateEngine.js +8 -21
  122. package/dist/services/ContextTemplateEngine.js.map +1 -1
  123. package/dist/services/CoreServiceFactory.d.ts +3 -0
  124. package/dist/services/CoreServiceFactory.d.ts.map +1 -1
  125. package/dist/services/CoreServiceFactory.js +19 -1
  126. package/dist/services/CoreServiceFactory.js.map +1 -1
  127. package/dist/services/ProjectPathService.d.ts +1 -1
  128. package/dist/services/ProjectPathService.d.ts.map +1 -1
  129. package/dist/services/ProjectPathService.js +2 -4
  130. package/dist/services/ProjectPathService.js.map +1 -1
  131. package/dist/services/SectionBuilder.d.ts +0 -4
  132. package/dist/services/SectionBuilder.d.ts.map +1 -1
  133. package/dist/services/SectionBuilder.js +8 -35
  134. package/dist/services/SectionBuilder.js.map +1 -1
  135. package/dist/services/SystemPromptParser.d.ts +1 -2
  136. package/dist/services/SystemPromptParser.d.ts.map +1 -1
  137. package/dist/services/SystemPromptParser.js +3 -14
  138. package/dist/services/SystemPromptParser.js.map +1 -1
  139. package/dist/services/TemplateProcessor.d.ts.map +1 -1
  140. package/dist/services/TemplateProcessor.js +12 -11
  141. package/dist/services/TemplateProcessor.js.map +1 -1
  142. package/dist/services/constants.d.ts.map +1 -1
  143. package/dist/services/constants.js +0 -6
  144. package/dist/services/constants.js.map +1 -1
  145. package/dist/services/interfaces.d.ts +1 -1
  146. package/dist/services/interfaces.d.ts.map +1 -1
  147. package/dist/storage/FileProjectStore.d.ts.map +1 -1
  148. package/dist/storage/FileProjectStore.js +25 -8
  149. package/dist/storage/FileProjectStore.js.map +1 -1
  150. package/dist/types/context.d.ts +4 -6
  151. package/dist/types/context.d.ts.map +1 -1
  152. package/dist/types/project.d.ts +15 -11
  153. package/dist/types/project.d.ts.map +1 -1
  154. package/dist/types/sections.d.ts +0 -1
  155. package/dist/types/sections.d.ts.map +1 -1
  156. package/dist/types/sections.js +0 -1
  157. package/dist/types/sections.js.map +1 -1
  158. package/package.json +5 -2
package/README.md CHANGED
@@ -8,7 +8,7 @@ This package contains the core logic shared by both the [MCP server](../mcp-serv
8
8
 
9
9
  Key capabilities:
10
10
  - **Context pipeline** — assembles structured context prompts from project configuration, templates, and statements
11
- - **Template processing** — variable substitution (`{{projectName}}`, `{{slice}}`, etc.) with conditional sections
11
+ - **Template processing** — variable substitution (`{{projectName}}`, `{{fileSlice}}`, etc.) with conditional sections
12
12
  - **Statement management** — loads and resolves default statements (start/continue, tool intro, instruction blocks)
13
13
  - **Prompt parsing** — reads `prompt.ai-project.system.md` files and extracts named template sections
14
14
  - **Project storage** — filesystem-backed CRUD for project configuration with backup and migration support
@@ -37,6 +37,14 @@ import { createContextPipeline } from '@context-forge/core/node';
37
37
  import { StatementManager, SystemPromptParser } from '@context-forge/core/node';
38
38
  import { ProjectPathService } from '@context-forge/core/node';
39
39
  import { getStoragePath } from '@context-forge/core/node';
40
+
41
+ // Artifact introspection
42
+ import { ArtifactIntrospector } from '@context-forge/core/node';
43
+ import { buildModel, scanDirectory } from '@context-forge/core/node';
44
+ import { parseFrontmatter, parseSlicePlan } from '@context-forge/core/node';
45
+ import { parseTaskItems, parseTaskFile } from '@context-forge/core/node';
46
+ import { parseFutureWork, detectDocuments } from '@context-forge/core/node';
47
+ import { FutureWorkCollector } from '@context-forge/core/node';
40
48
  ```
41
49
 
42
50
  This entry point includes filesystem-dependent services. Use it in main processes, CLI tools, MCP servers, and tests. Do not import from browser/renderer code.
@@ -53,6 +61,9 @@ This entry point includes filesystem-dependent services. Use it in main processe
53
61
  | `ContextIntegrator` | `.` | Orchestrates full context generation from a `ProjectData` object |
54
62
  | `TemplateProcessor` | `.` | Handles `{{variable}}` substitution in template strings |
55
63
  | `SectionBuilder` | `.` | Assembles individual context sections (statements, instructions, tools) |
64
+ | `ArtifactIntrospector` | `./node` | Parses methodology documents: slice plans, task files, frontmatter, future work, document detection |
65
+ | `buildModel` | `./node` | Builds a full `ProjectModel` from a project root path — foundation, initiatives, slices, tasks, future work |
66
+ | `FutureWorkCollector` | `./node` | Aggregates future work items across all slice plans; groups by initiative; supports status filtering |
56
67
 
57
68
  ## Usage in the Monorepo
58
69
 
@@ -0,0 +1,9 @@
1
+ export interface ConfigKeyDefinition {
2
+ type: 'string' | 'boolean' | 'number';
3
+ default: string | boolean | number;
4
+ description: string;
5
+ enum?: string[];
6
+ validate?: (value: string | boolean | number) => string | null;
7
+ }
8
+ export declare const CONFIG_KEYS: Record<string, ConfigKeyDefinition>;
9
+ //# sourceMappingURL=ConfigKeys.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ConfigKeys.d.ts","sourceRoot":"","sources":["../../src/config/ConfigKeys.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,mBAAmB;IAClC,IAAI,EAAE,QAAQ,GAAG,SAAS,GAAG,QAAQ,CAAC;IACtC,OAAO,EAAE,MAAM,GAAG,OAAO,GAAG,MAAM,CAAC;IACnC,WAAW,EAAE,MAAM,CAAC;IACpB,IAAI,CAAC,EAAE,MAAM,EAAE,CAAC;IAChB,QAAQ,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,GAAG,MAAM,KAAK,MAAM,GAAG,IAAI,CAAC;CAChE;AAED,eAAO,MAAM,WAAW,EAAE,MAAM,CAAC,MAAM,EAAE,mBAAmB,CAsB3D,CAAC"}
@@ -0,0 +1,24 @@
1
+ export const CONFIG_KEYS = {
2
+ default_project: {
3
+ type: 'string',
4
+ default: '',
5
+ description: 'Default project ID used when projectId is not provided to MCP tools',
6
+ },
7
+ 'guide.auto_update': {
8
+ type: 'boolean',
9
+ default: false,
10
+ description: 'Whether to automatically update the AI project guide',
11
+ },
12
+ 'guide.source': {
13
+ type: 'string',
14
+ default: '',
15
+ description: 'URL or path to the AI project guide source',
16
+ },
17
+ 'guide.git_strategy': {
18
+ type: 'string',
19
+ default: 'submodule',
20
+ description: 'Strategy for managing the AI project guide via git',
21
+ enum: ['submodule', 'clone', 'manual'],
22
+ },
23
+ };
24
+ //# sourceMappingURL=ConfigKeys.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ConfigKeys.js","sourceRoot":"","sources":["../../src/config/ConfigKeys.ts"],"names":[],"mappings":"AAQA,MAAM,CAAC,MAAM,WAAW,GAAwC;IAC9D,eAAe,EAAE;QACf,IAAI,EAAE,QAAQ;QACd,OAAO,EAAE,EAAE;QACX,WAAW,EAAE,qEAAqE;KACnF;IACD,mBAAmB,EAAE;QACnB,IAAI,EAAE,SAAS;QACf,OAAO,EAAE,KAAK;QACd,WAAW,EAAE,sDAAsD;KACpE;IACD,cAAc,EAAE;QACd,IAAI,EAAE,QAAQ;QACd,OAAO,EAAE,EAAE;QACX,WAAW,EAAE,4CAA4C;KAC1D;IACD,oBAAoB,EAAE;QACpB,IAAI,EAAE,QAAQ;QACd,OAAO,EAAE,WAAW;QACpB,WAAW,EAAE,oDAAoD;QACjE,IAAI,EAAE,CAAC,WAAW,EAAE,OAAO,EAAE,QAAQ,CAAC;KACvC;CACF,CAAC"}
@@ -0,0 +1,18 @@
1
+ export interface ConfigResult {
2
+ key: string;
3
+ value: string | boolean | number;
4
+ source: 'project' | 'user' | 'default';
5
+ description: string;
6
+ }
7
+ export interface ConfigListEntry extends ConfigResult {
8
+ type: 'string' | 'boolean' | 'number';
9
+ defaultValue: string | boolean | number;
10
+ }
11
+ export declare class ConfigManager {
12
+ private readonly projectPath;
13
+ constructor(projectPath?: string);
14
+ get(key: string): Promise<ConfigResult>;
15
+ set(key: string, value: string | boolean | number, scope: 'user' | 'project'): Promise<void>;
16
+ list(): Promise<ConfigListEntry[]>;
17
+ }
18
+ //# sourceMappingURL=ConfigManager.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ConfigManager.d.ts","sourceRoot":"","sources":["../../src/config/ConfigManager.ts"],"names":[],"mappings":"AAMA,MAAM,WAAW,YAAY;IAC3B,GAAG,EAAE,MAAM,CAAC;IACZ,KAAK,EAAE,MAAM,GAAG,OAAO,GAAG,MAAM,CAAC;IACjC,MAAM,EAAE,SAAS,GAAG,MAAM,GAAG,SAAS,CAAC;IACvC,WAAW,EAAE,MAAM,CAAC;CACrB;AAED,MAAM,WAAW,eAAgB,SAAQ,YAAY;IACnD,IAAI,EAAE,QAAQ,GAAG,SAAS,GAAG,QAAQ,CAAC;IACtC,YAAY,EAAE,MAAM,GAAG,OAAO,GAAG,MAAM,CAAC;CACzC;AAmED,qBAAa,aAAa;IACxB,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAqB;gBAErC,WAAW,CAAC,EAAE,MAAM;IAI1B,GAAG,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,YAAY,CAAC;IAyCvC,GAAG,CACP,GAAG,EAAE,MAAM,EACX,KAAK,EAAE,MAAM,GAAG,OAAO,GAAG,MAAM,EAChC,KAAK,EAAE,MAAM,GAAG,SAAS,GACxB,OAAO,CAAC,IAAI,CAAC;IAqBV,IAAI,IAAI,OAAO,CAAC,eAAe,EAAE,CAAC;CAYzC"}
@@ -0,0 +1,129 @@
1
+ import { readFile, writeFile, mkdir } from 'fs/promises';
2
+ import { dirname } from 'path';
3
+ import { parse, stringify } from 'smol-toml';
4
+ import { CONFIG_KEYS } from './ConfigKeys.js';
5
+ import { getUserConfigPath, getProjectConfigPath } from './configPaths.js';
6
+ async function readToml(filePath) {
7
+ try {
8
+ const content = await readFile(filePath, 'utf-8');
9
+ return parse(content);
10
+ }
11
+ catch (err) {
12
+ if (err.code === 'ENOENT') {
13
+ return {};
14
+ }
15
+ throw err;
16
+ }
17
+ }
18
+ async function writeToml(filePath, data) {
19
+ await mkdir(dirname(filePath), { recursive: true });
20
+ await writeFile(filePath, stringify(data), 'utf-8');
21
+ }
22
+ function resolveKey(obj, key) {
23
+ const parts = key.split('.');
24
+ let current = obj;
25
+ for (const part of parts) {
26
+ if (current === null || typeof current !== 'object')
27
+ return undefined;
28
+ current = current[part];
29
+ }
30
+ return current;
31
+ }
32
+ function setKey(obj, key, value) {
33
+ const parts = key.split('.');
34
+ let current = obj;
35
+ for (let i = 0; i < parts.length - 1; i++) {
36
+ const part = parts[i];
37
+ if (!(part in current) || typeof current[part] !== 'object' || current[part] === null) {
38
+ current[part] = {};
39
+ }
40
+ current = current[part];
41
+ }
42
+ current[parts[parts.length - 1]] = value;
43
+ }
44
+ function validateValue(key, value, def) {
45
+ if (typeof value !== def.type) {
46
+ throw new Error(`Config key "${key}" expects type "${def.type}", got "${typeof value}"`);
47
+ }
48
+ if (def.enum && typeof value === 'string' && !def.enum.includes(value)) {
49
+ throw new Error(`Config key "${key}" must be one of [${def.enum.map((v) => `"${v}"`).join(', ')}], got "${value}"`);
50
+ }
51
+ if (def.validate) {
52
+ const error = def.validate(value);
53
+ if (error !== null) {
54
+ throw new Error(`Config key "${key}" validation failed: ${error}`);
55
+ }
56
+ }
57
+ }
58
+ export class ConfigManager {
59
+ projectPath;
60
+ constructor(projectPath) {
61
+ this.projectPath = projectPath;
62
+ }
63
+ async get(key) {
64
+ const def = CONFIG_KEYS[key];
65
+ if (!def) {
66
+ throw new Error(`Unknown config key: "${key}"`);
67
+ }
68
+ // Check project config first
69
+ if (this.projectPath) {
70
+ const projectConfig = await readToml(getProjectConfigPath(this.projectPath));
71
+ const projectValue = resolveKey(projectConfig, key);
72
+ if (projectValue !== undefined) {
73
+ return {
74
+ key,
75
+ value: projectValue,
76
+ source: 'project',
77
+ description: def.description,
78
+ };
79
+ }
80
+ }
81
+ // Then user config
82
+ const userConfig = await readToml(getUserConfigPath());
83
+ const userValue = resolveKey(userConfig, key);
84
+ if (userValue !== undefined) {
85
+ return {
86
+ key,
87
+ value: userValue,
88
+ source: 'user',
89
+ description: def.description,
90
+ };
91
+ }
92
+ // Fall back to built-in default
93
+ return {
94
+ key,
95
+ value: def.default,
96
+ source: 'default',
97
+ description: def.description,
98
+ };
99
+ }
100
+ async set(key, value, scope) {
101
+ const def = CONFIG_KEYS[key];
102
+ if (!def) {
103
+ throw new Error(`Unknown config key: "${key}"`);
104
+ }
105
+ if (scope === 'project' && !this.projectPath) {
106
+ throw new Error(`Cannot set project-scoped config: no projectPath provided`);
107
+ }
108
+ validateValue(key, value, def);
109
+ const filePath = scope === 'project'
110
+ ? getProjectConfigPath(this.projectPath)
111
+ : getUserConfigPath();
112
+ const existing = await readToml(filePath);
113
+ setKey(existing, key, value);
114
+ await writeToml(filePath, existing);
115
+ }
116
+ async list() {
117
+ const results = [];
118
+ for (const [key, def] of Object.entries(CONFIG_KEYS)) {
119
+ const result = await this.get(key);
120
+ results.push({
121
+ ...result,
122
+ type: def.type,
123
+ defaultValue: def.default,
124
+ });
125
+ }
126
+ return results;
127
+ }
128
+ }
129
+ //# sourceMappingURL=ConfigManager.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ConfigManager.js","sourceRoot":"","sources":["../../src/config/ConfigManager.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,SAAS,EAAE,KAAK,EAAE,MAAM,aAAa,CAAC;AACzD,OAAO,EAAE,OAAO,EAAE,MAAM,MAAM,CAAC;AAC/B,OAAO,EAAE,KAAK,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC;AAC7C,OAAO,EAAE,WAAW,EAA4B,MAAM,iBAAiB,CAAC;AACxE,OAAO,EAAE,iBAAiB,EAAE,oBAAoB,EAAE,MAAM,kBAAkB,CAAC;AAgB3E,KAAK,UAAU,QAAQ,CAAC,QAAgB;IACtC,IAAI,CAAC;QACH,MAAM,OAAO,GAAG,MAAM,QAAQ,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC;QAClD,OAAO,KAAK,CAAC,OAAO,CAAe,CAAC;IACtC,CAAC;IAAC,OAAO,GAAY,EAAE,CAAC;QACtB,IAAK,GAA6B,CAAC,IAAI,KAAK,QAAQ,EAAE,CAAC;YACrD,OAAO,EAAE,CAAC;QACZ,CAAC;QACD,MAAM,GAAG,CAAC;IACZ,CAAC;AACH,CAAC;AAED,KAAK,UAAU,SAAS,CAAC,QAAgB,EAAE,IAAgB;IACzD,MAAM,KAAK,CAAC,OAAO,CAAC,QAAQ,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IACpD,MAAM,SAAS,CAAC,QAAQ,EAAE,SAAS,CAAC,IAAuC,CAAC,EAAE,OAAO,CAAC,CAAC;AACzF,CAAC;AAED,SAAS,UAAU,CAAC,GAAe,EAAE,GAAW;IAC9C,MAAM,KAAK,GAAG,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;IAC7B,IAAI,OAAO,GAAY,GAAG,CAAC;IAC3B,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACzB,IAAI,OAAO,KAAK,IAAI,IAAI,OAAO,OAAO,KAAK,QAAQ;YAAE,OAAO,SAAS,CAAC;QACtE,OAAO,GAAI,OAAsB,CAAC,IAAI,CAAC,CAAC;IAC1C,CAAC;IACD,OAAO,OAAO,CAAC;AACjB,CAAC;AAED,SAAS,MAAM,CAAC,GAAe,EAAE,GAAW,EAAE,KAAc;IAC1D,MAAM,KAAK,GAAG,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;IAC7B,IAAI,OAAO,GAAe,GAAG,CAAC;IAC9B,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,KAAK,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC;QAC1C,MAAM,IAAI,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC;QACtB,IAAI,CAAC,CAAC,IAAI,IAAI,OAAO,CAAC,IAAI,OAAO,OAAO,CAAC,IAAI,CAAC,KAAK,QAAQ,IAAI,OAAO,CAAC,IAAI,CAAC,KAAK,IAAI,EAAE,CAAC;YACtF,OAAO,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC;QACrB,CAAC;QACD,OAAO,GAAG,OAAO,CAAC,IAAI,CAAe,CAAC;IACxC,CAAC;IACD,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,GAAG,KAAK,CAAC;AAC3C,CAAC;AAED,SAAS,aAAa,CACpB,GAAW,EACX,KAAgC,EAChC,GAAwB;IAExB,IAAI,OAAO,KAAK,KAAK,GAAG,CAAC,IAAI,EAAE,CAAC;QAC9B,MAAM,IAAI,KAAK,CACb,eAAe,GAAG,mBAAmB,GAAG,CAAC,IAAI,WAAW,OAAO,KAAK,GAAG,CACxE,CAAC;IACJ,CAAC;IACD,IAAI,GAAG,CAAC,IAAI,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,QAAQ,CAAC,KAAK,CAAC,EAAE,CAAC;QACvE,MAAM,IAAI,KAAK,CACb,eAAe,GAAG,qBAAqB,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,WAAW,KAAK,GAAG,CACnG,CAAC;IACJ,CAAC;IACD,IAAI,GAAG,CAAC,QAAQ,EAAE,CAAC;QACjB,MAAM,KAAK,GAAG,GAAG,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC;QAClC,IAAI,KAAK,KAAK,IAAI,EAAE,CAAC;YACnB,MAAM,IAAI,KAAK,CAAC,eAAe,GAAG,wBAAwB,KAAK,EAAE,CAAC,CAAC;QACrE,CAAC;IACH,CAAC;AACH,CAAC;AAED,MAAM,OAAO,aAAa;IACP,WAAW,CAAqB;IAEjD,YAAY,WAAoB;QAC9B,IAAI,CAAC,WAAW,GAAG,WAAW,CAAC;IACjC,CAAC;IAED,KAAK,CAAC,GAAG,CAAC,GAAW;QACnB,MAAM,GAAG,GAAG,WAAW,CAAC,GAAG,CAAC,CAAC;QAC7B,IAAI,CAAC,GAAG,EAAE,CAAC;YACT,MAAM,IAAI,KAAK,CAAC,wBAAwB,GAAG,GAAG,CAAC,CAAC;QAClD,CAAC;QAED,6BAA6B;QAC7B,IAAI,IAAI,CAAC,WAAW,EAAE,CAAC;YACrB,MAAM,aAAa,GAAG,MAAM,QAAQ,CAAC,oBAAoB,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC,CAAC;YAC7E,MAAM,YAAY,GAAG,UAAU,CAAC,aAAa,EAAE,GAAG,CAAC,CAAC;YACpD,IAAI,YAAY,KAAK,SAAS,EAAE,CAAC;gBAC/B,OAAO;oBACL,GAAG;oBACH,KAAK,EAAE,YAAyC;oBAChD,MAAM,EAAE,SAAS;oBACjB,WAAW,EAAE,GAAG,CAAC,WAAW;iBAC7B,CAAC;YACJ,CAAC;QACH,CAAC;QAED,mBAAmB;QACnB,MAAM,UAAU,GAAG,MAAM,QAAQ,CAAC,iBAAiB,EAAE,CAAC,CAAC;QACvD,MAAM,SAAS,GAAG,UAAU,CAAC,UAAU,EAAE,GAAG,CAAC,CAAC;QAC9C,IAAI,SAAS,KAAK,SAAS,EAAE,CAAC;YAC5B,OAAO;gBACL,GAAG;gBACH,KAAK,EAAE,SAAsC;gBAC7C,MAAM,EAAE,MAAM;gBACd,WAAW,EAAE,GAAG,CAAC,WAAW;aAC7B,CAAC;QACJ,CAAC;QAED,gCAAgC;QAChC,OAAO;YACL,GAAG;YACH,KAAK,EAAE,GAAG,CAAC,OAAO;YAClB,MAAM,EAAE,SAAS;YACjB,WAAW,EAAE,GAAG,CAAC,WAAW;SAC7B,CAAC;IACJ,CAAC;IAED,KAAK,CAAC,GAAG,CACP,GAAW,EACX,KAAgC,EAChC,KAAyB;QAEzB,MAAM,GAAG,GAAG,WAAW,CAAC,GAAG,CAAC,CAAC;QAC7B,IAAI,CAAC,GAAG,EAAE,CAAC;YACT,MAAM,IAAI,KAAK,CAAC,wBAAwB,GAAG,GAAG,CAAC,CAAC;QAClD,CAAC;QACD,IAAI,KAAK,KAAK,SAAS,IAAI,CAAC,IAAI,CAAC,WAAW,EAAE,CAAC;YAC7C,MAAM,IAAI,KAAK,CAAC,2DAA2D,CAAC,CAAC;QAC/E,CAAC;QAED,aAAa,CAAC,GAAG,EAAE,KAAK,EAAE,GAAG,CAAC,CAAC;QAE/B,MAAM,QAAQ,GACZ,KAAK,KAAK,SAAS;YACjB,CAAC,CAAC,oBAAoB,CAAC,IAAI,CAAC,WAAY,CAAC;YACzC,CAAC,CAAC,iBAAiB,EAAE,CAAC;QAE1B,MAAM,QAAQ,GAAG,MAAM,QAAQ,CAAC,QAAQ,CAAC,CAAC;QAC1C,MAAM,CAAC,QAAQ,EAAE,GAAG,EAAE,KAAK,CAAC,CAAC;QAC7B,MAAM,SAAS,CAAC,QAAQ,EAAE,QAAQ,CAAC,CAAC;IACtC,CAAC;IAED,KAAK,CAAC,IAAI;QACR,MAAM,OAAO,GAAsB,EAAE,CAAC;QACtC,KAAK,MAAM,CAAC,GAAG,EAAE,GAAG,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,WAAW,CAAC,EAAE,CAAC;YACrD,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;YACnC,OAAO,CAAC,IAAI,CAAC;gBACX,GAAG,MAAM;gBACT,IAAI,EAAE,GAAG,CAAC,IAAI;gBACd,YAAY,EAAE,GAAG,CAAC,OAAO;aAC1B,CAAC,CAAC;QACL,CAAC;QACD,OAAO,OAAO,CAAC;IACjB,CAAC;CACF"}
@@ -0,0 +1,5 @@
1
+ /** Returns the user-level config file path: {storagePath}/config.toml */
2
+ export declare function getUserConfigPath(): string;
3
+ /** Returns the project-level config file path: {projectPath}/.context-forge.toml */
4
+ export declare function getProjectConfigPath(projectPath: string): string;
5
+ //# sourceMappingURL=configPaths.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"configPaths.d.ts","sourceRoot":"","sources":["../../src/config/configPaths.ts"],"names":[],"mappings":"AAGA,yEAAyE;AACzE,wBAAgB,iBAAiB,IAAI,MAAM,CAE1C;AAED,oFAAoF;AACpF,wBAAgB,oBAAoB,CAAC,WAAW,EAAE,MAAM,GAAG,MAAM,CAEhE"}
@@ -0,0 +1,11 @@
1
+ import { join } from 'path';
2
+ import { getStoragePath } from '../storage/storagePaths.js';
3
+ /** Returns the user-level config file path: {storagePath}/config.toml */
4
+ export function getUserConfigPath() {
5
+ return join(getStoragePath(), 'config.toml');
6
+ }
7
+ /** Returns the project-level config file path: {projectPath}/.context-forge.toml */
8
+ export function getProjectConfigPath(projectPath) {
9
+ return join(projectPath, '.context-forge.toml');
10
+ }
11
+ //# sourceMappingURL=configPaths.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"configPaths.js","sourceRoot":"","sources":["../../src/config/configPaths.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;AAC5B,OAAO,EAAE,cAAc,EAAE,MAAM,4BAA4B,CAAC;AAE5D,yEAAyE;AACzE,MAAM,UAAU,iBAAiB;IAC/B,OAAO,IAAI,CAAC,cAAc,EAAE,EAAE,aAAa,CAAC,CAAC;AAC/C,CAAC;AAED,oFAAoF;AACpF,MAAM,UAAU,oBAAoB,CAAC,WAAmB;IACtD,OAAO,IAAI,CAAC,WAAW,EAAE,qBAAqB,CAAC,CAAC;AAClD,CAAC"}
@@ -0,0 +1,4 @@
1
+ export { ConfigKeyDefinition, CONFIG_KEYS } from './ConfigKeys.js';
2
+ export { ConfigResult, ConfigListEntry, ConfigManager } from './ConfigManager.js';
3
+ export { getUserConfigPath, getProjectConfigPath } from './configPaths.js';
4
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/config/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,mBAAmB,EAAE,WAAW,EAAE,MAAM,iBAAiB,CAAC;AACnE,OAAO,EAAE,YAAY,EAAE,eAAe,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AAClF,OAAO,EAAE,iBAAiB,EAAE,oBAAoB,EAAE,MAAM,kBAAkB,CAAC"}
@@ -0,0 +1,4 @@
1
+ export { CONFIG_KEYS } from './ConfigKeys.js';
2
+ export { ConfigManager } from './ConfigManager.js';
3
+ export { getUserConfigPath, getProjectConfigPath } from './configPaths.js';
4
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/config/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAuB,WAAW,EAAE,MAAM,iBAAiB,CAAC;AACnE,OAAO,EAAiC,aAAa,EAAE,MAAM,oBAAoB,CAAC;AAClF,OAAO,EAAE,iBAAiB,EAAE,oBAAoB,EAAE,MAAM,kBAAkB,CAAC"}
@@ -0,0 +1,20 @@
1
+ import { type GuideInfo } from './types.js';
2
+ /**
3
+ * Compare two semver version strings. Returns true if latest > current.
4
+ */
5
+ export declare function isNewerVersion(current: string | null, latest: string | null): boolean;
6
+ export declare class GuideDetector {
7
+ /**
8
+ * Detect guide installation state for a project.
9
+ * @param projectPath - absolute path to the project root
10
+ * @param source - override source URL (defaults to DEFAULT_SOURCE_GIT)
11
+ */
12
+ detect(projectPath: string, source?: string): Promise<GuideInfo>;
13
+ /** Determine installation method by inspecting filesystem */
14
+ private detectMethod;
15
+ /** Detect current version based on method */
16
+ private detectVersion;
17
+ /** Fetch latest version from remote. Returns null on any failure. */
18
+ private fetchLatestVersion;
19
+ }
20
+ //# sourceMappingURL=GuideDetector.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"GuideDetector.d.ts","sourceRoot":"","sources":["../../src/guides/GuideDetector.ts"],"names":[],"mappings":"AAGA,OAAO,EACL,KAAK,SAAS,EAKf,MAAM,YAAY,CAAC;AAiCpB;;GAEG;AACH,wBAAgB,cAAc,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,EAAE,MAAM,EAAE,MAAM,GAAG,IAAI,GAAG,OAAO,CASrF;AAED,qBAAa,aAAa;IACxB;;;;OAIG;IACG,MAAM,CAAC,WAAW,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,SAAS,CAAC;IAuCtE,6DAA6D;IAC7D,OAAO,CAAC,YAAY;IAuBpB,6CAA6C;YAC/B,aAAa;IAmB3B,qEAAqE;YACvD,kBAAkB;CAWjC"}
@@ -0,0 +1,142 @@
1
+ // Detect guide installation state, method, and version
2
+ import { existsSync, readFileSync } from 'fs';
3
+ import { join } from 'path';
4
+ import { DEFAULT_SOURCE_GIT, GUIDE_RELATIVE_PATH, VERSION_MARKER_FILE, } from './types.js';
5
+ import { gitExec } from './gitExec.js';
6
+ /**
7
+ * Parse the highest semver tag from `git ls-remote --tags` output.
8
+ * Returns null if no valid tags found.
9
+ */
10
+ function parseHighestTag(lsRemoteOutput) {
11
+ const tagPattern = /refs\/tags\/(v?\d+\.\d+\.\d+)$/;
12
+ const tags = [];
13
+ for (const line of lsRemoteOutput.split('\n')) {
14
+ const match = tagPattern.exec(line.trim());
15
+ if (match) {
16
+ tags.push(match[1]);
17
+ }
18
+ }
19
+ if (tags.length === 0)
20
+ return null;
21
+ // Sort by semver descending
22
+ tags.sort((a, b) => {
23
+ const pa = a.replace(/^v/, '').split('.').map(Number);
24
+ const pb = b.replace(/^v/, '').split('.').map(Number);
25
+ for (let i = 0; i < 3; i++) {
26
+ if (pa[i] !== pb[i])
27
+ return pb[i] - pa[i];
28
+ }
29
+ return 0;
30
+ });
31
+ return tags[0];
32
+ }
33
+ /**
34
+ * Compare two semver version strings. Returns true if latest > current.
35
+ */
36
+ export function isNewerVersion(current, latest) {
37
+ if (!current || !latest)
38
+ return false;
39
+ const ca = current.replace(/^v/, '').split('.').map(Number);
40
+ const la = latest.replace(/^v/, '').split('.').map(Number);
41
+ for (let i = 0; i < 3; i++) {
42
+ if (la[i] > ca[i])
43
+ return true;
44
+ if (la[i] < ca[i])
45
+ return false;
46
+ }
47
+ return false;
48
+ }
49
+ export class GuideDetector {
50
+ /**
51
+ * Detect guide installation state for a project.
52
+ * @param projectPath - absolute path to the project root
53
+ * @param source - override source URL (defaults to DEFAULT_SOURCE_GIT)
54
+ */
55
+ async detect(projectPath, source) {
56
+ const resolvedSource = source || DEFAULT_SOURCE_GIT;
57
+ const guidePath = join(projectPath, GUIDE_RELATIVE_PATH);
58
+ const baseInfo = {
59
+ installed: false,
60
+ method: null,
61
+ version: null,
62
+ path: guidePath,
63
+ source: resolvedSource,
64
+ latestVersion: null,
65
+ updateAvailable: false,
66
+ usingBundledPrompt: true,
67
+ };
68
+ if (!existsSync(guidePath)) {
69
+ // Check latest version even when not installed
70
+ baseInfo.latestVersion = await this.fetchLatestVersion(resolvedSource);
71
+ return baseInfo;
72
+ }
73
+ // Guide directory exists — determine method
74
+ const method = this.detectMethod(projectPath, guidePath);
75
+ const version = await this.detectVersion(guidePath, method);
76
+ const latestVersion = await this.fetchLatestVersion(resolvedSource);
77
+ const updateAvailable = isNewerVersion(version, latestVersion);
78
+ return {
79
+ installed: true,
80
+ method,
81
+ version,
82
+ path: guidePath,
83
+ source: resolvedSource,
84
+ latestVersion,
85
+ updateAvailable,
86
+ usingBundledPrompt: false,
87
+ };
88
+ }
89
+ /** Determine installation method by inspecting filesystem */
90
+ detectMethod(projectPath, guidePath) {
91
+ // Check .gitmodules first — submodules also have a .git entry inside
92
+ // the guide directory, so checking .git first would misidentify them as clones
93
+ const gitmodulesPath = join(projectPath, '.gitmodules');
94
+ if (existsSync(gitmodulesPath)) {
95
+ try {
96
+ const content = readFileSync(gitmodulesPath, 'utf-8');
97
+ if (content.includes(GUIDE_RELATIVE_PATH)) {
98
+ return 'submodule';
99
+ }
100
+ }
101
+ catch {
102
+ // Fall through
103
+ }
104
+ }
105
+ // Check for .git subdirectory → clone (only reached if not a submodule)
106
+ if (existsSync(join(guidePath, '.git'))) {
107
+ return 'clone';
108
+ }
109
+ return 'manual';
110
+ }
111
+ /** Detect current version based on method */
112
+ async detectVersion(guidePath, method) {
113
+ if (method === 'submodule' || method === 'clone') {
114
+ try {
115
+ const { stdout } = await gitExec(['describe', '--tags', '--abbrev=0'], guidePath);
116
+ return stdout || null;
117
+ }
118
+ catch {
119
+ return null;
120
+ }
121
+ }
122
+ // Manual: read version marker file
123
+ const markerPath = join(guidePath, VERSION_MARKER_FILE);
124
+ try {
125
+ return readFileSync(markerPath, 'utf-8').trim() || null;
126
+ }
127
+ catch {
128
+ return null;
129
+ }
130
+ }
131
+ /** Fetch latest version from remote. Returns null on any failure. */
132
+ async fetchLatestVersion(source) {
133
+ try {
134
+ const { stdout } = await gitExec(['ls-remote', '--tags', '--sort=-v:refname', source], process.cwd());
135
+ return parseHighestTag(stdout);
136
+ }
137
+ catch {
138
+ return null;
139
+ }
140
+ }
141
+ }
142
+ //# sourceMappingURL=GuideDetector.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"GuideDetector.js","sourceRoot":"","sources":["../../src/guides/GuideDetector.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,21 @@
1
+ import type { ConfigManager } from '../config/ConfigManager.js';
2
+ import type { GuideInfo, GuideMethod, InstallResult, UpdateResult } from './types.js';
3
+ export declare class GuideManager {
4
+ private readonly projectPath;
5
+ private readonly configManager?;
6
+ private readonly detector;
7
+ constructor(projectPath: string, configManager?: ConfigManager);
8
+ /** Get current guide installation status */
9
+ status(): Promise<GuideInfo>;
10
+ /** Install the guide into the project */
11
+ install(strategyOverride?: GuideMethod, sourceOverride?: string): Promise<InstallResult>;
12
+ /** Update an existing guide installation */
13
+ update(): Promise<UpdateResult>;
14
+ /** Resolve source URL from config or default */
15
+ private resolveSource;
16
+ /** Resolve strategy from config or default */
17
+ private resolveStrategy;
18
+ /** Map method name to strategy instance */
19
+ private getStrategy;
20
+ }
21
+ //# sourceMappingURL=GuideManager.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"GuideManager.d.ts","sourceRoot":"","sources":["../../src/guides/GuideManager.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,4BAA4B,CAAC;AAChE,OAAO,KAAK,EAAE,SAAS,EAAE,WAAW,EAAE,aAAa,EAAE,YAAY,EAAmB,MAAM,YAAY,CAAC;AAOvG,qBAAa,YAAY;IACvB,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAS;IACrC,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAC,CAAgB;IAC/C,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAgB;gBAE7B,WAAW,EAAE,MAAM,EAAE,aAAa,CAAC,EAAE,aAAa;IAM9D,4CAA4C;IACtC,MAAM,IAAI,OAAO,CAAC,SAAS,CAAC;IAKlC,yCAAyC;IACnC,OAAO,CAAC,gBAAgB,CAAC,EAAE,WAAW,EAAE,cAAc,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,aAAa,CAAC;IAiB9F,4CAA4C;IACtC,MAAM,IAAI,OAAO,CAAC,YAAY,CAAC;IAerC,gDAAgD;YAClC,aAAa;IAc3B,8CAA8C;YAChC,eAAe;IAc7B,2CAA2C;IAC3C,OAAO,CAAC,WAAW;CAUpB"}
@@ -0,0 +1,88 @@
1
+ // Orchestration layer for guide lifecycle management
2
+ import { join } from 'path';
3
+ import { DEFAULT_SOURCE_GIT, GUIDE_RELATIVE_PATH } from './types.js';
4
+ import { GuideDetector } from './GuideDetector.js';
5
+ import { SubmoduleStrategy } from './strategies/SubmoduleStrategy.js';
6
+ import { CloneStrategy } from './strategies/CloneStrategy.js';
7
+ import { TarballStrategy } from './strategies/TarballStrategy.js';
8
+ export class GuideManager {
9
+ projectPath;
10
+ configManager;
11
+ detector;
12
+ constructor(projectPath, configManager) {
13
+ this.projectPath = projectPath;
14
+ this.configManager = configManager;
15
+ this.detector = new GuideDetector();
16
+ }
17
+ /** Get current guide installation status */
18
+ async status() {
19
+ const source = await this.resolveSource();
20
+ return this.detector.detect(this.projectPath, source);
21
+ }
22
+ /** Install the guide into the project */
23
+ async install(strategyOverride, sourceOverride) {
24
+ const source = sourceOverride || (await this.resolveSource());
25
+ const method = strategyOverride || (await this.resolveStrategy());
26
+ const targetDir = join(this.projectPath, GUIDE_RELATIVE_PATH);
27
+ // Check if already installed
28
+ const info = await this.detector.detect(this.projectPath, source);
29
+ if (info.installed) {
30
+ throw new Error('Guide is already installed. Use guide_update (or cf guides update) to update it.');
31
+ }
32
+ const strategy = this.getStrategy(method);
33
+ return strategy.install(this.projectPath, source, targetDir);
34
+ }
35
+ /** Update an existing guide installation */
36
+ async update() {
37
+ const source = await this.resolveSource();
38
+ const targetDir = join(this.projectPath, GUIDE_RELATIVE_PATH);
39
+ const info = await this.detector.detect(this.projectPath, source);
40
+ if (!info.installed || !info.method) {
41
+ throw new Error('Guide is not installed. Use guide_install (or cf guides install) to install it first.');
42
+ }
43
+ const strategy = this.getStrategy(info.method);
44
+ return strategy.update(this.projectPath, targetDir);
45
+ }
46
+ /** Resolve source URL from config or default */
47
+ async resolveSource() {
48
+ if (this.configManager) {
49
+ try {
50
+ const result = await this.configManager.get('guide.source');
51
+ if (result.value && typeof result.value === 'string' && result.value.length > 0) {
52
+ return result.value;
53
+ }
54
+ }
55
+ catch {
56
+ // Fall through to default
57
+ }
58
+ }
59
+ return DEFAULT_SOURCE_GIT;
60
+ }
61
+ /** Resolve strategy from config or default */
62
+ async resolveStrategy() {
63
+ if (this.configManager) {
64
+ try {
65
+ const result = await this.configManager.get('guide.git_strategy');
66
+ if (result.value && typeof result.value === 'string') {
67
+ return result.value;
68
+ }
69
+ }
70
+ catch {
71
+ // Fall through to default
72
+ }
73
+ }
74
+ return 'submodule';
75
+ }
76
+ /** Map method name to strategy instance */
77
+ getStrategy(method) {
78
+ switch (method) {
79
+ case 'submodule':
80
+ return new SubmoduleStrategy();
81
+ case 'clone':
82
+ return new CloneStrategy();
83
+ case 'manual':
84
+ return new TarballStrategy();
85
+ }
86
+ }
87
+ }
88
+ //# sourceMappingURL=GuideManager.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"GuideManager.js","sourceRoot":"","sources":["../../src/guides/GuideManager.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,15 @@
1
+ export interface GitExecResult {
2
+ stdout: string;
3
+ stderr: string;
4
+ }
5
+ /**
6
+ * Execute a git command safely using execFile (no shell injection).
7
+ * @param args - arguments to pass to git (e.g., ['clone', url, dir])
8
+ * @param cwd - working directory for the command
9
+ */
10
+ export declare function gitExec(args: string[], cwd: string): Promise<GitExecResult>;
11
+ /** Check whether git is available on the system */
12
+ export declare function isGitAvailable(): Promise<boolean>;
13
+ /** Check whether a directory is inside a git repository */
14
+ export declare function isGitRepo(dir: string): Promise<boolean>;
15
+ //# sourceMappingURL=gitExec.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"gitExec.d.ts","sourceRoot":"","sources":["../../src/guides/gitExec.ts"],"names":[],"mappings":"AAGA,MAAM,WAAW,aAAa;IAC5B,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;CAChB;AAED;;;;GAIG;AACH,wBAAgB,OAAO,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,aAAa,CAAC,CAc3E;AAED,mDAAmD;AACnD,wBAAsB,cAAc,IAAI,OAAO,CAAC,OAAO,CAAC,CAOvD;AAED,2DAA2D;AAC3D,wBAAsB,SAAS,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAO7D"}
@@ -0,0 +1,39 @@
1
+ // Safe shell execution wrapper for git commands
2
+ import { execFile } from 'child_process';
3
+ /**
4
+ * Execute a git command safely using execFile (no shell injection).
5
+ * @param args - arguments to pass to git (e.g., ['clone', url, dir])
6
+ * @param cwd - working directory for the command
7
+ */
8
+ export function gitExec(args, cwd) {
9
+ return new Promise((resolve, reject) => {
10
+ execFile('git', args, { cwd }, (error, stdout, stderr) => {
11
+ if (error) {
12
+ reject(new Error(`git ${args.join(' ')} failed in ${cwd}: ${stderr.trim() || error.message}`));
13
+ return;
14
+ }
15
+ resolve({ stdout: stdout.trim(), stderr: stderr.trim() });
16
+ });
17
+ });
18
+ }
19
+ /** Check whether git is available on the system */
20
+ export async function isGitAvailable() {
21
+ try {
22
+ await gitExec(['--version'], process.cwd());
23
+ return true;
24
+ }
25
+ catch {
26
+ return false;
27
+ }
28
+ }
29
+ /** Check whether a directory is inside a git repository */
30
+ export async function isGitRepo(dir) {
31
+ try {
32
+ await gitExec(['rev-parse', '--is-inside-work-tree'], dir);
33
+ return true;
34
+ }
35
+ catch {
36
+ return false;
37
+ }
38
+ }
39
+ //# sourceMappingURL=gitExec.js.map