@yemi33/minions 0.1.397 → 0.1.399
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 +6 -0
- package/dashboard/js/render-dispatch.js +7 -2
- package/engine/cli.js +1 -1
- package/engine/lifecycle.js +2 -2
- package/engine/playbook.js +2 -2
- package/engine/shared.js +46 -0
- package/engine.js +2 -2
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -37,7 +37,7 @@ function renderEngineStatus(engine) {
|
|
|
37
37
|
function renderEngineAlert(state, staleMs) {
|
|
38
38
|
const el = document.getElementById('engine-alert');
|
|
39
39
|
if (!el) return;
|
|
40
|
-
if (state !== 'stale') {
|
|
40
|
+
if (state !== 'stale' || (window._engineRestartedAt && Date.now() - window._engineRestartedAt < 30000)) {
|
|
41
41
|
el.style.display = 'none';
|
|
42
42
|
el.innerHTML = '';
|
|
43
43
|
return;
|
|
@@ -53,7 +53,12 @@ function renderEngineAlert(state, staleMs) {
|
|
|
53
53
|
const res = await fetch('/api/engine/restart', { method: 'POST' });
|
|
54
54
|
const data = await res.json();
|
|
55
55
|
if (data.ok) {
|
|
56
|
-
this.textContent = 'Restarted (PID ' + data.pid + ')';
|
|
56
|
+
this.textContent = '\u2713 Restarted (PID ' + data.pid + ')';
|
|
57
|
+
this.style.color = 'var(--green)';
|
|
58
|
+
this.style.borderColor = 'var(--green)';
|
|
59
|
+
showToast('cmd-toast', 'Engine restarted — PID ' + data.pid, true);
|
|
60
|
+
// Suppress stale banner for 30s while new engine writes its first heartbeat
|
|
61
|
+
window._engineRestartedAt = Date.now();
|
|
57
62
|
setTimeout(() => refresh(), 3000);
|
|
58
63
|
} else {
|
|
59
64
|
this.textContent = 'Failed: ' + (data.error || 'unknown');
|
package/engine/cli.js
CHANGED
|
@@ -735,7 +735,7 @@ const commands = {
|
|
|
735
735
|
agent_role: config.agents[agentId]?.role,
|
|
736
736
|
project_name: targetProject.name || 'Unknown',
|
|
737
737
|
project_path: targetProject.localPath || '',
|
|
738
|
-
main_branch: targetProject.mainBranch || 'main',
|
|
738
|
+
main_branch: targetProject.localPath ? shared.resolveMainBranch(targetProject.localPath, targetProject.mainBranch) : (targetProject.mainBranch || 'main'),
|
|
739
739
|
ado_org: targetProject.adoOrg || 'Unknown',
|
|
740
740
|
ado_project: targetProject.adoProject || 'Unknown',
|
|
741
741
|
repo_name: targetProject.repoName || 'Unknown',
|
package/engine/lifecycle.js
CHANGED
|
@@ -166,7 +166,7 @@ function checkPlanCompletion(meta, config) {
|
|
|
166
166
|
if (!existingPrItem) {
|
|
167
167
|
const id = 'PL-' + shared.uid();
|
|
168
168
|
const featureBranch = plan.feature_branch;
|
|
169
|
-
const mainBranch = primaryProject.mainBranch
|
|
169
|
+
const mainBranch = shared.resolveMainBranch(primaryProject.localPath, primaryProject.mainBranch);
|
|
170
170
|
const itemSummary = doneItems.map(w => '- ' + w.id + ': ' + w.title.replace('Implement: ', '')).join('\n');
|
|
171
171
|
workItems.push({
|
|
172
172
|
id, title: `Create PR for plan: ${plan.plan_summary || planFile}`,
|
|
@@ -196,7 +196,7 @@ function checkPlanCompletion(meta, config) {
|
|
|
196
196
|
return pr.status === PR_STATUS.ACTIVE && linkedId && doneItems.find(w => w.id === linkedId);
|
|
197
197
|
});
|
|
198
198
|
if (prs.length > 0) {
|
|
199
|
-
projectPrs[p.name] = { project: p, prs, mainBranch: p.mainBranch
|
|
199
|
+
projectPrs[p.name] = { project: p, prs, mainBranch: shared.resolveMainBranch(p.localPath, p.mainBranch) };
|
|
200
200
|
}
|
|
201
201
|
}
|
|
202
202
|
|
package/engine/playbook.js
CHANGED
|
@@ -30,7 +30,7 @@ function getPrCreateInstructions(project) {
|
|
|
30
30
|
if (host === 'github') {
|
|
31
31
|
const org = project?.adoOrg || '';
|
|
32
32
|
const repo = project?.repoName || '';
|
|
33
|
-
const mainBranch = project?.mainBranch || 'main';
|
|
33
|
+
const mainBranch = project?.localPath ? shared.resolveMainBranch(project.localPath, project.mainBranch) : (project?.mainBranch || 'main');
|
|
34
34
|
return `Use \`gh pr create\` to create a pull request:\n` +
|
|
35
35
|
`- \`gh pr create --base ${mainBranch} --head <your-branch> --title "PR title" --body "PR description" --repo ${org}/${repo}\`\n` +
|
|
36
36
|
`- Always set --base to \`${mainBranch}\` (the main branch)\n` +
|
|
@@ -62,7 +62,7 @@ function getPrFetchInstructions(project) {
|
|
|
62
62
|
if (host === 'github') {
|
|
63
63
|
const org = project?.adoOrg || '';
|
|
64
64
|
const repo = project?.repoName || '';
|
|
65
|
-
const mainBranch = project?.mainBranch || 'main';
|
|
65
|
+
const mainBranch = project?.localPath ? shared.resolveMainBranch(project.localPath, project.mainBranch) : (project?.mainBranch || 'main');
|
|
66
66
|
return `Use \`gh pr view\` to fetch PR status:\n` +
|
|
67
67
|
`- \`gh pr view <number> --json number,title,state,mergeable,reviewDecision,headRefName,baseRefName,statusCheckRollup --repo ${org}/${repo}\`\n` +
|
|
68
68
|
`- This returns JSON with PR state, mergeability, review decision, and check statuses\n` +
|
package/engine/shared.js
CHANGED
|
@@ -267,6 +267,51 @@ function execSilent(cmd, opts = {}) {
|
|
|
267
267
|
return _execSync(cmd, { stdio: 'pipe', windowsHide: true, ...opts });
|
|
268
268
|
}
|
|
269
269
|
|
|
270
|
+
/**
|
|
271
|
+
* Detect the default branch for a git repo. Tries in order:
|
|
272
|
+
* 1. The configured mainBranch (if it exists as a local or remote ref)
|
|
273
|
+
* 2. git symbolic-ref refs/remotes/origin/HEAD (what the remote says)
|
|
274
|
+
* 3. Fallback to 'main'
|
|
275
|
+
* Cached per rootDir to avoid repeated git calls within a tick.
|
|
276
|
+
*/
|
|
277
|
+
const _mainBranchCache = new Map();
|
|
278
|
+
function resolveMainBranch(rootDir, configuredBranch) {
|
|
279
|
+
const cacheKey = rootDir + ':' + (configuredBranch || '');
|
|
280
|
+
const cached = _mainBranchCache.get(cacheKey);
|
|
281
|
+
if (cached && (Date.now() - cached.ts) < 300000) return cached.branch; // 5min TTL
|
|
282
|
+
|
|
283
|
+
const gitOpts = { cwd: rootDir, encoding: 'utf8', stdio: 'pipe', timeout: 5000, windowsHide: true };
|
|
284
|
+
|
|
285
|
+
// 1. If configured branch exists, use it
|
|
286
|
+
if (configuredBranch) {
|
|
287
|
+
try {
|
|
288
|
+
_execSync(`git rev-parse --verify "${configuredBranch}"`, gitOpts);
|
|
289
|
+
_mainBranchCache.set(cacheKey, { branch: configuredBranch, ts: Date.now() });
|
|
290
|
+
return configuredBranch;
|
|
291
|
+
} catch { /* configured branch doesn't exist locally */ }
|
|
292
|
+
try {
|
|
293
|
+
_execSync(`git rev-parse --verify "origin/${configuredBranch}"`, gitOpts);
|
|
294
|
+
_mainBranchCache.set(cacheKey, { branch: configuredBranch, ts: Date.now() });
|
|
295
|
+
return configuredBranch;
|
|
296
|
+
} catch { /* not on remote either */ }
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
// 2. Auto-detect from remote HEAD
|
|
300
|
+
try {
|
|
301
|
+
const ref = _execSync('git symbolic-ref refs/remotes/origin/HEAD', gitOpts).trim();
|
|
302
|
+
const branch = ref.replace('refs/remotes/origin/', '');
|
|
303
|
+
if (branch) {
|
|
304
|
+
_mainBranchCache.set(cacheKey, { branch, ts: Date.now() });
|
|
305
|
+
return branch;
|
|
306
|
+
}
|
|
307
|
+
} catch { /* no remote HEAD set */ }
|
|
308
|
+
|
|
309
|
+
// 3. Fallback
|
|
310
|
+
const fallback = configuredBranch || 'main';
|
|
311
|
+
_mainBranchCache.set(cacheKey, { branch: fallback, ts: Date.now() });
|
|
312
|
+
return fallback;
|
|
313
|
+
}
|
|
314
|
+
|
|
270
315
|
// ── Environment ─────────────────────────────────────────────────────────────
|
|
271
316
|
|
|
272
317
|
function cleanChildEnv() {
|
|
@@ -651,6 +696,7 @@ module.exports = {
|
|
|
651
696
|
writeToInbox,
|
|
652
697
|
exec,
|
|
653
698
|
execSilent,
|
|
699
|
+
resolveMainBranch,
|
|
654
700
|
run,
|
|
655
701
|
runFile,
|
|
656
702
|
cleanChildEnv,
|
package/engine.js
CHANGED
|
@@ -323,7 +323,7 @@ function spawnAgent(dispatchItem, config) {
|
|
|
323
323
|
}
|
|
324
324
|
} else {
|
|
325
325
|
log('info', `Creating worktree: ${worktreePath} on branch ${branchName}`);
|
|
326
|
-
const mainRef = sanitizeBranch(project.mainBranch
|
|
326
|
+
const mainRef = sanitizeBranch(shared.resolveMainBranch(rootDir, project.mainBranch));
|
|
327
327
|
try {
|
|
328
328
|
runWorktreeAdd(rootDir, worktreePath, `-b "${branchName}" ${mainRef}`, _worktreeGitOpts, worktreeCreateRetries);
|
|
329
329
|
} catch (e1) {
|
|
@@ -1212,7 +1212,7 @@ function materializePlansAsWorkItems(config) {
|
|
|
1212
1212
|
const firstProject = itemsByProject.values().next().value?.project;
|
|
1213
1213
|
if (!firstProject?.localPath) throw new Error('no project with localPath');
|
|
1214
1214
|
const root = path.resolve(firstProject.localPath);
|
|
1215
|
-
const mainBranch = firstProject.mainBranch
|
|
1215
|
+
const mainBranch = shared.resolveMainBranch(root, firstProject.mainBranch);
|
|
1216
1216
|
const branch = sanitizeBranch(plan.feature_branch);
|
|
1217
1217
|
// Create branch from main (idempotent — ignores if exists)
|
|
1218
1218
|
exec(`git branch "${branch}" "${mainBranch}" 2>/dev/null || true`, { cwd: root, stdio: 'pipe' });
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@yemi33/minions",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.399",
|
|
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"
|