openspec-cn 0.23.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.
Files changed (235) hide show
  1. package/LICENSE +22 -0
  2. package/README.md +153 -0
  3. package/bin/openspec.js +3 -0
  4. package/dist/cli/index.d.ts +2 -0
  5. package/dist/cli/index.js +480 -0
  6. package/dist/commands/change.d.ts +35 -0
  7. package/dist/commands/change.js +277 -0
  8. package/dist/commands/completion.d.ts +72 -0
  9. package/dist/commands/completion.js +257 -0
  10. package/dist/commands/config.d.ts +8 -0
  11. package/dist/commands/config.js +198 -0
  12. package/dist/commands/feedback.d.ts +9 -0
  13. package/dist/commands/feedback.js +183 -0
  14. package/dist/commands/schema.d.ts +6 -0
  15. package/dist/commands/schema.js +869 -0
  16. package/dist/commands/show.d.ts +14 -0
  17. package/dist/commands/show.js +132 -0
  18. package/dist/commands/spec.d.ts +15 -0
  19. package/dist/commands/spec.js +225 -0
  20. package/dist/commands/validate.d.ts +24 -0
  21. package/dist/commands/validate.js +294 -0
  22. package/dist/commands/workflow/index.d.ts +17 -0
  23. package/dist/commands/workflow/index.js +12 -0
  24. package/dist/commands/workflow/instructions.d.ts +29 -0
  25. package/dist/commands/workflow/instructions.js +381 -0
  26. package/dist/commands/workflow/new-change.d.ts +11 -0
  27. package/dist/commands/workflow/new-change.js +44 -0
  28. package/dist/commands/workflow/schemas.d.ts +10 -0
  29. package/dist/commands/workflow/schemas.js +34 -0
  30. package/dist/commands/workflow/shared.d.ts +52 -0
  31. package/dist/commands/workflow/shared.js +111 -0
  32. package/dist/commands/workflow/status.d.ts +14 -0
  33. package/dist/commands/workflow/status.js +58 -0
  34. package/dist/commands/workflow/templates.d.ts +16 -0
  35. package/dist/commands/workflow/templates.js +68 -0
  36. package/dist/core/archive.d.ts +11 -0
  37. package/dist/core/archive.js +280 -0
  38. package/dist/core/artifact-graph/graph.d.ts +56 -0
  39. package/dist/core/artifact-graph/graph.js +141 -0
  40. package/dist/core/artifact-graph/index.d.ts +7 -0
  41. package/dist/core/artifact-graph/index.js +13 -0
  42. package/dist/core/artifact-graph/instruction-loader.d.ts +143 -0
  43. package/dist/core/artifact-graph/instruction-loader.js +214 -0
  44. package/dist/core/artifact-graph/resolver.d.ts +81 -0
  45. package/dist/core/artifact-graph/resolver.js +257 -0
  46. package/dist/core/artifact-graph/schema.d.ts +13 -0
  47. package/dist/core/artifact-graph/schema.js +108 -0
  48. package/dist/core/artifact-graph/state.d.ts +12 -0
  49. package/dist/core/artifact-graph/state.js +54 -0
  50. package/dist/core/artifact-graph/types.d.ts +45 -0
  51. package/dist/core/artifact-graph/types.js +43 -0
  52. package/dist/core/command-generation/adapters/amazon-q.d.ts +13 -0
  53. package/dist/core/command-generation/adapters/amazon-q.js +26 -0
  54. package/dist/core/command-generation/adapters/antigravity.d.ts +13 -0
  55. package/dist/core/command-generation/adapters/antigravity.js +26 -0
  56. package/dist/core/command-generation/adapters/auggie.d.ts +13 -0
  57. package/dist/core/command-generation/adapters/auggie.js +27 -0
  58. package/dist/core/command-generation/adapters/claude.d.ts +13 -0
  59. package/dist/core/command-generation/adapters/claude.js +50 -0
  60. package/dist/core/command-generation/adapters/cline.d.ts +14 -0
  61. package/dist/core/command-generation/adapters/cline.js +27 -0
  62. package/dist/core/command-generation/adapters/codebuddy.d.ts +13 -0
  63. package/dist/core/command-generation/adapters/codebuddy.js +28 -0
  64. package/dist/core/command-generation/adapters/codex.d.ts +13 -0
  65. package/dist/core/command-generation/adapters/codex.js +27 -0
  66. package/dist/core/command-generation/adapters/continue.d.ts +13 -0
  67. package/dist/core/command-generation/adapters/continue.js +28 -0
  68. package/dist/core/command-generation/adapters/costrict.d.ts +13 -0
  69. package/dist/core/command-generation/adapters/costrict.js +27 -0
  70. package/dist/core/command-generation/adapters/crush.d.ts +13 -0
  71. package/dist/core/command-generation/adapters/crush.js +30 -0
  72. package/dist/core/command-generation/adapters/cursor.d.ts +14 -0
  73. package/dist/core/command-generation/adapters/cursor.js +44 -0
  74. package/dist/core/command-generation/adapters/factory.d.ts +13 -0
  75. package/dist/core/command-generation/adapters/factory.js +27 -0
  76. package/dist/core/command-generation/adapters/gemini.d.ts +13 -0
  77. package/dist/core/command-generation/adapters/gemini.js +26 -0
  78. package/dist/core/command-generation/adapters/github-copilot.d.ts +13 -0
  79. package/dist/core/command-generation/adapters/github-copilot.js +26 -0
  80. package/dist/core/command-generation/adapters/iflow.d.ts +13 -0
  81. package/dist/core/command-generation/adapters/iflow.js +29 -0
  82. package/dist/core/command-generation/adapters/index.d.ts +27 -0
  83. package/dist/core/command-generation/adapters/index.js +27 -0
  84. package/dist/core/command-generation/adapters/kilocode.d.ts +14 -0
  85. package/dist/core/command-generation/adapters/kilocode.js +23 -0
  86. package/dist/core/command-generation/adapters/opencode.d.ts +13 -0
  87. package/dist/core/command-generation/adapters/opencode.js +26 -0
  88. package/dist/core/command-generation/adapters/qoder.d.ts +13 -0
  89. package/dist/core/command-generation/adapters/qoder.js +30 -0
  90. package/dist/core/command-generation/adapters/qwen.d.ts +13 -0
  91. package/dist/core/command-generation/adapters/qwen.js +26 -0
  92. package/dist/core/command-generation/adapters/roocode.d.ts +14 -0
  93. package/dist/core/command-generation/adapters/roocode.js +27 -0
  94. package/dist/core/command-generation/adapters/windsurf.d.ts +14 -0
  95. package/dist/core/command-generation/adapters/windsurf.js +51 -0
  96. package/dist/core/command-generation/generator.d.ts +21 -0
  97. package/dist/core/command-generation/generator.js +27 -0
  98. package/dist/core/command-generation/index.d.ts +22 -0
  99. package/dist/core/command-generation/index.js +24 -0
  100. package/dist/core/command-generation/registry.d.ts +36 -0
  101. package/dist/core/command-generation/registry.js +88 -0
  102. package/dist/core/command-generation/types.d.ts +55 -0
  103. package/dist/core/command-generation/types.js +8 -0
  104. package/dist/core/completions/command-registry.d.ts +7 -0
  105. package/dist/core/completions/command-registry.js +456 -0
  106. package/dist/core/completions/completion-provider.d.ts +60 -0
  107. package/dist/core/completions/completion-provider.js +102 -0
  108. package/dist/core/completions/factory.d.ts +64 -0
  109. package/dist/core/completions/factory.js +75 -0
  110. package/dist/core/completions/generators/bash-generator.d.ts +32 -0
  111. package/dist/core/completions/generators/bash-generator.js +174 -0
  112. package/dist/core/completions/generators/fish-generator.d.ts +32 -0
  113. package/dist/core/completions/generators/fish-generator.js +157 -0
  114. package/dist/core/completions/generators/powershell-generator.d.ts +33 -0
  115. package/dist/core/completions/generators/powershell-generator.js +207 -0
  116. package/dist/core/completions/generators/zsh-generator.d.ts +44 -0
  117. package/dist/core/completions/generators/zsh-generator.js +250 -0
  118. package/dist/core/completions/installers/bash-installer.d.ts +87 -0
  119. package/dist/core/completions/installers/bash-installer.js +318 -0
  120. package/dist/core/completions/installers/fish-installer.d.ts +43 -0
  121. package/dist/core/completions/installers/fish-installer.js +143 -0
  122. package/dist/core/completions/installers/powershell-installer.d.ts +88 -0
  123. package/dist/core/completions/installers/powershell-installer.js +327 -0
  124. package/dist/core/completions/installers/zsh-installer.d.ts +125 -0
  125. package/dist/core/completions/installers/zsh-installer.js +449 -0
  126. package/dist/core/completions/templates/bash-templates.d.ts +6 -0
  127. package/dist/core/completions/templates/bash-templates.js +24 -0
  128. package/dist/core/completions/templates/fish-templates.d.ts +7 -0
  129. package/dist/core/completions/templates/fish-templates.js +39 -0
  130. package/dist/core/completions/templates/powershell-templates.d.ts +6 -0
  131. package/dist/core/completions/templates/powershell-templates.js +25 -0
  132. package/dist/core/completions/templates/zsh-templates.d.ts +6 -0
  133. package/dist/core/completions/templates/zsh-templates.js +36 -0
  134. package/dist/core/completions/types.d.ts +79 -0
  135. package/dist/core/completions/types.js +2 -0
  136. package/dist/core/config-prompts.d.ts +9 -0
  137. package/dist/core/config-prompts.js +34 -0
  138. package/dist/core/config-schema.d.ts +76 -0
  139. package/dist/core/config-schema.js +200 -0
  140. package/dist/core/config.d.ts +17 -0
  141. package/dist/core/config.js +30 -0
  142. package/dist/core/converters/json-converter.d.ts +6 -0
  143. package/dist/core/converters/json-converter.js +51 -0
  144. package/dist/core/global-config.d.ts +39 -0
  145. package/dist/core/global-config.js +115 -0
  146. package/dist/core/index.d.ts +2 -0
  147. package/dist/core/index.js +3 -0
  148. package/dist/core/init.d.ts +32 -0
  149. package/dist/core/init.js +433 -0
  150. package/dist/core/legacy-cleanup.d.ts +162 -0
  151. package/dist/core/legacy-cleanup.js +501 -0
  152. package/dist/core/list.d.ts +9 -0
  153. package/dist/core/list.js +171 -0
  154. package/dist/core/parsers/change-parser.d.ts +13 -0
  155. package/dist/core/parsers/change-parser.js +193 -0
  156. package/dist/core/parsers/markdown-parser.d.ts +22 -0
  157. package/dist/core/parsers/markdown-parser.js +187 -0
  158. package/dist/core/parsers/requirement-blocks.d.ts +37 -0
  159. package/dist/core/parsers/requirement-blocks.js +201 -0
  160. package/dist/core/project-config.d.ts +64 -0
  161. package/dist/core/project-config.js +223 -0
  162. package/dist/core/schemas/base.schema.d.ts +13 -0
  163. package/dist/core/schemas/base.schema.js +13 -0
  164. package/dist/core/schemas/change.schema.d.ts +73 -0
  165. package/dist/core/schemas/change.schema.js +31 -0
  166. package/dist/core/schemas/index.d.ts +4 -0
  167. package/dist/core/schemas/index.js +4 -0
  168. package/dist/core/schemas/spec.schema.d.ts +18 -0
  169. package/dist/core/schemas/spec.schema.js +15 -0
  170. package/dist/core/shared/index.d.ts +8 -0
  171. package/dist/core/shared/index.js +8 -0
  172. package/dist/core/shared/skill-generation.d.ts +41 -0
  173. package/dist/core/shared/skill-generation.js +74 -0
  174. package/dist/core/shared/tool-detection.d.ts +66 -0
  175. package/dist/core/shared/tool-detection.js +140 -0
  176. package/dist/core/specs-apply.d.ts +73 -0
  177. package/dist/core/specs-apply.js +384 -0
  178. package/dist/core/styles/palette.d.ts +7 -0
  179. package/dist/core/styles/palette.js +8 -0
  180. package/dist/core/templates/index.d.ts +8 -0
  181. package/dist/core/templates/index.js +9 -0
  182. package/dist/core/templates/skill-templates.d.ts +112 -0
  183. package/dist/core/templates/skill-templates.js +2893 -0
  184. package/dist/core/update.d.ts +42 -0
  185. package/dist/core/update.js +306 -0
  186. package/dist/core/validation/constants.d.ts +34 -0
  187. package/dist/core/validation/constants.js +40 -0
  188. package/dist/core/validation/types.d.ts +18 -0
  189. package/dist/core/validation/types.js +2 -0
  190. package/dist/core/validation/validator.d.ts +33 -0
  191. package/dist/core/validation/validator.js +409 -0
  192. package/dist/core/view.d.ts +8 -0
  193. package/dist/core/view.js +168 -0
  194. package/dist/index.d.ts +3 -0
  195. package/dist/index.js +3 -0
  196. package/dist/prompts/searchable-multi-select.d.ts +27 -0
  197. package/dist/prompts/searchable-multi-select.js +149 -0
  198. package/dist/telemetry/config.d.ts +32 -0
  199. package/dist/telemetry/config.js +68 -0
  200. package/dist/telemetry/index.d.ts +31 -0
  201. package/dist/telemetry/index.js +145 -0
  202. package/dist/ui/ascii-patterns.d.ts +16 -0
  203. package/dist/ui/ascii-patterns.js +133 -0
  204. package/dist/ui/welcome-screen.d.ts +10 -0
  205. package/dist/ui/welcome-screen.js +146 -0
  206. package/dist/utils/change-metadata.d.ts +51 -0
  207. package/dist/utils/change-metadata.js +147 -0
  208. package/dist/utils/change-utils.d.ts +62 -0
  209. package/dist/utils/change-utils.js +121 -0
  210. package/dist/utils/file-system.d.ts +36 -0
  211. package/dist/utils/file-system.js +281 -0
  212. package/dist/utils/index.d.ts +5 -0
  213. package/dist/utils/index.js +7 -0
  214. package/dist/utils/interactive.d.ts +18 -0
  215. package/dist/utils/interactive.js +21 -0
  216. package/dist/utils/item-discovery.d.ts +4 -0
  217. package/dist/utils/item-discovery.js +72 -0
  218. package/dist/utils/match.d.ts +3 -0
  219. package/dist/utils/match.js +22 -0
  220. package/dist/utils/shell-detection.d.ts +20 -0
  221. package/dist/utils/shell-detection.js +41 -0
  222. package/dist/utils/task-progress.d.ts +8 -0
  223. package/dist/utils/task-progress.js +36 -0
  224. package/package.json +84 -0
  225. package/schemas/spec-driven/schema.yaml +148 -0
  226. package/schemas/spec-driven/templates/design.md +19 -0
  227. package/schemas/spec-driven/templates/proposal.md +23 -0
  228. package/schemas/spec-driven/templates/spec.md +8 -0
  229. package/schemas/spec-driven/templates/tasks.md +9 -0
  230. package/schemas/tdd/schema.yaml +213 -0
  231. package/schemas/tdd/templates/docs.md +15 -0
  232. package/schemas/tdd/templates/implementation.md +11 -0
  233. package/schemas/tdd/templates/spec.md +11 -0
  234. package/schemas/tdd/templates/test.md +11 -0
  235. package/scripts/postinstall.js +147 -0
