gsd-init 1.0.6 → 1.0.8
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/bin/gsd-init.js
CHANGED
|
@@ -8,11 +8,9 @@ if (major < 16) {
|
|
|
8
8
|
}
|
|
9
9
|
const fs = require('fs');
|
|
10
10
|
const path = require('path');
|
|
11
|
-
const os = require('os');
|
|
12
11
|
const readline = require('readline');
|
|
13
12
|
|
|
14
13
|
const TEMPLATES_DIR = path.join(__dirname, '..', 'templates');
|
|
15
|
-
const OBS_ROOT = process.env.GSD_INIT_OBS_ROOT || path.join(os.homedir(), '.claude', 'gsd-observer');
|
|
16
14
|
|
|
17
15
|
const TEMPLATE_FILES = [
|
|
18
16
|
{ src: 'agents/gsd-observer.md', dst: 'agents/gsd-observer.md' },
|
|
@@ -41,10 +39,16 @@ const SH_FILES = [
|
|
|
41
39
|
'scripts/verify.sh',
|
|
42
40
|
];
|
|
43
41
|
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
42
|
+
function gsdRoot(projDir) {
|
|
43
|
+
return process.env.GSD_INIT_OBS_ROOT || path.join(projDir, '.gsd');
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
function makeGsdEntry(projDir) {
|
|
47
|
+
return {
|
|
48
|
+
matcher: '',
|
|
49
|
+
hooks: [{ type: 'command', command: path.join(gsdRoot(projDir), 'hooks', 'gsd-stop-hook.sh') }]
|
|
50
|
+
};
|
|
51
|
+
}
|
|
48
52
|
|
|
49
53
|
function getSettingsLabel(settingsPath) {
|
|
50
54
|
if (!fs.existsSync(settingsPath)) return '[create]';
|
|
@@ -59,28 +63,24 @@ function getSettingsLabel(settingsPath) {
|
|
|
59
63
|
}
|
|
60
64
|
|
|
61
65
|
function planInstall(tmplDir, obsRoot, projDir) {
|
|
62
|
-
var homeDir = os.homedir();
|
|
63
66
|
var ops = [];
|
|
64
67
|
for (var i = 0; i < TEMPLATE_FILES.length; i++) {
|
|
65
68
|
var f = TEMPLATE_FILES[i];
|
|
66
69
|
var dest = path.join(obsRoot, f.dst);
|
|
67
70
|
var label = fs.existsSync(dest) ? '[overwrite]' : '[create]';
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
ops.push({ dest: dest, label: label, relative: relDisplay });
|
|
71
|
+
// Display relative to projDir
|
|
72
|
+
var rel = path.relative(projDir, dest);
|
|
73
|
+
ops.push({ dest: dest, label: label, relative: rel });
|
|
72
74
|
}
|
|
73
75
|
var settingsPath = path.join(projDir, '.claude', 'settings.json');
|
|
74
76
|
ops.push({ dest: settingsPath, label: getSettingsLabel(settingsPath), relative: '.claude/settings.json' });
|
|
75
77
|
return ops;
|
|
76
78
|
}
|
|
77
79
|
|
|
78
|
-
// Stubs — implemented in later tasks
|
|
79
80
|
function formatDryRun(ops) {
|
|
80
81
|
var lines = ['gsd-init — GSD Observer/Worker setup', '', 'Files to install:'];
|
|
81
82
|
for (var i = 0; i < ops.length; i++) {
|
|
82
83
|
var op = ops[i];
|
|
83
|
-
// Pad label to 14 chars for alignment: '[create]' is 8, '[overwrite]' is 11, '[merge]' is 7, '[skip]' is 6
|
|
84
84
|
var padded = op.label + ' '.repeat(Math.max(1, 14 - op.label.length));
|
|
85
85
|
lines.push(' ' + padded + op.relative);
|
|
86
86
|
}
|
|
@@ -98,7 +98,8 @@ function copyTemplates(tmplDir, obsRoot) {
|
|
|
98
98
|
}
|
|
99
99
|
function chmodScripts(obsRoot) {
|
|
100
100
|
for (var i = 0; i < SH_FILES.length; i++) {
|
|
101
|
-
fs.chmodSync(path.join(obsRoot, SH_FILES[i]), 0o755);
|
|
101
|
+
try { fs.chmodSync(path.join(obsRoot, SH_FILES[i]), 0o755); }
|
|
102
|
+
catch (e) { /* ignore */ }
|
|
102
103
|
}
|
|
103
104
|
}
|
|
104
105
|
function mergeSettings(projDir, entry) {
|
|
@@ -134,27 +135,40 @@ function prompt(question) {
|
|
|
134
135
|
});
|
|
135
136
|
}
|
|
136
137
|
|
|
137
|
-
function printSummary() {
|
|
138
|
+
function printSummary(projDir, projectName) {
|
|
139
|
+
var gsdScripts = path.join(gsdRoot(projDir), 'scripts');
|
|
140
|
+
var name = projectName || path.basename(projDir);
|
|
138
141
|
console.log([
|
|
139
142
|
'',
|
|
140
143
|
'Done! Next steps:',
|
|
141
|
-
'
|
|
144
|
+
' ' + path.join(gsdScripts, 'start.sh') + ' ' + name,
|
|
142
145
|
'',
|
|
143
|
-
' Creates tmux sessions
|
|
144
|
-
' project-dir defaults to current directory if omitted.',
|
|
146
|
+
' Creates tmux sessions gsd-observer-' + name + ' and gsd-worker-' + name + '.',
|
|
145
147
|
' Opens Terminal windows attached to each session.',
|
|
146
148
|
'',
|
|
147
|
-
' Observer agent
|
|
148
|
-
' Verify setup:
|
|
149
|
+
' Observer agent: ' + path.join(gsdRoot(projDir), 'agents', 'gsd-observer.md'),
|
|
150
|
+
' Verify setup: ' + path.join(gsdScripts, 'verify.sh'),
|
|
149
151
|
].join('\n'));
|
|
150
152
|
}
|
|
151
153
|
|
|
152
154
|
async function run() {
|
|
153
155
|
var args = process.argv.slice(2);
|
|
154
156
|
var skipPrompt = args.indexOf('--yes') !== -1 || args.indexOf('-y') !== -1;
|
|
155
|
-
var
|
|
157
|
+
var positional = args.filter(function(a) { return !a.startsWith('-'); });
|
|
158
|
+
var projectName = positional[0] || null;
|
|
159
|
+
|
|
160
|
+
var projDir;
|
|
161
|
+
if (process.env.GSD_INIT_PROJ_DIR) {
|
|
162
|
+
projDir = process.env.GSD_INIT_PROJ_DIR;
|
|
163
|
+
} else if (projectName) {
|
|
164
|
+
projDir = path.join(process.cwd(), projectName);
|
|
165
|
+
} else {
|
|
166
|
+
projDir = process.cwd();
|
|
167
|
+
}
|
|
168
|
+
var obsRoot = gsdRoot(projDir);
|
|
169
|
+
var gsdEntry = makeGsdEntry(projDir);
|
|
156
170
|
|
|
157
|
-
var ops = planInstall(TEMPLATES_DIR,
|
|
171
|
+
var ops = planInstall(TEMPLATES_DIR, obsRoot, projDir);
|
|
158
172
|
|
|
159
173
|
// Abort on malformed settings.json early
|
|
160
174
|
var errOp = null;
|
|
@@ -178,10 +192,16 @@ async function run() {
|
|
|
178
192
|
}
|
|
179
193
|
}
|
|
180
194
|
|
|
181
|
-
// Step
|
|
195
|
+
// Step 0: create project folder if a name was given
|
|
196
|
+
if (projectName) {
|
|
197
|
+
try { mkdirpSync(projDir); }
|
|
198
|
+
catch (e) { console.error('Error creating project folder ' + projDir + ': ' + e.message); process.exit(1); }
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
// Step 1: create .gsd/ subdirs
|
|
182
202
|
var subdirs = ['agents', 'hooks', 'scripts', 'schema'];
|
|
183
203
|
for (var j = 0; j < subdirs.length; j++) {
|
|
184
|
-
var subdir = path.join(
|
|
204
|
+
var subdir = path.join(obsRoot, subdirs[j]);
|
|
185
205
|
try { mkdirpSync(subdir); }
|
|
186
206
|
catch (e) { console.error('Error creating ' + subdir + ': ' + e.message); process.exit(1); }
|
|
187
207
|
}
|
|
@@ -192,18 +212,18 @@ async function run() {
|
|
|
192
212
|
catch (e) { console.error('Error creating ' + dotClaudeDir + ': ' + e.message); process.exit(1); }
|
|
193
213
|
|
|
194
214
|
// Step 3: copy templates
|
|
195
|
-
try { copyTemplates(TEMPLATES_DIR,
|
|
196
|
-
catch (e) { console.error('Error copying templates to ' +
|
|
215
|
+
try { copyTemplates(TEMPLATES_DIR, obsRoot); }
|
|
216
|
+
catch (e) { console.error('Error copying templates to ' + obsRoot + ': ' + e.message); process.exit(1); }
|
|
197
217
|
|
|
198
218
|
// Step 4: chmod .sh files
|
|
199
|
-
try { chmodScripts(
|
|
200
|
-
catch (e) { console.error('Error setting permissions in ' +
|
|
219
|
+
try { chmodScripts(obsRoot); }
|
|
220
|
+
catch (e) { console.error('Error setting permissions in ' + obsRoot + ': ' + e.message); process.exit(1); }
|
|
201
221
|
|
|
202
222
|
// Step 5: merge settings.json
|
|
203
|
-
try { mergeSettings(projDir,
|
|
223
|
+
try { mergeSettings(projDir, gsdEntry); }
|
|
204
224
|
catch (e) { console.error(e.message); process.exit(1); }
|
|
205
225
|
|
|
206
|
-
printSummary();
|
|
226
|
+
printSummary(projDir, projectName);
|
|
207
227
|
}
|
|
208
228
|
|
|
209
229
|
if (require.main === module) {
|
|
@@ -213,5 +233,5 @@ if (require.main === module) {
|
|
|
213
233
|
module.exports = {
|
|
214
234
|
planInstall, getSettingsLabel, formatDryRun, mkdirpSync,
|
|
215
235
|
copyTemplates, chmodScripts, mergeSettings, printSummary,
|
|
216
|
-
TEMPLATE_FILES, SH_FILES,
|
|
236
|
+
TEMPLATE_FILES, SH_FILES, makeGsdEntry, gsdRoot
|
|
217
237
|
};
|
package/package.json
CHANGED
|
@@ -43,9 +43,9 @@ When you receive an instruction to read an event file and respond:
|
|
|
43
43
|
}
|
|
44
44
|
```
|
|
45
45
|
|
|
46
|
-
6. Run the notify script:
|
|
46
|
+
6. Run the notify script (path is provided in the wake instruction):
|
|
47
47
|
```bash
|
|
48
|
-
|
|
48
|
+
<project_dir>/.gsd/scripts/notify-worker.sh <event_id>
|
|
49
49
|
```
|
|
50
50
|
|
|
51
51
|
**Rules:**
|
|
@@ -36,7 +36,7 @@ fi
|
|
|
36
36
|
|
|
37
37
|
# Inject task into Observer pane
|
|
38
38
|
tmux send-keys -t "$full_target" \
|
|
39
|
-
"Read ${event_path} and respond as GSD Observer. Write response to /tmp/gsd-response-${event_id}.json then run
|
|
39
|
+
"Read ${event_path} and respond as GSD Observer. Write response to /tmp/gsd-response-${event_id}.json then run ${SCRIPTS_DIR}/notify-worker.sh ${event_id}" \
|
|
40
40
|
Enter
|
|
41
41
|
|
|
42
42
|
echo "[wake-observer] Observer woken for event ${event_id}" >&2
|