pi-goal-list-loop-audit 0.38.18 → 0.38.20
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 +13 -0
- package/docs/INDEX.md +1 -1
- package/extensions/completion-summary.ts +28 -0
- package/extensions/goal-continuation.ts +48 -5
- package/extensions/goal-loop-display.ts +15 -2
- package/extensions/loops/goal-auditor-hooks.ts +16 -4
- package/extensions/loops/goal-tools.ts +22 -4
- package/extensions/loops/goal-ui.ts +6 -0
- package/extensions/loops/goal.ts +1 -1
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,18 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.38.20 — approval-notify cleanup (2026-09-04)
|
|
4
|
+
|
|
5
|
+
### Fixed
|
|
6
|
+
- Approval chat notify no longer reprints the agent's pre-verdict recap verbatim: the stale `Next: <verdict pending>` line (which read as complete-before-verify next to the approval trailer) is stripped on every approval surface, and the chat notify is outcome + at most two informing details + approval trailer + archive record pointer (`buildApprovalChatLines`, `withoutStaleNext`). The transcript notice keeps the informing details minus the stale Next. Applied to all three `✓ done` paths (detached approval, manual-verify approval, no-audit complete).
|
|
7
|
+
- Field note: the 19:20 `...` cuts were v0.38.13 word-boundary `…` clips working as designed (every cut lands on a word boundary), not mid-word mangling — but five 120-char label lines still scan as soup, which the cap above addresses. The same session showed zero `terminal_completion_notice_*` events because the tab runs pre-v0.38.18 loaded code — `/reload` to pick up the notice path.
|
|
8
|
+
|
|
9
|
+
## 0.38.19 — disapproval response: dispatch stall root-cause + state clear (2026-09-04)
|
|
10
|
+
|
|
11
|
+
### Fixed
|
|
12
|
+
- Track 2 root cause (post-answer stall): the wait-for-idle send gate deferred an owed continuation forever when the session went phantom-busy — busy, nothing pending, zero stream (neonbreak: 35 re-arms, zero sends, 45m to the zombie abort). A busy session with nothing pending and no real stream for `GLLA_BUSY_SILENT_SEND_MS` (default 5m) is wedged, not working: the marker is now sent into pi's followUp queue instead (`goal_continuation_send_busy_bypass`, `busyBypass` on the sent event). Genuinely working sessions and loaded queues keep the old wait path.
|
|
13
|
+
- Track 3 state clear (stale waiting-verdict): `auditorDisplayPhase` projects `awaiting-verdict` only while the goal is still `auditing`. Closed goals (complete/aborted) and pre-archive snapshots carrying a stale running claim fall through to the quiet gate — no stale progress object can resurrect the wait after `goal_archived`.
|
|
14
|
+
- Both fixes carry behavioral MockPi regression tests with empirical fail-before (old code fails the new assertions, guards pass throughout): `tests/answered-question-dispatch.test.ts` (3), `tests/closed-goal-clears-waiting.test.ts` (2).
|
|
15
|
+
|
|
3
16
|
## 0.38.18 — completion/lifecycle field trilogy (2026-09-04)
|
|
4
17
|
|
|
5
18
|
### Fixed
|
package/docs/INDEX.md
CHANGED
|
@@ -18,7 +18,7 @@ For shipped docs, the relevant entry points are:
|
|
|
18
18
|
failback; v0.35.9 hardened cross-version npm tarball checks; v0.35.10
|
|
19
19
|
handles multi-entry npm dry-run reports; v0.35.11 accepts both npm report
|
|
20
20
|
shapes; v0.35.12 supports npm 12's keyed pack reports; v0.35.13 fixes stale-API recovery loops.
|
|
21
|
-
v0.35.14–v0.38.
|
|
21
|
+
v0.35.14–v0.38.20 continue through the supervisor freeze (`/glla pause`),
|
|
22
22
|
load hold, auditor picker parity, Windows launch fix, zombie-watchdog
|
|
23
23
|
subagent carve-out, due-wait backstop, the `/glla agents` visibility panel,
|
|
24
24
|
durable state-root selection, blank-until-resume auditor context, frozen
|
|
@@ -159,6 +159,34 @@ export function humanCompletionBrief(
|
|
|
159
159
|
return { outcome, details };
|
|
160
160
|
}
|
|
161
161
|
|
|
162
|
+
/** v0.38.20: the agent's `Next:` recap line goes stale the moment the
|
|
163
|
+
* verdict lands — reprinting it next to the approval trailer reads as
|
|
164
|
+
* complete-before-verify (field 2026-09-04: `Next: detached auditor
|
|
165
|
+
* verdict decides.` printed above `— auditor … approved.`). Every approval
|
|
166
|
+
* surface strips it; the full six-label record stays in the archive. */
|
|
167
|
+
export function withoutStaleNext(details: string[] | undefined): string[] {
|
|
168
|
+
return (details ?? []).filter((d) => !/^\s*Next\s*:/i.test(d));
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
/** v0.38.20: the approval chat notify — outcome first, at most two
|
|
172
|
+
* informing details (the full record lives in the archive and the
|
|
173
|
+
* transcript notice), then the approval trailer and the record pointer.
|
|
174
|
+
* Five 120-char label lines scan as soup, not a summary (field
|
|
175
|
+
* 2026-09-04); the stale Next never reaches the chat. */
|
|
176
|
+
export function buildApprovalChatLines(notice: {
|
|
177
|
+
outcome: string;
|
|
178
|
+
details: string[] | undefined;
|
|
179
|
+
approval: string;
|
|
180
|
+
record: string;
|
|
181
|
+
}): string[] {
|
|
182
|
+
return [
|
|
183
|
+
`✓ done — ${notice.outcome}`,
|
|
184
|
+
...withoutStaleNext(notice.details).slice(0, 2),
|
|
185
|
+
notice.approval,
|
|
186
|
+
notice.record,
|
|
187
|
+
];
|
|
188
|
+
}
|
|
189
|
+
|
|
162
190
|
/** Multi-line projection: one `Label: value` line per label with generous
|
|
163
191
|
* word-bounded values. This is the user-facing `✓ done` block — six short
|
|
164
192
|
* facts that stay scannable in chat. The single-line projection remains
|
|
@@ -330,6 +330,26 @@ export function sendRearmDelayMs(streak: number): number {
|
|
|
330
330
|
return 30_000;
|
|
331
331
|
}
|
|
332
332
|
|
|
333
|
+
/** v0.38.19 (track 2): how long a busy session with an owed send may go
|
|
334
|
+
* without real stream output before the marker is sent into pi's followUp
|
|
335
|
+
* queue anyway. 5m matches SEND_REARM_ESCALATE_SILENT_MS's definition of
|
|
336
|
+
* wedged silence, far below the ~45m zombie abort that used to be the only
|
|
337
|
+
* exit from a phantom-busy session. */
|
|
338
|
+
export function busySilentSendMs(): number {
|
|
339
|
+
const raw = Number(process.env.GLLA_BUSY_SILENT_SEND_MS ?? 5 * 60_000);
|
|
340
|
+
return Number.isFinite(raw) && raw >= 0 ? raw : 5 * 60_000;
|
|
341
|
+
}
|
|
342
|
+
|
|
343
|
+
/** v0.38.19 (track 2): true when the session's business is stale enough
|
|
344
|
+
* that waiting for idle is the stall, not patience. Requires observed
|
|
345
|
+
* stream history (lastRealActivityAt > 0): a session that never streamed
|
|
346
|
+
* in this process is ignorance, not evidence of wedging — it keeps the old
|
|
347
|
+
* wait path (storm → escalation → zombie abort). */
|
|
348
|
+
export function busySilentBypassDue(): boolean {
|
|
349
|
+
if (flags.lastRealActivityAt <= 0) return false;
|
|
350
|
+
return Date.now() - flags.lastRealActivityAt >= busySilentSendMs();
|
|
351
|
+
}
|
|
352
|
+
|
|
333
353
|
export function accountSendRearm(ctx: ExtensionContext, kind: "continuation" | "loop"): void {
|
|
334
354
|
const streak = kind === "continuation" ? ++continuationRearmStreak : ++flags.loopRearmStreak;
|
|
335
355
|
if (streak === 1) {
|
|
@@ -1225,12 +1245,35 @@ export function sendContinuation(goalId: string): void {
|
|
|
1225
1245
|
}
|
|
1226
1246
|
if (!guardGoalBeforeContinuation(ctx, "dispatch", goalId)) return;
|
|
1227
1247
|
if (!isActionableGoal()) return;
|
|
1248
|
+
// v0.38.19 (track 2): set when the busy-but-silent bypass below fires so
|
|
1249
|
+
// the sent ledger event carries the marker. The test hook for the stream
|
|
1250
|
+
// clock lives in loops/goal-ui.ts (__testOnlySetLastRealActivityAt).
|
|
1251
|
+
let busyBypass = false;
|
|
1228
1252
|
if (!ctx.isIdle() || ctx.hasPendingMessages()) {
|
|
1229
1253
|
accountSendRearm(ctx, "continuation");
|
|
1230
|
-
|
|
1231
|
-
//
|
|
1232
|
-
|
|
1233
|
-
|
|
1254
|
+
// v0.38.19 (track 2, auditor-required): busy-but-silent bypass. A
|
|
1255
|
+
// session that is busy with nothing pending and zero real stream for
|
|
1256
|
+
// busySilentSendMs is not doing work a followUp could corrupt — it is
|
|
1257
|
+
// wedged (neonbreak: answer in, 45m of phantom-busy, zero sends because
|
|
1258
|
+
// wait-for-idle never cleared). pi's followUp queue is the designed
|
|
1259
|
+
// vehicle for exactly this: the marker queues behind the stuck turn
|
|
1260
|
+
// instead of rearming into the void until the zombie abort. Genuinely
|
|
1261
|
+
// working sessions (fresh stream) and loaded queues (pending messages)
|
|
1262
|
+
// keep the old wait path.
|
|
1263
|
+
if (!ctx.isIdle() && !ctx.hasPendingMessages() && busySilentBypassDue()) {
|
|
1264
|
+
busyBypass = true;
|
|
1265
|
+
appendLedger(ctx.cwd, "goal_continuation_send_busy_bypass", {
|
|
1266
|
+
goalId,
|
|
1267
|
+
generation: flags.sessionGeneration,
|
|
1268
|
+
silentMs: Date.now() - flags.lastRealActivityAt,
|
|
1269
|
+
rearmStreak: continuationRearmStreak,
|
|
1270
|
+
});
|
|
1271
|
+
} else {
|
|
1272
|
+
continuationScheduledFor = goalId;
|
|
1273
|
+
// v0.28.29: backing-off cadence (was flat 50ms — 6,000 spins in 5m).
|
|
1274
|
+
continuationTimer = scheduleSessionTimeout(() => sendContinuation(goalId), sendRearmDelayMs(continuationRearmStreak));
|
|
1275
|
+
return;
|
|
1276
|
+
}
|
|
1234
1277
|
}
|
|
1235
1278
|
if (!flags.extensionApi || flags.extensionApiStale) return;
|
|
1236
1279
|
try {
|
|
@@ -1264,7 +1307,7 @@ export function sendContinuation(goalId: string): void {
|
|
|
1264
1307
|
lastContinuationSentPayload = { content, display: false }; // v0.34.88: verbatim retry payload
|
|
1265
1308
|
if (!dispatchAccepted(ctx, attempt)) return;
|
|
1266
1309
|
continuationRearmStreak = 0; continuationRearmSince = 0; // v0.28.5 (E3): an accepted dispatch clears the storm
|
|
1267
|
-
appendLedger(ctx.cwd, "goal_continuation_sent", { goalId, attemptId: attempt.id, generation: attempt.generation, kind, payloadChars: content.length });
|
|
1310
|
+
appendLedger(ctx.cwd, "goal_continuation_sent", { goalId, attemptId: attempt.id, generation: attempt.generation, kind, payloadChars: content.length, ...(busyBypass ? { busyBypass: true } : {}) });
|
|
1268
1311
|
// v0.35.37 (audit finding): the welcome-back recovery notice must fire
|
|
1269
1312
|
// EXACTLY ONCE per auto-resume. The payload above was built with the
|
|
1270
1313
|
// notice in it; once the dispatch is ACCEPTED the message has landed in
|
|
@@ -668,7 +668,15 @@ export function auditorDisplayPhase(g: Goal, audit: AuditDisplayProgress | null
|
|
|
668
668
|
const label = audit?.label?.toLowerCase() ?? "";
|
|
669
669
|
if (label === "queued") return "queued";
|
|
670
670
|
if (/infra|error|failed|blocked|no verdict/.test(label)) return "blocked";
|
|
671
|
-
|
|
671
|
+
// v0.38.19 (track 3, auditor-required): awaiting-verdict is a LIVE claim
|
|
672
|
+
// — a worker done, its verdict not yet applied. A closed goal (complete /
|
|
673
|
+
// aborted, or anything past auditing) can never be waiting: the verdict
|
|
674
|
+
// landed or the claim died with the archive. A stale progress object
|
|
675
|
+
// handed in for a closed goal must not resurrect the wait (junk-runner:
|
|
676
|
+
// session narrating "waiting on the auditor's verdict" after
|
|
677
|
+
// goal_archived complete). Stale timestamps fall through to the quiet
|
|
678
|
+
// gate below, which is true — no worker will ever speak again.
|
|
679
|
+
if (audit?.phase === "complete" && g.status === "auditing") return "awaiting-verdict";
|
|
672
680
|
const age = auditorActivityAge(audit, now);
|
|
673
681
|
if (age !== undefined && age > AUDITOR_QUIET_MS) {
|
|
674
682
|
// v0.37.0: progress-aware quiet gate. A tool that is still running INSIDE
|
|
@@ -691,7 +699,12 @@ export function auditorDisplayPhase(g: Goal, audit: AuditDisplayProgress | null
|
|
|
691
699
|
return "running";
|
|
692
700
|
return "quiet";
|
|
693
701
|
}
|
|
694
|
-
|
|
702
|
+
// Same lifecycle scope as above: a stale goal snapshot that still
|
|
703
|
+
// carries a running pendingCompletion must not project a wait either.
|
|
704
|
+
// (The archive strips pendingCompletion; this guards pre-archive
|
|
705
|
+
// snapshots read after the close.)
|
|
706
|
+
if (!audit && g.status === "auditing" && g.pendingCompletion?.phase === "running") return "awaiting-verdict";
|
|
707
|
+
if (!audit && g.pendingCompletion?.phase === "running") return "quiet";
|
|
695
708
|
return "running";
|
|
696
709
|
}
|
|
697
710
|
|
|
@@ -241,7 +241,7 @@ import {
|
|
|
241
241
|
pushCapped as pushRepetitionCapped,
|
|
242
242
|
} from "../goal-loop-repetition.js";
|
|
243
243
|
import { buildStatusText, buildWidgetLines, type AuditDisplayProgress } from "../goal-loop-display.js";
|
|
244
|
-
import { compactCompletionSummary, compactTerminalCompletionSummary, isGenericCompletionSummary, missingCompletionSummaryLabels, terminalHumanBrief } from "../completion-summary.js";
|
|
244
|
+
import { buildApprovalChatLines, compactCompletionSummary, compactTerminalCompletionSummary, isGenericCompletionSummary, missingCompletionSummaryLabels, terminalHumanBrief, withoutStaleNext } from "../completion-summary.js";
|
|
245
245
|
import {
|
|
246
246
|
defaultAgentDir,
|
|
247
247
|
resolveEffectiveSubagentModel,
|
|
@@ -1424,6 +1424,9 @@ async function retryStoredCompletionAudit(origin: CompletionAuditOrigin = "provi
|
|
|
1424
1424
|
archivePath: path.relative(liveCtx.cwd, archivedGoalPath(liveCtx.cwd, state.goal.id)) || archivedGoalPath(liveCtx.cwd, state.goal.id),
|
|
1425
1425
|
}, state.goal.completionSummary);
|
|
1426
1426
|
const approvalVia = `${origin === "manual" ? " on /goal verify" : origin === "session-recovery" ? " after session recovery" : " on the provider retry"}${fallbackUsed ? " after an auditor-model fallback" : ""}`;
|
|
1427
|
+
// v0.38.20: the chat record pointer. Computed pre-archive like the
|
|
1428
|
+
// recap/brief above (archiveCurrentGoal clears state.goal).
|
|
1429
|
+
const approvalRecord = `— record: ${path.relative(liveCtx.cwd, archivedGoalPath(liveCtx.cwd, state.goal.id)) || archivedGoalPath(liveCtx.cwd, state.goal.id)}`;
|
|
1427
1430
|
const archived = archiveCurrentGoal(liveCtx, "complete", `auditor ${result.model} approved (${origin})`);
|
|
1428
1431
|
if (!archived) {
|
|
1429
1432
|
// archiveCurrentGoal already preserved the live record and warned the
|
|
@@ -1441,8 +1444,15 @@ async function retryStoredCompletionAudit(origin: CompletionAuditOrigin = "provi
|
|
|
1441
1444
|
}
|
|
1442
1445
|
// v0.38.14: the chat notify is the human briefing — outcome first,
|
|
1443
1446
|
// filler labels dropped — while the external notify keeps the compact
|
|
1444
|
-
// single line (pager/sound safe).
|
|
1445
|
-
|
|
1447
|
+
// single line (pager/sound safe). v0.38.20: outcome + at most two
|
|
1448
|
+
// details + approval + record pointer; the agent's pre-verdict `Next:`
|
|
1449
|
+
// is stale the moment the verdict lands and never reaches the chat.
|
|
1450
|
+
liveCtx.ui.notify(buildApprovalChatLines({
|
|
1451
|
+
outcome: brief.outcome,
|
|
1452
|
+
details: brief.details,
|
|
1453
|
+
approval: `— auditor ${result.model} approved${approvalVia}.`,
|
|
1454
|
+
record: approvalRecord,
|
|
1455
|
+
}).join("\n"), "info");
|
|
1446
1456
|
notifyExternal(liveCtx, `Goal complete (auditor approved, ${origin}): ${recap}`);
|
|
1447
1457
|
// v0.38.18 (track 3): the toast above is ephemeral — without a
|
|
1448
1458
|
// transcript entry the session keeps narrating "waiting on the
|
|
@@ -1454,7 +1464,9 @@ async function retryStoredCompletionAudit(origin: CompletionAuditOrigin = "provi
|
|
|
1454
1464
|
sendTerminalCompletionNotice(liveCtx, {
|
|
1455
1465
|
goalId,
|
|
1456
1466
|
outcome: brief.outcome,
|
|
1457
|
-
|
|
1467
|
+
// v0.38.20: the transcript keeps the informing details, but the
|
|
1468
|
+
// stale pre-verdict `Next:` is stripped here too.
|
|
1469
|
+
details: [...withoutStaleNext(brief.details), `— auditor ${result.model} approved${approvalVia}.`],
|
|
1458
1470
|
});
|
|
1459
1471
|
}
|
|
1460
1472
|
return;
|
|
@@ -252,7 +252,7 @@ import {
|
|
|
252
252
|
pushCapped as pushRepetitionCapped,
|
|
253
253
|
} from "../goal-loop-repetition.js";
|
|
254
254
|
import { buildStatusText, buildWidgetLines, type AuditDisplayProgress } from "../goal-loop-display.js";
|
|
255
|
-
import { compactCompletionSummary, compactTerminalCompletionSummary, resolveCompletionSummary, terminalHumanBrief } from "../completion-summary.js";
|
|
255
|
+
import { buildApprovalChatLines, compactCompletionSummary, compactTerminalCompletionSummary, resolveCompletionSummary, terminalHumanBrief, withoutStaleNext } from "../completion-summary.js";
|
|
256
256
|
import {
|
|
257
257
|
defaultAgentDir,
|
|
258
258
|
resolveEffectiveSubagentModel,
|
|
@@ -1224,8 +1224,16 @@ function registerAgentTools(pi: any): void {
|
|
|
1224
1224
|
stopReason: terminalReason,
|
|
1225
1225
|
archivePath: path.relative(ctx.cwd, archivedGoalPath(ctx.cwd, terminalGoal.id)) || archivedGoalPath(ctx.cwd, terminalGoal.id),
|
|
1226
1226
|
});
|
|
1227
|
-
|
|
1228
|
-
|
|
1227
|
+
// v0.38.20: the command output keeps the informing details (stale
|
|
1228
|
+
// `Next:` stripped); the chat notify is outcome + approval +
|
|
1229
|
+
// record pointer like every other approval path.
|
|
1230
|
+
const briefBlock = [...withoutStaleNext(brief.details), `— completed without audit (your choice).`].join("\n");
|
|
1231
|
+
ctx.ui.notify(buildApprovalChatLines({
|
|
1232
|
+
outcome: brief.outcome,
|
|
1233
|
+
details: brief.details,
|
|
1234
|
+
approval: `— completed without audit (your choice).`,
|
|
1235
|
+
record: `— record: ${path.relative(ctx.cwd, archivedGoalPath(ctx.cwd, terminalGoal.id)) || archivedGoalPath(ctx.cwd, terminalGoal.id)}`,
|
|
1236
|
+
}).join("\n"), "info");
|
|
1229
1237
|
notifyExternal(ctx, `Goal complete without audit (user choice): ${recap}`);
|
|
1230
1238
|
return { content: [{ type: "text", text: `Goal marked complete without audit (user choice).\n\n${briefBlock}` }], details: {} };
|
|
1231
1239
|
}
|
|
@@ -1259,6 +1267,9 @@ function registerAgentTools(pi: any): void {
|
|
|
1259
1267
|
stopReason: terminalReason,
|
|
1260
1268
|
archivePath: path.relative(ctx.cwd, archivedGoalPath(ctx.cwd, state.goal.id)) || archivedGoalPath(ctx.cwd, state.goal.id),
|
|
1261
1269
|
}, state.goal.completionSummary);
|
|
1270
|
+
// v0.38.20: captured pre-archive — archiveCurrentGoal clears
|
|
1271
|
+
// state.goal, so the record pointer must be computed here.
|
|
1272
|
+
const manualArchiveRecord = `— record: ${path.relative(ctx.cwd, archivedGoalPath(ctx.cwd, state.goal.id)) || archivedGoalPath(ctx.cwd, state.goal.id)}`;
|
|
1262
1273
|
const archived = archiveCurrentGoal(ctx, "complete", terminalReason);
|
|
1263
1274
|
if (!archived) {
|
|
1264
1275
|
// The archive helper preserves the live objective and emits the
|
|
@@ -1274,7 +1285,14 @@ function registerAgentTools(pi: any): void {
|
|
|
1274
1285
|
appendLedger(ctx.cwd, "goal_archive_failed_after_approval", { goalId: state.goal?.id, origin: "manual-verify", model: result.model });
|
|
1275
1286
|
return { content: [{ type: "text", text: "The auditor approved, but the terminal archive could not be persisted. The goal is paused; fix persistence, resume, and retry complete_goal." }], details: {} };
|
|
1276
1287
|
}
|
|
1277
|
-
|
|
1288
|
+
// v0.38.20: same approval voice as the detached path — the stale
|
|
1289
|
+
// pre-verdict `Next:` never reaches the chat.
|
|
1290
|
+
ctx.ui.notify(buildApprovalChatLines({
|
|
1291
|
+
outcome: brief.outcome,
|
|
1292
|
+
details: brief.details,
|
|
1293
|
+
approval: `— auditor ${result.model} approved.`,
|
|
1294
|
+
record: manualArchiveRecord,
|
|
1295
|
+
}).join("\n"), "info");
|
|
1278
1296
|
notifyExternal(ctx, `Goal complete (auditor approved): ${recap}`);
|
|
1279
1297
|
return { content: [{ type: "text", text: `Goal approved by auditor ${result.model}.` }], details: {} };
|
|
1280
1298
|
}
|
|
@@ -1044,6 +1044,12 @@ function isContextStarvedRefused(): boolean {
|
|
|
1044
1044
|
export function __testOnlySetLastCompactionAt(at: number | null): void {
|
|
1045
1045
|
lastCompactionAt = at ?? 0;
|
|
1046
1046
|
}
|
|
1047
|
+
/** Test-only: set the real-stream clock directly so busy-silence scenarios
|
|
1048
|
+
* (answered question, phantom-busy host, zero stream) are drivable without
|
|
1049
|
+
* wall-clock waits. Exported through loops/goal.js like the other hooks. */
|
|
1050
|
+
export function __testOnlySetLastRealActivityAt(at: number): void {
|
|
1051
|
+
lastRealActivityAt = at;
|
|
1052
|
+
}
|
|
1047
1053
|
|
|
1048
1054
|
/** Test-only: expose the live activity projection without requiring a TUI
|
|
1049
1055
|
* renderer. This drives the same scope/timestamp checks used by refreshUI. */
|
package/extensions/loops/goal.ts
CHANGED
|
@@ -74,7 +74,7 @@ export {
|
|
|
74
74
|
__testOnlyResetOwnerSession,
|
|
75
75
|
__testOnlyRunFanOutListAuditFindings,
|
|
76
76
|
} from "./goal-session.js";
|
|
77
|
-
export { __testOnlySetLastCompactionAt, __testOnlyLoadState, __testOnlyRegisterAgentTools, __testOnlyRememberCtx, __testOnlyDisplayActivityFor, __testOnlyResetToolActivity } from "./goal-ui.js";
|
|
77
|
+
export { __testOnlySetLastCompactionAt, __testOnlyLoadState, __testOnlyRegisterAgentTools, __testOnlyRememberCtx, __testOnlyDisplayActivityFor, __testOnlyResetToolActivity, __testOnlySetLastRealActivityAt } from "./goal-ui.js";
|
|
78
78
|
export { auditorRetryPlan, runDetachedCompletionWithFallback, __testOnlySetAuditorRecoveryRetryDelay, __testOnlyResetAuditorRecoveryRuntime, type AuditorModelCandidate } from "./goal-auditor-hooks.js";
|
|
79
79
|
export { handleSettingChoice } from "./goal-settings-ui.js";
|
|
80
80
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "pi-goal-list-loop-audit",
|
|
3
|
-
"version": "0.38.
|
|
3
|
+
"version": "0.38.20",
|
|
4
4
|
"description": "Mission control for autonomous pi: interview-drafted goals, an audited task queue, and forever-loops (metric, spec, project-audit) that run for hours. A detached extension-less auditor process re-verifies every completion with raw evidence without holding the main pi turn; confirmed drafts, decision pauses and consent gates keep you in charge.",
|
|
5
5
|
"license": "AGPL-3.0-only",
|
|
6
6
|
"author": "dracon",
|