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,240 @@
1
+ /**
2
+ * Structure detector for identifying GSD-OpenCode directory layout.
3
+ *
4
+ * This module provides detection and analysis of the command directory structure,
5
+ * supporting both legacy (command/gsd/) and new (commands/gsd/) layouts.
6
+ * Used during installation, update, and health checks to determine the correct
7
+ * structure and handle migration scenarios.
8
+ *
9
+ * @module structure-detector
10
+ */
11
+
12
+ import fs from 'fs/promises';
13
+ import path from 'path';
14
+ import { OLD_COMMAND_DIR, NEW_COMMAND_DIR, STRUCTURE_TYPES } from '../../lib/constants.js';
15
+
16
+ /**
17
+ * Detects and analyzes GSD-OpenCode directory structure.
18
+ *
19
+ * This class provides methods to determine which command directory structure
20
+ * exists at a given installation path: legacy (command/gsd/), new (commands/gsd/),
21
+ * both (dual/migration state), or neither (fresh install).
22
+ *
23
+ * @class StructureDetector
24
+ * @example
25
+ * const detector = new StructureDetector('/home/user/.config/opencode');
26
+ * const structure = await detector.detect();
27
+ * console.log(structure); // 'old', 'new', 'dual', or 'none'
28
+ */
29
+ export class StructureDetector {
30
+ /**
31
+ * Creates a new StructureDetector instance.
32
+ *
33
+ * @param {string} installPath - Path to the GSD-OpenCode installation directory
34
+ * @throws {Error} If installPath is not provided
35
+ *
36
+ * @example
37
+ * // Detect structure in global installation
38
+ * const detector = new StructureDetector('/home/user/.config/opencode');
39
+ *
40
+ * // Detect structure in local installation
41
+ * const detector = new StructureDetector('/project/.opencode');
42
+ */
43
+ constructor(installPath) {
44
+ if (!installPath) {
45
+ throw new Error('installPath is required');
46
+ }
47
+
48
+ this.installPath = installPath;
49
+ }
50
+
51
+ /**
52
+ * Detects the directory structure at the installation path.
53
+ *
54
+ * Checks for the existence of both old (command/gsd/) and new (commands/gsd/)
55
+ * directory structures and returns the appropriate STRUCTURE_TYPES value.
56
+ *
57
+ * @returns {Promise<string>} One of STRUCTURE_TYPES values:
58
+ * - 'old': Only legacy structure exists (command/gsd/)
59
+ * - 'new': Only new structure exists (commands/gsd/)
60
+ * - 'dual': Both structures exist (migration in progress)
61
+ * - 'none': Neither structure exists (fresh install or not installed)
62
+ *
63
+ * @example
64
+ * const detector = new StructureDetector('/home/user/.config/opencode');
65
+ *
66
+ * // Returns 'old' if only command/gsd/ exists
67
+ * // Returns 'new' if only commands/gsd/ exists
68
+ * // Returns 'dual' if both exist
69
+ * // Returns 'none' if neither exists
70
+ * const structure = await detector.detect();
71
+ */
72
+ async detect() {
73
+ const oldPath = path.join(this.installPath, OLD_COMMAND_DIR, 'gsd');
74
+ const newPath = path.join(this.installPath, NEW_COMMAND_DIR, 'gsd');
75
+
76
+ const [oldExists, newExists] = await Promise.all([
77
+ this._pathExists(oldPath),
78
+ this._pathExists(newPath)
79
+ ]);
80
+
81
+ if (oldExists && newExists) return STRUCTURE_TYPES.DUAL;
82
+ if (newExists) return STRUCTURE_TYPES.NEW;
83
+ if (oldExists) return STRUCTURE_TYPES.OLD;
84
+ return STRUCTURE_TYPES.NONE;
85
+ }
86
+
87
+ /**
88
+ * Checks if a path exists on the filesystem.
89
+ *
90
+ * Uses fs.access() for existence checking with proper error handling.
91
+ *
92
+ * @private
93
+ * @param {string} checkPath - Path to check for existence
94
+ * @returns {Promise<boolean>} True if path exists, false otherwise
95
+ */
96
+ async _pathExists(checkPath) {
97
+ try {
98
+ await fs.access(checkPath);
99
+ return true;
100
+ } catch {
101
+ return false;
102
+ }
103
+ }
104
+
105
+ /**
106
+ * Gets the appropriate command directory name for a structure type.
107
+ *
108
+ * Returns the command directory name to use based on the detected structure.
109
+ * For fresh installs (NONE), defaults to the new structure.
110
+ *
111
+ * @param {string} structureType - One of STRUCTURE_TYPES values
112
+ * @returns {string} The command directory name:
113
+ * - 'commands' for NEW, DUAL, or NONE
114
+ * - 'command' for OLD
115
+ *
116
+ * @example
117
+ * const detector = new StructureDetector('/home/user/.config/opencode');
118
+ *
119
+ * detector.getCommandDir('new'); // returns 'commands'
120
+ * detector.getCommandDir('old'); // returns 'command'
121
+ * detector.getCommandDir('dual'); // returns 'commands' (prefer new)
122
+ * detector.getCommandDir('none'); // returns 'commands' (default for fresh)
123
+ */
124
+ getCommandDir(structureType) {
125
+ switch (structureType) {
126
+ case STRUCTURE_TYPES.NEW:
127
+ case STRUCTURE_TYPES.DUAL:
128
+ case STRUCTURE_TYPES.NONE:
129
+ return NEW_COMMAND_DIR;
130
+ case STRUCTURE_TYPES.OLD:
131
+ return OLD_COMMAND_DIR;
132
+ default:
133
+ return NEW_COMMAND_DIR; // Default to new for unknown types
134
+ }
135
+ }
136
+
137
+ /**
138
+ * Gets detailed information about the structure state.
139
+ *
140
+ * Returns an object with detailed information about both structures,
141
+ * useful for health checks and diagnostic output.
142
+ *
143
+ * @returns {Promise<Object>} Structure state details:
144
+ * - type: The detected structure type
145
+ * - oldPath: Full path to old structure
146
+ * - newPath: Full path to new structure
147
+ * - oldExists: Whether old structure exists
148
+ * - newExists: Whether new structure exists
149
+ * - recommendedAction: Suggested action based on state
150
+ *
151
+ * @example
152
+ * const detector = new StructureDetector('/home/user/.config/opencode');
153
+ * const details = await detector.getDetails();
154
+ * // {
155
+ * // type: 'dual',
156
+ * // oldPath: '/home/user/.config/opencode/command/gsd',
157
+ * // newPath: '/home/user/.config/opencode/commands/gsd',
158
+ * // oldExists: true,
159
+ * // newExists: true,
160
+ * // recommendedAction: 'Run update to complete migration'
161
+ * // }
162
+ */
163
+ async getDetails() {
164
+ const oldPath = path.join(this.installPath, OLD_COMMAND_DIR, 'gsd');
165
+ const newPath = path.join(this.installPath, NEW_COMMAND_DIR, 'gsd');
166
+
167
+ const [oldExists, newExists] = await Promise.all([
168
+ this._pathExists(oldPath),
169
+ this._pathExists(newPath)
170
+ ]);
171
+
172
+ let type;
173
+ let recommendedAction;
174
+
175
+ if (oldExists && newExists) {
176
+ type = STRUCTURE_TYPES.DUAL;
177
+ recommendedAction = 'Run update to complete migration from old to new structure';
178
+ } else if (newExists) {
179
+ type = STRUCTURE_TYPES.NEW;
180
+ recommendedAction = 'Structure is up to date';
181
+ } else if (oldExists) {
182
+ type = STRUCTURE_TYPES.OLD;
183
+ recommendedAction = 'Run update to migrate to new structure';
184
+ } else {
185
+ type = STRUCTURE_TYPES.NONE;
186
+ recommendedAction = 'Fresh installation recommended';
187
+ }
188
+
189
+ return {
190
+ type,
191
+ oldPath,
192
+ newPath,
193
+ oldExists,
194
+ newExists,
195
+ recommendedAction
196
+ };
197
+ }
198
+ }
199
+
200
+ /**
201
+ * Convenience function for one-off structure detection.
202
+ *
203
+ * Creates a temporary StructureDetector instance and returns the detected type.
204
+ * Use this for simple detection without needing the full class instance.
205
+ *
206
+ * @param {string} installPath - Path to the installation directory
207
+ * @returns {Promise<string>} The detected structure type
208
+ *
209
+ * @example
210
+ * // Quick detection without instantiating a class
211
+ * const type = await detectStructure('/home/user/.config/opencode');
212
+ * if (type === 'old') {
213
+ * console.log('Legacy structure detected, migration needed');
214
+ * }
215
+ */
216
+ export async function detectStructure(installPath) {
217
+ const detector = new StructureDetector(installPath);
218
+ return await detector.detect();
219
+ }
220
+
221
+ /**
222
+ * Re-export of STRUCTURE_TYPES from constants for convenience.
223
+ *
224
+ * @type {Object.<string, string>}
225
+ */
226
+ export { STRUCTURE_TYPES } from '../../lib/constants.js';
227
+
228
+ /**
229
+ * Default export for the structure-detector module.
230
+ *
231
+ * @example
232
+ * import { StructureDetector, detectStructure, STRUCTURE_TYPES } from './services/structure-detector.js';
233
+ * const detector = new StructureDetector('/path/to/opencode');
234
+ * const type = await detector.detect();
235
+ */
236
+ export default {
237
+ StructureDetector,
238
+ detectStructure,
239
+ STRUCTURE_TYPES
240
+ };