@getpipher/armory-fleet 0.10.1 → 0.10.3
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/package.json +1 -1
- package/src/index.ts +3 -1
- package/src/panel/runs-rows.ts +3 -1
- package/src/panel/widget-rows.ts +4 -1
- package/src/runtime/reconcile.ts +17 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@getpipher/armory-fleet",
|
|
3
|
-
"version": "0.10.
|
|
3
|
+
"version": "0.10.3",
|
|
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/index.ts
CHANGED
|
@@ -258,7 +258,9 @@ export default async function (pi: ExtensionAPI): Promise<void> {
|
|
|
258
258
|
// SPEC-5b-1: per-session RunLog at .pi/fleet/conversations/ (separate from the
|
|
259
259
|
// SPEC-5a phase journal at .pi/fleet/runs/ — different granularity, no filename collision).
|
|
260
260
|
deps.runLog = new RunLog(join(dir, "conversations"));
|
|
261
|
-
|
|
261
|
+
// v0.10.2: pass the in-memory RunRegistry so reconcile syncs it too — otherwise orphaned
|
|
262
|
+
// (process-gone) runs keep status:"running" in memory and the live widget shows a stale ▶ forever.
|
|
263
|
+
const reconciled = reconcileRuns(deps.runLog, { runRegistry: deps.runRegistry });
|
|
262
264
|
if (reconciled.length > 0) {
|
|
263
265
|
ctx.ui.notify(`reconciled ${reconciled.length} interrupted fleet run${reconciled.length > 1 ? "s" : ""} (marked aborted)`, "info");
|
|
264
266
|
}
|
package/src/panel/runs-rows.ts
CHANGED
|
@@ -10,7 +10,9 @@ const STATUS_GLYPH: Record<RunMeta["status"], string> = {
|
|
|
10
10
|
|
|
11
11
|
export function runsRow(r: RunMeta, getModelContextWindow?: (model: string) => number | undefined): string {
|
|
12
12
|
const dur = r.endedAt ? fmtDuration(r.endedAt - r.startedAt) : "—";
|
|
13
|
-
|
|
13
|
+
// SPEC-6-1 fix: "tok" is the final context snapshot (contextTokens), NOT cumulative
|
|
14
|
+
// tokenTotal — it pairs with the ctx% segment (same metric).
|
|
15
|
+
const tok = r.contextTokens != null && r.contextTokens > 0 ? ` ${fmtTokens(r.contextTokens)} tok` : "";
|
|
14
16
|
const maxCtx = getModelContextWindow?.(r.model);
|
|
15
17
|
const ctx = (r.contextTokens != null && maxCtx != null && maxCtx > 0) ? ` ${Math.round(r.contextTokens / maxCtx * 100)}%` : "";
|
|
16
18
|
const cost = r.costTotal ? ` $${r.costTotal.toFixed(4)}` : "";
|
package/src/panel/widget-rows.ts
CHANGED
|
@@ -72,7 +72,10 @@ const STATUS_GLYPH: Record<WidgetRun["status"], string> = {
|
|
|
72
72
|
function widgetLine(r: WidgetRun, now: number): string {
|
|
73
73
|
const glyph = STATUS_GLYPH[r.status];
|
|
74
74
|
const dur = typeof r.startedAt === "number" ? ` ${fmtDuration(now - r.startedAt)}` : "";
|
|
75
|
-
|
|
75
|
+
// SPEC-6-1 fix: "tok" is the live context snapshot (contextTokens), NOT cumulative
|
|
76
|
+
// tokenTotal — it pairs with the ctx% segment (same metric). Showing tokenTotal here
|
|
77
|
+
// ballooned to 6.7M on long runs (cumulative re-sends) next to a 35% ctx, looking broken.
|
|
78
|
+
const tok = r.contextTokens != null ? ` ${fmtTokens(r.contextTokens)} tok` : "";
|
|
76
79
|
const ctx = (r.contextTokens != null && r.maxContext != null && r.maxContext > 0) ? ` ${Math.round(r.contextTokens / r.maxContext * 100)}%` : "";
|
|
77
80
|
const cost = r.costTotal ? ` $${r.costTotal.toFixed(4)}` : "";
|
|
78
81
|
|
package/src/runtime/reconcile.ts
CHANGED
|
@@ -2,19 +2,32 @@
|
|
|
2
2
|
// SPEC-5b-1 — on pi boot, mark orphan RunLog runs (run:meta with no run:ended whose process
|
|
3
3
|
// is gone) as aborted so the Runs tab doesn't show stale "running" rows across restarts.
|
|
4
4
|
// Foreground orphans; bg/lifecycle orphans are already handled by scanResumeCandidates (SPEC-5a).
|
|
5
|
+
//
|
|
6
|
+
// v0.10.2 patch: reconcile now ALSO syncs the in-memory RunRegistry (opts.runRegistry). Before this,
|
|
7
|
+
// reconcile only wrote run:ended: aborted to the durable RunLog — the in-memory RunRegistry kept
|
|
8
|
+
// status:"running", so the live above-editor widget (filterActive keeps running|queued|paused)
|
|
9
|
+
// rendered a stale ▶ row that ticked forever for every orphaned (process-gone) run.
|
|
5
10
|
import type { RunLog } from "./run-log.ts";
|
|
11
|
+
import type { RunRegistry } from "../engine/run-registry.ts";
|
|
6
12
|
|
|
7
13
|
export interface ReconcileOpts {
|
|
8
14
|
/** Orphans whose startedAt is older than (now - graceMs) are marked aborted. Default 60000. */
|
|
9
15
|
graceMs?: number;
|
|
10
16
|
/** Test injection. Default Date.now(). */
|
|
11
17
|
now?: number;
|
|
18
|
+
/**
|
|
19
|
+
* v0.10.2: the in-memory RunRegistry to sync alongside the durable log. When set, each orphan
|
|
20
|
+
* reconciled in the log is also transitioned to status:"aborted" in memory so the live widget
|
|
21
|
+
* clears its stale ▶ row. Optional — existing callers that pass only a RunLog are unaffected.
|
|
22
|
+
*/
|
|
23
|
+
runRegistry?: RunRegistry;
|
|
12
24
|
}
|
|
13
25
|
|
|
14
26
|
/** Returns the runIds it marked aborted. Idempotent: a run already ended is skipped. */
|
|
15
27
|
export function reconcileRuns(log: RunLog, opts: ReconcileOpts = {}): string[] {
|
|
16
28
|
const grace = opts.graceMs ?? 60_000;
|
|
17
29
|
const now = opts.now ?? Date.now();
|
|
30
|
+
const reg = opts.runRegistry;
|
|
18
31
|
const aborted: string[] = [];
|
|
19
32
|
for (const meta of log.scanMeta()) {
|
|
20
33
|
if (meta.status !== "running") continue;
|
|
@@ -23,6 +36,10 @@ export function reconcileRuns(log: RunLog, opts: ReconcileOpts = {}): string[] {
|
|
|
23
36
|
type: "run:ended", runId: meta.runId, status: "aborted",
|
|
24
37
|
endedAt: now, resultSummary: "process-gone", tokenTotal: meta.tokenTotal,
|
|
25
38
|
});
|
|
39
|
+
// v0.10.2: sync the in-memory registry so the live widget (which reads runRegistry.list(),
|
|
40
|
+
// not the RunLog) clears the orphan's stale ▶ row. No-op when the run isn't in the registry
|
|
41
|
+
// (e.g. a cross-cwd orphan from another session — out of scope for this patch).
|
|
42
|
+
reg?.update(meta.runId, { status: "aborted", endedAt: now });
|
|
26
43
|
aborted.push(meta.runId);
|
|
27
44
|
}
|
|
28
45
|
return aborted;
|