@getpipher/armory-fleet 0.12.3 → 0.12.4
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/README.md +2 -0
- package/package.json +1 -1
- package/src/tools/fleet.ts +8 -1
- package/src/workflows/builtin/adversarial-review.js +4 -4
- package/src/workflows/builtin/code-review.js +1 -1
- package/src/workflows/builtin/codebase-audit.js +1 -1
- package/src/workflows/builtin/deep-research.js +2 -2
- package/src/workflows/builtin/multi-perspective.js +2 -2
package/README.md
CHANGED
|
@@ -304,6 +304,8 @@ Workflows are authored in a JS DSL (`src/workflows/source.ts` parses; `vm-realm.
|
|
|
304
304
|
|
|
305
305
|
Every workflow run is **journaled** (`workflows/journal.ts`) and **resumable**. `edit-resume` replays the unchanged prefix from cache and re-runs only the edited suffix. `runtime/controller.ts` orchestrates; `runtime/pause-gate.ts` handles checkpoints; `runtime/adapters.ts` binds the controller to the fleet's spawn + accounting.
|
|
306
306
|
|
|
307
|
+
**Full JS DSL API reference:** [`docs/workflows.md`](./docs/workflows.md) — `export const meta`, `agent()`/`parallel()`/`pipeline()`/`phase()`, the 7 helpers, the script context, worked examples, and the error surface.
|
|
308
|
+
|
|
307
309
|
---
|
|
308
310
|
|
|
309
311
|
## Roadmap
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@getpipher/armory-fleet",
|
|
3
|
-
"version": "0.12.
|
|
3
|
+
"version": "0.12.4",
|
|
4
4
|
"private": false,
|
|
5
5
|
"description": "The armory suite's subagent orchestrator for the pi coding agent — a cross-harness, superpowers-native fleet where every agent is armory-native from birth.",
|
|
6
6
|
"license": "MIT",
|
package/src/tools/fleet.ts
CHANGED
|
@@ -125,7 +125,14 @@ async function handleControlAction(controller: WorkflowController, params: Fleet
|
|
|
125
125
|
if (!run) {
|
|
126
126
|
return { isError: true, content: [{ type: "text" as const, text: `workflow '${params.runId}' not found` }] }
|
|
127
127
|
}
|
|
128
|
-
|
|
128
|
+
// #37: surface the abort/failure reason in the status text (previously only `status` was shown —
|
|
129
|
+
// `workflow wf-x: aborted` with no WHY, leaving the orchestrator unable to tell a script error from
|
|
130
|
+
// a budget/timeout/signal abort). The `details.run.error` already carried it; this surfaces it in the
|
|
131
|
+
// headline text the model + user see first. Cap very long reasons to keep the status line concise.
|
|
132
|
+
const reason = (run.status === "aborted" || run.status === "failed") && run.error
|
|
133
|
+
? ` — ${run.error.length > 300 ? run.error.slice(0, 300) + `…(truncated from ${run.error.length} chars, see details.run.error)` : run.error}`
|
|
134
|
+
: "";
|
|
135
|
+
return { content: [{ type: "text" as const, text: `workflow ${run.runId}: ${run.status}${reason}` }], details: { run: summarizeRun(run) } }
|
|
129
136
|
}
|
|
130
137
|
|
|
131
138
|
if (control === "pause") {
|
|
@@ -6,13 +6,13 @@ export const meta = {
|
|
|
6
6
|
|
|
7
7
|
phase('Attack')
|
|
8
8
|
const vulns = await parallel([
|
|
9
|
-
() => agent('Find injection vulnerabilities in this code.', { tier: '
|
|
10
|
-
() => agent('Find logic errors and race conditions.', { tier: '
|
|
11
|
-
() => agent('Find authentication bypass vectors.', { tier: '
|
|
9
|
+
() => agent('Find injection vulnerabilities in this code.', { tier: 'standard' }),
|
|
10
|
+
() => agent('Find logic errors and race conditions.', { tier: 'standard' }),
|
|
11
|
+
() => agent('Find authentication bypass vectors.', { tier: 'standard' }),
|
|
12
12
|
])
|
|
13
13
|
|
|
14
14
|
phase('Defend')
|
|
15
|
-
const defenses = await parallel(vulns.map((v) => () => agent(`Propose a fix for: ${v}`, { tier: '
|
|
15
|
+
const defenses = await parallel(vulns.map((v) => () => agent(`Propose a fix for: ${v}`, { tier: 'economy' })))
|
|
16
16
|
|
|
17
17
|
phase('Judge')
|
|
18
18
|
const winner = await judgePanel([...vulns, ...defenses], { judges: 3, rubric: 'severity and fixability' })
|
|
@@ -6,7 +6,7 @@ export const meta = {
|
|
|
6
6
|
|
|
7
7
|
phase('Review')
|
|
8
8
|
const angles = ['security', 'correctness', 'performance', 'readability', 'edge-cases', 'tests', 'api-design']
|
|
9
|
-
const findings = await parallel(angles.map((angle) => () => agent(`Review this diff for ${angle} issues. Report concrete findings only.`, { tier: '
|
|
9
|
+
const findings = await parallel(angles.map((angle) => () => agent(`Review this diff for ${angle} issues. Report concrete findings only.`, { tier: 'standard' })))
|
|
10
10
|
|
|
11
11
|
phase('Verify')
|
|
12
12
|
const verified = await verify(findings.join('\n---\n'), { reviewers: 2, lens: 'false positives' })
|
|
@@ -6,7 +6,7 @@ export const meta = {
|
|
|
6
6
|
|
|
7
7
|
phase('Scan')
|
|
8
8
|
const files = await loopUntilDry({
|
|
9
|
-
round: (n) => n < 4 ? agent(`List files in dir ${n}. Return a JSON array of file path strings.`, { tier: '
|
|
9
|
+
round: (n) => n < 4 ? agent(`List files in dir ${n}. Return a JSON array of file path strings.`, { tier: 'economy', schema: { type: 'array' }, retries: 1 }) : [],
|
|
10
10
|
consecutiveEmpty: 2,
|
|
11
11
|
maxRounds: 6,
|
|
12
12
|
})
|
|
@@ -5,8 +5,8 @@ export const meta = {
|
|
|
5
5
|
}
|
|
6
6
|
|
|
7
7
|
phase('Discover')
|
|
8
|
-
const topics = await loopUntilDry({ round: (n) => n < 3 ? agent(`Find unique sources for round ${n}. Return a JSON array of source strings.`, { tier: '
|
|
8
|
+
const topics = await loopUntilDry({ round: (n) => n < 3 ? agent(`Find unique sources for round ${n}. Return a JSON array of source strings.`, { tier: 'economy', schema: { type: 'array' }, retries: 1 }) : [], consecutiveEmpty: 2, maxRounds: 5 })
|
|
9
9
|
|
|
10
10
|
phase('Synthesize')
|
|
11
|
-
const summary = await agent(`Synthesize these ${topics.length} sources into a coherent report.`, { tier: '
|
|
11
|
+
const summary = await agent(`Synthesize these ${topics.length} sources into a coherent report.`, { tier: 'standard' })
|
|
12
12
|
return { sources: topics, summary }
|
|
@@ -6,11 +6,11 @@ export const meta = {
|
|
|
6
6
|
|
|
7
7
|
phase('Review')
|
|
8
8
|
const personas = ['product manager', 'security engineer', 'UX designer', 'dev-ops lead']
|
|
9
|
-
const reviews = await parallel(personas.map((p) => () => agent(`Review this artifact as a ${p}. Focus on your domain only.`, { tier: '
|
|
9
|
+
const reviews = await parallel(personas.map((p) => () => agent(`Review this artifact as a ${p}. Focus on your domain only.`, { tier: 'standard' })))
|
|
10
10
|
|
|
11
11
|
phase('Merge')
|
|
12
12
|
const merged = await gate(
|
|
13
|
-
async (feedback, n) => n === 0 ? agent(`Initial synthesis of ${reviews.length} reviews.`, { tier: '
|
|
13
|
+
async (feedback, n) => n === 0 ? agent(`Initial synthesis of ${reviews.length} reviews.`, { tier: 'economy' }) : agent(`Revise synthesis: ${feedback}`, { tier: 'economy' }),
|
|
14
14
|
(v) => typeof v === 'string' && v.length > 100 ? { ok: true } : { ok: false, feedback: 'more detail needed' },
|
|
15
15
|
{ attempts: 3 },
|
|
16
16
|
)
|