@yemi33/minions 0.1.2194 → 0.1.2195

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.
@@ -476,6 +476,8 @@ function ccAbort() {
476
476
 
477
477
  function toggleCommandCenter() {
478
478
  _ccOpen = !_ccOpen;
479
+ // Opening CC means the operator found it — retire the first-use coachmark.
480
+ if (_ccOpen && typeof dismissCcHint === 'function') dismissCcHint();
479
481
  var drawer = document.getElementById('cc-drawer');
480
482
  var overlay = document.getElementById('cc-overlay');
481
483
  if (_ccOpen) ccApplySavedWidth();
@@ -188,4 +188,128 @@ function renderFre(statusOrProjects) {
188
188
  '</div>';
189
189
  }
190
190
 
191
- window.MinionsFre = { renderFre, dismissFre, openSettingsToDefaultCli, _freReset, FRE_DISMISS_KEY };
191
+ // ── Command Center first-use coachmark ──────────────────────────────────────
192
+ // A small popup anchored under the Command Center header button, shown to
193
+ // brand-new operators who have never used CC. Teaches the primary entry point:
194
+ // "prompt the Command Center to ask it to dispatch work." Self-contained and
195
+ // idempotent — safe to call renderCcHint() every refresh tick.
196
+ //
197
+ // Trigger: NOT dismissed AND the operator has never sent a CC message (no
198
+ // 'cc-tabs' entry carries any messages). Auto-suppressed while the CC drawer
199
+ // is open. Dismissed permanently when the user opens CC (see
200
+ // toggleCommandCenter in command-center.js) or clicks "Got it".
201
+
202
+ const CC_HINT_DISMISS_KEY = 'minions_cc_hint_dismissed';
203
+ const CC_HINT_MOUNT_ID = 'cc-hint-coachmark';
204
+
205
+ function _ccHintIsDismissed() {
206
+ try { return localStorage.getItem(CC_HINT_DISMISS_KEY) === '1'; } catch { return false; }
207
+ }
208
+
209
+ // "Brand new" = the operator has never sent a Command Center message. Reads the
210
+ // same 'cc-tabs' localStorage key command-center.js persists; any tab carrying
211
+ // at least one message means CC has been used and the hint has served its
212
+ // purpose. Absent/empty/parse-error all read as new (fail toward showing).
213
+ function _ccHintUserIsNew() {
214
+ try {
215
+ const raw = localStorage.getItem('cc-tabs');
216
+ if (!raw) return true;
217
+ const tabs = JSON.parse(raw);
218
+ if (!Array.isArray(tabs) || tabs.length === 0) return true;
219
+ return !tabs.some(function(t) { return t && Array.isArray(t.messages) && t.messages.length > 0; });
220
+ } catch { return true; }
221
+ }
222
+
223
+ function _ccHintRemove() {
224
+ const mount = document.getElementById(CC_HINT_MOUNT_ID);
225
+ if (mount && mount.parentNode) mount.parentNode.removeChild(mount);
226
+ }
227
+
228
+ function dismissCcHint() {
229
+ try { localStorage.setItem(CC_HINT_DISMISS_KEY, '1'); } catch { /* expected */ }
230
+ _ccHintRemove();
231
+ }
232
+
233
+ // Reset helper (exposed for tests / debugging only). Not wired to UI.
234
+ function _ccHintReset() {
235
+ try { localStorage.removeItem(CC_HINT_DISMISS_KEY); } catch { /* expected */ }
236
+ }
237
+
238
+ // Open the Command Center from the coachmark CTA, then dismiss the hint.
239
+ function openCcFromHint() {
240
+ dismissCcHint();
241
+ if (typeof toggleCommandCenter === 'function' && !window._ccOpen) {
242
+ try { toggleCommandCenter(); } catch { /* drawer not mounted yet */ }
243
+ }
244
+ }
245
+
246
+ // Re-anchor the coachmark under the CC button. Called on render and on resize.
247
+ function _ccHintPosition() {
248
+ const mount = document.getElementById(CC_HINT_MOUNT_ID);
249
+ const btn = document.getElementById('cc-toggle-btn');
250
+ if (!mount || !btn) return;
251
+ const rect = btn.getBoundingClientRect();
252
+ mount.style.top = (rect.bottom + 10) + 'px';
253
+ // Right-align the card to the button's right edge.
254
+ mount.style.right = Math.max(8, window.innerWidth - rect.right) + 'px';
255
+ // Point the caret at the button's horizontal centre.
256
+ const arrow = document.getElementById('cc-hint-arrow');
257
+ if (arrow) arrow.style.right = Math.max(12, (rect.width / 2) - 6) + 'px';
258
+ }
259
+
260
+ let _ccHintResizeBound = false;
261
+
262
+ // Render the coachmark into document.body. Idempotent — bails out (and removes
263
+ // any stale mount) when dismissed, when CC has been used, when the header
264
+ // button isn't mounted yet, or while the drawer is open.
265
+ function renderCcHint() {
266
+ if (_ccHintIsDismissed() || !_ccHintUserIsNew()) {
267
+ _ccHintRemove();
268
+ return;
269
+ }
270
+ const btn = document.getElementById('cc-toggle-btn');
271
+ if (!btn) return; // header not assembled yet
272
+ const drawer = document.getElementById('cc-drawer');
273
+ if (drawer && drawer.style.display === 'flex') {
274
+ // User already found CC — don't hover the hint over the open drawer.
275
+ _ccHintRemove();
276
+ return;
277
+ }
278
+
279
+ let mount = document.getElementById(CC_HINT_MOUNT_ID);
280
+ if (!mount) {
281
+ mount = document.createElement('div');
282
+ mount.id = CC_HINT_MOUNT_ID;
283
+ mount.style.cssText = [
284
+ 'position:fixed',
285
+ 'z-index:330',
286
+ 'width:260px',
287
+ 'padding:14px 16px',
288
+ 'background:var(--surface)',
289
+ 'border:1px solid var(--blue)',
290
+ 'border-radius:var(--radius-lg)',
291
+ 'box-shadow:var(--shadow-md)',
292
+ 'color:var(--text)',
293
+ 'font-size:var(--text-md)',
294
+ 'line-height:1.5',
295
+ ].join(';');
296
+ document.body.appendChild(mount);
297
+ // eslint-disable-next-line no-unsanitized/property -- reason: static string literal — no user-controlled data is interpolated
298
+ mount.innerHTML =
299
+ '<div id="cc-hint-arrow" style="position:absolute;top:-7px;width:12px;height:12px;background:var(--surface);border-left:1px solid var(--blue);border-top:1px solid var(--blue);transform:rotate(45deg)"></div>' +
300
+ '<div style="font-weight:700;color:var(--blue);margin-bottom:4px">&#x1F44B; Start here</div>' +
301
+ '<div style="color:var(--text)">Prompt your <strong>Command Center</strong> here to ask it to dispatch work.</div>' +
302
+ '<div style="display:flex;gap:8px;margin-top:12px">' +
303
+ '<button onclick="openCcFromHint()" class="btn-primary-solid" style="padding:5px 12px;font-size:var(--text-sm)">Open Command Center</button>' +
304
+ '<button onclick="dismissCcHint()" style="padding:5px 12px;font-size:var(--text-sm);background:transparent;color:var(--muted);border:1px solid var(--border);border-radius:var(--radius-sm);cursor:pointer">Got it</button>' +
305
+ '</div>';
306
+ }
307
+ _ccHintPosition();
308
+ if (!_ccHintResizeBound) {
309
+ _ccHintResizeBound = true;
310
+ window.addEventListener('resize', _ccHintPosition);
311
+ }
312
+ }
313
+
314
+ window.MinionsFre = { renderFre, dismissFre, openSettingsToDefaultCli, _freReset, FRE_DISMISS_KEY,
315
+ renderCcHint, dismissCcHint, openCcFromHint, _ccHintReset, _ccHintUserIsNew, CC_HINT_DISMISS_KEY };
@@ -612,6 +612,12 @@ function _processStatusUpdate(data, opts) {
612
612
  if (typeof renderFre === 'function') {
613
613
  _safeRender('fre', function() { renderFre(data); });
614
614
  }
615
+ // Command Center first-use coachmark — anchored under the CC header button
616
+ // for brand-new operators who have never sent a CC message. Idempotent +
617
+ // cheap; self-suppresses once CC is used or dismissed.
618
+ if (typeof renderCcHint === 'function') {
619
+ _safeRender('ccHint', function() { renderCcHint(); });
620
+ }
615
621
  // Notes file (notes.md) is now sourced from /state/notes.md. Same shape
616
622
  // as the legacy /api/status notes slice ({ content, updatedAt }); the
617
623
  // ETag mtime is parsed out of the response header for updatedAt.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@yemi33/minions",
3
- "version": "0.1.2194",
3
+ "version": "0.1.2195",
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"