@superkou/openspec 1.4.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 +213 -0
- package/bin/openspec.js +5 -0
- package/dist/cli/index.d.ts +5 -0
- package/dist/cli/index.js +544 -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/context-store.d.ts +3 -0
- package/dist/commands/context-store.js +475 -0
- package/dist/commands/feedback.d.ts +9 -0
- package/dist/commands/feedback.js +183 -0
- package/dist/commands/initiative.d.ts +13 -0
- package/dist/commands/initiative.js +318 -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 +19 -0
- package/dist/commands/workflow/index.js +13 -0
- package/dist/commands/workflow/initiative-link.d.ts +24 -0
- package/dist/commands/workflow/initiative-link.js +47 -0
- package/dist/commands/workflow/instructions.d.ts +29 -0
- package/dist/commands/workflow/instructions.js +344 -0
- package/dist/commands/workflow/new-change.d.ts +17 -0
- package/dist/commands/workflow/new-change.js +141 -0
- package/dist/commands/workflow/schemas.d.ts +10 -0
- package/dist/commands/workflow/schemas.js +34 -0
- package/dist/commands/workflow/set-change.d.ts +13 -0
- package/dist/commands/workflow/set-change.js +87 -0
- package/dist/commands/workflow/shared.d.ts +59 -0
- package/dist/commands/workflow/shared.js +116 -0
- package/dist/commands/workflow/status.d.ts +14 -0
- package/dist/commands/workflow/status.js +90 -0
- package/dist/commands/workflow/templates.d.ts +16 -0
- package/dist/commands/workflow/templates.js +69 -0
- package/dist/commands/workspace/context-status.d.ts +4 -0
- package/dist/commands/workspace/context-status.js +59 -0
- package/dist/commands/workspace/open-target-selection.d.ts +13 -0
- package/dist/commands/workspace/open-target-selection.js +146 -0
- package/dist/commands/workspace/open-view.d.ts +62 -0
- package/dist/commands/workspace/open-view.js +249 -0
- package/dist/commands/workspace/open.d.ts +37 -0
- package/dist/commands/workspace/open.js +110 -0
- package/dist/commands/workspace/opener-selection.d.ts +11 -0
- package/dist/commands/workspace/opener-selection.js +98 -0
- package/dist/commands/workspace/operations.d.ts +29 -0
- package/dist/commands/workspace/operations.js +543 -0
- package/dist/commands/workspace/prompt-theme.d.ts +29 -0
- package/dist/commands/workspace/prompt-theme.js +24 -0
- package/dist/commands/workspace/registration.d.ts +13 -0
- package/dist/commands/workspace/registration.js +84 -0
- package/dist/commands/workspace/selection.d.ts +8 -0
- package/dist/commands/workspace/selection.js +104 -0
- package/dist/commands/workspace/setup-prompts.d.ts +13 -0
- package/dist/commands/workspace/setup-prompts.js +121 -0
- package/dist/commands/workspace/types.d.ts +103 -0
- package/dist/commands/workspace/types.js +36 -0
- package/dist/commands/workspace.d.ts +5 -0
- package/dist/commands/workspace.js +577 -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 +9 -0
- package/dist/core/artifact-graph/index.js +14 -0
- package/dist/core/artifact-graph/instruction-loader.d.ts +183 -0
- package/dist/core/artifact-graph/instruction-loader.js +256 -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 +18 -0
- package/dist/core/change-metadata/schema.js +28 -0
- package/dist/core/change-status-policy.d.ts +50 -0
- package/dist/core/change-status-policy.js +70 -0
- package/dist/core/collections/index.d.ts +3 -0
- package/dist/core/collections/index.js +3 -0
- package/dist/core/collections/initiatives/collection.d.ts +4 -0
- package/dist/core/collections/initiatives/collection.js +17 -0
- package/dist/core/collections/initiatives/index.d.ts +6 -0
- package/dist/core/collections/initiatives/index.js +6 -0
- package/dist/core/collections/initiatives/operations.d.ts +49 -0
- package/dist/core/collections/initiatives/operations.js +175 -0
- package/dist/core/collections/initiatives/resolution.d.ts +87 -0
- package/dist/core/collections/initiatives/resolution.js +374 -0
- package/dist/core/collections/initiatives/schema.d.ts +41 -0
- package/dist/core/collections/initiatives/schema.js +134 -0
- package/dist/core/collections/initiatives/templates.d.ts +12 -0
- package/dist/core/collections/initiatives/templates.js +90 -0
- package/dist/core/collections/runtime.d.ts +46 -0
- package/dist/core/collections/runtime.js +194 -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 +3 -0
- package/dist/core/completions/command-registry.js +961 -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/shared-flags.d.ts +12 -0
- package/dist/core/completions/shared-flags.js +28 -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 +39 -0
- package/dist/core/context-store/binding.d.ts +53 -0
- package/dist/core/context-store/binding.js +197 -0
- package/dist/core/context-store/errors.d.ts +20 -0
- package/dist/core/context-store/errors.js +22 -0
- package/dist/core/context-store/foundation.d.ts +55 -0
- package/dist/core/context-store/foundation.js +321 -0
- package/dist/core/context-store/index.d.ts +6 -0
- package/dist/core/context-store/index.js +6 -0
- package/dist/core/context-store/operations.d.ts +85 -0
- package/dist/core/context-store/operations.js +528 -0
- package/dist/core/context-store/registry.d.ts +45 -0
- package/dist/core/context-store/registry.js +229 -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 +6 -0
- package/dist/core/index.js +7 -0
- package/dist/core/init.d.ts +37 -0
- package/dist/core/init.js +593 -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 +108 -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 +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 +43 -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/workspace/foundation.d.ts +67 -0
- package/dist/core/workspace/foundation.js +295 -0
- package/dist/core/workspace/index.d.ts +8 -0
- package/dist/core/workspace/index.js +8 -0
- package/dist/core/workspace/legacy-state.d.ts +28 -0
- package/dist/core/workspace/legacy-state.js +200 -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 +45 -0
- package/dist/core/workspace/open-surface.js +215 -0
- package/dist/core/workspace/openers.d.ts +21 -0
- package/dist/core/workspace/openers.js +124 -0
- package/dist/core/workspace/registry.d.ts +24 -0
- package/dist/core/workspace/registry.js +146 -0
- package/dist/core/workspace/skills.d.ts +57 -0
- package/dist/core/workspace/skills.js +334 -0
- package/dist/core/workspace/state-io.d.ts +10 -0
- package/dist/core/workspace/state-io.js +121 -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 +54 -0
- package/dist/utils/change-metadata.js +141 -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 +85 -0
- package/schemas/spec-driven/schema.yaml +151 -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,611 @@
|
|
|
1
|
+
import { spawn, execSync } from 'node:child_process';
|
|
2
|
+
import * as fs from 'node:fs';
|
|
3
|
+
import * as path from 'node:path';
|
|
4
|
+
import { getGlobalConfigPath, getGlobalConfig, saveGlobalConfig, } from '../core/global-config.js';
|
|
5
|
+
import { getNestedValue, setNestedValue, deleteNestedValue, coerceValue, formatValueYaml, validateConfigKeyPath, validateConfig, DEFAULT_CONFIG, } from '../core/config-schema.js';
|
|
6
|
+
import { CORE_WORKFLOWS, ALL_WORKFLOWS, getProfileWorkflows } from '../core/profiles.js';
|
|
7
|
+
import { OPENSPEC_DIR_NAME } from '../core/config.js';
|
|
8
|
+
import { hasProjectConfigDrift } from '../core/profile-sync-drift.js';
|
|
9
|
+
import { findWorkspaceRoot, hasWorkspaceSkillProfileDrift, readOptionalWorkspaceViewState, } from '../core/workspace/index.js';
|
|
10
|
+
const WORKFLOW_PROMPT_META = {
|
|
11
|
+
propose: {
|
|
12
|
+
name: '提出变更',
|
|
13
|
+
description: '根据需求创建提案、设计和任务',
|
|
14
|
+
},
|
|
15
|
+
explore: {
|
|
16
|
+
name: '探索构思',
|
|
17
|
+
description: '实现前调查分析问题',
|
|
18
|
+
},
|
|
19
|
+
new: {
|
|
20
|
+
name: '新建变更',
|
|
21
|
+
description: '快速创建新的变更脚手架',
|
|
22
|
+
},
|
|
23
|
+
continue: {
|
|
24
|
+
name: '继续变更',
|
|
25
|
+
description: '继续处理现有变更',
|
|
26
|
+
},
|
|
27
|
+
apply: {
|
|
28
|
+
name: '执行任务',
|
|
29
|
+
description: '实现当前变更中的任务',
|
|
30
|
+
},
|
|
31
|
+
ff: {
|
|
32
|
+
name: '快速推进',
|
|
33
|
+
description: '运行更快的实施工作流',
|
|
34
|
+
},
|
|
35
|
+
sync: {
|
|
36
|
+
name: '同步规格',
|
|
37
|
+
description: '同步变更制品与规格',
|
|
38
|
+
},
|
|
39
|
+
archive: {
|
|
40
|
+
name: '归档变更',
|
|
41
|
+
description: '定稿并归档已完成的变更',
|
|
42
|
+
},
|
|
43
|
+
'bulk-archive': {
|
|
44
|
+
name: '批量归档',
|
|
45
|
+
description: '批量归档多个已完成变更',
|
|
46
|
+
},
|
|
47
|
+
verify: {
|
|
48
|
+
name: '验证变更',
|
|
49
|
+
description: '对变更运行验证检查',
|
|
50
|
+
},
|
|
51
|
+
onboard: {
|
|
52
|
+
name: '引导上手',
|
|
53
|
+
description: 'OpenSpec 引导式上手流程',
|
|
54
|
+
},
|
|
55
|
+
};
|
|
56
|
+
function isPromptCancellationError(error) {
|
|
57
|
+
return (error instanceof Error &&
|
|
58
|
+
(error.name === 'ExitPromptError' || error.message.includes('force closed the prompt with SIGINT')));
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* Resolve the effective current profile state from global config defaults.
|
|
62
|
+
*/
|
|
63
|
+
export function resolveCurrentProfileState(config) {
|
|
64
|
+
const profile = config.profile || 'core';
|
|
65
|
+
const delivery = config.delivery || 'both';
|
|
66
|
+
const workflows = [
|
|
67
|
+
...getProfileWorkflows(profile, config.workflows ? [...config.workflows] : undefined),
|
|
68
|
+
];
|
|
69
|
+
return { profile, delivery, workflows };
|
|
70
|
+
}
|
|
71
|
+
/**
|
|
72
|
+
* Derive profile type from selected workflows.
|
|
73
|
+
*/
|
|
74
|
+
export function deriveProfileFromWorkflowSelection(selectedWorkflows) {
|
|
75
|
+
const isCoreMatch = selectedWorkflows.length === CORE_WORKFLOWS.length &&
|
|
76
|
+
CORE_WORKFLOWS.every((w) => selectedWorkflows.includes(w));
|
|
77
|
+
return isCoreMatch ? 'core' : 'custom';
|
|
78
|
+
}
|
|
79
|
+
/**
|
|
80
|
+
* Format a compact workflow summary for the profile header.
|
|
81
|
+
*/
|
|
82
|
+
export function formatWorkflowSummary(workflows, profile) {
|
|
83
|
+
return `${workflows.length} 个已选 (${profile})`;
|
|
84
|
+
}
|
|
85
|
+
function stableWorkflowOrder(workflows) {
|
|
86
|
+
const seen = new Set();
|
|
87
|
+
const ordered = [];
|
|
88
|
+
for (const workflow of ALL_WORKFLOWS) {
|
|
89
|
+
if (workflows.includes(workflow) && !seen.has(workflow)) {
|
|
90
|
+
ordered.push(workflow);
|
|
91
|
+
seen.add(workflow);
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
const extras = workflows.filter((w) => !ALL_WORKFLOWS.includes(w));
|
|
95
|
+
extras.sort();
|
|
96
|
+
for (const extra of extras) {
|
|
97
|
+
if (!seen.has(extra)) {
|
|
98
|
+
ordered.push(extra);
|
|
99
|
+
seen.add(extra);
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
return ordered;
|
|
103
|
+
}
|
|
104
|
+
/**
|
|
105
|
+
* Build a user-facing diff summary between two profile states.
|
|
106
|
+
*/
|
|
107
|
+
export function diffProfileState(before, after) {
|
|
108
|
+
const lines = [];
|
|
109
|
+
if (before.delivery !== after.delivery) {
|
|
110
|
+
lines.push(`交付方式: ${before.delivery} -> ${after.delivery}`);
|
|
111
|
+
}
|
|
112
|
+
if (before.profile !== after.profile) {
|
|
113
|
+
lines.push(`配置文件: ${before.profile} -> ${after.profile}`);
|
|
114
|
+
}
|
|
115
|
+
const beforeOrdered = stableWorkflowOrder(before.workflows);
|
|
116
|
+
const afterOrdered = stableWorkflowOrder(after.workflows);
|
|
117
|
+
const beforeSet = new Set(beforeOrdered);
|
|
118
|
+
const afterSet = new Set(afterOrdered);
|
|
119
|
+
const added = afterOrdered.filter((w) => !beforeSet.has(w));
|
|
120
|
+
const removed = beforeOrdered.filter((w) => !afterSet.has(w));
|
|
121
|
+
if (added.length > 0 || removed.length > 0) {
|
|
122
|
+
const tokens = [];
|
|
123
|
+
if (added.length > 0) {
|
|
124
|
+
tokens.push(`新增 ${added.join(', ')}`);
|
|
125
|
+
}
|
|
126
|
+
if (removed.length > 0) {
|
|
127
|
+
tokens.push(`移除 ${removed.join(', ')}`);
|
|
128
|
+
}
|
|
129
|
+
lines.push(`工作流: ${tokens.join('; ')}`);
|
|
130
|
+
}
|
|
131
|
+
return {
|
|
132
|
+
hasChanges: lines.length > 0,
|
|
133
|
+
lines,
|
|
134
|
+
};
|
|
135
|
+
}
|
|
136
|
+
async function resolveWorkspaceConfigProfileContext(cwd = process.cwd()) {
|
|
137
|
+
const workspaceRoot = await findWorkspaceRoot(cwd);
|
|
138
|
+
if (!workspaceRoot) {
|
|
139
|
+
return null;
|
|
140
|
+
}
|
|
141
|
+
return {
|
|
142
|
+
root: workspaceRoot,
|
|
143
|
+
commandCwd: cwd,
|
|
144
|
+
};
|
|
145
|
+
}
|
|
146
|
+
function maybeWarnProjectConfigDrift(projectDir, state, colorize) {
|
|
147
|
+
const openspecDir = path.join(projectDir, OPENSPEC_DIR_NAME);
|
|
148
|
+
if (!fs.existsSync(openspecDir)) {
|
|
149
|
+
return;
|
|
150
|
+
}
|
|
151
|
+
if (!hasProjectConfigDrift(projectDir, state.workflows, state.delivery)) {
|
|
152
|
+
return;
|
|
153
|
+
}
|
|
154
|
+
console.log(colorize('警告:全局配置尚未应用到该项目。请运行 `openspec update` 同步。'));
|
|
155
|
+
}
|
|
156
|
+
async function maybeWarnConfigDrift(state, colorize) {
|
|
157
|
+
const workspaceContext = await resolveWorkspaceConfigProfileContext();
|
|
158
|
+
if (workspaceContext) {
|
|
159
|
+
let viewState = null;
|
|
160
|
+
try {
|
|
161
|
+
viewState = await readOptionalWorkspaceViewState(workspaceContext.root);
|
|
162
|
+
}
|
|
163
|
+
catch {
|
|
164
|
+
return;
|
|
165
|
+
}
|
|
166
|
+
if (hasWorkspaceSkillProfileDrift(viewState)) {
|
|
167
|
+
console.log(colorize('警告:工作区本地 Agent 技能与当前全局配置文件不同步。请运行 `openspec workspace update` 同步。'));
|
|
168
|
+
}
|
|
169
|
+
return;
|
|
170
|
+
}
|
|
171
|
+
maybeWarnProjectConfigDrift(process.cwd(), state, colorize);
|
|
172
|
+
}
|
|
173
|
+
function printConfigProfileApplyGuidance(workspaceContext) {
|
|
174
|
+
if (workspaceContext) {
|
|
175
|
+
console.log('配置已更新。运行 `openspec workspace update` 将其应用到工作区本地技能。');
|
|
176
|
+
return;
|
|
177
|
+
}
|
|
178
|
+
console.log('配置已更新。在项目中运行 `openspec update` 以应用。');
|
|
179
|
+
}
|
|
180
|
+
/**
|
|
181
|
+
* Register the config command and all its subcommands.
|
|
182
|
+
*
|
|
183
|
+
* @param program - The Commander program instance
|
|
184
|
+
*/
|
|
185
|
+
export function registerConfigCommand(program) {
|
|
186
|
+
const configCmd = program
|
|
187
|
+
.command('config')
|
|
188
|
+
.description('查看和修改全局 OpenSpec 配置')
|
|
189
|
+
.option('--scope <scope>', '配置作用域(目前仅支持 "global")')
|
|
190
|
+
.hook('preAction', (thisCommand) => {
|
|
191
|
+
const opts = thisCommand.opts();
|
|
192
|
+
if (opts.scope && opts.scope !== 'global') {
|
|
193
|
+
console.error('错误:项目级配置尚未实现');
|
|
194
|
+
process.exit(1);
|
|
195
|
+
}
|
|
196
|
+
});
|
|
197
|
+
// config path
|
|
198
|
+
configCmd
|
|
199
|
+
.command('path')
|
|
200
|
+
.description('显示配置文件路径')
|
|
201
|
+
.action(() => {
|
|
202
|
+
console.log(getGlobalConfigPath());
|
|
203
|
+
});
|
|
204
|
+
// config list
|
|
205
|
+
configCmd
|
|
206
|
+
.command('list')
|
|
207
|
+
.description('显示所有当前设置')
|
|
208
|
+
.option('--json', '以 JSON 格式输出')
|
|
209
|
+
.action((options) => {
|
|
210
|
+
const config = getGlobalConfig();
|
|
211
|
+
if (options.json) {
|
|
212
|
+
console.log(JSON.stringify(config, null, 2));
|
|
213
|
+
}
|
|
214
|
+
else {
|
|
215
|
+
// Read raw config to determine which values are explicit vs defaults
|
|
216
|
+
const configPath = getGlobalConfigPath();
|
|
217
|
+
let rawConfig = {};
|
|
218
|
+
try {
|
|
219
|
+
if (fs.existsSync(configPath)) {
|
|
220
|
+
rawConfig = JSON.parse(fs.readFileSync(configPath, 'utf-8'));
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
catch {
|
|
224
|
+
// If reading fails, treat all as defaults
|
|
225
|
+
}
|
|
226
|
+
console.log(formatValueYaml(config));
|
|
227
|
+
// Annotate profile settings
|
|
228
|
+
const profileSource = rawConfig.profile !== undefined ? '(显式设置)' : '(默认)';
|
|
229
|
+
const deliverySource = rawConfig.delivery !== undefined ? '(显式设置)' : '(默认)';
|
|
230
|
+
console.log(`\n配置文件设置:`);
|
|
231
|
+
console.log(` profile: ${config.profile} ${profileSource}`);
|
|
232
|
+
console.log(` delivery: ${config.delivery} ${deliverySource}`);
|
|
233
|
+
if (config.profile === 'core') {
|
|
234
|
+
console.log(` workflows: ${CORE_WORKFLOWS.join(', ')}(来自 core 配置文件)`);
|
|
235
|
+
}
|
|
236
|
+
else if (config.workflows && config.workflows.length > 0) {
|
|
237
|
+
console.log(` workflows: ${config.workflows.join(', ')}(显式设置)`);
|
|
238
|
+
}
|
|
239
|
+
else {
|
|
240
|
+
console.log(` workflows:(无)`);
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
});
|
|
244
|
+
// config get
|
|
245
|
+
configCmd
|
|
246
|
+
.command('get <key>')
|
|
247
|
+
.description('获取特定值(原始格式,可脚本化)')
|
|
248
|
+
.action((key) => {
|
|
249
|
+
const config = getGlobalConfig();
|
|
250
|
+
const value = getNestedValue(config, key);
|
|
251
|
+
if (value === undefined) {
|
|
252
|
+
process.exitCode = 1;
|
|
253
|
+
return;
|
|
254
|
+
}
|
|
255
|
+
if (typeof value === 'object' && value !== null) {
|
|
256
|
+
console.log(JSON.stringify(value));
|
|
257
|
+
}
|
|
258
|
+
else {
|
|
259
|
+
console.log(String(value));
|
|
260
|
+
}
|
|
261
|
+
});
|
|
262
|
+
// config set
|
|
263
|
+
configCmd
|
|
264
|
+
.command('set <key> <value>')
|
|
265
|
+
.description('设置一个值(自动类型转换)')
|
|
266
|
+
.option('--string', '强制将值存储为字符串')
|
|
267
|
+
.option('--allow-unknown', '允许设置未预定义的键')
|
|
268
|
+
.action((key, value, options) => {
|
|
269
|
+
const allowUnknown = Boolean(options.allowUnknown);
|
|
270
|
+
const keyValidation = validateConfigKeyPath(key);
|
|
271
|
+
if (!keyValidation.valid && !allowUnknown) {
|
|
272
|
+
const reason = keyValidation.reason ? ` ${keyValidation.reason}。` : '';
|
|
273
|
+
console.error(`错误:无效的配置键 "${key}"。${reason}`);
|
|
274
|
+
console.error('使用 "openspec config list" 查看可用的键。');
|
|
275
|
+
console.error('使用 --allow-unknown 跳过此检查。');
|
|
276
|
+
process.exitCode = 1;
|
|
277
|
+
return;
|
|
278
|
+
}
|
|
279
|
+
const config = getGlobalConfig();
|
|
280
|
+
const coercedValue = coerceValue(value, options.string || false);
|
|
281
|
+
// Create a copy to validate before saving
|
|
282
|
+
const newConfig = JSON.parse(JSON.stringify(config));
|
|
283
|
+
setNestedValue(newConfig, key, coercedValue);
|
|
284
|
+
// Validate the new config
|
|
285
|
+
const validation = validateConfig(newConfig);
|
|
286
|
+
if (!validation.success) {
|
|
287
|
+
console.error(`错误:配置无效 - ${validation.error}`);
|
|
288
|
+
process.exitCode = 1;
|
|
289
|
+
return;
|
|
290
|
+
}
|
|
291
|
+
// Apply changes and save
|
|
292
|
+
setNestedValue(config, key, coercedValue);
|
|
293
|
+
saveGlobalConfig(config);
|
|
294
|
+
const displayValue = typeof coercedValue === 'string' ? `"${coercedValue}"` : String(coercedValue);
|
|
295
|
+
console.log(`已设置 ${key} = ${displayValue}`);
|
|
296
|
+
});
|
|
297
|
+
// config unset
|
|
298
|
+
configCmd
|
|
299
|
+
.command('unset <key>')
|
|
300
|
+
.description('删除一个键(恢复为默认值)')
|
|
301
|
+
.action((key) => {
|
|
302
|
+
const config = getGlobalConfig();
|
|
303
|
+
const existed = deleteNestedValue(config, key);
|
|
304
|
+
if (existed) {
|
|
305
|
+
saveGlobalConfig(config);
|
|
306
|
+
console.log(`已取消设置 ${key}(已恢复为默认值)`);
|
|
307
|
+
}
|
|
308
|
+
else {
|
|
309
|
+
console.log(`键 "${key}" 未被设置`);
|
|
310
|
+
}
|
|
311
|
+
});
|
|
312
|
+
// config reset
|
|
313
|
+
configCmd
|
|
314
|
+
.command('reset')
|
|
315
|
+
.description('将配置重置为默认值')
|
|
316
|
+
.option('--all', '重置所有配置(必选)')
|
|
317
|
+
.option('-y, --yes', '跳过确认提示')
|
|
318
|
+
.action(async (options) => {
|
|
319
|
+
if (!options.all) {
|
|
320
|
+
console.error('错误:重置需要 --all 标志');
|
|
321
|
+
console.error('用法:openspec config reset --all [-y]');
|
|
322
|
+
process.exitCode = 1;
|
|
323
|
+
return;
|
|
324
|
+
}
|
|
325
|
+
if (!options.yes) {
|
|
326
|
+
const { confirm } = await import('@inquirer/prompts');
|
|
327
|
+
let confirmed;
|
|
328
|
+
try {
|
|
329
|
+
confirmed = await confirm({
|
|
330
|
+
message: '将所有配置重置为默认值?',
|
|
331
|
+
default: false,
|
|
332
|
+
});
|
|
333
|
+
}
|
|
334
|
+
catch (error) {
|
|
335
|
+
if (isPromptCancellationError(error)) {
|
|
336
|
+
console.log('已取消重置。');
|
|
337
|
+
process.exitCode = 130;
|
|
338
|
+
return;
|
|
339
|
+
}
|
|
340
|
+
throw error;
|
|
341
|
+
}
|
|
342
|
+
if (!confirmed) {
|
|
343
|
+
console.log('已取消重置。');
|
|
344
|
+
return;
|
|
345
|
+
}
|
|
346
|
+
}
|
|
347
|
+
saveGlobalConfig({ ...DEFAULT_CONFIG });
|
|
348
|
+
console.log('配置已重置为默认值');
|
|
349
|
+
});
|
|
350
|
+
// config edit
|
|
351
|
+
configCmd
|
|
352
|
+
.command('edit')
|
|
353
|
+
.description('在 $EDITOR 中编辑配置')
|
|
354
|
+
.action(async () => {
|
|
355
|
+
const editor = process.env.EDITOR || process.env.VISUAL;
|
|
356
|
+
if (!editor) {
|
|
357
|
+
console.error('错误:未配置编辑器');
|
|
358
|
+
console.error('设置 EDITOR 或 VISUAL 环境变量为您偏好的编辑器');
|
|
359
|
+
console.error('示例:export EDITOR=vim');
|
|
360
|
+
process.exitCode = 1;
|
|
361
|
+
return;
|
|
362
|
+
}
|
|
363
|
+
const configPath = getGlobalConfigPath();
|
|
364
|
+
// Ensure config file exists with defaults
|
|
365
|
+
if (!fs.existsSync(configPath)) {
|
|
366
|
+
saveGlobalConfig({ ...DEFAULT_CONFIG });
|
|
367
|
+
}
|
|
368
|
+
// Spawn editor and wait for it to close
|
|
369
|
+
// Avoid shell parsing to correctly handle paths with spaces in both
|
|
370
|
+
// the editor path and config path
|
|
371
|
+
const child = spawn(editor, [configPath], {
|
|
372
|
+
stdio: 'inherit',
|
|
373
|
+
shell: false,
|
|
374
|
+
});
|
|
375
|
+
await new Promise((resolve, reject) => {
|
|
376
|
+
child.on('close', (code) => {
|
|
377
|
+
if (code === 0) {
|
|
378
|
+
resolve();
|
|
379
|
+
}
|
|
380
|
+
else {
|
|
381
|
+
reject(new Error(`编辑器退出,退出码为 ${code}`));
|
|
382
|
+
}
|
|
383
|
+
});
|
|
384
|
+
child.on('error', reject);
|
|
385
|
+
});
|
|
386
|
+
try {
|
|
387
|
+
const rawConfig = fs.readFileSync(configPath, 'utf-8');
|
|
388
|
+
const parsedConfig = JSON.parse(rawConfig);
|
|
389
|
+
const validation = validateConfig(parsedConfig);
|
|
390
|
+
if (!validation.success) {
|
|
391
|
+
console.error(`错误:配置无效 - ${validation.error}`);
|
|
392
|
+
process.exitCode = 1;
|
|
393
|
+
}
|
|
394
|
+
}
|
|
395
|
+
catch (error) {
|
|
396
|
+
if (error.code === 'ENOENT') {
|
|
397
|
+
console.error(`错误:未找到配置文件 ${configPath}`);
|
|
398
|
+
}
|
|
399
|
+
else if (error instanceof SyntaxError) {
|
|
400
|
+
console.error(`错误:${configPath} 中的 JSON 格式无效`);
|
|
401
|
+
console.error(error.message);
|
|
402
|
+
}
|
|
403
|
+
else {
|
|
404
|
+
console.error(`错误:无法验证配置 - ${error instanceof Error ? error.message : String(error)}`);
|
|
405
|
+
}
|
|
406
|
+
process.exitCode = 1;
|
|
407
|
+
}
|
|
408
|
+
});
|
|
409
|
+
// config profile [preset]
|
|
410
|
+
configCmd
|
|
411
|
+
.command('profile [preset]')
|
|
412
|
+
.description('配置工作流配置文件(交互式选择或预设快捷方式)')
|
|
413
|
+
.action(async (preset) => {
|
|
414
|
+
// Preset shortcut: `openspec config profile core`
|
|
415
|
+
if (preset === 'core') {
|
|
416
|
+
const config = getGlobalConfig();
|
|
417
|
+
config.profile = 'core';
|
|
418
|
+
config.workflows = [...CORE_WORKFLOWS];
|
|
419
|
+
// Preserve delivery setting
|
|
420
|
+
saveGlobalConfig(config);
|
|
421
|
+
const workspaceContext = await resolveWorkspaceConfigProfileContext();
|
|
422
|
+
printConfigProfileApplyGuidance(workspaceContext);
|
|
423
|
+
return;
|
|
424
|
+
}
|
|
425
|
+
if (preset) {
|
|
426
|
+
console.error(`错误:未知的配置文件预设 "${preset}"。可用预设:core`);
|
|
427
|
+
process.exitCode = 1;
|
|
428
|
+
return;
|
|
429
|
+
}
|
|
430
|
+
// Non-interactive check
|
|
431
|
+
if (!process.stdout.isTTY) {
|
|
432
|
+
console.error('需要交互模式。请使用 `openspec config profile core` 或通过环境变量/标志设置配置。');
|
|
433
|
+
process.exitCode = 1;
|
|
434
|
+
return;
|
|
435
|
+
}
|
|
436
|
+
// Interactive picker
|
|
437
|
+
const { select, checkbox, confirm } = await import('@inquirer/prompts');
|
|
438
|
+
const chalk = (await import('chalk')).default;
|
|
439
|
+
try {
|
|
440
|
+
const config = getGlobalConfig();
|
|
441
|
+
const currentState = resolveCurrentProfileState(config);
|
|
442
|
+
console.log(chalk.bold('\n当前配置文件设置'));
|
|
443
|
+
console.log(` 交付方式: ${currentState.delivery}`);
|
|
444
|
+
console.log(` 工作流: ${formatWorkflowSummary(currentState.workflows, currentState.profile)}`);
|
|
445
|
+
console.log(chalk.dim(' 交付方式 = 工作流的安装位置(skills、commands 或 both)'));
|
|
446
|
+
console.log(chalk.dim(' 工作流 = 可用的操作(propose、explore、apply 等)'));
|
|
447
|
+
console.log();
|
|
448
|
+
const action = await select({
|
|
449
|
+
message: '您想配置什么?',
|
|
450
|
+
choices: [
|
|
451
|
+
{
|
|
452
|
+
value: 'both',
|
|
453
|
+
name: '交付方式和工作流',
|
|
454
|
+
description: '同时更新安装模式和可用操作',
|
|
455
|
+
},
|
|
456
|
+
{
|
|
457
|
+
value: 'delivery',
|
|
458
|
+
name: '仅交付方式',
|
|
459
|
+
description: '更改工作流的安装位置',
|
|
460
|
+
},
|
|
461
|
+
{
|
|
462
|
+
value: 'workflows',
|
|
463
|
+
name: '仅工作流',
|
|
464
|
+
description: '更改可用的工作流操作',
|
|
465
|
+
},
|
|
466
|
+
{
|
|
467
|
+
value: 'keep',
|
|
468
|
+
name: '保留当前设置(退出)',
|
|
469
|
+
description: '保持配置不变并退出',
|
|
470
|
+
},
|
|
471
|
+
],
|
|
472
|
+
});
|
|
473
|
+
if (action === 'keep') {
|
|
474
|
+
console.log('配置未更改。');
|
|
475
|
+
await maybeWarnConfigDrift(currentState, chalk.yellow);
|
|
476
|
+
return;
|
|
477
|
+
}
|
|
478
|
+
const nextState = {
|
|
479
|
+
profile: currentState.profile,
|
|
480
|
+
delivery: currentState.delivery,
|
|
481
|
+
workflows: [...currentState.workflows],
|
|
482
|
+
};
|
|
483
|
+
if (action === 'both' || action === 'delivery') {
|
|
484
|
+
const deliveryChoices = [
|
|
485
|
+
{
|
|
486
|
+
value: 'both',
|
|
487
|
+
name: '两者(skills + commands)',
|
|
488
|
+
description: '将工作流同时安装为技能和斜杠命令',
|
|
489
|
+
},
|
|
490
|
+
{
|
|
491
|
+
value: 'skills',
|
|
492
|
+
name: '仅技能',
|
|
493
|
+
description: '仅将工作流安装为技能',
|
|
494
|
+
},
|
|
495
|
+
{
|
|
496
|
+
value: 'commands',
|
|
497
|
+
name: '仅命令',
|
|
498
|
+
description: '仅将工作流安装为斜杠命令',
|
|
499
|
+
},
|
|
500
|
+
];
|
|
501
|
+
for (const choice of deliveryChoices) {
|
|
502
|
+
if (choice.value === currentState.delivery) {
|
|
503
|
+
choice.name += ' [当前]';
|
|
504
|
+
}
|
|
505
|
+
}
|
|
506
|
+
nextState.delivery = await select({
|
|
507
|
+
message: '交付模式(工作流的安装方式):',
|
|
508
|
+
choices: deliveryChoices,
|
|
509
|
+
default: currentState.delivery,
|
|
510
|
+
});
|
|
511
|
+
}
|
|
512
|
+
if (action === 'both' || action === 'workflows') {
|
|
513
|
+
const formatWorkflowChoice = (workflow) => {
|
|
514
|
+
const metadata = WORKFLOW_PROMPT_META[workflow] ?? {
|
|
515
|
+
name: workflow,
|
|
516
|
+
description: `工作流:${workflow}`,
|
|
517
|
+
};
|
|
518
|
+
return {
|
|
519
|
+
value: workflow,
|
|
520
|
+
name: metadata.name,
|
|
521
|
+
description: metadata.description,
|
|
522
|
+
short: metadata.name,
|
|
523
|
+
checked: currentState.workflows.includes(workflow),
|
|
524
|
+
};
|
|
525
|
+
};
|
|
526
|
+
const selectedWorkflows = await checkbox({
|
|
527
|
+
message: '选择要启用的工作流:',
|
|
528
|
+
instructions: '空格键切换,回车键确认',
|
|
529
|
+
pageSize: ALL_WORKFLOWS.length,
|
|
530
|
+
theme: {
|
|
531
|
+
icon: {
|
|
532
|
+
checked: '[x]',
|
|
533
|
+
unchecked: '[ ]',
|
|
534
|
+
},
|
|
535
|
+
},
|
|
536
|
+
choices: ALL_WORKFLOWS.map(formatWorkflowChoice),
|
|
537
|
+
});
|
|
538
|
+
nextState.workflows = selectedWorkflows;
|
|
539
|
+
nextState.profile = deriveProfileFromWorkflowSelection(selectedWorkflows);
|
|
540
|
+
}
|
|
541
|
+
const diff = diffProfileState(currentState, nextState);
|
|
542
|
+
if (!diff.hasChanges) {
|
|
543
|
+
console.log('配置未更改。');
|
|
544
|
+
await maybeWarnConfigDrift(nextState, chalk.yellow);
|
|
545
|
+
return;
|
|
546
|
+
}
|
|
547
|
+
console.log(chalk.bold('\n配置变更:'));
|
|
548
|
+
for (const line of diff.lines) {
|
|
549
|
+
console.log(` ${line}`);
|
|
550
|
+
}
|
|
551
|
+
console.log();
|
|
552
|
+
config.profile = nextState.profile;
|
|
553
|
+
config.delivery = nextState.delivery;
|
|
554
|
+
config.workflows = nextState.workflows;
|
|
555
|
+
saveGlobalConfig(config);
|
|
556
|
+
const workspaceContext = await resolveWorkspaceConfigProfileContext();
|
|
557
|
+
if (workspaceContext) {
|
|
558
|
+
const applyNow = await confirm({
|
|
559
|
+
message: '立即将变更应用到当前工作区?',
|
|
560
|
+
default: true,
|
|
561
|
+
});
|
|
562
|
+
if (applyNow) {
|
|
563
|
+
try {
|
|
564
|
+
execSync('npx openspec workspace update', {
|
|
565
|
+
stdio: 'inherit',
|
|
566
|
+
cwd: workspaceContext.commandCwd,
|
|
567
|
+
});
|
|
568
|
+
console.log('在其他工作区中运行 `openspec workspace update` 以应用变更。');
|
|
569
|
+
}
|
|
570
|
+
catch {
|
|
571
|
+
console.error('`openspec workspace update` 执行失败。请手动运行它以应用配置文件变更。');
|
|
572
|
+
process.exitCode = 1;
|
|
573
|
+
}
|
|
574
|
+
return;
|
|
575
|
+
}
|
|
576
|
+
printConfigProfileApplyGuidance(workspaceContext);
|
|
577
|
+
return;
|
|
578
|
+
}
|
|
579
|
+
// Check if inside an OpenSpec project
|
|
580
|
+
const projectDir = process.cwd();
|
|
581
|
+
const openspecDir = path.join(projectDir, OPENSPEC_DIR_NAME);
|
|
582
|
+
if (fs.existsSync(openspecDir)) {
|
|
583
|
+
const applyNow = await confirm({
|
|
584
|
+
message: '立即将变更应用到当前项目?',
|
|
585
|
+
default: true,
|
|
586
|
+
});
|
|
587
|
+
if (applyNow) {
|
|
588
|
+
try {
|
|
589
|
+
execSync('npx openspec update', { stdio: 'inherit', cwd: projectDir });
|
|
590
|
+
console.log('在其他项目中运行 `openspec update` 以应用变更。');
|
|
591
|
+
}
|
|
592
|
+
catch {
|
|
593
|
+
console.error('`openspec update` 执行失败。请手动运行它以应用配置文件变更。');
|
|
594
|
+
process.exitCode = 1;
|
|
595
|
+
}
|
|
596
|
+
return;
|
|
597
|
+
}
|
|
598
|
+
}
|
|
599
|
+
printConfigProfileApplyGuidance(null);
|
|
600
|
+
}
|
|
601
|
+
catch (error) {
|
|
602
|
+
if (isPromptCancellationError(error)) {
|
|
603
|
+
console.log('已取消配置文件设置。');
|
|
604
|
+
process.exitCode = 130;
|
|
605
|
+
return;
|
|
606
|
+
}
|
|
607
|
+
throw error;
|
|
608
|
+
}
|
|
609
|
+
});
|
|
610
|
+
}
|
|
611
|
+
//# sourceMappingURL=config.js.map
|