@dedesfr/prompter 0.9.0 → 1.1.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 +35 -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.map +1 -1
- package/dist/commands/init.js +35 -9
- 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 +0 -2
- package/dist/commands/update.d.ts.map +1 -1
- package/dist/commands/update.js +19 -48
- 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/config.d.ts +0 -7
- package/dist/core/config.d.ts.map +1 -1
- package/dist/core/config.js +0 -128
- package/dist/core/config.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/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/prompt-templates.d.ts +0 -23
- package/dist/core/prompt-templates.d.ts.map +0 -1
- package/dist/core/prompt-templates.js +0 -3485
- package/dist/core/prompt-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/ai-humanizer/SKILL.md +0 -50
- package/skills/api-contract-generator/SKILL.md +0 -243
- package/skills/apply/SKILL.md +0 -23
- package/skills/archive/SKILL.md +0 -27
- 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/SKILL.md +0 -216
- 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-explainer/SKILL.md +0 -155
- package/skills/document-translator/SKILL.md +0 -58
- package/skills/enhance/SKILL.md +0 -47
- 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/epic-generator/SKILL.md +0 -204
- package/skills/epic-single/SKILL.md +0 -63
- package/skills/erd-generator/SKILL.md +0 -138
- 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/fsd-generator/SKILL.md +0 -163
- 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/prd-agent-generator/SKILL.md +0 -132
- package/skills/prd-generator/SKILL.md +0 -211
- package/skills/product-brief/SKILL.md +0 -141
- 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/proposal/SKILL.md +0 -28
- package/skills/qa-test-scenario/SKILL.md +0 -149
- package/skills/skill-creator/SKILL.md +0 -173
- package/skills/sph-generator/SKILL.md +0 -488
- package/skills/story-generator/SKILL.md +0 -285
- package/skills/story-single/SKILL.md +0 -86
- package/skills/tdd-generator/SKILL.md +0 -300
- package/skills/tdd-lite-generator/SKILL.md +0 -230
- 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/skills/wireframe-generator/SKILL.md +0 -227
- 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 -597
- 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 -129
- 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 -10
- package/src/core/configurators/slash/base.ts +0 -109
- package/src/core/configurators/slash/claude.ts +0 -10
- package/src/core/configurators/slash/codex.ts +0 -10
- package/src/core/configurators/slash/droid.ts +0 -10
- package/src/core/configurators/slash/forge.ts +0 -10
- package/src/core/configurators/slash/github-copilot.ts +0 -10
- package/src/core/configurators/slash/index.ts +0 -10
- package/src/core/configurators/slash/kilocode.ts +0 -10
- package/src/core/configurators/slash/opencode.ts +0 -10
- 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 -3
- package/src/core/templates/project-template.ts +0 -32
- 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/update.ts
DELETED
|
@@ -1,129 +0,0 @@
|
|
|
1
|
-
import chalk from 'chalk';
|
|
2
|
-
import { promises as fs } from 'fs';
|
|
3
|
-
import path from 'path';
|
|
4
|
-
import { fileURLToPath } from 'url';
|
|
5
|
-
import { PrompterConfig, AVAILABLE_PROMPTS, PROMPTER_DIR } from '../core/config.js';
|
|
6
|
-
import { registry } from '../core/configurators/slash/index.js';
|
|
7
|
-
import { PROMPT_TEMPLATES } from '../core/prompt-templates.js';
|
|
8
|
-
import { discoverSkills } from '../core/skill-discovery.js';
|
|
9
|
-
|
|
10
|
-
export class UpdateCommand {
|
|
11
|
-
async execute(): Promise<void> {
|
|
12
|
-
const projectPath = process.cwd();
|
|
13
|
-
|
|
14
|
-
console.log(chalk.blue('\n🔄 Updating Prompter workflow files...\n'));
|
|
15
|
-
|
|
16
|
-
// Check if initialized
|
|
17
|
-
if (!await PrompterConfig.prompterDirExists(projectPath)) {
|
|
18
|
-
console.log(chalk.red('❌ Prompter is not initialized in this project.'));
|
|
19
|
-
console.log(chalk.gray(' Run `prompter init` first.\n'));
|
|
20
|
-
process.exitCode = 1;
|
|
21
|
-
return;
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
// Detect configured tools
|
|
25
|
-
const configuredTools = await this.detectConfiguredTools(projectPath);
|
|
26
|
-
|
|
27
|
-
if (configuredTools.length === 0) {
|
|
28
|
-
console.log(chalk.yellow('⚠️ No configured tools found.'));
|
|
29
|
-
console.log(chalk.gray(' Run `prompter init` to configure tools.\n'));
|
|
30
|
-
process.exitCode = 1;
|
|
31
|
-
return;
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
let updatedCount = 0;
|
|
35
|
-
|
|
36
|
-
// Clean up legacy slash command files and update skills for each tool
|
|
37
|
-
const packageDir = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '../..');
|
|
38
|
-
const availableSkills = await discoverSkills(path.join(packageDir, 'skills'));
|
|
39
|
-
|
|
40
|
-
for (const toolId of configuredTools) {
|
|
41
|
-
const configurator = registry.get(toolId);
|
|
42
|
-
if (!configurator) continue;
|
|
43
|
-
|
|
44
|
-
try {
|
|
45
|
-
if (availableSkills.length > 0) {
|
|
46
|
-
const updatedSkillFiles = await configurator.updateExistingSkills(projectPath, availableSkills);
|
|
47
|
-
for (const file of updatedSkillFiles) {
|
|
48
|
-
console.log(chalk.green('✓') + ` Updated ${chalk.cyan(file)}`);
|
|
49
|
-
updatedCount++;
|
|
50
|
-
}
|
|
51
|
-
}
|
|
52
|
-
} catch (error) {
|
|
53
|
-
console.log(chalk.red('✗') + ` Failed to update ${configurator.toolId}: ${error}`);
|
|
54
|
-
}
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
// Update existing prompts in prompter/core/
|
|
58
|
-
const prompterPath = path.join(projectPath, PROMPTER_DIR);
|
|
59
|
-
const updatedCorePrompts = await this.updateCorePrompts(prompterPath);
|
|
60
|
-
for (const promptName of updatedCorePrompts) {
|
|
61
|
-
console.log(chalk.green('✓') + ` Updated ${chalk.cyan(`${PROMPTER_DIR}/core/${promptName}`)}`);
|
|
62
|
-
updatedCount++;
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
if (updatedCount === 0) {
|
|
66
|
-
console.log(chalk.yellow('⚠️ No workflow files found to update.'));
|
|
67
|
-
console.log(chalk.gray(' Run `prompter init` to create them.\n'));
|
|
68
|
-
} else {
|
|
69
|
-
console.log(chalk.green(`\n✅ ${updatedCount} file(s) updated.\n`));
|
|
70
|
-
}
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
private async fileExists(filePath: string): Promise<boolean> {
|
|
74
|
-
try {
|
|
75
|
-
await fs.access(filePath);
|
|
76
|
-
return true;
|
|
77
|
-
} catch {
|
|
78
|
-
return false;
|
|
79
|
-
}
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
private async detectConfiguredTools(projectPath: string): Promise<string[]> {
|
|
83
|
-
const configuredTools: string[] = [];
|
|
84
|
-
const allConfigurators = registry.getAll();
|
|
85
|
-
|
|
86
|
-
for (const configurator of allConfigurators) {
|
|
87
|
-
const skillsRoot = path.join(projectPath, configurator.getSkillsRootDir());
|
|
88
|
-
try {
|
|
89
|
-
const stat = await fs.stat(skillsRoot);
|
|
90
|
-
if (stat.isDirectory()) configuredTools.push(configurator.toolId);
|
|
91
|
-
} catch {
|
|
92
|
-
// directory doesn't exist — tool not configured
|
|
93
|
-
}
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
return configuredTools;
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
private async updateCorePrompts(prompterPath: string): Promise<string[]> {
|
|
100
|
-
const updatedPrompts: string[] = [];
|
|
101
|
-
const corePath = path.join(prompterPath, 'core');
|
|
102
|
-
|
|
103
|
-
if (!await this.fileExists(corePath)) {
|
|
104
|
-
return updatedPrompts;
|
|
105
|
-
}
|
|
106
|
-
|
|
107
|
-
for (const prompt of AVAILABLE_PROMPTS) {
|
|
108
|
-
const promptFilePath = path.join(corePath, prompt.sourceFile);
|
|
109
|
-
|
|
110
|
-
if (await this.fileExists(promptFilePath)) {
|
|
111
|
-
try {
|
|
112
|
-
const content = PROMPT_TEMPLATES[prompt.value];
|
|
113
|
-
|
|
114
|
-
if (!content) {
|
|
115
|
-
console.log(chalk.yellow(` Warning: Template not found for ${prompt.name}`));
|
|
116
|
-
continue;
|
|
117
|
-
}
|
|
118
|
-
|
|
119
|
-
await fs.writeFile(promptFilePath, content, 'utf-8');
|
|
120
|
-
updatedPrompts.push(prompt.sourceFile);
|
|
121
|
-
} catch (error) {
|
|
122
|
-
console.log(chalk.red(` Error updating ${prompt.name}: ${error}`));
|
|
123
|
-
}
|
|
124
|
-
}
|
|
125
|
-
}
|
|
126
|
-
|
|
127
|
-
return updatedPrompts;
|
|
128
|
-
}
|
|
129
|
-
}
|
package/src/commands/upgrade.ts
DELETED
|
@@ -1,30 +0,0 @@
|
|
|
1
|
-
import { spawn } from 'child_process';
|
|
2
|
-
import chalk from 'chalk';
|
|
3
|
-
|
|
4
|
-
export class UpgradeCommand {
|
|
5
|
-
async execute(): Promise<void> {
|
|
6
|
-
console.log(chalk.cyan('\n🔄 Upgrading Prompter to the latest version...\n'));
|
|
7
|
-
|
|
8
|
-
const npmCommand = process.platform === 'win32' ? 'npm.cmd' : 'npm';
|
|
9
|
-
|
|
10
|
-
const upgrade = spawn(npmCommand, ['install', '-g', '@dedesfr/prompter@latest'], {
|
|
11
|
-
stdio: 'inherit',
|
|
12
|
-
shell: true
|
|
13
|
-
});
|
|
14
|
-
|
|
15
|
-
upgrade.on('close', (code) => {
|
|
16
|
-
if (code === 0) {
|
|
17
|
-
console.log(chalk.green('\n✓ Prompter has been upgraded successfully!\n'));
|
|
18
|
-
} else {
|
|
19
|
-
console.error(chalk.red(`\n✗ Upgrade failed with exit code ${code}\n`));
|
|
20
|
-
process.exit(code || 1);
|
|
21
|
-
}
|
|
22
|
-
});
|
|
23
|
-
|
|
24
|
-
upgrade.on('error', (error) => {
|
|
25
|
-
console.error(chalk.red('\n✗ Failed to run upgrade command:'), error.message);
|
|
26
|
-
console.log(chalk.yellow('\nPlease run manually: npm install -g @dedesfr/prompter@latest\n'));
|
|
27
|
-
process.exit(1);
|
|
28
|
-
});
|
|
29
|
-
}
|
|
30
|
-
}
|
package/src/commands/validate.ts
DELETED
|
@@ -1,326 +0,0 @@
|
|
|
1
|
-
import ora from 'ora';
|
|
2
|
-
import path from 'path';
|
|
3
|
-
import { Validator } from '../core/validation/validator.js';
|
|
4
|
-
import { isInteractive, resolveNoInteractive } from '../utils/interactive.js';
|
|
5
|
-
import { getActiveChangeIds, getSpecIds } from '../utils/item-discovery.js';
|
|
6
|
-
import { nearestMatches } from '../utils/match.js';
|
|
7
|
-
|
|
8
|
-
type ItemType = 'change' | 'spec';
|
|
9
|
-
|
|
10
|
-
interface ExecuteOptions {
|
|
11
|
-
all?: boolean;
|
|
12
|
-
changes?: boolean;
|
|
13
|
-
specs?: boolean;
|
|
14
|
-
type?: string;
|
|
15
|
-
strict?: boolean;
|
|
16
|
-
json?: boolean;
|
|
17
|
-
noInteractive?: boolean;
|
|
18
|
-
interactive?: boolean; // Commander sets this to false when --no-interactive is used
|
|
19
|
-
concurrency?: string;
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
interface BulkItemResult {
|
|
23
|
-
id: string;
|
|
24
|
-
type: ItemType;
|
|
25
|
-
valid: boolean;
|
|
26
|
-
issues: { level: 'ERROR' | 'WARNING' | 'INFO'; path: string; message: string }[];
|
|
27
|
-
durationMs: number;
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
export class ValidateCommand {
|
|
31
|
-
async execute(itemName: string | undefined, options: ExecuteOptions = {}): Promise<void> {
|
|
32
|
-
const interactive = isInteractive(options);
|
|
33
|
-
|
|
34
|
-
// Handle bulk flags first
|
|
35
|
-
if (options.all || options.changes || options.specs) {
|
|
36
|
-
await this.runBulkValidation({
|
|
37
|
-
changes: !!options.all || !!options.changes,
|
|
38
|
-
specs: !!options.all || !!options.specs,
|
|
39
|
-
}, { strict: !!options.strict, json: !!options.json, concurrency: options.concurrency, noInteractive: resolveNoInteractive(options) });
|
|
40
|
-
return;
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
// No item and no flags
|
|
44
|
-
if (!itemName) {
|
|
45
|
-
if (interactive) {
|
|
46
|
-
await this.runInteractiveSelector({ strict: !!options.strict, json: !!options.json, concurrency: options.concurrency });
|
|
47
|
-
return;
|
|
48
|
-
}
|
|
49
|
-
this.printNonInteractiveHint();
|
|
50
|
-
process.exitCode = 1;
|
|
51
|
-
return;
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
// Direct item validation with type detection or override
|
|
55
|
-
const typeOverride = this.normalizeType(options.type);
|
|
56
|
-
await this.validateDirectItem(itemName, { typeOverride, strict: !!options.strict, json: !!options.json });
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
private normalizeType(value?: string): ItemType | undefined {
|
|
60
|
-
if (!value) return undefined;
|
|
61
|
-
const v = value.toLowerCase();
|
|
62
|
-
if (v === 'change' || v === 'spec') return v;
|
|
63
|
-
return undefined;
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
private async runInteractiveSelector(opts: { strict: boolean; json: boolean; concurrency?: string }): Promise<void> {
|
|
67
|
-
const { select } = await import('@inquirer/prompts');
|
|
68
|
-
const choice = await select({
|
|
69
|
-
message: 'What would you like to validate?',
|
|
70
|
-
choices: [
|
|
71
|
-
{ name: 'All (changes + specs)', value: 'all' },
|
|
72
|
-
{ name: 'All changes', value: 'changes' },
|
|
73
|
-
{ name: 'All specs', value: 'specs' },
|
|
74
|
-
{ name: 'Pick a specific change or spec', value: 'one' },
|
|
75
|
-
],
|
|
76
|
-
});
|
|
77
|
-
|
|
78
|
-
if (choice === 'all') return this.runBulkValidation({ changes: true, specs: true }, opts);
|
|
79
|
-
if (choice === 'changes') return this.runBulkValidation({ changes: true, specs: false }, opts);
|
|
80
|
-
if (choice === 'specs') return this.runBulkValidation({ changes: false, specs: true }, opts);
|
|
81
|
-
|
|
82
|
-
// one
|
|
83
|
-
const [changes, specs] = await Promise.all([getActiveChangeIds(), getSpecIds()]);
|
|
84
|
-
const items: { name: string; value: { type: ItemType; id: string } }[] = [];
|
|
85
|
-
items.push(...changes.map(id => ({ name: `change/${id}`, value: { type: 'change' as const, id } })));
|
|
86
|
-
items.push(...specs.map(id => ({ name: `spec/${id}`, value: { type: 'spec' as const, id } })));
|
|
87
|
-
if (items.length === 0) {
|
|
88
|
-
console.error('No items found to validate.');
|
|
89
|
-
process.exitCode = 1;
|
|
90
|
-
return;
|
|
91
|
-
}
|
|
92
|
-
const picked = await select<{ type: ItemType; id: string }>({ message: 'Pick an item', choices: items });
|
|
93
|
-
await this.validateByType(picked.type, picked.id, opts);
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
private printNonInteractiveHint(): void {
|
|
97
|
-
console.error('Nothing to validate. Try one of:');
|
|
98
|
-
console.error(' prompter validate --all');
|
|
99
|
-
console.error(' prompter validate --changes');
|
|
100
|
-
console.error(' prompter validate --specs');
|
|
101
|
-
console.error(' prompter validate <item-name>');
|
|
102
|
-
console.error('Or run in an interactive terminal.');
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
private async validateDirectItem(itemName: string, opts: { typeOverride?: ItemType; strict: boolean; json: boolean }): Promise<void> {
|
|
106
|
-
const [changes, specs] = await Promise.all([getActiveChangeIds(), getSpecIds()]);
|
|
107
|
-
const isChange = changes.includes(itemName);
|
|
108
|
-
const isSpec = specs.includes(itemName);
|
|
109
|
-
|
|
110
|
-
const type = opts.typeOverride ?? (isChange ? 'change' : isSpec ? 'spec' : undefined);
|
|
111
|
-
|
|
112
|
-
if (!type) {
|
|
113
|
-
console.error(`Unknown item '${itemName}'`);
|
|
114
|
-
const suggestions = nearestMatches(itemName, [...changes, ...specs]);
|
|
115
|
-
if (suggestions.length) console.error(`Did you mean: ${suggestions.join(', ')}?`);
|
|
116
|
-
process.exitCode = 1;
|
|
117
|
-
return;
|
|
118
|
-
}
|
|
119
|
-
|
|
120
|
-
if (!opts.typeOverride && isChange && isSpec) {
|
|
121
|
-
console.error(`Ambiguous item '${itemName}' matches both a change and a spec.`);
|
|
122
|
-
console.error('Pass --type change|spec, or use: prompter change validate / prompter spec validate');
|
|
123
|
-
process.exitCode = 1;
|
|
124
|
-
return;
|
|
125
|
-
}
|
|
126
|
-
|
|
127
|
-
await this.validateByType(type, itemName, opts);
|
|
128
|
-
}
|
|
129
|
-
|
|
130
|
-
private async validateByType(type: ItemType, id: string, opts: { strict: boolean; json: boolean }): Promise<void> {
|
|
131
|
-
const validator = new Validator(opts.strict);
|
|
132
|
-
if (type === 'change') {
|
|
133
|
-
const changeDir = path.join(process.cwd(), 'prompter', 'changes', id);
|
|
134
|
-
const start = Date.now();
|
|
135
|
-
const report = await validator.validateChangeDeltaSpecs(changeDir);
|
|
136
|
-
const durationMs = Date.now() - start;
|
|
137
|
-
this.printReport('change', id, report, durationMs, opts.json);
|
|
138
|
-
// Non-zero exit if invalid (keeps enriched output test semantics)
|
|
139
|
-
process.exitCode = report.valid ? 0 : 1;
|
|
140
|
-
return;
|
|
141
|
-
}
|
|
142
|
-
const file = path.join(process.cwd(), 'prompter', 'specs', id, 'spec.md');
|
|
143
|
-
const start = Date.now();
|
|
144
|
-
const report = await validator.validateSpec(file);
|
|
145
|
-
const durationMs = Date.now() - start;
|
|
146
|
-
this.printReport('spec', id, report, durationMs, opts.json);
|
|
147
|
-
process.exitCode = report.valid ? 0 : 1;
|
|
148
|
-
}
|
|
149
|
-
|
|
150
|
-
private printReport(type: ItemType, id: string, report: { valid: boolean; issues: any[] }, durationMs: number, json: boolean): void {
|
|
151
|
-
if (json) {
|
|
152
|
-
const out = { items: [{ id, type, valid: report.valid, issues: report.issues, durationMs }], summary: { totals: { items: 1, passed: report.valid ? 1 : 0, failed: report.valid ? 0 : 1 }, byType: { [type]: { items: 1, passed: report.valid ? 1 : 0, failed: report.valid ? 0 : 1 } } }, version: '1.0' };
|
|
153
|
-
console.log(JSON.stringify(out, null, 2));
|
|
154
|
-
return;
|
|
155
|
-
}
|
|
156
|
-
if (report.valid) {
|
|
157
|
-
console.log(`${type === 'change' ? 'Change' : 'Specification'} '${id}' is valid`);
|
|
158
|
-
} else {
|
|
159
|
-
console.error(`${type === 'change' ? 'Change' : 'Specification'} '${id}' has issues`);
|
|
160
|
-
for (const issue of report.issues) {
|
|
161
|
-
const label = issue.level === 'ERROR' ? 'ERROR' : issue.level;
|
|
162
|
-
const prefix = issue.level === 'ERROR' ? '✗' : issue.level === 'WARNING' ? '⚠' : 'ℹ';
|
|
163
|
-
console.error(`${prefix} [${label}] ${issue.path}: ${issue.message}`);
|
|
164
|
-
}
|
|
165
|
-
this.printNextSteps(type);
|
|
166
|
-
}
|
|
167
|
-
}
|
|
168
|
-
|
|
169
|
-
private printNextSteps(type: ItemType): void {
|
|
170
|
-
const bullets: string[] = [];
|
|
171
|
-
if (type === 'change') {
|
|
172
|
-
bullets.push('- Ensure change has deltas in specs/: use headers ## ADDED/MODIFIED/REMOVED/RENAMED Requirements');
|
|
173
|
-
bullets.push('- Each requirement MUST include at least one #### Scenario: block');
|
|
174
|
-
bullets.push('- Debug parsed deltas: prompter change show <id> --json --deltas-only');
|
|
175
|
-
} else {
|
|
176
|
-
bullets.push('- Ensure spec includes ## Purpose and ## Requirements sections');
|
|
177
|
-
bullets.push('- Each requirement MUST include at least one #### Scenario: block');
|
|
178
|
-
bullets.push('- Re-run with --json to see structured report');
|
|
179
|
-
}
|
|
180
|
-
console.error('Next steps:');
|
|
181
|
-
bullets.forEach(b => console.error(` ${b}`));
|
|
182
|
-
}
|
|
183
|
-
|
|
184
|
-
private async runBulkValidation(scope: { changes: boolean; specs: boolean }, opts: { strict: boolean; json: boolean; concurrency?: string; noInteractive?: boolean }): Promise<void> {
|
|
185
|
-
const spinner = !opts.json && !opts.noInteractive ? ora('Validating...').start() : undefined;
|
|
186
|
-
const [changeIds, specIds] = await Promise.all([
|
|
187
|
-
scope.changes ? getActiveChangeIds() : Promise.resolve<string[]>([]),
|
|
188
|
-
scope.specs ? getSpecIds() : Promise.resolve<string[]>([]),
|
|
189
|
-
]);
|
|
190
|
-
|
|
191
|
-
const DEFAULT_CONCURRENCY = 6;
|
|
192
|
-
const maxSuggestions = 5; // used by nearestMatches
|
|
193
|
-
const concurrency = normalizeConcurrency(opts.concurrency) ?? normalizeConcurrency(process.env.PROMPTER_CONCURRENCY) ?? DEFAULT_CONCURRENCY;
|
|
194
|
-
const validator = new Validator(opts.strict);
|
|
195
|
-
const queue: Array<() => Promise<BulkItemResult>> = [];
|
|
196
|
-
|
|
197
|
-
for (const id of changeIds) {
|
|
198
|
-
queue.push(async () => {
|
|
199
|
-
const start = Date.now();
|
|
200
|
-
const changeDir = path.join(process.cwd(), 'prompter', 'changes', id);
|
|
201
|
-
const report = await validator.validateChangeDeltaSpecs(changeDir);
|
|
202
|
-
const durationMs = Date.now() - start;
|
|
203
|
-
return { id, type: 'change' as const, valid: report.valid, issues: report.issues, durationMs };
|
|
204
|
-
});
|
|
205
|
-
}
|
|
206
|
-
for (const id of specIds) {
|
|
207
|
-
queue.push(async () => {
|
|
208
|
-
const start = Date.now();
|
|
209
|
-
const file = path.join(process.cwd(), 'prompter', 'specs', id, 'spec.md');
|
|
210
|
-
const report = await validator.validateSpec(file);
|
|
211
|
-
const durationMs = Date.now() - start;
|
|
212
|
-
return { id, type: 'spec' as const, valid: report.valid, issues: report.issues, durationMs };
|
|
213
|
-
});
|
|
214
|
-
}
|
|
215
|
-
|
|
216
|
-
if (queue.length === 0) {
|
|
217
|
-
spinner?.stop();
|
|
218
|
-
|
|
219
|
-
const summary = {
|
|
220
|
-
totals: { items: 0, passed: 0, failed: 0 },
|
|
221
|
-
byType: {
|
|
222
|
-
...(scope.changes ? { change: { items: 0, passed: 0, failed: 0 } } : {}),
|
|
223
|
-
...(scope.specs ? { spec: { items: 0, passed: 0, failed: 0 } } : {}),
|
|
224
|
-
},
|
|
225
|
-
} as const;
|
|
226
|
-
|
|
227
|
-
if (opts.json) {
|
|
228
|
-
const out = { items: [] as BulkItemResult[], summary, version: '1.0' };
|
|
229
|
-
console.log(JSON.stringify(out, null, 2));
|
|
230
|
-
} else {
|
|
231
|
-
console.log('No items found to validate.');
|
|
232
|
-
}
|
|
233
|
-
|
|
234
|
-
process.exitCode = 0;
|
|
235
|
-
return;
|
|
236
|
-
}
|
|
237
|
-
|
|
238
|
-
const results: BulkItemResult[] = [];
|
|
239
|
-
let index = 0;
|
|
240
|
-
let running = 0;
|
|
241
|
-
let passed = 0;
|
|
242
|
-
let failed = 0;
|
|
243
|
-
|
|
244
|
-
await new Promise<void>((resolve) => {
|
|
245
|
-
const next = () => {
|
|
246
|
-
while (running < concurrency && index < queue.length) {
|
|
247
|
-
const currentIndex = index++;
|
|
248
|
-
const task = queue[currentIndex];
|
|
249
|
-
running++;
|
|
250
|
-
if (spinner) spinner.text = `Validating (${currentIndex + 1}/${queue.length})...`;
|
|
251
|
-
task()
|
|
252
|
-
.then(res => {
|
|
253
|
-
results.push(res);
|
|
254
|
-
if (res.valid) passed++; else failed++;
|
|
255
|
-
})
|
|
256
|
-
.catch((error: any) => {
|
|
257
|
-
const message = error?.message || 'Unknown error';
|
|
258
|
-
const res: BulkItemResult = { id: getPlannedId(currentIndex, changeIds, specIds) ?? 'unknown', type: getPlannedType(currentIndex, changeIds, specIds) ?? 'change', valid: false, issues: [{ level: 'ERROR', path: 'file', message }], durationMs: 0 };
|
|
259
|
-
results.push(res);
|
|
260
|
-
failed++;
|
|
261
|
-
})
|
|
262
|
-
.finally(() => {
|
|
263
|
-
running--;
|
|
264
|
-
if (index >= queue.length && running === 0) resolve();
|
|
265
|
-
else next();
|
|
266
|
-
});
|
|
267
|
-
}
|
|
268
|
-
};
|
|
269
|
-
next();
|
|
270
|
-
});
|
|
271
|
-
|
|
272
|
-
spinner?.stop();
|
|
273
|
-
|
|
274
|
-
results.sort((a, b) => a.id.localeCompare(b.id));
|
|
275
|
-
const summary = {
|
|
276
|
-
totals: { items: results.length, passed, failed },
|
|
277
|
-
byType: {
|
|
278
|
-
...(scope.changes ? { change: summarizeType(results, 'change') } : {}),
|
|
279
|
-
...(scope.specs ? { spec: summarizeType(results, 'spec') } : {}),
|
|
280
|
-
},
|
|
281
|
-
} as const;
|
|
282
|
-
|
|
283
|
-
if (opts.json) {
|
|
284
|
-
const out = { items: results, summary, version: '1.0' };
|
|
285
|
-
console.log(JSON.stringify(out, null, 2));
|
|
286
|
-
} else {
|
|
287
|
-
for (const res of results) {
|
|
288
|
-
if (res.valid) console.log(`✓ ${res.type}/${res.id}`);
|
|
289
|
-
else console.error(`✗ ${res.type}/${res.id}`);
|
|
290
|
-
}
|
|
291
|
-
console.log(`Totals: ${summary.totals.passed} passed, ${summary.totals.failed} failed (${summary.totals.items} items)`);
|
|
292
|
-
}
|
|
293
|
-
|
|
294
|
-
process.exitCode = failed > 0 ? 1 : 0;
|
|
295
|
-
}
|
|
296
|
-
}
|
|
297
|
-
|
|
298
|
-
function summarizeType(results: BulkItemResult[], type: ItemType) {
|
|
299
|
-
const filtered = results.filter(r => r.type === type);
|
|
300
|
-
const items = filtered.length;
|
|
301
|
-
const passed = filtered.filter(r => r.valid).length;
|
|
302
|
-
const failed = items - passed;
|
|
303
|
-
return { items, passed, failed };
|
|
304
|
-
}
|
|
305
|
-
|
|
306
|
-
function normalizeConcurrency(value?: string): number | undefined {
|
|
307
|
-
if (!value) return undefined;
|
|
308
|
-
const n = parseInt(value, 10);
|
|
309
|
-
if (Number.isNaN(n) || n <= 0) return undefined;
|
|
310
|
-
return n;
|
|
311
|
-
}
|
|
312
|
-
|
|
313
|
-
function getPlannedId(index: number, changeIds: string[], specIds: string[]): string | undefined {
|
|
314
|
-
const totalChanges = changeIds.length;
|
|
315
|
-
if (index < totalChanges) return changeIds[index];
|
|
316
|
-
const specIndex = index - totalChanges;
|
|
317
|
-
return specIds[specIndex];
|
|
318
|
-
}
|
|
319
|
-
|
|
320
|
-
function getPlannedType(index: number, changeIds: string[], specIds: string[]): ItemType | undefined {
|
|
321
|
-
const totalChanges = changeIds.length;
|
|
322
|
-
if (index < totalChanges) return 'change';
|
|
323
|
-
const specIndex = index - totalChanges;
|
|
324
|
-
if (specIndex >= 0 && specIndex < specIds.length) return 'spec';
|
|
325
|
-
return undefined;
|
|
326
|
-
}
|
|
@@ -1,167 +0,0 @@
|
|
|
1
|
-
import type { Artifact, SchemaYaml, CompletedSet, BlockedArtifacts } from './types.js';
|
|
2
|
-
import { loadSchema, parseSchema } from './schema.js';
|
|
3
|
-
|
|
4
|
-
/**
|
|
5
|
-
* Represents an artifact dependency graph.
|
|
6
|
-
* Provides methods for querying build order, ready artifacts, and completion status.
|
|
7
|
-
*/
|
|
8
|
-
export class ArtifactGraph {
|
|
9
|
-
private artifacts: Map<string, Artifact>;
|
|
10
|
-
private schema: SchemaYaml;
|
|
11
|
-
|
|
12
|
-
private constructor(schema: SchemaYaml) {
|
|
13
|
-
this.schema = schema;
|
|
14
|
-
this.artifacts = new Map(schema.artifacts.map(a => [a.id, a]));
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
/**
|
|
18
|
-
* Creates an ArtifactGraph from a YAML file path.
|
|
19
|
-
*/
|
|
20
|
-
static fromYaml(filePath: string): ArtifactGraph {
|
|
21
|
-
const schema = loadSchema(filePath);
|
|
22
|
-
return new ArtifactGraph(schema);
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
/**
|
|
26
|
-
* Creates an ArtifactGraph from YAML content string.
|
|
27
|
-
*/
|
|
28
|
-
static fromYamlContent(yamlContent: string): ArtifactGraph {
|
|
29
|
-
const schema = parseSchema(yamlContent);
|
|
30
|
-
return new ArtifactGraph(schema);
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
/**
|
|
34
|
-
* Creates an ArtifactGraph from a pre-validated schema object.
|
|
35
|
-
*/
|
|
36
|
-
static fromSchema(schema: SchemaYaml): ArtifactGraph {
|
|
37
|
-
return new ArtifactGraph(schema);
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
/**
|
|
41
|
-
* Gets a single artifact by ID.
|
|
42
|
-
*/
|
|
43
|
-
getArtifact(id: string): Artifact | undefined {
|
|
44
|
-
return this.artifacts.get(id);
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
/**
|
|
48
|
-
* Gets all artifacts in the graph.
|
|
49
|
-
*/
|
|
50
|
-
getAllArtifacts(): Artifact[] {
|
|
51
|
-
return Array.from(this.artifacts.values());
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
/**
|
|
55
|
-
* Gets the schema name.
|
|
56
|
-
*/
|
|
57
|
-
getName(): string {
|
|
58
|
-
return this.schema.name;
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
/**
|
|
62
|
-
* Gets the schema version.
|
|
63
|
-
*/
|
|
64
|
-
getVersion(): number {
|
|
65
|
-
return this.schema.version;
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
/**
|
|
69
|
-
* Computes the topological build order using Kahn's algorithm.
|
|
70
|
-
* Returns artifact IDs in the order they should be built.
|
|
71
|
-
*/
|
|
72
|
-
getBuildOrder(): string[] {
|
|
73
|
-
const inDegree = new Map<string, number>();
|
|
74
|
-
const dependents = new Map<string, string[]>();
|
|
75
|
-
|
|
76
|
-
// Initialize all artifacts
|
|
77
|
-
for (const artifact of this.artifacts.values()) {
|
|
78
|
-
inDegree.set(artifact.id, artifact.requires.length);
|
|
79
|
-
dependents.set(artifact.id, []);
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
// Build reverse adjacency (who depends on whom)
|
|
83
|
-
for (const artifact of this.artifacts.values()) {
|
|
84
|
-
for (const req of artifact.requires) {
|
|
85
|
-
dependents.get(req)!.push(artifact.id);
|
|
86
|
-
}
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
// Start with roots (in-degree 0), sorted for determinism
|
|
90
|
-
const queue = [...this.artifacts.keys()]
|
|
91
|
-
.filter(id => inDegree.get(id) === 0)
|
|
92
|
-
.sort();
|
|
93
|
-
|
|
94
|
-
const result: string[] = [];
|
|
95
|
-
|
|
96
|
-
while (queue.length > 0) {
|
|
97
|
-
const current = queue.shift()!;
|
|
98
|
-
result.push(current);
|
|
99
|
-
|
|
100
|
-
// Collect newly ready artifacts, then sort before adding
|
|
101
|
-
const newlyReady: string[] = [];
|
|
102
|
-
for (const dep of dependents.get(current)!) {
|
|
103
|
-
const newDegree = inDegree.get(dep)! - 1;
|
|
104
|
-
inDegree.set(dep, newDegree);
|
|
105
|
-
if (newDegree === 0) {
|
|
106
|
-
newlyReady.push(dep);
|
|
107
|
-
}
|
|
108
|
-
}
|
|
109
|
-
queue.push(...newlyReady.sort());
|
|
110
|
-
}
|
|
111
|
-
|
|
112
|
-
return result;
|
|
113
|
-
}
|
|
114
|
-
|
|
115
|
-
/**
|
|
116
|
-
* Gets artifacts that are ready to be created (all dependencies completed).
|
|
117
|
-
*/
|
|
118
|
-
getNextArtifacts(completed: CompletedSet): string[] {
|
|
119
|
-
const ready: string[] = [];
|
|
120
|
-
|
|
121
|
-
for (const artifact of this.artifacts.values()) {
|
|
122
|
-
if (completed.has(artifact.id)) {
|
|
123
|
-
continue; // Already completed
|
|
124
|
-
}
|
|
125
|
-
|
|
126
|
-
const allDepsCompleted = artifact.requires.every(req => completed.has(req));
|
|
127
|
-
if (allDepsCompleted) {
|
|
128
|
-
ready.push(artifact.id);
|
|
129
|
-
}
|
|
130
|
-
}
|
|
131
|
-
|
|
132
|
-
// Sort for deterministic ordering
|
|
133
|
-
return ready.sort();
|
|
134
|
-
}
|
|
135
|
-
|
|
136
|
-
/**
|
|
137
|
-
* Checks if all artifacts in the graph are completed.
|
|
138
|
-
*/
|
|
139
|
-
isComplete(completed: CompletedSet): boolean {
|
|
140
|
-
for (const artifact of this.artifacts.values()) {
|
|
141
|
-
if (!completed.has(artifact.id)) {
|
|
142
|
-
return false;
|
|
143
|
-
}
|
|
144
|
-
}
|
|
145
|
-
return true;
|
|
146
|
-
}
|
|
147
|
-
|
|
148
|
-
/**
|
|
149
|
-
* Gets blocked artifacts and their unmet dependencies.
|
|
150
|
-
*/
|
|
151
|
-
getBlocked(completed: CompletedSet): BlockedArtifacts {
|
|
152
|
-
const blocked: BlockedArtifacts = {};
|
|
153
|
-
|
|
154
|
-
for (const artifact of this.artifacts.values()) {
|
|
155
|
-
if (completed.has(artifact.id)) {
|
|
156
|
-
continue; // Already completed
|
|
157
|
-
}
|
|
158
|
-
|
|
159
|
-
const unmetDeps = artifact.requires.filter(req => !completed.has(req));
|
|
160
|
-
if (unmetDeps.length > 0) {
|
|
161
|
-
blocked[artifact.id] = unmetDeps.sort();
|
|
162
|
-
}
|
|
163
|
-
}
|
|
164
|
-
|
|
165
|
-
return blocked;
|
|
166
|
-
}
|
|
167
|
-
}
|
|
@@ -1,44 +0,0 @@
|
|
|
1
|
-
// Types
|
|
2
|
-
export {
|
|
3
|
-
ArtifactSchema,
|
|
4
|
-
SchemaYamlSchema,
|
|
5
|
-
type Artifact,
|
|
6
|
-
type SchemaYaml,
|
|
7
|
-
type CompletedSet,
|
|
8
|
-
type BlockedArtifacts,
|
|
9
|
-
} from './types.js';
|
|
10
|
-
|
|
11
|
-
// Schema loading and validation
|
|
12
|
-
export { loadSchema, parseSchema, SchemaValidationError } from './schema.js';
|
|
13
|
-
|
|
14
|
-
// Graph operations
|
|
15
|
-
export { ArtifactGraph } from './graph.js';
|
|
16
|
-
|
|
17
|
-
// State detection
|
|
18
|
-
export { detectCompleted } from './state.js';
|
|
19
|
-
|
|
20
|
-
// Schema resolution
|
|
21
|
-
export {
|
|
22
|
-
resolveSchema,
|
|
23
|
-
listSchemas,
|
|
24
|
-
listSchemasWithInfo,
|
|
25
|
-
getSchemaDir,
|
|
26
|
-
getPackageSchemasDir,
|
|
27
|
-
getUserSchemasDir,
|
|
28
|
-
SchemaLoadError,
|
|
29
|
-
type SchemaInfo,
|
|
30
|
-
} from './resolver.js';
|
|
31
|
-
|
|
32
|
-
// Instruction loading
|
|
33
|
-
export {
|
|
34
|
-
loadTemplate,
|
|
35
|
-
loadChangeContext,
|
|
36
|
-
generateInstructions,
|
|
37
|
-
formatChangeStatus,
|
|
38
|
-
TemplateLoadError,
|
|
39
|
-
type ChangeContext,
|
|
40
|
-
type ArtifactInstructions,
|
|
41
|
-
type DependencyInfo,
|
|
42
|
-
type ArtifactStatus,
|
|
43
|
-
type ChangeStatus,
|
|
44
|
-
} from './instruction-loader.js';
|