@codewalla_india/openspec 1.0.1
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 +225 -0
- package/bin/openspec.js +5 -0
- package/dist/cli/index.d.ts +10 -0
- package/dist/cli/index.js +548 -0
- package/dist/commands/change.d.ts +39 -0
- package/dist/commands/change.js +279 -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 +552 -0
- package/dist/commands/context.d.ts +3 -0
- package/dist/commands/context.js +155 -0
- package/dist/commands/doctor.d.ts +8 -0
- package/dist/commands/doctor.js +163 -0
- package/dist/commands/feedback.d.ts +9 -0
- package/dist/commands/feedback.js +183 -0
- package/dist/commands/schema.d.ts +6 -0
- package/dist/commands/schema.js +869 -0
- package/dist/commands/shared-gather.d.ts +14 -0
- package/dist/commands/shared-gather.js +31 -0
- package/dist/commands/shared-output.d.ts +18 -0
- package/dist/commands/shared-output.js +61 -0
- package/dist/commands/show.d.ts +19 -0
- package/dist/commands/show.js +177 -0
- package/dist/commands/spec.d.ts +19 -0
- package/dist/commands/spec.js +236 -0
- package/dist/commands/store.d.ts +3 -0
- package/dist/commands/store.js +547 -0
- package/dist/commands/validate.d.ts +26 -0
- package/dist/commands/validate.js +330 -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 +45 -0
- package/dist/commands/workflow/instructions.js +500 -0
- package/dist/commands/workflow/new-change.d.ts +20 -0
- package/dist/commands/workflow/new-change.js +106 -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 +84 -0
- package/dist/commands/workflow/shared.js +133 -0
- package/dist/commands/workflow/status.d.ts +16 -0
- package/dist/commands/workflow/status.js +92 -0
- package/dist/commands/workflow/templates.d.ts +16 -0
- package/dist/commands/workflow/templates.js +69 -0
- package/dist/commands/workset-input.d.ts +19 -0
- package/dist/commands/workset-input.js +112 -0
- package/dist/commands/workset-prompts.d.ts +12 -0
- package/dist/commands/workset-prompts.js +143 -0
- package/dist/commands/workset.d.ts +25 -0
- package/dist/commands/workset.js +446 -0
- package/dist/core/archive.d.ts +22 -0
- package/dist/core/archive.js +471 -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 +9 -0
- package/dist/core/artifact-graph/index.js +14 -0
- package/dist/core/artifact-graph/instruction-loader.d.ts +188 -0
- package/dist/core/artifact-graph/instruction-loader.js +233 -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 +40 -0
- package/dist/core/artifact-graph/types.js +29 -0
- package/dist/core/available-tools.d.ts +17 -0
- package/dist/core/available-tools.js +43 -0
- package/dist/core/change-metadata/index.d.ts +2 -0
- package/dist/core/change-metadata/index.js +2 -0
- package/dist/core/change-metadata/schema.d.ts +19 -0
- package/dist/core/change-metadata/schema.js +30 -0
- package/dist/core/change-status-policy.d.ts +37 -0
- package/dist/core/change-status-policy.js +35 -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 +32 -0
- package/dist/core/command-generation/adapters/claude.d.ts +13 -0
- package/dist/core/command-generation/adapters/claude.js +37 -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 +31 -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 +42 -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 +38 -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/command-generation/yaml.d.ts +22 -0
- package/dist/core/command-generation/yaml.js +38 -0
- package/dist/core/completions/command-registry.d.ts +3 -0
- package/dist/core/completions/command-registry.js +778 -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 +276 -0
- package/dist/core/completions/installers/bash-installer.d.ts +87 -0
- package/dist/core/completions/installers/bash-installer.js +321 -0
- package/dist/core/completions/installers/fish-installer.d.ts +43 -0
- package/dist/core/completions/installers/fish-installer.js +151 -0
- package/dist/core/completions/installers/powershell-installer.d.ts +102 -0
- package/dist/core/completions/installers/powershell-installer.js +415 -0
- package/dist/core/completions/installers/zsh-installer.d.ts +117 -0
- package/dist/core/completions/installers/zsh-installer.js +424 -0
- package/dist/core/completions/shared-flags.d.ts +13 -0
- package/dist/core/completions/shared-flags.js +33 -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/comprehension/config.d.ts +20 -0
- package/dist/core/comprehension/config.js +23 -0
- package/dist/core/comprehension/fingerprint.d.ts +5 -0
- package/dist/core/comprehension/fingerprint.js +25 -0
- package/dist/core/comprehension/index.d.ts +49 -0
- package/dist/core/comprehension/index.js +78 -0
- package/dist/core/comprehension/pass-record.d.ts +29 -0
- package/dist/core/comprehension/pass-record.js +64 -0
- package/dist/core/comprehension/stats.d.ts +18 -0
- package/dist/core/comprehension/stats.js +41 -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 +87 -0
- package/dist/core/config-schema.js +239 -0
- package/dist/core/config.d.ts +18 -0
- package/dist/core/config.js +39 -0
- package/dist/core/converters/json-converter.d.ts +6 -0
- package/dist/core/converters/json-converter.js +51 -0
- package/dist/core/file-state.d.ts +36 -0
- package/dist/core/file-state.js +112 -0
- package/dist/core/global-config.d.ts +51 -0
- package/dist/core/global-config.js +124 -0
- package/dist/core/id.d.ts +17 -0
- package/dist/core/id.js +30 -0
- package/dist/core/index.d.ts +6 -0
- package/dist/core/index.js +7 -0
- package/dist/core/init.d.ts +37 -0
- package/dist/core/init.js +613 -0
- package/dist/core/legacy-cleanup.d.ts +162 -0
- package/dist/core/legacy-cleanup.js +514 -0
- package/dist/core/list.d.ts +11 -0
- package/dist/core/list.js +185 -0
- package/dist/core/migration.d.ts +23 -0
- package/dist/core/migration.js +108 -0
- package/dist/core/openers.d.ts +77 -0
- package/dist/core/openers.js +251 -0
- package/dist/core/openspec-root.d.ts +45 -0
- package/dist/core/openspec-root.js +192 -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 +16 -0
- package/dist/core/planning-home.js +67 -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 +120 -0
- package/dist/core/project-config.js +406 -0
- package/dist/core/references.d.ts +63 -0
- package/dist/core/references.js +310 -0
- package/dist/core/relationship-health.d.ts +65 -0
- package/dist/core/relationship-health.js +64 -0
- package/dist/core/root-selection.d.ts +122 -0
- package/dist/core/root-selection.js +337 -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 +78 -0
- package/dist/core/specs-apply.js +394 -0
- package/dist/core/store/errors.d.ts +20 -0
- package/dist/core/store/errors.js +22 -0
- package/dist/core/store/foundation.d.ts +56 -0
- package/dist/core/store/foundation.js +251 -0
- package/dist/core/store/git.d.ts +23 -0
- package/dist/core/store/git.js +137 -0
- package/dist/core/store/index.d.ts +5 -0
- package/dist/core/store/index.js +5 -0
- package/dist/core/store/operations.d.ts +114 -0
- package/dist/core/store/operations.js +783 -0
- package/dist/core/store/registry.d.ts +58 -0
- package/dist/core/store/registry.js +275 -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 +337 -0
- package/dist/core/templates/workflows/archive-change.d.ts +10 -0
- package/dist/core/templates/workflows/archive-change.js +278 -0
- package/dist/core/templates/workflows/bulk-archive-change.d.ts +10 -0
- package/dist/core/templates/workflows/bulk-archive-change.js +493 -0
- package/dist/core/templates/workflows/comprehension-guidance.d.ts +9 -0
- package/dist/core/templates/workflows/comprehension-guidance.js +58 -0
- package/dist/core/templates/workflows/continue-change.d.ts +10 -0
- package/dist/core/templates/workflows/continue-change.js +239 -0
- package/dist/core/templates/workflows/explore.d.ts +10 -0
- package/dist/core/templates/workflows/explore.js +464 -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 +205 -0
- package/dist/core/templates/workflows/mcp-guidance.d.ts +13 -0
- package/dist/core/templates/workflows/mcp-guidance.js +116 -0
- package/dist/core/templates/workflows/new-change.d.ts +10 -0
- package/dist/core/templates/workflows/new-change.js +148 -0
- package/dist/core/templates/workflows/onboard.d.ts +10 -0
- package/dist/core/templates/workflows/onboard.js +566 -0
- package/dist/core/templates/workflows/propose.d.ts +10 -0
- package/dist/core/templates/workflows/propose.js +228 -0
- package/dist/core/templates/workflows/store-selection.d.ts +8 -0
- package/dist/core/templates/workflows/store-selection.js +8 -0
- package/dist/core/templates/workflows/sync-specs.d.ts +10 -0
- package/dist/core/templates/workflows/sync-specs.js +291 -0
- package/dist/core/templates/workflows/verify-change.d.ts +10 -0
- package/dist/core/templates/workflows/verify-change.js +346 -0
- package/dist/core/update.d.ts +82 -0
- package/dist/core/update.js +557 -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 +44 -0
- package/dist/core/validation/validator.js +435 -0
- package/dist/core/view.d.ts +8 -0
- package/dist/core/view.js +168 -0
- package/dist/core/working-set.d.ts +47 -0
- package/dist/core/working-set.js +43 -0
- package/dist/core/worksets.d.ts +75 -0
- package/dist/core/worksets.js +245 -0
- package/dist/core/zod-issues.d.ts +4 -0
- package/dist/core/zod-issues.js +10 -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 +55 -0
- package/dist/utils/change-metadata.js +141 -0
- package/dist/utils/change-utils.d.ts +71 -0
- package/dist/utils/change-utils.js +138 -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 +320 -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 +84 -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/scripts/postinstall.js +83 -0
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared Types and Utilities for Artifact Workflow Commands
|
|
3
|
+
*
|
|
4
|
+
* This module contains types, constants, and validation helpers used across
|
|
5
|
+
* multiple artifact workflow commands.
|
|
6
|
+
*/
|
|
7
|
+
import type { ReferenceIndexEntry } from '../../core/references.js';
|
|
8
|
+
export interface ChangeCommandStatus {
|
|
9
|
+
severity: 'error' | 'warning';
|
|
10
|
+
code: string;
|
|
11
|
+
message: string;
|
|
12
|
+
target?: string;
|
|
13
|
+
fix?: string;
|
|
14
|
+
}
|
|
15
|
+
export interface TaskItem {
|
|
16
|
+
id: string;
|
|
17
|
+
description: string;
|
|
18
|
+
done: boolean;
|
|
19
|
+
}
|
|
20
|
+
export interface ApplyComprehensionInfo {
|
|
21
|
+
required: boolean;
|
|
22
|
+
passed: boolean;
|
|
23
|
+
thresholdPercent: number;
|
|
24
|
+
bestScorePercent?: number;
|
|
25
|
+
questionCount: number;
|
|
26
|
+
requirementCount: number;
|
|
27
|
+
scenarioCount: number;
|
|
28
|
+
pendingTaskCount: number;
|
|
29
|
+
attempts?: number;
|
|
30
|
+
}
|
|
31
|
+
export interface ApplyInstructions {
|
|
32
|
+
changeName: string;
|
|
33
|
+
changeDir: string;
|
|
34
|
+
schemaName: string;
|
|
35
|
+
contextFiles: Record<string, string[]>;
|
|
36
|
+
progress: {
|
|
37
|
+
total: number;
|
|
38
|
+
complete: number;
|
|
39
|
+
remaining: number;
|
|
40
|
+
};
|
|
41
|
+
tasks: TaskItem[];
|
|
42
|
+
state: 'blocked' | 'all_done' | 'ready';
|
|
43
|
+
missingArtifacts?: string[];
|
|
44
|
+
missingComprehension?: boolean;
|
|
45
|
+
comprehension?: ApplyComprehensionInfo;
|
|
46
|
+
instruction: string;
|
|
47
|
+
/** Referenced-store index (read-only upstream context; omitted when none declared) */
|
|
48
|
+
references?: ReferenceIndexEntry[];
|
|
49
|
+
}
|
|
50
|
+
export declare const DEFAULT_SCHEMA = "spec-driven";
|
|
51
|
+
export declare function printJson(payload: unknown): void;
|
|
52
|
+
export declare function statusFromError(error: unknown): ChangeCommandStatus;
|
|
53
|
+
/**
|
|
54
|
+
* Checks if color output is disabled via NO_COLOR env or --no-color flag.
|
|
55
|
+
*/
|
|
56
|
+
export declare function isColorDisabled(): boolean;
|
|
57
|
+
/**
|
|
58
|
+
* Gets the color function based on status.
|
|
59
|
+
*/
|
|
60
|
+
export declare function getStatusColor(status: 'done' | 'ready' | 'blocked'): (text: string) => string;
|
|
61
|
+
/**
|
|
62
|
+
* Gets the status indicator for an artifact.
|
|
63
|
+
*/
|
|
64
|
+
export declare function getStatusIndicator(status: 'done' | 'ready' | 'blocked'): string;
|
|
65
|
+
/**
|
|
66
|
+
* Returns the list of available change directory names under openspec/changes/.
|
|
67
|
+
* Excludes the archive directory and hidden directories.
|
|
68
|
+
*/
|
|
69
|
+
export declare function getAvailableChanges(projectRoot: string, changesDir?: string): Promise<string[]>;
|
|
70
|
+
/**
|
|
71
|
+
* Validates that a change exists and returns available changes if not.
|
|
72
|
+
* Checks directory existence directly to support scaffolded changes (without proposal.md).
|
|
73
|
+
*/
|
|
74
|
+
export declare function validateChangeExists(changeName: string | undefined, projectRoot: string, changesDir?: string, hints?: {
|
|
75
|
+
newChangeHint?: string;
|
|
76
|
+
}): Promise<string>;
|
|
77
|
+
/**
|
|
78
|
+
* Validates that a schema exists and returns available schemas if not.
|
|
79
|
+
*
|
|
80
|
+
* @param schemaName - The schema name to validate
|
|
81
|
+
* @param projectRoot - Optional project root for project-local schema resolution
|
|
82
|
+
*/
|
|
83
|
+
export declare function validateSchemaExists(schemaName: string, projectRoot?: string): string;
|
|
84
|
+
//# sourceMappingURL=shared.d.ts.map
|
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared Types and Utilities for Artifact Workflow Commands
|
|
3
|
+
*
|
|
4
|
+
* This module contains types, constants, and validation helpers used across
|
|
5
|
+
* multiple artifact workflow commands.
|
|
6
|
+
*/
|
|
7
|
+
import chalk from 'chalk';
|
|
8
|
+
import path from 'path';
|
|
9
|
+
import * as fs from 'fs';
|
|
10
|
+
import { getSchemaDir, listSchemas } from '../../core/artifact-graph/index.js';
|
|
11
|
+
import { isRootSelectionError } from '../../core/root-selection.js';
|
|
12
|
+
import { validateChangeName } from '../../utils/change-utils.js';
|
|
13
|
+
// -----------------------------------------------------------------------------
|
|
14
|
+
// Constants
|
|
15
|
+
// -----------------------------------------------------------------------------
|
|
16
|
+
export const DEFAULT_SCHEMA = 'spec-driven';
|
|
17
|
+
// -----------------------------------------------------------------------------
|
|
18
|
+
// Utility Functions
|
|
19
|
+
// -----------------------------------------------------------------------------
|
|
20
|
+
export function printJson(payload) {
|
|
21
|
+
console.log(JSON.stringify(payload, null, 2));
|
|
22
|
+
}
|
|
23
|
+
export function statusFromError(error) {
|
|
24
|
+
if (isRootSelectionError(error)) {
|
|
25
|
+
return { ...error.diagnostic };
|
|
26
|
+
}
|
|
27
|
+
return {
|
|
28
|
+
severity: 'error',
|
|
29
|
+
code: 'change_error',
|
|
30
|
+
message: error instanceof Error ? error.message : String(error),
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Checks if color output is disabled via NO_COLOR env or --no-color flag.
|
|
35
|
+
*/
|
|
36
|
+
export function isColorDisabled() {
|
|
37
|
+
return process.env.NO_COLOR === '1' || process.env.NO_COLOR === 'true';
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Gets the color function based on status.
|
|
41
|
+
*/
|
|
42
|
+
export function getStatusColor(status) {
|
|
43
|
+
if (isColorDisabled()) {
|
|
44
|
+
return (text) => text;
|
|
45
|
+
}
|
|
46
|
+
switch (status) {
|
|
47
|
+
case 'done':
|
|
48
|
+
return chalk.green;
|
|
49
|
+
case 'ready':
|
|
50
|
+
return chalk.yellow;
|
|
51
|
+
case 'blocked':
|
|
52
|
+
return chalk.red;
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* Gets the status indicator for an artifact.
|
|
57
|
+
*/
|
|
58
|
+
export function getStatusIndicator(status) {
|
|
59
|
+
const color = getStatusColor(status);
|
|
60
|
+
switch (status) {
|
|
61
|
+
case 'done':
|
|
62
|
+
return color('[x]');
|
|
63
|
+
case 'ready':
|
|
64
|
+
return color('[ ]');
|
|
65
|
+
case 'blocked':
|
|
66
|
+
return color('[-]');
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* Returns the list of available change directory names under openspec/changes/.
|
|
71
|
+
* Excludes the archive directory and hidden directories.
|
|
72
|
+
*/
|
|
73
|
+
export async function getAvailableChanges(projectRoot, changesDir = path.join(projectRoot, 'openspec', 'changes')) {
|
|
74
|
+
const changesPath = changesDir;
|
|
75
|
+
try {
|
|
76
|
+
const entries = await fs.promises.readdir(changesPath, { withFileTypes: true });
|
|
77
|
+
return entries
|
|
78
|
+
.filter((e) => e.isDirectory() && e.name !== 'archive' && !e.name.startsWith('.'))
|
|
79
|
+
.map((e) => e.name);
|
|
80
|
+
}
|
|
81
|
+
catch (error) {
|
|
82
|
+
if (error.code === 'ENOENT')
|
|
83
|
+
return [];
|
|
84
|
+
throw error;
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
/**
|
|
88
|
+
* Validates that a change exists and returns available changes if not.
|
|
89
|
+
* Checks directory existence directly to support scaffolded changes (without proposal.md).
|
|
90
|
+
*/
|
|
91
|
+
export async function validateChangeExists(changeName, projectRoot, changesDir = path.join(projectRoot, 'openspec', 'changes'), hints = {}) {
|
|
92
|
+
// Hints must stay pasteable: callers with a selected store pass a
|
|
93
|
+
// store-carrying hint so following it lands in the same root.
|
|
94
|
+
const newChangeHint = hints.newChangeHint ?? 'openspec new change <name>';
|
|
95
|
+
if (!changeName) {
|
|
96
|
+
const available = await getAvailableChanges(projectRoot, changesDir);
|
|
97
|
+
if (available.length === 0) {
|
|
98
|
+
throw new Error(`No changes found. Create one with: ${newChangeHint}`);
|
|
99
|
+
}
|
|
100
|
+
throw new Error(`Missing required option --change. Available changes:\n ${available.join('\n ')}`);
|
|
101
|
+
}
|
|
102
|
+
// Validate change name format to prevent path traversal
|
|
103
|
+
const nameValidation = validateChangeName(changeName);
|
|
104
|
+
if (!nameValidation.valid) {
|
|
105
|
+
throw new Error(`Invalid change name '${changeName}': ${nameValidation.error}`);
|
|
106
|
+
}
|
|
107
|
+
// Check directory existence directly
|
|
108
|
+
const changePath = path.join(changesDir, changeName);
|
|
109
|
+
const exists = fs.existsSync(changePath) && fs.statSync(changePath).isDirectory();
|
|
110
|
+
if (!exists) {
|
|
111
|
+
const available = await getAvailableChanges(projectRoot, changesDir);
|
|
112
|
+
if (available.length === 0) {
|
|
113
|
+
throw new Error(`Change '${changeName}' not found. No changes exist. Create one with: ${newChangeHint}`);
|
|
114
|
+
}
|
|
115
|
+
throw new Error(`Change '${changeName}' not found. Available changes:\n ${available.join('\n ')}`);
|
|
116
|
+
}
|
|
117
|
+
return changeName;
|
|
118
|
+
}
|
|
119
|
+
/**
|
|
120
|
+
* Validates that a schema exists and returns available schemas if not.
|
|
121
|
+
*
|
|
122
|
+
* @param schemaName - The schema name to validate
|
|
123
|
+
* @param projectRoot - Optional project root for project-local schema resolution
|
|
124
|
+
*/
|
|
125
|
+
export function validateSchemaExists(schemaName, projectRoot) {
|
|
126
|
+
const schemaDir = getSchemaDir(schemaName, projectRoot);
|
|
127
|
+
if (!schemaDir) {
|
|
128
|
+
const availableSchemas = listSchemas(projectRoot);
|
|
129
|
+
throw new Error(`Schema '${schemaName}' not found. Available schemas:\n ${availableSchemas.join('\n ')}`);
|
|
130
|
+
}
|
|
131
|
+
return schemaName;
|
|
132
|
+
}
|
|
133
|
+
//# sourceMappingURL=shared.js.map
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Status Command
|
|
3
|
+
*
|
|
4
|
+
* Displays artifact completion status for a change.
|
|
5
|
+
*/
|
|
6
|
+
import { type ChangeStatus } from '../../core/artifact-graph/index.js';
|
|
7
|
+
export interface StatusOptions {
|
|
8
|
+
change?: string;
|
|
9
|
+
schema?: string;
|
|
10
|
+
store?: string;
|
|
11
|
+
storePath?: string;
|
|
12
|
+
json?: boolean;
|
|
13
|
+
}
|
|
14
|
+
export declare function statusCommand(options: StatusOptions): Promise<void>;
|
|
15
|
+
export declare function printStatusText(status: ChangeStatus): void;
|
|
16
|
+
//# sourceMappingURL=status.d.ts.map
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Status Command
|
|
3
|
+
*
|
|
4
|
+
* Displays artifact completion status for a change.
|
|
5
|
+
*/
|
|
6
|
+
import ora from 'ora';
|
|
7
|
+
import chalk from 'chalk';
|
|
8
|
+
import { getChangeDir } from '../../core/planning-home.js';
|
|
9
|
+
import { resolveRootForCommand, toPlanningHome, toRootOutput, withStoreFlag, isStoreSelectedRoot, } from '../../core/root-selection.js';
|
|
10
|
+
import { loadChangeContext, formatChangeStatus, } from '../../core/artifact-graph/index.js';
|
|
11
|
+
import { validateChangeExists, validateSchemaExists, getAvailableChanges, getStatusIndicator, getStatusColor, } from './shared.js';
|
|
12
|
+
// -----------------------------------------------------------------------------
|
|
13
|
+
// Command Implementation
|
|
14
|
+
// -----------------------------------------------------------------------------
|
|
15
|
+
export async function statusCommand(options) {
|
|
16
|
+
// The root resolves (and the store banner prints) before the spinner starts
|
|
17
|
+
// so the two do not fight over stderr.
|
|
18
|
+
const root = await resolveRootForCommand(options, { json: options.json });
|
|
19
|
+
if (!root) {
|
|
20
|
+
return;
|
|
21
|
+
}
|
|
22
|
+
const spinner = options.json ? undefined : ora('Loading change status...').start();
|
|
23
|
+
try {
|
|
24
|
+
const planningHome = toPlanningHome(root);
|
|
25
|
+
const projectRoot = root.path;
|
|
26
|
+
const rootOutput = toRootOutput(root);
|
|
27
|
+
const newChangeHint = withStoreFlag(root, 'openspec new change <name>');
|
|
28
|
+
// Handle no-changes case gracefully — status is informational,
|
|
29
|
+
// so "no changes" is a valid state, not an error.
|
|
30
|
+
if (!options.change) {
|
|
31
|
+
const available = await getAvailableChanges(projectRoot, root.changesDir);
|
|
32
|
+
if (available.length === 0) {
|
|
33
|
+
spinner?.stop();
|
|
34
|
+
if (options.json) {
|
|
35
|
+
console.log(JSON.stringify({ changes: [], message: 'No active changes.', root: rootOutput }, null, 2));
|
|
36
|
+
return;
|
|
37
|
+
}
|
|
38
|
+
console.log(`No active changes. Create one with: ${newChangeHint}`);
|
|
39
|
+
return;
|
|
40
|
+
}
|
|
41
|
+
// Changes exist but --change not provided
|
|
42
|
+
spinner?.stop();
|
|
43
|
+
throw new Error(`Missing required option --change. Available changes:\n ${available.join('\n ')}`);
|
|
44
|
+
}
|
|
45
|
+
const changeName = await validateChangeExists(options.change, projectRoot, root.changesDir, { newChangeHint });
|
|
46
|
+
// Validate schema if explicitly provided
|
|
47
|
+
if (options.schema) {
|
|
48
|
+
validateSchemaExists(options.schema, projectRoot);
|
|
49
|
+
}
|
|
50
|
+
// loadChangeContext will auto-detect schema from metadata if not provided
|
|
51
|
+
const context = loadChangeContext(projectRoot, changeName, options.schema, {
|
|
52
|
+
changeDir: getChangeDir(planningHome, changeName),
|
|
53
|
+
planningHome,
|
|
54
|
+
});
|
|
55
|
+
const status = formatChangeStatus(context, isStoreSelectedRoot(root) ? { storeId: root.storeId } : {});
|
|
56
|
+
spinner?.stop();
|
|
57
|
+
if (options.json) {
|
|
58
|
+
console.log(JSON.stringify({ ...status, root: rootOutput }, null, 2));
|
|
59
|
+
return;
|
|
60
|
+
}
|
|
61
|
+
printStatusText(status);
|
|
62
|
+
}
|
|
63
|
+
catch (error) {
|
|
64
|
+
spinner?.stop();
|
|
65
|
+
throw error;
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
export function printStatusText(status) {
|
|
69
|
+
const doneCount = status.artifacts.filter((a) => a.status === 'done').length;
|
|
70
|
+
const total = status.artifacts.length;
|
|
71
|
+
console.log(`Change: ${status.changeName}`);
|
|
72
|
+
console.log(`Schema: ${status.schemaName}`);
|
|
73
|
+
if (status.changeRoot) {
|
|
74
|
+
console.log(`Change root: ${status.changeRoot}`);
|
|
75
|
+
}
|
|
76
|
+
console.log(`Progress: ${doneCount}/${total} artifacts complete`);
|
|
77
|
+
console.log();
|
|
78
|
+
for (const artifact of status.artifacts) {
|
|
79
|
+
const indicator = getStatusIndicator(artifact.status);
|
|
80
|
+
const color = getStatusColor(artifact.status);
|
|
81
|
+
let line = `${indicator} ${artifact.id}`;
|
|
82
|
+
if (artifact.status === 'blocked' && artifact.missingDeps && artifact.missingDeps.length > 0) {
|
|
83
|
+
line += color(` (blocked by: ${artifact.missingDeps.join(', ')})`);
|
|
84
|
+
}
|
|
85
|
+
console.log(line);
|
|
86
|
+
}
|
|
87
|
+
if (status.isComplete) {
|
|
88
|
+
console.log();
|
|
89
|
+
console.log(chalk.green('All artifacts complete!'));
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
//# sourceMappingURL=status.js.map
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Templates Command
|
|
3
|
+
*
|
|
4
|
+
* Shows resolved template paths for all artifacts in a schema.
|
|
5
|
+
*/
|
|
6
|
+
export interface TemplatesOptions {
|
|
7
|
+
schema?: string;
|
|
8
|
+
json?: boolean;
|
|
9
|
+
}
|
|
10
|
+
export interface TemplateInfo {
|
|
11
|
+
artifactId: string;
|
|
12
|
+
templatePath: string;
|
|
13
|
+
source: 'project' | 'user' | 'package';
|
|
14
|
+
}
|
|
15
|
+
export declare function templatesCommand(options: TemplatesOptions): Promise<void>;
|
|
16
|
+
//# sourceMappingURL=templates.d.ts.map
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Templates Command
|
|
3
|
+
*
|
|
4
|
+
* Shows resolved template paths for all artifacts in a schema.
|
|
5
|
+
*/
|
|
6
|
+
import ora from 'ora';
|
|
7
|
+
import path from 'path';
|
|
8
|
+
import { resolveSchema, getSchemaDir, ArtifactGraph, } from '../../core/artifact-graph/index.js';
|
|
9
|
+
import { FileSystemUtils } from '../../utils/file-system.js';
|
|
10
|
+
import { validateSchemaExists, DEFAULT_SCHEMA } from './shared.js';
|
|
11
|
+
// -----------------------------------------------------------------------------
|
|
12
|
+
// Command Implementation
|
|
13
|
+
// -----------------------------------------------------------------------------
|
|
14
|
+
export async function templatesCommand(options) {
|
|
15
|
+
const spinner = options.json ? undefined : ora('Loading templates...').start();
|
|
16
|
+
try {
|
|
17
|
+
const projectRoot = process.cwd();
|
|
18
|
+
const schemaName = validateSchemaExists(options.schema ?? DEFAULT_SCHEMA, projectRoot);
|
|
19
|
+
const schema = resolveSchema(schemaName, projectRoot);
|
|
20
|
+
const graph = ArtifactGraph.fromSchema(schema);
|
|
21
|
+
const schemaDir = getSchemaDir(schemaName, projectRoot);
|
|
22
|
+
// Determine the source (project, user, or package)
|
|
23
|
+
const { getUserSchemasDir, getProjectSchemasDir, } = await import('../../core/artifact-graph/resolver.js');
|
|
24
|
+
const projectSchemasDir = getProjectSchemasDir(projectRoot);
|
|
25
|
+
const userSchemasDir = getUserSchemasDir();
|
|
26
|
+
// Determine source by checking if schemaDir is inside each base directory
|
|
27
|
+
// Using path.relative is more robust than startsWith for path comparisons
|
|
28
|
+
const isInsideDir = (child, parent) => {
|
|
29
|
+
const relative = path.relative(parent, child);
|
|
30
|
+
return !relative.startsWith('..') && !path.isAbsolute(relative);
|
|
31
|
+
};
|
|
32
|
+
let source;
|
|
33
|
+
if (isInsideDir(schemaDir, projectSchemasDir)) {
|
|
34
|
+
source = 'project';
|
|
35
|
+
}
|
|
36
|
+
else if (isInsideDir(schemaDir, userSchemasDir)) {
|
|
37
|
+
source = 'user';
|
|
38
|
+
}
|
|
39
|
+
else {
|
|
40
|
+
source = 'package';
|
|
41
|
+
}
|
|
42
|
+
const templates = graph.getAllArtifacts().map((artifact) => ({
|
|
43
|
+
artifactId: artifact.id,
|
|
44
|
+
templatePath: FileSystemUtils.canonicalizeExistingPath(path.join(schemaDir, 'templates', artifact.template)),
|
|
45
|
+
source,
|
|
46
|
+
}));
|
|
47
|
+
spinner?.stop();
|
|
48
|
+
if (options.json) {
|
|
49
|
+
const output = {};
|
|
50
|
+
for (const t of templates) {
|
|
51
|
+
output[t.artifactId] = { path: t.templatePath, source: t.source };
|
|
52
|
+
}
|
|
53
|
+
console.log(JSON.stringify(output, null, 2));
|
|
54
|
+
return;
|
|
55
|
+
}
|
|
56
|
+
console.log(`Schema: ${schemaName}`);
|
|
57
|
+
console.log(`Source: ${source}`);
|
|
58
|
+
console.log();
|
|
59
|
+
for (const t of templates) {
|
|
60
|
+
console.log(`${t.artifactId}:`);
|
|
61
|
+
console.log(` ${t.templatePath}`);
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
catch (error) {
|
|
65
|
+
spinner?.stop();
|
|
66
|
+
throw error;
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
//# sourceMappingURL=templates.js.map
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { type OpenerDefinition, type OpenerScanOptions } from '../core/openers.js';
|
|
2
|
+
import { StoreError } from '../core/store/errors.js';
|
|
3
|
+
import { type Workset, type WorksetMember } from '../core/worksets.js';
|
|
4
|
+
/** Concurrent stats; the first invalid flag (by flag order) reports. */
|
|
5
|
+
export declare function resolveMemberFlags(flags: string[]): Promise<WorksetMember[]>;
|
|
6
|
+
/** One spelling of "this tool id must exist in the merged table". */
|
|
7
|
+
export declare function assertKnownTool(tool: string, table: OpenerDefinition[]): void;
|
|
8
|
+
/** Final assembly shared by both compose paths: one validation rule. */
|
|
9
|
+
export declare function finalizeWorkset(name: string, members: WorksetMember[], tool: string | undefined, table: OpenerDefinition[]): Workset;
|
|
10
|
+
/** The aligned `<name> <path>` rows used by list, remove, and the
|
|
11
|
+
* open fallback; callers pick the stream and indent. */
|
|
12
|
+
export declare function formatMemberRows(members: WorksetMember[]): string[];
|
|
13
|
+
export declare function toolUnknownError(toolId: string, table: OpenerDefinition[]): StoreError;
|
|
14
|
+
/** Stops at the first installed alternative instead of scanning all. */
|
|
15
|
+
export declare function firstInstalledAlternative(table: OpenerDefinition[], excludeId: string | undefined, scan?: OpenerScanOptions): string | null;
|
|
16
|
+
export declare function toolUnavailableError(opener: OpenerDefinition, table: OpenerDefinition[], worksetName: string, scan?: OpenerScanOptions): StoreError;
|
|
17
|
+
/** Interactive open with no saved tool and nothing installed at all. */
|
|
18
|
+
export declare function noToolInstalledError(table: OpenerDefinition[], worksetName: string): StoreError;
|
|
19
|
+
//# sourceMappingURL=workset-input.d.ts.map
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Input resolution and error builders shared by the workset command
|
|
3
|
+
* and its interactive prompt flows.
|
|
4
|
+
*/
|
|
5
|
+
import * as path from 'node:path';
|
|
6
|
+
import { pathIsDirectory } from '../core/file-state.js';
|
|
7
|
+
import { findOpener, isOpenerCommandAvailable, isOpenerEnabled, } from '../core/openers.js';
|
|
8
|
+
import { StoreError } from '../core/store/errors.js';
|
|
9
|
+
import { expandUserPath } from '../core/store/operations.js';
|
|
10
|
+
import { getGlobalConfigPath } from '../core/global-config.js';
|
|
11
|
+
import { memberLabelProblem, memberListProblem, } from '../core/worksets.js';
|
|
12
|
+
function memberInvalidError(problem) {
|
|
13
|
+
return new StoreError(`Invalid workset member: ${problem}.`, 'workset_member_invalid', {
|
|
14
|
+
target: 'workset.member',
|
|
15
|
+
fix: 'Pass --member <path> with an existing folder, or --member <name>=<path> to label it.',
|
|
16
|
+
});
|
|
17
|
+
}
|
|
18
|
+
/** `--member <path>` or `--member <name>=<path>` (the first `=` splits). */
|
|
19
|
+
async function resolveMemberFlag(raw) {
|
|
20
|
+
const separator = raw.indexOf('=');
|
|
21
|
+
const label = separator > 0 ? raw.slice(0, separator) : undefined;
|
|
22
|
+
const rawPath = separator > 0 ? raw.slice(separator + 1) : raw;
|
|
23
|
+
if (rawPath.length === 0) {
|
|
24
|
+
throw memberInvalidError(`'${raw}' has no path`);
|
|
25
|
+
}
|
|
26
|
+
const resolvedPath = path.resolve(expandUserPath(rawPath));
|
|
27
|
+
if (!(await pathIsDirectory(resolvedPath))) {
|
|
28
|
+
throw memberInvalidError(`'${rawPath}' is not an existing folder`);
|
|
29
|
+
}
|
|
30
|
+
const name = label ?? path.basename(resolvedPath);
|
|
31
|
+
const labelProblem = memberLabelProblem(name);
|
|
32
|
+
if (labelProblem !== null) {
|
|
33
|
+
throw memberInvalidError(labelProblem);
|
|
34
|
+
}
|
|
35
|
+
return { name, path: resolvedPath };
|
|
36
|
+
}
|
|
37
|
+
/** Concurrent stats; the first invalid flag (by flag order) reports. */
|
|
38
|
+
export async function resolveMemberFlags(flags) {
|
|
39
|
+
const settled = await Promise.allSettled(flags.map(resolveMemberFlag));
|
|
40
|
+
const members = [];
|
|
41
|
+
for (const result of settled) {
|
|
42
|
+
if (result.status === 'rejected') {
|
|
43
|
+
throw result.reason;
|
|
44
|
+
}
|
|
45
|
+
members.push(result.value);
|
|
46
|
+
}
|
|
47
|
+
return members;
|
|
48
|
+
}
|
|
49
|
+
/** One spelling of "this tool id must exist in the merged table". */
|
|
50
|
+
export function assertKnownTool(tool, table) {
|
|
51
|
+
if (findOpener(table, tool) === null) {
|
|
52
|
+
throw toolUnknownError(tool, table);
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
/** Final assembly shared by both compose paths: one validation rule. */
|
|
56
|
+
export function finalizeWorkset(name, members, tool, table) {
|
|
57
|
+
const problem = memberListProblem(members);
|
|
58
|
+
if (problem !== null) {
|
|
59
|
+
throw memberInvalidError(problem);
|
|
60
|
+
}
|
|
61
|
+
if (tool !== undefined) {
|
|
62
|
+
assertKnownTool(tool, table);
|
|
63
|
+
}
|
|
64
|
+
return {
|
|
65
|
+
name,
|
|
66
|
+
...(tool !== undefined ? { tool } : {}),
|
|
67
|
+
members,
|
|
68
|
+
};
|
|
69
|
+
}
|
|
70
|
+
/** The aligned `<name> <path>` rows used by list, remove, and the
|
|
71
|
+
* open fallback; callers pick the stream and indent. */
|
|
72
|
+
export function formatMemberRows(members) {
|
|
73
|
+
const width = Math.max(...members.map((member) => member.name.length));
|
|
74
|
+
return members.map((member) => `${member.name.padEnd(width)} ${member.path}`);
|
|
75
|
+
}
|
|
76
|
+
export function toolUnknownError(toolId, table) {
|
|
77
|
+
const knownIds = table
|
|
78
|
+
.filter((opener) => isOpenerEnabled(opener))
|
|
79
|
+
.map((opener) => opener.id)
|
|
80
|
+
.join(', ');
|
|
81
|
+
return new StoreError(`Unknown tool '${toolId}'.`, 'workset_tool_unknown', {
|
|
82
|
+
target: 'workset.tool',
|
|
83
|
+
fix: `Known tools: ${knownIds}. Add new tools under "openers" in ${getGlobalConfigPath()}.`,
|
|
84
|
+
});
|
|
85
|
+
}
|
|
86
|
+
/** Stops at the first installed alternative instead of scanning all. */
|
|
87
|
+
export function firstInstalledAlternative(table, excludeId, scan) {
|
|
88
|
+
return (table.find((candidate) => candidate.id !== excludeId &&
|
|
89
|
+
isOpenerEnabled(candidate) &&
|
|
90
|
+
isOpenerCommandAvailable(candidate.command, scan))?.id ?? null);
|
|
91
|
+
}
|
|
92
|
+
export function toolUnavailableError(opener, table, worksetName, scan) {
|
|
93
|
+
const alternative = firstInstalledAlternative(table, opener.id, scan);
|
|
94
|
+
return new StoreError(`${opener.label} ('${opener.command}') is not on PATH.`, 'workset_tool_unavailable', {
|
|
95
|
+
target: 'workset.tool',
|
|
96
|
+
fix: alternative !== null
|
|
97
|
+
? `Install '${opener.command}' or run: openspec workset open ${worksetName} --tool ${alternative}`
|
|
98
|
+
: `Install '${opener.command}', then rerun: openspec workset open ${worksetName}`,
|
|
99
|
+
});
|
|
100
|
+
}
|
|
101
|
+
/** Interactive open with no saved tool and nothing installed at all. */
|
|
102
|
+
export function noToolInstalledError(table, worksetName) {
|
|
103
|
+
const commands = table
|
|
104
|
+
.filter((opener) => isOpenerEnabled(opener))
|
|
105
|
+
.map((opener) => opener.command)
|
|
106
|
+
.join(', ');
|
|
107
|
+
return new StoreError('None of the known tools is on PATH.', 'workset_tool_unavailable', {
|
|
108
|
+
target: 'workset.tool',
|
|
109
|
+
fix: `Install one of: ${commands}. Then rerun: openspec workset open ${worksetName}`,
|
|
110
|
+
});
|
|
111
|
+
}
|
|
112
|
+
//# sourceMappingURL=workset-input.js.map
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { type OpenerChoice, type OpenerDefinition } from '../core/openers.js';
|
|
2
|
+
import { type Workset } from '../core/worksets.js';
|
|
3
|
+
export interface ComposeInput {
|
|
4
|
+
memberFlags: string[];
|
|
5
|
+
tool?: string;
|
|
6
|
+
}
|
|
7
|
+
export declare function composeInteractively(givenName: string | undefined, input: ComposeInput, table: OpenerDefinition[]): Promise<Workset>;
|
|
8
|
+
export declare function promptToolFromChoices(available: OpenerChoice[]): Promise<string>;
|
|
9
|
+
export declare function promptOpenNow(label: string): Promise<boolean>;
|
|
10
|
+
/** Prints the workset (decision 13: remove shows what it removes). */
|
|
11
|
+
export declare function confirmRemoveInteractively(workset: Workset): Promise<boolean>;
|
|
12
|
+
//# sourceMappingURL=workset-prompts.d.ts.map
|