@dedesfr/prompter 0.8.23 → 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +70 -0
- package/README.md +105 -77
- package/dist/cli/index.js +25 -1
- package/dist/cli/index.js.map +1 -1
- package/dist/commands/init.d.ts +1 -7
- package/dist/commands/init.d.ts.map +1 -1
- package/dist/commands/init.js +60 -299
- package/dist/commands/init.js.map +1 -1
- package/dist/commands/login.d.ts +4 -0
- package/dist/commands/login.d.ts.map +1 -0
- package/dist/commands/login.js +56 -0
- package/dist/commands/login.js.map +1 -0
- package/dist/commands/logout.d.ts +4 -0
- package/dist/commands/logout.d.ts.map +1 -0
- package/dist/commands/logout.js +14 -0
- package/dist/commands/logout.js.map +1 -0
- package/dist/commands/update.d.ts.map +1 -1
- package/dist/commands/update.js +31 -41
- package/dist/commands/update.js.map +1 -1
- package/dist/commands/whoami.d.ts +4 -0
- package/dist/commands/whoami.d.ts.map +1 -0
- package/dist/commands/whoami.js +42 -0
- package/dist/commands/whoami.js.map +1 -0
- package/dist/core/auth-store.d.ts +10 -0
- package/dist/core/auth-store.d.ts.map +1 -0
- package/dist/core/auth-store.js +39 -0
- package/dist/core/auth-store.js.map +1 -0
- package/dist/core/configurators/slash/antigravity.d.ts +2 -5
- package/dist/core/configurators/slash/antigravity.d.ts.map +1 -1
- package/dist/core/configurators/slash/antigravity.js +2 -57
- package/dist/core/configurators/slash/antigravity.js.map +1 -1
- package/dist/core/configurators/slash/base.d.ts +6 -18
- package/dist/core/configurators/slash/base.d.ts.map +1 -1
- package/dist/core/configurators/slash/base.js +8 -77
- package/dist/core/configurators/slash/base.js.map +1 -1
- package/dist/core/configurators/slash/claude.d.ts +2 -5
- package/dist/core/configurators/slash/claude.d.ts.map +1 -1
- package/dist/core/configurators/slash/claude.js +2 -57
- package/dist/core/configurators/slash/claude.js.map +1 -1
- package/dist/core/configurators/slash/codex.d.ts +2 -5
- package/dist/core/configurators/slash/codex.d.ts.map +1 -1
- package/dist/core/configurators/slash/codex.js +2 -57
- package/dist/core/configurators/slash/codex.js.map +1 -1
- package/dist/core/configurators/slash/droid.d.ts +2 -5
- package/dist/core/configurators/slash/droid.d.ts.map +1 -1
- package/dist/core/configurators/slash/droid.js +2 -32
- package/dist/core/configurators/slash/droid.js.map +1 -1
- package/dist/core/configurators/slash/forge.d.ts +2 -5
- package/dist/core/configurators/slash/forge.d.ts.map +1 -1
- package/dist/core/configurators/slash/forge.js +2 -32
- package/dist/core/configurators/slash/forge.js.map +1 -1
- package/dist/core/configurators/slash/github-copilot.d.ts +2 -7
- package/dist/core/configurators/slash/github-copilot.d.ts.map +1 -1
- package/dist/core/configurators/slash/github-copilot.js +2 -96
- package/dist/core/configurators/slash/github-copilot.js.map +1 -1
- package/dist/core/configurators/slash/index.d.ts +1 -1
- package/dist/core/configurators/slash/index.d.ts.map +1 -1
- package/dist/core/configurators/slash/index.js +1 -1
- package/dist/core/configurators/slash/index.js.map +1 -1
- package/dist/core/configurators/slash/kilocode.d.ts +2 -5
- package/dist/core/configurators/slash/kilocode.d.ts.map +1 -1
- package/dist/core/configurators/slash/kilocode.js +2 -57
- package/dist/core/configurators/slash/kilocode.js.map +1 -1
- package/dist/core/configurators/slash/opencode.d.ts +2 -5
- package/dist/core/configurators/slash/opencode.d.ts.map +1 -1
- package/dist/core/configurators/slash/opencode.js +2 -57
- package/dist/core/configurators/slash/opencode.js.map +1 -1
- package/dist/core/configurators/slash/registry.d.ts +4 -4
- package/dist/core/configurators/slash/registry.d.ts.map +1 -1
- package/dist/core/configurators/slash/registry.js.map +1 -1
- package/dist/core/registry.d.ts +18 -0
- package/dist/core/registry.d.ts.map +1 -0
- package/dist/core/registry.js +94 -0
- package/dist/core/registry.js.map +1 -0
- package/dist/core/templates/index.d.ts +0 -1
- package/dist/core/templates/index.d.ts.map +1 -1
- package/dist/core/templates/index.js +0 -1
- package/dist/core/templates/index.js.map +1 -1
- package/package.json +7 -1
- package/AGENTS.md +0 -123
- package/CLAUDE.md +0 -17
- package/build.js +0 -20
- package/convex-setup.md +0 -403
- package/dist/core/templates/slash-command-templates.d.ts +0 -7
- package/dist/core/templates/slash-command-templates.d.ts.map +0 -1
- package/dist/core/templates/slash-command-templates.js +0 -1041
- package/dist/core/templates/slash-command-templates.js.map +0 -1
- package/prompt/ai-humanizer.md +0 -45
- package/prompt/api-contract-generator.md +0 -234
- package/prompt/apply.md +0 -17
- package/prompt/archive.md +0 -21
- package/prompt/design-system.md +0 -210
- package/prompt/document-explainer.md +0 -149
- package/prompt/epic-generator.md +0 -198
- package/prompt/epic-single.md +0 -47
- package/prompt/erd-generator.md +0 -130
- package/prompt/fsd-generator.md +0 -157
- package/prompt/prd-agent-generator.md +0 -147
- package/prompt/prd-generator.md +0 -195
- package/prompt/product-brief.md +0 -289
- package/prompt/proposal.md +0 -22
- package/prompt/qa-test-scenario.md +0 -133
- package/prompt/skill-creator.md +0 -350
- package/prompt/story-generator.md +0 -278
- package/prompt/story-single.md +0 -70
- package/prompt/tdd-generator.md +0 -294
- package/prompt/tdd-lite-generator.md +0 -224
- package/prompt/wireframe-generator.md +0 -219
- package/skills/ai-context-generator/SKILL.md +0 -54
- package/skills/ai-context-generator/references/AGENTS.template.md +0 -83
- package/skills/ai-context-generator/references/CLAUDE.template.md +0 -39
- package/skills/ai-context-generator/references/behavioral-guidelines.md +0 -71
- package/skills/ai-context-generator/references/discovery-checklist.md +0 -40
- package/skills/ai-context-generator/references/examples/AGENTS.good.md +0 -103
- package/skills/ai-context-generator/references/extraction-checklist.md +0 -23
- package/skills/ai-context-generator/references/overlays/laravel.md +0 -44
- package/skills/cerebro/SKILL.md +0 -187
- package/skills/cerebro/references/agents.md +0 -213
- package/skills/code-review/SKILL.md +0 -373
- package/skills/code-review/assets/report-template-agent.md +0 -212
- package/skills/code-review/assets/report-template-compact.md +0 -81
- package/skills/code-review/assets/report-template-full.md +0 -264
- package/skills/code-review/assets/report-template-human.md +0 -168
- package/skills/code-review/references/universal-patterns.md +0 -495
- package/skills/design-md/README.md +0 -34
- package/skills/design-md/SKILL.md +0 -172
- package/skills/design-md/examples/DESIGN.md +0 -154
- package/skills/design-system-generator/SKILL.md +0 -324
- package/skills/design-system-generator/assets/design-system-template.md +0 -348
- package/skills/design-system-generator/references/extraction-patterns.md +0 -321
- package/skills/doc-builder/SKILL.md +0 -115
- package/skills/doc-builder/references/ui-patterns.md +0 -394
- package/skills/document-translator/SKILL.md +0 -58
- package/skills/enhance-prompt/README.md +0 -34
- package/skills/enhance-prompt/SKILL.md +0 -204
- package/skills/enhance-prompt/references/KEYWORDS.md +0 -114
- package/skills/feature-planner/SKILL.md +0 -305
- package/skills/feature-planner/assets/implementation-plan-template.md +0 -85
- package/skills/frontend-design/LICENSE.txt +0 -177
- package/skills/frontend-design/SKILL.md +0 -42
- package/skills/gamma-builder/SKILL.md +0 -134
- package/skills/laravel-code-review/SKILL.md +0 -383
- package/skills/laravel-code-review/assets/report-template-agent.md +0 -195
- package/skills/laravel-code-review/assets/report-template-compact.md +0 -79
- package/skills/laravel-code-review/assets/report-template-full.md +0 -253
- package/skills/laravel-code-review/assets/report-template-human.md +0 -159
- package/skills/laravel-code-review/references/laravel-patterns.md +0 -571
- package/skills/laravel-code-review/references/php84-features.md +0 -442
- package/skills/mcp-builder/LICENSE.txt +0 -202
- package/skills/mcp-builder/SKILL.md +0 -236
- package/skills/mcp-builder/reference/evaluation.md +0 -602
- package/skills/mcp-builder/reference/mcp_best_practices.md +0 -249
- package/skills/mcp-builder/reference/node_mcp_server.md +0 -970
- package/skills/mcp-builder/reference/python_mcp_server.md +0 -719
- package/skills/mcp-builder/scripts/connections.py +0 -151
- package/skills/mcp-builder/scripts/evaluation.py +0 -373
- package/skills/mcp-builder/scripts/example_evaluation.xml +0 -22
- package/skills/mcp-builder/scripts/requirements.txt +0 -2
- package/skills/meeting-notes/SKILL.md +0 -159
- package/skills/meeting-notes/evals/evals.json +0 -23
- package/skills/project-orchestrator/SKILL.md +0 -487
- package/skills/project-orchestrator/assets/caddy-vps-setup.md +0 -180
- package/skills/project-orchestrator/assets/plan-summary-template.md +0 -159
- package/skills/prompter-specs/SKILL.md +0 -115
- package/skills/prompter-workflow/SKILL.md +0 -166
- package/skills/prompter-workflow/evals/evals.json +0 -89
- package/skills/sph-generator/SKILL.md +0 -488
- package/skills/ui-ux-pro/SKILL.md +0 -199
- package/skills/ui-ux-pro/assets/design-spec-template.md +0 -173
- package/skills/ui-ux-pro/references/component-patterns.md +0 -255
- package/skills/ui-ux-pro/references/design-principles.md +0 -167
- package/src/cli/index.ts +0 -223
- package/src/commands/archive.ts +0 -302
- package/src/commands/change.ts +0 -292
- package/src/commands/config.ts +0 -233
- package/src/commands/guide.ts +0 -50
- package/src/commands/init.ts +0 -899
- package/src/commands/list.ts +0 -194
- package/src/commands/show.ts +0 -138
- package/src/commands/spec.ts +0 -251
- package/src/commands/update.ts +0 -156
- package/src/commands/upgrade.ts +0 -30
- package/src/commands/validate.ts +0 -326
- package/src/core/artifact-graph/graph.ts +0 -167
- package/src/core/artifact-graph/index.ts +0 -44
- package/src/core/artifact-graph/instruction-loader.ts +0 -302
- package/src/core/artifact-graph/resolver.ts +0 -226
- package/src/core/artifact-graph/schema.ts +0 -124
- package/src/core/artifact-graph/state.ts +0 -64
- package/src/core/artifact-graph/types.ts +0 -65
- package/src/core/completions/command-registry.ts +0 -382
- package/src/core/completions/completion-provider.ts +0 -128
- package/src/core/completions/generators/bash-generator.ts +0 -191
- package/src/core/completions/generators/fish-generator.ts +0 -188
- package/src/core/completions/generators/powershell-generator.ts +0 -223
- package/src/core/completions/generators/zsh-generator.ts +0 -281
- package/src/core/completions/templates/bash-templates.ts +0 -24
- package/src/core/completions/templates/fish-templates.ts +0 -40
- package/src/core/completions/templates/powershell-templates.ts +0 -25
- package/src/core/completions/templates/zsh-templates.ts +0 -36
- package/src/core/completions/types.ts +0 -90
- package/src/core/config-schema.ts +0 -230
- package/src/core/config.ts +0 -181
- package/src/core/configurators/slash/antigravity.ts +0 -70
- package/src/core/configurators/slash/base.ts +0 -203
- package/src/core/configurators/slash/claude.ts +0 -70
- package/src/core/configurators/slash/codex.ts +0 -70
- package/src/core/configurators/slash/droid.ts +0 -44
- package/src/core/configurators/slash/forge.ts +0 -44
- package/src/core/configurators/slash/github-copilot.ts +0 -114
- package/src/core/configurators/slash/index.ts +0 -10
- package/src/core/configurators/slash/kilocode.ts +0 -70
- package/src/core/configurators/slash/opencode.ts +0 -70
- package/src/core/configurators/slash/registry.ts +0 -51
- package/src/core/converters/json-converter.ts +0 -62
- package/src/core/global-config.ts +0 -136
- package/src/core/parsers/change-parser.ts +0 -234
- package/src/core/parsers/markdown-parser.ts +0 -237
- package/src/core/parsers/requirement-blocks.ts +0 -234
- package/src/core/prompt-templates.ts +0 -3504
- package/src/core/schemas/base.schema.ts +0 -20
- package/src/core/schemas/change.schema.ts +0 -42
- package/src/core/schemas/index.ts +0 -20
- package/src/core/schemas/spec.schema.ts +0 -17
- package/src/core/skill-discovery.ts +0 -68
- package/src/core/specs-apply.ts +0 -483
- package/src/core/styles/palette.ts +0 -8
- package/src/core/templates/agents-template.ts +0 -459
- package/src/core/templates/claude-template.ts +0 -2
- package/src/core/templates/index.ts +0 -4
- package/src/core/templates/project-template.ts +0 -32
- package/src/core/templates/slash-command-templates.ts +0 -1068
- package/src/core/validation/constants.ts +0 -48
- package/src/core/validation/types.ts +0 -19
- package/src/core/validation/validator.ts +0 -449
- package/src/core/view.ts +0 -219
- package/src/index.ts +0 -1
- package/src/utils/change-metadata.ts +0 -171
- package/src/utils/change-utils.ts +0 -131
- package/src/utils/file-system.ts +0 -252
- package/src/utils/index.ts +0 -12
- package/src/utils/interactive.ts +0 -29
- package/src/utils/item-discovery.ts +0 -66
- package/src/utils/match.ts +0 -26
- package/src/utils/shell-detection.ts +0 -62
- package/src/utils/task-progress.ts +0 -43
- package/tsconfig.json +0 -28
|
@@ -1,230 +0,0 @@
|
|
|
1
|
-
import { z } from 'zod';
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* Zod schema for global Prompter configuration.
|
|
5
|
-
* Uses passthrough() to preserve unknown fields for forward compatibility.
|
|
6
|
-
*/
|
|
7
|
-
export const GlobalConfigSchema = z
|
|
8
|
-
.object({
|
|
9
|
-
featureFlags: z
|
|
10
|
-
.record(z.string(), z.boolean())
|
|
11
|
-
.optional()
|
|
12
|
-
.default({}),
|
|
13
|
-
})
|
|
14
|
-
.passthrough();
|
|
15
|
-
|
|
16
|
-
export type GlobalConfigType = z.infer<typeof GlobalConfigSchema>;
|
|
17
|
-
|
|
18
|
-
/**
|
|
19
|
-
* Default configuration values.
|
|
20
|
-
*/
|
|
21
|
-
export const DEFAULT_CONFIG: GlobalConfigType = {
|
|
22
|
-
featureFlags: {},
|
|
23
|
-
};
|
|
24
|
-
|
|
25
|
-
const KNOWN_TOP_LEVEL_KEYS = new Set(Object.keys(DEFAULT_CONFIG));
|
|
26
|
-
|
|
27
|
-
/**
|
|
28
|
-
* Validate a config key path for CLI set operations.
|
|
29
|
-
* Unknown top-level keys are rejected unless explicitly allowed by the caller.
|
|
30
|
-
*/
|
|
31
|
-
export function validateConfigKeyPath(path: string): { valid: boolean; reason?: string } {
|
|
32
|
-
const rawKeys = path.split('.');
|
|
33
|
-
|
|
34
|
-
if (rawKeys.length === 0 || rawKeys.some((key) => key.trim() === '')) {
|
|
35
|
-
return { valid: false, reason: 'Key path must not be empty' };
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
const rootKey = rawKeys[0];
|
|
39
|
-
if (!KNOWN_TOP_LEVEL_KEYS.has(rootKey)) {
|
|
40
|
-
return { valid: false, reason: `Unknown top-level key "${rootKey}"` };
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
if (rootKey === 'featureFlags') {
|
|
44
|
-
if (rawKeys.length > 2) {
|
|
45
|
-
return { valid: false, reason: 'featureFlags values are booleans and do not support nested keys' };
|
|
46
|
-
}
|
|
47
|
-
return { valid: true };
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
if (rawKeys.length > 1) {
|
|
51
|
-
return { valid: false, reason: `"${rootKey}" does not support nested keys` };
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
return { valid: true };
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
/**
|
|
58
|
-
* Get a nested value from an object using dot notation.
|
|
59
|
-
*
|
|
60
|
-
* @param obj - The object to access
|
|
61
|
-
* @param path - Dot-separated path (e.g., "featureFlags.someFlag")
|
|
62
|
-
* @returns The value at the path, or undefined if not found
|
|
63
|
-
*/
|
|
64
|
-
export function getNestedValue(obj: Record<string, unknown>, path: string): unknown {
|
|
65
|
-
const keys = path.split('.');
|
|
66
|
-
let current: unknown = obj;
|
|
67
|
-
|
|
68
|
-
for (const key of keys) {
|
|
69
|
-
if (current === null || current === undefined) {
|
|
70
|
-
return undefined;
|
|
71
|
-
}
|
|
72
|
-
if (typeof current !== 'object') {
|
|
73
|
-
return undefined;
|
|
74
|
-
}
|
|
75
|
-
current = (current as Record<string, unknown>)[key];
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
return current;
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
/**
|
|
82
|
-
* Set a nested value in an object using dot notation.
|
|
83
|
-
* Creates intermediate objects as needed.
|
|
84
|
-
*
|
|
85
|
-
* @param obj - The object to modify (mutated in place)
|
|
86
|
-
* @param path - Dot-separated path (e.g., "featureFlags.someFlag")
|
|
87
|
-
* @param value - The value to set
|
|
88
|
-
*/
|
|
89
|
-
export function setNestedValue(obj: Record<string, unknown>, path: string, value: unknown): void {
|
|
90
|
-
const keys = path.split('.');
|
|
91
|
-
let current: Record<string, unknown> = obj;
|
|
92
|
-
|
|
93
|
-
for (let i = 0; i < keys.length - 1; i++) {
|
|
94
|
-
const key = keys[i];
|
|
95
|
-
if (current[key] === undefined || current[key] === null || typeof current[key] !== 'object') {
|
|
96
|
-
current[key] = {};
|
|
97
|
-
}
|
|
98
|
-
current = current[key] as Record<string, unknown>;
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
const lastKey = keys[keys.length - 1];
|
|
102
|
-
current[lastKey] = value;
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
/**
|
|
106
|
-
* Delete a nested value from an object using dot notation.
|
|
107
|
-
*
|
|
108
|
-
* @param obj - The object to modify (mutated in place)
|
|
109
|
-
* @param path - Dot-separated path (e.g., "featureFlags.someFlag")
|
|
110
|
-
* @returns true if the key existed and was deleted, false otherwise
|
|
111
|
-
*/
|
|
112
|
-
export function deleteNestedValue(obj: Record<string, unknown>, path: string): boolean {
|
|
113
|
-
const keys = path.split('.');
|
|
114
|
-
let current: Record<string, unknown> = obj;
|
|
115
|
-
|
|
116
|
-
for (let i = 0; i < keys.length - 1; i++) {
|
|
117
|
-
const key = keys[i];
|
|
118
|
-
if (current[key] === undefined || current[key] === null || typeof current[key] !== 'object') {
|
|
119
|
-
return false;
|
|
120
|
-
}
|
|
121
|
-
current = current[key] as Record<string, unknown>;
|
|
122
|
-
}
|
|
123
|
-
|
|
124
|
-
const lastKey = keys[keys.length - 1];
|
|
125
|
-
if (lastKey in current) {
|
|
126
|
-
delete current[lastKey];
|
|
127
|
-
return true;
|
|
128
|
-
}
|
|
129
|
-
return false;
|
|
130
|
-
}
|
|
131
|
-
|
|
132
|
-
/**
|
|
133
|
-
* Coerce a string value to its appropriate type.
|
|
134
|
-
* - "true" / "false" -> boolean
|
|
135
|
-
* - Numeric strings -> number
|
|
136
|
-
* - Everything else -> string
|
|
137
|
-
*
|
|
138
|
-
* @param value - The string value to coerce
|
|
139
|
-
* @param forceString - If true, always return the value as a string
|
|
140
|
-
* @returns The coerced value
|
|
141
|
-
*/
|
|
142
|
-
export function coerceValue(value: string, forceString: boolean = false): string | number | boolean {
|
|
143
|
-
if (forceString) {
|
|
144
|
-
return value;
|
|
145
|
-
}
|
|
146
|
-
|
|
147
|
-
// Boolean coercion
|
|
148
|
-
if (value === 'true') {
|
|
149
|
-
return true;
|
|
150
|
-
}
|
|
151
|
-
if (value === 'false') {
|
|
152
|
-
return false;
|
|
153
|
-
}
|
|
154
|
-
|
|
155
|
-
// Number coercion - must be a valid finite number
|
|
156
|
-
const num = Number(value);
|
|
157
|
-
if (!isNaN(num) && isFinite(num) && value.trim() !== '') {
|
|
158
|
-
return num;
|
|
159
|
-
}
|
|
160
|
-
|
|
161
|
-
return value;
|
|
162
|
-
}
|
|
163
|
-
|
|
164
|
-
/**
|
|
165
|
-
* Format a value for YAML-like display.
|
|
166
|
-
*
|
|
167
|
-
* @param value - The value to format
|
|
168
|
-
* @param indent - Current indentation level
|
|
169
|
-
* @returns Formatted string
|
|
170
|
-
*/
|
|
171
|
-
export function formatValueYaml(value: unknown, indent: number = 0): string {
|
|
172
|
-
const indentStr = ' '.repeat(indent);
|
|
173
|
-
|
|
174
|
-
if (value === null || value === undefined) {
|
|
175
|
-
return 'null';
|
|
176
|
-
}
|
|
177
|
-
|
|
178
|
-
if (typeof value === 'boolean' || typeof value === 'number') {
|
|
179
|
-
return String(value);
|
|
180
|
-
}
|
|
181
|
-
|
|
182
|
-
if (typeof value === 'string') {
|
|
183
|
-
return value;
|
|
184
|
-
}
|
|
185
|
-
|
|
186
|
-
if (Array.isArray(value)) {
|
|
187
|
-
if (value.length === 0) {
|
|
188
|
-
return '[]';
|
|
189
|
-
}
|
|
190
|
-
return value.map((item) => `${indentStr}- ${formatValueYaml(item, indent + 1)}`).join('\n');
|
|
191
|
-
}
|
|
192
|
-
|
|
193
|
-
if (typeof value === 'object') {
|
|
194
|
-
const entries = Object.entries(value as Record<string, unknown>);
|
|
195
|
-
if (entries.length === 0) {
|
|
196
|
-
return '{}';
|
|
197
|
-
}
|
|
198
|
-
return entries
|
|
199
|
-
.map(([key, val]) => {
|
|
200
|
-
const formattedVal = formatValueYaml(val, indent + 1);
|
|
201
|
-
if (typeof val === 'object' && val !== null && Object.keys(val).length > 0) {
|
|
202
|
-
return `${indentStr}${key}:\n${formattedVal}`;
|
|
203
|
-
}
|
|
204
|
-
return `${indentStr}${key}: ${formattedVal}`;
|
|
205
|
-
})
|
|
206
|
-
.join('\n');
|
|
207
|
-
}
|
|
208
|
-
|
|
209
|
-
return String(value);
|
|
210
|
-
}
|
|
211
|
-
|
|
212
|
-
/**
|
|
213
|
-
* Validate a configuration object against the schema.
|
|
214
|
-
*
|
|
215
|
-
* @param config - The configuration to validate
|
|
216
|
-
* @returns Validation result with success status and optional error message
|
|
217
|
-
*/
|
|
218
|
-
export function validateConfig(config: unknown): { success: boolean; error?: string } {
|
|
219
|
-
try {
|
|
220
|
-
GlobalConfigSchema.parse(config);
|
|
221
|
-
return { success: true };
|
|
222
|
-
} catch (error) {
|
|
223
|
-
if (error instanceof z.ZodError) {
|
|
224
|
-
const zodError = error as z.ZodError;
|
|
225
|
-
const messages = zodError.issues.map((e) => `${e.path.join('.')}: ${e.message}`);
|
|
226
|
-
return { success: false, error: messages.join('; ') };
|
|
227
|
-
}
|
|
228
|
-
return { success: false, error: 'Unknown validation error' };
|
|
229
|
-
}
|
|
230
|
-
}
|
package/src/core/config.ts
DELETED
|
@@ -1,181 +0,0 @@
|
|
|
1
|
-
import { promises as fs } from 'fs';
|
|
2
|
-
import path from 'path';
|
|
3
|
-
|
|
4
|
-
export const PROMPTER_DIR = 'prompter';
|
|
5
|
-
|
|
6
|
-
export const PROMPTER_MARKERS = {
|
|
7
|
-
start: '<!-- prompter-managed-start -->',
|
|
8
|
-
end: '<!-- prompter-managed-end -->'
|
|
9
|
-
};
|
|
10
|
-
|
|
11
|
-
export interface ToolChoice {
|
|
12
|
-
name: string;
|
|
13
|
-
value: string;
|
|
14
|
-
available: boolean;
|
|
15
|
-
successLabel: string;
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
export interface PromptChoice {
|
|
19
|
-
name: string;
|
|
20
|
-
value: string;
|
|
21
|
-
description: string;
|
|
22
|
-
sourceFile: string;
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
export const SUPPORTED_TOOLS: ToolChoice[] = [
|
|
26
|
-
{ name: 'Antigravity', value: 'antigravity', available: true, successLabel: 'Antigravity' },
|
|
27
|
-
{ name: 'Claude Code', value: 'claude', available: true, successLabel: 'Claude Code' },
|
|
28
|
-
{ name: 'Codex', value: 'codex', available: true, successLabel: 'Codex' },
|
|
29
|
-
{ name: 'GitHub Copilot', value: 'github-copilot', available: true, successLabel: 'GitHub Copilot' },
|
|
30
|
-
{ name: 'OpenCode', value: 'opencode', available: true, successLabel: 'OpenCode' },
|
|
31
|
-
{ name: 'Kilo Code', value: 'kilocode', available: true, successLabel: 'Kilo Code' },
|
|
32
|
-
{ name: 'Forge', value: 'forge', available: true, successLabel: 'Forge' },
|
|
33
|
-
{ name: 'Droid', value: 'droid', available: true, successLabel: 'Droid' }
|
|
34
|
-
];
|
|
35
|
-
|
|
36
|
-
export const AVAILABLE_PROMPTS: PromptChoice[] = [
|
|
37
|
-
{
|
|
38
|
-
name: 'AI Humanizer',
|
|
39
|
-
value: 'ai-humanizer',
|
|
40
|
-
description: 'Transform AI-generated text into natural, human-like content',
|
|
41
|
-
sourceFile: 'ai-humanizer.md'
|
|
42
|
-
},
|
|
43
|
-
{
|
|
44
|
-
name: 'API Contract Generator',
|
|
45
|
-
value: 'api-contract-generator',
|
|
46
|
-
description: 'Generate OpenAPI specification from FSD and ERD',
|
|
47
|
-
sourceFile: 'api-contract-generator.md'
|
|
48
|
-
},
|
|
49
|
-
{
|
|
50
|
-
name: 'Apply',
|
|
51
|
-
value: 'apply',
|
|
52
|
-
description: 'Implement and apply an approved change proposal',
|
|
53
|
-
sourceFile: 'apply.md'
|
|
54
|
-
},
|
|
55
|
-
{
|
|
56
|
-
name: 'Archive',
|
|
57
|
-
value: 'archive',
|
|
58
|
-
description: 'Archive a completed change and update specs',
|
|
59
|
-
sourceFile: 'archive.md'
|
|
60
|
-
},
|
|
61
|
-
{
|
|
62
|
-
name: 'Design System',
|
|
63
|
-
value: 'design-system',
|
|
64
|
-
description: 'Generate comprehensive design system documentation for components and tokens',
|
|
65
|
-
sourceFile: 'design-system.md'
|
|
66
|
-
},
|
|
67
|
-
{
|
|
68
|
-
name: 'Document Explainer',
|
|
69
|
-
value: 'document-explainer',
|
|
70
|
-
description: 'Analyze and explain complex documents into clear, actionable insights',
|
|
71
|
-
sourceFile: 'document-explainer.md'
|
|
72
|
-
},
|
|
73
|
-
{
|
|
74
|
-
name: 'Epic (Single)',
|
|
75
|
-
value: 'epic-single',
|
|
76
|
-
description: 'Generate comprehensive epic documentation',
|
|
77
|
-
sourceFile: 'epic-single.md'
|
|
78
|
-
},
|
|
79
|
-
{
|
|
80
|
-
name: 'Epic Generator',
|
|
81
|
-
value: 'epic-generator',
|
|
82
|
-
description: 'Generate comprehensive EPICs from FSD and TDD documentation',
|
|
83
|
-
sourceFile: 'epic-generator.md'
|
|
84
|
-
},
|
|
85
|
-
{
|
|
86
|
-
name: 'ERD Generator',
|
|
87
|
-
value: 'erd-generator',
|
|
88
|
-
description: 'Generate Entity Relationship Diagram from FSD',
|
|
89
|
-
sourceFile: 'erd-generator.md'
|
|
90
|
-
},
|
|
91
|
-
{
|
|
92
|
-
name: 'FSD Generator',
|
|
93
|
-
value: 'fsd-generator',
|
|
94
|
-
description: 'Generate Functional Specification Document from PRD',
|
|
95
|
-
sourceFile: 'fsd-generator.md'
|
|
96
|
-
},
|
|
97
|
-
{
|
|
98
|
-
name: 'PRD Agent Generator',
|
|
99
|
-
value: 'prd-agent-generator',
|
|
100
|
-
description: 'Create AGENT.md files with Product Requirements Document prompts',
|
|
101
|
-
sourceFile: 'prd-agent-generator.md'
|
|
102
|
-
},
|
|
103
|
-
{
|
|
104
|
-
name: 'PRD Generator',
|
|
105
|
-
value: 'prd-generator',
|
|
106
|
-
description: 'Generate detailed Product Requirements Documents',
|
|
107
|
-
sourceFile: 'prd-generator.md'
|
|
108
|
-
},
|
|
109
|
-
{
|
|
110
|
-
name: 'Product Brief',
|
|
111
|
-
value: 'product-brief',
|
|
112
|
-
description: 'Create concise product brief documents',
|
|
113
|
-
sourceFile: 'product-brief.md'
|
|
114
|
-
},
|
|
115
|
-
{
|
|
116
|
-
name: 'Proposal',
|
|
117
|
-
value: 'proposal',
|
|
118
|
-
description: 'Create a new change proposal with spec deltas',
|
|
119
|
-
sourceFile: 'proposal.md'
|
|
120
|
-
},
|
|
121
|
-
{
|
|
122
|
-
name: 'QA Test Scenario',
|
|
123
|
-
value: 'qa-test-scenario',
|
|
124
|
-
description: 'Generate comprehensive test scenarios and test cases',
|
|
125
|
-
sourceFile: 'qa-test-scenario.md'
|
|
126
|
-
},
|
|
127
|
-
{
|
|
128
|
-
name: 'Skill Creator',
|
|
129
|
-
value: 'skill-creator',
|
|
130
|
-
description: 'Create structured skill documentation for AI agents',
|
|
131
|
-
sourceFile: 'skill-creator.md'
|
|
132
|
-
},
|
|
133
|
-
{
|
|
134
|
-
name: 'Story (Single)',
|
|
135
|
-
value: 'story-single',
|
|
136
|
-
description: 'Generate detailed user story documentation',
|
|
137
|
-
sourceFile: 'story-single.md'
|
|
138
|
-
},
|
|
139
|
-
{
|
|
140
|
-
name: 'Story Generator',
|
|
141
|
-
value: 'story-generator',
|
|
142
|
-
description: 'Generate comprehensive user stories from EPICs and FSD',
|
|
143
|
-
sourceFile: 'story-generator.md'
|
|
144
|
-
},
|
|
145
|
-
{
|
|
146
|
-
name: 'TDD Generator',
|
|
147
|
-
value: 'tdd-generator',
|
|
148
|
-
description: 'Generate comprehensive Technical Design Document',
|
|
149
|
-
sourceFile: 'tdd-generator.md'
|
|
150
|
-
},
|
|
151
|
-
{
|
|
152
|
-
name: 'TDD-Lite Generator',
|
|
153
|
-
value: 'tdd-lite-generator',
|
|
154
|
-
description: 'Generate lean Technical Design Document (TDD-Lite)',
|
|
155
|
-
sourceFile: 'tdd-lite-generator.md'
|
|
156
|
-
},
|
|
157
|
-
{
|
|
158
|
-
name: 'Wireframe Generator',
|
|
159
|
-
value: 'wireframe-generator',
|
|
160
|
-
description: 'Generate UI/UX wireframes from technical specs',
|
|
161
|
-
sourceFile: 'wireframe-generator.md'
|
|
162
|
-
}
|
|
163
|
-
];
|
|
164
|
-
|
|
165
|
-
export class PrompterConfig {
|
|
166
|
-
static async ensurePrompterDir(projectPath: string): Promise<string> {
|
|
167
|
-
const prompterPath = path.join(projectPath, PROMPTER_DIR);
|
|
168
|
-
await fs.mkdir(prompterPath, { recursive: true });
|
|
169
|
-
return prompterPath;
|
|
170
|
-
}
|
|
171
|
-
|
|
172
|
-
static async prompterDirExists(projectPath: string): Promise<boolean> {
|
|
173
|
-
try {
|
|
174
|
-
const prompterPath = path.join(projectPath, PROMPTER_DIR);
|
|
175
|
-
await fs.access(prompterPath);
|
|
176
|
-
return true;
|
|
177
|
-
} catch {
|
|
178
|
-
return false;
|
|
179
|
-
}
|
|
180
|
-
}
|
|
181
|
-
}
|
|
@@ -1,70 +0,0 @@
|
|
|
1
|
-
import { SlashCommandConfigurator } from './base.js';
|
|
2
|
-
import { SlashCommandId } from '../../templates/index.js';
|
|
3
|
-
|
|
4
|
-
const FILE_PATHS: Record<SlashCommandId, string> = {
|
|
5
|
-
enhance: '.agent/workflows/prompter-enhance.md',
|
|
6
|
-
'prd-generator': '.agent/workflows/prd-generator.md',
|
|
7
|
-
'prd-agent-generator': '.agent/workflows/prd-agent-generator.md',
|
|
8
|
-
'product-brief': '.agent/workflows/product-brief.md',
|
|
9
|
-
'epic-single': '.agent/workflows/epic-single.md',
|
|
10
|
-
'epic-generator': '.agent/workflows/epic-generator.md',
|
|
11
|
-
'story-single': '.agent/workflows/story-single.md',
|
|
12
|
-
'story-generator': '.agent/workflows/story-generator.md',
|
|
13
|
-
'qa-test-scenario': '.agent/workflows/qa-test-scenario.md',
|
|
14
|
-
'skill-creator': '.agent/workflows/skill-creator.md',
|
|
15
|
-
'ai-humanizer': '.agent/workflows/ai-humanizer.md',
|
|
16
|
-
'api-contract-generator': '.agent/workflows/api-contract-generator.md',
|
|
17
|
-
'apply': '.agent/workflows/apply.md',
|
|
18
|
-
'archive': '.agent/workflows/archive.md',
|
|
19
|
-
'design-system': '.agent/workflows/design-system.md',
|
|
20
|
-
'erd-generator': '.agent/workflows/erd-generator.md',
|
|
21
|
-
'fsd-generator': '.agent/workflows/fsd-generator.md',
|
|
22
|
-
'proposal': '.agent/workflows/proposal.md',
|
|
23
|
-
'tdd-generator': '.agent/workflows/tdd-generator.md',
|
|
24
|
-
'tdd-lite-generator': '.agent/workflows/tdd-lite-generator.md',
|
|
25
|
-
'wireframe-generator': '.agent/workflows/wireframe-generator.md',
|
|
26
|
-
'document-explainer': '.agent/workflows/document-explainer.md'
|
|
27
|
-
};
|
|
28
|
-
|
|
29
|
-
const DESCRIPTIONS: Record<SlashCommandId, string> = {
|
|
30
|
-
enhance: 'Enhance a rough prompt into a professional specification',
|
|
31
|
-
'prd-generator': 'Generate a comprehensive Product Requirements Document (PRD)',
|
|
32
|
-
'prd-agent-generator': 'Generate a PRD with autonomous assumptions (non-interactive mode)',
|
|
33
|
-
'product-brief': 'Generate an executive-level product brief (1-page summary)',
|
|
34
|
-
'epic-single': 'Generate a single well-defined Jira Epic',
|
|
35
|
-
'epic-generator': 'Generate a comprehensive set of EPICs from documentation',
|
|
36
|
-
'story-single': 'Generate a single Jira User Story from requirements',
|
|
37
|
-
'story-generator': 'Generate comprehensive user stories from EPICs and FSD',
|
|
38
|
-
'qa-test-scenario': 'Generate focused QA test scenarios from PRD',
|
|
39
|
-
'skill-creator': 'Create a modular skill package that extends AI agent capabilities',
|
|
40
|
-
'ai-humanizer': 'Humanize and proofread AI-generated content for natural, publication-ready output',
|
|
41
|
-
'api-contract-generator': 'Generate OpenAPI specification from FSD and ERD',
|
|
42
|
-
'apply': 'Implement and apply an approved change proposal',
|
|
43
|
-
'archive': 'Archive a completed change and update specs',
|
|
44
|
-
'design-system': 'Generate comprehensive design system documentation for components and tokens',
|
|
45
|
-
'erd-generator': 'Generate Entity Relationship Diagram from FSD',
|
|
46
|
-
'fsd-generator': 'Generate Functional Specification Document from PRD',
|
|
47
|
-
'proposal': 'Create a new change proposal with spec deltas',
|
|
48
|
-
'tdd-generator': 'Generate comprehensive Technical Design Document',
|
|
49
|
-
'tdd-lite-generator': 'Generate lean Technical Design Document (TDD-Lite)',
|
|
50
|
-
'wireframe-generator': 'Generate UI/UX wireframes from technical specs',
|
|
51
|
-
'document-explainer': 'Analyze and explain complex documents into clear, actionable insights'
|
|
52
|
-
};
|
|
53
|
-
|
|
54
|
-
export class AntigravityConfigurator extends SlashCommandConfigurator {
|
|
55
|
-
readonly toolId = 'antigravity';
|
|
56
|
-
readonly isAvailable = true;
|
|
57
|
-
|
|
58
|
-
protected getRelativePath(id: SlashCommandId): string {
|
|
59
|
-
return FILE_PATHS[id];
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
protected getFrontmatter(id: SlashCommandId): string | undefined {
|
|
63
|
-
const description = DESCRIPTIONS[id];
|
|
64
|
-
return `---\ndescription: ${description}\n---`;
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
protected getSkillTargetDir(skillName: string): string {
|
|
68
|
-
return `.agent/skills/${skillName}`;
|
|
69
|
-
}
|
|
70
|
-
}
|
|
@@ -1,203 +0,0 @@
|
|
|
1
|
-
import { promises as fs } from 'fs';
|
|
2
|
-
import path from 'path';
|
|
3
|
-
import { SlashCommandId, TemplateManager } from '../../templates/index.js';
|
|
4
|
-
import { PROMPTER_MARKERS } from '../../config.js';
|
|
5
|
-
import { SkillMetadata } from '../../skill-discovery.js';
|
|
6
|
-
|
|
7
|
-
export interface SlashCommandTarget {
|
|
8
|
-
id: SlashCommandId;
|
|
9
|
-
path: string;
|
|
10
|
-
kind: 'slash';
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
export interface SkillTarget {
|
|
14
|
-
name: string;
|
|
15
|
-
path: string;
|
|
16
|
-
kind: 'skill';
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
const ALL_COMMANDS: SlashCommandId[] = ['enhance', 'prd-generator', 'prd-agent-generator', 'product-brief', 'epic-single', 'epic-generator', 'story-single', 'story-generator', 'qa-test-scenario', 'skill-creator', 'ai-humanizer', 'api-contract-generator', 'apply', 'archive', 'design-system', 'erd-generator', 'fsd-generator', 'proposal', 'tdd-generator', 'tdd-lite-generator', 'wireframe-generator', 'document-explainer'];
|
|
20
|
-
|
|
21
|
-
export abstract class SlashCommandConfigurator {
|
|
22
|
-
abstract readonly toolId: string;
|
|
23
|
-
abstract readonly isAvailable: boolean;
|
|
24
|
-
|
|
25
|
-
getTargets(filterIds?: SlashCommandId[]): SlashCommandTarget[] {
|
|
26
|
-
// If filterIds is undefined, generate all commands
|
|
27
|
-
// If filterIds is an empty array, generate nothing
|
|
28
|
-
// If filterIds has items, generate only those
|
|
29
|
-
const commandsToGenerate = filterIds === undefined
|
|
30
|
-
? ALL_COMMANDS
|
|
31
|
-
: ALL_COMMANDS.filter(id => filterIds.includes(id));
|
|
32
|
-
|
|
33
|
-
return commandsToGenerate.map((id) => ({
|
|
34
|
-
id,
|
|
35
|
-
path: this.getRelativePath(id),
|
|
36
|
-
kind: 'slash'
|
|
37
|
-
}));
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
async generateAll(projectPath: string, filterIds?: SlashCommandId[]): Promise<string[]> {
|
|
41
|
-
const createdOrUpdated: string[] = [];
|
|
42
|
-
|
|
43
|
-
for (const target of this.getTargets(filterIds)) {
|
|
44
|
-
const body = this.getBody(target.id);
|
|
45
|
-
const filePath = path.join(projectPath, target.path);
|
|
46
|
-
|
|
47
|
-
// Ensure directory exists
|
|
48
|
-
await fs.mkdir(path.dirname(filePath), { recursive: true });
|
|
49
|
-
|
|
50
|
-
if (await this.fileExists(filePath)) {
|
|
51
|
-
await this.updateBody(filePath, body);
|
|
52
|
-
} else {
|
|
53
|
-
const frontmatter = this.getFrontmatter(target.id);
|
|
54
|
-
const sections: string[] = [];
|
|
55
|
-
if (frontmatter) {
|
|
56
|
-
sections.push(frontmatter.trim());
|
|
57
|
-
}
|
|
58
|
-
sections.push(`${PROMPTER_MARKERS.start}\n${body}\n${PROMPTER_MARKERS.end}`);
|
|
59
|
-
const content = sections.join('\n') + '\n';
|
|
60
|
-
await fs.writeFile(filePath, content, 'utf-8');
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
createdOrUpdated.push(target.path);
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
return createdOrUpdated;
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
async updateExisting(projectPath: string): Promise<string[]> {
|
|
70
|
-
const updated: string[] = [];
|
|
71
|
-
|
|
72
|
-
for (const target of this.getTargets()) {
|
|
73
|
-
const filePath = path.join(projectPath, target.path);
|
|
74
|
-
if (await this.fileExists(filePath)) {
|
|
75
|
-
const body = this.getBody(target.id);
|
|
76
|
-
await this.updateBody(filePath, body);
|
|
77
|
-
updated.push(target.path);
|
|
78
|
-
}
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
return updated;
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
protected abstract getRelativePath(id: SlashCommandId): string;
|
|
85
|
-
protected abstract getFrontmatter(id: SlashCommandId): string | undefined;
|
|
86
|
-
|
|
87
|
-
/**
|
|
88
|
-
* Returns the relative directory path where the skill's full directory
|
|
89
|
-
* will be placed inside the tool's config dir.
|
|
90
|
-
* e.g. `.claude/skills/laravel-code-review`
|
|
91
|
-
*/
|
|
92
|
-
protected abstract getSkillTargetDir(skillName: string): string;
|
|
93
|
-
|
|
94
|
-
protected getBody(id: SlashCommandId): string {
|
|
95
|
-
return TemplateManager.getSlashCommandBody(id).trim();
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
// --- Skill directory management ---
|
|
99
|
-
|
|
100
|
-
getSkillTargets(skills: SkillMetadata[]): SkillTarget[] {
|
|
101
|
-
return skills.map(skill => ({
|
|
102
|
-
name: skill.name,
|
|
103
|
-
path: this.getSkillTargetDir(skill.name),
|
|
104
|
-
kind: 'skill'
|
|
105
|
-
}));
|
|
106
|
-
}
|
|
107
|
-
|
|
108
|
-
async generateSkills(projectPath: string, skills: SkillMetadata[]): Promise<string[]> {
|
|
109
|
-
const created: string[] = [];
|
|
110
|
-
|
|
111
|
-
for (const skill of skills) {
|
|
112
|
-
const targetDir = path.join(projectPath, this.getSkillTargetDir(skill.name));
|
|
113
|
-
await this.copyDir(skill.sourcePath, targetDir);
|
|
114
|
-
created.push(this.getSkillTargetDir(skill.name));
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
return created;
|
|
118
|
-
}
|
|
119
|
-
|
|
120
|
-
async updateExistingSkills(projectPath: string, skills: SkillMetadata[]): Promise<string[]> {
|
|
121
|
-
const updated: string[] = [];
|
|
122
|
-
|
|
123
|
-
for (const skill of skills) {
|
|
124
|
-
const relativeDir = this.getSkillTargetDir(skill.name);
|
|
125
|
-
const targetDir = path.join(projectPath, relativeDir);
|
|
126
|
-
|
|
127
|
-
if (await this.dirExists(targetDir)) {
|
|
128
|
-
await this.copyDir(skill.sourcePath, targetDir);
|
|
129
|
-
updated.push(relativeDir);
|
|
130
|
-
}
|
|
131
|
-
}
|
|
132
|
-
|
|
133
|
-
return updated;
|
|
134
|
-
}
|
|
135
|
-
|
|
136
|
-
async removeSkillFiles(projectPath: string, skillNames: string[]): Promise<string[]> {
|
|
137
|
-
const removed: string[] = [];
|
|
138
|
-
|
|
139
|
-
for (const name of skillNames) {
|
|
140
|
-
const relativeDir = this.getSkillTargetDir(name);
|
|
141
|
-
const targetDir = path.join(projectPath, relativeDir);
|
|
142
|
-
|
|
143
|
-
if (await this.dirExists(targetDir)) {
|
|
144
|
-
await fs.rm(targetDir, { recursive: true, force: true });
|
|
145
|
-
removed.push(relativeDir);
|
|
146
|
-
}
|
|
147
|
-
}
|
|
148
|
-
|
|
149
|
-
return removed;
|
|
150
|
-
}
|
|
151
|
-
|
|
152
|
-
private async copyDir(src: string, dest: string): Promise<void> {
|
|
153
|
-
await fs.mkdir(dest, { recursive: true });
|
|
154
|
-
const entries = await fs.readdir(src, { withFileTypes: true });
|
|
155
|
-
|
|
156
|
-
for (const entry of entries) {
|
|
157
|
-
const srcPath = path.join(src, entry.name);
|
|
158
|
-
const destPath = path.join(dest, entry.name);
|
|
159
|
-
|
|
160
|
-
if (entry.isDirectory()) {
|
|
161
|
-
await this.copyDir(srcPath, destPath);
|
|
162
|
-
} else {
|
|
163
|
-
await fs.copyFile(srcPath, destPath);
|
|
164
|
-
}
|
|
165
|
-
}
|
|
166
|
-
}
|
|
167
|
-
|
|
168
|
-
private async dirExists(dirPath: string): Promise<boolean> {
|
|
169
|
-
try {
|
|
170
|
-
const stat = await fs.stat(dirPath);
|
|
171
|
-
return stat.isDirectory();
|
|
172
|
-
} catch {
|
|
173
|
-
return false;
|
|
174
|
-
}
|
|
175
|
-
}
|
|
176
|
-
|
|
177
|
-
// --- Shared helpers ---
|
|
178
|
-
|
|
179
|
-
protected async updateBody(filePath: string, body: string): Promise<void> {
|
|
180
|
-
const content = await fs.readFile(filePath, 'utf-8');
|
|
181
|
-
const startIndex = content.indexOf(PROMPTER_MARKERS.start);
|
|
182
|
-
const endIndex = content.indexOf(PROMPTER_MARKERS.end);
|
|
183
|
-
|
|
184
|
-
if (startIndex === -1 || endIndex === -1 || endIndex <= startIndex) {
|
|
185
|
-
throw new Error(`Missing Prompter markers in ${filePath}`);
|
|
186
|
-
}
|
|
187
|
-
|
|
188
|
-
const before = content.slice(0, startIndex + PROMPTER_MARKERS.start.length);
|
|
189
|
-
const after = content.slice(endIndex);
|
|
190
|
-
const updatedContent = `${before}\n${body}\n${after}`;
|
|
191
|
-
|
|
192
|
-
await fs.writeFile(filePath, updatedContent, 'utf-8');
|
|
193
|
-
}
|
|
194
|
-
|
|
195
|
-
private async fileExists(filePath: string): Promise<boolean> {
|
|
196
|
-
try {
|
|
197
|
-
await fs.access(filePath);
|
|
198
|
-
return true;
|
|
199
|
-
} catch {
|
|
200
|
-
return false;
|
|
201
|
-
}
|
|
202
|
-
}
|
|
203
|
-
}
|