gsd-opencode 1.9.2 → 1.10.2

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 (59) hide show
  1. package/agents/gsd-debugger.md +5 -5
  2. package/agents/gsd-settings.md +476 -30
  3. package/bin/gsd-install.js +105 -0
  4. package/bin/gsd.js +352 -0
  5. package/{command → commands}/gsd/add-phase.md +1 -1
  6. package/{command → commands}/gsd/audit-milestone.md +1 -1
  7. package/{command → commands}/gsd/debug.md +3 -3
  8. package/{command → commands}/gsd/discuss-phase.md +1 -1
  9. package/{command → commands}/gsd/execute-phase.md +1 -1
  10. package/{command → commands}/gsd/list-phase-assumptions.md +1 -1
  11. package/{command → commands}/gsd/map-codebase.md +1 -1
  12. package/{command → commands}/gsd/new-milestone.md +1 -1
  13. package/{command → commands}/gsd/new-project.md +3 -3
  14. package/{command → commands}/gsd/plan-phase.md +2 -2
  15. package/{command → commands}/gsd/research-phase.md +1 -1
  16. package/{command → commands}/gsd/verify-work.md +1 -1
  17. package/get-shit-done/workflows/list-phase-assumptions.md +1 -1
  18. package/get-shit-done/workflows/verify-work.md +5 -5
  19. package/lib/constants.js +199 -0
  20. package/package.json +34 -20
  21. package/src/commands/check.js +329 -0
  22. package/src/commands/config.js +337 -0
  23. package/src/commands/install.js +608 -0
  24. package/src/commands/list.js +256 -0
  25. package/src/commands/repair.js +519 -0
  26. package/src/commands/uninstall.js +732 -0
  27. package/src/commands/update.js +444 -0
  28. package/src/services/backup-manager.js +585 -0
  29. package/src/services/config.js +262 -0
  30. package/src/services/file-ops.js +855 -0
  31. package/src/services/health-checker.js +475 -0
  32. package/src/services/manifest-manager.js +301 -0
  33. package/src/services/migration-service.js +831 -0
  34. package/src/services/repair-service.js +846 -0
  35. package/src/services/scope-manager.js +303 -0
  36. package/src/services/settings.js +553 -0
  37. package/src/services/structure-detector.js +240 -0
  38. package/src/services/update-service.js +863 -0
  39. package/src/utils/hash.js +71 -0
  40. package/src/utils/interactive.js +222 -0
  41. package/src/utils/logger.js +128 -0
  42. package/src/utils/npm-registry.js +255 -0
  43. package/src/utils/path-resolver.js +226 -0
  44. /package/{command → commands}/gsd/add-todo.md +0 -0
  45. /package/{command → commands}/gsd/check-todos.md +0 -0
  46. /package/{command → commands}/gsd/complete-milestone.md +0 -0
  47. /package/{command → commands}/gsd/help.md +0 -0
  48. /package/{command → commands}/gsd/insert-phase.md +0 -0
  49. /package/{command → commands}/gsd/pause-work.md +0 -0
  50. /package/{command → commands}/gsd/plan-milestone-gaps.md +0 -0
  51. /package/{command → commands}/gsd/progress.md +0 -0
  52. /package/{command → commands}/gsd/quick.md +0 -0
  53. /package/{command → commands}/gsd/remove-phase.md +0 -0
  54. /package/{command → commands}/gsd/resume-work.md +0 -0
  55. /package/{command → commands}/gsd/set-model.md +0 -0
  56. /package/{command → commands}/gsd/set-profile.md +0 -0
  57. /package/{command → commands}/gsd/settings.md +0 -0
  58. /package/{command → commands}/gsd/update.md +0 -0
  59. /package/{command → commands}/gsd/whats-new.md +0 -0
