@yemi33/minions 0.1.2315 → 0.1.2317

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/engine/meeting.js CHANGED
@@ -231,18 +231,14 @@ function resolveMeetingContributionContent(output, structuredCompletion) {
231
231
  return resolveStructuredMeetingContent(structuredCompletion);
232
232
  }
233
233
 
234
- function truncateMeetingContext(text, maxBytes, label) {
235
- return shared.truncateTextBytes(text, maxBytes, `\n\n_...${label} truncated — review the meeting transcript if needed._`);
236
- }
237
-
238
234
  function formatMeetingContributions(entries, agents, emptyText, label, maxBytes) {
239
235
  const pairs = Object.entries(typeof entries === 'object' && entries ? entries : {});
240
236
  if (pairs.length === 0) return emptyText;
241
237
  const perEntryBytes = Math.max(1024, Math.floor(maxBytes / Math.max(1, pairs.length)));
242
238
  const combined = pairs.map(([agent, value]) =>
243
- `### ${agents[agent]?.name || agent}\n\n${truncateMeetingContext(value?.content || emptyText, perEntryBytes, `${label} entry`)}`
239
+ `### ${agents[agent]?.name || agent}\n\n${shared.truncateTextBytes(value?.content || emptyText, perEntryBytes, `\n\n_...${label} entry truncated — review the meeting transcript if needed._`)}`
244
240
  ).join('\n\n---\n\n');
245
- return truncateMeetingContext(combined, maxBytes, label);
241
+ return shared.truncateTextBytes(combined, maxBytes, `\n\n_...${label} truncated — review the meeting transcript if needed._`);
246
242
  }
247
243
 