@@ -0,0 +1,198 @@
1
+ import { spawn } from 'node:child_process';
2
+ import * as fs from 'node:fs';
3
+ import { getGlobalConfigPath, getGlobalConfig, saveGlobalConfig, } from '../core/global-config.js';
4
+ import { getNestedValue, setNestedValue, deleteNestedValue, coerceValue, formatValueYaml, validateConfigKeyPath, validateConfig, DEFAULT_CONFIG, } from '../core/config-schema.js';
5
+ /**
6
+ * Register the config command and all its subcommands.
7
+ *
8
+ * @param program - The Commander program instance
9
+ */
10
+ export function registerConfigCommand(program) {
11
+ const configCmd = program
12
+ .command('config')
13
+ .description('View and modify global OpenSpec configuration')
14
+ .option('--scope <scope>', 'Config scope (only "global" supported currently)')
15
+ .hook('preAction', (thisCommand) => {
16
+ const opts = thisCommand.opts();
17
+ if (opts.scope && opts.scope !== 'global') {
18
+ console.error('Error: Project-local config is not yet implemented');
19
+ process.exit(1);
20
+ }
21
+ });
22
+ // config path
23
+ configCmd
24
+ .command('path')
25
+ .description('Show config file location')
26
+ .action(() => {
27
+ console.log(getGlobalConfigPath());
28
+ });
29
+ // config list
30
+ configCmd
31
+ .command('list')
32
+ .description('Show all current settings')
33
+ .option('--json', 'Output as JSON')
34
+ .action((options) => {
35
+ const config = getGlobalConfig();
36
+ if (options.json) {
37
+ console.log(JSON.stringify(config, null, 2));
38
+ }
39
+ else {
40
+ console.log(formatValueYaml(config));
41
+ }
42
+ });
43
+ // config get
44
+ configCmd
45
+ .command('get <key>')
46
+ .description('Get a specific value (raw, scriptable)')
47
+ .action((key) => {
48
+ const config = getGlobalConfig();
49
+ const value = getNestedValue(config, key);
50
+ if (value === undefined) {
51
+ process.exitCode = 1;
52
+ return;
53
+ }
54
+ if (typeof value === 'object' && value !== null) {
55
+ console.log(JSON.stringify(value));
56
+ }
57
+ else {
58
+ console.log(String(value));
59
+ }
60
+ });
61
+ // config set
62
+ configCmd
63
+ .command('set <key> <value>')
64
+ .description('Set a value (auto-coerce types)')
65
+ .option('--string', 'Force value to be stored as string')
66
+ .option('--allow-unknown', 'Allow setting unknown keys')
67
+ .action((key, value, options) => {
68
+ const allowUnknown = Boolean(options.allowUnknown);
69
+ const keyValidation = validateConfigKeyPath(key);
70
+ if (!keyValidation.valid && !allowUnknown) {
71
+ const reason = keyValidation.reason ? ` ${keyValidation.reason}.` : '';
72
+ console.error(`Error: Invalid configuration key "${key}".${reason}`);
73
+ console.error('Use "openspec config list" to see available keys.');
74
+ console.error('Pass --allow-unknown to bypass this check.');
75
+ process.exitCode = 1;
76
+ return;
77
+ }
78
+ const config = getGlobalConfig();
79
+ const coercedValue = coerceValue(value, options.string || false);
80
+ // Create a copy to validate before saving
81
+ const newConfig = JSON.parse(JSON.stringify(config));
82
+ setNestedValue(newConfig, key, coercedValue);
83
+ // Validate the new config
84
+ const validation = validateConfig(newConfig);
85
+ if (!validation.success) {
86
+ console.error(`Error: Invalid configuration - ${validation.error}`);
87
+ process.exitCode = 1;
88
+ return;
89
+ }
90
+ // Apply changes and save
91
+ setNestedValue(config, key, coercedValue);
92
+ saveGlobalConfig(config);
93
+ const displayValue = typeof coercedValue === 'string' ? `"${coercedValue}"` : String(coercedValue);
94
+ console.log(`Set ${key} = ${displayValue}`);
95
+ });
96
+ // config unset
97
+ configCmd
98
+ .command('unset <key>')
99
+ .description('Remove a key (revert to default)')
100
+ .action((key) => {
101
+ const config = getGlobalConfig();
102
+ const existed = deleteNestedValue(config, key);
103
+ if (existed) {
104
+ saveGlobalConfig(config);
105
+ console.log(`Unset ${key} (reverted to default)`);
106
+ }
107
+ else {
108
+ console.log(`Key "${key}" was not set`);
109
+ }
110
+ });
111
+ // config reset
112
+ configCmd
113
+ .command('reset')
114
+ .description('Reset configuration to defaults')
115
+ .option('--all', 'Reset all configuration (required)')
116
+ .option('-y, --yes', 'Skip confirmation prompts')
117
+ .action(async (options) => {
118
+ if (!options.all) {
119
+ console.error('Error: --all flag is required for reset');
120
+ console.error('Usage: openspec config reset --all [-y]');
121
+ process.exitCode = 1;
122
+ return;
123
+ }
124
+ if (!options.yes) {
125
+ const { confirm } = await import('@inquirer/prompts');
126
+ const confirmed = await confirm({
127
+ message: 'Reset all configuration to defaults?',
128
+ default: false,
129
+ });
130
+ if (!confirmed) {
131
+ console.log('Reset cancelled.');
132
+ return;
133
+ }
134
+ }
135
+ saveGlobalConfig({ ...DEFAULT_CONFIG });
136
+ console.log('Configuration reset to defaults');
137
+ });
138
+ // config edit
139
+ configCmd
140
+ .command('edit')
141
+ .description('Open config in $EDITOR')
142
+ .action(async () => {
143
+ const editor = process.env.EDITOR || process.env.VISUAL;
144
+ if (!editor) {
145
+ console.error('Error: No editor configured');
146
+ console.error('Set the EDITOR or VISUAL environment variable to your preferred editor');
147
+ console.error('Example: export EDITOR=vim');
148
+ process.exitCode = 1;
149
+ return;
150
+ }
151
+ const configPath = getGlobalConfigPath();
152
+ // Ensure config file exists with defaults
153
+ if (!fs.existsSync(configPath)) {
154
+ saveGlobalConfig({ ...DEFAULT_CONFIG });
155
+ }
156
+ // Spawn editor and wait for it to close
157
+ // Avoid shell parsing to correctly handle paths with spaces in both
158
+ // the editor path and config path
159
+ const child = spawn(editor, [configPath], {
160
+ stdio: 'inherit',
161
+ shell: false,
162
+ });
163
+ await new Promise((resolve, reject) => {
164
+ child.on('close', (code) => {
165
+ if (code === 0) {
166
+ resolve();
167
+ }
168
+ else {
169
+ reject(new Error(`Editor exited with code ${code}`));
170
+ }
171
+ });
172
+ child.on('error', reject);
173
+ });
174
+ try {
175
+ const rawConfig = fs.readFileSync(configPath, 'utf-8');
176
+ const parsedConfig = JSON.parse(rawConfig);
177
+ const validation = validateConfig(parsedConfig);
178
+ if (!validation.success) {
179
+ console.error(`Error: Invalid configuration - ${validation.error}`);
180
+ process.exitCode = 1;
181
+ }
182
+ }
183
+ catch (error) {
184
+ if (error.code === 'ENOENT') {
185
+ console.error(`Error: Config file not found at ${configPath}`);
186
+ }
187
+ else if (error instanceof SyntaxError) {
188
+ console.error(`Error: Invalid JSON in ${configPath}`);
189
+ console.error(error.message);
190
+ }
191
+ else {
192
+ console.error(`Error: Unable to validate configuration - ${error instanceof Error ? error.message : String(error)}`);
193
+ }
194
+ process.exitCode = 1;
195
+ }
196
+ });
197
+ }
198
+ //# sourceMappingURL=config.js.map
@@ -0,0 +1,9 @@
1
+ /**
2
+ * Feedback command implementation
3
+ */
4
+ export declare class FeedbackCommand {
5
+ execute(message: string, options?: {
6
+ body?: string;
7
+ }): Promise<void>;
8
+ }
9
+ //# sourceMappingURL=feedback.d.ts.map
@@ -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,6 @@
1
+ import { Command } from 'commander';
2
+ /**
3
+ * Register the schema command and all its subcommands.
4
+ */
5
+ export declare function registerSchemaCommand(program: Command): void;
6
+ //# sourceMappingURL=schema.d.ts.map