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,183 @@
|
|
|
1
|
+
import { execSync, execFileSync } from 'child_process';
|
|
2
|
+
import { createRequire } from 'module';
|
|
3
|
+
import os from 'os';
|
|
4
|
+
const require = createRequire(import.meta.url);
|
|
5
|
+
/**
|
|
6
|
+
* Check if gh CLI is installed and available in PATH
|
|
7
|
+
* Uses platform-appropriate command: 'where' on Windows, 'which' on Unix/macOS
|
|
8
|
+
*/
|
|
9
|
+
function isGhInstalled() {
|
|
10
|
+
try {
|
|
11
|
+
const command = process.platform === 'win32' ? 'where gh' : 'which gh';
|
|
12
|
+
execSync(command, { stdio: 'pipe' });
|
|
13
|
+
return true;
|
|
14
|
+
}
|
|
15
|
+
catch {
|
|
16
|
+
return false;
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Check if gh CLI is authenticated
|
|
21
|
+
*/
|
|
22
|
+
function isGhAuthenticated() {
|
|
23
|
+
try {
|
|
24
|
+
execSync('gh auth status', { stdio: 'pipe' });
|
|
25
|
+
return true;
|
|
26
|
+
}
|
|
27
|
+
catch {
|
|
28
|
+
return false;
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Get OpenSpec version from package.json
|
|
33
|
+
*/
|
|
34
|
+
function getVersion() {
|
|
35
|
+
try {
|
|
36
|
+
const { version } = require('../../package.json');
|
|
37
|
+
return version;
|
|
38
|
+
}
|
|
39
|
+
catch {
|
|
40
|
+
return 'unknown';
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* Get platform name
|
|
45
|
+
*/
|
|
46
|
+
function getPlatform() {
|
|
47
|
+
return os.platform();
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* Get current timestamp in ISO format
|
|
51
|
+
*/
|
|
52
|
+
function getTimestamp() {
|
|
53
|
+
return new Date().toISOString();
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* Generate metadata footer for feedback
|
|
57
|
+
*/
|
|
58
|
+
function generateMetadata() {
|
|
59
|
+
const version = getVersion();
|
|
60
|
+
const platform = getPlatform();
|
|
61
|
+
const timestamp = getTimestamp();
|
|
62
|
+
return `---
|
|
63
|
+
Submitted via OpenSpec CLI
|
|
64
|
+
- Version: ${version}
|
|
65
|
+
- Platform: ${platform}
|
|
66
|
+
- Timestamp: ${timestamp}`;
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* Format the feedback title
|
|
70
|
+
*/
|
|
71
|
+
function formatTitle(message) {
|
|
72
|
+
return `Feedback: ${message}`;
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* Format the full feedback body
|
|
76
|
+
*/
|
|
77
|
+
function formatBody(bodyText) {
|
|
78
|
+
const parts = [];
|
|
79
|
+
if (bodyText) {
|
|
80
|
+
parts.push(bodyText);
|
|
81
|
+
parts.push(''); // Empty line before metadata
|
|
82
|
+
}
|
|
83
|
+
parts.push(generateMetadata());
|
|
84
|
+
return parts.join('\n');
|
|
85
|
+
}
|
|
86
|
+
/**
|
|
87
|
+
* Generate a pre-filled GitHub issue URL for manual submission
|
|
88
|
+
*/
|
|
89
|
+
function generateManualSubmissionUrl(title, body) {
|
|
90
|
+
const repo = 'Fission-AI/OpenSpec';
|
|
91
|
+
const encodedTitle = encodeURIComponent(title);
|
|
92
|
+
const encodedBody = encodeURIComponent(body);
|
|
93
|
+
const encodedLabels = encodeURIComponent('feedback');
|
|
94
|
+
return `https://github.com/${repo}/issues/new?title=${encodedTitle}&body=${encodedBody}&labels=${encodedLabels}`;
|
|
95
|
+
}
|
|
96
|
+
/**
|
|
97
|
+
* Display formatted feedback content for manual submission
|
|
98
|
+
*/
|
|
99
|
+
function displayFormattedFeedback(title, body) {
|
|
100
|
+
console.log('\n--- FORMATTED FEEDBACK ---');
|
|
101
|
+
console.log(`Title: ${title}`);
|
|
102
|
+
console.log(`Labels: feedback`);
|
|
103
|
+
console.log('\nBody:');
|
|
104
|
+
console.log(body);
|
|
105
|
+
console.log('--- END FEEDBACK ---\n');
|
|
106
|
+
}
|
|
107
|
+
/**
|
|
108
|
+
* Submit feedback via gh CLI
|
|
109
|
+
* Uses execFileSync to prevent shell injection vulnerabilities
|
|
110
|
+
*/
|
|
111
|
+
function submitViaGhCli(title, body) {
|
|
112
|
+
try {
|
|
113
|
+
const result = execFileSync('gh', [
|
|
114
|
+
'issue',
|
|
115
|
+
'create',
|
|
116
|
+
'--repo',
|
|
117
|
+
'Fission-AI/OpenSpec',
|
|
118
|
+
'--title',
|
|
119
|
+
title,
|
|
120
|
+
'--body',
|
|
121
|
+
body,
|
|
122
|
+
'--label',
|
|
123
|
+
'feedback',
|
|
124
|
+
], { encoding: 'utf-8', stdio: 'pipe' });
|
|
125
|
+
const issueUrl = result.trim();
|
|
126
|
+
console.log(`\n✓ Feedback submitted successfully!`);
|
|
127
|
+
console.log(`Issue URL: ${issueUrl}\n`);
|
|
128
|
+
}
|
|
129
|
+
catch (error) {
|
|
130
|
+
// Display the error output from gh CLI
|
|
131
|
+
if (error.stderr) {
|
|
132
|
+
console.error(error.stderr.toString());
|
|
133
|
+
}
|
|
134
|
+
else if (error.message) {
|
|
135
|
+
console.error(error.message);
|
|
136
|
+
}
|
|
137
|
+
// Exit with the same code as gh CLI
|
|
138
|
+
process.exit(error.status ?? 1);
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
/**
|
|
142
|
+
* Handle fallback when gh CLI is not available or not authenticated
|
|
143
|
+
*/
|
|
144
|
+
function handleFallback(title, body, reason) {
|
|
145
|
+
if (reason === 'missing') {
|
|
146
|
+
console.log('⚠️ GitHub CLI not found. Manual submission required.');
|
|
147
|
+
}
|
|
148
|
+
else {
|
|
149
|
+
console.log('⚠️ GitHub authentication required. Manual submission required.');
|
|
150
|
+
}
|
|
151
|
+
displayFormattedFeedback(title, body);
|
|
152
|
+
const manualUrl = generateManualSubmissionUrl(title, body);
|
|
153
|
+
console.log('Please submit your feedback manually:');
|
|
154
|
+
console.log(manualUrl);
|
|
155
|
+
if (reason === 'unauthenticated') {
|
|
156
|
+
console.log('\nTo auto-submit in the future: gh auth login');
|
|
157
|
+
}
|
|
158
|
+
// Exit with success code (fallback is successful)
|
|
159
|
+
process.exit(0);
|
|
160
|
+
}
|
|
161
|
+
/**
|
|
162
|
+
* Feedback command implementation
|
|
163
|
+
*/
|
|
164
|
+
export class FeedbackCommand {
|
|
165
|
+
async execute(message, options) {
|
|
166
|
+
// Format title and body once for all code paths
|
|
167
|
+
const title = formatTitle(message);
|
|
168
|
+
const body = formatBody(options?.body);
|
|
169
|
+
// Check if gh CLI is installed
|
|
170
|
+
if (!isGhInstalled()) {
|
|
171
|
+
handleFallback(title, body, 'missing');
|
|
172
|
+
return;
|
|
173
|
+
}
|
|
174
|
+
// Check if gh CLI is authenticated
|
|
175
|
+
if (!isGhAuthenticated()) {
|
|
176
|
+
handleFallback(title, body, 'unauthenticated');
|
|
177
|
+
return;
|
|
178
|
+
}
|
|
179
|
+
// Submit via gh CLI
|
|
180
|
+
submitViaGhCli(title, body);
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
//# sourceMappingURL=feedback.js.map
|
|
@@ -0,0 +1,249 @@
|
|
|
1
|
+
import { createRequire } from 'module';
|
|
2
|
+
import path from 'path';
|
|
3
|
+
import chalk from 'chalk';
|
|
4
|
+
import ora from 'ora';
|
|
5
|
+
import { getGlobalConfig } from '../core/global-config.js';
|
|
6
|
+
import { getAllowedNext, readJiraIntake, runJiraDoctor, setupJiraIntegration, validateJiraId, validateJiraIntake, } from '../core/jira/index.js';
|
|
7
|
+
const require = createRequire(import.meta.url);
|
|
8
|
+
const { version: OPENSPEC_VERSION } = require('../../package.json');
|
|
9
|
+
const VALID_STAGES = new Set(['source', 'requirement', 'stories', 'propose']);
|
|
10
|
+
export function registerJiraCommand(program) {
|
|
11
|
+
const jiraCmd = program
|
|
12
|
+
.command('jira')
|
|
13
|
+
.description('Manage Jira intake setup, validation, and status');
|
|
14
|
+
jiraCmd
|
|
15
|
+
.command('setup [path]')
|
|
16
|
+
.description('Set up Jira intake configuration and AI workflow artifacts')
|
|
17
|
+
.option('--tools <tools>', 'AI tools to configure: all, none, detected, or comma-separated tool IDs', 'detected')
|
|
18
|
+
.option('--provider <provider>', 'Jira provider (V1 supports atlassian-rovo)', 'atlassian-rovo')
|
|
19
|
+
.option('--endpoint <url>', 'Atlassian MCP endpoint')
|
|
20
|
+
.option('--force', 'Overwrite existing Jira setup files when needed')
|
|
21
|
+
.option('--json', 'Output setup result as JSON')
|
|
22
|
+
.action(async (targetPath = '.', options) => {
|
|
23
|
+
const spinner = options?.json ? undefined : ora('Setting up Jira intake...').start();
|
|
24
|
+
try {
|
|
25
|
+
const projectRoot = path.resolve(targetPath);
|
|
26
|
+
const globalConfig = getGlobalConfig();
|
|
27
|
+
const result = await setupJiraIntegration(projectRoot, {
|
|
28
|
+
tools: options?.tools,
|
|
29
|
+
provider: options?.provider,
|
|
30
|
+
endpoint: options?.endpoint,
|
|
31
|
+
force: options?.force,
|
|
32
|
+
delivery: globalConfig.delivery ?? 'both',
|
|
33
|
+
generatedByVersion: OPENSPEC_VERSION,
|
|
34
|
+
});
|
|
35
|
+
spinner?.succeed('Jira intake setup complete');
|
|
36
|
+
if (options?.json) {
|
|
37
|
+
console.log(JSON.stringify(result, null, 2));
|
|
38
|
+
}
|
|
39
|
+
else {
|
|
40
|
+
printSetupResult(result);
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
catch (error) {
|
|
44
|
+
spinner?.fail('Jira intake setup failed');
|
|
45
|
+
console.error(`Error: ${error instanceof Error ? error.message : String(error)}`);
|
|
46
|
+
process.exitCode = 1;
|
|
47
|
+
}
|
|
48
|
+
});
|
|
49
|
+
jiraCmd
|
|
50
|
+
.command('doctor [path]')
|
|
51
|
+
.description('Check Jira intake configuration and local MCP prerequisites')
|
|
52
|
+
.option('--json', 'Output doctor report as JSON')
|
|
53
|
+
.action((targetPath = '.', options) => {
|
|
54
|
+
try {
|
|
55
|
+
const projectRoot = path.resolve(targetPath);
|
|
56
|
+
const report = runJiraDoctor(projectRoot);
|
|
57
|
+
if (options?.json) {
|
|
58
|
+
console.log(JSON.stringify(report, null, 2));
|
|
59
|
+
}
|
|
60
|
+
else {
|
|
61
|
+
printDoctorReport(report);
|
|
62
|
+
}
|
|
63
|
+
if (!report.ok)
|
|
64
|
+
process.exitCode = 1;
|
|
65
|
+
}
|
|
66
|
+
catch (error) {
|
|
67
|
+
console.error(`Error: ${error instanceof Error ? error.message : String(error)}`);
|
|
68
|
+
process.exitCode = 1;
|
|
69
|
+
}
|
|
70
|
+
});
|
|
71
|
+
jiraCmd
|
|
72
|
+
.command('validate <jira-id>')
|
|
73
|
+
.description('Validate a Jira intake folder before moving to the next stage')
|
|
74
|
+
.option('--stage <stage>', 'Validation stage: source, requirement, stories, propose', 'source')
|
|
75
|
+
.option('--json', 'Output validation report as JSON')
|
|
76
|
+
.action((jiraId, options) => {
|
|
77
|
+
try {
|
|
78
|
+
const stage = normalizeStage(options?.stage);
|
|
79
|
+
const report = validateJiraIntake(process.cwd(), jiraId, stage);
|
|
80
|
+
if (options?.json) {
|
|
81
|
+
console.log(JSON.stringify(report, null, 2));
|
|
82
|
+
}
|
|
83
|
+
else {
|
|
84
|
+
printValidationReport(report);
|
|
85
|
+
}
|
|
86
|
+
if (!report.ok)
|
|
87
|
+
process.exitCode = 1;
|
|
88
|
+
}
|
|
89
|
+
catch (error) {
|
|
90
|
+
console.error(`Error: ${error instanceof Error ? error.message : String(error)}`);
|
|
91
|
+
process.exitCode = 1;
|
|
92
|
+
}
|
|
93
|
+
});
|
|
94
|
+
jiraCmd
|
|
95
|
+
.command('status <jira-id>')
|
|
96
|
+
.description('Show Jira intake status and allowed next states')
|
|
97
|
+
.option('--json', 'Output status as JSON')
|
|
98
|
+
.action((jiraId, options) => {
|
|
99
|
+
try {
|
|
100
|
+
const idValidation = validateJiraId(jiraId);
|
|
101
|
+
if (!idValidation.valid) {
|
|
102
|
+
throw new Error(idValidation.error);
|
|
103
|
+
}
|
|
104
|
+
const intakeResult = readJiraIntake(process.cwd(), jiraId);
|
|
105
|
+
const status = intakeResult.intake?.status;
|
|
106
|
+
const blockingStage = status ? getStatusBlockingStage(status) : undefined;
|
|
107
|
+
const blockingValidation = blockingStage ? validateJiraIntake(process.cwd(), jiraId, blockingStage) : undefined;
|
|
108
|
+
const result = {
|
|
109
|
+
ok: intakeResult.intake != null,
|
|
110
|
+
jira: jiraId.toUpperCase(),
|
|
111
|
+
issueDir: intakeResult.issueDir,
|
|
112
|
+
intakePath: intakeResult.path,
|
|
113
|
+
status,
|
|
114
|
+
allowedNext: status ? getAllowedNext(status) : [],
|
|
115
|
+
nextCommands: status ? getNextCommands(status, jiraId.toUpperCase()) : [],
|
|
116
|
+
blockingStage,
|
|
117
|
+
blockingItems: blockingValidation?.errors ?? [],
|
|
118
|
+
warnings: intakeResult.warnings,
|
|
119
|
+
};
|
|
120
|
+
if (options?.json) {
|
|
121
|
+
console.log(JSON.stringify(result, null, 2));
|
|
122
|
+
}
|
|
123
|
+
else {
|
|
124
|
+
printStatusResult(result);
|
|
125
|
+
}
|
|
126
|
+
if (!result.ok)
|
|
127
|
+
process.exitCode = 1;
|
|
128
|
+
}
|
|
129
|
+
catch (error) {
|
|
130
|
+
console.error(`Error: ${error instanceof Error ? error.message : String(error)}`);
|
|
131
|
+
process.exitCode = 1;
|
|
132
|
+
}
|
|
133
|
+
});
|
|
134
|
+
}
|
|
135
|
+
function normalizeStage(stage) {
|
|
136
|
+
const normalized = stage ?? 'source';
|
|
137
|
+
if (!VALID_STAGES.has(normalized)) {
|
|
138
|
+
throw new Error(`Invalid stage "${normalized}". Expected one of: ${[...VALID_STAGES].join(', ')}`);
|
|
139
|
+
}
|
|
140
|
+
return normalized;
|
|
141
|
+
}
|
|
142
|
+
function printSetupResult(result) {
|
|
143
|
+
console.log();
|
|
144
|
+
console.log(chalk.bold('Jira Intake Setup'));
|
|
145
|
+
console.log(`Config: ${result.configPath}`);
|
|
146
|
+
console.log(`Provider: ${result.config.provider}`);
|
|
147
|
+
console.log(`Endpoint: ${result.config.endpoint}`);
|
|
148
|
+
console.log(`Tools: ${result.tools.length > 0 ? result.tools.join(', ') : 'none'}`);
|
|
149
|
+
console.log(`Artifacts: ${result.skillsWritten} skills, ${result.commandsWritten} commands`);
|
|
150
|
+
printMcpConfigResults(result.mcpConfigResults);
|
|
151
|
+
if (result.commandsSkipped.length > 0) {
|
|
152
|
+
console.log(chalk.dim(`Commands skipped for: ${result.commandsSkipped.join(', ')} (no adapter)`));
|
|
153
|
+
}
|
|
154
|
+
console.log();
|
|
155
|
+
console.log(chalk.bold('MCP snippet'));
|
|
156
|
+
console.log(result.tools.length > 0 ? Object.values(result.snippets)[0] : 'Configure your AI client with an Atlassian MCP server before importing Jira tickets.');
|
|
157
|
+
console.log();
|
|
158
|
+
console.log('Next: restart your AI client, then run /opsx:jira-import ABC-123.');
|
|
159
|
+
}
|
|
160
|
+
function printMcpConfigResults(results) {
|
|
161
|
+
if (results.length === 0) {
|
|
162
|
+
return;
|
|
163
|
+
}
|
|
164
|
+
const summary = results.map((result) => `${result.toolId}: ${result.status}`).join(', ');
|
|
165
|
+
console.log(`MCP configs: ${summary}`);
|
|
166
|
+
for (const result of results) {
|
|
167
|
+
if (result.status === 'unsupported' || result.status === 'invalid-json') {
|
|
168
|
+
console.log(chalk.yellow(`MCP ${result.toolId}: ${result.message}`));
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
function printDoctorReport(report) {
|
|
173
|
+
console.log(chalk.bold('Jira Intake Doctor'));
|
|
174
|
+
for (const check of report.checks) {
|
|
175
|
+
const symbol = check.level === 'ok' ? chalk.green('✓') : check.level === 'error' ? chalk.red('✗') : chalk.yellow('!');
|
|
176
|
+
console.log(`${symbol} ${check.message}`);
|
|
177
|
+
if (check.details) {
|
|
178
|
+
console.log(chalk.dim(check.details));
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
console.log();
|
|
182
|
+
console.log(chalk.bold('AI client test prompt'));
|
|
183
|
+
console.log(report.testPrompt);
|
|
184
|
+
}
|
|
185
|
+
function printValidationReport(report) {
|
|
186
|
+
const status = report.ok ? chalk.green('valid') : chalk.red('invalid');
|
|
187
|
+
console.log(`Jira intake ${report.jira} (${report.stage}): ${status}`);
|
|
188
|
+
console.log(`Folder: ${report.issueDir}`);
|
|
189
|
+
if (report.status)
|
|
190
|
+
console.log(`Status: ${report.status}`);
|
|
191
|
+
for (const warning of report.warnings) {
|
|
192
|
+
console.log(chalk.yellow(`Warning [${warning.code}]: ${warning.message}${warning.file ? ` (${warning.file})` : ''}`));
|
|
193
|
+
}
|
|
194
|
+
for (const error of report.errors) {
|
|
195
|
+
console.log(chalk.red(`Error [${error.code}]: ${error.message}${error.file ? ` (${error.file})` : ''}`));
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
function printStatusResult(result) {
|
|
199
|
+
if (!result.ok) {
|
|
200
|
+
console.log(chalk.red(`No Jira intake found for ${result.jira}. Run /opsx:jira-import ${result.jira} first.`));
|
|
201
|
+
console.log(chalk.dim(`Expected: ${result.intakePath}`));
|
|
202
|
+
return;
|
|
203
|
+
}
|
|
204
|
+
console.log(chalk.bold(`Jira Intake ${result.jira}`));
|
|
205
|
+
console.log(`Status: ${result.status}`);
|
|
206
|
+
console.log(`Folder: ${result.issueDir}`);
|
|
207
|
+
console.log(`Allowed next: ${result.allowedNext.length > 0 ? result.allowedNext.join(', ') : 'none'}`);
|
|
208
|
+
const richResult = result;
|
|
209
|
+
console.log(`Next commands: ${richResult.nextCommands && richResult.nextCommands.length > 0 ? richResult.nextCommands.join(', ') : 'none'}`);
|
|
210
|
+
if (richResult.blockingStage) {
|
|
211
|
+
console.log(`Blocking check: ${richResult.blockingStage}`);
|
|
212
|
+
}
|
|
213
|
+
if (richResult.blockingItems && richResult.blockingItems.length > 0) {
|
|
214
|
+
for (const item of richResult.blockingItems) {
|
|
215
|
+
console.log(chalk.red(`Blocker [${item.code}]: ${item.message}${item.file ? ` (${item.file})` : ''}`));
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
for (const warning of result.warnings) {
|
|
219
|
+
console.log(chalk.yellow(`Warning: ${warning}`));
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
function getStatusBlockingStage(status) {
|
|
223
|
+
if (status === 'imported')
|
|
224
|
+
return 'source';
|
|
225
|
+
if (status === 'refining' || status === 'ready-for-review' || status === 'reviewed')
|
|
226
|
+
return 'requirement';
|
|
227
|
+
if (status === 'split' || status === 'stories-reviewed')
|
|
228
|
+
return 'stories';
|
|
229
|
+
return 'propose';
|
|
230
|
+
}
|
|
231
|
+
function getNextCommands(status, jiraId) {
|
|
232
|
+
switch (status) {
|
|
233
|
+
case 'imported':
|
|
234
|
+
case 'refining':
|
|
235
|
+
return [`/opsx:jira-refine ${jiraId}`];
|
|
236
|
+
case 'ready-for-review':
|
|
237
|
+
return [`/opsx:jira-review ${jiraId}`];
|
|
238
|
+
case 'reviewed':
|
|
239
|
+
case 'split':
|
|
240
|
+
return [`/opsx:jira-split ${jiraId}`];
|
|
241
|
+
case 'stories-reviewed':
|
|
242
|
+
return [`/opsx:jira-propose ${jiraId}`];
|
|
243
|
+
case 'proposed':
|
|
244
|
+
return [`/opsx:jira-sync ${jiraId}`];
|
|
245
|
+
case 'synced':
|
|
246
|
+
return [];
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
//# sourceMappingURL=jira.js.map
|