@yemi33/squad 0.1.4 → 0.1.5

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 (2) hide show
  1. package/engine.js +31 -11
  2. package/package.json +1 -1
package/engine.js CHANGED
@@ -129,23 +129,25 @@ function safeWrite(p, data) {
129
129
  try {
130
130
  fs.writeFileSync(tmp, content);
131
131
  // Atomic rename — retry on Windows EPERM (file locking)
132
- for (let attempt = 0; attempt < 3; attempt++) {
132
+ for (let attempt = 0; attempt < 5; attempt++) {
133
133
  try {
134
134
  fs.renameSync(tmp, p);
135
135
  return;
136
136
  } catch (e) {
137
- if (e.code === 'EPERM' && attempt < 2) {
138
- // Brief sync sleep (10ms) then retry
139
- const start = Date.now(); while (Date.now() - start < 10) {}
137
+ if (e.code === 'EPERM' && attempt < 4) {
138
+ const delay = 50 * (attempt + 1); // 50, 100, 150, 200ms
139
+ const start = Date.now(); while (Date.now() - start < delay) {}
140
140
  continue;
141
141
  }
142
- throw e;
142
+ // Final attempt failed — fall through to direct write
143
143
  }
144
144
  }
145
- } catch (e) {
146
- // Fallback: direct write if atomic rename fails entirely
145
+ // All rename attempts failed — direct write as fallback (not atomic but won't lose data)
146
+ try { fs.unlinkSync(tmp); } catch {}
147
+ fs.writeFileSync(p, content);
148
+ } catch {
149
+ // Even direct write failed — clean up tmp silently
147
150
  try { fs.unlinkSync(tmp); } catch {}
148
- try { fs.writeFileSync(p, content); } catch {}
149
151
  }
150
152
  }
151
153
 
@@ -851,6 +853,8 @@ function completeDispatch(id, result = 'success', reason = '') {
851
853
  item.completed_at = ts();
852
854
  item.result = result;
853
855
  if (reason) item.reason = reason;
856
+ // Strip prompt from completed items (saves ~10KB per item, reduces file lock contention)
857
+ delete item.prompt;
854
858
  dispatch.completed = dispatch.completed || [];
855
859
  dispatch.completed.push(item);
856
860
  // Keep last 100 completed
@@ -3008,7 +3012,10 @@ async function tick() {
3008
3012
 
3009
3013
  async function tickInner() {
3010
3014
  const control = getControl();
3011
- if (control.state !== 'running') return;
3015
+ if (control.state !== 'running') {
3016
+ log('info', `Engine state is "${control.state}" — exiting process`);
3017
+ process.exit(0);
3018
+ }
3012
3019
 
3013
3020
  const config = getConfig();
3014
3021
  tickCount++;
@@ -3081,8 +3088,16 @@ const commands = {
3081
3088
  start() {
3082
3089
  const control = getControl();
3083
3090
  if (control.state === 'running') {
3084
- console.log('Engine is already running.');
3085
- return;
3091
+ // Check if the PID is actually alive
3092
+ let alive = false;
3093
+ if (control.pid) {
3094
+ try { process.kill(control.pid, 0); alive = true; } catch {}
3095
+ }
3096
+ if (alive) {
3097
+ console.log(`Engine is already running (PID ${control.pid}).`);
3098
+ return;
3099
+ }
3100
+ console.log(`Engine was running (PID ${control.pid}) but process is dead — restarting.`);
3086
3101
  }
3087
3102
 
3088
3103
  safeWrite(CONTROL_PATH, { state: 'running', pid: process.pid, started_at: ts() });
@@ -3147,6 +3162,11 @@ const commands = {
3147
3162
  console.log(' On next start, they\'ll get a 20-min grace period before being marked as orphans.');
3148
3163
  console.log(' To kill them now, run: node engine.js kill\n');
3149
3164
  }
3165
+ // Kill the running engine process by PID
3166
+ const control = getControl();
3167
+ if (control.pid && control.pid !== process.pid) {
3168
+ try { process.kill(control.pid); } catch {}
3169
+ }
3150
3170
  safeWrite(CONTROL_PATH, { state: 'stopped', stopped_at: ts() });
3151
3171
  log('info', 'Engine stopped');
3152
3172
  console.log('Engine stopped.');
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@yemi33/squad",
3
- "version": "0.1.4",
3
+ "version": "0.1.5",
4
4
  "description": "Multi-agent AI dev team that runs from ~/.squad/ — five autonomous agents share a single engine, dashboard, and knowledge base",
5
5
  "bin": {
6
6
  "squad": "bin/squad.js"