248
244
  function stripMeetingSummaryMarkdown(text) {
@@ -542,10 +538,10 @@ function discoverMeetingWork(config) {
542
538
  const key = `${concludePrefix}${concluder}`;
543
539
  if (activeKeys.has(key)) continue;
544
540
 
545
- const humanNotes = truncateMeetingContext(
541
+ const humanNotes = shared.truncateTextBytes(
546
542
  (Array.isArray(meeting.humanNotes) ? meeting.humanNotes : []).map(n => '- ' + n).join('\n'),
547
543
  ENGINE_DEFAULTS.maxMeetingHumanNotesBytes,
548
- 'human meeting notes'
544
+ '\n\n_...human meeting notes truncated — review the meeting transcript if needed._'
549
545
  );
550
546
  const allFindings = formatMeetingContributions(
551
547
  meeting.findings,
@@ -605,10 +601,10 @@ function discoverMeetingWork(config) {
605
601
  const key = `meeting-${meeting.id}-r${round}-${agentId}`;
606
602
  if (activeKeys.has(key)) continue;
607
603
 
608
- const humanNotes = truncateMeetingContext(
604
+ const humanNotes = shared.truncateTextBytes(
609
605
  (meeting.humanNotes || []).map(n => '- ' + n).join('\n'),
610
606
  ENGINE_DEFAULTS.maxMeetingHumanNotesBytes,
611
- 'human meeting notes'
607
+ '\n\n_...human meeting notes truncated — review the meeting transcript if needed._'
612
608
  );
613
609
  const vars = {
614
610
  agent_name: agents[agentId]?.name || agentId,
@@ -26,10 +26,6 @@ const NOTES_INBOX_DIR = path.join(MINIONS_DIR, 'notes', 'inbox');
26
26
  const NOTES_ARCHIVE_DIR = path.join(MINIONS_DIR, 'notes', 'archive');
27
27
  const CONFIG_PATH = path.join(MINIONS_DIR, 'config.json');
28
28
 
29
- function truncatePipelineContext(text, maxBytes, label) {
30
- return shared.truncateTextBytes(text, maxBytes, `\n\n_...${label} truncated — inspect the upstream artifacts if needed._`);
31
- }
32
-
33
29
  // ── Pipeline CRUD ────────────────────────────────────────────────────────────
34
30
 
35
31
  function getPipelines() {
@@ -619,10 +615,10 @@ async function executePlanStage(stage, stageState, run, config, pipeline = {}) {
619
615
  try {
620
616
  const mtg = safeJson(path.join(MEETINGS_DIR, mid + '.json'));
621
617
  if (mtg) {
622
- const transcript = truncatePipelineContext(
618
+ const transcript = shared.truncateTextBytes(
623
619
  (mtg.transcript || []).map(formatTranscriptEntry).join('\n\n---\n\n'),
624
620
  ENGINE_DEFAULTS.maxPipelineMeetingContextBytes,
625
- `meeting transcript for ${mtg.title || mid}`
621
+ `\n\n_...meeting transcript for ${mtg.title || mid} truncated — inspect the upstream artifacts if needed._`
626
622
  );
627
623
  meetingContext += '# Meeting: ' + (mtg.title || mid) + '\n\n**Agenda:** ' + (mtg.agenda || '') + '\n\n' + transcript + '\n\n';
628
624
  }
@@ -633,15 +629,15 @@ async function executePlanStage(stage, stageState, run, config, pipeline = {}) {
633
629
  for (const depId of stage.dependsOn) {
634
630
  const depStage = run.stages[depId];
635
631
  if (depStage?.output && !depStage.artifacts?.meetings?.length) {
636
- meetingContext += '## From: ' + depId + '\n\n' + truncatePipelineContext(
632
+ meetingContext += '## From: ' + depId + '\n\n' + shared.truncateTextBytes(
637
633
  depStage.output,
638
634
  ENGINE_DEFAULTS.maxPipelineMeetingContextBytes,
639
- `pipeline stage output from ${depId}`
635
+ `\n\n_...pipeline stage output from ${depId} truncated — inspect the upstream artifacts if needed._`
640
636
  ) + '\n\n';
641
637
  }
642
638
  }
643
639
  }
644
- meetingContext = truncatePipelineContext(meetingContext, ENGINE_DEFAULTS.maxPipelineMeetingContextBytes, 'pipeline meeting context');
640
+ meetingContext = shared.truncateTextBytes(meetingContext, ENGINE_DEFAULTS.maxPipelineMeetingContextBytes, '\n\n_...pipeline meeting context truncated — inspect the upstream artifacts if needed._');
645
641
 
646
642
  // Use LLM to generate a structured plan (same approach as dashboard "Create Plan from Meeting" button)
647
643
  let content = '';
@@ -1259,7 +1255,7 @@ module.exports = {
1259
1255
  getPipelineRuns, getActiveRun, startRun, updateRunStage, upsertRunStage, completeRun,
1260
1256
  discoverPipelineWork,
1261
1257
  evaluateCondition, // exported for testing
1262
- truncatePipelineContext, executeTaskStage, executePlanStage, executeScheduleStage, executeApiStage, executeMeetingStage, executeMergePrsStage, isStageComplete, resolveTemplate, // exported for testing
1258
+ executeTaskStage, executePlanStage, executeScheduleStage, executeApiStage, executeMeetingStage, executeMergePrsStage, isStageComplete, resolveTemplate, // exported for testing
1263
1259
  _resolvePipelineProjects, // exported for testing
1264
1260
  _findMeetingsInRun, _findExistingPlanForMeeting, _findExistingPrdForPlan, _canonicalPlanName, // exported for testing
1265
1261
  };
@@ -69,24 +69,9 @@ const GIT_OP_TIMEOUT_MS = 60 * 1000;
69
69
  * `PrActionError` (400) on missing/unrecognized input — mirrors the read-only,
70
70
  * choice-surface, and temp-clone paths so the dashboard reflects a 400, not a 500.
71
71
  */
72
- function _resolveRef(input) {
73
- if (input && typeof input === 'object') {
74
- if (input.host && input.slug && input.number) return input; // already normalized
75
- if (input.ref && input.ref.host) return input.ref; // plan/handle carrying a ref
76
- }
77
- const rawUrl = input && typeof input === 'object'
78
- ? (typeof input.url === 'string' ? input.url.trim() : '')
79
- : (typeof input === 'string' ? input.trim() : '');
80
- if (!rawUrl) throw new PrActionError('url required');
81
- const ref = prResolve.normalizePrRef(rawUrl);
82
- if (!ref) throw new PrActionError(`unrecognized PR reference: ${JSON.stringify(rawUrl.slice(0, 120))}`);
83
- return ref;
84
- }
72
+ const _resolveRef = (input) => prResolve.resolvePrActionRef(input, PrActionError);
85
73
 
86
- function _prId(ref) {
87
- if (!ref) return null;
88
- return ref.id || (ref.host && ref.slug && ref.number ? `${ref.host}:${ref.slug}#${ref.number}` : null);
89
- }
74
+ const _prId = prResolve.prIdFromRef;
90
75
 
91
76
  /** Filesystem-safe slug for the persistent project dir name (from the repo name). */
92
77
  function _safeDirSlug(name) {
@@ -60,24 +60,9 @@ const DEFAULT_REMOTE_TMP_ROOT = 'C:/minions-devbox-tmp';
60
60
  * `PrActionError` (400) on missing/unrecognized input — mirrors the other
61
61
  * projectless paths so the dashboard reflects a 400, not a 500.
62
62
  */
63
- function _resolveRef(input) {
64
- if (input && typeof input === 'object') {
65
- if (input.host && input.slug && input.number) return input; // already normalized
66
- if (input.ref && input.ref.host) return input.ref; // plan/handle carrying a ref
67
- }
68
- const rawUrl = input && typeof input === 'object'
69
- ? (typeof input.url === 'string' ? input.url.trim() : '')
70
- : (typeof input === 'string' ? input.trim() : '');
71
- if (!rawUrl) throw new PrActionError('url required');
72
- const ref = prResolve.normalizePrRef(rawUrl);
73
- if (!ref) throw new PrActionError(`unrecognized PR reference: ${JSON.stringify(rawUrl.slice(0, 120))}`);
74
- return ref;
75
- }
63
+ const _resolveRef = (input) => prResolve.resolvePrActionRef(input, PrActionError);
76
64
 
77
- function _prId(ref) {
78
- if (!ref) return null;
79
- return ref.id || (ref.host && ref.slug && ref.number ? `${ref.host}:${ref.slug}#${ref.number}` : null);
80
- }
65
+ const _prId = prResolve.prIdFromRef;
81
66
 
82
67
  /** Filesystem-safe slug for a PR id (used in the remote dir name). */
83
68
  function _safeDirSlug(prId) {
@@ -143,21 +143,7 @@ function _routedRecord(plan, target, extra = {}) {
143
143
  * a normalized PR ref. Throws `PrActionError` (400) on missing/unrecognized input
144
144
  * so the dashboard handler reflects it as a 400 (matching the read-only path).
145
145
  */
146
- function _resolveRef(input) {
147
- if (input && typeof input === 'object' && input.host && input.slug && input.number) {
148
- return input; // already normalized
149
- }
150
- if (input && typeof input === 'object' && input.ref && input.ref.host) {
151
- return input.ref; // a plan/handle carrying a ref
152
- }
153
- const rawUrl = input && typeof input === 'object'
154
- ? (typeof input.url === 'string' ? input.url.trim() : '')
155
- : (typeof input === 'string' ? input.trim() : '');
156
- if (!rawUrl) throw new PrActionError('url required');
157
- const ref = prResolve.normalizePrRef(rawUrl);
158
- if (!ref) throw new PrActionError(`unrecognized PR reference: ${JSON.stringify(rawUrl.slice(0, 120))}`);
159
- return ref;
160
- }
146
+ const _resolveRef = (input) => prResolve.resolvePrActionRef(input, PrActionError);
161
147
 
162
148
  // ── Configured-project detection ──────────────────────────────────────────────
163
149
 
@@ -309,7 +295,7 @@ function buildPrFixTargetModal(plan) {
309
295
  function planPrFix(input = {}, opts = {}) {
310
296
  const ref = _resolveRef(input);
311
297
  const prUrl = opts.prUrl || (input && typeof input === 'object' ? input.url : undefined) || null;
312
- const prId = ref.id || (ref.host && ref.slug && ref.number ? `${ref.host}:${ref.slug}#${ref.number}` : null);
298
+ const prId = prResolve.prIdFromRef(ref);
313
299
 
314
300
  const project = findConfiguredProjectForRef(ref, opts.config);
315
301
  if (project) {
@@ -59,24 +59,9 @@ const REMOTE_PATCH_NO_VALIDATION_LABEL =
59
59
  * `PrActionError` (400) on missing/unrecognized input — mirrors the read-only,
60
60
  * choice-surface, and temp-clone paths so the dashboard reflects a 400, not 500.
61
61
  */
62
- function _resolveRef(input) {
63
- if (input && typeof input === 'object') {
64
- if (input.host && input.slug && input.number) return input; // already normalized
65
- if (input.ref && input.ref.host) return input.ref; // plan/handle carrying a ref
66
- }
67
- const rawUrl = input && typeof input === 'object'
68
- ? (typeof input.url === 'string' ? input.url.trim() : '')
69
- : (typeof input === 'string' ? input.trim() : '');
70
- if (!rawUrl) throw new PrActionError('url required');
71
- const ref = prResolve.normalizePrRef(rawUrl);
72
- if (!ref) throw new PrActionError(`unrecognized PR reference: ${JSON.stringify(rawUrl.slice(0, 120))}`);
73
- return ref;
74
- }
62
+ const _resolveRef = (input) => prResolve.resolvePrActionRef(input, PrActionError);
75
63
 
76
- function _prId(ref) {
77
- if (!ref) return null;
78
- return ref.id || (ref.host && ref.slug && ref.number ? `${ref.host}:${ref.slug}#${ref.number}` : null);
79
- }
64
+ const _prId = prResolve.prIdFromRef;
80
65
 
81
66
  // ── Patch normalization (the trivial-single-file guardrail) ───────────────────
82
67
 
@@ -102,6 +102,42 @@ function normalizePrRef(input) {
102
102
  return _normalizeFromScope(parsed.scope, parsed.prNumber);
103
103
  }
104
104
 
105
+ // ── Shared ref resolution for the PR-action executors ───────────────────────
106
+
107
+ /**
108
+ * Resolve `{ url }` (raw PR URL / canonical id), an already-normalized ref, or a
109
+ * plan/handle carrying `.ref` into a normalized PR ref. Throws `PrActionError`
110
+ * (400) on missing/unrecognized input so callers reflect a 400, not a 500.
111
+ *
112
+ * Shared by the 6 PR-action executor modules (pr-clone-keep, pr-devbox,
113
+ * pr-remote-patch, pr-temp-clone, pr-track, pr-fix-target), which previously
114
+ * each defined a byte-identical copy of this function. `PrActionError` must be
115
+ * passed in by the caller — pr-resolve.js does not import engine/pr-action.js
116
+ * (that would introduce a new cross-module dependency in that direction).
117
+ */
118
+ function resolvePrActionRef(input, PrActionError) {
119
+ if (input && typeof input === 'object') {
120
+ if (input.host && input.slug && input.number) return input; // already normalized
121
+ if (input.ref && input.ref.host) return input.ref; // plan/handle carrying a ref
122
+ }
123
+ const rawUrl = input && typeof input === 'object'
124
+ ? (typeof input.url === 'string' ? input.url.trim() : '')
125
+ : (typeof input === 'string' ? input.trim() : '');
126
+ if (!rawUrl) throw new PrActionError('url required');
127
+ const ref = normalizePrRef(rawUrl);
128
+ if (!ref) throw new PrActionError(`unrecognized PR reference: ${JSON.stringify(rawUrl.slice(0, 120))}`);
129
+ return ref;
130
+ }
131
+
132
+ /**
133
+ * Derive the canonical `host:slug#number` PR id string from a normalized ref
134
+ * (or its already-computed `.id`). Returns null when `ref` is falsy.
135
+ */
136
+ function prIdFromRef(ref) {
137
+ if (!ref) return null;
138
+ return ref.id || (ref.host && ref.slug && ref.number ? `${ref.host}:${ref.slug}#${ref.number}` : null);
139
+ }
140
+
105
141
  // ── Config (for the unknown-slug account fallback) ───────────────────────────
106
142
 
107
143
  function _readConfig(opts = {}) {
@@ -432,6 +468,8 @@ async function fetchPrPayload(refOrInput, opts = {}) {
432
468
 
433
469
  module.exports = {
434
470
  normalizePrRef,
471
+ resolvePrActionRef,
472
+ prIdFromRef,
435
473
  fetchPrPayload,
436
474
  fetchPrBranches,
437
475
  // Exported for testing.
@@ -57,24 +57,9 @@ const GIT_OP_TIMEOUT_MS = 60 * 1000;
57
57
  * `PrActionError` (400) on missing/unrecognized input — mirrors the read-only
58
58
  * and choice-surface paths so the dashboard reflects a 400, not a 500.
59
59
  */
60
- function _resolveRef(input) {
61
- if (input && typeof input === 'object') {
62
- if (input.host && input.slug && input.number) return input; // already normalized
63
- if (input.ref && input.ref.host) return input.ref; // plan/handle carrying a ref
64
- }
65
- const rawUrl = input && typeof input === 'object'
66
- ? (typeof input.url === 'string' ? input.url.trim() : '')
67
- : (typeof input === 'string' ? input.trim() : '');
68
- if (!rawUrl) throw new PrActionError('url required');
69
- const ref = prResolve.normalizePrRef(rawUrl);
70
- if (!ref) throw new PrActionError(`unrecognized PR reference: ${JSON.stringify(rawUrl.slice(0, 120))}`);
71
- return ref;
72
- }
60
+ const _resolveRef = (input) => prResolve.resolvePrActionRef(input, PrActionError);
73
61
 
74
- function _prId(ref) {
75
- if (!ref) return null;
76
- return ref.id || (ref.host && ref.slug && ref.number ? `${ref.host}:${ref.slug}#${ref.number}` : null);
77
- }
62
+ const _prId = prResolve.prIdFromRef;
78
63
 
79
64
  /** Filesystem-safe slug for a PR id (used in the ephemeral dir name). */
80
65
  function _safeDirSlug(prId) {
@@ -56,24 +56,9 @@ const TRACK_RECOMMENDED_TARGET = 'clone-keep';
56
56
  * missing/unrecognized input so the dashboard reflects a 400 — mirrors the
57
57
  * read-only and choice-surface paths.
58
58
  */
59
- function _resolveRef(input) {
60
- if (input && typeof input === 'object') {
61
- if (input.host && input.slug && input.number) return input; // already normalized
62
- if (input.ref && input.ref.host) return input.ref; // plan/handle carrying a ref
63
- }
64
- const rawUrl = input && typeof input === 'object'
65
- ? (typeof input.url === 'string' ? input.url.trim() : '')
66
- : (typeof input === 'string' ? input.trim() : '');
67
- if (!rawUrl) throw new PrActionError('url required');
68
- const ref = prResolve.normalizePrRef(rawUrl);
69
- if (!ref) throw new PrActionError(`unrecognized PR reference: ${JSON.stringify(rawUrl.slice(0, 120))}`);
70
- return ref;
71
- }
59
+ const _resolveRef = (input) => prResolve.resolvePrActionRef(input, PrActionError);
72
60
 
73
- function _prId(ref) {
74
- if (!ref) return null;
75
- return ref.id || (ref.host && ref.slug && ref.number ? `${ref.host}:${ref.slug}#${ref.number}` : null);
76
- }
61
+ const _prId = prResolve.prIdFromRef;
77
62
 
78
63
  // ── Choice surface (Clone & keep implied) ─────────────────────────────────────
79
64
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@yemi33/minions",
3
- "version": "0.1.2315",
3
+ "version": "0.1.2317",
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"