grind mode baby

This commit is contained in:
Harivansh Rathi 2026-03-08 23:38:13 -07:00
parent aa70afbd7e
commit ff6e39dd10
17 changed files with 1232 additions and 8 deletions

View file

@ -0,0 +1,44 @@
import { describe, expect, it } from "vitest";
import { detectCue, parseAutoActivation, parseGrindStatus, parseStopCondition } from "../src/parser.js";
describe("pi-grind parser", () => {
const now = new Date(2026, 2, 9, 9, 0, 0);
const cues = ["don't stop", "keep going", "run until"];
it("detects explicit grind cues", () => {
expect(detectCue("Please keep going on this", cues)).toBe("keep going");
expect(detectCue("Normal prompt", cues)).toBeNull();
});
it("parses time-based stop conditions", () => {
const result = parseStopCondition("keep going until 5pm", now);
expect(result.deadlineAt).toBe(new Date(2026, 2, 9, 17, 0, 0).toISOString());
expect(result.completionCriterion).toBeNull();
});
it("parses criterion-based stop conditions when no time is found", () => {
const result = parseStopCondition("don't stop until the migration is finished", now);
expect(result.deadlineAt).toBeNull();
expect(result.completionCriterion).toBe("the migration is finished");
});
it("parses full auto activation payloads", () => {
const result = parseAutoActivation("run until tomorrow 5:30pm and finish the report", cues, now);
expect(result).not.toBeNull();
expect(result?.matchedCue).toBe("run until");
expect(result?.stopCondition.deadlineAt).toBe(new Date(2026, 2, 10, 17, 30, 0).toISOString());
});
it("parses grind status trailers", () => {
const payload = parseGrindStatus(
'Work done.\n<grind_status>{"state":"continue","summary":"half done","nextAction":"finish tests"}</grind_status>',
);
expect(payload).toEqual({
state: "continue",
summary: "half done",
nextAction: "finish tests",
});
});
});

View file

@ -0,0 +1,72 @@
import type { SessionEntry } from "@mariozechner/pi-coding-agent";
import { describe, expect, it } from "vitest";
import { createRunState, getLatestRunState, withLoopStatus, withStatus } from "../src/state.js";
import { GRIND_STATE_ENTRY_TYPE } from "../src/types.js";
describe("pi-grind state", () => {
it("creates active run state", () => {
const state = createRunState({
activation: "explicit",
goal: "Ship the refactor",
sourcePrompt: "Don't stop until this is done",
deadlineAt: null,
completionCriterion: "this is done",
});
expect(state.status).toBe("active");
expect(state.goal).toBe("Ship the refactor");
expect(state.completionCriterion).toBe("this is done");
});
it("hydrates latest persisted state from session entries", () => {
const older = createRunState({
activation: "command",
goal: "older",
sourcePrompt: "older",
deadlineAt: null,
completionCriterion: null,
});
const newer = withStatus(older, "paused");
const entries = [
{
type: "custom",
id: "a",
parentId: null,
timestamp: new Date().toISOString(),
customType: GRIND_STATE_ENTRY_TYPE,
data: older,
},
{
type: "custom",
id: "b",
parentId: "a",
timestamp: new Date().toISOString(),
customType: GRIND_STATE_ENTRY_TYPE,
data: newer,
},
] satisfies SessionEntry[];
expect(getLatestRunState(entries)?.status).toBe("paused");
});
it("applies loop results", () => {
const state = createRunState({
activation: "explicit",
goal: "Ship it",
sourcePrompt: "Ship it",
deadlineAt: null,
completionCriterion: null,
});
const next = withLoopStatus(state, {
state: "done",
summary: "finished",
nextAction: "none",
});
expect(next.status).toBe("done");
expect(next.lastCheckpoint).toBe("finished");
expect(next.lastNextAction).toBe("none");
});
});