@yemi33/minions 0.1.1894 → 0.1.1895

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/cli.js CHANGED
@@ -1144,7 +1144,8 @@ const commands = {
1144
1144
  const e = engine();
1145
1145
  if (!title) {
1146
1146
  console.log('Usage: node .minions/engine.js work "<title>" [options-json]');
1147
- console.log('Options: {"type":"implement","priority":"high","agent":"dallas","description":"...","branch":"feature/..."}');
1147
+ console.log('Options: {"id":"W-customid","type":"implement","priority":"high","agent":"dallas","description":"...","branch":"feature/...","project":"minions"}');
1148
+ console.log(' id Optional caller-supplied work item ID. Defaults to a cuid-style W-<id>.');
1148
1149
  return;
1149
1150
  }
1150
1151
 
@@ -1157,7 +1158,7 @@ const commands = {
1157
1158
  }
1158
1159
 
1159
1160
  const config = getConfig();
1160
- const { getProjects, projectWorkItemsPath, resolveProjectSource } = require('./shared');
1161
+ const { getProjects, projectWorkItemsPath, resolveProjectSource, uid, safeJsonArr } = require('./shared');
1161
1162
  const projects = getProjects(config);
1162
1163
  const target = opts.project ? resolveProjectSource(opts.project, projects, { allowCentral: false }) : null;
1163
1164
  if (target?.error) {
@@ -1166,10 +1167,36 @@ const commands = {
1166
1167
  }
1167
1168
  const targetProject = target?.project || (projects.length > 0 ? projects[0] : null);
1168
1169
  const wiPath = projectWorkItemsPath(targetProject);
1170
+ const archivePath = wiPath.replace(/\.json$/, '-archive.json');
1171
+
1172
+ // Caller-supplied id: validate and pre-check live + archive for collisions
1173
+ // BEFORE acquiring the work-items lock, so a rejection never mutates state.
1174
+ let requestedId = null;
1175
+ if (opts.id != null) {
1176
+ if (typeof opts.id !== 'string' || !opts.id.trim()) {
1177
+ console.log('Error: opts.id must be a non-empty string');
1178
+ process.exit(1);
1179
+ }
1180
+ requestedId = opts.id.trim();
1181
+ const liveItems = safeJsonArr(wiPath);
1182
+ const archivedItems = safeJsonArr(archivePath);
1183
+ if (liveItems.some(w => w?.id === requestedId) || archivedItems.some(w => w?.id === requestedId)) {
1184
+ console.log(`Error: work item id "${requestedId}" already exists in ${path.basename(wiPath)} or its archive`);
1185
+ process.exit(1);
1186
+ }
1187
+ }
1188
+
1169
1189
  let item;
1190
+ let collision = false;
1170
1191
  mutateWorkItems(wiPath, items => {
1192
+ const id = requestedId || ('W-' + uid());
1193
+ // Re-check inside the lock to close the TOCTOU race against other writers.
1194
+ if (items.some(w => w?.id === id)) {
1195
+ collision = true;
1196
+ return items;
1197
+ }
1171
1198
  item = {
1172
- id: `W${String(items.length + 1).padStart(3, '0')}`,
1199
+ id,
1173
1200
  title: title,
1174
1201
  type: opts.type || 'implement',
1175
1202
  status: WI_STATUS.QUEUED,
@@ -1184,7 +1211,12 @@ const commands = {
1184
1211
  items.push(item);
1185
1212
  });
1186
1213
 
1187
- console.log(`Queued work item: ${item.id} — ${item.title} (project: ${targetProject.name || 'default'})`);
1214
+ if (collision || !item) {
1215
+ console.log(`Error: work item id collision detected for "${requestedId || 'auto-generated'}"`);
1216
+ process.exit(1);
1217
+ }
1218
+
1219
+ console.log(`Queued work item: ${item.id} — ${item.title} (project: ${targetProject?.name || 'default'})`);
1188
1220
  console.log(` Type: ${item.type} | Priority: ${item.priority} | Agent: ${item.agent || 'auto'}`);
1189
1221
  },
1190
1222
 
package/engine/shared.js CHANGED
@@ -1716,7 +1716,7 @@ const ESCALATION_POLICY = {
1716
1716
  };
1717
1717
 
1718
1718
  // Structured completion protocol — fields agents must produce in ```completion blocks
1719
- const COMPLETION_FIELDS = ['status', 'summary', 'files_changed', 'tests', 'pr', 'pending', 'failure_class', 'retryable', 'needs_rerun', 'verdict', 'artifacts'];
1719
+ const COMPLETION_FIELDS = ['status', 'summary', 'files_changed', 'tests', 'pr', 'not_changed', 'failure_class', 'retryable', 'needs_rerun', 'verdict', 'artifacts'];
1720
1720
 
1721
1721
  const DEFAULT_AGENT_METRICS = {
1722
1722
  tasksCompleted: 0, tasksErrored: 0,
package/engine.js CHANGED
@@ -1649,7 +1649,6 @@ async function spawnAgent(dispatchItem, config) {
1649
1649
  errorReason = structuredCompletion
1650
1650
  ? String(
1651
1651
  structuredCompletion.summary
1652
- || structuredCompletion.pending
1653
1652
  || structuredCompletion.failure_class
1654
1653
  || `Agent reported ${structuredCompletion.status || 'failure'}`
1655
1654
  ).slice(0, 300)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@yemi33/minions",
3
- "version": "0.1.1894",
3
+ "version": "0.1.1895",
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"
@@ -67,7 +67,7 @@ Bias toward senior-engineer restraint:
67
67
  The engine provides a completion report path in the prompt and in `MINIONS_COMPLETION_REPORT`. Before exiting, write JSON there with the actual outcome:
68
68
 
69
69
  ```json
70
- {"status":"success","summary":"what changed and how it was validated","verdict":null,"pr":"PR id/url or N/A","failure_class":"N/A","retryable":false,"needs_rerun":false,"artifacts":[{"type":"note|plan|prd|pr|file","path":"relative/path/or/url","title":"short label"}]}
70
+ {"status":"success","summary":"what changed and how it was validated","verdict":null,"pr":"PR id/url or N/A","failure_class":"N/A","retryable":false,"needs_rerun":false,"not_changed":"adjacent X left alone; refactor Y declined as out of scope","artifacts":[{"type":"note|plan|prd|pr|file","path":"relative/path/or/url","title":"short label"}]}
71
71
  ```
72
72
 
73
73
  For the canonical schema — every field, the `failure_class` enum, `noop:true` semantics, `retryable` / `needs_rerun` shape, and the artifacts array — see `docs/completion-reports.md`. The JSON report is the primary signal; fenced `completion` blocks in stdout are accepted only as a fallback.