@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.
- package/README.md +12 -1
- package/dist/config/ConfigKeys.d.ts +9 -0
- package/dist/config/ConfigKeys.d.ts.map +1 -0
- package/dist/config/ConfigKeys.js +24 -0
- package/dist/config/ConfigKeys.js.map +1 -0
- package/dist/config/ConfigManager.d.ts +18 -0
- package/dist/config/ConfigManager.d.ts.map +1 -0
- package/dist/config/ConfigManager.js +129 -0
- package/dist/config/ConfigManager.js.map +1 -0
- package/dist/config/configPaths.d.ts +5 -0
- package/dist/config/configPaths.d.ts.map +1 -0
- package/dist/config/configPaths.js +11 -0
- package/dist/config/configPaths.js.map +1 -0
- package/dist/config/index.d.ts +4 -0
- package/dist/config/index.d.ts.map +1 -0
- package/dist/config/index.js +4 -0
- package/dist/config/index.js.map +1 -0
- package/dist/guides/GuideDetector.d.ts +20 -0
- package/dist/guides/GuideDetector.d.ts.map +1 -0
- package/dist/guides/GuideDetector.js +142 -0
- package/dist/guides/GuideDetector.js.map +1 -0
- package/dist/guides/GuideManager.d.ts +21 -0
- package/dist/guides/GuideManager.d.ts.map +1 -0
- package/dist/guides/GuideManager.js +88 -0
- package/dist/guides/GuideManager.js.map +1 -0
- package/dist/guides/gitExec.d.ts +15 -0
- package/dist/guides/gitExec.d.ts.map +1 -0
- package/dist/guides/gitExec.js +39 -0
- package/dist/guides/gitExec.js.map +1 -0
- package/dist/guides/index.d.ts +4 -0
- package/dist/guides/index.d.ts.map +1 -0
- package/dist/guides/index.js +5 -0
- package/dist/guides/index.js.map +1 -0
- package/dist/guides/strategies/CloneStrategy.d.ts +7 -0
- package/dist/guides/strategies/CloneStrategy.d.ts.map +1 -0
- package/dist/guides/strategies/CloneStrategy.js +80 -0
- package/dist/guides/strategies/CloneStrategy.js.map +1 -0
- package/dist/guides/strategies/SubmoduleStrategy.d.ts +7 -0
- package/dist/guides/strategies/SubmoduleStrategy.d.ts.map +1 -0
- package/dist/guides/strategies/SubmoduleStrategy.js +74 -0
- package/dist/guides/strategies/SubmoduleStrategy.js.map +1 -0
- package/dist/guides/strategies/TarballStrategy.d.ts +19 -0
- package/dist/guides/strategies/TarballStrategy.d.ts.map +1 -0
- package/dist/guides/strategies/TarballStrategy.js +118 -0
- package/dist/guides/strategies/TarballStrategy.js.map +1 -0
- package/dist/guides/types.d.ts +44 -0
- package/dist/guides/types.d.ts.map +1 -0
- package/dist/guides/types.js +7 -0
- package/dist/guides/types.js.map +1 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +4 -0
- package/dist/index.js.map +1 -1
- package/dist/introspection/ArtifactIntrospector.d.ts +20 -0
- package/dist/introspection/ArtifactIntrospector.d.ts.map +1 -0
- package/dist/introspection/ArtifactIntrospector.js +140 -0
- package/dist/introspection/ArtifactIntrospector.js.map +1 -0
- package/dist/introspection/FutureWorkCollector.d.ts +7 -0
- package/dist/introspection/FutureWorkCollector.d.ts.map +1 -0
- package/dist/introspection/FutureWorkCollector.js +116 -0
- package/dist/introspection/FutureWorkCollector.js.map +1 -0
- package/dist/introspection/ProjectModelBuilder.d.ts +32 -0
- package/dist/introspection/ProjectModelBuilder.d.ts.map +1 -0
- package/dist/introspection/ProjectModelBuilder.js +321 -0
- package/dist/introspection/ProjectModelBuilder.js.map +1 -0
- package/dist/introspection/index.d.ts +4 -0
- package/dist/introspection/index.d.ts.map +1 -0
- package/dist/introspection/index.js +5 -0
- package/dist/introspection/index.js.map +1 -0
- package/dist/introspection/interfaces.d.ts +18 -0
- package/dist/introspection/interfaces.d.ts.map +1 -0
- package/dist/introspection/interfaces.js +2 -0
- package/dist/introspection/interfaces.js.map +1 -0
- package/dist/introspection/parsers/documentDetector.d.ts +12 -0
- package/dist/introspection/parsers/documentDetector.d.ts.map +1 -0
- package/dist/introspection/parsers/documentDetector.js +66 -0
- package/dist/introspection/parsers/documentDetector.js.map +1 -0
- package/dist/introspection/parsers/frontmatterParser.d.ts +8 -0
- package/dist/introspection/parsers/frontmatterParser.d.ts.map +1 -0
- package/dist/introspection/parsers/frontmatterParser.js +43 -0
- package/dist/introspection/parsers/frontmatterParser.js.map +1 -0
- package/dist/introspection/parsers/futureWorkParser.d.ts +8 -0
- package/dist/introspection/parsers/futureWorkParser.d.ts.map +1 -0
- package/dist/introspection/parsers/futureWorkParser.js +75 -0
- package/dist/introspection/parsers/futureWorkParser.js.map +1 -0
- package/dist/introspection/parsers/slicePlanParser.d.ts +8 -0
- package/dist/introspection/parsers/slicePlanParser.d.ts.map +1 -0
- package/dist/introspection/parsers/slicePlanParser.js +51 -0
- package/dist/introspection/parsers/slicePlanParser.js.map +1 -0
- package/dist/introspection/parsers/statusNormalizer.d.ts +4 -0
- package/dist/introspection/parsers/statusNormalizer.d.ts.map +1 -0
- package/dist/introspection/parsers/statusNormalizer.js +23 -0
- package/dist/introspection/parsers/statusNormalizer.js.map +1 -0
- package/dist/introspection/parsers/taskFileParser.d.ts +13 -0
- package/dist/introspection/parsers/taskFileParser.d.ts.map +1 -0
- package/dist/introspection/parsers/taskFileParser.js +66 -0
- package/dist/introspection/parsers/taskFileParser.js.map +1 -0
- package/dist/introspection/types.d.ts +178 -0
- package/dist/introspection/types.d.ts.map +1 -0
- package/dist/introspection/types.js +2 -0
- package/dist/introspection/types.js.map +1 -0
- package/dist/node.d.ts +11 -0
- package/dist/node.d.ts.map +1 -1
- package/dist/node.js +15 -0
- package/dist/node.js.map +1 -1
- package/dist/schema/projectSchema.d.ts +54 -0
- package/dist/schema/projectSchema.d.ts.map +1 -0
- package/dist/schema/projectSchema.js +131 -0
- package/dist/schema/projectSchema.js.map +1 -0
- package/dist/schema/resolveFileByIndex.d.ts +11 -0
- package/dist/schema/resolveFileByIndex.d.ts.map +1 -0
- package/dist/schema/resolveFileByIndex.js +53 -0
- package/dist/schema/resolveFileByIndex.js.map +1 -0
- package/dist/services/ContextGenerator.d.ts.map +1 -1
- package/dist/services/ContextGenerator.js +3 -5
- package/dist/services/ContextGenerator.js.map +1 -1
- package/dist/services/ContextIntegrator.d.ts.map +1 -1
- package/dist/services/ContextIntegrator.js +10 -14
- package/dist/services/ContextIntegrator.js.map +1 -1
- package/dist/services/ContextTemplateEngine.d.ts.map +1 -1
- package/dist/services/ContextTemplateEngine.js +8 -21
- package/dist/services/ContextTemplateEngine.js.map +1 -1
- package/dist/services/CoreServiceFactory.d.ts +3 -0
- package/dist/services/CoreServiceFactory.d.ts.map +1 -1
- package/dist/services/CoreServiceFactory.js +19 -1
- package/dist/services/CoreServiceFactory.js.map +1 -1
- package/dist/services/ProjectPathService.d.ts +1 -1
- package/dist/services/ProjectPathService.d.ts.map +1 -1
- package/dist/services/ProjectPathService.js +2 -4
- package/dist/services/ProjectPathService.js.map +1 -1
- package/dist/services/SectionBuilder.d.ts +0 -4
- package/dist/services/SectionBuilder.d.ts.map +1 -1
- package/dist/services/SectionBuilder.js +8 -35
- package/dist/services/SectionBuilder.js.map +1 -1
- package/dist/services/SystemPromptParser.d.ts +1 -2
- package/dist/services/SystemPromptParser.d.ts.map +1 -1
- package/dist/services/SystemPromptParser.js +3 -14
- package/dist/services/SystemPromptParser.js.map +1 -1
- package/dist/services/TemplateProcessor.d.ts.map +1 -1
- package/dist/services/TemplateProcessor.js +12 -11
- package/dist/services/TemplateProcessor.js.map +1 -1
- package/dist/services/constants.d.ts.map +1 -1
- package/dist/services/constants.js +0 -6
- package/dist/services/constants.js.map +1 -1
- package/dist/services/interfaces.d.ts +1 -1
- package/dist/services/interfaces.d.ts.map +1 -1
- package/dist/storage/FileProjectStore.d.ts.map +1 -1
- package/dist/storage/FileProjectStore.js +25 -8
- package/dist/storage/FileProjectStore.js.map +1 -1
- package/dist/types/context.d.ts +4 -6
- package/dist/types/context.d.ts.map +1 -1
- package/dist/types/project.d.ts +15 -11
- package/dist/types/project.d.ts.map +1 -1
- package/dist/types/sections.d.ts +0 -1
- package/dist/types/sections.d.ts.map +1 -1
- package/dist/types/sections.js +0 -1
- package/dist/types/sections.js.map +1 -1
- 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}}`, `{{
|
|
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":"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"}
|
|
@@ -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 @@
|
|
|
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 @@
|
|
|
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
|