@yemi33/minions 0.1.1738 → 0.1.1739
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/CHANGELOG.md +5 -0
- package/dashboard/js/command-center.js +6 -0
- package/dashboard.js +21 -13
- package/docs/command-center.md +4 -3
- package/engine/cleanup.js +4 -13
- package/engine/copilot-models.json +1 -1
- package/engine/llm.js +3 -0
- package/engine/shared.js +0 -1
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -392,6 +392,12 @@ function ccCloseTab(id) {
|
|
|
392
392
|
closingTab._queue = [];
|
|
393
393
|
_ccSending = (_ccTabs.some(function(t) { return t._sending; }));
|
|
394
394
|
}
|
|
395
|
+
// Tabs are non-expiring on the server — explicit close is the only path that
|
|
396
|
+
// removes the persisted session. Fire-and-forget DELETE so closing a tab
|
|
397
|
+
// also evicts the server-side cc-sessions.json entry.
|
|
398
|
+
try {
|
|
399
|
+
fetch('/api/cc-sessions/' + encodeURIComponent(id), { method: 'DELETE' }).catch(function() {});
|
|
400
|
+
} catch {}
|
|
395
401
|
_ccTabs.splice(idx, 1);
|
|
396
402
|
if (_ccActiveTabId === id) {
|
|
397
403
|
// Switch to adjacent tab or create new
|
package/dashboard.js
CHANGED
|
@@ -932,9 +932,14 @@ setInterval(() => {
|
|
|
932
932
|
|
|
933
933
|
// ── Command Center: session state + helpers ─────────────────────────────────
|
|
934
934
|
|
|
935
|
-
//
|
|
935
|
+
// CC chat sessions do NOT auto-expire. A tab is removed only via explicit user
|
|
936
|
+
// deletion (DELETE /api/cc-sessions/:id, wired from ccCloseTab). Doc-chat
|
|
937
|
+
// sessions keep their own TTL (DOC_SESSION_TTL_MS) — that's a separate store.
|
|
938
|
+
//
|
|
939
|
+
// CC_SESSION_MAX_TURNS is reused by the doc-chat session pruner to cap
|
|
940
|
+
// per-session turn growth there; CC chat sessions are not capped because
|
|
941
|
+
// users are expected to keep long-running tabs alive indefinitely.
|
|
936
942
|
const CC_SESSION_MAX_TURNS = shared.ENGINE_DEFAULTS.ccMaxTurns;
|
|
937
|
-
const CC_SESSION_TTL_MS = shared.ENGINE_DEFAULTS.ccSessionTtlMs;
|
|
938
943
|
let ccSession = { sessionId: null, createdAt: null, lastActiveAt: null, turnCount: 0 };
|
|
939
944
|
const ccInFlightTabs = new Map(); // tabId → timestamp — per-tab in-flight tracking for parallel CC requests
|
|
940
945
|
const ccInFlightAborts = new Map(); // tabId → abortFn — lets a new request kill the stale LLM
|
|
@@ -1070,18 +1075,17 @@ function _ccTabIsInFlight(tabId) {
|
|
|
1070
1075
|
|
|
1071
1076
|
function ccSessionValid() {
|
|
1072
1077
|
if (!ccSession.sessionId) return false;
|
|
1073
|
-
// Invalidate session if system prompt changed (e.g. after code update + restart)
|
|
1078
|
+
// Invalidate session if system prompt changed (e.g. after code update + restart).
|
|
1079
|
+
// This is correctness-driven, not expiration-driven: a session created against
|
|
1080
|
+
// a stale system prompt would carry the old persona/rules into resume turns.
|
|
1074
1081
|
if (ccSession._promptHash && ccSession._promptHash !== _ccPromptHash) {
|
|
1075
1082
|
console.log('[CC] System prompt changed — invalidating stale session');
|
|
1076
1083
|
ccSession = { sessionId: null, createdAt: null, lastActiveAt: null, turnCount: 0 };
|
|
1077
1084
|
return false;
|
|
1078
1085
|
}
|
|
1079
|
-
|
|
1080
|
-
|
|
1081
|
-
|
|
1082
|
-
return false;
|
|
1083
|
-
}
|
|
1084
|
-
return ccSession.turnCount < CC_SESSION_MAX_TURNS;
|
|
1086
|
+
// No TTL or turn-count cap — CC chat sessions live until the user explicitly
|
|
1087
|
+
// closes the tab (which calls DELETE /api/cc-sessions/:id).
|
|
1088
|
+
return true;
|
|
1085
1089
|
}
|
|
1086
1090
|
|
|
1087
1091
|
// Static system prompt — baked into session on creation, never changes
|
|
@@ -1120,11 +1124,13 @@ function _sessionExpired(lastActiveAt, ttlMs) {
|
|
|
1120
1124
|
return Date.now() - at > ttlMs;
|
|
1121
1125
|
}
|
|
1122
1126
|
|
|
1127
|
+
// CC tab sessions never auto-expire — only invalid records (missing id /
|
|
1128
|
+
// sessionId) and prompt-hash mismatches are filtered out. Tabs are removed
|
|
1129
|
+
// from disk only when the user explicitly closes them via DELETE
|
|
1130
|
+
// /api/cc-sessions/:id.
|
|
1123
1131
|
function _filterCcTabSessions(sessions) {
|
|
1124
1132
|
return (Array.isArray(sessions) ? sessions : []).filter(s =>
|
|
1125
1133
|
s && s.id && s.sessionId &&
|
|
1126
|
-
(s.turnCount || 0) < CC_SESSION_MAX_TURNS &&
|
|
1127
|
-
!_sessionExpired(s.lastActiveAt || s.createdAt, CC_SESSION_TTL_MS) &&
|
|
1128
1134
|
(!s._promptHash || s._promptHash === _ccPromptHash)
|
|
1129
1135
|
);
|
|
1130
1136
|
}
|
|
@@ -1157,10 +1163,12 @@ function _buildTranscriptCarryover(transcript, { previousRuntime } = {}) {
|
|
|
1157
1163
|
return `${header}\n\n${truncationNote}${lines.join('\n\n')}\n\n--- Current message follows ---`;
|
|
1158
1164
|
}
|
|
1159
1165
|
|
|
1160
|
-
// Load persisted CC session on startup
|
|
1166
|
+
// Load persisted CC session on startup. CC chat sessions are non-expiring;
|
|
1167
|
+
// only restore-time validity checks here are sessionId presence (anything
|
|
1168
|
+
// else would auto-expire the user's chat without their consent).
|
|
1161
1169
|
try {
|
|
1162
1170
|
const saved = safeJson(path.join(ENGINE_DIR, 'cc-session.json'));
|
|
1163
|
-
if (saved && saved.sessionId
|
|
1171
|
+
if (saved && saved.sessionId) ccSession = saved;
|
|
1164
1172
|
} catch { /* optional */ }
|
|
1165
1173
|
|
|
1166
1174
|
let _preambleCache = null;
|
package/docs/command-center.md
CHANGED
|
@@ -13,11 +13,12 @@ CC maintains a true multi-turn session using Claude CLI's `--resume` flag. Unlik
|
|
|
13
13
|
**Session lifecycle:**
|
|
14
14
|
- **Created** on first message (or after the system prompt changes, or when you click **New Session**)
|
|
15
15
|
- **Resumed** on subsequent messages via `--resume <sessionId>`
|
|
16
|
-
- **Invalidated** when the CC system prompt changes — detected by hashing `CC_STATIC_SYSTEM_PROMPT` into `_ccPromptHash` and comparing on each call.
|
|
17
|
-
- **Persisted** to `engine/cc-session.json` —
|
|
16
|
+
- **Invalidated** only when the CC system prompt changes — detected by hashing `CC_STATIC_SYSTEM_PROMPT` into `_ccPromptHash` and comparing on each call. CC chat sessions do **not** auto-expire by TTL or turn count; `ENGINE_DEFAULTS.ccMaxTurns` (default 50) is a per-call tool-use cap inside the Claude CLI, not a session lifetime cap.
|
|
17
|
+
- **Persisted** to `engine/cc-session.json` (legacy global session) and `engine/cc-sessions.json` (per-tab sessions) — both survive dashboard restarts and engine cleanup ticks
|
|
18
18
|
- **Frontend messages** saved to `localStorage` — survive page refresh
|
|
19
|
+
- **Removed** only when the user explicitly closes a tab via the **×** button on the tab strip — that fires `DELETE /api/cc-sessions/:id` to evict the persisted session
|
|
19
20
|
|
|
20
|
-
Click **New Session** in the drawer header to start fresh.
|
|
21
|
+
Click **New Session** in the drawer header to start fresh; click the **×** on a tab to remove it permanently.
|
|
21
22
|
|
|
22
23
|
### Fresh State Each Turn
|
|
23
24
|
|
package/engine/cleanup.js
CHANGED
|
@@ -681,20 +681,11 @@ async function runCleanup(config, verbose = false) {
|
|
|
681
681
|
}
|
|
682
682
|
} catch (e) { log('warn', 'orphan PRD status reset: ' + e.message); }
|
|
683
683
|
|
|
684
|
-
// 10.
|
|
684
|
+
// 10. CC tab sessions are non-expiring by design — they persist until the
|
|
685
|
+
// user explicitly closes the tab (which fires DELETE /api/cc-sessions/:id).
|
|
686
|
+
// Cleanup intentionally does NOT prune cc-sessions.json; doing so would
|
|
687
|
+
// silently invalidate live chat tabs the user expects to keep.
|
|
685
688
|
cleaned.ccSessions = 0;
|
|
686
|
-
try {
|
|
687
|
-
const ccSessionsPath = path.join(ENGINE_DIR, 'cc-sessions.json');
|
|
688
|
-
const sessions = shared.safeJsonArr(ccSessionsPath);
|
|
689
|
-
const CC_SESSIONS_CAP = 50;
|
|
690
|
-
if (sessions.length > CC_SESSIONS_CAP) {
|
|
691
|
-
// Sort by lastActiveAt descending, keep newest
|
|
692
|
-
sessions.sort((a, b) => new Date(b.lastActiveAt || 0) - new Date(a.lastActiveAt || 0));
|
|
693
|
-
const pruned = sessions.slice(0, CC_SESSIONS_CAP);
|
|
694
|
-
cleaned.ccSessions = sessions.length - pruned.length;
|
|
695
|
-
safeWrite(ccSessionsPath, pruned);
|
|
696
|
-
}
|
|
697
|
-
} catch (e) { log('warn', 'prune cc-sessions: ' + e.message); }
|
|
698
689
|
|
|
699
690
|
// 10b. Prune doc-chat sessions — cap at 100 entries, remove oldest beyond cap
|
|
700
691
|
cleaned.docSessions = 0;
|
package/engine/llm.js
CHANGED
|
@@ -787,6 +787,9 @@ function callLLMStreaming(promptText, sysPromptText, opts = {}) {
|
|
|
787
787
|
|
|
788
788
|
proc.on('close', finish);
|
|
789
789
|
proc.on('exit', (code) => {
|
|
790
|
+
// 'close' waits for stdio to close. If the runtime spawned a detached
|
|
791
|
+
// grandchild that inherited stdout/stderr, the OS pipe stays open and
|
|
792
|
+
// 'close' may never fire. Fall back to 'exit' after a drain window.
|
|
790
793
|
if (settled) return;
|
|
791
794
|
exitSettleTimer = setTimeout(() => finish(code), LLM_EXIT_SETTLE_GRACE_MS);
|
|
792
795
|
});
|
package/engine/shared.js
CHANGED
|
@@ -914,7 +914,6 @@ const ENGINE_DEFAULTS = {
|
|
|
914
914
|
removeWorktreeFailureTtlMs: 24 * 60 * 60 * 1000, // stale failed paths are forgotten after a day
|
|
915
915
|
removeWorktreeFailureMaxEntries: 1000, // bound failed-worktree retry suppression cache
|
|
916
916
|
ccMaxTurns: 50, // max tool-use turns for CC/doc-chat before CLI stops
|
|
917
|
-
ccSessionTtlMs: 7 * 24 * 60 * 60 * 1000, // 7d — keep chats resumable after breaks, still bounded by turn cap
|
|
918
917
|
docSessionTtlMs: 7 * 24 * 60 * 60 * 1000, // 7d — longer-lived doc sessions, still bounded
|
|
919
918
|
docSessionMaxEntries: 200, // cap doc-chat session map/disk store by least-recent activity
|
|
920
919
|
ccLiveStreamMaxAgeMs: 30 * 60 * 1000, // hard cap reconnect buffers if abort/cleanup stalls
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@yemi33/minions",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.1739",
|
|
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"
|