@@ -0,0 +1,262 @@
1
+ /**
2
+ * Configuration manager for GSD-OpenCode installation state.
3
+ *
4
+ * This module provides persistent configuration management through the VERSION
5
+ * file, tracking installed versions and providing comprehensive installation
6
+ * information. Works in conjunction with ScopeManager to handle different
7
+ * installation scopes.
8
+ *
9
+ * All file operations are async and include proper error handling for common
10
+ * filesystem issues like permission errors and missing files.
11
+ *
12
+ * @module config
13
+ */
14
+
15
+ import fs from 'fs/promises';
16
+ import path from 'path';
17
+ import { VERSION_FILE } from '../../lib/constants.js';
18
+ import { ScopeManager } from './scope-manager.js';
19
+
20
+ /**
21
+ * Manages configuration persistence and installation state.
22
+ *
23
+ * This class handles reading and writing the VERSION file, which tracks the
24
+ * installed version of GSD-OpenCode. It delegates path resolution to a
25
+ * ScopeManager instance, allowing it to work with both global and local
26
+ * installations seamlessly.
27
+ *
28
+ * @class ConfigManager
29
+ * @example
30
+ * const scope = new ScopeManager({ scope: 'global' });
31
+ * const config = new ConfigManager(scope);
32
+ *
33
+ * // Check installation status
34
+ * const info = await config.getInstallationInfo();
35
+ * console.log(info.installed); // true/false
36
+ * console.log(info.version); // '1.0.0' or null
37
+ * console.log(info.location); // '/home/user/.config/opencode'
38
+ * console.log(info.scope); // 'global'
39
+ *
40
+ * // Set version during installation
41
+ * await config.setVersion('1.0.0');
42
+ */
43
+ export class ConfigManager {
44
+ /**
45
+ * Creates a new ConfigManager instance.
46
+ *
47
+ * @param {ScopeManager} scopeManager - ScopeManager instance for path resolution
48
+ * @throws {Error} If scopeManager is not provided or invalid
49
+ *
50
+ * @example
51
+ * const scope = new ScopeManager({ scope: 'global' });
52
+ * const config = new ConfigManager(scope);
53
+ */
54
+ constructor(scopeManager) {
55
+ if (!scopeManager) {
56
+ throw new Error('ScopeManager instance is required');
57
+ }
58
+
59
+ if (typeof scopeManager.getTargetDir !== 'function') {
60
+ throw new Error('Invalid ScopeManager: missing getTargetDir method');
61
+ }
62
+
63
+ this.scopeManager = scopeManager;
64
+ }
65
+
66
+ /**
67
+ * Gets the target installation directory.
68
+ *
69
+ * Delegates to the ScopeManager's getTargetDir method.
70
+ *
71
+ * @returns {string} Absolute path to the installation directory
72
+ *
73
+ * @example
74
+ * const config = new ConfigManager(scope);
75
+ * config.getTargetDir(); // '/home/user/.config/opencode'
76
+ */
77
+ getTargetDir() {
78
+ return this.scopeManager.getTargetDir();
79
+ }
80
+
81
+ /**
82
+ * Gets the full path to the VERSION file.
83
+ *
84
+ * Private helper method that constructs the path to the VERSION file
85
+ * in the target installation directory.
86
+ *
87
+ * @returns {string} Absolute path to VERSION file
88
+ * @private
89
+ *
90
+ * @example
91
+ * const versionPath = config._getVersionPath();
92
+ * // Returns: '/home/user/.config/opencode/VERSION'
93
+ */
94
+ _getVersionPath() {
95
+ return path.join(this.getTargetDir(), VERSION_FILE);
96
+ }
97
+
98
+ /**
99
+ * Checks if GSD-OpenCode is installed.
100
+ *
101
+ * Async version that checks for VERSION file existence. This is the
102
+ * preferred method for checking installation status in async contexts.
103
+ *
104
+ * @returns {Promise<boolean>} True if VERSION file exists
105
+ *
106
+ * @example
107
+ * const config = new ConfigManager(scope);
108
+ * if (await config.isInstalled()) {
109
+ * console.log('Already installed');
110
+ * }
111
+ */
112
+ async isInstalled() {
113
+ try {
114
+ await fs.access(this._getVersionPath(), fs.constants.F_OK);
115
+ return true;
116
+ } catch (error) {
117
+ if (error.code === 'ENOENT') {
118
+ return false;
119
+ }
120
+ // For other errors (permissions, etc.), assume not installed
121
+ return false;
122
+ }
123
+ }
124
+
125
+ /**
126
+ * Reads the installed version from the VERSION file.
127
+ *
128
+ * Returns the version string stored in the VERSION file, or null if
129
+ * the file doesn't exist or can't be read.
130
+ *
131
+ * @returns {Promise<string|null>} The installed version, or null if not installed
132
+ *
133
+ * @example
134
+ * const config = new ConfigManager(scope);
135
+ * const version = await config.getVersion();
136
+ * if (version) {
137
+ * console.log(`Installed version: ${version}`);
138
+ * } else {
139
+ * console.log('Not installed');
140
+ * }
141
+ */
142
+ async getVersion() {
143
+ try {
144
+ const content = await fs.readFile(this._getVersionPath(), 'utf-8');
145
+ return content.trim();
146
+ } catch (error) {
147
+ if (error.code === 'ENOENT') {
148
+ return null;
149
+ }
150
+ if (error.code === 'EACCES') {
151
+ throw new Error(
152
+ `Permission denied: Cannot read version file at ${this._getVersionPath()}. ` +
153
+ 'Check file permissions or run with appropriate privileges.'
154
+ );
155
+ }
156
+ // Return null for any other error
157
+ return null;
158
+ }
159
+ }
160
+
161
+ /**
162
+ * Writes the version to the VERSION file.
163
+ *
164
+ * Creates the target directory if it doesn't exist, then writes the
165
+ * version string to the VERSION file. Handles permission errors
166
+ * gracefully with helpful error messages.
167
+ *
168
+ * @param {string} version - Version string to write (e.g., '1.0.0')
169
+ * @returns {Promise<void>}
170
+ * @throws {Error} If directory cannot be created or file cannot be written
171
+ *
172
+ * @example
173
+ * const config = new ConfigManager(scope);
174
+ * await config.setVersion('1.0.0');
175
+ * console.log('Version set successfully');
176
+ */
177
+ async setVersion(version) {
178
+ if (!version || typeof version !== 'string') {
179
+ throw new Error('Version must be a non-empty string');
180
+ }
181
+
182
+ const targetDir = this.getTargetDir();
183
+ const versionPath = this._getVersionPath();
184
+
185
+ try {
186
+ // Ensure target directory exists
187
+ await fs.mkdir(targetDir, { recursive: true });
188
+
189
+ // Write version file
190
+ await fs.writeFile(versionPath, version.trim(), 'utf-8');
191
+ } catch (error) {
192
+ if (error.code === 'EACCES') {
193
+ throw new Error(
194
+ `Permission denied: Cannot write version file to ${targetDir}. ` +
195
+ 'Check directory permissions or run with appropriate privileges.'
196
+ );
197
+ }
198
+ if (error.code === 'ENOSPC') {
199
+ throw new Error(
200
+ `No space left on device: Cannot write version file to ${targetDir}. ` +
201
+ 'Free up disk space and try again.'
202
+ );
203
+ }
204
+ throw new Error(
205
+ `Failed to write version file: ${error.message}`
206
+ );
207
+ }
208
+ }
209
+
210
+ /**
211
+ * Gets comprehensive installation information.
212
+ *
213
+ * Returns an object containing all relevant installation details:
214
+ * whether GSD-OpenCode is installed, the installed version, the
215
+ * installation location, scope (global/local), and a display-friendly
216
+ * path prefix.
217
+ *
218
+ * @returns {Promise<Object>} Installation information object
219
+ * @property {boolean} installed - Whether GSD-OpenCode is installed
220
+ * @property {string|null} version - The installed version, or null
221
+ * @property {string} location - Absolute path to installation directory
222
+ * @property {string} scope - 'global' or 'local'
223
+ * @property {string} pathPrefix - Display-friendly path (e.g., '~/.config/opencode')
224
+ *
225
+ * @example
226
+ * const config = new ConfigManager(scope);
227
+ * const info = await config.getInstallationInfo();
228
+ * console.log(info);
229
+ * // {
230
+ * // installed: true,
231
+ * // version: '1.0.0',
232
+ * // location: '/home/user/.config/opencode',
233
+ * // scope: 'global',
234
+ * // pathPrefix: '~/.config/opencode'
235
+ * // }
236
+ */
237
+ async getInstallationInfo() {
238
+ const [installed, version] = await Promise.all([
239
+ this.isInstalled(),
240
+ this.getVersion()
241
+ ]);
242
+
243
+ return {
244
+ installed,
245
+ version,
246
+ location: this.getTargetDir(),
247
+ scope: this.scopeManager.getScope(),
248
+ pathPrefix: this.scopeManager.getPathPrefix()
249
+ };
250
+ }
251
+ }
252
+
253
+ /**
254
+ * Default export for the config module.
255
+ *
256
+ * @example
257
+ * import { ConfigManager } from './services/config.js';
258
+ * const config = new ConfigManager(scope);
259
+ */
260
+ export default {
261
+ ConfigManager
262
+ };