@yemi33/minions 0.1.1990 → 0.1.1991
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 +35 -5
- package/engine/shared.js +10 -0
- package/package.json +1 -1
package/dashboard.js
CHANGED
|
@@ -34,7 +34,7 @@ const features = require('./engine/features');
|
|
|
34
34
|
const ccWorkerPool = require('./engine/cc-worker-pool');
|
|
35
35
|
const os = require('os');
|
|
36
36
|
|
|
37
|
-
const { safeRead, safeReadDir, safeWrite, safeJson, safeJsonObj, safeJsonArr, safeJsonNoRestore, safeUnlink, mutateJsonFileLocked, mutateTextFileLocked, mutateControl, mutateCooldowns, mutateWorkItems, getProjects: _getProjects, DONE_STATUSES, WI_STATUS, WORK_TYPE, WORKTREE_REQUIRING_TYPES, reopenWorkItem } = shared;
|
|
37
|
+
const { safeRead, safeReadOrNull, safeReadDir, safeWrite, safeJson, safeJsonObj, safeJsonArr, safeJsonNoRestore, safeUnlink, mutateJsonFileLocked, mutateTextFileLocked, mutateControl, mutateCooldowns, mutateWorkItems, getProjects: _getProjects, DONE_STATUSES, WI_STATUS, WORK_TYPE, WORKTREE_REQUIRING_TYPES, reopenWorkItem } = shared;
|
|
38
38
|
const { getAgents, getAgentDetail, getPrdInfo, getWorkItems, getDispatchQueue,
|
|
39
39
|
getSkills, getInbox, getNotesWithMeta, getPullRequests,
|
|
40
40
|
getEngineLog, getMetrics, getKnowledgeBaseEntries, getProjectGitStatus, timeSince,
|
|
@@ -2640,11 +2640,31 @@ async function _preflightModelCheck({ runtime: cliOverride, model: modelOverride
|
|
|
2640
2640
|
* document body. Always re-sending extraContext is correctness-safe; the
|
|
2641
2641
|
* pool's warm-process saving is preserved regardless.
|
|
2642
2642
|
*/
|
|
2643
|
+
/**
|
|
2644
|
+
* Build the persistent doc-chat pool tabKey from a session key (filePath or
|
|
2645
|
+
* title). Single source of truth shared by _invokeDocChatViaPool (the
|
|
2646
|
+
* streaming path) and handleDocChatWarm (the pre-warm endpoint). Both call
|
|
2647
|
+
* sites MUST resolve to the same key, otherwise warm spawns an orphan worker
|
|
2648
|
+
* the streaming call ignores — silently breaking the skip-18-21s Copilot
|
|
2649
|
+
* cold-spawn optimization documented at modal-qa.js:506-516.
|
|
2650
|
+
*
|
|
2651
|
+
* The `default` fallback mirrors the legacy inline behavior for empty input
|
|
2652
|
+
* so older callers (and the dashboard test fixtures that omit sessionKey)
|
|
2653
|
+
* still land on a stable, predictable key.
|
|
2654
|
+
*
|
|
2655
|
+
* The freshSession one-shot branch in _invokeDocChatViaPool intentionally
|
|
2656
|
+
* bypasses this helper — those callers want a unique short-lived key under
|
|
2657
|
+
* `doc-chat:fresh:<uid>`, not the persistent namespace.
|
|
2658
|
+
*/
|
|
2659
|
+
function _buildDocChatTabKey(sessionKey) {
|
|
2660
|
+
return 'doc-chat:' + (sessionKey || 'default');
|
|
2661
|
+
}
|
|
2662
|
+
|
|
2643
2663
|
function _invokeDocChatViaPool({ prompt, model, effort, engineConfig, systemPrompt, sessionKey, freshSession, timeoutMs, onChunk, onToolUse, onToolUpdate }) {
|
|
2644
2664
|
const oneShot = !!freshSession;
|
|
2645
2665
|
const tabKey = oneShot
|
|
2646
2666
|
? 'doc-chat:fresh:' + shared.uid()
|
|
2647
|
-
:
|
|
2667
|
+
: _buildDocChatTabKey(sessionKey);
|
|
2648
2668
|
let cancelled = false;
|
|
2649
2669
|
let settled = false;
|
|
2650
2670
|
let accumulated = '';
|
|
@@ -5905,7 +5925,10 @@ What would you like to discuss or change? When you're happy, say "approve" and I
|
|
|
5905
5925
|
if (canEdit) {
|
|
5906
5926
|
try { shared.sanitizePath(body.filePath, MINIONS_DIR); } catch { return jsonReply(res, 400, { error: 'path must be under minions directory' }); }
|
|
5907
5927
|
fullPath = path.resolve(MINIONS_DIR, body.filePath);
|
|
5908
|
-
|
|
5928
|
+
// safeReadOrNull returns null when the file is missing/inaccessible.
|
|
5929
|
+
// If absent, keep body.document (the client-sent panel content) — do
|
|
5930
|
+
// NOT overwrite currentContent with '' (W-mpede4j7000ab7e4).
|
|
5931
|
+
const diskContent = safeReadOrNull(fullPath);
|
|
5909
5932
|
if (diskContent !== null) {
|
|
5910
5933
|
// If client sent a contentHash and it matches disk, skip replacement — client copy is fresh
|
|
5911
5934
|
if (body.contentHash && contentFingerprint(diskContent) === body.contentHash) {
|
|
@@ -5992,7 +6015,10 @@ What would you like to discuss or change? When you're happy, say "approve" and I
|
|
|
5992
6015
|
try { shared.sanitizePath(body.filePath, MINIONS_DIR); }
|
|
5993
6016
|
catch { docChatInFlight.delete(docKey); res.statusCode = 400; res.setHeader('Content-Type', 'application/json'); res.end(JSON.stringify({ error: 'path must be under minions directory' })); return; }
|
|
5994
6017
|
fullPath = path.resolve(MINIONS_DIR, body.filePath);
|
|
5995
|
-
|
|
6018
|
+
// safeReadOrNull returns null when the file is missing/inaccessible.
|
|
6019
|
+
// If absent, keep body.document (the client-sent panel content) — do
|
|
6020
|
+
// NOT overwrite currentContent with '' (W-mpede4j7000ab7e4).
|
|
6021
|
+
const diskContent = safeReadOrNull(fullPath);
|
|
5996
6022
|
if (diskContent !== null) {
|
|
5997
6023
|
if (!(body.contentHash && contentFingerprint(diskContent) === body.contentHash)) {
|
|
5998
6024
|
currentContent = diskContent;
|
|
@@ -6595,7 +6621,10 @@ What would you like to discuss or change? When you're happy, say "approve" and I
|
|
|
6595
6621
|
const body = await readBody(req);
|
|
6596
6622
|
const sessionKey = body && (body.filePath || body.title);
|
|
6597
6623
|
if (!sessionKey) return jsonReply(res, 400, { error: 'filePath or title required' });
|
|
6598
|
-
|
|
6624
|
+
// Must match the persistent tabKey _invokeDocChatViaPool hands to
|
|
6625
|
+
// ccWorkerPool.getSession at first-message time, or this warm spawns
|
|
6626
|
+
// an orphan worker (regression W-mpede4bf000957b5).
|
|
6627
|
+
const result = await _warmCcPool(_buildDocChatTabKey(sessionKey), _docChatPromptHash);
|
|
6599
6628
|
return jsonReply(res, 200, result);
|
|
6600
6629
|
} catch (e) { return jsonReply(res, e.statusCode || 500, { error: e.message }); }
|
|
6601
6630
|
}
|
|
@@ -9261,6 +9290,7 @@ module.exports = {
|
|
|
9261
9290
|
parsePinnedEntries,
|
|
9262
9291
|
_formatDocChatContext,
|
|
9263
9292
|
_buildDocChatPass,
|
|
9293
|
+
_buildDocChatTabKey,
|
|
9264
9294
|
_docSessionsForTesting: docSessions,
|
|
9265
9295
|
_docChatPromptHashForTesting: _docChatPromptHash,
|
|
9266
9296
|
_isCompletedMeetingJson,
|
package/engine/shared.js
CHANGED
|
@@ -323,6 +323,15 @@ function safeRead(p) {
|
|
|
323
323
|
try { return fs.readFileSync(p, 'utf8'); } catch { return ''; }
|
|
324
324
|
}
|
|
325
325
|
|
|
326
|
+
// Like safeRead, but returns null when the file is missing/inaccessible so
|
|
327
|
+
// callers can distinguish "file absent" from "file present but empty".
|
|
328
|
+
// Used by doc-chat handlers (W-mpede4j7000ab7e4) to avoid silently overwriting
|
|
329
|
+
// the client-sent document body with '' when the file was deleted/moved
|
|
330
|
+
// between panel open and send.
|
|
331
|
+
function safeReadOrNull(p) {
|
|
332
|
+
try { return fs.readFileSync(p, 'utf8'); } catch { return null; }
|
|
333
|
+
}
|
|
334
|
+
|
|
326
335
|
function safeReadDir(dir) {
|
|
327
336
|
try { return fs.readdirSync(dir); } catch { return []; }
|
|
328
337
|
}
|
|
@@ -4680,6 +4689,7 @@ module.exports = {
|
|
|
4680
4689
|
dateStamp,
|
|
4681
4690
|
log,
|
|
4682
4691
|
safeRead,
|
|
4692
|
+
safeReadOrNull,
|
|
4683
4693
|
safeReadDir,
|
|
4684
4694
|
safeJson, safeJsonObj, safeJsonArr, safeJsonNoRestore,
|
|
4685
4695
|
safeWrite,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@yemi33/minions",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.1991",
|
|
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"
|