@yemi33/minions 0.1.2325 → 0.1.2327
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/dashboard.js +33 -4
- package/engine/pull-requests-store.js +14 -1
- package/engine/work-items-store.js +12 -1
- package/package.json +1 -1
package/dashboard.js
CHANGED
|
@@ -9105,6 +9105,29 @@ What would you like to discuss or change? When you're happy, say "approve" and I
|
|
|
9105
9105
|
}
|
|
9106
9106
|
}
|
|
9107
9107
|
|
|
9108
|
+
// W-mr5m9inn002d27e1 — safeWrite/safeUnlink can both throw or silently no-op
|
|
9109
|
+
// (disk full, permission error, locked file on Windows). Previously the
|
|
9110
|
+
// archive step's try/catch only logged to console.error while the handler
|
|
9111
|
+
// still returned ok:true, so a failed archive left the note in
|
|
9112
|
+
// notes/inbox/ (risking double-processing) with no operator-visible
|
|
9113
|
+
// signal. Centralize the archive attempt so both call sites report
|
|
9114
|
+
// {archived, archiveError} instead of swallowing the failure.
|
|
9115
|
+
function _archiveInboxNote(inboxPath, archiveDestPath) {
|
|
9116
|
+
try {
|
|
9117
|
+
const _c = safeRead(inboxPath);
|
|
9118
|
+
safeWrite(archiveDestPath, _c);
|
|
9119
|
+
safeUnlink(inboxPath);
|
|
9120
|
+
if (fs.existsSync(inboxPath)) {
|
|
9121
|
+
// safeUnlink swallows its own errors, so a failed removal doesn't
|
|
9122
|
+
// throw — detect it by checking the source file is actually gone.
|
|
9123
|
+
return { archived: false, archiveError: 'inbox note could not be removed after archiving (unlink failed)' };
|
|
9124
|
+
}
|
|
9125
|
+
return { archived: true, archiveError: null };
|
|
9126
|
+
} catch (e) {
|
|
9127
|
+
return { archived: false, archiveError: e.message };
|
|
9128
|
+
}
|
|
9129
|
+
}
|
|
9130
|
+
|
|
9108
9131
|
async function handleInboxPersist(req, res) {
|
|
9109
9132
|
try {
|
|
9110
9133
|
const body = await readBody(req);
|
|
@@ -9150,9 +9173,12 @@ What would you like to discuss or change? When you're happy, say "approve" and I
|
|
|
9150
9173
|
// Move to archive
|
|
9151
9174
|
const archiveDir = path.join(MINIONS_DIR, 'notes', 'archive');
|
|
9152
9175
|
if (!fs.existsSync(archiveDir)) fs.mkdirSync(archiveDir, { recursive: true });
|
|
9153
|
-
|
|
9176
|
+
const { archived, archiveError } = _archiveInboxNote(inboxPath, path.join(archiveDir, `persisted-${name}`));
|
|
9177
|
+
if (!archived) console.error('inbox archive:', archiveError);
|
|
9154
9178
|
|
|
9155
|
-
return jsonReply(res, 200,
|
|
9179
|
+
return jsonReply(res, 200, archived
|
|
9180
|
+
? { ok: true, title, archived: true }
|
|
9181
|
+
: { ok: true, title, archived: false, warning: `Persisted to notes.md, but the inbox note could not be archived: ${archiveError}. It remains in notes/inbox and may be reprocessed.` });
|
|
9156
9182
|
} catch (e) { return jsonReply(res, 400, { error: e.message }); }
|
|
9157
9183
|
}
|
|
9158
9184
|
|
|
@@ -9215,9 +9241,12 @@ What would you like to discuss or change? When you're happy, say "approve" and I
|
|
|
9215
9241
|
// Move inbox item to archive
|
|
9216
9242
|
const archiveDir = path.join(MINIONS_DIR, 'notes', 'archive');
|
|
9217
9243
|
if (!fs.existsSync(archiveDir)) fs.mkdirSync(archiveDir, { recursive: true });
|
|
9218
|
-
|
|
9244
|
+
const { archived, archiveError } = _archiveInboxNote(inboxPath, path.join(archiveDir, `kb-${category}-${name}`));
|
|
9245
|
+
if (!archived) console.error('inbox archive:', archiveError);
|
|
9219
9246
|
|
|
9220
|
-
return jsonReply(res, 200,
|
|
9247
|
+
return jsonReply(res, 200, archived
|
|
9248
|
+
? { ok: true, category, file: name, archived: true }
|
|
9249
|
+
: { ok: true, category, file: name, archived: false, warning: `Promoted to knowledge/${category}/${name}, but the inbox note could not be archived: ${archiveError}. It remains in notes/inbox and may be reprocessed.` });
|
|
9221
9250
|
} catch (e) { return jsonReply(res, 400, { error: e.message }); }
|
|
9222
9251
|
}
|
|
9223
9252
|
|
|
@@ -299,11 +299,24 @@ function _mirrorJsonFromSql(scope, filePath) {
|
|
|
299
299
|
}
|
|
300
300
|
}
|
|
301
301
|
|
|
302
|
+
// Drop every SQL row for `scope` and forget its mirror-hash. Called by
|
|
303
|
+
// removeProject after the JSON file is archived so safeJson shim reads no
|
|
304
|
+
// longer surface the removed project's records.
|
|
305
|
+
//
|
|
306
|
+
// Per CLAUDE.md's mutator contract, every mutator wrapper must call
|
|
307
|
+
// emitStateEvent() so the dashboard's MAX(events.id) cache-version
|
|
308
|
+
// advances — otherwise the dashboard keeps serving stale cached
|
|
309
|
+
// pull-requests data for other still-active projects. Emit only when rows
|
|
310
|
+
// were actually deleted, matching the wrote-gated emit convention used by
|
|
311
|
+
// applyPullRequestsMutation's callers (see shared.js mutatePullRequests).
|
|
302
312
|
function dropScope(scope) {
|
|
303
313
|
try {
|
|
304
314
|
const { getDb } = require('./db');
|
|
305
|
-
getDb().prepare('DELETE FROM pull_requests WHERE scope = ?').run(scope);
|
|
315
|
+
const result = getDb().prepare('DELETE FROM pull_requests WHERE scope = ?').run(scope);
|
|
306
316
|
_lastMirrorHashByScope.delete(scope);
|
|
317
|
+
if (result && result.changes > 0) {
|
|
318
|
+
try { require('./db-events').emitStateEvent('pull_requests'); } catch { /* optional */ }
|
|
319
|
+
}
|
|
307
320
|
} catch { /* db unavailable */ }
|
|
308
321
|
}
|
|
309
322
|
|
|
@@ -379,11 +379,22 @@ function _mirrorJsonFromSql(scope, filePath) {
|
|
|
379
379
|
// Drop every SQL row for `scope` and forget its mirror-hash. Called by
|
|
380
380
|
// removeProject after the JSON file is archived so safeJson shim reads no
|
|
381
381
|
// longer surface the removed project's records.
|
|
382
|
+
//
|
|
383
|
+
// Per CLAUDE.md's mutator contract, every mutator wrapper must call
|
|
384
|
+
// emitStateEvent() so the dashboard's MAX(events.id) cache-version
|
|
385
|
+
// advances — otherwise the dashboard keeps serving stale cached
|
|
386
|
+
// work-items data for other still-active projects. Emit only when rows
|
|
387
|
+
// were actually deleted, matching the wrote-gated emit convention used by
|
|
388
|
+
// applyWorkItemsMutation's callers (see shared.js mutateWorkItems).
|
|
382
389
|
function dropScope(scope) {
|
|
383
390
|
try {
|
|
384
391
|
const { getDb } = require('./db');
|
|
385
|
-
getDb().prepare('DELETE FROM work_items WHERE scope = ?').run(scope);
|
|
392
|
+
const result = getDb().prepare('DELETE FROM work_items WHERE scope = ?').run(scope);
|
|
386
393
|
_lastMirrorHashByScope.delete(scope);
|
|
394
|
+
if (result && result.changes > 0) {
|
|
395
|
+
try { require('./db-events').emitStateEvent('work_items'); } catch { /* optional */ }
|
|
396
|
+
try { require('./queries').invalidateWorkItemsCache(); } catch { /* queries not loaded */ }
|
|
397
|
+
}
|
|
387
398
|
} catch { /* db unavailable */ }
|
|
388
399
|
}
|
|
389
400
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@yemi33/minions",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.2327",
|
|
4
4
|
"description": "Multi-agent AI dev team that runs from ~/.minions/ — five autonomous agents share a single engine, dashboard, and knowledge base",
|
|
5
5
|
"bin": {
|
|
6
6
|
"minions": "bin/minions.js"
|