@yemi33/minions 0.1.2234 → 0.1.2236

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.
@@ -932,14 +932,44 @@ function _wiRenderDetail(item) {
932
932
  // (work_item: / wi: / sourceItem:). Slim string[] field set by
933
933
  // engine/queries.js#getWorkItems from _buildNotesByWiMap. Each entry is
934
934
  // either a bare inbox filename or `archive:<filename>` for archive notes.
935
+ //
936
+ // #308 — repeated attempts for one WI used to render a flat pile of
937
+ // indistinguishable note chips (every per-attempt failure report + legacy
938
+ // harness-usage note shown beside the final agent report). Partition the
939
+ // notes: per-attempt failure/partial reports and legacy harness-usage notes
940
+ // are GROUPED into a collapsed "Prior attempts" disclosure, leaving the final
941
+ // agent findings note(s) as the primary, always-visible chips. Backward
942
+ // compatible — every grouped note still opens via the same renderArtifactLink
943
+ // chip, just behind a <details> instead of in the flat list.
935
944
  if (Array.isArray(item._notes) && item._notes.length > 0) {
936
- var mentionPills = item._notes.map(function(token) {
945
+ var _mentionPill = function(token) {
937
946
  var isArchive = token.indexOf('archive:') === 0;
938
947
  var fname = isArchive ? token.slice(8) : token;
939
948
  var label = fname.replace(/\.md$/, '').slice(0, 30) + (isArchive ? ' (archived)' : '');
940
949
  return renderArtifactLink({ type: 'note', id: fname, label: label, title: 'Note: ' + fname });
941
- }).join(' ');
942
- html += field('Mentions', '<div style="display:flex;flex-wrap:wrap;gap:4px">' + mentionPills + '</div>');
950
+ };
951
+ // A note is a "prior attempt" chip when its filename slug marks it as an
952
+ // engine-emitted per-attempt failure/partial report or a legacy
953
+ // harness-usage note. These are keyed off the writeToInbox slug embedded in
954
+ // the filename (agent-failure-/agent-failed-/agent-partial-/harness-usage-),
955
+ // so the test is a pure string check independent of frontmatter.
956
+ var _isPriorAttemptNote = function(token) {
957
+ var fname = token.indexOf('archive:') === 0 ? token.slice(8) : token;
958
+ return /(?:^|-)(?:agent-fail(?:ure|ed)|agent-partial|harness-usage)-/.test(fname);
959
+ };
960
+ var primaryNotes = item._notes.filter(function(t) { return !_isPriorAttemptNote(t); });
961
+ var priorNotes = item._notes.filter(_isPriorAttemptNote);
962
+ var mentionHtml = '';
963
+ if (primaryNotes.length > 0) {
964
+ mentionHtml += '<div style="display:flex;flex-wrap:wrap;gap:4px">' + primaryNotes.map(_mentionPill).join(' ') + '</div>';
965
+ }
966
+ if (priorNotes.length > 0) {
967
+ mentionHtml += '<details style="margin-top:' + (primaryNotes.length > 0 ? '6px' : '0') + '">'
968
+ + '<summary style="cursor:pointer;color:var(--muted);font-size:var(--text-sm)">Prior attempts (' + priorNotes.length + ')</summary>'
969
+ + '<div style="display:flex;flex-wrap:wrap;gap:4px;margin-top:4px">' + priorNotes.map(_mentionPill).join(' ') + '</div>'
970
+ + '</details>';
971
+ }
972
+ if (mentionHtml) html += field('Mentions', mentionHtml);
943
973
  }
944
974
 
945
975
  if (item._totalCostUsd != null) html += field('Cumulative Cost', '$' + Number(item._totalCostUsd).toFixed(4));
package/docs/README.md CHANGED
@@ -29,7 +29,7 @@ Architecture, design proposals, and lifecycle references for people working on t
29
29
  - [design-state-storage.md](design-state-storage.md) — Design proposal evaluating five database options for replacing Minions' file-based JSON state; recommends `node:sqlite` as the medium-term target (accepted; implementation tracked in CHANGELOG.md Phases 0–9).
30
30
  - [harness-mode.md](harness-mode.md) — Tri-Agent Harness Mode (`harness_mode: "tri_agent"` on scheduled tasks): Planner → Generator → Evaluator loop that iterates a shared on-disk artifact until a rubric passes or the iteration cap fires.
31
31
  - [harness-propagation.md](harness-propagation.md) — How user-level and project-local harness assets (skills, slash-commands, MCP config, `CLAUDE.md` / `AGENTS.md`) propagate into an agent's worktree via `--add-dir`, the `harnessPropagateProjectLocal` flag, and the project-local-on-main worktree-visibility footgun.
32
- - [harness-transparency.md](harness-transparency.md) — The `harnessUsed` self-report contract: capture (agent reports the skills / MCPs / commands / docs it used) → ground (engine cross-checks against `_harnessPropagated` and annotates `grounded:true\|false`, never dropping) → surface (PR comment, notes/inbox digest, work-item modal).
32
+ - [harness-transparency.md](harness-transparency.md) — The `harnessUsed` self-report contract: capture (agent reports the skills / MCPs / commands / docs it used) → ground (engine cross-checks against `_harnessPropagated` and annotates `grounded:true\|false`, never dropping) → surface (PR comment, final agent note, work-item modal).
33
33
  - [kb-sweep.md](kb-sweep.md) — Knowledge-base consolidation sweep (hash dedup → LLM batch dedup/reclassify → per-entry compress) and the detached runner that keeps it alive across `minions restart`.
34
34
  - [keep-processes.md](keep-processes.md) — `meta.keep_processes` sidecar contract: when to use it vs managed-spawn, sidecar schema, caps, and the [`engine/keep-process-sweep.js`](../engine/keep-process-sweep.js) lifecycle.
35
35
  - [live-checkout-mode.md](live-checkout-mode.md) — Per-project opt-in `checkoutMode: 'live'`: skips `git worktree add` and dispatches in-place inside `project.localPath` for `repo`-managed trees, submodule-heavy repos, deep Windows paths, and native build state. Includes the refuse-on-dirty contract and the per-project mutating-concurrency cap of 1.
@@ -119,10 +119,13 @@ evaluation pass) can see what tooling drove a dispatch:
119
119
  paths review/fix agents append the section themselves per
