@yemi33/minions 0.1.1638 → 0.1.1639
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 +2 -1
- package/dashboard.js +21 -3
- package/engine/copilot-models.json +1 -1
- package/engine/lifecycle.js +27 -4
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
-
## 0.1.
|
|
3
|
+
## 0.1.1639 (2026-04-30)
|
|
4
4
|
|
|
5
5
|
### Fixes
|
|
6
|
+
- auto-link agent-created PRs to work items (#1904)
|
|
6
7
|
- Playbook 'fix' / 'review' gates items forever when pr_branch is unresolved (closes #1899) (#1901)
|
|
7
8
|
|
|
8
9
|
## 0.1.1637 (2026-04-30)
|
package/dashboard.js
CHANGED
|
@@ -5838,9 +5838,9 @@ What would you like to discuss or change? When you're happy, say "approve" and I
|
|
|
5838
5838
|
// /api/prd/regenerate removed — use /api/plans/approve which does diff-aware update
|
|
5839
5839
|
|
|
5840
5840
|
// Agents
|
|
5841
|
-
{ method: 'POST', path: '/api/pull-requests/link', desc: 'Manually link an external PR for tracking', params: 'url, title?, project?, autoObserve?, context?', handler: async (req, res) => {
|
|
5841
|
+
{ method: 'POST', path: '/api/pull-requests/link', desc: 'Manually link an external PR for tracking', params: 'url, title?, project?, autoObserve?, context?, workItemId?', handler: async (req, res) => {
|
|
5842
5842
|
const body = await readBody(req);
|
|
5843
|
-
const { url, title, project: projectName, autoObserve, context } = body;
|
|
5843
|
+
const { url, title, project: projectName, autoObserve, context, workItemId } = body;
|
|
5844
5844
|
if (!url) return jsonReply(res, 400, { error: 'url required' });
|
|
5845
5845
|
|
|
5846
5846
|
// Determine project
|
|
@@ -5855,6 +5855,14 @@ What would you like to discuss or change? When you're happy, say "approve" and I
|
|
|
5855
5855
|
const prId = shared.getCanonicalPrId(targetProject, prNum, url);
|
|
5856
5856
|
const contextText = typeof context === 'string' ? context : (context == null ? '' : JSON.stringify(context));
|
|
5857
5857
|
|
|
5858
|
+
// Resolve a work-item association from either the top-level workItemId
|
|
5859
|
+
// field (preferred) or context.workItemId (legacy CC payload shape).
|
|
5860
|
+
// Without this, manually-linked PRs end up with prdItems=[] and the
|
|
5861
|
+
// Work Items page renders no PR even though _context records the ID.
|
|
5862
|
+
const linkedItemId = (typeof workItemId === 'string' && workItemId.trim())
|
|
5863
|
+
|| (context && typeof context === 'object' && typeof context.workItemId === 'string' && context.workItemId.trim())
|
|
5864
|
+
|| '';
|
|
5865
|
+
|
|
5858
5866
|
// Atomic check-and-insert to prevent duplicates and races with polling loops
|
|
5859
5867
|
let duplicate = false;
|
|
5860
5868
|
mutateJsonFileLocked(prPath, (prs) => {
|
|
@@ -5871,7 +5879,7 @@ What would you like to discuss or change? When you're happy, say "approve" and I
|
|
|
5871
5879
|
status: 'active',
|
|
5872
5880
|
created: new Date().toISOString(),
|
|
5873
5881
|
url,
|
|
5874
|
-
prdItems: [],
|
|
5882
|
+
prdItems: linkedItemId ? [linkedItemId] : [],
|
|
5875
5883
|
_manual: true,
|
|
5876
5884
|
_contextOnly: !autoObserve,
|
|
5877
5885
|
_autoObserve: !!autoObserve,
|
|
@@ -5880,6 +5888,16 @@ What would you like to discuss or change? When you're happy, say "approve" and I
|
|
|
5880
5888
|
return prs;
|
|
5881
5889
|
}, { defaultValue: [] });
|
|
5882
5890
|
if (duplicate) return jsonReply(res, 400, { error: 'PR already tracked' });
|
|
5891
|
+
// Persist the work-item ↔ PR association in pr-links.json so
|
|
5892
|
+
// queries.getWorkItems() can render item._pr / item._prUrl. addPrLink
|
|
5893
|
+
// is idempotent and handles the central / project-scoped split.
|
|
5894
|
+
if (linkedItemId) {
|
|
5895
|
+
try {
|
|
5896
|
+
shared.addPrLink(prId, linkedItemId, { project: targetProject, prNumber: parseInt(prNum, 10) || null, url });
|
|
5897
|
+
} catch (e) {
|
|
5898
|
+
shared.log('warn', `PR link addPrLink failed for ${prId} → ${linkedItemId}: ${e.message}`);
|
|
5899
|
+
}
|
|
5900
|
+
}
|
|
5883
5901
|
invalidateStatusCache();
|
|
5884
5902
|
jsonReply(res, 200, { ok: true, id: prId });
|
|
5885
5903
|
|
package/engine/lifecycle.js
CHANGED
|
@@ -744,13 +744,33 @@ function syncPrsFromOutput(output, agentId, meta, config) {
|
|
|
744
744
|
}
|
|
745
745
|
} catch {}
|
|
746
746
|
|
|
747
|
+
// prId → URL captured from inbox notes. Populated alongside prMatches so
|
|
748
|
+
// extractPrUrl below has a fallback when the agent's stdout doesn't contain
|
|
749
|
+
// the URL (the W-moljyu60wuzr / #1902 case — gh pr create ran in a sibling
|
|
750
|
+
// dispatch and only the inbox note carries the link).
|
|
751
|
+
const inboxUrls = new Map();
|
|
747
752
|
const today = dateStamp();
|
|
748
753
|
const inboxFiles = getInboxFiles().filter(f => f.includes(agentId) && f.includes(today));
|
|
749
754
|
for (const f of inboxFiles) {
|
|
750
755
|
const content = safeRead(path.join(INBOX_DIR, f));
|
|
751
756
|
if (!content) continue;
|
|
752
|
-
|
|
753
|
-
|
|
757
|
+
// Match a PR declaration line in the agent's findings note: optional bold,
|
|
758
|
+
// optional "Pull Request" spelling, line-anchored so "see PR https://..."
|
|
759
|
+
// mid-paragraph mentions don't trigger a false-positive. The protocol
|
|
760
|
+
// and host prefix is optional so "PR: https://github.com/..." ,
|
|
761
|
+
// "**PR:** github.com/...", etc. all match.
|
|
762
|
+
const prHeaderPattern = /(?:^|\n)\s*\*{0,2}(?:PR|Pull\s+Request)[:\*]*\*?\s*[#-]*\s*(?:https?:\/\/)?[^\s"]*?(?:(?:visualstudio\.com|dev\.azure\.com)[^\s"]*?pullrequest\/(\d+)|github\.com\/[^\s"]*?\/pull\/(\d+))/gi;
|
|
763
|
+
while ((match = prHeaderPattern.exec(content)) !== null) {
|
|
764
|
+
const prId = match[1] || match[2];
|
|
765
|
+
prMatches.add(prId);
|
|
766
|
+
// Pull the URL substring out of the matched chunk so we can hand it to
|
|
767
|
+
// extractPrUrl as a fallback. Prefer the first inbox URL we see for a
|
|
768
|
+
// given prId — later notes don't override the canonical record.
|
|
769
|
+
if (!inboxUrls.has(prId)) {
|
|
770
|
+
const urlMatch = match[0].match(/https?:\/\/[^\s"\\)]+/);
|
|
771
|
+
if (urlMatch) inboxUrls.set(prId, urlMatch[0].replace(/[.,;:]+$/, ''));
|
|
772
|
+
}
|
|
773
|
+
}
|
|
754
774
|
}
|
|
755
775
|
|
|
756
776
|
if (prMatches.size === 0) return 0;
|
|
@@ -773,7 +793,10 @@ function syncPrsFromOutput(output, agentId, meta, config) {
|
|
|
773
793
|
return defaultProject;
|
|
774
794
|
}
|
|
775
795
|
|
|
776
|
-
// Extract PR URL directly from agent output — no manual construction
|
|
796
|
+
// Extract PR URL directly from agent output — no manual construction.
|
|
797
|
+
// Falls back to the URL captured from the inbox note when the agent stdout
|
|
798
|
+
// doesn't contain the link (gh pr create may have run in a sibling dispatch
|
|
799
|
+
// whose stdout was rotated; the inbox note is the durable artifact).
|
|
777
800
|
function extractPrUrl(prId) {
|
|
778
801
|
// Stop at backslash in addition to whitespace/quotes — raw JSONL encodes newlines as \n (literal
|
|
779
802
|
// backslash-n), so without this the regex would capture e.g. "pull/1804\n/usr/bin/bash".
|
|
@@ -781,7 +804,7 @@ function syncPrsFromOutput(output, agentId, meta, config) {
|
|
|
781
804
|
if (ghMatch) return ghMatch[0].replace(/[.,;:]+$/, '');
|
|
782
805
|
const adoMatch = output.match(new RegExp(`https?://(?:dev\\.azure\\.com|[^/]+\\.visualstudio\\.com)[^\\s"'\\)\\]\\\\]*?pullrequest/${prId}(?:[^\\s"'\\)\\]\\\\]*)`, 'i'));
|
|
783
806
|
if (adoMatch) return adoMatch[0].replace(/[.,;:]+$/, '');
|
|
784
|
-
return '';
|
|
807
|
+
return inboxUrls.get(prId) || '';
|
|
785
808
|
}
|
|
786
809
|
|
|
787
810
|
const agentName = config.agents?.[agentId]?.name || agentId;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@yemi33/minions",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.1639",
|
|
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"
|