@linimin/pi-letscook 0.1.31 → 0.1.33
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 +14 -0
- package/extensions/completion/index.ts +226 -57
- package/package.json +1 -1
- package/scripts/smoke-test.sh +21 -0
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,19 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.1.33
|
|
4
|
+
|
|
5
|
+
### Changed
|
|
6
|
+
|
|
7
|
+
- kept full mission text in `/cook` confirmation instead of truncating mission anchors during derivation
|
|
8
|
+
- refined `/cook` activity and completion-role text contrast by reducing overuse of `dim` styling in high-value status surfaces
|
|
9
|
+
|
|
10
|
+
## 0.1.32
|
|
11
|
+
|
|
12
|
+
### Changed
|
|
13
|
+
|
|
14
|
+
- made `/cook` auto-continue workflows from canonical state when `continuation_policy == continue`, so the primary driver re-queues the canonical resume prompt after intermediate role turns instead of parking silently on known mandatory steps
|
|
15
|
+
- added smoke coverage for the new auto-resume driver prompt behavior and a guarded parked-state warning path to avoid infinite requeue loops on an unchanged mandatory state
|
|
16
|
+
|
|
3
17
|
## 0.1.31
|
|
4
18
|
|
|
5
19
|
### Changed
|
|
@@ -203,7 +203,7 @@ class StartupAnalystOverlay extends Container {
|
|
|
203
203
|
|
|
204
204
|
private updateDisplay(): void {
|
|
205
205
|
this.title.setText(this.theme.fg("accent", this.theme.bold("/cook proposal analyst")));
|
|
206
|
-
this.body.setText(this.theme
|
|
206
|
+
this.body.setText(formatInlineRunningText(this.theme, this.lines, { primaryAssistant: true }));
|
|
207
207
|
this.footer.setText(this.theme.fg("muted", "Esc cancel • This analysis runs before /cook writes canonical workflow state"));
|
|
208
208
|
}
|
|
209
209
|
|
|
@@ -225,6 +225,16 @@ const liveRoleActivityByRoot = new Map<string, LiveRoleActivity>();
|
|
|
225
225
|
const LIVE_ROLE_WAITING_MS = 15_000;
|
|
226
226
|
const LIVE_ROLE_STALLED_MS = 45_000;
|
|
227
227
|
const LIVE_ROLE_HEARTBEAT_MS = 5_000;
|
|
228
|
+
const DRIVER_AUTO_CONTINUE_MAX_ATTEMPTS = 2;
|
|
229
|
+
|
|
230
|
+
type DriverContinuationTracker = {
|
|
231
|
+
fingerprint: string;
|
|
232
|
+
attempts: number;
|
|
233
|
+
inFlight: boolean;
|
|
234
|
+
warned: boolean;
|
|
235
|
+
};
|
|
236
|
+
|
|
237
|
+
const driverContinuationByRoot = new Map<string, DriverContinuationTracker>();
|
|
228
238
|
|
|
229
239
|
function isRecord(value: unknown): value is JsonRecord {
|
|
230
240
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
@@ -529,6 +539,14 @@ function completionTestDriverPromptPath(): string | undefined {
|
|
|
529
539
|
return asString(process.env.PI_COMPLETION_TEST_DRIVER_PROMPT_PATH);
|
|
530
540
|
}
|
|
531
541
|
|
|
542
|
+
function completionTestAutoContinuePromptPath(): string | undefined {
|
|
543
|
+
return asString(process.env.PI_COMPLETION_TEST_AUTO_CONTINUE_PROMPT_PATH);
|
|
544
|
+
}
|
|
545
|
+
|
|
546
|
+
function shouldTestAutoContinueOnSessionStart(): boolean {
|
|
547
|
+
return process.env.PI_COMPLETION_TEST_AUTO_CONTINUE_ON_SESSION_START === "1";
|
|
548
|
+
}
|
|
549
|
+
|
|
532
550
|
function completionTestSystemReminderPath(): string | undefined {
|
|
533
551
|
return asString(process.env.PI_COMPLETION_TEST_SYSTEM_REMINDER_PATH);
|
|
534
552
|
}
|
|
@@ -1641,6 +1659,128 @@ function currentEvaluationProfile(snapshot: CompletionStateSnapshot): string | u
|
|
|
1641
1659
|
);
|
|
1642
1660
|
}
|
|
1643
1661
|
|
|
1662
|
+
function completionContinuationFingerprint(snapshot: CompletionStateSnapshot): string | undefined {
|
|
1663
|
+
if (asString(snapshot.state?.continuation_policy) !== "continue") return undefined;
|
|
1664
|
+
const nextMandatoryRole = asString(snapshot.state?.next_mandatory_role);
|
|
1665
|
+
if (!nextMandatoryRole) return undefined;
|
|
1666
|
+
return JSON.stringify({
|
|
1667
|
+
mission_anchor: asString(snapshot.state?.mission_anchor) ?? asString(snapshot.plan?.mission_anchor) ?? null,
|
|
1668
|
+
task_type: currentTaskType(snapshot) ?? null,
|
|
1669
|
+
evaluation_profile: currentEvaluationProfile(snapshot) ?? null,
|
|
1670
|
+
current_phase: asString(snapshot.state?.current_phase) ?? null,
|
|
1671
|
+
next_mandatory_role: nextMandatoryRole,
|
|
1672
|
+
next_mandatory_action: asString(snapshot.state?.next_mandatory_action) ?? null,
|
|
1673
|
+
active_status: asString(snapshot.active?.status) ?? null,
|
|
1674
|
+
active_slice_id: asString(snapshot.active?.slice_id) ?? asString(snapshot.activeSlice?.slice_id) ?? null,
|
|
1675
|
+
latest_completed_slice: asString(snapshot.state?.latest_completed_slice) ?? null,
|
|
1676
|
+
latest_verified_slice: asString(snapshot.state?.latest_verified_slice) ?? null,
|
|
1677
|
+
});
|
|
1678
|
+
}
|
|
1679
|
+
|
|
1680
|
+
function noteQueuedDriverPrompt(rootKey: string, fingerprint: string): void {
|
|
1681
|
+
const tracker = driverContinuationByRoot.get(rootKey);
|
|
1682
|
+
if (tracker && tracker.fingerprint === fingerprint) {
|
|
1683
|
+
tracker.attempts += 1;
|
|
1684
|
+
tracker.inFlight = false;
|
|
1685
|
+
tracker.warned = false;
|
|
1686
|
+
return;
|
|
1687
|
+
}
|
|
1688
|
+
driverContinuationByRoot.set(rootKey, {
|
|
1689
|
+
fingerprint,
|
|
1690
|
+
attempts: 1,
|
|
1691
|
+
inFlight: false,
|
|
1692
|
+
warned: false,
|
|
1693
|
+
});
|
|
1694
|
+
}
|
|
1695
|
+
|
|
1696
|
+
function markQueuedDriverPromptInFlight(rootKey: string, fingerprint: string): void {
|
|
1697
|
+
const tracker = driverContinuationByRoot.get(rootKey);
|
|
1698
|
+
if (!tracker || tracker.fingerprint !== fingerprint) return;
|
|
1699
|
+
tracker.inFlight = true;
|
|
1700
|
+
}
|
|
1701
|
+
|
|
1702
|
+
function clearDriverContinuationTracker(rootKey: string): void {
|
|
1703
|
+
driverContinuationByRoot.delete(rootKey);
|
|
1704
|
+
}
|
|
1705
|
+
|
|
1706
|
+
function hasRunningCompletionRole(rootKey: string): boolean {
|
|
1707
|
+
return liveRoleActivityByRoot.get(rootKey)?.status === "running";
|
|
1708
|
+
}
|
|
1709
|
+
|
|
1710
|
+
function isWorkflowDriverActive(snapshot: CompletionStateSnapshot | undefined): boolean {
|
|
1711
|
+
return Boolean(snapshot) && asString(snapshot?.state?.continuation_policy) === "continue";
|
|
1712
|
+
}
|
|
1713
|
+
|
|
1714
|
+
function isDriverContinuationStateParked(rootKey: string, fingerprint: string): boolean {
|
|
1715
|
+
const tracker = driverContinuationByRoot.get(rootKey);
|
|
1716
|
+
if (!tracker || tracker.fingerprint !== fingerprint) return false;
|
|
1717
|
+
return tracker.warned;
|
|
1718
|
+
}
|
|
1719
|
+
|
|
1720
|
+
function rememberParkedDriverContinuation(rootKey: string, fingerprint: string): void {
|
|
1721
|
+
const tracker = driverContinuationByRoot.get(rootKey);
|
|
1722
|
+
if (!tracker || tracker.fingerprint !== fingerprint) return;
|
|
1723
|
+
tracker.warned = true;
|
|
1724
|
+
tracker.inFlight = false;
|
|
1725
|
+
}
|
|
1726
|
+
|
|
1727
|
+
async function queueCompletionDriverPrompt(
|
|
1728
|
+
pi: ExtensionAPI,
|
|
1729
|
+
ctx: { cwd: string; hasUI: boolean; ui: any },
|
|
1730
|
+
rootKey: string,
|
|
1731
|
+
fingerprint: string,
|
|
1732
|
+
prompt: string,
|
|
1733
|
+
kind: "kickoff" | "resume" | "auto-resume",
|
|
1734
|
+
): Promise<boolean> {
|
|
1735
|
+
const snapshotPath = kind === "auto-resume" ? completionTestAutoContinuePromptPath() : completionTestDriverPromptPath();
|
|
1736
|
+
maybeWriteTestSnapshot(snapshotPath, `${prompt}\n`);
|
|
1737
|
+
noteQueuedDriverPrompt(rootKey, fingerprint);
|
|
1738
|
+
if (shouldSkipDriverKickoffForTests()) {
|
|
1739
|
+
emitCommandText(ctx, `Skipped completion workflow ${kind} prompt (test mode)`, "info");
|
|
1740
|
+
return false;
|
|
1741
|
+
}
|
|
1742
|
+
pi.sendUserMessage(prompt);
|
|
1743
|
+
emitCommandText(ctx, `Queued completion workflow ${kind}`, "info");
|
|
1744
|
+
return true;
|
|
1745
|
+
}
|
|
1746
|
+
|
|
1747
|
+
async function autoContinueWorkflowIfNeeded(pi: ExtensionAPI, ctx: { cwd: string; hasUI: boolean; ui: any }): Promise<void> {
|
|
1748
|
+
if (roleFromEnv()) return;
|
|
1749
|
+
const snapshot = await loadCompletionSnapshot(getCtxCwd(ctx));
|
|
1750
|
+
const rootKey = completionRootKey(snapshot, getCtxCwd(ctx));
|
|
1751
|
+
if (!snapshot) {
|
|
1752
|
+
clearDriverContinuationTracker(rootKey);
|
|
1753
|
+
return;
|
|
1754
|
+
}
|
|
1755
|
+
const fingerprint = completionContinuationFingerprint(snapshot);
|
|
1756
|
+
if (!fingerprint) {
|
|
1757
|
+
clearDriverContinuationTracker(rootKey);
|
|
1758
|
+
return;
|
|
1759
|
+
}
|
|
1760
|
+
if (!isWorkflowDriverActive(snapshot) || hasRunningCompletionRole(rootKey)) return;
|
|
1761
|
+
const tracker = driverContinuationByRoot.get(rootKey);
|
|
1762
|
+
if (tracker && tracker.fingerprint === fingerprint) {
|
|
1763
|
+
if (tracker.inFlight) {
|
|
1764
|
+
tracker.inFlight = false;
|
|
1765
|
+
if (tracker.attempts >= DRIVER_AUTO_CONTINUE_MAX_ATTEMPTS) {
|
|
1766
|
+
if (!isDriverContinuationStateParked(rootKey, fingerprint)) {
|
|
1767
|
+
rememberParkedDriverContinuation(rootKey, fingerprint);
|
|
1768
|
+
emitCommandText(
|
|
1769
|
+
ctx,
|
|
1770
|
+
`Completion workflow is parked before mandatory role dispatch: ${asString(snapshot.state?.next_mandatory_role) ?? "(unknown)"}. Rerun /cook to continue from canonical state.`,
|
|
1771
|
+
"warning",
|
|
1772
|
+
);
|
|
1773
|
+
}
|
|
1774
|
+
return;
|
|
1775
|
+
}
|
|
1776
|
+
} else {
|
|
1777
|
+
return;
|
|
1778
|
+
}
|
|
1779
|
+
}
|
|
1780
|
+
const resumePrompt = completionResumePrompt(currentTaskType(snapshot) ?? "(missing)", currentEvaluationProfile(snapshot) ?? "(missing)");
|
|
1781
|
+
await queueCompletionDriverPrompt(pi, ctx, rootKey, fingerprint, resumePrompt, "auto-resume");
|
|
1782
|
+
}
|
|
1783
|
+
|
|
1644
1784
|
function isRubricEvaluationRole(role: string | undefined): role is RubricEvaluationRole {
|
|
1645
1785
|
return RUBRIC_EVALUATION_ROLES.includes(role as RubricEvaluationRole);
|
|
1646
1786
|
}
|
|
@@ -1806,10 +1946,6 @@ function deriveMissionAnchor(rawGoal: string, projectName: string): string {
|
|
|
1806
1946
|
.replace(/\bwith docs\b/gi, "with docs parity")
|
|
1807
1947
|
.trim();
|
|
1808
1948
|
|
|
1809
|
-
if (mission.length > 120) {
|
|
1810
|
-
mission = `${mission.slice(0, 117).trimEnd()}...`;
|
|
1811
|
-
}
|
|
1812
|
-
|
|
1813
1949
|
if (!/[.!?。!?]$/u.test(mission)) mission += ".";
|
|
1814
1950
|
return mission;
|
|
1815
1951
|
}
|
|
@@ -2798,6 +2934,53 @@ function collapseRecentActivity(items: string[], maxItems = 4): string[] {
|
|
|
2798
2934
|
return collapsed.slice(-maxItems);
|
|
2799
2935
|
}
|
|
2800
2936
|
|
|
2937
|
+
function formatInlineRunningText(theme: any, lines: string[], options?: { primaryAssistant?: boolean }): string {
|
|
2938
|
+
let text = "";
|
|
2939
|
+
for (const [index, line] of lines.entries()) {
|
|
2940
|
+
if (index > 0) text += "\n";
|
|
2941
|
+
if (index === 0) {
|
|
2942
|
+
const [prefix, ...rest] = line.split(" ");
|
|
2943
|
+
text += theme.fg("warning", prefix);
|
|
2944
|
+
if (rest.length > 0) text += ` ${theme.fg("accent", rest.join(" "))}`;
|
|
2945
|
+
continue;
|
|
2946
|
+
}
|
|
2947
|
+
if (line.startsWith("tool:") || line.startsWith("progress:")) {
|
|
2948
|
+
text += theme.fg("toolOutput", line);
|
|
2949
|
+
continue;
|
|
2950
|
+
}
|
|
2951
|
+
if (line.startsWith("activity:")) {
|
|
2952
|
+
text += theme.fg(line.includes("stalled") ? "warning" : "dim", line);
|
|
2953
|
+
continue;
|
|
2954
|
+
}
|
|
2955
|
+
if (line === "recent tools:") {
|
|
2956
|
+
text += theme.fg("muted", line);
|
|
2957
|
+
continue;
|
|
2958
|
+
}
|
|
2959
|
+
if (line.startsWith("- ")) {
|
|
2960
|
+
text += `${theme.fg("muted", "- ")}${theme.fg("muted", line.slice(2))}`;
|
|
2961
|
+
continue;
|
|
2962
|
+
}
|
|
2963
|
+
if (line.startsWith("elapsed:")) {
|
|
2964
|
+
text += theme.fg("dim", line);
|
|
2965
|
+
continue;
|
|
2966
|
+
}
|
|
2967
|
+
if (line.startsWith("assistant:")) {
|
|
2968
|
+
text += options?.primaryAssistant ? line : theme.fg("muted", line);
|
|
2969
|
+
continue;
|
|
2970
|
+
}
|
|
2971
|
+
if (line.startsWith("next:") || line.startsWith("verifying:")) {
|
|
2972
|
+
text += theme.fg("muted", line);
|
|
2973
|
+
continue;
|
|
2974
|
+
}
|
|
2975
|
+
if (line.startsWith("rationale:") || line.startsWith("state-delta:")) {
|
|
2976
|
+
text += theme.fg("dim", line);
|
|
2977
|
+
continue;
|
|
2978
|
+
}
|
|
2979
|
+
text += theme.fg("muted", line);
|
|
2980
|
+
}
|
|
2981
|
+
return text;
|
|
2982
|
+
}
|
|
2983
|
+
|
|
2801
2984
|
function buildInlineRunningLines(details: {
|
|
2802
2985
|
role?: string;
|
|
2803
2986
|
startedAt?: number;
|
|
@@ -3020,6 +3203,9 @@ function completionResumePrompt(taskType: string, evaluationProfile: string): st
|
|
|
3020
3203
|
export default function completionExtension(pi: ExtensionAPI) {
|
|
3021
3204
|
pi.on("session_start", async (_event, ctx) => {
|
|
3022
3205
|
await refreshStatus(ctx);
|
|
3206
|
+
if (shouldTestAutoContinueOnSessionStart()) {
|
|
3207
|
+
await autoContinueWorkflowIfNeeded(pi, ctx);
|
|
3208
|
+
}
|
|
3023
3209
|
});
|
|
3024
3210
|
|
|
3025
3211
|
pi.on("turn_end", async (_event, ctx) => {
|
|
@@ -3032,10 +3218,16 @@ export default function completionExtension(pi: ExtensionAPI) {
|
|
|
3032
3218
|
await fsp.rm(snapshot.files.compactionMarkerPath, { force: true });
|
|
3033
3219
|
}
|
|
3034
3220
|
await refreshStatus(ctx);
|
|
3221
|
+
await autoContinueWorkflowIfNeeded(pi, ctx);
|
|
3035
3222
|
});
|
|
3036
3223
|
|
|
3037
3224
|
pi.on("before_agent_start", async (_event, ctx) => {
|
|
3038
3225
|
const loaded = await loadCompletionDataForReminder(getCtxCwd(ctx));
|
|
3226
|
+
if (loaded) {
|
|
3227
|
+
const rootKey = completionRootKey(loaded.snapshot, getCtxCwd(ctx));
|
|
3228
|
+
const fingerprint = completionContinuationFingerprint(loaded.snapshot);
|
|
3229
|
+
if (fingerprint) markQueuedDriverPromptInFlight(rootKey, fingerprint);
|
|
3230
|
+
}
|
|
3039
3231
|
if (!loaded) return;
|
|
3040
3232
|
const markerText = await readText(loaded.snapshot.files.compactionMarkerPath);
|
|
3041
3233
|
let marker: JsonRecord | undefined;
|
|
@@ -3324,7 +3516,7 @@ export default function completionExtension(pi: ExtensionAPI) {
|
|
|
3324
3516
|
const task = typeof args.task === "string" ? args.task.trim() : "";
|
|
3325
3517
|
let text = theme.fg("toolTitle", theme.bold("completion_role ")) + theme.fg("accent", role);
|
|
3326
3518
|
if (task) {
|
|
3327
|
-
text += `\n${theme.fg("
|
|
3519
|
+
text += `\n${theme.fg("muted", task)}`;
|
|
3328
3520
|
}
|
|
3329
3521
|
return new Text(text, 0, 0);
|
|
3330
3522
|
},
|
|
@@ -3352,53 +3544,26 @@ export default function completionExtension(pi: ExtensionAPI) {
|
|
|
3352
3544
|
};
|
|
3353
3545
|
if (isPartial) {
|
|
3354
3546
|
const lines = buildInlineRunningLines(details);
|
|
3355
|
-
|
|
3356
|
-
for (const [index, line] of lines.entries()) {
|
|
3357
|
-
if (index > 0) text += "\n";
|
|
3358
|
-
if (index === 0) {
|
|
3359
|
-
const [prefix, ...rest] = line.split(" ");
|
|
3360
|
-
text += theme.fg("warning", prefix);
|
|
3361
|
-
if (rest.length > 0) text += ` ${theme.fg("accent", rest.join(" "))}`;
|
|
3362
|
-
continue;
|
|
3363
|
-
}
|
|
3364
|
-
if (line.startsWith("tool:") || line.startsWith("progress:")) {
|
|
3365
|
-
text += theme.fg("toolOutput", line);
|
|
3366
|
-
continue;
|
|
3367
|
-
}
|
|
3368
|
-
if (line.startsWith("activity:")) {
|
|
3369
|
-
text += theme.fg(line.includes("stalled") ? "warning" : "dim", line);
|
|
3370
|
-
continue;
|
|
3371
|
-
}
|
|
3372
|
-
if (line === "recent tools:") {
|
|
3373
|
-
text += theme.fg("dim", line);
|
|
3374
|
-
continue;
|
|
3375
|
-
}
|
|
3376
|
-
if (line.startsWith("- ")) {
|
|
3377
|
-
text += `${theme.fg("muted", "- ")}${theme.fg("dim", line.slice(2))}`;
|
|
3378
|
-
continue;
|
|
3379
|
-
}
|
|
3380
|
-
text += theme.fg("dim", line);
|
|
3381
|
-
}
|
|
3382
|
-
return new Text(text, 0, 0);
|
|
3547
|
+
return new Text(formatInlineRunningText(theme, lines), 0, 0);
|
|
3383
3548
|
}
|
|
3384
3549
|
const role = details.role ?? "completion-role";
|
|
3385
3550
|
const ok = details.status === "ok" && !result.isError;
|
|
3386
3551
|
let text = `${theme.fg(ok ? "success" : "error", ok ? "done" : "error")} ${theme.fg("toolTitle", theme.bold(role))}`;
|
|
3387
|
-
if (details.startedAt !== undefined) text += `\n${theme.fg("
|
|
3552
|
+
if (details.startedAt !== undefined) text += `\n${theme.fg("muted", `elapsed: ${formatElapsed(nowMs() - details.startedAt)}`)}`;
|
|
3388
3553
|
if (details.toolActivity) text += `\n${theme.fg("toolOutput", `tool: ${details.toolActivity}`)}`;
|
|
3389
3554
|
if (details.progress) text += `\n${theme.fg("toolOutput", `progress: ${details.progress}`)}`;
|
|
3390
|
-
else if (details.assistantSummary) text += `\
|
|
3391
|
-
if (details.rationale) text += `\n${theme.fg("
|
|
3392
|
-
if (details.nextStep) text += `\n${theme.fg("
|
|
3393
|
-
if (details.verifying) text += `\n${theme.fg("
|
|
3555
|
+
else if (details.assistantSummary) text += `\nassistant: ${details.assistantSummary}`;
|
|
3556
|
+
if (details.rationale) text += `\n${theme.fg("muted", `rationale: ${details.rationale}`)}`;
|
|
3557
|
+
if (details.nextStep) text += `\n${theme.fg("muted", `next: ${details.nextStep}`)}`;
|
|
3558
|
+
if (details.verifying) text += `\n${theme.fg("muted", `verifying: ${details.verifying}`)}`;
|
|
3394
3559
|
if (details.stateDeltas?.length) {
|
|
3395
|
-
for (const delta of details.stateDeltas.slice(-4)) text += `\n${theme.fg("
|
|
3560
|
+
for (const delta of details.stateDeltas.slice(-4)) text += `\n${theme.fg("muted", `state-delta: ${delta}`)}`;
|
|
3396
3561
|
}
|
|
3397
3562
|
if (details.transcription?.appended?.length) {
|
|
3398
3563
|
text += `\n${theme.fg("success", `transcribed: ${details.transcription.appended.join(", ")}`)}`;
|
|
3399
3564
|
}
|
|
3400
3565
|
if (details.transcription?.skipped?.length && expanded) {
|
|
3401
|
-
text += `\n${theme.fg("
|
|
3566
|
+
text += `\n${theme.fg("muted", `skipped: ${details.transcription.skipped.join(" | ")}`)}`;
|
|
3402
3567
|
}
|
|
3403
3568
|
if (details.transcription?.errors?.length) {
|
|
3404
3569
|
text += `\n${theme.fg("warning", `warnings: ${details.transcription.errors.join(" | ")}`)}`;
|
|
@@ -3416,14 +3581,14 @@ export default function completionExtension(pi: ExtensionAPI) {
|
|
|
3416
3581
|
for (const key of summaryKeys) {
|
|
3417
3582
|
const value = reportFields[key];
|
|
3418
3583
|
if (!value) continue;
|
|
3419
|
-
text += `\n${theme.fg("
|
|
3584
|
+
text += `\n${theme.fg("muted", `${key}: `)}${value}`;
|
|
3420
3585
|
}
|
|
3421
3586
|
const body = result.content.find((item) => item.type === "text");
|
|
3422
3587
|
if (expanded && body?.type === "text") {
|
|
3423
3588
|
text += `\n\n${body.text}`;
|
|
3424
3589
|
} else if (!expanded && body?.type === "text") {
|
|
3425
3590
|
const preview = body.text.split("\n").slice(0, 4).join("\n");
|
|
3426
|
-
text += `\n${theme.fg("
|
|
3591
|
+
text += `\n${theme.fg("muted", preview)}`;
|
|
3427
3592
|
}
|
|
3428
3593
|
if (details.stderr && expanded) text += `\n${theme.fg("error", details.stderr)}`;
|
|
3429
3594
|
return new Text(text, 0, 0);
|
|
@@ -3538,13 +3703,14 @@ export default function completionExtension(pi: ExtensionAPI) {
|
|
|
3538
3703
|
currentTaskType(snapshot) ?? "(missing)",
|
|
3539
3704
|
currentEvaluationProfile(snapshot) ?? "(missing)",
|
|
3540
3705
|
);
|
|
3541
|
-
|
|
3542
|
-
|
|
3543
|
-
|
|
3544
|
-
|
|
3545
|
-
|
|
3546
|
-
|
|
3547
|
-
|
|
3706
|
+
const rootKey = completionRootKey(snapshot, getCtxCwd(ctx));
|
|
3707
|
+
const fingerprint = completionContinuationFingerprint(snapshot) ?? JSON.stringify({
|
|
3708
|
+
kind: "resume",
|
|
3709
|
+
mission_anchor: currentMissionAnchor(snapshot),
|
|
3710
|
+
current_phase: asString(snapshot.state?.current_phase) ?? null,
|
|
3711
|
+
next_mandatory_role: asString(snapshot.state?.next_mandatory_role) ?? null,
|
|
3712
|
+
});
|
|
3713
|
+
await queueCompletionDriverPrompt(pi, ctx, rootKey, fingerprint, resumePrompt, "resume");
|
|
3548
3714
|
return;
|
|
3549
3715
|
}
|
|
3550
3716
|
}
|
|
@@ -3613,13 +3779,16 @@ export default function completionExtension(pi: ExtensionAPI) {
|
|
|
3613
3779
|
kickoffIntent,
|
|
3614
3780
|
kickoffMissionAnchor,
|
|
3615
3781
|
);
|
|
3616
|
-
|
|
3617
|
-
|
|
3618
|
-
|
|
3619
|
-
|
|
3620
|
-
|
|
3621
|
-
|
|
3622
|
-
|
|
3782
|
+
const rootKey = completionRootKey(snapshot, getCtxCwd(ctx));
|
|
3783
|
+
const fingerprint = completionContinuationFingerprint(snapshot) ?? JSON.stringify({
|
|
3784
|
+
kind: "kickoff",
|
|
3785
|
+
mission_anchor: kickoffMissionAnchor,
|
|
3786
|
+
goal,
|
|
3787
|
+
intent: kickoffIntent,
|
|
3788
|
+
task_type: currentTaskType(snapshot) ?? "(missing)",
|
|
3789
|
+
evaluation_profile: currentEvaluationProfile(snapshot) ?? "(missing)",
|
|
3790
|
+
});
|
|
3791
|
+
await queueCompletionDriverPrompt(pi, ctx, rootKey, fingerprint, kickoffPrompt, "kickoff");
|
|
3623
3792
|
},
|
|
3624
3793
|
});
|
|
3625
3794
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@linimin/pi-letscook",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.33",
|
|
4
4
|
"description": "Pi package for long-running completion workflows with canonical .agent state, role-based subagents, continuity, and verification helpers.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"private": false,
|
package/scripts/smoke-test.sh
CHANGED
|
@@ -8,6 +8,7 @@ trap 'rm -rf "$TMPDIR"' EXIT
|
|
|
8
8
|
ROOT="$TMPDIR/repo"
|
|
9
9
|
KICKOFF_PROMPT="$TMPDIR/kickoff-prompt.txt"
|
|
10
10
|
RESUME_PROMPT="$TMPDIR/resume-prompt.txt"
|
|
11
|
+
AUTO_RESUME_PROMPT="$TMPDIR/auto-resume-prompt.txt"
|
|
11
12
|
|
|
12
13
|
mkdir -p "$ROOT"
|
|
13
14
|
cd "$ROOT"
|
|
@@ -72,6 +73,26 @@ assert f'- task_type: {expected_task_type}' in resume, 'resume prompt missing ca
|
|
|
72
73
|
assert f'- evaluation_profile: {expected_eval_profile}' in resume, 'resume prompt missing canonical evaluation_profile'
|
|
73
74
|
PY
|
|
74
75
|
|
|
76
|
+
PI_COMPLETION_SKIP_DRIVER_KICKOFF=1 \
|
|
77
|
+
PI_COMPLETION_TEST_AUTO_CONTINUE_ON_SESSION_START=1 \
|
|
78
|
+
PI_COMPLETION_TEST_AUTO_CONTINUE_PROMPT_PATH="$AUTO_RESUME_PROMPT" \
|
|
79
|
+
pi -e "$PKG_ROOT" -p "/cook" \
|
|
80
|
+
>"$TMPDIR/pi-completion-smoke-auto-resume.out" 2>"$TMPDIR/pi-completion-smoke-auto-resume.err"
|
|
81
|
+
|
|
82
|
+
python3 - "$AUTO_RESUME_PROMPT" <<'PY'
|
|
83
|
+
import sys
|
|
84
|
+
from pathlib import Path
|
|
85
|
+
|
|
86
|
+
expected_task_type = 'completion-workflow'
|
|
87
|
+
expected_eval_profile = 'completion-rubric-v1'
|
|
88
|
+
auto_resume = Path(sys.argv[1]).read_text()
|
|
89
|
+
|
|
90
|
+
assert 'Resume the completion workflow from canonical state.' in auto_resume, 'auto-resume prompt should use the canonical resume workflow prompt'
|
|
91
|
+
assert 'Canonical routing profile:' in auto_resume, 'auto-resume prompt should expose canonical routing profile'
|
|
92
|
+
assert f'- task_type: {expected_task_type}' in auto_resume, 'auto-resume prompt missing canonical task_type'
|
|
93
|
+
assert f'- evaluation_profile: {expected_eval_profile}' in auto_resume, 'auto-resume prompt missing canonical evaluation_profile'
|
|
94
|
+
PY
|
|
95
|
+
|
|
75
96
|
python3 - <<'PY'
|
|
76
97
|
import json
|
|
77
98
|
from pathlib import Path
|