@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
package/src/utils/file-system.ts
DELETED
|
@@ -1,252 +0,0 @@
|
|
|
1
|
-
import { promises as fs, constants as fsConstants } from 'fs';
|
|
2
|
-
import path from 'path';
|
|
3
|
-
|
|
4
|
-
function isMarkerOnOwnLine(content: string, markerIndex: number, markerLength: number): boolean {
|
|
5
|
-
let leftIndex = markerIndex - 1;
|
|
6
|
-
while (leftIndex >= 0 && content[leftIndex] !== '\n') {
|
|
7
|
-
const char = content[leftIndex];
|
|
8
|
-
if (char !== ' ' && char !== '\t' && char !== '\r') {
|
|
9
|
-
return false;
|
|
10
|
-
}
|
|
11
|
-
leftIndex--;
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
let rightIndex = markerIndex + markerLength;
|
|
15
|
-
while (rightIndex < content.length && content[rightIndex] !== '\n') {
|
|
16
|
-
const char = content[rightIndex];
|
|
17
|
-
if (char !== ' ' && char !== '\t' && char !== '\r') {
|
|
18
|
-
return false;
|
|
19
|
-
}
|
|
20
|
-
rightIndex++;
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
return true;
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
function findMarkerIndex(
|
|
27
|
-
content: string,
|
|
28
|
-
marker: string,
|
|
29
|
-
fromIndex = 0
|
|
30
|
-
): number {
|
|
31
|
-
let currentIndex = content.indexOf(marker, fromIndex);
|
|
32
|
-
|
|
33
|
-
while (currentIndex !== -1) {
|
|
34
|
-
if (isMarkerOnOwnLine(content, currentIndex, marker.length)) {
|
|
35
|
-
return currentIndex;
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
currentIndex = content.indexOf(marker, currentIndex + marker.length);
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
return -1;
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
export class FileSystemUtils {
|
|
45
|
-
/**
|
|
46
|
-
* Converts a path to use forward slashes (POSIX style).
|
|
47
|
-
* Essential for cross-platform compatibility with glob libraries like fast-glob.
|
|
48
|
-
*/
|
|
49
|
-
static toPosixPath(p: string): string {
|
|
50
|
-
return p.replace(/\\/g, '/');
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
private static isWindowsBasePath(basePath: string): boolean {
|
|
54
|
-
return /^[A-Za-z]:[\\/]/.test(basePath) || basePath.startsWith('\\');
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
private static normalizeSegments(segments: string[]): string[] {
|
|
58
|
-
return segments
|
|
59
|
-
.flatMap((segment) => segment.split(/[\\/]+/u))
|
|
60
|
-
.filter((part) => part.length > 0);
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
static joinPath(basePath: string, ...segments: string[]): string {
|
|
64
|
-
const normalizedSegments = this.normalizeSegments(segments);
|
|
65
|
-
|
|
66
|
-
if (this.isWindowsBasePath(basePath)) {
|
|
67
|
-
const normalizedBasePath = path.win32.normalize(basePath);
|
|
68
|
-
return normalizedSegments.length
|
|
69
|
-
? path.win32.join(normalizedBasePath, ...normalizedSegments)
|
|
70
|
-
: normalizedBasePath;
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
const posixBasePath = basePath.replace(/\\/g, '/');
|
|
74
|
-
|
|
75
|
-
return normalizedSegments.length
|
|
76
|
-
? path.posix.join(posixBasePath, ...normalizedSegments)
|
|
77
|
-
: path.posix.normalize(posixBasePath);
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
static async createDirectory(dirPath: string): Promise<void> {
|
|
81
|
-
await fs.mkdir(dirPath, { recursive: true });
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
static async fileExists(filePath: string): Promise<boolean> {
|
|
85
|
-
try {
|
|
86
|
-
await fs.access(filePath);
|
|
87
|
-
return true;
|
|
88
|
-
} catch (error: any) {
|
|
89
|
-
if (error.code !== 'ENOENT') {
|
|
90
|
-
console.debug(`Unable to check if file exists at ${filePath}: ${error.message}`);
|
|
91
|
-
}
|
|
92
|
-
return false;
|
|
93
|
-
}
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
/**
|
|
97
|
-
* Finds the first existing parent directory by walking up the directory tree.
|
|
98
|
-
* @param dirPath Starting directory path
|
|
99
|
-
* @returns The first existing directory path, or null if root is reached without finding one
|
|
100
|
-
*/
|
|
101
|
-
private static async findFirstExistingDirectory(dirPath: string): Promise<string | null> {
|
|
102
|
-
let currentDir = dirPath;
|
|
103
|
-
|
|
104
|
-
while (true) {
|
|
105
|
-
try {
|
|
106
|
-
const stats = await fs.stat(currentDir);
|
|
107
|
-
if (stats.isDirectory()) {
|
|
108
|
-
return currentDir;
|
|
109
|
-
}
|
|
110
|
-
// Path component exists but is not a directory (edge case)
|
|
111
|
-
console.debug(`Path component ${currentDir} exists but is not a directory`);
|
|
112
|
-
return null;
|
|
113
|
-
} catch (error: any) {
|
|
114
|
-
if (error.code === 'ENOENT') {
|
|
115
|
-
// Directory doesn't exist, move up one level
|
|
116
|
-
const parentDir = path.dirname(currentDir);
|
|
117
|
-
if (parentDir === currentDir) {
|
|
118
|
-
// Reached filesystem root without finding existing directory
|
|
119
|
-
return null;
|
|
120
|
-
}
|
|
121
|
-
currentDir = parentDir;
|
|
122
|
-
} else {
|
|
123
|
-
// Unexpected error (permissions, I/O error, etc.)
|
|
124
|
-
console.debug(`Error checking directory ${currentDir}: ${error.message}`);
|
|
125
|
-
return null;
|
|
126
|
-
}
|
|
127
|
-
}
|
|
128
|
-
}
|
|
129
|
-
}
|
|
130
|
-
|
|
131
|
-
static async canWriteFile(filePath: string): Promise<boolean> {
|
|
132
|
-
try {
|
|
133
|
-
const stats = await fs.stat(filePath);
|
|
134
|
-
|
|
135
|
-
if (!stats.isFile()) {
|
|
136
|
-
return true;
|
|
137
|
-
}
|
|
138
|
-
|
|
139
|
-
// On Windows, stats.mode doesn't reliably indicate write permissions.
|
|
140
|
-
// Use fs.access with W_OK to check actual write permissions cross-platform.
|
|
141
|
-
try {
|
|
142
|
-
await fs.access(filePath, fsConstants.W_OK);
|
|
143
|
-
return true;
|
|
144
|
-
} catch {
|
|
145
|
-
return false;
|
|
146
|
-
}
|
|
147
|
-
} catch (error: any) {
|
|
148
|
-
if (error.code === 'ENOENT') {
|
|
149
|
-
// File doesn't exist - find first existing parent directory and check its permissions
|
|
150
|
-
const parentDir = path.dirname(filePath);
|
|
151
|
-
const existingDir = await this.findFirstExistingDirectory(parentDir);
|
|
152
|
-
|
|
153
|
-
if (existingDir === null) {
|
|
154
|
-
// No existing parent directory found (edge case)
|
|
155
|
-
return false;
|
|
156
|
-
}
|
|
157
|
-
|
|
158
|
-
// Check if the existing parent directory is writable
|
|
159
|
-
try {
|
|
160
|
-
await fs.access(existingDir, fsConstants.W_OK);
|
|
161
|
-
return true;
|
|
162
|
-
} catch {
|
|
163
|
-
return false;
|
|
164
|
-
}
|
|
165
|
-
}
|
|
166
|
-
|
|
167
|
-
console.debug(`Unable to determine write permissions for ${filePath}: ${error.message}`);
|
|
168
|
-
return false;
|
|
169
|
-
}
|
|
170
|
-
}
|
|
171
|
-
|
|
172
|
-
static async directoryExists(dirPath: string): Promise<boolean> {
|
|
173
|
-
try {
|
|
174
|
-
const stats = await fs.stat(dirPath);
|
|
175
|
-
return stats.isDirectory();
|
|
176
|
-
} catch (error: any) {
|
|
177
|
-
if (error.code !== 'ENOENT') {
|
|
178
|
-
console.debug(`Unable to check if directory exists at ${dirPath}: ${error.message}`);
|
|
179
|
-
}
|
|
180
|
-
return false;
|
|
181
|
-
}
|
|
182
|
-
}
|
|
183
|
-
|
|
184
|
-
static async writeFile(filePath: string, content: string): Promise<void> {
|
|
185
|
-
const dir = path.dirname(filePath);
|
|
186
|
-
await this.createDirectory(dir);
|
|
187
|
-
await fs.writeFile(filePath, content, 'utf-8');
|
|
188
|
-
}
|
|
189
|
-
|
|
190
|
-
static async readFile(filePath: string): Promise<string> {
|
|
191
|
-
return await fs.readFile(filePath, 'utf-8');
|
|
192
|
-
}
|
|
193
|
-
|
|
194
|
-
static async updateFileWithMarkers(
|
|
195
|
-
filePath: string,
|
|
196
|
-
content: string,
|
|
197
|
-
startMarker: string,
|
|
198
|
-
endMarker: string
|
|
199
|
-
): Promise<void> {
|
|
200
|
-
let existingContent = '';
|
|
201
|
-
|
|
202
|
-
if (await this.fileExists(filePath)) {
|
|
203
|
-
existingContent = await this.readFile(filePath);
|
|
204
|
-
|
|
205
|
-
const startIndex = findMarkerIndex(existingContent, startMarker);
|
|
206
|
-
const endIndex = startIndex !== -1
|
|
207
|
-
? findMarkerIndex(existingContent, endMarker, startIndex + startMarker.length)
|
|
208
|
-
: findMarkerIndex(existingContent, endMarker);
|
|
209
|
-
|
|
210
|
-
if (startIndex !== -1 && endIndex !== -1) {
|
|
211
|
-
if (endIndex < startIndex) {
|
|
212
|
-
throw new Error(
|
|
213
|
-
`Invalid marker state in ${filePath}. End marker appears before start marker.`
|
|
214
|
-
);
|
|
215
|
-
}
|
|
216
|
-
|
|
217
|
-
const before = existingContent.substring(0, startIndex);
|
|
218
|
-
const after = existingContent.substring(endIndex + endMarker.length);
|
|
219
|
-
existingContent = before + startMarker + '\n' + content + '\n' + endMarker + after;
|
|
220
|
-
} else if (startIndex === -1 && endIndex === -1) {
|
|
221
|
-
existingContent = startMarker + '\n' + content + '\n' + endMarker + '\n\n' + existingContent;
|
|
222
|
-
} else {
|
|
223
|
-
throw new Error(`Invalid marker state in ${filePath}. Found start: ${startIndex !== -1}, Found end: ${endIndex !== -1}`);
|
|
224
|
-
}
|
|
225
|
-
} else {
|
|
226
|
-
existingContent = startMarker + '\n' + content + '\n' + endMarker;
|
|
227
|
-
}
|
|
228
|
-
|
|
229
|
-
await this.writeFile(filePath, existingContent);
|
|
230
|
-
}
|
|
231
|
-
|
|
232
|
-
static async ensureWritePermissions(dirPath: string): Promise<boolean> {
|
|
233
|
-
try {
|
|
234
|
-
// If directory doesn't exist, check parent directory permissions
|
|
235
|
-
if (!await this.directoryExists(dirPath)) {
|
|
236
|
-
const parentDir = path.dirname(dirPath);
|
|
237
|
-
if (!await this.directoryExists(parentDir)) {
|
|
238
|
-
await this.createDirectory(parentDir);
|
|
239
|
-
}
|
|
240
|
-
return await this.ensureWritePermissions(parentDir);
|
|
241
|
-
}
|
|
242
|
-
|
|
243
|
-
const testFile = path.join(dirPath, '.prompter-test-' + Date.now());
|
|
244
|
-
await fs.writeFile(testFile, '');
|
|
245
|
-
await fs.unlink(testFile);
|
|
246
|
-
return true;
|
|
247
|
-
} catch (error: any) {
|
|
248
|
-
console.debug(`Insufficient permissions to write to ${dirPath}: ${error.message}`);
|
|
249
|
-
return false;
|
|
250
|
-
}
|
|
251
|
-
}
|
|
252
|
-
}
|
package/src/utils/index.ts
DELETED
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
// Shared utilities
|
|
2
|
-
export { validateChangeName, createChange } from './change-utils.js';
|
|
3
|
-
export type { ValidationResult, CreateChangeOptions } from './change-utils.js';
|
|
4
|
-
|
|
5
|
-
// Change metadata utilities
|
|
6
|
-
export {
|
|
7
|
-
readChangeMetadata,
|
|
8
|
-
writeChangeMetadata,
|
|
9
|
-
resolveSchemaForChange,
|
|
10
|
-
validateSchemaName,
|
|
11
|
-
ChangeMetadataError,
|
|
12
|
-
} from './change-metadata.js';
|
package/src/utils/interactive.ts
DELETED
|
@@ -1,29 +0,0 @@
|
|
|
1
|
-
export type InteractiveOptions = {
|
|
2
|
-
/**
|
|
3
|
-
* Explicit "disable prompts" flag passed by internal callers.
|
|
4
|
-
*/
|
|
5
|
-
noInteractive?: boolean;
|
|
6
|
-
/**
|
|
7
|
-
* Commander-style negated option: `--no-interactive` sets this to false.
|
|
8
|
-
*/
|
|
9
|
-
interactive?: boolean;
|
|
10
|
-
};
|
|
11
|
-
|
|
12
|
-
/**
|
|
13
|
-
* Resolves whether non-interactive mode is requested.
|
|
14
|
-
* Handles both explicit `noInteractive: true` and Commander.js style `interactive: false`.
|
|
15
|
-
* Use this helper instead of manually checking options.noInteractive to avoid bugs.
|
|
16
|
-
*/
|
|
17
|
-
export function resolveNoInteractive(value?: boolean | InteractiveOptions): boolean {
|
|
18
|
-
if (typeof value === 'boolean') return value;
|
|
19
|
-
return value?.noInteractive === true || value?.interactive === false;
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
export function isInteractive(value?: boolean | InteractiveOptions): boolean {
|
|
23
|
-
if (resolveNoInteractive(value)) return false;
|
|
24
|
-
if (process.env.OPEN_SPEC_INTERACTIVE === '0') return false;
|
|
25
|
-
// Respect the standard CI environment variable (set by GitHub Actions, GitLab CI, Travis, etc.)
|
|
26
|
-
if ('CI' in process.env) return false;
|
|
27
|
-
return !!process.stdin.isTTY;
|
|
28
|
-
}
|
|
29
|
-
|
|
@@ -1,66 +0,0 @@
|
|
|
1
|
-
import { promises as fs } from 'fs';
|
|
2
|
-
import path from 'path';
|
|
3
|
-
|
|
4
|
-
export async function getActiveChangeIds(root: string = process.cwd()): Promise<string[]> {
|
|
5
|
-
const changesPath = path.join(root, 'prompter', 'changes');
|
|
6
|
-
try {
|
|
7
|
-
const entries = await fs.readdir(changesPath, { withFileTypes: true });
|
|
8
|
-
const result: string[] = [];
|
|
9
|
-
for (const entry of entries) {
|
|
10
|
-
if (!entry.isDirectory() || entry.name.startsWith('.') || entry.name === 'archive') continue;
|
|
11
|
-
const proposalPath = path.join(changesPath, entry.name, 'proposal.md');
|
|
12
|
-
try {
|
|
13
|
-
await fs.access(proposalPath);
|
|
14
|
-
result.push(entry.name);
|
|
15
|
-
} catch {
|
|
16
|
-
// skip directories without proposal.md
|
|
17
|
-
}
|
|
18
|
-
}
|
|
19
|
-
return result.sort();
|
|
20
|
-
} catch {
|
|
21
|
-
return [];
|
|
22
|
-
}
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
export async function getSpecIds(root: string = process.cwd()): Promise<string[]> {
|
|
26
|
-
const specsPath = path.join(root, 'prompter', 'specs');
|
|
27
|
-
const result: string[] = [];
|
|
28
|
-
try {
|
|
29
|
-
const entries = await fs.readdir(specsPath, { withFileTypes: true });
|
|
30
|
-
for (const entry of entries) {
|
|
31
|
-
if (!entry.isDirectory() || entry.name.startsWith('.')) continue;
|
|
32
|
-
const specFile = path.join(specsPath, entry.name, 'spec.md');
|
|
33
|
-
try {
|
|
34
|
-
await fs.access(specFile);
|
|
35
|
-
result.push(entry.name);
|
|
36
|
-
} catch {
|
|
37
|
-
// ignore
|
|
38
|
-
}
|
|
39
|
-
}
|
|
40
|
-
} catch {
|
|
41
|
-
// ignore
|
|
42
|
-
}
|
|
43
|
-
return result.sort();
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
export async function getArchivedChangeIds(root: string = process.cwd()): Promise<string[]> {
|
|
47
|
-
const archivePath = path.join(root, 'prompter', 'changes', 'archive');
|
|
48
|
-
try {
|
|
49
|
-
const entries = await fs.readdir(archivePath, { withFileTypes: true });
|
|
50
|
-
const result: string[] = [];
|
|
51
|
-
for (const entry of entries) {
|
|
52
|
-
if (!entry.isDirectory() || entry.name.startsWith('.')) continue;
|
|
53
|
-
const proposalPath = path.join(archivePath, entry.name, 'proposal.md');
|
|
54
|
-
try {
|
|
55
|
-
await fs.access(proposalPath);
|
|
56
|
-
result.push(entry.name);
|
|
57
|
-
} catch {
|
|
58
|
-
// skip directories without proposal.md
|
|
59
|
-
}
|
|
60
|
-
}
|
|
61
|
-
return result.sort();
|
|
62
|
-
} catch {
|
|
63
|
-
return [];
|
|
64
|
-
}
|
|
65
|
-
}
|
|
66
|
-
|
package/src/utils/match.ts
DELETED
|
@@ -1,26 +0,0 @@
|
|
|
1
|
-
export function nearestMatches(input: string, candidates: string[], max: number = 5): string[] {
|
|
2
|
-
const scored = candidates.map(candidate => ({ candidate, distance: levenshtein(input, candidate) }));
|
|
3
|
-
scored.sort((a, b) => a.distance - b.distance);
|
|
4
|
-
return scored.slice(0, max).map(s => s.candidate);
|
|
5
|
-
}
|
|
6
|
-
|
|
7
|
-
export function levenshtein(a: string, b: string): number {
|
|
8
|
-
const m = a.length;
|
|
9
|
-
const n = b.length;
|
|
10
|
-
const dp: number[][] = Array.from({ length: m + 1 }, () => Array(n + 1).fill(0));
|
|
11
|
-
for (let i = 0; i <= m; i++) dp[i][0] = i;
|
|
12
|
-
for (let j = 0; j <= n; j++) dp[0][j] = j;
|
|
13
|
-
for (let i = 1; i <= m; i++) {
|
|
14
|
-
for (let j = 1; j <= n; j++) {
|
|
15
|
-
const cost = a[i - 1] === b[j - 1] ? 0 : 1;
|
|
16
|
-
dp[i][j] = Math.min(
|
|
17
|
-
dp[i - 1][j] + 1,
|
|
18
|
-
dp[i][j - 1] + 1,
|
|
19
|
-
dp[i - 1][j - 1] + cost
|
|
20
|
-
);
|
|
21
|
-
}
|
|
22
|
-
}
|
|
23
|
-
return dp[m][n];
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
|
|
@@ -1,62 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Supported shell types for completion generation
|
|
3
|
-
*/
|
|
4
|
-
export type SupportedShell = 'zsh' | 'bash' | 'fish' | 'powershell';
|
|
5
|
-
|
|
6
|
-
/**
|
|
7
|
-
* Result of shell detection
|
|
8
|
-
*/
|
|
9
|
-
export interface ShellDetectionResult {
|
|
10
|
-
/** The detected shell if supported, otherwise undefined */
|
|
11
|
-
shell: SupportedShell | undefined;
|
|
12
|
-
/** The raw shell name detected (even if unsupported), or undefined if nothing detected */
|
|
13
|
-
detected: string | undefined;
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
/**
|
|
17
|
-
* Detects the current user's shell based on environment variables
|
|
18
|
-
*
|
|
19
|
-
* @returns Detection result with supported shell and raw detected name
|
|
20
|
-
*/
|
|
21
|
-
export function detectShell(): ShellDetectionResult {
|
|
22
|
-
// Try SHELL environment variable first (Unix-like systems)
|
|
23
|
-
const shellPath = process.env.SHELL;
|
|
24
|
-
|
|
25
|
-
if (shellPath) {
|
|
26
|
-
const shellName = shellPath.toLowerCase();
|
|
27
|
-
|
|
28
|
-
if (shellName.includes('zsh')) {
|
|
29
|
-
return { shell: 'zsh', detected: 'zsh' };
|
|
30
|
-
}
|
|
31
|
-
if (shellName.includes('bash')) {
|
|
32
|
-
return { shell: 'bash', detected: 'bash' };
|
|
33
|
-
}
|
|
34
|
-
if (shellName.includes('fish')) {
|
|
35
|
-
return { shell: 'fish', detected: 'fish' };
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
// Shell detected but not supported
|
|
39
|
-
// Extract shell name from path (e.g., /bin/tcsh -> tcsh)
|
|
40
|
-
const match = shellPath.match(/\/([^/]+)$/);
|
|
41
|
-
const detectedName = match ? match[1] : shellPath;
|
|
42
|
-
return { shell: undefined, detected: detectedName };
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
// Check for PowerShell on Windows
|
|
46
|
-
// PSModulePath is a reliable PowerShell-specific environment variable
|
|
47
|
-
if (process.env.PSModulePath || process.platform === 'win32') {
|
|
48
|
-
const comspec = process.env.COMSPEC?.toLowerCase();
|
|
49
|
-
|
|
50
|
-
// If PSModulePath exists, we're definitely in PowerShell
|
|
51
|
-
if (process.env.PSModulePath) {
|
|
52
|
-
return { shell: 'powershell', detected: 'powershell' };
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
// On Windows without PSModulePath, we might be in cmd.exe
|
|
56
|
-
if (comspec?.includes('cmd.exe')) {
|
|
57
|
-
return { shell: undefined, detected: 'cmd.exe' };
|
|
58
|
-
}
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
return { shell: undefined, detected: undefined };
|
|
62
|
-
}
|
|
@@ -1,43 +0,0 @@
|
|
|
1
|
-
import { promises as fs } from 'fs';
|
|
2
|
-
import path from 'path';
|
|
3
|
-
|
|
4
|
-
const TASK_PATTERN = /^[-*]\s+\[[\sx]\]/i;
|
|
5
|
-
const COMPLETED_TASK_PATTERN = /^[-*]\s+\[x\]/i;
|
|
6
|
-
|
|
7
|
-
export interface TaskProgress {
|
|
8
|
-
total: number;
|
|
9
|
-
completed: number;
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
export function countTasksFromContent(content: string): TaskProgress {
|
|
13
|
-
const lines = content.split('\n');
|
|
14
|
-
let total = 0;
|
|
15
|
-
let completed = 0;
|
|
16
|
-
for (const line of lines) {
|
|
17
|
-
if (line.match(TASK_PATTERN)) {
|
|
18
|
-
total++;
|
|
19
|
-
if (line.match(COMPLETED_TASK_PATTERN)) {
|
|
20
|
-
completed++;
|
|
21
|
-
}
|
|
22
|
-
}
|
|
23
|
-
}
|
|
24
|
-
return { total, completed };
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
export async function getTaskProgressForChange(changesDir: string, changeName: string): Promise<TaskProgress> {
|
|
28
|
-
const tasksPath = path.join(changesDir, changeName, 'tasks.md');
|
|
29
|
-
try {
|
|
30
|
-
const content = await fs.readFile(tasksPath, 'utf-8');
|
|
31
|
-
return countTasksFromContent(content);
|
|
32
|
-
} catch {
|
|
33
|
-
return { total: 0, completed: 0 };
|
|
34
|
-
}
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
export function formatTaskStatus(progress: TaskProgress): string {
|
|
38
|
-
if (progress.total === 0) return 'No tasks';
|
|
39
|
-
if (progress.completed === progress.total) return '✓ Complete';
|
|
40
|
-
return `${progress.completed}/${progress.total} tasks`;
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
|
package/tsconfig.json
DELETED
|
@@ -1,28 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"compilerOptions": {
|
|
3
|
-
"target": "ES2022",
|
|
4
|
-
"module": "NodeNext",
|
|
5
|
-
"moduleResolution": "NodeNext",
|
|
6
|
-
"lib": [
|
|
7
|
-
"ES2022"
|
|
8
|
-
],
|
|
9
|
-
"outDir": "./dist",
|
|
10
|
-
"rootDir": "./src",
|
|
11
|
-
"strict": true,
|
|
12
|
-
"esModuleInterop": true,
|
|
13
|
-
"skipLibCheck": true,
|
|
14
|
-
"forceConsistentCasingInFileNames": true,
|
|
15
|
-
"resolveJsonModule": true,
|
|
16
|
-
"declaration": true,
|
|
17
|
-
"declarationMap": true,
|
|
18
|
-
"sourceMap": true
|
|
19
|
-
},
|
|
20
|
-
"include": [
|
|
21
|
-
"src/**/*"
|
|
22
|
-
],
|
|
23
|
-
"exclude": [
|
|
24
|
-
"node_modules",
|
|
25
|
-
"dist",
|
|
26
|
-
"test"
|
|
27
|
-
]
|
|
28
|
-
}
|