@yemi33/squad 0.1.3 → 0.1.4

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 +26 -3
  2. package/package.json +1 -1
package/engine.js CHANGED
@@ -128,10 +128,24 @@ function safeWrite(p, data) {
128
128
  const tmp = p + '.tmp.' + process.pid;
129
129
  try {
130
130
  fs.writeFileSync(tmp, content);
131
- fs.renameSync(tmp, p);
131
+ // Atomic rename — retry on Windows EPERM (file locking)
132
+ for (let attempt = 0; attempt < 3; attempt++) {
133
+ try {
134
+ fs.renameSync(tmp, p);
135
+ return;
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) {}
140
+ continue;
141
+ }
142
+ throw e;
143
+ }
144
+ }
132
145
  } catch (e) {
146
+ // Fallback: direct write if atomic rename fails entirely
133
147
  try { fs.unlinkSync(tmp); } catch {}
134
- throw e;
148
+ try { fs.writeFileSync(p, content); } catch {}
135
149
  }
136
150
  }
137
151
 
@@ -1146,13 +1160,22 @@ function getAdoToken() {
1146
1160
  return null;
1147
1161
  }
1148
1162
 
1149
- async function adoFetch(url, token) {
1163
+ async function adoFetch(url, token, _retried = false) {
1150
1164
  const res = await fetch(url, {
1151
1165
  headers: { 'Authorization': `Bearer ${token}`, 'Content-Type': 'application/json' }
1152
1166
  });
1153
1167
  if (!res.ok) throw new Error(`ADO API ${res.status}: ${res.statusText}`);
1154
1168
  const text = await res.text();
1155
1169
  if (!text || text.trimStart().startsWith('<')) {
1170
+ // Auth redirect — token likely expired. Invalidate cache and retry once.
1171
+ if (!_retried) {
1172
+ _adoTokenCache = { token: null, expiresAt: 0 };
1173
+ const freshToken = getAdoToken();
1174
+ if (freshToken) {
1175
+ log('info', 'ADO token expired mid-session — refreshed and retrying');
1176
+ return adoFetch(url, freshToken, true);
1177
+ }
1178
+ }
1156
1179
  throw new Error(`ADO returned HTML instead of JSON (likely auth redirect) for ${url.split('?')[0]}`);
1157
1180
  }
1158
1181
  return JSON.parse(text);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@yemi33/squad",
3
- "version": "0.1.3",
3
+ "version": "0.1.4",
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"