@yemi33/minions 0.1.2300 → 0.1.2302
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/refresh.js +1 -1
- package/dashboard/js/render-other.js +9 -0
- package/dashboard/styles.css +1 -0
- package/dashboard.js +50 -3
- package/engine/shared.js +42 -0
- package/package.json +1 -1
- package/prompts/cc-system.md +21 -0
package/dashboard/js/refresh.js
CHANGED
|
@@ -91,9 +91,18 @@ function _renderProjectBranch(p) {
|
|
|
91
91
|
// unset → 'worktree'). Live is the riskier/special mode (capped to one mutating
|
|
92
92
|
// dispatch per project, refuses on a dirty tree) so it gets a more prominent
|
|
93
93
|
// color than the muted worktree pill.
|
|
94
|
+
//
|
|
95
|
+
// Hybrid live-validation: when checkoutMode is 'live' AND p.liveValidationType
|
|
96
|
+
// is set, coding WIs author in isolated worktrees and only the named validation
|
|
97
|
+
// type runs in-place on the live checkout. This is a materially different
|
|
98
|
+
// dispatch profile from full-live, so it gets its own pill.
|
|
94
99
|
function _renderWorktreeModePill(p) {
|
|
95
100
|
if (!p) return '';
|
|
96
101
|
if (p.checkoutMode === 'live') {
|
|
102
|
+
if (p.liveValidationType) {
|
|
103
|
+
const vt = escapeHtml(p.liveValidationType);
|
|
104
|
+
return ' <span class="project-mode-pill project-mode-hybrid" title="Hybrid live-validation — coding work items author in isolated worktrees; only the "' + vt + '" validation type runs in-place on the live checkout (capped to one mutating dispatch, refused on a dirty tree)">⚡ Hybrid · ' + vt + '</span>';
|
|
105
|
+
}
|
|
97
106
|
return ' <span class="project-mode-pill project-mode-live" title="Live-checkout dispatch mode — agents run in-place inside the project working tree (no isolated worktree); capped to one mutating dispatch and refused on a dirty tree">⚡ Live checkout</span>';
|
|
98
107
|
}
|
|
99
108
|
return ' <span class="project-mode-pill project-mode-isolated" title="Worktree dispatch mode (default) — each agent runs in its own git worktree">Worktrees</span>';
|
package/dashboard/styles.css
CHANGED
|
@@ -1286,6 +1286,7 @@
|
|
|
1286
1286
|
}
|
|
1287
1287
|
.project-mode-isolated { background: var(--surface); color: var(--muted); border: 1px solid var(--border); }
|
|
1288
1288
|
.project-mode-live { background: rgba(210,153,34,0.15); color: var(--yellow); border: 1px solid var(--yellow); }
|
|
1289
|
+
.project-mode-hybrid { background: rgba(88,166,255,0.15); color: var(--blue); border: 1px solid var(--blue); }
|
|
1289
1290
|
|
|
1290
1291
|
/* QA tab (W-mpeiwz6k0005bf34-d) — targets / runbooks / runs sections.
|
|
1291
1292
|
* Reuses surface/border/text tokens defined in :root so the QA page
|
package/dashboard.js
CHANGED
|
@@ -2719,6 +2719,14 @@ function _buildStatusSlowState() {
|
|
|
2719
2719
|
// pill. resolveCheckoutMode honors the legacy worktreeMode field and
|
|
2720
2720
|
// defaults to 'worktree' when unset (matches engine spawn behavior).
|
|
2721
2721
|
checkoutMode: shared.resolveCheckoutMode(p),
|
|
2722
|
+
// Surface the hybrid live-validation type (when configured) so the
|
|
2723
|
+
// Projects view can render a distinct "Hybrid" pill: coding WIs author
|
|
2724
|
+
// in isolated worktrees while only the named validation type runs
|
|
2725
|
+
// in-place on the live checkout. Only meaningful when checkoutMode is
|
|
2726
|
+
// 'live'; null otherwise (full-live or worktree projects).
|
|
2727
|
+
liveValidationType: (shared.resolveCheckoutMode(p) === 'live' && p.liveValidation && p.liveValidation.type)
|
|
2728
|
+
? p.liveValidation.type
|
|
2729
|
+
: null,
|
|
2722
2730
|
};
|
|
2723
2731
|
}),
|
|
2724
2732
|
autoMode: {
|
|
@@ -4255,12 +4263,25 @@ function _resetPreambleCache() {
|
|
|
4255
4263
|
_preambleCacheTs = 0;
|
|
4256
4264
|
}
|
|
4257
4265
|
|
|
4266
|
+
// Compact one-word-ish label for a project's effective dispatch checkout mode,
|
|
4267
|
+
// for CC state surfaces (preamble + refresh). 'worktree' | 'live' |
|
|
4268
|
+
// 'hybrid (live-validation: <type>)' so CC can see at a glance whether a project
|
|
4269
|
+
// authors in isolated worktrees, runs in-place on the operator tree, or splits
|
|
4270
|
+
// the two (coding → worktree, validation type → live). See resolveCheckoutMode.
|
|
4271
|
+
function _projectCheckoutModeLabel(p) {
|
|
4272
|
+
const mode = shared.resolveCheckoutMode(p);
|
|
4273
|
+
if (mode === 'live' && p && p.liveValidation && p.liveValidation.type) {
|
|
4274
|
+
return `hybrid (live-validation: ${p.liveValidation.type})`;
|
|
4275
|
+
}
|
|
4276
|
+
return mode;
|
|
4277
|
+
}
|
|
4278
|
+
|
|
4258
4279
|
function buildCCStatePreamble() {
|
|
4259
4280
|
const now = Date.now();
|
|
4260
4281
|
if (_preambleCache && now - _preambleCacheTs < PREAMBLE_TTL) return _preambleCache;
|
|
4261
4282
|
// Lightweight snapshot — just enough to orient. Use tools for details.
|
|
4262
4283
|
const agents = getAgents().map(a => `- ${a.name} (${a.id}): ${a.status}${a.currentTask ? ' — ' + a.currentTask.slice(0, 60) : ''}`).join('\n');
|
|
4263
|
-
const projects = PROJECTS.map(p => `- ${p.name}: ${p.localPath}`).join('\n');
|
|
4284
|
+
const projects = PROJECTS.map(p => `- ${p.name}: ${p.localPath} [${_projectCheckoutModeLabel(p)}]`).join('\n');
|
|
4264
4285
|
|
|
4265
4286
|
const dq = getDispatchQueue();
|
|
4266
4287
|
const active = (dq.active || []).map(d => `- ${d.agentName || d.agent}: ${(d.task || '').slice(0, 50)}`).join('\n') || '(none)';
|
|
@@ -4332,7 +4353,7 @@ function buildCCStateRefresh() {
|
|
|
4332
4353
|
// Agent roster carries the current task too — without it a resumed session
|
|
4333
4354
|
// sees only that an agent is "busy", never *what* it is busy with.
|
|
4334
4355
|
const agents = getAgents().map(a => `- ${a.name}: ${a.status}${a.currentTask ? ' — ' + a.currentTask.slice(0, 50) : ''}`).join('\n');
|
|
4335
|
-
const projects = PROJECTS.map(p => `- ${p.name} (${p.repo || p.localPath})`).join('\n');
|
|
4356
|
+
const projects = PROJECTS.map(p => `- ${p.name} (${p.repo || p.localPath}) [${_projectCheckoutModeLabel(p)}]`).join('\n');
|
|
4336
4357
|
|
|
4337
4358
|
// MCP servers — just names + source for orientation
|
|
4338
4359
|
let mcpLine = '(none discovered)';
|
|
@@ -11329,6 +11350,31 @@ What would you like to discuss or change? When you're happy, say "approve" and I
|
|
|
11329
11350
|
}
|
|
11330
11351
|
// Drop the legacy field so a migrated project never carries both.
|
|
11331
11352
|
delete proj.worktreeMode;
|
|
11353
|
+
// Defensive cleanup: liveValidation is only honored under
|
|
11354
|
+
// checkoutMode:'live'. If this update moves the project OFF live,
|
|
11355
|
+
// drop any stale hybrid block so resolveCheckoutMode doesn't have to
|
|
11356
|
+
// warn-and-ignore an orphaned liveValidation on every resolve.
|
|
11357
|
+
if (shared.resolveCheckoutMode(proj) !== 'live') {
|
|
11358
|
+
delete proj.liveValidation;
|
|
11359
|
+
}
|
|
11360
|
+
}
|
|
11361
|
+
// Hybrid live-validation block (per-project). Only meaningful when the
|
|
11362
|
+
// resolved checkout mode is 'live' — runs AFTER the checkoutMode block
|
|
11363
|
+
// above so resolveCheckoutMode(proj) reflects the intended final mode.
|
|
11364
|
+
// Empty string / null clears the override; any other value flows
|
|
11365
|
+
// through shared.validateLiveValidation which throws HTTP 400 on
|
|
11366
|
+
// malformed input or when checkoutMode !== 'live'. Absent key leaves
|
|
11367
|
+
// any existing block untouched (so a Settings save that omits the
|
|
11368
|
+
// field never silently drops a configured hybrid project).
|
|
11369
|
+
if (Object.prototype.hasOwnProperty.call(update, 'liveValidation')) {
|
|
11370
|
+
const rawLv = update.liveValidation;
|
|
11371
|
+
if (rawLv === '' || rawLv === null || rawLv === undefined) {
|
|
11372
|
+
delete proj.liveValidation;
|
|
11373
|
+
} else {
|
|
11374
|
+
const validatedLv = shared.validateLiveValidation(rawLv, { checkoutMode: shared.resolveCheckoutMode(proj) });
|
|
11375
|
+
if (validatedLv === undefined) delete proj.liveValidation;
|
|
11376
|
+
else proj.liveValidation = validatedLv;
|
|
11377
|
+
}
|
|
11332
11378
|
}
|
|
11333
11379
|
}
|
|
11334
11380
|
}
|
|
@@ -14293,7 +14339,7 @@ What would you like to discuss or change? When you're happy, say "approve" and I
|
|
|
14293
14339
|
|
|
14294
14340
|
// Settings
|
|
14295
14341
|
{ method: 'GET', path: '/api/settings', desc: 'Return current engine + claude + routing config', handler: handleSettingsRead },
|
|
14296
|
-
{ method: 'POST', path: '/api/settings', desc: 'Update engine + claude + agent + projects config', params: 'engine?, claude?, agents?, projects?', handler: handleSettingsUpdate },
|
|
14342
|
+
{ method: 'POST', path: '/api/settings', desc: 'Update engine + claude + agent + projects config', params: 'engine?, claude?, agents?, projects? (per-project: checkoutMode, liveValidation, mainBranch, workSources)', handler: handleSettingsUpdate },
|
|
14297
14343
|
{ method: 'POST', path: '/api/settings/routing', desc: 'Update routing.md', params: 'content', handler: handleSettingsRouting },
|
|
14298
14344
|
{ method: 'POST', path: '/api/settings/reset', desc: 'Reset engine + claude + agent settings to defaults', handler: handleSettingsReset },
|
|
14299
14345
|
|
|
@@ -14504,6 +14550,7 @@ module.exports = {
|
|
|
14504
14550
|
_resolveScheduleProjectValue: resolveScheduleProjectValue,
|
|
14505
14551
|
_collectArchivedWorkItems: collectArchivedWorkItems,
|
|
14506
14552
|
buildCCStatePreamble,
|
|
14553
|
+
_projectCheckoutModeLabel,
|
|
14507
14554
|
buildCCStateRefresh,
|
|
14508
14555
|
_resetRefreshCache,
|
|
14509
14556
|
_routesAsMeta,
|
package/engine/shared.js
CHANGED
|
@@ -2757,6 +2757,47 @@ function validateCheckoutMode(value) {
|
|
|
2757
2757
|
return value;
|
|
2758
2758
|
}
|
|
2759
2759
|
|
|
2760
|
+
// Validate + normalize a per-project `liveValidation` block (hybrid mode).
|
|
2761
|
+
// Hybrid = checkoutMode:'live' + liveValidation:{ type, autoDispatch }: coding
|
|
2762
|
+
// work items author in isolated worktrees (escaping the live cap) while only
|
|
2763
|
+
// work items whose type === liveValidation.type run in-place on the live
|
|
2764
|
+
// checkout. See resolveCheckoutMode (which routes per work-item type) and
|
|
2765
|
+
// docs/live-checkout-mode.md.
|
|
2766
|
+
//
|
|
2767
|
+
// Returns:
|
|
2768
|
+
// - undefined → caller should clear the field (empty / null / '' input)
|
|
2769
|
+
// - { type, autoDispatch? } normalized object on success
|
|
2770
|
+
// Throws HTTP 400 (via _httpError) on malformed input, or when the effective
|
|
2771
|
+
// checkout mode is not 'live' (liveValidation is meaningless without it — it is
|
|
2772
|
+
// silently ignored at resolve time, so we refuse to persist a misconfiguration).
|
|
2773
|
+
//
|
|
2774
|
+
// `opts.checkoutMode` is the project's effective (resolved) checkout mode; pass
|
|
2775
|
+
// shared.resolveCheckoutMode(project) AFTER any checkoutMode update has been
|
|
2776
|
+
// applied so the gate sees the intended final mode.
|
|
2777
|
+
function validateLiveValidation(value, opts) {
|
|
2778
|
+
if (value === undefined || value === null || value === '') return undefined;
|
|
2779
|
+
if (typeof value !== 'object' || Array.isArray(value)) {
|
|
2780
|
+
throw _httpError(400, 'Invalid liveValidation: must be an object { type, autoDispatch }.');
|
|
2781
|
+
}
|
|
2782
|
+
const checkoutMode = opts && opts.checkoutMode;
|
|
2783
|
+
if (checkoutMode !== CHECKOUT_MODES.LIVE) {
|
|
2784
|
+
throw _httpError(400, 'liveValidation requires checkoutMode "live" (hybrid mode). Set checkoutMode to "live" first, or clear liveValidation.');
|
|
2785
|
+
}
|
|
2786
|
+
const type = typeof value.type === 'string' ? value.type.trim() : '';
|
|
2787
|
+
if (!type) {
|
|
2788
|
+
throw _httpError(400, 'Invalid liveValidation: "type" is required and must be a non-empty string — the work-item type that runs on the live checkout (e.g. "build-and-test").');
|
|
2789
|
+
}
|
|
2790
|
+
const out = { type };
|
|
2791
|
+
// autoDispatch (optional): when true, lifecycle auto-creates a validation WI
|
|
2792
|
+
// of `type` after each coding WI completes with a PR (engine/lifecycle.js
|
|
2793
|
+
// autoDispatchLiveValidationWi). Coerce to a strict boolean; absent leaves it
|
|
2794
|
+
// off so the operator opts in explicitly.
|
|
2795
|
+
if (Object.prototype.hasOwnProperty.call(value, 'autoDispatch')) {
|
|
2796
|
+
out.autoDispatch = !!value.autoDispatch;
|
|
2797
|
+
}
|
|
2798
|
+
return out;
|
|
2799
|
+
}
|
|
2800
|
+
|
|
2760
2801
|
// ── Engine Defaults ─────────────────────────────────────────────────────────
|
|
2761
2802
|
// Single source of truth for engine configuration defaults.
|
|
2762
2803
|
// Used by: engine.js, minions.js (init). config.template.json only has the project schema.
|
|
@@ -9192,6 +9233,7 @@ module.exports = {
|
|
|
9192
9233
|
validateProjectPath,
|
|
9193
9234
|
CHECKOUT_MODES,
|
|
9194
9235
|
validateCheckoutMode,
|
|
9236
|
+
validateLiveValidation,
|
|
9195
9237
|
resolveCheckoutMode,
|
|
9196
9238
|
isLiveCheckoutProject,
|
|
9197
9239
|
resolveLiveCheckoutAutoReset,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@yemi33/minions",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.2302",
|
|
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"
|
package/prompts/cc-system.md
CHANGED
|
@@ -319,6 +319,27 @@ The `X-CC-Turn-Id` header is the audit trail — the handler stamps it onto the
|
|
|
319
319
|
|
|
320
320
|
**Errors:** if a `curl` returns 4xx/5xx, surface the error text in your reply so the user sees what went wrong. Don't retry blindly — usually the body explains the missing field.
|
|
321
321
|
|
|
322
|
+
## Project checkout modes (worktree / live / hybrid)
|
|
323
|
+
|
|
324
|
+
Every configured project has an effective **checkout mode** — surfaced in your state snapshot next to the project as `[worktree]`, `[live]`, or `[hybrid (live-validation: <type>)]`. It controls where dispatched agents run:
|
|
325
|
+
|
|
326
|
+
- **`worktree`** (default) — each dispatch gets its own isolated `git worktree`. Agents run fully in parallel; nothing touches the operator's working tree. Use for normal repos.
|
|
327
|
+
- **`live`** — agents run **in-place** inside the project's `localPath` (no worktree). The engine caps this to **one mutating dispatch at a time** per project and **refuses on a dirty tree**. Use only when worktrees are unworkable (e.g. Android `repo`, submodules, deep Windows paths, emulators that bind the real checkout).
|
|
328
|
+
- **`hybrid`** — `live` **plus** a `liveValidation: { type, autoDispatch }` block. Coding work items (`implement`/`fix`/`docs`/`decompose`) author in **isolated worktrees** (full parallelism), while **only** work items whose type matches `liveValidation.type` (e.g. `build-and-test`) run **in-place on the live checkout**. This is the best of both: parallel code authoring + a real on-disk build/validation that can't run in a worktree.
|
|
329
|
+
|
|
330
|
+
**When to recommend hybrid:** the project's build/test/validation genuinely cannot run in an isolated worktree (it needs the real checkout — submodules, a `repo`-managed tree, an emulator/dev-server bound to `localPath`, deep-path tooling), **but** you still want coding agents to work in parallel rather than serialize through the single live checkout. If the *whole* workflow must run on the real tree, use plain `live`. If nothing needs the real tree, stay on `worktree`.
|
|
331
|
+
|
|
332
|
+
**Configuring it** (via the projects array on `POST /api/settings` — never hand-edit `config.json`):
|
|
333
|
+
```bash
|
|
334
|
+
# Switch a project to hybrid mode (live checkout + deferred build-and-test validation)
|
|
335
|
+
curl -s -X POST http://localhost:{{dashboard_port}}/api/settings \
|
|
336
|
+
-H 'Content-Type: application/json' -H 'X-CC-Turn-Id: {{cc_turn_id}}' \
|
|
337
|
+
-d '{"projects":[{"name":"<project>","checkoutMode":"live","liveValidation":{"type":"build-and-test","autoDispatch":true}}]}'
|
|
338
|
+
# Clear hybrid (back to plain live): pass "liveValidation": null
|
|
339
|
+
# Clear live entirely (back to worktree): pass "checkoutMode": "worktree" (also clear liveValidation)
|
|
340
|
+
```
|
|
341
|
+
The server validates: `liveValidation` requires `checkoutMode:"live"` (400 otherwise) and a non-empty `type`. With `autoDispatch:true`, the engine auto-creates a `<type>` validation WI on the live checkout after each coding WI completes with a PR. **Always confirm the mode switch with the user before applying it** — it changes how every future dispatch on that project runs.
|
|
342
|
+
|
|
322
343
|
## GitHub auth
|
|
323
344
|
|
|
324
345
|
We have multiple authed `gh` accounts (`yemi33`, `yemishin_microsoft`) covering three repo scopes (`yemi33/minions`, `yemishin_microsoft/minions`, `opg-microsoft/minions`).
|