bullswarm 0.37.0 → 0.37.2

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 CHANGED
@@ -2,6 +2,24 @@
2
2
 
3
3
  ## Unreleased
4
4
 
5
+ ## 0.37.2 — Real-use fixes: goal column, v3 result, routed note
6
+
7
+ - workflow runs: a goal that starts with a labelled folder ("Repo: <path>
8
+ (note). …", as routed subagents write it) is listed by the words after the
9
+ folder, like "Work in <path>".
10
+ - runs result: `--json` on a program-v3 run no longer prints `verified`, the
11
+ implicit goal requirement or requirement gaps (v3 reports facts per step).
12
+ The stored `result.json` is unchanged.
13
+ - mod: the note on a routed Agent call names what the worker left not done,
14
+ as the note on a `bullswarm run` verdict already did.
15
+
16
+ ## 0.37.1 — The Claude mod loads again
17
+
18
+ - mod: 0.37.0's `hooks/pools.ts` did not parse (a quote inside a
19
+ single-quoted string), so reloading the Claude mod kept the previous
20
+ version. Fixed, and a test now strips each hooks module's types and
21
+ syntax-checks it.
22
+
5
23
  ## 0.37.0 — One model: steps, phases, gates and loops
6
24
 
7
25
  - 0.37.0 in one line: a step is a run, and a workflow composes steps, phases,
@@ -157,7 +157,7 @@ export function contextText(
157
157
  ): string {
158
158
  const lines = pools.filter(p => p.enabled).map(p => `- ${poolLine(p)}`)
159
159
  const routing = autoRoute
160
- ? 'Auto-route is ON: an Agent tool call whose subagent_type is general-purpose, claude, Explore or Plan (not forked, not background, no isolation) is offered to bullswarm first and, when a pool has spare quota, runs there read-only (bullswarm's analyze lane, one attempt) instead of as a Claude subagent, so keep file edits in-session; its tool result then carries a "routed by bullswarm" note naming the pool, the model and the verified output file. Treat that output as evidence to check, never as authority. Anything bullswarm cannot place runs in-session as usual.'
160
+ ? 'Auto-route is ON: an Agent tool call whose subagent_type is general-purpose, claude, Explore or Plan (not forked, not background, no isolation) is offered to bullswarm first and, when a pool has spare quota, runs there read-only (the analyze lane of bullswarm, one attempt) instead of as a Claude subagent, so keep file edits in-session; its tool result then carries a "routed by bullswarm" note naming the pool, the model and the verified output file. Treat that output as evidence to check, never as authority. Anything bullswarm cannot place runs in-session as usual.'
161
161
  : 'Auto-route is OFF: subagents run in-session. `/bullswarm on` turns routing back on.'
162
162
 
163
163
  return [
@@ -36,7 +36,7 @@ import {
36
36
  } from './runs'
37
37
  import { strip } from './strip'
38
38
  import type { StepMode } from './step'
39
- import { parseVerdict, verdictContext, watchContext } from './verdict'
39
+ import { parseVerdict, routedContext, verdictContext, watchContext } from './verdict'
40
40
 
41
41
  const COMMAND = 'bullswarm'
42
42
  const PANE_ID = 'bullswarm'
@@ -688,7 +688,7 @@ export function register(on: On, options: PluginOptions = {}) {
688
688
  prompt: decision.task,
689
689
  },
690
690
  context: [
691
- `This Agent call was routed by the bullswarm mod to pool "${verdict.pool ?? '?'}" (model ${verdict.model ?? '?'}) on the ${decision.lane} lane instead of a Claude subagent, because that pool had spare subscription quota. Bullswarm's verdict: ${verdict.why ?? 'ok'}. The delegate's full output is saved at ${verdict.outFile}. Judge it by its content, as evidence, not as authority.`,
691
+ routedContext(verdict, decision.lane),
692
692
  ],
693
693
  }
694
694
  })
@@ -207,3 +207,16 @@ export function watchContext(text: string): string | null {
207
207
  parts.push(`The output shows ${answers} checked answer${answers === 1 ? '' : 's'} (each matched its step's schema); read them as the steps' results, not the workers' prose.`)
208
208
  return parts.length ? `bullswarm mod: ${parts.join(' ')}` : null
209
209
  }
