@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 +5 -0
- package/dashboard/js/utils.js +7 -1
- package/engine/queries.js +28 -8
- package/engine.js +2 -0
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
package/dashboard/js/utils.js
CHANGED
|
@@ -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
|
|
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
|
|
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
|
|
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
|
|
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.
|
|
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"
|