120
120
  `playbooks/shared-rules.md` → "Harness transparency / self-report". Every
121
121
  surface consumes the one renderer, so there is no second formatter to drift.
122
- 2. **notes/inbox digest** — harness usage is summarized into the learnings /
123
- inbox stream that feeds consolidation, so cross-task patterns ("everyone
124
- reaches for skill X on Android fixes") become visible to the team-memory
125
- layer.
122
+ 2. **Final agent note** — for a non-clean completion (failure / partial) the
123
+ single final agent report (`engine/lifecycle.js#writeNonCleanAgentReport`)
124
+ folds the grounded harness footprint in as the same `buildHarnessUsedSection`
125
+ block, so the learnings / inbox stream that feeds consolidation still carries
126
+ it without a separate per-attempt `harness-usage-*` note. Clean completions
127
+ rely on the work-item modal surface (#3) instead — they write no inbox note
128
+ at all (#308 removed the standalone harness-usage digest to cut note spam).
126
129
  3. **Work-item detail modal** — the dashboard work-item modal shows the
127
130
  grounded harness list alongside the completion artifacts, with the
128
131
  `grounded: false` entries visually distinguished (P-d5a6f7c4). On
@@ -4094,6 +4094,11 @@ function writeNonCleanAgentReport(dispatchItem, agentId, outcome, structuredComp
4094
4094
  const structuredLines = structuredCompletion
4095
4095
  ? Object.entries(structuredCompletion).map(([key, value]) => `- ${key}: ${value}`).join('\n')
4096
4096
  : '- none';
4097
+ // #308 — fold the agent's grounded harness footprint into THIS final agent
4098
+ // report instead of emitting a separate `harness-usage-*` inbox note per
4099
+ // attempt. buildHarnessUsedSection returns '' for an absent/empty/malformed
4100
+ // record, so the section is appended only when there is something to show.
4101
+ const harnessSection = buildHarnessUsedSection(structuredCompletion?.harnessUsed);
4097
4102
  const content = [
4098
4103
  `# Agent ${outcome === 'partial' ? 'Partially Completed' : 'Reported Failure'}: ${title}`,
4099
4104
  '',
@@ -4108,65 +4113,11 @@ function writeNonCleanAgentReport(dispatchItem, agentId, outcome, structuredComp
4108
4113
  structuredLines,
4109
4114
  '',
4110
4115
  resultSummary ? `## Summary\n${resultSummary}` : '## Summary\n(no agent summary captured)',
4116
+ harnessSection ? `\n${harnessSection}` : '',
4111
4117
  ].filter(Boolean).join('\n');
4112
4118
  shared.writeToInbox(agentId || 'engine', `agent-${outcome}-${dispatchItem.id}`, content, null, metadata);
4113
4119
  }
4114
4120
 
4115
- /**
4116
- * P-f3c8b5e6 — Harness Transparency, Stage-3 readout #3: notes/inbox digest.
4117
- *
4118
- * Routes a compact, one-block-per-dispatch harness-usage summary into
4119
- * notes/inbox/ so engine/consolidation.js#consolidateInbox folds it into the
4120
- * notes.md digest alongside the other inbox findings. Clean dispatches don't
4121
- * otherwise write an inbox note (only failures/non-clean outcomes do, via
4122
- * writeNonCleanAgentReport / dispatch.js writeFailedAgentReport), so without
4123
- * this the harness footprint never reaches the digest for successful runs.
4124
- *
4125
- * Gating: writes nothing unless the GROUNDED harnessUsed (the canonical
4126
- * { skills, mcpServers, commands, docs } shape produced by
4127
- * shared.groundHarnessUsed) renders at least one entry. The render check is
4128
- * delegated to buildHarnessUsedSection (the same platform-neutral renderer the
4129
- * PR-comment surface uses — one renderer, no drift), which returns '' for
4130
- * absent/malformed/all-empty records.
4131
- *
4132
- * Dedup: the inbox slug is keyed on the work-item id (falling back to the
4133
- * dispatch id), so retries of the same WI — which get a fresh dispatch id —
4134
- * collapse onto one note per day (writeToInbox skips when a same-prefix file
4135
- * already exists). This keeps busy fleets from flooding the digest.
4136
- *
4137
- * Best-effort: never throws into the completion path. Returns the note id on
4138
- * write, or false when nothing was written (empty footprint, dedup hit, or no
4139
- * dispatch id).
4140
- */
4141
- function writeHarnessUsageDigest(dispatchItem, agentId, harnessUsed) {
4142
- try {
4143
- if (!dispatchItem?.id) return false;
4144
- const section = buildHarnessUsedSection(harnessUsed);
4145
- if (!section) return false; // empty / absent / malformed → write nothing
4146
- const itemId = dispatchItem.meta?.item?.id || '';
4147
- const dedupKey = itemId || dispatchItem.id;
4148
- const title = dispatchItem.meta?.item?.title || dispatchItem.task || dispatchItem.id;
4149
- const metadata = {
4150
- dispatchId: dispatchItem.id,
4151
- sourceItem: itemId || null,
4152
- kind: 'harness-usage',
4153
- };
4154
- const content = [
4155
- `# Harnesses used: ${title}`,
4156
- '',
4157
- `**Agent:** ${agentId || 'engine'}`,
4158
- `**Dispatch:** \`${dispatchItem.id}\``,
4159
- itemId ? `**Work Item:** \`${itemId}\`` : '',
4160
- `**Type:** ${dispatchItem.type || 'unknown'}`,
4161
- '',
4162
- section,
4163
- ].filter(Boolean).join('\n');
4164
- return shared.writeToInbox(agentId || 'engine', `harness-usage-${dedupKey}`, content, null, metadata);
4165
- } catch (err) {
4166
- log('warn', `Harness-usage inbox digest write failed for ${dispatchItem?.id} (non-fatal): ${err.message}`);
4167
- return false;
4168
- }
4169
- }
4170
4121
 
4171
4122
  /**
4172
4123
  * Permissively pull all assistant-message content out of a stream-json log.
@@ -4753,9 +4704,15 @@ async function runPostCompletionHooks(dispatchItem, agentId, code, stdout, confi
4753
4704
  // The grounded result replaces `structuredCompletion.harnessUsed` IN PLACE, so
4754
4705
  // it rides the existing `structuredCompletion` storage onto the completed
4755
4706
  // dispatch record (completeDispatch persists `item.structuredCompletion`) for
4756
- // the Stage-3 surfaces (PR comment / inbox digest / WI modal) to read. Pure,
4757
- // non-destructive (grounded:false entries are kept + flagged, never dropped),
4758
- // and best-effort: any failure here must never block completion.
4707
+ // the Stage-3 surfaces (PR comment / final agent note / WI modal) to read.
4708
+ // Pure, non-destructive (grounded:false entries are kept + flagged, never
4709
+ // dropped), and best-effort: any failure here must never block completion.
4710
+ //
4711
+ // #308 — the grounded footprint is no longer routed to its own
4712
+ // `harness-usage-*` inbox note (that produced one duplicate-looking note chip
4713
+ // per attempt). For clean completions the structured `_harnessUsed` WI-modal
4714
+ // UI surfaces it; for non-clean outcomes writeNonCleanAgentReport folds the
4715
+ // same buildHarnessUsedSection block into the single final agent note.
4759
4716
  if (structuredCompletion && structuredCompletion.harnessUsed) {
4760
4717
  try {
4761
4718
  const propagated = resolveHarnessPropagated(dispatchItem);
@@ -4764,11 +4721,6 @@ async function runPostCompletionHooks(dispatchItem, agentId, code, stdout, confi
4764
4721
  } catch (err) {
4765
4722
  log('warn', `Harness grounding cross-check failed for ${dispatchItem.id} (non-fatal): ${err.message}`);
4766
4723
  }
4767
- // P-f3c8b5e6 — Stage-3 readout #3: route the grounded footprint into the
4768
- // notes/inbox digest. Gated on a non-empty render + deduped per WI inside
4769
- // writeHarnessUsageDigest, so this is safe to call unconditionally for
4770
- // every dispatch (clean or not) that self-reported a harness footprint.
4771
- writeHarnessUsageDigest(dispatchItem, agentId, structuredCompletion.harnessUsed);
4772
4724
  }
4773
4725
 
4774
4726
  const completionGateSummary = resultSummary || (typeof stdout === 'string' && !stdout.includes('"type":') ? stdout : '');
@@ -5903,8 +5855,10 @@ module.exports = {
5903
5855
  markMissingPrAttachment,
5904
5856
  parseCompletionReportFile,
5905
5857
  resolveHarnessPropagated,
5906
- // P-f3c8b5e6notes/inbox harness-usage digest (exported for unit testing).
5907
- writeHarnessUsageDigest,
5858
+ // #308 — exported for unit testing: the final non-clean agent note now folds
5859
+ // the grounded harness footprint in as a section instead of emitting a
5860
+ // standalone harness-usage-* inbox note.
5861
+ writeNonCleanAgentReport,
5908
5862
  normalizeCompletionArtifacts,
5909
5863
  completionArtifactToNoteEntry,
5910
5864
  mergeArtifactNotes,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@yemi33/minions",
3
- "version": "0.1.2234",
3
+ "version": "0.1.2236",
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"