@umgbhalla/pi-gigaplan 0.1.2 → 0.1.3

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.
@@ -96,6 +96,11 @@ function inferNextSteps(state: PlanState): string[] {
96
96
  case STATE_PLANNED: return ["critique"];
97
97
  case STATE_CRITIQUED: return ["evaluate"];
98
98
  case STATE_EVALUATED: {
99
+ const lastHistory = state.history[state.history.length - 1];
100
+ if (lastHistory?.step === "gate" && lastHistory.result === "failed") {
101
+ return ["integrate"];
102
+ }
103
+
99
104
  const rec = (state.last_evaluation as Record<string, unknown>)?.recommendation as string;
100
105
  if (rec === "CONTINUE") return ["integrate"];
101
106
  if (rec === "SKIP") return ["gate"];
@@ -108,6 +113,19 @@ function inferNextSteps(state: PlanState): string[] {
108
113
  }
109
114
  }
110
115
 
116
+ const LLM_STEPS = new Set(["clarify", "plan", "critique", "integrate", "execute", "review"]);
117
+ const LOGIC_STEPS = new Set(["evaluate", "gate"]);
118
+
119
+ function requireAllowedStep(state: PlanState, step: string): void {
120
+ const nextSteps = inferNextSteps(state);
121
+ if (!nextSteps.includes(step)) {
122
+ throw new GigaplanError(
123
+ "invalid_state",
124
+ `Step "${step}" is not valid from state ${state.current_state}. Expected next step: ${nextSteps.join(", ") || "none"}`,
125
+ );
126
+ }
127
+ }
128
+
111
129
  // ---------------------------------------------------------------------------
112
130
  // Step handlers
113
131
  // ---------------------------------------------------------------------------
@@ -194,6 +212,7 @@ function processStepOutput(
194
212
 
195
213
  switch (step) {
196
214
  case "clarify": {
215
+ requireState(state, STATE_INITIALIZED);
197
216
  state.clarification = payload;
198
217
  state.current_state = STATE_CLARIFIED;
199
218
  state.history.push({
@@ -214,6 +233,9 @@ function processStepOutput(
214
233
 
215
234
  case "plan":
216
235
  case "integrate": {
236
+ if (step === "plan") requireState(state, STATE_CLARIFIED);
237
+ else requireState(state, STATE_EVALUATED);
238
+
217
239
  const newIteration = iteration + 1;
218
240
  state.iteration = newIteration;
219
241
 
@@ -276,6 +298,8 @@ function processStepOutput(
276
298
  }
277
299
 
278
300
  case "critique": {
301
+ requireState(state, STATE_PLANNED);
302
+
279
303
  // Save critique artifact
280
304
  const critiqueFile = `critique_v${iteration}.json`;
281
305
  atomicWriteJson(path.join(planDir, critiqueFile), payload);
@@ -336,6 +360,7 @@ function processStepOutput(
336
360
  }
337
361
 
338
362
  case "execute": {
363
+ requireState(state, STATE_GATED);
339
364
  atomicWriteJson(path.join(planDir, "execution.json"), payload);
340
365
  state.current_state = STATE_EXECUTED;
341
366
  state.history.push({
@@ -357,6 +382,7 @@ function processStepOutput(
357
382
  }
358
383
 
359
384
  case "review": {
385
+ requireState(state, STATE_EXECUTED);
360
386
  atomicWriteJson(path.join(planDir, "review.json"), payload);
361
387
  state.current_state = STATE_DONE;
362
388
  state.history.push({
@@ -492,10 +518,27 @@ export default function gigaplanExtension(pi: ExtensionAPI) {
492
518
  // Widget state
493
519
  let activePlan: { name: string; state: string; step: string } | null = null;
494
520
 
521
+ function syncActivePlan(root: string): void {
522
+ try {
523
+ const [, state] = loadPlan(root);
524
+ if (TERMINAL_STATES.has(state.current_state)) {
525
+ activePlan = null;
526
+ return;
527
+ }
528
+ activePlan = {
529
+ name: state.name,
530
+ state: state.current_state,
531
+ step: inferNextSteps(state)[0] ?? "done",
532
+ };
533
+ } catch {
534
+ activePlan = null;
535
+ }
536
+ }
537
+
495
538
  function updateWidget(ctx?: any) {
496
539
  if (!ctx?.ui) return;
497
540
  if (!activePlan) {
498
- ctx.ui.setStatus("gigaplan", "");
541
+ ctx.ui.setStatus("gigaplan", undefined);
499
542
  return;
500
543
  }
501
544
  ctx.ui.setStatus(
@@ -504,6 +547,21 @@ export default function gigaplanExtension(pi: ExtensionAPI) {
504
547
  );
505
548
  }
506
549
 
550
+ pi.on("session_start", (_event, ctx) => {
551
+ syncActivePlan(ctx.cwd);
552
+ updateWidget(ctx);
553
+ });
554
+
555
+ pi.on("session_switch", (_event, ctx) => {
556
+ syncActivePlan(ctx.cwd);
557
+ updateWidget(ctx);
558
+ });
559
+
560
+ pi.on("session_shutdown", (_event, ctx) => {
561
+ activePlan = null;
562
+ updateWidget(ctx);
563
+ });
564
+
507
565
  // ── /gigaplan command ──
508
566
  pi.registerCommand("gigaplan", {
509
567
  description: "Start a structured planning session: /gigaplan <idea>",
@@ -572,7 +630,7 @@ For each LLM step, use the \`gigaplan_step\` tool which returns the subagent con
572
630
 
573
631
  Start now with the **clarify** step.`;
574
632
 
575
- pi.sendUserMessage(orchestrationPrompt);
633
+ pi.sendUserMessage(orchestrationPrompt, { deliverAs: "followUp" });
576
634
  },
577
635
  });
578
636
 
@@ -591,6 +649,10 @@ Start now with the **clarify** step.`;
591
649
  async execute(_id, params) {
592
650
  try {
593
651
  const state = readJson(path.join(params.planDir, "state.json")) as PlanState;
652
+ if (!LLM_STEPS.has(params.step)) {
653
+ throw new GigaplanError("unsupported_step", `Unknown LLM step: ${params.step}`);
654
+ }
655
+ requireAllowedStep(state, params.step);
594
656
  const config = buildStepConfig(params.step, state, params.planDir);
595
657
 
596
658
  return {
@@ -640,6 +702,11 @@ Start now with the **clarify** step.`;
640
702
  async execute(_id, params, _signal, _onUpdate, ctx) {
641
703
  try {
642
704
  const state = readJson(path.join(params.planDir, "state.json")) as PlanState;
705
+ if (!LLM_STEPS.has(params.step) && !LOGIC_STEPS.has(params.step)) {
706
+ throw new GigaplanError("unsupported_step", `Unknown step: ${params.step}`);
707
+ }
708
+ requireAllowedStep(state, params.step);
709
+
643
710
  let result: StepResult;
644
711
 
645
712
  if (params.step === "evaluate") {
@@ -805,6 +872,7 @@ Start now with the **clarify** step.`;
805
872
  }
806
873
 
807
874
  case "force-proceed": {
875
+ requireState(state, STATE_EVALUATED);
808
876
  state.current_state = STATE_GATED;
809
877
  state.meta.user_approved_gate = true;
810
878
  state.history.push({
@@ -820,6 +888,7 @@ Start now with the **clarify** step.`;
820
888
  }
821
889
 
822
890
  case "skip": {
891
+ requireState(state, STATE_EVALUATED);
823
892
  state.last_evaluation = { recommendation: "SKIP" };
824
893
  state.current_state = STATE_EVALUATED;
825
894
  state.history.push({
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@umgbhalla/pi-gigaplan",
3
- "version": "0.1.2",
3
+ "version": "0.1.3",
4
4
  "description": "Structured AI planning with cross-model critique — gigaplan as a pi extension",
5
5
  "keywords": [
6
6
  "pi-package",