feat(core,cli,server,web): add goal mode — loop Tasks on one Session until an objective completes (#66)
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,37 @@
|
||||
/**
|
||||
* Goal-command parsing (pure logic, shared by chat's `/goal` and run's `--goal`, unit-tested).
|
||||
*
|
||||
* Chat syntax: `/goal[:<budget>] <objective>` — the optional budget rides on the command
|
||||
* token (`/goal:500k Raise coverage to 80%`); omitting it means no budget. Run passes the
|
||||
* budget value (or `true` for a bare `--goal`), so only `parseTokenBudget` applies there.
|
||||
*/
|
||||
import { UNLIMITED_BUDGET } from "@prismshadow/penguin-core";
|
||||
|
||||
/**
|
||||
* Parses a budget token: a positive number with an optional `k` / `m` suffix
|
||||
* (`500k` = 500_000, `1.5m` = 1_500_000, `123456` literal). Returns null when invalid.
|
||||
*/
|
||||
export function parseTokenBudget(text: string): number | null {
|
||||
const m = /^(\d+(?:\.\d+)?)([km])?$/i.exec(text.trim());
|
||||
if (!m) return null;
|
||||
const scale = m[2]?.toLowerCase() === "m" ? 1_000_000 : m[2]?.toLowerCase() === "k" ? 1_000 : 1;
|
||||
const value = Math.round(Number(m[1]) * scale);
|
||||
return value > 0 ? value : null;
|
||||
}
|
||||
|
||||
export type GoalCommandResult =
|
||||
| { ok: true; budget: number; objective: string }
|
||||
| { ok: false; reason: "usage" }
|
||||
| { ok: false; reason: "budget"; value: string };
|
||||
|
||||
/** Parses a full `/goal…` chat line (the caller has already matched the `/goal` prefix). */
|
||||
export function parseGoalCommand(line: string): GoalCommandResult {
|
||||
const m = /^\/goal(?::(\S+))?(?:\s+([\s\S]+))?$/.exec(line.trim());
|
||||
if (!m) return { ok: false, reason: "usage" };
|
||||
const rest = m[2]?.trim() ?? "";
|
||||
if (!rest) return { ok: false, reason: "usage" };
|
||||
if (m[1] === undefined) return { ok: true, budget: UNLIMITED_BUDGET, objective: rest };
|
||||
const budget = parseTokenBudget(m[1]);
|
||||
if (budget === null) return { ok: false, reason: "budget", value: m[1] };
|
||||
return { ok: true, budget, objective: rest };
|
||||
}
|
||||
Reference in New Issue
Block a user