@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.
- package/dashboard/js/render-work-items.js +33 -3
- package/docs/README.md +1 -1
- package/docs/harness-transparency.md +7 -4
- package/engine/lifecycle.js +19 -65
- package/package.json +1 -1
|
@@ -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
|
|
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
|
-
}
|
|
942
|
-
|
|
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,
|
|
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. **
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
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
|
package/engine/lifecycle.js
CHANGED
|
@@ -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 /
|
|
4757
|
-
// non-destructive (grounded:false entries are kept + flagged, never
|
|
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
|
-
//
|
|
5907
|
-
|
|
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.
|
|
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"
|