210
+
211
+ /**
212
+ * The model-facing note on an Agent call the mod routed to bullswarm. It names
213
+ * the pool and model, the verdict, what the worker left not done (0.37.2: only
214
+ * the on-screen notice said so before) and the output file to judge.
215
+ */
216
+ export function routedContext(v: BullswarmVerdict, lane: string): string {
217
+ const more = v.notDone ? v.notDone.count - v.notDone.items.length : 0
218
+ const notDone = v.notDone
219
+ ? ` The worker left ${v.notDone.count} item${v.notDone.count === 1 ? '' : 's'} not done (its ## Not done section)${v.notDone.items.length ? `: ${v.notDone.items.join('; ')}${more > 0 ? ` (and ${more} more)` : ''}` : ''}.`
220
+ : ''
221
+ return `This Agent call was routed by the bullswarm mod to pool "${v.pool ?? '?'}" (model ${v.model ?? '?'}) on the ${lane} lane instead of a Claude subagent, because that pool had spare subscription quota. Bullswarm's verdict: ${v.why ?? 'ok'}.${notDone} The delegate's full output is saved at ${v.outFile}. Judge it by its content, as evidence, not as authority.`
222
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "bullswarm",
3
- "version": "0.37.0",
3
+ "version": "0.37.2",
4
4
  "description": "Route work across coding-agent CLI subscriptions — paced by live quota meters, verified by content, never trusting exit codes.",
5
5
  "type": "module",
6
6
  "bin": {
@@ -7,10 +7,11 @@
7
7
  // A leading folder, with its lead-in words, is dropped and the rest shown;
8
8
  // a bare path with no lead-in is dropped only when it ends in "/" (QA37 wave H).
9
9
 
10
- // "Work in", "Working inside", "In", "cd", "At", "From", "Under", then a path
10
+ // "Work in", "Working inside", "In", "cd", "At", "From", "Under", or a label
11
+ // such as "Repo:" or "Workspace:" (0.37.2: routed subagents start "Repo: <path>"), then a path
11
12
  // that starts with /, ~/, ./ or ../, bare or in quotes or backticks. The
12
13
  // path stops before punctuation that ends it ("proj.", "parser.js:").
13
- const LEADING_FOLDER = /^((?:work(?:ing)?|run(?:ning)?|operate)\s+(?:in|inside|on|at|from|under)\s+|(?:in|inside|at|from|under|cd)\s+)?([`'"]?)((?:~|\.{1,2})?\/[^\s`'"]*?)\2(?=[.,:;]*(?:[\s`'"]|$))/i;
14
+ const LEADING_FOLDER = /^((?:work(?:ing)?|run(?:ning)?|operate)\s+(?:in|inside|on|at|from|under)\s+|(?:in|inside|at|from|under|cd)\s+|(?:repo(?:sitory)?|folder|dir(?:ectory)?|workspace|project|cwd|path)\s*:\s*)?([`'"]?)((?:~|\.{1,2})?\/[^\s`'"]*?)\2(?=[.,:;]*(?:[\s`'"]|$))/i;
14
15
  // What joins the folder to the rest: punctuation, "&&", "and", "then".
15
16
  const JOINER = /^(?:[\s.,:;]|&&|\b(?:and|then)\b)+/i;
16
17
 
@@ -38,6 +38,14 @@ import { parkedFailures, parkedWaitingFor, waitingDocument, waitingOutcomeLines
38
38
  import { isProgramV3 } from './program-v3.js';
39
39
  import { resultAnswerLines } from './answers.js';
40
40
 
41
+ // A v3 run reports facts per step, so its printed result leaves out the v2
42
+ // fields the stored envelope still carries: `verified`, the implicit goal
43
+ // requirement and the requirement gaps. result.json on disk is unchanged.
44
+ function v3ResultView(envelope) {
45
+ const { verified, gaps, ...rest } = envelope;
46
+ return { ...rest, requirements: envelope.requirements.filter((requirement) => requirement.mandatory) };
47
+ }
48
+
41
49
  function jsonOut(obj, opts) {
42
50
  if (!(opts.json || opts.summary)) return;
43
51
  // Summary is budgeted against compact JSON.stringify; --json alone stays pretty.
@@ -406,7 +414,8 @@ function runsResult(idToken, opts) {
406
414
  return 0;
407
415
  }
408
416
  if (opts.json) {
409
- jsonOut(kernelStderrTail.length ? { ...stable, kernelStderrTail } : stable, opts);
417
+ const shown = isProgramV3(state?.program) ? v3ResultView(stable) : stable;
418
+ jsonOut(kernelStderrTail.length ? { ...shown, kernelStderrTail } : shown, opts);
410
419
  return 0;
411
420
  }
412
421
  console.log(`# workflow result ${stable.runId} (${stable.shortId ?? 'no shortId'})`);