@yemi33/minions 0.1.2104 → 0.1.2105
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 +10 -12
- package/engine/shared.js +66 -0
- package/engine.js +7 -2
- package/package.json +1 -1
- package/playbooks/fix.md +4 -0
- package/playbooks/shared-rules.md +11 -0
package/dashboard.js
CHANGED
|
@@ -3329,8 +3329,12 @@ function normalizeMeetingParticipants(participants) {
|
|
|
3329
3329
|
|
|
3330
3330
|
|
|
3331
3331
|
function getWorkItemPrRef(input) {
|
|
3332
|
-
|
|
3333
|
-
|
|
3332
|
+
// Delegates to shared.extractWorkItemPrRef so the dashboard's WI-create
|
|
3333
|
+
// path detects PR pointers in references[*].url / meta.pr_followup /
|
|
3334
|
+
// description text — not just the canonical structured fields — and routes
|
|
3335
|
+
// the dispatch to the existing PR branch instead of a fresh `work/<wi-id>`
|
|
3336
|
+
// parallel branch (issue #2999 / W-mpx6i5kh000ac040).
|
|
3337
|
+
return shared.extractWorkItemPrRef(input);
|
|
3334
3338
|
}
|
|
3335
3339
|
|
|
3336
3340
|
function isPrTargetedWorkType(workType) {
|
|
@@ -3341,17 +3345,11 @@ function trimTrailingPrRefPunctuation(value) {
|
|
|
3341
3345
|
return String(value || '').replace(/[),.;:]+$/g, '');
|
|
3342
3346
|
}
|
|
3343
3347
|
|
|
3348
|
+
// Thin wrapper over shared.extractPrRefFromText so callers in dashboard.js
|
|
3349
|
+
// keep their existing import shape while the canonical regex + extraction
|
|
3350
|
+
// logic lives in engine/shared.js (issue #2999 / W-mpx6i5kh000ac040).
|
|
3344
3351
|
function extractPrRefFromText(value) {
|
|
3345
|
-
|
|
3346
|
-
if (!text.trim()) return null;
|
|
3347
|
-
const urlMatch = text.match(/https?:\/\/[^\s<>()]+(?:\/pull\/\d+|\/pullrequest\/\d+)[^\s<>()]*/i);
|
|
3348
|
-
if (urlMatch) return trimTrailingPrRefPunctuation(urlMatch[0]);
|
|
3349
|
-
const canonicalMatch = text.match(/\b(?:github|ado):[^\s#]+#\d+\b/i);
|
|
3350
|
-
if (canonicalMatch) return canonicalMatch[0];
|
|
3351
|
-
const legacyMatch = text.match(/\bPR-(\d+)\b/i);
|
|
3352
|
-
if (legacyMatch) return legacyMatch[1];
|
|
3353
|
-
const numberMatch = text.match(/\b(?:pr|pull\s+request|pullrequest)\s*#?\s*(\d+)\b/i);
|
|
3354
|
-
return numberMatch ? numberMatch[1] : null;
|
|
3352
|
+
return shared.extractPrRefFromText(value);
|
|
3355
3353
|
}
|
|
3356
3354
|
|
|
3357
3355
|
|
package/engine/shared.js
CHANGED
|
@@ -4300,6 +4300,70 @@ function parsePrUrl(url) {
|
|
|
4300
4300
|
return parseGitHubPrUrl(url) || parseAdoPrUrl(url);
|
|
4301
4301
|
}
|
|
4302
4302
|
|
|
4303
|
+
// ─── PR reference extraction from work-item bodies (W-mpx6i5kh000ac040) ─────
|
|
4304
|
+
//
|
|
4305
|
+
// `extractPrRefFromText` scans free-form text (description, comment bodies,
|
|
4306
|
+
// release notes) for the first PR reference it can recognise: a GitHub or ADO
|
|
4307
|
+
// PR URL, a canonical `github:owner/repo#N` / `ado:org/proj/repo#N` id, or a
|
|
4308
|
+
// legacy `PR-<n>` token. Returns null when nothing parseable is found.
|
|
4309
|
+
//
|
|
4310
|
+
// `extractWorkItemPrRef` is the engine + dashboard's single source of truth
|
|
4311
|
+
// for "does this work-item target an existing PR?". It checks the canonical
|
|
4312
|
+
// structured fields first (current behaviour preserved), then falls back to
|
|
4313
|
+
// `references[*].url`, `meta.pr_followup.parent_pr_url`, and finally a text
|
|
4314
|
+
// scan of the title/description. Returning a truthy ref keeps `linkedPr` /
|
|
4315
|
+
// `isPrTargeted` paths intact and prevents PR-feedback fix WIs from being
|
|
4316
|
+
// dispatched on a fresh `work/<wi-id>` branch when only the description /
|
|
4317
|
+
// references[] carried the PR pointer (issue #2999).
|
|
4318
|
+
function _trimTrailingPrRefPunctuation(value) {
|
|
4319
|
+
return String(value || '').replace(/[),.;:]+$/g, '');
|
|
4320
|
+
}
|
|
4321
|
+
|
|
4322
|
+
function extractPrRefFromText(value) {
|
|
4323
|
+
const text = String(value || '');
|
|
4324
|
+
if (!text.trim()) return null;
|
|
4325
|
+
const urlMatch = text.match(/https?:\/\/[^\s<>()]+(?:\/pull\/\d+|\/pullrequest\/\d+)[^\s<>()]*/i);
|
|
4326
|
+
if (urlMatch) return _trimTrailingPrRefPunctuation(urlMatch[0]);
|
|
4327
|
+
const canonicalMatch = text.match(/\b(?:github|ado):[^\s#]+#\d+\b/i);
|
|
4328
|
+
if (canonicalMatch) return canonicalMatch[0];
|
|
4329
|
+
const legacyMatch = text.match(/\bPR-(\d+)\b/i);
|
|
4330
|
+
if (legacyMatch) return legacyMatch[1];
|
|
4331
|
+
const numberMatch = text.match(/\b(?:pr|pull\s+request|pullrequest)\s*#?\s*(\d+)\b/i);
|
|
4332
|
+
return numberMatch ? numberMatch[1] : null;
|
|
4333
|
+
}
|
|
4334
|
+
|
|
4335
|
+
function extractWorkItemPrRef(item) {
|
|
4336
|
+
if (!item || typeof item !== 'object') return null;
|
|
4337
|
+
const structured = item.targetPr
|
|
4338
|
+
|| item.pr
|
|
4339
|
+
|| item.pr_id
|
|
4340
|
+
|| item.prId
|
|
4341
|
+
|| item.sourcePr
|
|
4342
|
+
|| item.pullRequest
|
|
4343
|
+
|| item.prUrl
|
|
4344
|
+
|| item.prNumber;
|
|
4345
|
+
if (structured) return structured;
|
|
4346
|
+
// references[*].url — manual /api/work-items callers often supply the PR
|
|
4347
|
+
// pointer here when no structured prId/targetPr is known up front.
|
|
4348
|
+
if (Array.isArray(item.references)) {
|
|
4349
|
+
for (const ref of item.references) {
|
|
4350
|
+
const url = ref && typeof ref === 'object' ? ref.url : null;
|
|
4351
|
+
const fromUrl = extractPrRefFromText(url);
|
|
4352
|
+
if (fromUrl) return fromUrl;
|
|
4353
|
+
}
|
|
4354
|
+
}
|
|
4355
|
+
// meta.pr_followup.parent_pr_url — set by playbooks/templates/followup-dispatch.md.
|
|
4356
|
+
const followupUrl = item?.meta?.pr_followup?.parent_pr_url;
|
|
4357
|
+
if (followupUrl) {
|
|
4358
|
+
const fromFollowup = extractPrRefFromText(followupUrl);
|
|
4359
|
+
if (fromFollowup) return fromFollowup;
|
|
4360
|
+
}
|
|
4361
|
+
// Last resort: scan description + title for a PR URL / canonical id.
|
|
4362
|
+
const fromDescription = extractPrRefFromText(item.description);
|
|
4363
|
+
if (fromDescription) return fromDescription;
|
|
4364
|
+
return extractPrRefFromText(item.title) || null;
|
|
4365
|
+
}
|
|
4366
|
+
|
|
4303
4367
|
function getProjectPrScope(project) {
|
|
4304
4368
|
if (!project) return '';
|
|
4305
4369
|
const host = String(project.repoHost || '').toLowerCase();
|
|
@@ -5632,6 +5696,8 @@ module.exports = {
|
|
|
5632
5696
|
parseGitHubPrUrl, // exported for testing
|
|
5633
5697
|
parseAdoPrUrl, // exported for testing
|
|
5634
5698
|
parsePrUrl, // exported for testing
|
|
5699
|
+
extractPrRefFromText,
|
|
5700
|
+
extractWorkItemPrRef,
|
|
5635
5701
|
getProjectPrScope,
|
|
5636
5702
|
getPrNumber,
|
|
5637
5703
|
getPrDisplayId,
|
package/engine.js
CHANGED
|
@@ -5583,8 +5583,13 @@ function renderProjectWorkItemPromptForAgent(item, workType, agentId, config, pr
|
|
|
5583
5583
|
}
|
|
5584
5584
|
|
|
5585
5585
|
function getWorkItemPrRef(item) {
|
|
5586
|
-
|
|
5587
|
-
|
|
5586
|
+
// Delegates to shared.extractWorkItemPrRef so engine + dashboard agree on
|
|
5587
|
+
// which work-item fields count as PR pointers — covers structured fields,
|
|
5588
|
+
// references[*].url, meta.pr_followup.parent_pr_url, and description text
|
|
5589
|
+
// (issue #2999 / W-mpx6i5kh000ac040). Defence in depth: even if a manual
|
|
5590
|
+
// /api/work-items create slipped through without structured PR fields, the
|
|
5591
|
+
// engine still detects the PR pointer here at dispatch time.
|
|
5592
|
+
return shared.extractWorkItemPrRef(item);
|
|
5588
5593
|
}
|
|
5589
5594
|
|
|
5590
5595
|
function resolveWorkItemPrRecord(item, project) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@yemi33/minions",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.2105",
|
|
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/playbooks/fix.md
CHANGED
|
@@ -46,6 +46,10 @@ Before editing, split the feedback into:
|
|
|
46
46
|
|
|
47
47
|
Before starting work, run `git status` and verify the worktree is clean and on the expected branch (`{{pr_branch}}`). If the worktree is dirty or on the wrong branch, report the issue and stop.
|
|
48
48
|
|
|
49
|
+
### Branch-mismatch guard (issue #2999)
|
|
50
|
+
|
|
51
|
+
If your task description, `references[]`, or the PR thread clearly identifies an existing PR but your checkout branch does **not** match the PR's source branch — for example you are on `work/W-…` while the task references PR `!5284819` (source branch `yemishin/task-hub-symphony-gate`) — **stop immediately**. Do not branch off master, do not replay the PR's commits onto a fresh branch, and do not open a duplicate PR. Emit a non-retryable completion (`failure_class: "branch-mismatch"`, `retryable: false`) with the referenced PR id and the actual branch you found, so the engine and the operator can re-dispatch on the correct branch. The canonical bad incident is in issue #2999 — manual fix WI `W-mpwxgd4v00078c06` opened duplicate ADO PR `!5288540` instead of patching `!5284819`.
|
|
52
|
+
|
|
49
53
|
## Working Style
|
|
50
54
|
|
|
51
55
|
Use subagents only for genuinely parallel, independent tasks. For sequential work, single-file edits, searches, and file reads, work directly — do not spawn subagents.
|
|
@@ -64,6 +64,17 @@ Application:
|
|
|
64
64
|
- When you create a work item programmatically (API, plan-to-prd, scripts), set the WI's `branch` (or PRD `feature_branch`) to the conventional name so the engine creates the worktree on the right branch from the start. `dashboard.js` derives this automatically when callers omit `branch`.
|
|
65
65
|
- The legacy `feat/<id>-<slug>` and bare `work/<id>` formats are deprecated; the engine no longer falls back to them.
|
|
66
66
|
|
|
67
|
+
### PR-fix exception (DO NOT branch off master)
|
|
68
|
+
|
|
69
|
+
For a `type: "fix"` work item that targets an existing PR, the engine reuses the PR's **source branch** (e.g. `yemishin/task-hub-symphony-gate`) instead of derivingthe `user/<loginname>/<wi-id>-<slug>` form. PR pointers are detected from any of:
|
|
70
|
+
|
|
71
|
+
- Structured fields: `targetPr`, `pr_id`, `prUrl`, `prNumber`, `pullRequest`, `sourcePr`
|
|
72
|
+
- `references[*].url` (manual `/api/work-items` callers usually pass the PR pointer here)
|
|
73
|
+
- `meta.pr_followup.parent_pr_url` (follow-up dispatch template)
|
|
74
|
+
- A PR URL or canonical `github:owner/repo#N` / `ado:org/proj/repo#N` id in the `description` text
|
|
75
|
+
|
|
76
|
+
If you are running a fix task and `{{pr_branch}}` is populated, your worktree is already on that branch — push the fix commit there and do **not** create a new PR. If `{{pr_branch}}` is empty but the task description / references clearly point at an existing PR, **stop** and emit a non-retryable completion (`failure_class: 'branch-mismatch'`) instead of branching off master and opening a duplicate PR. See issue #2999 for the canonical bad incident (ADO PR `!5284819` → duplicate `!5288540`).
|
|
77
|
+
|
|
67
78
|
## Engine Rules (apply to all tasks)
|
|
68
79
|
|
|
69
80
|
**Context compaction:** Your context window may be compacted mid-task by Claude's infrastructure. If you notice your earlier conversation history appears truncated or summarized, this is normal and expected. Do not interpret compaction as a signal to stop early or wrap up. Continue working toward your task objective — all relevant instructions and state remain available.
|