gsd-opencode 1.9.1 → 1.10.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/agents/gsd-debugger.md +5 -5
- package/agents/gsd-set-model.md +287 -0
- package/agents/gsd-set-profile.md +239 -0
- package/agents/gsd-settings.md +303 -0
- package/bin/gsd-install.js +105 -0
- package/bin/gsd.js +352 -0
- package/bin/install.js +81 -1
- package/{command → commands}/gsd/add-phase.md +1 -1
- package/{command → commands}/gsd/audit-milestone.md +1 -1
- package/{command → commands}/gsd/debug.md +3 -3
- package/{command → commands}/gsd/discuss-phase.md +1 -1
- package/{command → commands}/gsd/execute-phase.md +1 -1
- package/{command → commands}/gsd/list-phase-assumptions.md +1 -1
- package/{command → commands}/gsd/map-codebase.md +1 -1
- package/{command → commands}/gsd/new-milestone.md +1 -1
- package/{command → commands}/gsd/new-project.md +71 -6
- package/{command → commands}/gsd/plan-phase.md +2 -2
- package/{command → commands}/gsd/research-phase.md +1 -1
- package/commands/gsd/set-model.md +77 -0
- package/commands/gsd/set-profile.md +46 -0
- package/commands/gsd/settings.md +33 -0
- package/{command → commands}/gsd/verify-work.md +1 -1
- package/get-shit-done/references/model-profiles.md +67 -36
- package/get-shit-done/workflows/list-phase-assumptions.md +1 -1
- package/get-shit-done/workflows/verify-work.md +5 -5
- package/lib/constants.js +193 -0
- package/package.json +34 -20
- package/src/commands/check.js +329 -0
- package/src/commands/config.js +337 -0
- package/src/commands/install.js +608 -0
- package/src/commands/list.js +256 -0
- package/src/commands/repair.js +519 -0
- package/src/commands/uninstall.js +732 -0
- package/src/commands/update.js +444 -0
- package/src/services/backup-manager.js +585 -0
- package/src/services/config.js +262 -0
- package/src/services/file-ops.js +830 -0
- package/src/services/health-checker.js +475 -0
- package/src/services/manifest-manager.js +301 -0
- package/src/services/migration-service.js +831 -0
- package/src/services/repair-service.js +846 -0
- package/src/services/scope-manager.js +303 -0
- package/src/services/settings.js +553 -0
- package/src/services/structure-detector.js +240 -0
- package/src/services/update-service.js +863 -0
- package/src/utils/hash.js +71 -0
- package/src/utils/interactive.js +222 -0
- package/src/utils/logger.js +128 -0
- package/src/utils/npm-registry.js +255 -0
- package/src/utils/path-resolver.js +226 -0
- package/command/gsd/set-profile.md +0 -111
- package/command/gsd/settings.md +0 -136
- /package/{command → commands}/gsd/add-todo.md +0 -0
- /package/{command → commands}/gsd/check-todos.md +0 -0
- /package/{command → commands}/gsd/complete-milestone.md +0 -0
- /package/{command → commands}/gsd/help.md +0 -0
- /package/{command → commands}/gsd/insert-phase.md +0 -0
- /package/{command → commands}/gsd/pause-work.md +0 -0
- /package/{command → commands}/gsd/plan-milestone-gaps.md +0 -0
- /package/{command → commands}/gsd/progress.md +0 -0
- /package/{command → commands}/gsd/quick.md +0 -0
- /package/{command → commands}/gsd/remove-phase.md +0 -0
- /package/{command → commands}/gsd/resume-work.md +0 -0
- /package/{command → commands}/gsd/update.md +0 -0
- /package/{command → commands}/gsd/whats-new.md +0 -0
package/bin/gsd.js
ADDED
|
@@ -0,0 +1,352 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Main CLI entry point for GSD-OpenCode package manager.
|
|
5
|
+
*
|
|
6
|
+
* This is the primary executable that routes commands to their respective
|
|
7
|
+
* handlers using Commander.js. Supports both new subcommand-based interface
|
|
8
|
+
* and legacy argument patterns for backward compatibility.
|
|
9
|
+
*
|
|
10
|
+
* Commands:
|
|
11
|
+
* - install: Install GSD-OpenCode distribution
|
|
12
|
+
* - list: Show installation status
|
|
13
|
+
*
|
|
14
|
+
* Legacy compatibility:
|
|
15
|
+
* - Direct flags like --global, --local are routed to install command
|
|
16
|
+
* - No arguments defaults to interactive install
|
|
17
|
+
*
|
|
18
|
+
* @module gsd
|
|
19
|
+
*/
|
|
20
|
+
|
|
21
|
+
import { Command } from 'commander';
|
|
22
|
+
import chalk from 'chalk';
|
|
23
|
+
import { installCommand } from '../src/commands/install.js';
|
|
24
|
+
import { listCommand } from '../src/commands/list.js';
|
|
25
|
+
import { uninstallCommand } from '../src/commands/uninstall.js';
|
|
26
|
+
import { configGetCommand, configSetCommand, configResetCommand, configListCommand } from '../src/commands/config.js';
|
|
27
|
+
import { checkCommand } from '../src/commands/check.js';
|
|
28
|
+
import { repairCommand } from '../src/commands/repair.js';
|
|
29
|
+
import { updateCommand } from '../src/commands/update.js';
|
|
30
|
+
import { logger, setVerbose } from '../src/utils/logger.js';
|
|
31
|
+
import { ERROR_CODES } from '../lib/constants.js';
|
|
32
|
+
import { readFileSync } from 'fs';
|
|
33
|
+
import { fileURLToPath } from 'url';
|
|
34
|
+
import path from 'path';
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* Gets the package version from package.json.
|
|
38
|
+
*
|
|
39
|
+
* @returns {string} The package version
|
|
40
|
+
* @private
|
|
41
|
+
*/
|
|
42
|
+
function getPackageVersion() {
|
|
43
|
+
try {
|
|
44
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
45
|
+
const __dirname = path.dirname(__filename);
|
|
46
|
+
const packageRoot = path.resolve(__dirname, '..');
|
|
47
|
+
const packageJsonPath = path.join(packageRoot, 'package.json');
|
|
48
|
+
|
|
49
|
+
const content = readFileSync(packageJsonPath, 'utf-8');
|
|
50
|
+
const pkg = JSON.parse(content);
|
|
51
|
+
return pkg.version || '1.0.0';
|
|
52
|
+
} catch (error) {
|
|
53
|
+
return '1.0.0';
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* Checks if arguments are legacy-style (direct flags without subcommand).
|
|
59
|
+
*
|
|
60
|
+
* Legacy patterns:
|
|
61
|
+
* - --global, -g
|
|
62
|
+
* - --local, -l
|
|
63
|
+
* - --config-dir, -c
|
|
64
|
+
* - (no args)
|
|
65
|
+
*
|
|
66
|
+
* @param {string[]} args - Process arguments
|
|
67
|
+
* @returns {boolean} True if legacy pattern detected
|
|
68
|
+
* @private
|
|
69
|
+
*/
|
|
70
|
+
function isLegacyArgs(args) {
|
|
71
|
+
// If no args beyond node and script, it's legacy (default to install)
|
|
72
|
+
if (args.length <= 2) {
|
|
73
|
+
return true;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
const userArgs = args.slice(2);
|
|
77
|
+
|
|
78
|
+
// Check for any known command
|
|
79
|
+
const knownCommands = ['install', 'list', 'uninstall', 'config', 'check', 'repair', 'update', '--help', '-h', '--version', '-V'];
|
|
80
|
+
const hasKnownCommand = knownCommands.some(cmd => userArgs.includes(cmd));
|
|
81
|
+
|
|
82
|
+
if (hasKnownCommand) {
|
|
83
|
+
return false;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
// Check for legacy flags
|
|
87
|
+
const legacyFlags = ['--global', '-g', '--local', '-l', '--config-dir', '-c'];
|
|
88
|
+
const hasLegacyFlags = legacyFlags.some(flag =>
|
|
89
|
+
userArgs.some(arg => arg.startsWith(flag))
|
|
90
|
+
);
|
|
91
|
+
|
|
92
|
+
return hasLegacyFlags || userArgs.length === 0;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
/**
|
|
96
|
+
* Transform legacy arguments to new subcommand format.
|
|
97
|
+
*
|
|
98
|
+
* @param {string[]} args - Process arguments
|
|
99
|
+
* @returns {string[]} Transformed arguments
|
|
100
|
+
* @private
|
|
101
|
+
*/
|
|
102
|
+
function transformLegacyArgs(args) {
|
|
103
|
+
const userArgs = args.slice(2);
|
|
104
|
+
|
|
105
|
+
// If no args, transform to 'install'
|
|
106
|
+
if (userArgs.length === 0) {
|
|
107
|
+
return [...args.slice(0, 2), 'install'];
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
// Check if already has 'install' subcommand
|
|
111
|
+
if (userArgs[0] === 'install') {
|
|
112
|
+
return args;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
// Transform: [flags...] -> ['install', flags...]
|
|
116
|
+
// But don't add 'install' if the first arg starts with a flag
|
|
117
|
+
const firstArg = userArgs[0];
|
|
118
|
+
if (firstArg.startsWith('-')) {
|
|
119
|
+
return [...args.slice(0, 2), 'install', ...userArgs];
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
return args;
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
/**
|
|
126
|
+
* Main CLI function.
|
|
127
|
+
*
|
|
128
|
+
* Sets up Commander program, registers commands, handles legacy
|
|
129
|
+
* compatibility, and executes the appropriate command.
|
|
130
|
+
*
|
|
131
|
+
* @returns {Promise<void>}
|
|
132
|
+
* @private
|
|
133
|
+
*/
|
|
134
|
+
async function main() {
|
|
135
|
+
const program = new Command();
|
|
136
|
+
|
|
137
|
+
// Basic program setup
|
|
138
|
+
program
|
|
139
|
+
.name('gsd-opencode')
|
|
140
|
+
.description('GSD-OpenCode distribution manager')
|
|
141
|
+
.version(getPackageVersion(), '-v, --version', 'Display version number')
|
|
142
|
+
.helpOption('-h, --help', 'Display help for command')
|
|
143
|
+
.configureOutput({
|
|
144
|
+
writeErr: (str) => logger.error(str.trim()),
|
|
145
|
+
outputError: (str, write) => write(chalk.red(str))
|
|
146
|
+
});
|
|
147
|
+
|
|
148
|
+
// Global options (available to all subcommands)
|
|
149
|
+
program.option('--verbose', 'Enable verbose output for debugging', false);
|
|
150
|
+
|
|
151
|
+
// Install command
|
|
152
|
+
program
|
|
153
|
+
.command('install')
|
|
154
|
+
.description('Install GSD-OpenCode distribution to your system')
|
|
155
|
+
.option('-g, --global', 'Install globally to ~/.config/opencode/')
|
|
156
|
+
.option('-l, --local', 'Install locally to ./.opencode/')
|
|
157
|
+
.option('-c, --config-dir <path>', 'Specify custom configuration directory')
|
|
158
|
+
.action(async (options, command) => {
|
|
159
|
+
// Get global verbose option from parent
|
|
160
|
+
const globalOptions = command.parent.opts();
|
|
161
|
+
const fullOptions = {
|
|
162
|
+
...options,
|
|
163
|
+
verbose: globalOptions.verbose || options.verbose
|
|
164
|
+
};
|
|
165
|
+
|
|
166
|
+
const exitCode = await installCommand(fullOptions);
|
|
167
|
+
process.exit(exitCode);
|
|
168
|
+
});
|
|
169
|
+
|
|
170
|
+
// List command
|
|
171
|
+
program
|
|
172
|
+
.command('list')
|
|
173
|
+
.alias('ls')
|
|
174
|
+
.description('Show GSD-OpenCode installation status and version')
|
|
175
|
+
.option('-g, --global', 'Show global installation only')
|
|
176
|
+
.option('-l, --local', 'Show local installation only')
|
|
177
|
+
.action(async (options, command) => {
|
|
178
|
+
// Get global verbose option from parent
|
|
179
|
+
const globalOptions = command.parent.opts();
|
|
180
|
+
const fullOptions = {
|
|
181
|
+
...options,
|
|
182
|
+
verbose: globalOptions.verbose || options.verbose
|
|
183
|
+
};
|
|
184
|
+
|
|
185
|
+
const exitCode = await listCommand(fullOptions);
|
|
186
|
+
process.exit(exitCode);
|
|
187
|
+
});
|
|
188
|
+
|
|
189
|
+
// Check command
|
|
190
|
+
program
|
|
191
|
+
.command('check')
|
|
192
|
+
.alias('verify')
|
|
193
|
+
.description('Verify GSD-OpenCode installation health')
|
|
194
|
+
.option('-g, --global', 'Check global installation only')
|
|
195
|
+
.option('-l, --local', 'Check local installation only')
|
|
196
|
+
.action(async (options, command) => {
|
|
197
|
+
const globalOptions = command.parent.opts();
|
|
198
|
+
const fullOptions = {
|
|
199
|
+
...options,
|
|
200
|
+
verbose: globalOptions.verbose || options.verbose
|
|
201
|
+
};
|
|
202
|
+
|
|
203
|
+
const exitCode = await checkCommand(fullOptions);
|
|
204
|
+
process.exit(exitCode);
|
|
205
|
+
});
|
|
206
|
+
|
|
207
|
+
// Repair command
|
|
208
|
+
program
|
|
209
|
+
.command('repair')
|
|
210
|
+
.description('Repair broken GSD-OpenCode installation')
|
|
211
|
+
.option('-g, --global', 'Repair global installation only')
|
|
212
|
+
.option('-l, --local', 'Repair local installation only')
|
|
213
|
+
.action(async (options, command) => {
|
|
214
|
+
const globalOptions = command.parent.opts();
|
|
215
|
+
const fullOptions = {
|
|
216
|
+
...options,
|
|
217
|
+
verbose: globalOptions.verbose || options.verbose
|
|
218
|
+
};
|
|
219
|
+
|
|
220
|
+
const exitCode = await repairCommand(fullOptions);
|
|
221
|
+
process.exit(exitCode);
|
|
222
|
+
});
|
|
223
|
+
|
|
224
|
+
// Update command
|
|
225
|
+
program
|
|
226
|
+
.command('update [version]')
|
|
227
|
+
.description('Update GSD-OpenCode to latest or specified version')
|
|
228
|
+
.option('-g, --global', 'Update global installation only')
|
|
229
|
+
.option('-l, --local', 'Update local installation only')
|
|
230
|
+
.option('--beta', 'Update to beta version from @rokicool/gsd-opencode')
|
|
231
|
+
.option('-f, --force', 'Skip confirmation prompt')
|
|
232
|
+
.option('--dry-run', 'Show what would be updated without making changes')
|
|
233
|
+
.option('--skip-migration', 'Skip automatic structure migration (not recommended)')
|
|
234
|
+
.action(async (version, options, command) => {
|
|
235
|
+
const globalOptions = command.parent.opts();
|
|
236
|
+
const fullOptions = {
|
|
237
|
+
...options,
|
|
238
|
+
version,
|
|
239
|
+
verbose: globalOptions.verbose || options.verbose
|
|
240
|
+
};
|
|
241
|
+
|
|
242
|
+
const exitCode = await updateCommand(fullOptions);
|
|
243
|
+
process.exit(exitCode);
|
|
244
|
+
});
|
|
245
|
+
|
|
246
|
+
// Uninstall command
|
|
247
|
+
program
|
|
248
|
+
.command('uninstall')
|
|
249
|
+
.alias('rm')
|
|
250
|
+
.description('Remove GSD-OpenCode installation')
|
|
251
|
+
.option('-g, --global', 'Remove global installation')
|
|
252
|
+
.option('-l, --local', 'Remove local installation')
|
|
253
|
+
.option('-f, --force', 'Skip confirmation prompt')
|
|
254
|
+
.option('--dry-run', 'Show what would be removed without removing')
|
|
255
|
+
.option('--no-backup', 'Skip backup creation before removal')
|
|
256
|
+
.action(async (options, command) => {
|
|
257
|
+
const globalOptions = command.parent.opts();
|
|
258
|
+
const fullOptions = {
|
|
259
|
+
...options,
|
|
260
|
+
verbose: globalOptions.verbose || options.verbose
|
|
261
|
+
};
|
|
262
|
+
|
|
263
|
+
const exitCode = await uninstallCommand(fullOptions);
|
|
264
|
+
process.exit(exitCode);
|
|
265
|
+
});
|
|
266
|
+
|
|
267
|
+
// Config command with subcommands
|
|
268
|
+
const configCmd = program
|
|
269
|
+
.command('config')
|
|
270
|
+
.description('Manage GSD-OpenCode configuration');
|
|
271
|
+
|
|
272
|
+
configCmd
|
|
273
|
+
.command('get <key>')
|
|
274
|
+
.description('Get a configuration value')
|
|
275
|
+
.action(async (key, options, command) => {
|
|
276
|
+
const globalOptions = command.parent.parent.opts();
|
|
277
|
+
const fullOptions = {
|
|
278
|
+
verbose: globalOptions.verbose || options.verbose
|
|
279
|
+
};
|
|
280
|
+
|
|
281
|
+
const exitCode = await configGetCommand(key, fullOptions);
|
|
282
|
+
process.exit(exitCode);
|
|
283
|
+
});
|
|
284
|
+
|
|
285
|
+
configCmd
|
|
286
|
+
.command('set <key> <value>')
|
|
287
|
+
.description('Set a configuration value')
|
|
288
|
+
.action(async (key, value, options, command) => {
|
|
289
|
+
const globalOptions = command.parent.parent.opts();
|
|
290
|
+
const fullOptions = {
|
|
291
|
+
verbose: globalOptions.verbose || options.verbose
|
|
292
|
+
};
|
|
293
|
+
|
|
294
|
+
const exitCode = await configSetCommand(key, value, fullOptions);
|
|
295
|
+
process.exit(exitCode);
|
|
296
|
+
});
|
|
297
|
+
|
|
298
|
+
configCmd
|
|
299
|
+
.command('reset [key]')
|
|
300
|
+
.description('Reset configuration to defaults')
|
|
301
|
+
.option('--all', 'Reset all settings')
|
|
302
|
+
.action(async (key, options, command) => {
|
|
303
|
+
const globalOptions = command.parent.parent.opts();
|
|
304
|
+
const fullOptions = {
|
|
305
|
+
...options,
|
|
306
|
+
verbose: globalOptions.verbose || options.verbose
|
|
307
|
+
};
|
|
308
|
+
|
|
309
|
+
const exitCode = await configResetCommand(key, fullOptions);
|
|
310
|
+
process.exit(exitCode);
|
|
311
|
+
});
|
|
312
|
+
|
|
313
|
+
configCmd
|
|
314
|
+
.command('list')
|
|
315
|
+
.alias('ls')
|
|
316
|
+
.description('List all configuration settings')
|
|
317
|
+
.option('--json', 'Output as JSON')
|
|
318
|
+
.action(async (options, command) => {
|
|
319
|
+
const globalOptions = command.parent.parent.opts();
|
|
320
|
+
const fullOptions = {
|
|
321
|
+
...options,
|
|
322
|
+
verbose: globalOptions.verbose || options.verbose
|
|
323
|
+
};
|
|
324
|
+
|
|
325
|
+
const exitCode = await configListCommand(fullOptions);
|
|
326
|
+
process.exit(exitCode);
|
|
327
|
+
});
|
|
328
|
+
|
|
329
|
+
// Handle legacy argument patterns
|
|
330
|
+
const args = process.argv;
|
|
331
|
+
|
|
332
|
+
if (isLegacyArgs(args)) {
|
|
333
|
+
// Transform legacy args to new format
|
|
334
|
+
process.argv = transformLegacyArgs(args);
|
|
335
|
+
|
|
336
|
+
// Show deprecation notice in verbose mode
|
|
337
|
+
const userArgs = args.slice(2);
|
|
338
|
+
if (userArgs.some(arg => arg === '--verbose' || arg === '-v')) {
|
|
339
|
+
setVerbose(true);
|
|
340
|
+
logger.debug('Legacy argument pattern detected, routing to install command');
|
|
341
|
+
}
|
|
342
|
+
}
|
|
343
|
+
|
|
344
|
+
// Parse and execute
|
|
345
|
+
await program.parseAsync(process.argv);
|
|
346
|
+
}
|
|
347
|
+
|
|
348
|
+
// Run CLI
|
|
349
|
+
main().catch((error) => {
|
|
350
|
+
logger.error('Unexpected error:', error);
|
|
351
|
+
process.exit(ERROR_CODES.GENERAL_ERROR);
|
|
352
|
+
});
|
package/bin/install.js
CHANGED
|
@@ -126,10 +126,25 @@ function copyWithPathReplacement(srcDir, destDir, pathPrefix) {
|
|
|
126
126
|
if (entry.isDirectory()) {
|
|
127
127
|
copyWithPathReplacement(srcPath, destPath, pathPrefix);
|
|
128
128
|
} else if (entry.name.endsWith(".md")) {
|
|
129
|
-
// Replace
|
|
129
|
+
// Replace repo-local prompt references so installed prompts work outside this repo.
|
|
130
|
+
// IMPORTANT: order matters to avoid double-rewrites.
|
|
130
131
|
let content = fs.readFileSync(srcPath, "utf8");
|
|
132
|
+
|
|
133
|
+
// 1) @-references to this repo → install-relative @-references
|
|
134
|
+
// @gsd-opencode/... → @~/.config/opencode/... (global)
|
|
135
|
+
// @gsd-opencode/... → @./.opencode/... (local)
|
|
136
|
+
content = content.replace(/@gsd-opencode\//g, `@${pathPrefix}`);
|
|
137
|
+
|
|
138
|
+
// 2) Plain (non-@) repo-local paths → install-relative paths
|
|
139
|
+
// gsd-opencode/... → ~/.config/opencode/... (global)
|
|
140
|
+
// gsd-opencode/... → ./.opencode/... (local)
|
|
141
|
+
content = content.replace(/\bgsd-opencode\//g, pathPrefix);
|
|
142
|
+
|
|
143
|
+
// 3) Back-compat: rewrite legacy Claude paths → OpenCode paths
|
|
144
|
+
// NOTE: keep these rewrites verbatim for backward compatibility.
|
|
131
145
|
content = content.replace(/~\/\.claude\//g, pathPrefix);
|
|
132
146
|
content = content.replace(/\.\/\.claude\//g, "./.opencode/");
|
|
147
|
+
|
|
133
148
|
fs.writeFileSync(destPath, content);
|
|
134
149
|
} else {
|
|
135
150
|
fs.copyFileSync(srcPath, destPath);
|
|
@@ -164,6 +179,68 @@ function install(isGlobal) {
|
|
|
164
179
|
: "~/.config/opencode/"
|
|
165
180
|
: "./.opencode/";
|
|
166
181
|
|
|
182
|
+
function scanForUnresolvedRepoLocalTokens(destRoot) {
|
|
183
|
+
const tokenRegex = /@gsd-opencode\/|\bgsd-opencode\//g;
|
|
184
|
+
const maxHits = 10;
|
|
185
|
+
const hits = [];
|
|
186
|
+
|
|
187
|
+
function walk(dir) {
|
|
188
|
+
const entries = fs.readdirSync(dir, { withFileTypes: true });
|
|
189
|
+
for (const entry of entries) {
|
|
190
|
+
if (hits.length >= maxHits) return;
|
|
191
|
+
|
|
192
|
+
const filePath = path.join(dir, entry.name);
|
|
193
|
+
if (entry.isDirectory()) {
|
|
194
|
+
walk(filePath);
|
|
195
|
+
continue;
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
if (!entry.name.endsWith(".md")) continue;
|
|
199
|
+
|
|
200
|
+
const content = fs.readFileSync(filePath, "utf8");
|
|
201
|
+
tokenRegex.lastIndex = 0;
|
|
202
|
+
if (!tokenRegex.test(content)) continue;
|
|
203
|
+
|
|
204
|
+
// Capture a readable snippet (first matching line)
|
|
205
|
+
const lines = content.split(/\r?\n/);
|
|
206
|
+
for (let i = 0; i < lines.length; i++) {
|
|
207
|
+
tokenRegex.lastIndex = 0;
|
|
208
|
+
if (tokenRegex.test(lines[i])) {
|
|
209
|
+
hits.push({
|
|
210
|
+
file: filePath,
|
|
211
|
+
line: i + 1,
|
|
212
|
+
snippet: lines[i].trim().slice(0, 200),
|
|
213
|
+
});
|
|
214
|
+
break;
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
walk(destRoot);
|
|
221
|
+
|
|
222
|
+
if (hits.length > 0) {
|
|
223
|
+
console.log(
|
|
224
|
+
`\n ${yellow}⚠️ Install sanity check: unresolved repo-local tokens found${reset}`,
|
|
225
|
+
);
|
|
226
|
+
console.log(
|
|
227
|
+
` ${yellow}This may cause commands like /gsd-settings to fail in other repos (ENOENT).${reset}`,
|
|
228
|
+
);
|
|
229
|
+
console.log(` ${dim}Showing up to ${maxHits} matches:${reset}`);
|
|
230
|
+
|
|
231
|
+
for (const hit of hits) {
|
|
232
|
+
const displayPath = isGlobal
|
|
233
|
+
? hit.file.replace(os.homedir(), "~")
|
|
234
|
+
: hit.file.replace(process.cwd(), ".");
|
|
235
|
+
console.log(
|
|
236
|
+
` - ${displayPath}:${hit.line}\n ${dim}${hit.snippet}${reset}`,
|
|
237
|
+
);
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
console.log("");
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
|
|
167
244
|
console.log(` Installing to ${cyan}${locationLabel}${reset}\n`);
|
|
168
245
|
|
|
169
246
|
// Create commands directory (singular "command" not "commands")
|
|
@@ -188,6 +265,9 @@ function install(isGlobal) {
|
|
|
188
265
|
copyWithPathReplacement(skillSrc, skillDest, pathPrefix);
|
|
189
266
|
console.log(` ${green}✓${reset} Installed get-shit-done`);
|
|
190
267
|
|
|
268
|
+
// Post-install diagnostic (do not fail install).
|
|
269
|
+
scanForUnresolvedRepoLocalTokens(opencodeDir);
|
|
270
|
+
|
|
191
271
|
// Create VERSION file
|
|
192
272
|
fs.writeFileSync(path.join(skillDest, "VERSION"), `v${pkg.version}`);
|
|
193
273
|
console.log(` ${green}✓${reset} Created VERSION file`);
|
|
@@ -25,7 +25,7 @@ Purpose: Add planned work discovered during execution that belongs at the end of
|
|
|
25
25
|
|
|
26
26
|
<step name="parse_arguments">
|
|
27
27
|
Parse the command arguments:
|
|
28
|
-
-
|
|
28
|
+
- `$ARGUMENTS` the phase description
|
|
29
29
|
- Example: `/gsd-add-phase Add authentication` → description = "Add authentication"
|
|
30
30
|
- Example: `/gsd-add-phase Fix critical performance issues` → description = "Fix critical performance issues"
|
|
31
31
|
|
|
@@ -22,7 +22,7 @@ Verify milestone achieved its definition of done. Check requirements coverage, c
|
|
|
22
22
|
</execution_context>
|
|
23
23
|
|
|
24
24
|
<context>
|
|
25
|
-
Version:
|
|
25
|
+
Version: `$ARGUMENTS` (optional — defaults to current milestone)
|
|
26
26
|
|
|
27
27
|
**Original Intent:**
|
|
28
28
|
@.planning/PROJECT.md
|
|
@@ -18,7 +18,7 @@ Debug issues using scientific method with subagent isolation.
|
|
|
18
18
|
</objective>
|
|
19
19
|
|
|
20
20
|
<context>
|
|
21
|
-
User's issue:
|
|
21
|
+
User's issue: `$ARGUMENTS`
|
|
22
22
|
|
|
23
23
|
Check for active sessions:
|
|
24
24
|
```bash
|
|
@@ -48,11 +48,11 @@ Store resolved model for use in Task calls below.
|
|
|
48
48
|
|
|
49
49
|
## 1. Check Active Sessions
|
|
50
50
|
|
|
51
|
-
If active sessions exist AND no
|
|
51
|
+
If active sessions exist AND no `$ARGUMENTS`:
|
|
52
52
|
- List sessions with status, hypothesis, next action
|
|
53
53
|
- User picks number to resume OR describes new issue
|
|
54
54
|
|
|
55
|
-
If
|
|
55
|
+
If `$ARGUMENTS` provided OR user describes new issue:
|
|
56
56
|
- Continue to symptom gathering
|
|
57
57
|
|
|
58
58
|
## 2. Gather Symptoms (if new issue)
|
|
@@ -28,7 +28,7 @@ Context budget: ~15% orchestrator, 100% fresh per subagent.
|
|
|
28
28
|
</execution_context>
|
|
29
29
|
|
|
30
30
|
<context>
|
|
31
|
-
Phase:
|
|
31
|
+
Phase: `$ARGUMENTS`
|
|
32
32
|
|
|
33
33
|
**Flags:**
|
|
34
34
|
- `--gaps-only` — Execute only gap closure plans (plans with `gap_closure: true` in frontmatter). Use after verify-work creates fix plans.
|
|
@@ -24,7 +24,7 @@ Output: .planning/codebase/ folder with 7 structured documents about the codebas
|
|
|
24
24
|
</execution_context>
|
|
25
25
|
|
|
26
26
|
<context>
|
|
27
|
-
Focus area:
|
|
27
|
+
Focus area: `$ARGUMENTS` (optional - if provided, tells agents to focus on specific subsystem)
|
|
28
28
|
|
|
29
29
|
**Load project state if exists:**
|
|
30
30
|
Check for .planning/STATE.md - loads context if project already initialized
|
|
@@ -33,7 +33,7 @@ This is the brownfield equivalent of new-project. The project exists, PROJECT.md
|
|
|
33
33
|
</execution_context>
|
|
34
34
|
|
|
35
35
|
<context>
|
|
36
|
-
Milestone name:
|
|
36
|
+
Milestone name: `$ARGUMENTS` (optional - will prompt if not provided)
|
|
37
37
|
|
|
38
38
|
**Load project context:**
|
|
39
39
|
@.planning/PROJECT.md
|
|
@@ -327,9 +327,9 @@ questions: [
|
|
|
327
327
|
question: "Which AI models for planning agents?",
|
|
328
328
|
multiSelect: false,
|
|
329
329
|
options: [
|
|
330
|
-
{ label: "Balanced
|
|
331
|
-
{ label: "Quality", description: "
|
|
332
|
-
{ label: "Budget", description: "
|
|
330
|
+
{ label: "Balanced", description: "planning/verifier: opencode/glm-4.7-free, execution: opencode/minimax-m2.1-free" },
|
|
331
|
+
{ label: "Quality", description: "All stages: opencode/glm-4.7-free" },
|
|
332
|
+
{ label: "Budget", description: "planning/verifier: opencode/minimax-m2.1-free, execution: opencode/grok-code" }
|
|
333
333
|
]
|
|
334
334
|
}
|
|
335
335
|
]
|
|
@@ -344,6 +344,31 @@ Create `.planning/config.json` with all settings:
|
|
|
344
344
|
"parallelization": true|false,
|
|
345
345
|
"commit_docs": true|false,
|
|
346
346
|
"model_profile": "quality|balanced|budget",
|
|
347
|
+
"profiles": {
|
|
348
|
+
"active_profile": "balanced",
|
|
349
|
+
"presets": {
|
|
350
|
+
"quality": {
|
|
351
|
+
"planning": "opencode/glm-4.7-free",
|
|
352
|
+
"execution": "opencode/glm-4.7-free",
|
|
353
|
+
"verification": "opencode/glm-4.7-free"
|
|
354
|
+
},
|
|
355
|
+
"balanced": {
|
|
356
|
+
"planning": "opencode/glm-4.7-free",
|
|
357
|
+
"execution": "opencode/minimax-m2.1-free",
|
|
358
|
+
"verification": "opencode/glm-4.7-free"
|
|
359
|
+
},
|
|
360
|
+
"budget": {
|
|
361
|
+
"planning": "opencode/minimax-m2.1-free",
|
|
362
|
+
"execution": "opencode/grok-code",
|
|
363
|
+
"verification": "opencode/minimax-m2.1-free"
|
|
364
|
+
}
|
|
365
|
+
},
|
|
366
|
+
"custom_overrides": {
|
|
367
|
+
"quality": {},
|
|
368
|
+
"balanced": {},
|
|
369
|
+
"budget": {}
|
|
370
|
+
}
|
|
371
|
+
},
|
|
347
372
|
"workflow": {
|
|
348
373
|
"research": true|false,
|
|
349
374
|
"plan_check": true|false,
|
|
@@ -374,6 +399,46 @@ EOF
|
|
|
374
399
|
)"
|
|
375
400
|
```
|
|
376
401
|
|
|
402
|
+
**Generate opencode.json from active profile:**
|
|
403
|
+
|
|
404
|
+
Create `opencode.json` in the project root. This is a derived config that assigns a model to each GSD agent.
|
|
405
|
+
|
|
406
|
+
Use the effective stage models from `.planning/config.json`:
|
|
407
|
+
|
|
408
|
+
- planning model = `profiles.presets.{active_profile}.planning` (unless overridden)
|
|
409
|
+
- execution model = `profiles.presets.{active_profile}.execution` (unless overridden)
|
|
410
|
+
- verification model = `profiles.presets.{active_profile}.verification` (unless overridden)
|
|
411
|
+
|
|
412
|
+
Write `opencode.json`:
|
|
413
|
+
|
|
414
|
+
```json
|
|
415
|
+
{
|
|
416
|
+
"$schema": "https://opencode.ai/config.json",
|
|
417
|
+
"agent": {
|
|
418
|
+
"gsd-planner": { "model": "{planning model}" },
|
|
419
|
+
"gsd-plan-checker": { "model": "{planning model}" },
|
|
420
|
+
"gsd-phase-researcher": { "model": "{planning model}" },
|
|
421
|
+
"gsd-roadmapper": { "model": "{planning model}" },
|
|
422
|
+
"gsd-project-researcher": { "model": "{planning model}" },
|
|
423
|
+
"gsd-research-synthesizer": { "model": "{planning model}" },
|
|
424
|
+
"gsd-codebase-mapper": { "model": "{planning model}" },
|
|
425
|
+
"gsd-executor": { "model": "{execution model}" },
|
|
426
|
+
"gsd-debugger": { "model": "{execution model}" },
|
|
427
|
+
"gsd-verifier": { "model": "{verification model}" },
|
|
428
|
+
"gsd-integration-checker": { "model": "{verification model}" }
|
|
429
|
+
}
|
|
430
|
+
}
|
|
431
|
+
```
|
|
432
|
+
|
|
433
|
+
**Commit opencode.json:**
|
|
434
|
+
|
|
435
|
+
```bash
|
|
436
|
+
git add opencode.json
|
|
437
|
+
git commit -m "chore: configure opencode agent models"
|
|
438
|
+
```
|
|
439
|
+
|
|
440
|
+
**Important:** OpenCode loads `opencode.json` at session start and does not hot-reload. If you change profiles later via `/gsd-set-profile` or `/gsd-settings`, run `/new` (or restart OpenCode) for it to take effect.
|
|
441
|
+
|
|
377
442
|
**Note:** Run `/gsd-settings` anytime to update these preferences.
|
|
378
443
|
|
|
379
444
|
## Phase 5.5: Resolve Model Profile
|
|
@@ -949,14 +1014,14 @@ Present completion with next steps:
|
|
|
949
1014
|
|
|
950
1015
|
**Phase 1: [Phase Name]** — [Goal from ROADMAP.md]
|
|
951
1016
|
|
|
952
|
-
|
|
1017
|
+
/gsd-discuss-phase 1 — gather context and clarify approach
|
|
953
1018
|
|
|
954
|
-
|
|
1019
|
+
*/new first → fresh context window*
|
|
955
1020
|
|
|
956
1021
|
---
|
|
957
1022
|
|
|
958
1023
|
**Also available:**
|
|
959
|
-
-
|
|
1024
|
+
- /gsd-plan-phase 1 — skip discussion, plan directly
|
|
960
1025
|
|
|
961
1026
|
───────────────────────────────────────────────────────────────
|
|
962
1027
|
```
|
|
@@ -29,7 +29,7 @@ Create executable phase prompts (PLAN.md files) for a roadmap phase with integra
|
|
|
29
29
|
</objective>
|
|
30
30
|
|
|
31
31
|
<context>
|
|
32
|
-
Phase number:
|
|
32
|
+
Phase number: `$ARGUMENTS` (optional - auto-detects next unplanned phase if not provided)
|
|
33
33
|
|
|
34
34
|
**Flags:**
|
|
35
35
|
- `--research` — Force re-research even if RESEARCH.md exists
|
|
@@ -70,7 +70,7 @@ Store resolved models for use in Task calls below.
|
|
|
70
70
|
|
|
71
71
|
## 2. Parse and Normalize Arguments
|
|
72
72
|
|
|
73
|
-
Extract from
|
|
73
|
+
Extract from `$ARGUMENTS`:
|
|
74
74
|
|
|
75
75
|
- Phase number (integer or decimal like `2.1`)
|
|
76
76
|
- `--research` flag to force re-research
|
|
@@ -24,7 +24,7 @@ Research how to implement a phase. Spawns gsd-phase-researcher agent with phase
|
|
|
24
24
|
</objective>
|
|
25
25
|
|
|
26
26
|
<context>
|
|
27
|
-
Phase number:
|
|
27
|
+
Phase number: `$ARGUMENTS` (required)
|
|
28
28
|
|
|
29
29
|
Normalize phase input in step 1 before any directory lookups.
|
|
30
30
|
</context>
|