gmc-openspec 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/LICENSE +22 -0
- package/README.md +207 -0
- package/bin/openspec.js +3 -0
- package/dist/cli/index.d.ts +2 -0
- package/dist/cli/index.js +494 -0
- package/dist/commands/change.d.ts +35 -0
- package/dist/commands/change.js +277 -0
- package/dist/commands/completion.d.ts +72 -0
- package/dist/commands/completion.js +264 -0
- package/dist/commands/config.d.ts +36 -0
- package/dist/commands/config.js +611 -0
- package/dist/commands/feedback.d.ts +9 -0
- package/dist/commands/feedback.js +183 -0
- package/dist/commands/jira.d.ts +3 -0
- package/dist/commands/jira.js +249 -0
- package/dist/commands/schema.d.ts +6 -0
- package/dist/commands/schema.js +869 -0
- package/dist/commands/show.d.ts +14 -0
- package/dist/commands/show.js +132 -0
- package/dist/commands/spec.d.ts +15 -0
- package/dist/commands/spec.js +225 -0
- package/dist/commands/validate.d.ts +24 -0
- package/dist/commands/validate.js +294 -0
- package/dist/commands/workflow/index.d.ts +17 -0
- package/dist/commands/workflow/index.js +12 -0
- package/dist/commands/workflow/instructions.d.ts +29 -0
- package/dist/commands/workflow/instructions.js +336 -0
- package/dist/commands/workflow/new-change.d.ts +13 -0
- package/dist/commands/workflow/new-change.js +92 -0
- package/dist/commands/workflow/schemas.d.ts +10 -0
- package/dist/commands/workflow/schemas.js +34 -0
- package/dist/commands/workflow/shared.d.ts +57 -0
- package/dist/commands/workflow/shared.js +116 -0
- package/dist/commands/workflow/status.d.ts +14 -0
- package/dist/commands/workflow/status.js +87 -0
- package/dist/commands/workflow/templates.d.ts +16 -0
- package/dist/commands/workflow/templates.js +69 -0
- package/dist/commands/workspace/open.d.ts +29 -0
- package/dist/commands/workspace/open.js +84 -0
- package/dist/commands/workspace/operations.d.ts +23 -0
- package/dist/commands/workspace/operations.js +475 -0
- package/dist/commands/workspace/selection.d.ts +6 -0
- package/dist/commands/workspace/selection.js +113 -0
- package/dist/commands/workspace/types.d.ts +88 -0
- package/dist/commands/workspace/types.js +36 -0
- package/dist/commands/workspace.d.ts +6 -0
- package/dist/commands/workspace.js +868 -0
- package/dist/core/archive.d.ts +11 -0
- package/dist/core/archive.js +318 -0
- package/dist/core/artifact-graph/graph.d.ts +56 -0
- package/dist/core/artifact-graph/graph.js +141 -0
- package/dist/core/artifact-graph/index.d.ts +8 -0
- package/dist/core/artifact-graph/index.js +14 -0
- package/dist/core/artifact-graph/instruction-loader.d.ts +196 -0
- package/dist/core/artifact-graph/instruction-loader.js +317 -0
- package/dist/core/artifact-graph/outputs.d.ts +14 -0
- package/dist/core/artifact-graph/outputs.js +39 -0
- package/dist/core/artifact-graph/resolver.d.ts +81 -0
- package/dist/core/artifact-graph/resolver.js +257 -0
- package/dist/core/artifact-graph/schema.d.ts +13 -0
- package/dist/core/artifact-graph/schema.js +108 -0
- package/dist/core/artifact-graph/state.d.ts +12 -0
- package/dist/core/artifact-graph/state.js +31 -0
- package/dist/core/artifact-graph/types.d.ts +47 -0
- package/dist/core/artifact-graph/types.js +48 -0
- package/dist/core/available-tools.d.ts +17 -0
- package/dist/core/available-tools.js +43 -0
- package/dist/core/command-generation/adapters/amazon-q.d.ts +13 -0
- package/dist/core/command-generation/adapters/amazon-q.js +26 -0
- package/dist/core/command-generation/adapters/antigravity.d.ts +13 -0
- package/dist/core/command-generation/adapters/antigravity.js +26 -0
- package/dist/core/command-generation/adapters/auggie.d.ts +13 -0
- package/dist/core/command-generation/adapters/auggie.js +27 -0
- package/dist/core/command-generation/adapters/bob.d.ts +14 -0
- package/dist/core/command-generation/adapters/bob.js +45 -0
- package/dist/core/command-generation/adapters/claude.d.ts +13 -0
- package/dist/core/command-generation/adapters/claude.js +50 -0
- package/dist/core/command-generation/adapters/cline.d.ts +14 -0
- package/dist/core/command-generation/adapters/cline.js +27 -0
- package/dist/core/command-generation/adapters/codebuddy.d.ts +13 -0
- package/dist/core/command-generation/adapters/codebuddy.js +28 -0
- package/dist/core/command-generation/adapters/codex.d.ts +16 -0
- package/dist/core/command-generation/adapters/codex.js +39 -0
- package/dist/core/command-generation/adapters/continue.d.ts +13 -0
- package/dist/core/command-generation/adapters/continue.js +28 -0
- package/dist/core/command-generation/adapters/costrict.d.ts +13 -0
- package/dist/core/command-generation/adapters/costrict.js +27 -0
- package/dist/core/command-generation/adapters/crush.d.ts +13 -0
- package/dist/core/command-generation/adapters/crush.js +30 -0
- package/dist/core/command-generation/adapters/cursor.d.ts +14 -0
- package/dist/core/command-generation/adapters/cursor.js +44 -0
- package/dist/core/command-generation/adapters/factory.d.ts +13 -0
- package/dist/core/command-generation/adapters/factory.js +27 -0
- package/dist/core/command-generation/adapters/gemini.d.ts +13 -0
- package/dist/core/command-generation/adapters/gemini.js +26 -0
- package/dist/core/command-generation/adapters/github-copilot.d.ts +13 -0
- package/dist/core/command-generation/adapters/github-copilot.js +26 -0
- package/dist/core/command-generation/adapters/iflow.d.ts +13 -0
- package/dist/core/command-generation/adapters/iflow.js +29 -0
- package/dist/core/command-generation/adapters/index.d.ts +32 -0
- package/dist/core/command-generation/adapters/index.js +32 -0
- package/dist/core/command-generation/adapters/junie.d.ts +13 -0
- package/dist/core/command-generation/adapters/junie.js +26 -0
- package/dist/core/command-generation/adapters/kilocode.d.ts +14 -0
- package/dist/core/command-generation/adapters/kilocode.js +23 -0
- package/dist/core/command-generation/adapters/kiro.d.ts +13 -0
- package/dist/core/command-generation/adapters/kiro.js +26 -0
- package/dist/core/command-generation/adapters/lingma.d.ts +13 -0
- package/dist/core/command-generation/adapters/lingma.js +30 -0
- package/dist/core/command-generation/adapters/opencode.d.ts +13 -0
- package/dist/core/command-generation/adapters/opencode.js +29 -0
- package/dist/core/command-generation/adapters/pi.d.ts +18 -0
- package/dist/core/command-generation/adapters/pi.js +55 -0
- package/dist/core/command-generation/adapters/qoder.d.ts +13 -0
- package/dist/core/command-generation/adapters/qoder.js +30 -0
- package/dist/core/command-generation/adapters/qwen.d.ts +13 -0
- package/dist/core/command-generation/adapters/qwen.js +26 -0
- package/dist/core/command-generation/adapters/roocode.d.ts +14 -0
- package/dist/core/command-generation/adapters/roocode.js +27 -0
- package/dist/core/command-generation/adapters/windsurf.d.ts +14 -0
- package/dist/core/command-generation/adapters/windsurf.js +51 -0
- package/dist/core/command-generation/generator.d.ts +21 -0
- package/dist/core/command-generation/generator.js +27 -0
- package/dist/core/command-generation/index.d.ts +22 -0
- package/dist/core/command-generation/index.js +24 -0
- package/dist/core/command-generation/registry.d.ts +36 -0
- package/dist/core/command-generation/registry.js +98 -0
- package/dist/core/command-generation/types.d.ts +56 -0
- package/dist/core/command-generation/types.js +8 -0
- package/dist/core/completions/command-registry.d.ts +7 -0
- package/dist/core/completions/command-registry.js +626 -0
- package/dist/core/completions/completion-provider.d.ts +71 -0
- package/dist/core/completions/completion-provider.js +129 -0
- package/dist/core/completions/factory.d.ts +64 -0
- package/dist/core/completions/factory.js +75 -0
- package/dist/core/completions/generators/bash-generator.d.ts +35 -0
- package/dist/core/completions/generators/bash-generator.js +230 -0
- package/dist/core/completions/generators/fish-generator.d.ts +32 -0
- package/dist/core/completions/generators/fish-generator.js +160 -0
- package/dist/core/completions/generators/powershell-generator.d.ts +36 -0
- package/dist/core/completions/generators/powershell-generator.js +266 -0
- package/dist/core/completions/generators/zsh-generator.d.ts +47 -0
- package/dist/core/completions/generators/zsh-generator.js +274 -0
- package/dist/core/completions/installers/bash-installer.d.ts +87 -0
- package/dist/core/completions/installers/bash-installer.js +318 -0
- package/dist/core/completions/installers/fish-installer.d.ts +43 -0
- package/dist/core/completions/installers/fish-installer.js +143 -0
- package/dist/core/completions/installers/powershell-installer.d.ts +102 -0
- package/dist/core/completions/installers/powershell-installer.js +387 -0
- package/dist/core/completions/installers/zsh-installer.d.ts +117 -0
- package/dist/core/completions/installers/zsh-installer.js +421 -0
- package/dist/core/completions/templates/bash-templates.d.ts +6 -0
- package/dist/core/completions/templates/bash-templates.js +30 -0
- package/dist/core/completions/templates/fish-templates.d.ts +7 -0
- package/dist/core/completions/templates/fish-templates.js +45 -0
- package/dist/core/completions/templates/powershell-templates.d.ts +6 -0
- package/dist/core/completions/templates/powershell-templates.js +34 -0
- package/dist/core/completions/templates/zsh-templates.d.ts +6 -0
- package/dist/core/completions/templates/zsh-templates.js +45 -0
- package/dist/core/completions/types.d.ts +101 -0
- package/dist/core/completions/types.js +2 -0
- package/dist/core/config-prompts.d.ts +9 -0
- package/dist/core/config-prompts.js +34 -0
- package/dist/core/config-schema.d.ts +86 -0
- package/dist/core/config-schema.js +213 -0
- package/dist/core/config.d.ts +18 -0
- package/dist/core/config.js +38 -0
- package/dist/core/converters/json-converter.d.ts +6 -0
- package/dist/core/converters/json-converter.js +51 -0
- package/dist/core/global-config.d.ts +49 -0
- package/dist/core/global-config.js +124 -0
- package/dist/core/index.d.ts +5 -0
- package/dist/core/index.js +6 -0
- package/dist/core/init.d.ts +37 -0
- package/dist/core/init.js +593 -0
- package/dist/core/jira/config.d.ts +35 -0
- package/dist/core/jira/config.js +151 -0
- package/dist/core/jira/constants.d.ts +20 -0
- package/dist/core/jira/constants.js +49 -0
- package/dist/core/jira/doctor.d.ts +19 -0
- package/dist/core/jira/doctor.js +173 -0
- package/dist/core/jira/hash.d.ts +3 -0
- package/dist/core/jira/hash.js +9 -0
- package/dist/core/jira/index.d.ts +11 -0
- package/dist/core/jira/index.js +11 -0
- package/dist/core/jira/intake.d.ts +40 -0
- package/dist/core/jira/intake.js +54 -0
- package/dist/core/jira/mcp-config.d.ts +13 -0
- package/dist/core/jira/mcp-config.js +259 -0
- package/dist/core/jira/paths.d.ts +12 -0
- package/dist/core/jira/paths.js +66 -0
- package/dist/core/jira/setup.d.ts +30 -0
- package/dist/core/jira/setup.js +99 -0
- package/dist/core/jira/templates.d.ts +12 -0
- package/dist/core/jira/templates.js +204 -0
- package/dist/core/jira/validation.d.ts +17 -0
- package/dist/core/jira/validation.js +341 -0
- package/dist/core/legacy-cleanup.d.ts +162 -0
- package/dist/core/legacy-cleanup.js +514 -0
- package/dist/core/list.d.ts +9 -0
- package/dist/core/list.js +171 -0
- package/dist/core/migration.d.ts +23 -0
- package/dist/core/migration.js +108 -0
- package/dist/core/parsers/change-parser.d.ts +13 -0
- package/dist/core/parsers/change-parser.js +197 -0
- package/dist/core/parsers/markdown-parser.d.ts +26 -0
- package/dist/core/parsers/markdown-parser.js +227 -0
- package/dist/core/parsers/requirement-blocks.d.ts +37 -0
- package/dist/core/parsers/requirement-blocks.js +201 -0
- package/dist/core/parsers/spec-structure.d.ts +9 -0
- package/dist/core/parsers/spec-structure.js +88 -0
- package/dist/core/planning-home.d.ts +21 -0
- package/dist/core/planning-home.js +124 -0
- package/dist/core/profile-sync-drift.d.ts +38 -0
- package/dist/core/profile-sync-drift.js +200 -0
- package/dist/core/profiles.d.ts +26 -0
- package/dist/core/profiles.js +40 -0
- package/dist/core/project-config.d.ts +64 -0
- package/dist/core/project-config.js +223 -0
- package/dist/core/schemas/base.schema.d.ts +13 -0
- package/dist/core/schemas/base.schema.js +13 -0
- package/dist/core/schemas/change.schema.d.ts +73 -0
- package/dist/core/schemas/change.schema.js +31 -0
- package/dist/core/schemas/index.d.ts +4 -0
- package/dist/core/schemas/index.js +4 -0
- package/dist/core/schemas/spec.schema.d.ts +18 -0
- package/dist/core/schemas/spec.schema.js +15 -0
- package/dist/core/shared/index.d.ts +8 -0
- package/dist/core/shared/index.js +8 -0
- package/dist/core/shared/skill-generation.d.ts +49 -0
- package/dist/core/shared/skill-generation.js +96 -0
- package/dist/core/shared/tool-detection.d.ts +71 -0
- package/dist/core/shared/tool-detection.js +158 -0
- package/dist/core/specs-apply.d.ts +73 -0
- package/dist/core/specs-apply.js +392 -0
- package/dist/core/styles/palette.d.ts +7 -0
- package/dist/core/styles/palette.js +8 -0
- package/dist/core/templates/index.d.ts +8 -0
- package/dist/core/templates/index.js +9 -0
- package/dist/core/templates/skill-templates.d.ts +19 -0
- package/dist/core/templates/skill-templates.js +18 -0
- package/dist/core/templates/types.d.ts +19 -0
- package/dist/core/templates/types.js +5 -0
- package/dist/core/templates/workflows/apply-change.d.ts +10 -0
- package/dist/core/templates/workflows/apply-change.js +314 -0
- package/dist/core/templates/workflows/archive-change.d.ts +10 -0
- package/dist/core/templates/workflows/archive-change.js +277 -0
- package/dist/core/templates/workflows/bulk-archive-change.d.ts +10 -0
- package/dist/core/templates/workflows/bulk-archive-change.js +492 -0
- package/dist/core/templates/workflows/continue-change.d.ts +10 -0
- package/dist/core/templates/workflows/continue-change.js +234 -0
- package/dist/core/templates/workflows/explore.d.ts +10 -0
- package/dist/core/templates/workflows/explore.js +459 -0
- package/dist/core/templates/workflows/feedback.d.ts +9 -0
- package/dist/core/templates/workflows/feedback.js +108 -0
- package/dist/core/templates/workflows/ff-change.d.ts +10 -0
- package/dist/core/templates/workflows/ff-change.js +200 -0
- package/dist/core/templates/workflows/new-change.d.ts +10 -0
- package/dist/core/templates/workflows/new-change.js +143 -0
- package/dist/core/templates/workflows/onboard.d.ts +10 -0
- package/dist/core/templates/workflows/onboard.js +563 -0
- package/dist/core/templates/workflows/propose.d.ts +10 -0
- package/dist/core/templates/workflows/propose.js +218 -0
- package/dist/core/templates/workflows/sync-specs.d.ts +10 -0
- package/dist/core/templates/workflows/sync-specs.js +290 -0
- package/dist/core/templates/workflows/verify-change.d.ts +10 -0
- package/dist/core/templates/workflows/verify-change.js +338 -0
- package/dist/core/update.d.ts +83 -0
- package/dist/core/update.js +573 -0
- package/dist/core/validation/constants.d.ts +34 -0
- package/dist/core/validation/constants.js +40 -0
- package/dist/core/validation/types.d.ts +18 -0
- package/dist/core/validation/types.js +2 -0
- package/dist/core/validation/validator.d.ts +33 -0
- package/dist/core/validation/validator.js +418 -0
- package/dist/core/view.d.ts +8 -0
- package/dist/core/view.js +168 -0
- package/dist/core/workspace/foundation.d.ts +87 -0
- package/dist/core/workspace/foundation.js +379 -0
- package/dist/core/workspace/index.d.ts +6 -0
- package/dist/core/workspace/index.js +6 -0
- package/dist/core/workspace/link-input.d.ts +9 -0
- package/dist/core/workspace/link-input.js +32 -0
- package/dist/core/workspace/open-surface.d.ts +24 -0
- package/dist/core/workspace/open-surface.js +137 -0
- package/dist/core/workspace/openers.d.ts +21 -0
- package/dist/core/workspace/openers.js +119 -0
- package/dist/core/workspace/skills.d.ts +55 -0
- package/dist/core/workspace/skills.js +334 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.js +3 -0
- package/dist/prompts/searchable-multi-select.d.ts +28 -0
- package/dist/prompts/searchable-multi-select.js +159 -0
- package/dist/telemetry/config.d.ts +38 -0
- package/dist/telemetry/config.js +136 -0
- package/dist/telemetry/index.d.ts +31 -0
- package/dist/telemetry/index.js +164 -0
- package/dist/ui/ascii-patterns.d.ts +16 -0
- package/dist/ui/ascii-patterns.js +133 -0
- package/dist/ui/welcome-screen.d.ts +10 -0
- package/dist/ui/welcome-screen.js +146 -0
- package/dist/utils/change-metadata.d.ts +51 -0
- package/dist/utils/change-metadata.js +147 -0
- package/dist/utils/change-utils.d.ts +71 -0
- package/dist/utils/change-utils.js +123 -0
- package/dist/utils/command-references.d.ts +18 -0
- package/dist/utils/command-references.js +20 -0
- package/dist/utils/file-system.d.ts +41 -0
- package/dist/utils/file-system.js +301 -0
- package/dist/utils/index.d.ts +6 -0
- package/dist/utils/index.js +9 -0
- package/dist/utils/interactive.d.ts +18 -0
- package/dist/utils/interactive.js +21 -0
- package/dist/utils/item-discovery.d.ts +4 -0
- package/dist/utils/item-discovery.js +72 -0
- package/dist/utils/match.d.ts +3 -0
- package/dist/utils/match.js +22 -0
- package/dist/utils/shell-detection.d.ts +20 -0
- package/dist/utils/shell-detection.js +41 -0
- package/dist/utils/task-progress.d.ts +8 -0
- package/dist/utils/task-progress.js +36 -0
- package/package.json +79 -0
- package/schemas/spec-driven/schema.yaml +153 -0
- package/schemas/spec-driven/templates/design.md +19 -0
- package/schemas/spec-driven/templates/proposal.md +23 -0
- package/schemas/spec-driven/templates/spec.md +8 -0
- package/schemas/spec-driven/templates/tasks.md +9 -0
- package/schemas/workspace-planning/schema.yaml +72 -0
- package/schemas/workspace-planning/templates/design.md +33 -0
- package/schemas/workspace-planning/templates/proposal.md +28 -0
- package/schemas/workspace-planning/templates/spec.md +9 -0
- package/schemas/workspace-planning/templates/tasks.md +15 -0
- package/scripts/postinstall.js +83 -0
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { type JiraValidationStage } from './constants.js';
|
|
2
|
+
export interface JiraValidationIssue {
|
|
3
|
+
code: string;
|
|
4
|
+
message: string;
|
|
5
|
+
file?: string;
|
|
6
|
+
}
|
|
7
|
+
export interface JiraValidationReport {
|
|
8
|
+
ok: boolean;
|
|
9
|
+
jira: string;
|
|
10
|
+
stage: JiraValidationStage;
|
|
11
|
+
issueDir: string;
|
|
12
|
+
status?: string;
|
|
13
|
+
errors: JiraValidationIssue[];
|
|
14
|
+
warnings: JiraValidationIssue[];
|
|
15
|
+
}
|
|
16
|
+
export declare function validateJiraIntake(projectRoot: string, jiraId: string, stage: JiraValidationStage): JiraValidationReport;
|
|
17
|
+
//# sourceMappingURL=validation.d.ts.map
|
|
@@ -0,0 +1,341 @@
|
|
|
1
|
+
import { existsSync, readFileSync } from 'fs';
|
|
2
|
+
import path from 'path';
|
|
3
|
+
import { parse as parseYaml } from 'yaml';
|
|
4
|
+
import { JIRA_STAGE_MIN_STATUS, } from './constants.js';
|
|
5
|
+
import { hashFileSha256 } from './hash.js';
|
|
6
|
+
import { readJiraIntake, statusAtLeast } from './intake.js';
|
|
7
|
+
import { normalizeJiraId, toDisplayPath, validateJiraId } from './paths.js';
|
|
8
|
+
export function validateJiraIntake(projectRoot, jiraId, stage) {
|
|
9
|
+
const normalizedJira = normalizeJiraId(jiraId);
|
|
10
|
+
const errors = [];
|
|
11
|
+
const warnings = [];
|
|
12
|
+
const idValidation = validateJiraId(normalizedJira);
|
|
13
|
+
if (!idValidation.valid) {
|
|
14
|
+
errors.push({ code: 'invalid-jira-id', message: idValidation.error ?? 'Invalid Jira issue id' });
|
|
15
|
+
}
|
|
16
|
+
const intakeResult = readJiraIntake(projectRoot, normalizedJira);
|
|
17
|
+
warnings.push(...intakeResult.warnings.map((message) => ({ code: 'intake-warning', message, file: toDisplayPath(projectRoot, intakeResult.path) })));
|
|
18
|
+
if (!intakeResult.intake) {
|
|
19
|
+
errors.push({
|
|
20
|
+
code: 'missing-intake',
|
|
21
|
+
message: 'Missing jira intake.yaml. Run /opsx:jira-import first.',
|
|
22
|
+
file: toDisplayPath(projectRoot, intakeResult.path),
|
|
23
|
+
});
|
|
24
|
+
return buildReport(projectRoot, normalizedJira, stage, intakeResult.issueDir, undefined, errors, warnings);
|
|
25
|
+
}
|
|
26
|
+
const intake = intakeResult.intake;
|
|
27
|
+
const requiredStatus = JIRA_STAGE_MIN_STATUS[stage];
|
|
28
|
+
if (!statusAtLeast(intake.status, requiredStatus)) {
|
|
29
|
+
errors.push({
|
|
30
|
+
code: 'status-not-ready',
|
|
31
|
+
message: `Stage ${stage} requires status ${requiredStatus} or later, but intake is ${intake.status}.`,
|
|
32
|
+
file: toDisplayPath(projectRoot, intakeResult.path),
|
|
33
|
+
});
|
|
34
|
+
}
|
|
35
|
+
validateSource(projectRoot, intakeResult.issueDir, intake.sourceHashSha256, errors);
|
|
36
|
+
if (stage === 'requirement' || stage === 'stories' || stage === 'propose') {
|
|
37
|
+
validateRequirementFiles(projectRoot, intakeResult.issueDir, errors);
|
|
38
|
+
validateBlockingQuestions(projectRoot, intakeResult.issueDir, errors);
|
|
39
|
+
validateAssumptions(projectRoot, intakeResult.issueDir, errors);
|
|
40
|
+
}
|
|
41
|
+
if (stage === 'stories' || stage === 'propose') {
|
|
42
|
+
validateStories(projectRoot, intakeResult.issueDir, errors);
|
|
43
|
+
validateMapping(projectRoot, intakeResult.issueDir, stage, errors, warnings);
|
|
44
|
+
}
|
|
45
|
+
return buildReport(projectRoot, normalizedJira, stage, intakeResult.issueDir, intake.status, errors, warnings);
|
|
46
|
+
}
|
|
47
|
+
function buildReport(projectRoot, jira, stage, issueDir, status, errors, warnings) {
|
|
48
|
+
return {
|
|
49
|
+
ok: errors.length === 0,
|
|
50
|
+
jira,
|
|
51
|
+
stage,
|
|
52
|
+
issueDir: toDisplayPath(projectRoot, issueDir),
|
|
53
|
+
status,
|
|
54
|
+
errors,
|
|
55
|
+
warnings,
|
|
56
|
+
};
|
|
57
|
+
}
|
|
58
|
+
function validateSource(projectRoot, issueDir, expectedHash, errors) {
|
|
59
|
+
const sourcePath = path.join(issueDir, 'source.md');
|
|
60
|
+
if (!existsSync(sourcePath)) {
|
|
61
|
+
errors.push({ code: 'missing-source', message: 'Missing source.md.', file: toDisplayPath(projectRoot, sourcePath) });
|
|
62
|
+
return;
|
|
63
|
+
}
|
|
64
|
+
if (!expectedHash) {
|
|
65
|
+
errors.push({
|
|
66
|
+
code: 'missing-source-hash',
|
|
67
|
+
message: 'intake.yaml must record sourceHashSha256 so source.md remains an auditable read-only snapshot.',
|
|
68
|
+
file: toDisplayPath(projectRoot, path.join(issueDir, 'intake.yaml')),
|
|
69
|
+
});
|
|
70
|
+
return;
|
|
71
|
+
}
|
|
72
|
+
const actualHash = hashFileSha256(sourcePath);
|
|
73
|
+
if (actualHash !== expectedHash) {
|
|
74
|
+
errors.push({
|
|
75
|
+
code: 'source-hash-drift',
|
|
76
|
+
message: 'source.md has changed since import. Re-import or restore the original Jira snapshot.',
|
|
77
|
+
file: toDisplayPath(projectRoot, sourcePath),
|
|
78
|
+
});
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
function validateRequirementFiles(projectRoot, issueDir, errors) {
|
|
82
|
+
const requirementPath = path.join(issueDir, 'requirement.md');
|
|
83
|
+
if (!existsSync(requirementPath)) {
|
|
84
|
+
errors.push({ code: 'missing-requirement', message: 'Missing reviewed requirement.md.', file: toDisplayPath(projectRoot, requirementPath) });
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
function validateStories(projectRoot, issueDir, errors) {
|
|
88
|
+
const storiesPath = path.join(issueDir, 'stories.md');
|
|
89
|
+
if (!existsSync(storiesPath)) {
|
|
90
|
+
errors.push({ code: 'missing-stories', message: 'Missing reviewed stories.md.', file: toDisplayPath(projectRoot, storiesPath) });
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
function validateBlockingQuestions(projectRoot, issueDir, errors) {
|
|
94
|
+
const questionsPath = path.join(issueDir, 'questions.md');
|
|
95
|
+
if (!existsSync(questionsPath))
|
|
96
|
+
return;
|
|
97
|
+
const unresolved = findUnresolvedQuestionBlocks(readFileSync(questionsPath, 'utf8'));
|
|
98
|
+
for (const question of unresolved) {
|
|
99
|
+
errors.push({
|
|
100
|
+
code: 'blocking-question-open',
|
|
101
|
+
message: `Blocking question is unresolved: ${question}`,
|
|
102
|
+
file: toDisplayPath(projectRoot, questionsPath),
|
|
103
|
+
});
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
function validateAssumptions(projectRoot, issueDir, errors) {
|
|
107
|
+
const assumptionsPath = path.join(issueDir, 'assumptions.md');
|
|
108
|
+
if (!existsSync(assumptionsPath))
|
|
109
|
+
return;
|
|
110
|
+
const unresolved = findUnapprovedAssumptionBlocks(readFileSync(assumptionsPath, 'utf8'));
|
|
111
|
+
for (const assumption of unresolved) {
|
|
112
|
+
errors.push({
|
|
113
|
+
code: 'assumption-not-approved',
|
|
114
|
+
message: `Assumption is not approved: ${assumption}`,
|
|
115
|
+
file: toDisplayPath(projectRoot, assumptionsPath),
|
|
116
|
+
});
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
function validateMapping(projectRoot, issueDir, stage, errors, warnings) {
|
|
120
|
+
const mappingPath = path.join(issueDir, 'mapping.yaml');
|
|
121
|
+
if (!existsSync(mappingPath)) {
|
|
122
|
+
errors.push({ code: 'missing-mapping', message: 'Missing mapping.yaml traceability matrix.', file: toDisplayPath(projectRoot, mappingPath) });
|
|
123
|
+
return;
|
|
124
|
+
}
|
|
125
|
+
let mapping;
|
|
126
|
+
try {
|
|
127
|
+
mapping = parseYaml(readFileSync(mappingPath, 'utf8')) ?? {};
|
|
128
|
+
}
|
|
129
|
+
catch (error) {
|
|
130
|
+
errors.push({
|
|
131
|
+
code: 'invalid-mapping',
|
|
132
|
+
message: `Failed to parse mapping.yaml: ${error instanceof Error ? error.message : String(error)}`,
|
|
133
|
+
file: toDisplayPath(projectRoot, mappingPath),
|
|
134
|
+
});
|
|
135
|
+
return;
|
|
136
|
+
}
|
|
137
|
+
const acIds = collectAcceptanceCriteriaIds(mapping);
|
|
138
|
+
if (acIds.length === 0) {
|
|
139
|
+
warnings.push({
|
|
140
|
+
code: 'no-acceptance-criteria-mapped',
|
|
141
|
+
message: 'mapping.yaml does not list Jira acceptance criteria; story coverage cannot be proven.',
|
|
142
|
+
file: toDisplayPath(projectRoot, mappingPath),
|
|
143
|
+
});
|
|
144
|
+
}
|
|
145
|
+
for (const acId of acIds) {
|
|
146
|
+
if (!isAcceptanceCriteriaCovered(mapping, acId)) {
|
|
147
|
+
errors.push({
|
|
148
|
+
code: 'acceptance-criteria-uncovered',
|
|
149
|
+
message: `Acceptance criterion ${acId} is not mapped to any story.`,
|
|
150
|
+
file: toDisplayPath(projectRoot, mappingPath),
|
|
151
|
+
});
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
const storiesWithoutRequirementSource = findStoriesWithoutRequirementSource(mapping);
|
|
155
|
+
for (const storyId of storiesWithoutRequirementSource) {
|
|
156
|
+
errors.push({
|
|
157
|
+
code: 'story-without-requirement-source',
|
|
158
|
+
message: `Story ${storyId} must trace back to at least one requirement.`,
|
|
159
|
+
file: toDisplayPath(projectRoot, mappingPath),
|
|
160
|
+
});
|
|
161
|
+
}
|
|
162
|
+
if (stage === 'propose') {
|
|
163
|
+
const storyIssues = findStoriesWithoutChange(mapping);
|
|
164
|
+
for (const storyId of storyIssues) {
|
|
165
|
+
errors.push({
|
|
166
|
+
code: 'story-without-openspec-change',
|
|
167
|
+
message: `Story ${storyId} must have an OpenSpec change or be marked deferred.`,
|
|
168
|
+
file: toDisplayPath(projectRoot, mappingPath),
|
|
169
|
+
});
|
|
170
|
+
}
|
|
171
|
+
const storiesWithoutSpecFiles = findStoriesWithoutSpecFiles(mapping);
|
|
172
|
+
for (const storyId of storiesWithoutSpecFiles) {
|
|
173
|
+
errors.push({
|
|
174
|
+
code: 'story-without-spec-file',
|
|
175
|
+
message: `Story ${storyId} must map to at least one OpenSpec spec file.`,
|
|
176
|
+
file: toDisplayPath(projectRoot, mappingPath),
|
|
177
|
+
});
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
function findUnresolvedQuestionBlocks(content) {
|
|
182
|
+
const blocking = sectionContent(content, 'Blocking');
|
|
183
|
+
return itemBlocks(blocking).filter((block) => {
|
|
184
|
+
if (/\bstatus\s*:\s*(answered|resolved|accepted|closed)\b/i.test(block))
|
|
185
|
+
return false;
|
|
186
|
+
return /\bstatus\s*:\s*(unanswered|open|pending|needs|unresolved)\b/i.test(block) || block.trim().length > 0;
|
|
187
|
+
}).map(firstLineText);
|
|
188
|
+
}
|
|
189
|
+
function findUnapprovedAssumptionBlocks(content) {
|
|
190
|
+
return itemBlocks(content).filter((block) => {
|
|
191
|
+
if (/\bstatus\s*:\s*(accepted|approved)\b/i.test(block))
|
|
192
|
+
return false;
|
|
193
|
+
return /\bstatus\s*:/i.test(block) || block.trim().length > 0;
|
|
194
|
+
}).map(firstLineText);
|
|
195
|
+
}
|
|
196
|
+
function sectionContent(content, heading) {
|
|
197
|
+
const lines = content.split(/\r?\n/);
|
|
198
|
+
const start = lines.findIndex((line) => new RegExp(`^##\\s+${heading}\\s*$`, 'i').test(line.trim()));
|
|
199
|
+
if (start === -1)
|
|
200
|
+
return '';
|
|
201
|
+
const end = lines.findIndex((line, index) => index > start && /^##\s+/.test(line));
|
|
202
|
+
return lines.slice(start + 1, end === -1 ? undefined : end).join('\n');
|
|
203
|
+
}
|
|
204
|
+
function itemBlocks(content) {
|
|
205
|
+
const lines = content.split(/\r?\n/);
|
|
206
|
+
const blocks = [];
|
|
207
|
+
let current = [];
|
|
208
|
+
for (const line of lines) {
|
|
209
|
+
if (/^-\s+/.test(line)) {
|
|
210
|
+
if (current.length > 0)
|
|
211
|
+
blocks.push(current.join('\n'));
|
|
212
|
+
current = [line];
|
|
213
|
+
}
|
|
214
|
+
else if (current.length > 0) {
|
|
215
|
+
current.push(line);
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
if (current.length > 0)
|
|
219
|
+
blocks.push(current.join('\n'));
|
|
220
|
+
return blocks.filter((block) => block.trim().length > 0);
|
|
221
|
+
}
|
|
222
|
+
function firstLineText(block) {
|
|
223
|
+
return block.split(/\r?\n/)[0].replace(/^\s*-\s+/, '').trim();
|
|
224
|
+
}
|
|
225
|
+
function collectAcceptanceCriteriaIds(mapping) {
|
|
226
|
+
const ids = new Set();
|
|
227
|
+
const acObject = mapping?.acceptanceCriteria ?? mapping?.acceptance_criteria;
|
|
228
|
+
if (acObject && typeof acObject === 'object' && !Array.isArray(acObject)) {
|
|
229
|
+
for (const key of Object.keys(acObject))
|
|
230
|
+
ids.add(key);
|
|
231
|
+
}
|
|
232
|
+
for (const requirement of Object.values(mapping?.requirements ?? {})) {
|
|
233
|
+
const source = requirement?.source;
|
|
234
|
+
const acValues = Array.isArray(source?.ac) ? source.ac : source?.ac ? [source.ac] : [];
|
|
235
|
+
for (const ac of acValues)
|
|
236
|
+
ids.add(String(ac));
|
|
237
|
+
}
|
|
238
|
+
return [...ids].sort();
|
|
239
|
+
}
|
|
240
|
+
function isAcceptanceCriteriaCovered(mapping, acId) {
|
|
241
|
+
const acObject = mapping?.acceptanceCriteria ?? mapping?.acceptance_criteria;
|
|
242
|
+
const acEntry = acObject?.[acId];
|
|
243
|
+
if (hasNonEmptyArray(acEntry?.stories))
|
|
244
|
+
return true;
|
|
245
|
+
for (const requirement of Object.values(mapping?.requirements ?? {})) {
|
|
246
|
+
const source = requirement?.source;
|
|
247
|
+
const acValues = Array.isArray(source?.ac) ? source.ac : source?.ac ? [source.ac] : [];
|
|
248
|
+
if (acValues.map(String).includes(acId) && hasNonEmptyArray(requirement?.stories)) {
|
|
249
|
+
return true;
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
return false;
|
|
253
|
+
}
|
|
254
|
+
function findStoriesWithoutChange(mapping) {
|
|
255
|
+
const stories = mapping?.stories;
|
|
256
|
+
if (!stories || typeof stories !== 'object' || Array.isArray(stories))
|
|
257
|
+
return [];
|
|
258
|
+
return Object.entries(stories)
|
|
259
|
+
.filter(([, value]) => {
|
|
260
|
+
const story = value;
|
|
261
|
+
if (story?.deferred === true || story?.status === 'deferred')
|
|
262
|
+
return false;
|
|
263
|
+
return !(story?.openspecChange || story?.openSpecChange || story?.openspec_change);
|
|
264
|
+
})
|
|
265
|
+
.map(([key]) => key)
|
|
266
|
+
.sort();
|
|
267
|
+
}
|
|
268
|
+
function findStoriesWithoutRequirementSource(mapping) {
|
|
269
|
+
const stories = mapping?.stories;
|
|
270
|
+
if (!stories || typeof stories !== 'object' || Array.isArray(stories))
|
|
271
|
+
return [];
|
|
272
|
+
return Object.entries(stories)
|
|
273
|
+
.filter(([storyId, value]) => {
|
|
274
|
+
const story = value;
|
|
275
|
+
if (isDeferredStory(story))
|
|
276
|
+
return false;
|
|
277
|
+
if (hasTraceValue(story?.requirements) || hasTraceValue(story?.requirement))
|
|
278
|
+
return false;
|
|
279
|
+
if (hasTraceValue(story?.source?.requirements) || hasTraceValue(story?.source?.requirement))
|
|
280
|
+
return false;
|
|
281
|
+
if (hasTraceValue(story?.sources?.requirements) || hasTraceValue(story?.sources?.requirement))
|
|
282
|
+
return false;
|
|
283
|
+
return !isStoryReferencedByRequirement(mapping, storyId);
|
|
284
|
+
})
|
|
285
|
+
.map(([key]) => key)
|
|
286
|
+
.sort();
|
|
287
|
+
}
|
|
288
|
+
function findStoriesWithoutSpecFiles(mapping) {
|
|
289
|
+
const stories = mapping?.stories;
|
|
290
|
+
if (!stories || typeof stories !== 'object' || Array.isArray(stories))
|
|
291
|
+
return [];
|
|
292
|
+
return Object.entries(stories)
|
|
293
|
+
.filter(([storyId, value]) => {
|
|
294
|
+
const story = value;
|
|
295
|
+
if (isDeferredStory(story))
|
|
296
|
+
return false;
|
|
297
|
+
if (hasTraceValue(story?.specFiles) || hasTraceValue(story?.specs) || hasTraceValue(story?.spec_files))
|
|
298
|
+
return false;
|
|
299
|
+
if (hasTraceValue(story?.specFile) || hasTraceValue(story?.spec))
|
|
300
|
+
return false;
|
|
301
|
+
const changeName = story?.openspecChange ?? story?.openSpecChange ?? story?.openspec_change;
|
|
302
|
+
if (typeof changeName !== 'string' || changeName.trim().length === 0)
|
|
303
|
+
return true;
|
|
304
|
+
const change = mapping?.openspecChanges?.[changeName] ?? mapping?.openSpecChanges?.[changeName] ?? mapping?.openspec_changes?.[changeName] ?? mapping?.changes?.[changeName];
|
|
305
|
+
return !(hasTraceValue(change?.specFiles) ||
|
|
306
|
+
hasTraceValue(change?.specs) ||
|
|
307
|
+
hasTraceValue(change?.spec_files) ||
|
|
308
|
+
hasTraceValue(change?.specFile) ||
|
|
309
|
+
hasTraceValue(change?.spec));
|
|
310
|
+
})
|
|
311
|
+
.map(([key]) => key)
|
|
312
|
+
.sort();
|
|
313
|
+
}
|
|
314
|
+
function isStoryReferencedByRequirement(mapping, storyId) {
|
|
315
|
+
for (const requirement of Object.values(mapping?.requirements ?? {})) {
|
|
316
|
+
if (hasTraceValue(requirement?.stories) && traceValues(requirement.stories).includes(storyId)) {
|
|
317
|
+
return true;
|
|
318
|
+
}
|
|
319
|
+
}
|
|
320
|
+
return false;
|
|
321
|
+
}
|
|
322
|
+
function isDeferredStory(story) {
|
|
323
|
+
return story?.deferred === true || story?.status === 'deferred';
|
|
324
|
+
}
|
|
325
|
+
function hasTraceValue(value) {
|
|
326
|
+
return traceValues(value).length > 0;
|
|
327
|
+
}
|
|
328
|
+
function traceValues(value) {
|
|
329
|
+
if (Array.isArray(value)) {
|
|
330
|
+
return value.map(String).map((item) => item.trim()).filter(Boolean);
|
|
331
|
+
}
|
|
332
|
+
if (typeof value === 'string') {
|
|
333
|
+
const trimmed = value.trim();
|
|
334
|
+
return trimmed ? [trimmed] : [];
|
|
335
|
+
}
|
|
336
|
+
return [];
|
|
337
|
+
}
|
|
338
|
+
function hasNonEmptyArray(value) {
|
|
339
|
+
return Array.isArray(value) && value.length > 0;
|
|
340
|
+
}
|
|
341
|
+
//# sourceMappingURL=validation.js.map
|
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Legacy cleanup module for detecting and removing OpenSpec artifacts
|
|
3
|
+
* from previous init versions during the migration to the skill-based workflow.
|
|
4
|
+
*/
|
|
5
|
+
/**
|
|
6
|
+
* Legacy config file names from the old ToolRegistry.
|
|
7
|
+
* These were config files created at project root with OpenSpec markers.
|
|
8
|
+
*/
|
|
9
|
+
export declare const LEGACY_CONFIG_FILES: readonly ["CLAUDE.md", "CLINE.md", "CODEBUDDY.md", "COSTRICT.md", "QODER.md", "IFLOW.md", "AGENTS.md", "QWEN.md"];
|
|
10
|
+
/**
|
|
11
|
+
* Legacy slash command patterns from the old SlashCommandRegistry.
|
|
12
|
+
* These map toolId to the path pattern where legacy commands were created.
|
|
13
|
+
* Some tools used a directory structure, others used individual files.
|
|
14
|
+
*/
|
|
15
|
+
export declare const LEGACY_SLASH_COMMAND_PATHS: Record<string, LegacySlashCommandPattern>;
|
|
16
|
+
/**
|
|
17
|
+
* Pattern types for legacy slash commands
|
|
18
|
+
*/
|
|
19
|
+
export interface LegacySlashCommandPattern {
|
|
20
|
+
type: 'directory' | 'files';
|
|
21
|
+
path?: string;
|
|
22
|
+
pattern?: string | string[];
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Result of legacy artifact detection
|
|
26
|
+
*/
|
|
27
|
+
export interface LegacyDetectionResult {
|
|
28
|
+
/** Config files with OpenSpec markers detected */
|
|
29
|
+
configFiles: string[];
|
|
30
|
+
/** Config files to update (remove markers only, never delete) */
|
|
31
|
+
configFilesToUpdate: string[];
|
|
32
|
+
/** Legacy slash command directories found */
|
|
33
|
+
slashCommandDirs: string[];
|
|
34
|
+
/** Legacy slash command files found (for file-based tools) */
|
|
35
|
+
slashCommandFiles: string[];
|
|
36
|
+
/** Whether openspec/AGENTS.md exists */
|
|
37
|
+
hasOpenspecAgents: boolean;
|
|
38
|
+
/** Whether openspec/project.md exists (preserved, migration hint only) */
|
|
39
|
+
hasProjectMd: boolean;
|
|
40
|
+
/** Whether root AGENTS.md has OpenSpec markers */
|
|
41
|
+
hasRootAgentsWithMarkers: boolean;
|
|
42
|
+
/** Whether any legacy artifacts were found */
|
|
43
|
+
hasLegacyArtifacts: boolean;
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* Detects all legacy OpenSpec artifacts in a project.
|
|
47
|
+
*
|
|
48
|
+
* @param projectPath - The root path of the project
|
|
49
|
+
* @returns Detection result with all found legacy artifacts
|
|
50
|
+
*/
|
|
51
|
+
export declare function detectLegacyArtifacts(projectPath: string): Promise<LegacyDetectionResult>;
|
|
52
|
+
/**
|
|
53
|
+
* Detects legacy config files with OpenSpec markers.
|
|
54
|
+
* All config files with markers are candidates for update (marker removal only).
|
|
55
|
+
* Config files are NEVER deleted - they belong to the user's project root.
|
|
56
|
+
*
|
|
57
|
+
* @param projectPath - The root path of the project
|
|
58
|
+
* @returns Object with all files found and files to update
|
|
59
|
+
*/
|
|
60
|
+
export declare function detectLegacyConfigFiles(projectPath: string): Promise<{
|
|
61
|
+
allFiles: string[];
|
|
62
|
+
filesToUpdate: string[];
|
|
63
|
+
}>;
|
|
64
|
+
/**
|
|
65
|
+
* Detects legacy slash command directories and files.
|
|
66
|
+
*
|
|
67
|
+
* @param projectPath - The root path of the project
|
|
68
|
+
* @returns Object with directories and individual files found
|
|
69
|
+
*/
|
|
70
|
+
export declare function detectLegacySlashCommands(projectPath: string): Promise<{
|
|
71
|
+
directories: string[];
|
|
72
|
+
files: string[];
|
|
73
|
+
}>;
|
|
74
|
+
/**
|
|
75
|
+
* Detects legacy OpenSpec structure files (AGENTS.md and project.md).
|
|
76
|
+
*
|
|
77
|
+
* @param projectPath - The root path of the project
|
|
78
|
+
* @returns Object with detection results for structure files
|
|
79
|
+
*/
|
|
80
|
+
export declare function detectLegacyStructureFiles(projectPath: string): Promise<{
|
|
81
|
+
hasOpenspecAgents: boolean;
|
|
82
|
+
hasProjectMd: boolean;
|
|
83
|
+
hasRootAgentsWithMarkers: boolean;
|
|
84
|
+
}>;
|
|
85
|
+
/**
|
|
86
|
+
* Checks if content contains OpenSpec markers.
|
|
87
|
+
*
|
|
88
|
+
* @param content - File content to check
|
|
89
|
+
* @returns True if both start and end markers are present
|
|
90
|
+
*/
|
|
91
|
+
export declare function hasOpenSpecMarkers(content: string): boolean;
|
|
92
|
+
/**
|
|
93
|
+
* Checks if file content is 100% OpenSpec content (only markers and whitespace outside).
|
|
94
|
+
*
|
|
95
|
+
* @param content - File content to check
|
|
96
|
+
* @returns True if content outside markers is only whitespace
|
|
97
|
+
*/
|
|
98
|
+
export declare function isOnlyOpenSpecContent(content: string): boolean;
|
|
99
|
+
/**
|
|
100
|
+
* Removes the OpenSpec marker block from file content.
|
|
101
|
+
* Only removes markers that are on their own lines (ignores inline mentions).
|
|
102
|
+
* Cleans up double blank lines that may result from removal.
|
|
103
|
+
*
|
|
104
|
+
* @param content - File content with OpenSpec markers
|
|
105
|
+
* @returns Content with marker block removed
|
|
106
|
+
*/
|
|
107
|
+
export declare function removeMarkerBlock(content: string): string;
|
|
108
|
+
/**
|
|
109
|
+
* Result of cleanup operation
|
|
110
|
+
*/
|
|
111
|
+
export interface CleanupResult {
|
|
112
|
+
/** Files that were deleted entirely */
|
|
113
|
+
deletedFiles: string[];
|
|
114
|
+
/** Files that had marker blocks removed */
|
|
115
|
+
modifiedFiles: string[];
|
|
116
|
+
/** Directories that were deleted */
|
|
117
|
+
deletedDirs: string[];
|
|
118
|
+
/** Whether project.md exists and needs manual migration */
|
|
119
|
+
projectMdNeedsMigration: boolean;
|
|
120
|
+
/** Error messages if any operations failed */
|
|
121
|
+
errors: string[];
|
|
122
|
+
}
|
|
123
|
+
/**
|
|
124
|
+
* Cleans up legacy OpenSpec artifacts from a project.
|
|
125
|
+
* Preserves openspec/project.md (shows migration hint instead of deleting).
|
|
126
|
+
*
|
|
127
|
+
* @param projectPath - The root path of the project
|
|
128
|
+
* @param detection - Detection result from detectLegacyArtifacts
|
|
129
|
+
* @returns Cleanup result with summary of actions taken
|
|
130
|
+
*/
|
|
131
|
+
export declare function cleanupLegacyArtifacts(projectPath: string, detection: LegacyDetectionResult): Promise<CleanupResult>;
|
|
132
|
+
/**
|
|
133
|
+
* Generates a cleanup summary message for display.
|
|
134
|
+
*
|
|
135
|
+
* @param result - Cleanup result from cleanupLegacyArtifacts
|
|
136
|
+
* @returns Formatted summary string for console output
|
|
137
|
+
*/
|
|
138
|
+
export declare function formatCleanupSummary(result: CleanupResult): string;
|
|
139
|
+
/**
|
|
140
|
+
* Generates a detection summary message for display before cleanup.
|
|
141
|
+
* Groups files by action type: removals, updates, and manual migration.
|
|
142
|
+
*
|
|
143
|
+
* @param detection - Detection result from detectLegacyArtifacts
|
|
144
|
+
* @returns Formatted summary string showing what was found
|
|
145
|
+
*/
|
|
146
|
+
export declare function formatDetectionSummary(detection: LegacyDetectionResult): string;
|
|
147
|
+
/**
|
|
148
|
+
* Extract tool IDs from detected legacy artifacts.
|
|
149
|
+
* Uses LEGACY_SLASH_COMMAND_PATHS to map paths back to tool IDs.
|
|
150
|
+
*
|
|
151
|
+
* @param detection - Detection result from detectLegacyArtifacts
|
|
152
|
+
* @returns Array of tool IDs that had legacy artifacts
|
|
153
|
+
*/
|
|
154
|
+
export declare function getToolsFromLegacyArtifacts(detection: LegacyDetectionResult): string[];
|
|
155
|
+
/**
|
|
156
|
+
* Generates a migration hint message for project.md.
|
|
157
|
+
* This is shown when project.md exists and needs manual migration to config.yaml.
|
|
158
|
+
*
|
|
159
|
+
* @returns Formatted migration hint string for console output
|
|
160
|
+
*/
|
|
161
|
+
export declare function formatProjectMdMigrationHint(): string;
|
|
162
|
+
//# sourceMappingURL=legacy-cleanup.d.ts.map
|