@zhushanwen/pi-goal 0.1.3 → 0.1.4

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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@zhushanwen/pi-goal",
3
- "version": "0.1.3",
3
+ "version": "0.1.4",
4
4
  "description": "Codex-style /goal command for Pi — persistent goal-driven autonomous loop with evidence-based completion, token/time budgets, blocked detection, and steering templates.",
5
5
  "type": "module",
6
6
  "main": "src/index.ts",
package/src/budget.ts CHANGED
@@ -147,7 +147,7 @@ export function checkProgress(state: GoalRuntimeState, tasksCompletedAtStart: nu
147
147
  return {
148
148
  allTasksDone: totalCount > 0 && incomplete.length === 0 && completedCount > 0,
149
149
  noTasksCreated: totalCount === 0,
150
- maxTurnsReached: state.turnCount >= state.budget.maxTurns,
150
+ maxTurnsReached: state.currentTurnIndex >= state.budget.maxTurns,
151
151
  isStalled: progressThisRound === 0,
152
152
  budgetTight: Boolean(
153
153
  state.budget.tokenBudget &&
package/src/index.ts CHANGED
@@ -12,7 +12,7 @@
12
12
  * 健壮性保障:
13
13
  * - goalId snapshot 防止旧回调操作新 goal
14
14
  * - 时间累计统一由 persistState 管理,无双写
15
- * - 防重入保护(hasPendingInjection)
15
+ * - before_agent_start 注入 context,agent_end 负责 continuation(预算检查/进度评估/续跑)
16
16
  * - deserializeState 向后兼容旧格式
17
17
  */
18
18
 
@@ -159,7 +159,7 @@ async function handleGoalCommand(pi: ExtensionAPI, session: GoalSession, args: s
159
159
  const lines = [
160
160
  `Objective: ${session.state.objective}`,
161
161
  `Status: ${session.state.status}`,
162
- `Turn: ${session.state.turnCount}/${session.state.budget.maxTurns}`,
162
+ `Turn: ${session.state.currentTurnIndex}/${session.state.budget.maxTurns}`,
163
163
  `Tasks: ${completed}/${total} completed`,
164
164
  `Stall turns: ${session.state.stallCount}`,
165
165
  `Time elapsed: ${Math.floor(elapsed / SECONDS_PER_MINUTE)}m${Math.floor(elapsed % SECONDS_PER_MINUTE)}s`,
@@ -306,6 +306,7 @@ Objective: ${session.state.objective}`,
306
306
  session.state.tasks = [];
307
307
  session.state.stallCount = 0;
308
308
  session.state.turnCount = 0;
309
+ session.state.currentTurnIndex = 0;
309
310
  session.state.lastProgressTurn = 0;
310
311
  session.state.budgetLimitSteeringSent = false;
311
312
  session.state.budgetWarning70Sent = false;
@@ -510,7 +511,7 @@ async function handleAgentEnd(pi: ExtensionAPI, session: GoalSession, ctx: Exten
510
511
  if (checkStale()) return;
511
512
  updateWidget(session, ctx);
512
513
  ctx.ui.notify(
513
- `Objective completed ✓ (${getCompletedCount(session.state.tasks)}/${session.state.tasks.length} tasks, ${session.state.turnCount} turns)`,
514
+ `Objective completed ✓ (${getCompletedCount(session.state.tasks)}/${session.state.tasks.length} tasks, ${session.state.currentTurnIndex} turns)`,
514
515
  "info",
515
516
  );
516
517
  return;
@@ -526,12 +527,6 @@ async function handleAgentEnd(pi: ExtensionAPI, session: GoalSession, ctx: Exten
526
527
 
527
528
  if (!isActiveStatus(session.state.status)) return;
528
529
 
529
- // 防重入
530
- if (session.hasPendingInjection) {
531
- session.hasPendingInjection = false;
532
- return;
533
- }
534
-
535
530
  if (checkStale()) return;
536
531
 
537
532
  // ── 预算策略(集中检查)──
@@ -595,7 +590,7 @@ async function handleAgentEnd(pi: ExtensionAPI, session: GoalSession, ctx: Exten
595
590
  if (checkStale()) return;
596
591
  updateWidget(session, ctx);
597
592
  ctx.ui.notify(
598
- `All tasks completed, Goal auto-closed. (${progress.completedCount}/${progress.totalCount} tasks, ${session.state.turnCount} turns)`,
593
+ `All tasks completed, Goal auto-closed. (${progress.completedCount}/${progress.totalCount} tasks, ${session.state.currentTurnIndex} turns)`,
599
594
  "info",
600
595
  );
601
596
  return;
@@ -666,7 +661,7 @@ async function handleAgentEnd(pi: ExtensionAPI, session: GoalSession, ctx: Exten
666
661
  session.state.stallCount++;
667
662
  } else {
668
663
  session.state.stallCount = 0;
669
- session.state.lastProgressTurn = session.state.turnCount;
664
+ session.state.lastProgressTurn = session.state.currentTurnIndex;
670
665
  }
671
666
 
672
667
  if (session.state.stallCount >= session.state.budget.maxStallTurns) {
package/src/templates.ts CHANGED
@@ -42,7 +42,7 @@ export function continuationPrompt(state: GoalRuntimeState): string {
42
42
 
43
43
  return (
44
44
  `<goal_context>\n` +
45
- `[GOAL] Turn ${state.turnCount}/${state.budget.maxTurns}${budgetLine}${stallLine}\n` +
45
+ `[GOAL] Turn ${state.currentTurnIndex}/${state.budget.maxTurns}${budgetLine}${stallLine}\n` +
46
46
  `<objective>${objective}</objective>\n` +
47
47
  `${taskLine}\n` +
48
48
  `Rules: create_tasks→update_tasks(evidence)→complete_goal(evidence). blocked→report_blocked(reason). subtask: add_subtasks/update_subtasks (replaces todo tool).\n` +
@@ -117,7 +117,7 @@ export function contextInjectionPrompt(state: GoalRuntimeState): string {
117
117
  `[GOAL mode activated]\n\n` +
118
118
  `<objective>\n${objective}\n</objective>\n` +
119
119
  `Status: ${state.status}\n` +
120
- `Turn: ${state.turnCount}/${state.budget.maxTurns}${budgetInfo}\n` +
120
+ `Turn: ${state.currentTurnIndex}/${state.budget.maxTurns}${budgetInfo}\n` +
121
121
  `Task progress: ${completedCount}/${total}\n\n` +
122
122
  `Strict rules:\n` +
123
123
  `1. First step: call goal_manager's create_tasks to decompose tasks (if not yet created)\n` +
@@ -160,7 +160,7 @@ export function stalenessReminderPrompt(
160
160
  }
161
161
 
162
162
  lines.push(`\nObjective: ${objective}`);
163
- lines.push(`Turn: ${state.turnCount}/${state.budget.maxTurns}`);
163
+ lines.push(`Turn: ${state.currentTurnIndex}/${state.budget.maxTurns}`);
164
164
  lines.push("</goal_context>");
165
165
 
166
166
  return lines.join("\n");
@@ -193,7 +193,7 @@ export function makeGoalResult(session: GoalSession, text: string) {
193
193
  meta: {
194
194
  ...(state.budget.tokenBudget ? { "Token": `${state.tokensUsed}/${state.budget.tokenBudget}` } : {}),
195
195
  ...(state.budget.timeBudgetMinutes ? { "Time": `${Math.floor(getElapsedTimeSeconds(state) / SECONDS_PER_MINUTE)}m/${state.budget.timeBudgetMinutes}m` } : {}),
196
- "Turn": `${state.turnCount}/${state.budget.maxTurns}`,
196
+ "Turn": `${state.currentTurnIndex}/${state.budget.maxTurns}`,
197
197
  },
198
198
  },
199
199
  },
@@ -333,7 +333,7 @@ export async function executeGoalAction(
333
333
  writeGoalHistoryEntry(pi, session);
334
334
  persistGoalState(pi, session, ctx);
335
335
  const budgetReport: string[] = [];
336
- budgetReport.push(`Total turns: ${state.turnCount}`);
336
+ budgetReport.push(`Total turns: ${state.currentTurnIndex}`);
337
337
  budgetReport.push(`Tasks completed: ${getCompletedCount(state.tasks)}/${state.tasks.length}`);
338
338
  if (state.budget.tokenBudget) {
339
339
  budgetReport.push(`Token usage: ${state.tokensUsed}/${state.budget.tokenBudget}`);
package/src/widget.ts CHANGED
@@ -39,7 +39,7 @@ export function renderStatusLine(state: GoalRuntimeState, th: ThemeLike): string
39
39
  const completedCount = getCompletedCount(state.tasks);
40
40
  const total = state.tasks.length;
41
41
 
42
- let text = th.fg("accent", `◆ Goal`) + th.fg("muted", ` ${state.turnCount}/${state.budget.maxTurns}`);
42
+ let text = th.fg("accent", `◆ Goal`) + th.fg("muted", ` ${state.currentTurnIndex}/${state.budget.maxTurns}`);
43
43
 
44
44
  if (total > 0) {
45
45
  text += th.fg("muted", ` | ${completedCount}/${total} tasks`);