@yemi33/minions 0.1.1549 → 0.1.1551

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 CHANGED
@@ -1,5 +1,10 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.1.1551 (2026-04-27)
4
+
5
+ ### Fixes
6
+ - derive PR URL from canonical PR ID scope, not projects[0]
7
+
3
8
  ## 0.1.1549 (2026-04-24)
4
9
 
5
10
  ### Other
@@ -98,9 +98,15 @@ function toggleModalPin() {
98
98
 
99
99
  // Canonical HTML-escape helper (SEC-03). Use this in all new code and for any user-controlled
100
100
  // field that reaches `.innerHTML` / a template literal. Escapes the 6 HTML metacharacters
101
- // (& < > " ' /) — the `/` escape closes the `</script>` break-out path that a 5-char escape
101
+ // (& < > " ' /) — the `/` escape closes the `<\/script>` break-out path that a 5-char escape
102
102
  // leaves open. Returns '' for null/undefined so missing fields never render the literal strings
103
103
  // "null"/"undefined". Idempotent for non-metacharacter input (double-escaping only expands `&`).
104
+ // NOTE: the `<\/script>` spelling above is deliberate. dashboard.js inlines every module in
105
+ // dashboard/js/ into a single inline <script> block; a raw closing-script-tag literal in any
106
+ // comment or string closes that block early and spills the rest as document text (issue #1746).
107
+ // The HTML5 tokenizer's script-data end-tag match is byte-level and ignores JS comment/string
108
+ // boundaries, so the only safe way to reference the token in-source is to break the match —
109
+ // `<` followed by `\/` works because after `<` only `/` (not `\`) triggers end-tag-open state.
104
110
  function escapeHtml(str) {
105
111
  if (str === null || str === undefined) return '';
106
112
  return String(str)
package/engine/queries.js CHANGED
@@ -1022,6 +1022,31 @@ function getPrdInfo(config) {
1022
1022
  const prById = {};
1023
1023
  for (const pr of allPrs) prById[pr.id] = pr;
1024
1024
 
1025
+ // Build URL for a PR when pr.url isn't set. Prefer the PR ID's own scope
1026
+ // (e.g. `github:owner/repo#123` → github.com URL) so a github PR never gets
1027
+ // an ADO URL just because the only configured project happens to be ADO.
1028
+ // Only use a project's prUrlBase when its host actually matches the PR.
1029
+ const _buildPrUrlFromId = (prId, pr) => {
1030
+ if (pr?.url) return pr.url;
1031
+ const canonical = shared.parseCanonicalPrId(prId);
1032
+ if (canonical) {
1033
+ const [host, rest] = canonical.scope.split(':');
1034
+ if (host === 'github') return `https://github.com/${rest}/pull/${canonical.prNumber}`;
1035
+ if (host === 'ado') {
1036
+ const [org, adoProject, repo] = rest.split('/');
1037
+ if (org && adoProject && repo) {
1038
+ return `https://dev.azure.com/${org}/${adoProject}/_git/${repo}/pullrequest/${canonical.prNumber}`;
1039
+ }
1040
+ }
1041
+ }
1042
+ // Legacy `PR-N` ID with no host scope: only use project's prUrlBase if a
1043
+ // matching project (by name) exists. Never blindly fall back to projects[0].
1044
+ const project = pr?._project ? projects.find(p => p.name === pr._project) : null;
1045
+ const prNumber = shared.getPrNumber(pr || prId);
1046
+ if (project?.prUrlBase && prNumber != null) return project.prUrlBase + prNumber;
1047
+ return '';
1048
+ };
1049
+
1025
1050
  const prdToPr = {};
1026
1051
  const prLinks = shared.getPrLinks(); // { "PR-xxxx": ["P-xxxx", "P-yyyy"] }
1027
1052
  for (const [prId, itemIds] of Object.entries(prLinks)) {
@@ -1030,9 +1055,7 @@ function getPrdInfo(config) {
1030
1055
  // (or are typed as verify) and would bleed through as duplicate entries on every
1031
1056
  // constituent item. They are surfaced via renderE2eSection instead. (#1220)
1032
1057
  if ((itemIds || []).length > 1 || pr?.itemType === 'verify' || pr?.title?.startsWith('[E2E]')) continue;
1033
- const project = projects.find(p => p.name === pr?._project) || projects[0] || null;
1034
- const prNumber = shared.getPrNumber(pr || prId);
1035
- const url = pr?.url || (project?.prUrlBase && prNumber != null ? project.prUrlBase + prNumber : '');
1058
+ const url = _buildPrUrlFromId(prId, pr);
1036
1059
  for (const itemId of (itemIds || [])) {
1037
1060
  if (!prdToPr[itemId]) prdToPr[itemId] = [];
1038
1061
  prdToPr[itemId].push({ id: prId, url, title: pr?.title || '', status: pr?.status || 'active', _project: pr?._project || '' });
@@ -1046,8 +1069,7 @@ function getPrdInfo(config) {
1046
1069
  const exactPr = prById[canonicalPrId] || null;
1047
1070
  const displayMatches = exactPr ? [] : Object.values(prById).filter(candidate => shared.getPrDisplayId(candidate) === shared.getPrDisplayId(wi._pr));
1048
1071
  const pr = exactPr || (displayMatches.length === 1 ? displayMatches[0] : null);
1049
- const prNumber = shared.getPrNumber(pr || wi._pr);
1050
- const url = pr?.url || (project?.prUrlBase && prNumber != null ? project.prUrlBase + prNumber : '');
1072
+ const url = _buildPrUrlFromId(canonicalPrId || wi._pr, pr);
1051
1073
  prdToPr[wi.id] = [{ id: pr?.id || canonicalPrId || wi._pr, url, title: pr?.title || '', status: pr?.status || 'active', _project: project?.name || '' }];
1052
1074
  }
1053
1075
  // Aggregate sub-task PRs to decomposed parent (sub-tasks aren't PRD items but their PRs should show)
@@ -1060,9 +1082,7 @@ function getPrdInfo(config) {
1060
1082
  const parentId = wi.parent_id;
1061
1083
  if (!prdToPr[parentId]) prdToPr[parentId] = [];
1062
1084
  if (!prdToPr[parentId].some(p => p.id === pr.id)) {
1063
- const project = projects.find(p => p.name === pr._project) || projects[0] || null;
1064
- const prNumber = shared.getPrNumber(pr);
1065
- const url = pr.url || (project?.prUrlBase && prNumber != null ? project.prUrlBase + prNumber : '');
1085
+ const url = _buildPrUrlFromId(pr.id, pr);
1066
1086
  prdToPr[parentId].push({ id: pr.id, url, title: pr.title || '', status: pr.status || 'active', _project: pr._project || '' });
1067
1087
  }
1068
1088
  }
package/engine.js CHANGED
@@ -3759,6 +3759,8 @@ module.exports = {
3759
3759
  // Shared helpers (used by lifecycle.js and tests)
3760
3760
  reconcileItemsWithPrs, detectDependencyCycles,
3761
3761
  parseConflictFiles, pruneAncestorDeps, preflightMergeSimulation, // exported for testing
3762
+ isWorktreeRetryableError, removeStaleIndexLock, // exported for testing
3763
+ _maxTurnsForType, buildProjectContext, normalizeAc, // exported for testing
3762
3764
 
3763
3765
  // Playbooks
3764
3766
  renderPlaybook, validatePlaybookVars, PLAYBOOK_REQUIRED_VARS, buildWorkItemDispatchVars,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@yemi33/minions",
3
- "version": "0.1.1549",
3
+ "version": "0.1.1551",
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"