@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/commands/change.ts
DELETED
|
@@ -1,292 +0,0 @@
|
|
|
1
|
-
import { promises as fs } from 'fs';
|
|
2
|
-
import path from 'path';
|
|
3
|
-
import { JsonConverter } from '../core/converters/json-converter.js';
|
|
4
|
-
import { Validator } from '../core/validation/validator.js';
|
|
5
|
-
import { ChangeParser } from '../core/parsers/change-parser.js';
|
|
6
|
-
import { Change } from '../core/schemas/index.js';
|
|
7
|
-
import { isInteractive } from '../utils/interactive.js';
|
|
8
|
-
import { getActiveChangeIds } from '../utils/item-discovery.js';
|
|
9
|
-
|
|
10
|
-
// Constants for better maintainability
|
|
11
|
-
const ARCHIVE_DIR = 'archive';
|
|
12
|
-
const TASK_PATTERN = /^[-*]\s+\[[\sx]\]/i;
|
|
13
|
-
const COMPLETED_TASK_PATTERN = /^[-*]\s+\[x\]/i;
|
|
14
|
-
|
|
15
|
-
export class ChangeCommand {
|
|
16
|
-
private converter: JsonConverter;
|
|
17
|
-
|
|
18
|
-
constructor() {
|
|
19
|
-
this.converter = new JsonConverter();
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
/**
|
|
23
|
-
* Show a change proposal.
|
|
24
|
-
* - Text mode: raw markdown passthrough (no filters)
|
|
25
|
-
* - JSON mode: minimal object with deltas; --deltas-only returns same object with filtered deltas
|
|
26
|
-
* Note: --requirements-only is deprecated alias for --deltas-only
|
|
27
|
-
*/
|
|
28
|
-
async show(changeName?: string, options?: { json?: boolean; requirementsOnly?: boolean; deltasOnly?: boolean; noInteractive?: boolean }): Promise<void> {
|
|
29
|
-
const changesPath = path.join(process.cwd(), 'prompter', 'changes');
|
|
30
|
-
|
|
31
|
-
if (!changeName) {
|
|
32
|
-
const canPrompt = isInteractive(options);
|
|
33
|
-
const changes = await this.getActiveChanges(changesPath);
|
|
34
|
-
if (canPrompt && changes.length > 0) {
|
|
35
|
-
const { select } = await import('@inquirer/prompts');
|
|
36
|
-
const selected = await select({
|
|
37
|
-
message: 'Select a change to show',
|
|
38
|
-
choices: changes.map(id => ({ name: id, value: id })),
|
|
39
|
-
});
|
|
40
|
-
changeName = selected;
|
|
41
|
-
} else {
|
|
42
|
-
if (changes.length === 0) {
|
|
43
|
-
console.error('No change specified. No active changes found.');
|
|
44
|
-
} else {
|
|
45
|
-
console.error(`No change specified. Available IDs: ${changes.join(', ')}`);
|
|
46
|
-
}
|
|
47
|
-
console.error('Hint: use "prompter change list" to view available changes.');
|
|
48
|
-
process.exitCode = 1;
|
|
49
|
-
return;
|
|
50
|
-
}
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
const proposalPath = path.join(changesPath, changeName, 'proposal.md');
|
|
54
|
-
|
|
55
|
-
try {
|
|
56
|
-
await fs.access(proposalPath);
|
|
57
|
-
} catch {
|
|
58
|
-
throw new Error(`Change "${changeName}" not found at ${proposalPath}`);
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
if (options?.json) {
|
|
62
|
-
const jsonOutput = await this.converter.convertChangeToJson(proposalPath);
|
|
63
|
-
|
|
64
|
-
if (options.requirementsOnly) {
|
|
65
|
-
console.error('Flag --requirements-only is deprecated; use --deltas-only instead.');
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
const parsed: Change = JSON.parse(jsonOutput);
|
|
69
|
-
const contentForTitle = await fs.readFile(proposalPath, 'utf-8');
|
|
70
|
-
const title = this.extractTitle(contentForTitle, changeName);
|
|
71
|
-
const id = parsed.name;
|
|
72
|
-
const deltas = parsed.deltas || [];
|
|
73
|
-
|
|
74
|
-
if (options.requirementsOnly || options.deltasOnly) {
|
|
75
|
-
const output = { id, title, deltaCount: deltas.length, deltas };
|
|
76
|
-
console.log(JSON.stringify(output, null, 2));
|
|
77
|
-
} else {
|
|
78
|
-
const output = {
|
|
79
|
-
id,
|
|
80
|
-
title,
|
|
81
|
-
deltaCount: deltas.length,
|
|
82
|
-
deltas,
|
|
83
|
-
};
|
|
84
|
-
console.log(JSON.stringify(output, null, 2));
|
|
85
|
-
}
|
|
86
|
-
} else {
|
|
87
|
-
const content = await fs.readFile(proposalPath, 'utf-8');
|
|
88
|
-
console.log(content);
|
|
89
|
-
}
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
/**
|
|
93
|
-
* List active changes.
|
|
94
|
-
* - Text default: IDs only; --long prints minimal details (title, counts)
|
|
95
|
-
* - JSON: array of { id, title, deltaCount, taskStatus }, sorted by id
|
|
96
|
-
*/
|
|
97
|
-
async list(options?: { json?: boolean; long?: boolean }): Promise<void> {
|
|
98
|
-
const changesPath = path.join(process.cwd(), 'prompter', 'changes');
|
|
99
|
-
|
|
100
|
-
const changes = await this.getActiveChanges(changesPath);
|
|
101
|
-
|
|
102
|
-
if (options?.json) {
|
|
103
|
-
const changeDetails = await Promise.all(
|
|
104
|
-
changes.map(async (changeName) => {
|
|
105
|
-
const proposalPath = path.join(changesPath, changeName, 'proposal.md');
|
|
106
|
-
const tasksPath = path.join(changesPath, changeName, 'tasks.md');
|
|
107
|
-
|
|
108
|
-
try {
|
|
109
|
-
const content = await fs.readFile(proposalPath, 'utf-8');
|
|
110
|
-
const changeDir = path.join(changesPath, changeName);
|
|
111
|
-
const parser = new ChangeParser(content, changeDir);
|
|
112
|
-
const change = await parser.parseChangeWithDeltas(changeName);
|
|
113
|
-
|
|
114
|
-
let taskStatus = { total: 0, completed: 0 };
|
|
115
|
-
try {
|
|
116
|
-
const tasksContent = await fs.readFile(tasksPath, 'utf-8');
|
|
117
|
-
taskStatus = this.countTasks(tasksContent);
|
|
118
|
-
} catch (error) {
|
|
119
|
-
// Tasks file may not exist, which is okay
|
|
120
|
-
if (process.env.DEBUG) {
|
|
121
|
-
console.error(`Failed to read tasks file at ${tasksPath}:`, error);
|
|
122
|
-
}
|
|
123
|
-
}
|
|
124
|
-
|
|
125
|
-
return {
|
|
126
|
-
id: changeName,
|
|
127
|
-
title: this.extractTitle(content, changeName),
|
|
128
|
-
deltaCount: change.deltas.length,
|
|
129
|
-
taskStatus,
|
|
130
|
-
};
|
|
131
|
-
} catch (error) {
|
|
132
|
-
return {
|
|
133
|
-
id: changeName,
|
|
134
|
-
title: 'Unknown',
|
|
135
|
-
deltaCount: 0,
|
|
136
|
-
taskStatus: { total: 0, completed: 0 },
|
|
137
|
-
};
|
|
138
|
-
}
|
|
139
|
-
})
|
|
140
|
-
);
|
|
141
|
-
|
|
142
|
-
const sorted = changeDetails.sort((a, b) => a.id.localeCompare(b.id));
|
|
143
|
-
console.log(JSON.stringify(sorted, null, 2));
|
|
144
|
-
} else {
|
|
145
|
-
if (changes.length === 0) {
|
|
146
|
-
console.log('No items found');
|
|
147
|
-
return;
|
|
148
|
-
}
|
|
149
|
-
const sorted = [...changes].sort();
|
|
150
|
-
if (!options?.long) {
|
|
151
|
-
// IDs only
|
|
152
|
-
sorted.forEach(id => console.log(id));
|
|
153
|
-
return;
|
|
154
|
-
}
|
|
155
|
-
|
|
156
|
-
// Long format: id: title and minimal counts
|
|
157
|
-
for (const changeName of sorted) {
|
|
158
|
-
const proposalPath = path.join(changesPath, changeName, 'proposal.md');
|
|
159
|
-
const tasksPath = path.join(changesPath, changeName, 'tasks.md');
|
|
160
|
-
try {
|
|
161
|
-
const content = await fs.readFile(proposalPath, 'utf-8');
|
|
162
|
-
const title = this.extractTitle(content, changeName);
|
|
163
|
-
let taskStatusText = '';
|
|
164
|
-
try {
|
|
165
|
-
const tasksContent = await fs.readFile(tasksPath, 'utf-8');
|
|
166
|
-
const { total, completed } = this.countTasks(tasksContent);
|
|
167
|
-
taskStatusText = ` [tasks ${completed}/${total}]`;
|
|
168
|
-
} catch (error) {
|
|
169
|
-
if (process.env.DEBUG) {
|
|
170
|
-
console.error(`Failed to read tasks file at ${tasksPath}:`, error);
|
|
171
|
-
}
|
|
172
|
-
}
|
|
173
|
-
const changeDir = path.join(changesPath, changeName);
|
|
174
|
-
const parser = new ChangeParser(await fs.readFile(proposalPath, 'utf-8'), changeDir);
|
|
175
|
-
const change = await parser.parseChangeWithDeltas(changeName);
|
|
176
|
-
const deltaCountText = ` [deltas ${change.deltas.length}]`;
|
|
177
|
-
console.log(`${changeName}: ${title}${deltaCountText}${taskStatusText}`);
|
|
178
|
-
} catch {
|
|
179
|
-
console.log(`${changeName}: (unable to read)`);
|
|
180
|
-
}
|
|
181
|
-
}
|
|
182
|
-
}
|
|
183
|
-
}
|
|
184
|
-
|
|
185
|
-
async validate(changeName?: string, options?: { strict?: boolean; json?: boolean; noInteractive?: boolean }): Promise<void> {
|
|
186
|
-
const changesPath = path.join(process.cwd(), 'prompter', 'changes');
|
|
187
|
-
|
|
188
|
-
if (!changeName) {
|
|
189
|
-
const canPrompt = isInteractive(options);
|
|
190
|
-
const changes = await getActiveChangeIds();
|
|
191
|
-
if (canPrompt && changes.length > 0) {
|
|
192
|
-
const { select } = await import('@inquirer/prompts');
|
|
193
|
-
const selected = await select({
|
|
194
|
-
message: 'Select a change to validate',
|
|
195
|
-
choices: changes.map(id => ({ name: id, value: id })),
|
|
196
|
-
});
|
|
197
|
-
changeName = selected;
|
|
198
|
-
} else {
|
|
199
|
-
if (changes.length === 0) {
|
|
200
|
-
console.error('No change specified. No active changes found.');
|
|
201
|
-
} else {
|
|
202
|
-
console.error(`No change specified. Available IDs: ${changes.join(', ')}`);
|
|
203
|
-
}
|
|
204
|
-
console.error('Hint: use "prompter change list" to view available changes.');
|
|
205
|
-
process.exitCode = 1;
|
|
206
|
-
return;
|
|
207
|
-
}
|
|
208
|
-
}
|
|
209
|
-
|
|
210
|
-
const changeDir = path.join(changesPath, changeName);
|
|
211
|
-
|
|
212
|
-
try {
|
|
213
|
-
await fs.access(changeDir);
|
|
214
|
-
} catch {
|
|
215
|
-
throw new Error(`Change "${changeName}" not found at ${changeDir}`);
|
|
216
|
-
}
|
|
217
|
-
|
|
218
|
-
const validator = new Validator(options?.strict || false);
|
|
219
|
-
const report = await validator.validateChangeDeltaSpecs(changeDir);
|
|
220
|
-
|
|
221
|
-
if (options?.json) {
|
|
222
|
-
console.log(JSON.stringify(report, null, 2));
|
|
223
|
-
} else {
|
|
224
|
-
if (report.valid) {
|
|
225
|
-
console.log(`Change "${changeName}" is valid`);
|
|
226
|
-
} else {
|
|
227
|
-
console.error(`Change "${changeName}" has issues`);
|
|
228
|
-
report.issues.forEach(issue => {
|
|
229
|
-
const label = issue.level === 'ERROR' ? 'ERROR' : 'WARNING';
|
|
230
|
-
const prefix = issue.level === 'ERROR' ? '✗' : '⚠';
|
|
231
|
-
console.error(`${prefix} [${label}] ${issue.path}: ${issue.message}`);
|
|
232
|
-
});
|
|
233
|
-
// Next steps footer to guide fixing issues
|
|
234
|
-
this.printNextSteps();
|
|
235
|
-
if (!options?.json) {
|
|
236
|
-
process.exitCode = 1;
|
|
237
|
-
}
|
|
238
|
-
}
|
|
239
|
-
}
|
|
240
|
-
}
|
|
241
|
-
|
|
242
|
-
private async getActiveChanges(changesPath: string): Promise<string[]> {
|
|
243
|
-
try {
|
|
244
|
-
const entries = await fs.readdir(changesPath, { withFileTypes: true });
|
|
245
|
-
const result: string[] = [];
|
|
246
|
-
for (const entry of entries) {
|
|
247
|
-
if (!entry.isDirectory() || entry.name.startsWith('.') || entry.name === ARCHIVE_DIR) continue;
|
|
248
|
-
const proposalPath = path.join(changesPath, entry.name, 'proposal.md');
|
|
249
|
-
try {
|
|
250
|
-
await fs.access(proposalPath);
|
|
251
|
-
result.push(entry.name);
|
|
252
|
-
} catch {
|
|
253
|
-
// skip directories without proposal.md
|
|
254
|
-
}
|
|
255
|
-
}
|
|
256
|
-
return result.sort();
|
|
257
|
-
} catch {
|
|
258
|
-
return [];
|
|
259
|
-
}
|
|
260
|
-
}
|
|
261
|
-
|
|
262
|
-
private extractTitle(content: string, changeName: string): string {
|
|
263
|
-
const match = content.match(/^#\s+(?:Change:\s+)?(.+)$/im);
|
|
264
|
-
return match ? match[1].trim() : changeName;
|
|
265
|
-
}
|
|
266
|
-
|
|
267
|
-
private countTasks(content: string): { total: number; completed: number } {
|
|
268
|
-
const lines = content.split('\n');
|
|
269
|
-
let total = 0;
|
|
270
|
-
let completed = 0;
|
|
271
|
-
|
|
272
|
-
for (const line of lines) {
|
|
273
|
-
if (line.match(TASK_PATTERN)) {
|
|
274
|
-
total++;
|
|
275
|
-
if (line.match(COMPLETED_TASK_PATTERN)) {
|
|
276
|
-
completed++;
|
|
277
|
-
}
|
|
278
|
-
}
|
|
279
|
-
}
|
|
280
|
-
|
|
281
|
-
return { total, completed };
|
|
282
|
-
}
|
|
283
|
-
|
|
284
|
-
private printNextSteps(): void {
|
|
285
|
-
const bullets: string[] = [];
|
|
286
|
-
bullets.push('- Ensure change has deltas in specs/: use headers ## ADDED/MODIFIED/REMOVED/RENAMED Requirements');
|
|
287
|
-
bullets.push('- Each requirement MUST include at least one #### Scenario: block');
|
|
288
|
-
bullets.push('- Debug parsed deltas: prompter change show <id> --json --deltas-only');
|
|
289
|
-
console.error('Next steps:');
|
|
290
|
-
bullets.forEach(b => console.error(` ${b}`));
|
|
291
|
-
}
|
|
292
|
-
}
|
package/src/commands/config.ts
DELETED
|
@@ -1,233 +0,0 @@
|
|
|
1
|
-
import { Command } from 'commander';
|
|
2
|
-
import { spawn } from 'node:child_process';
|
|
3
|
-
import * as fs from 'node:fs';
|
|
4
|
-
import {
|
|
5
|
-
getGlobalConfigPath,
|
|
6
|
-
getGlobalConfig,
|
|
7
|
-
saveGlobalConfig,
|
|
8
|
-
GlobalConfig,
|
|
9
|
-
} from '../core/global-config.js';
|
|
10
|
-
import {
|
|
11
|
-
getNestedValue,
|
|
12
|
-
setNestedValue,
|
|
13
|
-
deleteNestedValue,
|
|
14
|
-
coerceValue,
|
|
15
|
-
formatValueYaml,
|
|
16
|
-
validateConfigKeyPath,
|
|
17
|
-
validateConfig,
|
|
18
|
-
DEFAULT_CONFIG,
|
|
19
|
-
} from '../core/config-schema.js';
|
|
20
|
-
|
|
21
|
-
/**
|
|
22
|
-
* Register the config command and all its subcommands.
|
|
23
|
-
*
|
|
24
|
-
* @param program - The Commander program instance
|
|
25
|
-
*/
|
|
26
|
-
export function registerConfigCommand(program: Command): void {
|
|
27
|
-
const configCmd = program
|
|
28
|
-
.command('config')
|
|
29
|
-
.description('View and modify global Prompter configuration')
|
|
30
|
-
.option('--scope <scope>', 'Config scope (only "global" supported currently)')
|
|
31
|
-
.hook('preAction', (thisCommand) => {
|
|
32
|
-
const opts = thisCommand.opts();
|
|
33
|
-
if (opts.scope && opts.scope !== 'global') {
|
|
34
|
-
console.error('Error: Project-local config is not yet implemented');
|
|
35
|
-
process.exit(1);
|
|
36
|
-
}
|
|
37
|
-
});
|
|
38
|
-
|
|
39
|
-
// config path
|
|
40
|
-
configCmd
|
|
41
|
-
.command('path')
|
|
42
|
-
.description('Show config file location')
|
|
43
|
-
.action(() => {
|
|
44
|
-
console.log(getGlobalConfigPath());
|
|
45
|
-
});
|
|
46
|
-
|
|
47
|
-
// config list
|
|
48
|
-
configCmd
|
|
49
|
-
.command('list')
|
|
50
|
-
.description('Show all current settings')
|
|
51
|
-
.option('--json', 'Output as JSON')
|
|
52
|
-
.action((options: { json?: boolean }) => {
|
|
53
|
-
const config = getGlobalConfig();
|
|
54
|
-
|
|
55
|
-
if (options.json) {
|
|
56
|
-
console.log(JSON.stringify(config, null, 2));
|
|
57
|
-
} else {
|
|
58
|
-
console.log(formatValueYaml(config));
|
|
59
|
-
}
|
|
60
|
-
});
|
|
61
|
-
|
|
62
|
-
// config get
|
|
63
|
-
configCmd
|
|
64
|
-
.command('get <key>')
|
|
65
|
-
.description('Get a specific value (raw, scriptable)')
|
|
66
|
-
.action((key: string) => {
|
|
67
|
-
const config = getGlobalConfig();
|
|
68
|
-
const value = getNestedValue(config as Record<string, unknown>, key);
|
|
69
|
-
|
|
70
|
-
if (value === undefined) {
|
|
71
|
-
process.exitCode = 1;
|
|
72
|
-
return;
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
if (typeof value === 'object' && value !== null) {
|
|
76
|
-
console.log(JSON.stringify(value));
|
|
77
|
-
} else {
|
|
78
|
-
console.log(String(value));
|
|
79
|
-
}
|
|
80
|
-
});
|
|
81
|
-
|
|
82
|
-
// config set
|
|
83
|
-
configCmd
|
|
84
|
-
.command('set <key> <value>')
|
|
85
|
-
.description('Set a value (auto-coerce types)')
|
|
86
|
-
.option('--string', 'Force value to be stored as string')
|
|
87
|
-
.option('--allow-unknown', 'Allow setting unknown keys')
|
|
88
|
-
.action((key: string, value: string, options: { string?: boolean; allowUnknown?: boolean }) => {
|
|
89
|
-
const allowUnknown = Boolean(options.allowUnknown);
|
|
90
|
-
const keyValidation = validateConfigKeyPath(key);
|
|
91
|
-
if (!keyValidation.valid && !allowUnknown) {
|
|
92
|
-
const reason = keyValidation.reason ? ` ${keyValidation.reason}.` : '';
|
|
93
|
-
console.error(`Error: Invalid configuration key "${key}".${reason}`);
|
|
94
|
-
console.error('Use "prompter config list" to see available keys.');
|
|
95
|
-
console.error('Pass --allow-unknown to bypass this check.');
|
|
96
|
-
process.exitCode = 1;
|
|
97
|
-
return;
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
const config = getGlobalConfig() as Record<string, unknown>;
|
|
101
|
-
const coercedValue = coerceValue(value, options.string || false);
|
|
102
|
-
|
|
103
|
-
// Create a copy to validate before saving
|
|
104
|
-
const newConfig = JSON.parse(JSON.stringify(config));
|
|
105
|
-
setNestedValue(newConfig, key, coercedValue);
|
|
106
|
-
|
|
107
|
-
// Validate the new config
|
|
108
|
-
const validation = validateConfig(newConfig);
|
|
109
|
-
if (!validation.success) {
|
|
110
|
-
console.error(`Error: Invalid configuration - ${validation.error}`);
|
|
111
|
-
process.exitCode = 1;
|
|
112
|
-
return;
|
|
113
|
-
}
|
|
114
|
-
|
|
115
|
-
// Apply changes and save
|
|
116
|
-
setNestedValue(config, key, coercedValue);
|
|
117
|
-
saveGlobalConfig(config as GlobalConfig);
|
|
118
|
-
|
|
119
|
-
const displayValue =
|
|
120
|
-
typeof coercedValue === 'string' ? `"${coercedValue}"` : String(coercedValue);
|
|
121
|
-
console.log(`Set ${key} = ${displayValue}`);
|
|
122
|
-
});
|
|
123
|
-
|
|
124
|
-
// config unset
|
|
125
|
-
configCmd
|
|
126
|
-
.command('unset <key>')
|
|
127
|
-
.description('Remove a key (revert to default)')
|
|
128
|
-
.action((key: string) => {
|
|
129
|
-
const config = getGlobalConfig() as Record<string, unknown>;
|
|
130
|
-
const existed = deleteNestedValue(config, key);
|
|
131
|
-
|
|
132
|
-
if (existed) {
|
|
133
|
-
saveGlobalConfig(config as GlobalConfig);
|
|
134
|
-
console.log(`Unset ${key} (reverted to default)`);
|
|
135
|
-
} else {
|
|
136
|
-
console.log(`Key "${key}" was not set`);
|
|
137
|
-
}
|
|
138
|
-
});
|
|
139
|
-
|
|
140
|
-
// config reset
|
|
141
|
-
configCmd
|
|
142
|
-
.command('reset')
|
|
143
|
-
.description('Reset configuration to defaults')
|
|
144
|
-
.option('--all', 'Reset all configuration (required)')
|
|
145
|
-
.option('-y, --yes', 'Skip confirmation prompts')
|
|
146
|
-
.action(async (options: { all?: boolean; yes?: boolean }) => {
|
|
147
|
-
if (!options.all) {
|
|
148
|
-
console.error('Error: --all flag is required for reset');
|
|
149
|
-
console.error('Usage: prompter config reset --all [-y]');
|
|
150
|
-
process.exitCode = 1;
|
|
151
|
-
return;
|
|
152
|
-
}
|
|
153
|
-
|
|
154
|
-
if (!options.yes) {
|
|
155
|
-
const { confirm } = await import('@inquirer/prompts');
|
|
156
|
-
const confirmed = await confirm({
|
|
157
|
-
message: 'Reset all configuration to defaults?',
|
|
158
|
-
default: false,
|
|
159
|
-
});
|
|
160
|
-
|
|
161
|
-
if (!confirmed) {
|
|
162
|
-
console.log('Reset cancelled.');
|
|
163
|
-
return;
|
|
164
|
-
}
|
|
165
|
-
}
|
|
166
|
-
|
|
167
|
-
saveGlobalConfig({ ...DEFAULT_CONFIG });
|
|
168
|
-
console.log('Configuration reset to defaults');
|
|
169
|
-
});
|
|
170
|
-
|
|
171
|
-
// config edit
|
|
172
|
-
configCmd
|
|
173
|
-
.command('edit')
|
|
174
|
-
.description('Open config in $EDITOR')
|
|
175
|
-
.action(async () => {
|
|
176
|
-
const editor = process.env.EDITOR || process.env.VISUAL;
|
|
177
|
-
|
|
178
|
-
if (!editor) {
|
|
179
|
-
console.error('Error: No editor configured');
|
|
180
|
-
console.error('Set the EDITOR or VISUAL environment variable to your preferred editor');
|
|
181
|
-
console.error('Example: export EDITOR=vim');
|
|
182
|
-
process.exitCode = 1;
|
|
183
|
-
return;
|
|
184
|
-
}
|
|
185
|
-
|
|
186
|
-
const configPath = getGlobalConfigPath();
|
|
187
|
-
|
|
188
|
-
// Ensure config file exists with defaults
|
|
189
|
-
if (!fs.existsSync(configPath)) {
|
|
190
|
-
saveGlobalConfig({ ...DEFAULT_CONFIG });
|
|
191
|
-
}
|
|
192
|
-
|
|
193
|
-
// Spawn editor and wait for it to close
|
|
194
|
-
// Avoid shell parsing to correctly handle paths with spaces in both
|
|
195
|
-
// the editor path and config path
|
|
196
|
-
const child = spawn(editor, [configPath], {
|
|
197
|
-
stdio: 'inherit',
|
|
198
|
-
shell: false,
|
|
199
|
-
});
|
|
200
|
-
|
|
201
|
-
await new Promise<void>((resolve, reject) => {
|
|
202
|
-
child.on('close', (code) => {
|
|
203
|
-
if (code === 0) {
|
|
204
|
-
resolve();
|
|
205
|
-
} else {
|
|
206
|
-
reject(new Error(`Editor exited with code ${code}`));
|
|
207
|
-
}
|
|
208
|
-
});
|
|
209
|
-
child.on('error', reject);
|
|
210
|
-
});
|
|
211
|
-
|
|
212
|
-
try {
|
|
213
|
-
const rawConfig = fs.readFileSync(configPath, 'utf-8');
|
|
214
|
-
const parsedConfig = JSON.parse(rawConfig);
|
|
215
|
-
const validation = validateConfig(parsedConfig);
|
|
216
|
-
|
|
217
|
-
if (!validation.success) {
|
|
218
|
-
console.error(`Error: Invalid configuration - ${validation.error}`);
|
|
219
|
-
process.exitCode = 1;
|
|
220
|
-
}
|
|
221
|
-
} catch (error) {
|
|
222
|
-
if ((error as NodeJS.ErrnoException).code === 'ENOENT') {
|
|
223
|
-
console.error(`Error: Config file not found at ${configPath}`);
|
|
224
|
-
} else if (error instanceof SyntaxError) {
|
|
225
|
-
console.error(`Error: Invalid JSON in ${configPath}`);
|
|
226
|
-
console.error(error.message);
|
|
227
|
-
} else {
|
|
228
|
-
console.error(`Error: Unable to validate configuration - ${error instanceof Error ? error.message : String(error)}`);
|
|
229
|
-
}
|
|
230
|
-
process.exitCode = 1;
|
|
231
|
-
}
|
|
232
|
-
});
|
|
233
|
-
}
|
package/src/commands/guide.ts
DELETED
|
@@ -1,50 +0,0 @@
|
|
|
1
|
-
import chalk from 'chalk';
|
|
2
|
-
|
|
3
|
-
export class GuideCommand {
|
|
4
|
-
async execute(): Promise<void> {
|
|
5
|
-
console.log(chalk.blue('\nGuides:'));
|
|
6
|
-
console.log(chalk.gray(' 1. Provide a detailed and filled-out version of the "prompter/project.md"'));
|
|
7
|
-
console.log(chalk.gray(' document based on the project\'s specifics, including a clear description'));
|
|
8
|
-
console.log(chalk.gray(' of the project, its purpose, the technologies used (tech stack), and any'));
|
|
9
|
-
console.log(chalk.gray(' conventions or standards being followed.'));
|
|
10
|
-
|
|
11
|
-
console.log(chalk.blue('\nDocument Workflow & Dependencies:'));
|
|
12
|
-
console.log(chalk.gray(' This table shows the recommended order for document generation:\n'));
|
|
13
|
-
|
|
14
|
-
// Print table header
|
|
15
|
-
console.log(chalk.cyan(' Document │ Required Inputs │ Extra Inputs │ Recommended Model'));
|
|
16
|
-
console.log(chalk.cyan(' ─────────────────┼───────────────────────────────────────┼───────────────────────────────────┼──────────────────────────'));
|
|
17
|
-
|
|
18
|
-
// Table rows
|
|
19
|
-
const rows = [
|
|
20
|
-
['Product Brief ', '— ', '— ', 'Opus'],
|
|
21
|
-
['PRD ', 'Product Brief ', '— ', 'Sonnet'],
|
|
22
|
-
['FSD ', 'PRD ', 'Product Brief ', 'Sonnet'],
|
|
23
|
-
['ERD ', 'FSD ', '— ', 'Sonnet'],
|
|
24
|
-
['API Contract ', 'FSD + ERD ', '— ', 'Sonnet / GPT 5.2 Codex'],
|
|
25
|
-
['UI Wireframes ', 'FSD + ERD + API Contract ', '— ', 'Gemini 3 Pro / Sonnet'],
|
|
26
|
-
['Design System ', 'UI Wireframes (new) / FSD (existing) ', 'Brand guide / existing UI ', 'Sonnet'],
|
|
27
|
-
['TDD ', 'FSD ', 'ERD + API + UI + Design System ', 'Sonnet'],
|
|
28
|
-
['Epics ', 'FSD + TDD-Lite ', 'UI Wireframes + Design System ', 'Sonnet'],
|
|
29
|
-
['Stories ', 'Epics ', 'FSD + UI Wireframes + API ', 'Sonnet'],
|
|
30
|
-
['Proposal ', 'Specs (FSD/TDD/etc) ', '— ', 'Opus'],
|
|
31
|
-
['Apply ', 'Approved Proposal ', '— ', 'Sonnet / Gemini 3 / GPT 5.2 / GLM / Haiku']
|
|
32
|
-
];
|
|
33
|
-
|
|
34
|
-
rows.forEach(row => {
|
|
35
|
-
console.log(chalk.gray(` ${row[0]} │ ${row[1]} │ ${row[2]} │ ${row[3]}`));
|
|
36
|
-
});
|
|
37
|
-
|
|
38
|
-
console.log(chalk.blue('\n Complexity-Based Workflows:'));
|
|
39
|
-
console.log(chalk.gray(' Small → Brief → FSD → Design System → Stories'));
|
|
40
|
-
console.log(chalk.gray(' Medium → Brief → PRD → FSD → UI → Design System → Stories'));
|
|
41
|
-
console.log(chalk.gray(' High → Brief → PRD → FSD → ERD → API → UI → Design System → TDD → Epics → Stories'));
|
|
42
|
-
|
|
43
|
-
console.log(chalk.blue('\n Prompter Solo Dev 🤓 Workflow:'));
|
|
44
|
-
console.log(chalk.green.bold(' Step 1 📄: Brief → PRD → Epic (Foundation)'));
|
|
45
|
-
console.log(chalk.green.bold(' Step 2 🚀: [ Proposal ⇄ Apply ⇄ Archive ] ↺ (Development Loop)'));
|
|
46
|
-
console.log(chalk.gray(' • Initial setup: Create Brief, PRD and Epic to establish context.'));
|
|
47
|
-
console.log(chalk.gray(' • Active Dev: Repeat Step 2 for every feature, bugfix, or improvement.'));
|
|
48
|
-
console.log(chalk.gray(' • Archive step automatically updates your specs to keep them current.'));
|
|
49
|
-
}
|
|
50
|
-
}
|