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
- const GSD_ENTRY = {
45
- matcher: '',
46
- hooks: [{ type: 'command', command: '~/.claude/gsd-observer/hooks/gsd-stop-hook.sh' }]
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
- var relDisplay = dest.startsWith(homeDir)
69
- ? '~' + dest.slice(homeDir.length)
70
- : dest;
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
- ' ~/.claude/gsd-observer/scripts/start.sh <project-name> [project-dir]',
144
+ ' ' + path.join(gsdScripts, 'start.sh') + ' ' + name,
142
145
  '',
143
- ' Creates tmux sessions named gsd-observer-<project-name> and gsd-worker-<project-name>.',
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 prompt: ~/.claude/gsd-observer/agents/gsd-observer.md',
148
- ' Verify setup: ~/.claude/gsd-observer/scripts/verify.sh',
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 projDir = process.env.GSD_INIT_PROJ_DIR || process.cwd();
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, OBS_ROOT, projDir);
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 1: create ~/.claude/gsd-observer subdirs
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(OBS_ROOT, subdirs[j]);
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, OBS_ROOT); }
196
- catch (e) { console.error('Error copying templates to ' + OBS_ROOT + ': ' + e.message); process.exit(1); }
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(OBS_ROOT); }
200
- catch (e) { console.error('Error setting permissions in ' + OBS_ROOT + ': ' + e.message); process.exit(1); }
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, GSD_ENTRY); }
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, GSD_ENTRY
236
+ TEMPLATE_FILES, SH_FILES, makeGsdEntry, gsdRoot
217
237
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "gsd-init",
3
- "version": "1.0.6",
3
+ "version": "1.0.8",
4
4
  "description": "Set up GSD observer/worker tmux system in a project",
5
5
  "bin": {
6
6
  "gsd-init": "bin/gsd-init.js"
@@ -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
- ~/.claude/gsd-observer/scripts/notify-worker.sh <event_id>
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 ~/.claude/gsd-observer/scripts/notify-worker.sh ${event_id}" \
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