@umgbhalla/pi-gigaplan 0.1.1 → 0.1.2
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/extensions/index.ts +4 -3
- package/package.json +1 -1
- package/skills/gigaplan/SKILL.md +1 -1
- package/src/workers.ts +119 -0
package/extensions/index.ts
CHANGED
|
@@ -492,7 +492,8 @@ export default function gigaplanExtension(pi: ExtensionAPI) {
|
|
|
492
492
|
// Widget state
|
|
493
493
|
let activePlan: { name: string; state: string; step: string } | null = null;
|
|
494
494
|
|
|
495
|
-
function updateWidget(ctx
|
|
495
|
+
function updateWidget(ctx?: any) {
|
|
496
|
+
if (!ctx?.ui) return;
|
|
496
497
|
if (!activePlan) {
|
|
497
498
|
ctx.ui.setStatus("gigaplan", "");
|
|
498
499
|
return;
|
|
@@ -636,7 +637,7 @@ Start now with the **clarify** step.`;
|
|
|
636
637
|
durationMs: Type.Optional(Type.Number({ description: "How long the step took in ms" })),
|
|
637
638
|
}),
|
|
638
639
|
|
|
639
|
-
async execute(_id, params) {
|
|
640
|
+
async execute(_id, params, _signal, _onUpdate, ctx) {
|
|
640
641
|
try {
|
|
641
642
|
const state = readJson(path.join(params.planDir, "state.json")) as PlanState;
|
|
642
643
|
let result: StepResult;
|
|
@@ -662,7 +663,7 @@ Start now with the **clarify** step.`;
|
|
|
662
663
|
if (activePlan) {
|
|
663
664
|
activePlan.state = result.step;
|
|
664
665
|
activePlan.step = result.nextSteps[0] ?? "done";
|
|
665
|
-
updateWidget(
|
|
666
|
+
updateWidget(ctx);
|
|
666
667
|
}
|
|
667
668
|
|
|
668
669
|
const nextAction = result.nextSteps.length > 0
|
package/package.json
CHANGED
package/skills/gigaplan/SKILL.md
CHANGED
|
@@ -40,7 +40,7 @@ For **evaluate** and **gate** steps: skip the subagent, just call `gigaplan_adva
|
|
|
40
40
|
```
|
|
41
41
|
clarify → plan → critique → evaluate
|
|
42
42
|
↓
|
|
43
|
-
CONTINUE → integrate →
|
|
43
|
+
CONTINUE → integrate → critique (loop)
|
|
44
44
|
SKIP → gate → execute → review → done
|
|
45
45
|
ESCALATE → ask user → override
|
|
46
46
|
ABORT → done
|
package/src/workers.ts
CHANGED
|
@@ -60,6 +60,82 @@ function getRequiredKeys(step: string): string[] {
|
|
|
60
60
|
return (schema?.required as string[] | undefined) ?? [];
|
|
61
61
|
}
|
|
62
62
|
|
|
63
|
+
function getStepSchema(step: string): Record<string, unknown> | undefined {
|
|
64
|
+
const filename = STEP_SCHEMA_FILENAMES[step];
|
|
65
|
+
if (!filename) return undefined;
|
|
66
|
+
return SCHEMAS[filename] as Record<string, unknown> | undefined;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
function describeType(value: unknown): string {
|
|
70
|
+
if (Array.isArray(value)) return "array";
|
|
71
|
+
if (value === null) return "null";
|
|
72
|
+
return typeof value;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
function validateValueAgainstSchema(
|
|
76
|
+
value: unknown,
|
|
77
|
+
schema: Record<string, unknown> | undefined,
|
|
78
|
+
keyPath: string,
|
|
79
|
+
): void {
|
|
80
|
+
if (!schema) return;
|
|
81
|
+
|
|
82
|
+
const expectedType = schema.type as string | undefined;
|
|
83
|
+
if (expectedType === "string" && typeof value !== "string") {
|
|
84
|
+
throw new GigaplanError(
|
|
85
|
+
"parse_error",
|
|
86
|
+
`${keyPath} must be a string, got ${describeType(value)}`,
|
|
87
|
+
);
|
|
88
|
+
}
|
|
89
|
+
if (expectedType === "boolean" && typeof value !== "boolean") {
|
|
90
|
+
throw new GigaplanError(
|
|
91
|
+
"parse_error",
|
|
92
|
+
`${keyPath} must be a boolean, got ${describeType(value)}`,
|
|
93
|
+
);
|
|
94
|
+
}
|
|
95
|
+
if (expectedType === "array") {
|
|
96
|
+
if (!Array.isArray(value)) {
|
|
97
|
+
throw new GigaplanError(
|
|
98
|
+
"parse_error",
|
|
99
|
+
`${keyPath} must be an array, got ${describeType(value)}`,
|
|
100
|
+
);
|
|
101
|
+
}
|
|
102
|
+
const itemSchema = schema.items as Record<string, unknown> | undefined;
|
|
103
|
+
value.forEach((item, index) => {
|
|
104
|
+
validateValueAgainstSchema(item, itemSchema, `${keyPath}[${index}]`);
|
|
105
|
+
});
|
|
106
|
+
return;
|
|
107
|
+
}
|
|
108
|
+
if (expectedType === "object") {
|
|
109
|
+
if (typeof value !== "object" || value === null || Array.isArray(value)) {
|
|
110
|
+
throw new GigaplanError(
|
|
111
|
+
"parse_error",
|
|
112
|
+
`${keyPath} must be an object, got ${describeType(value)}`,
|
|
113
|
+
);
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
const obj = value as Record<string, unknown>;
|
|
117
|
+
const required = (schema.required as string[] | undefined) ?? [];
|
|
118
|
+
const missing = required.filter((k) => !(k in obj));
|
|
119
|
+
if (missing.length > 0) {
|
|
120
|
+
throw new GigaplanError(
|
|
121
|
+
"parse_error",
|
|
122
|
+
`${keyPath} missing required keys: ${missing.join(", ")}`,
|
|
123
|
+
);
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
const properties = (schema.properties as Record<string, unknown> | undefined) ?? {};
|
|
127
|
+
for (const [prop, propSchema] of Object.entries(properties)) {
|
|
128
|
+
if (prop in obj) {
|
|
129
|
+
validateValueAgainstSchema(
|
|
130
|
+
obj[prop],
|
|
131
|
+
propSchema as Record<string, unknown>,
|
|
132
|
+
keyPath === "payload" ? prop : `${keyPath}.${prop}`,
|
|
133
|
+
);
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
|
|
63
139
|
// ---------------------------------------------------------------------------
|
|
64
140
|
// Validation
|
|
65
141
|
// ---------------------------------------------------------------------------
|
|
@@ -73,6 +149,8 @@ export function validatePayload(step: string, payload: Record<string, unknown>):
|
|
|
73
149
|
`${step} output missing required keys: ${missing.join(", ")}`,
|
|
74
150
|
);
|
|
75
151
|
}
|
|
152
|
+
|
|
153
|
+
validateValueAgainstSchema(payload, getStepSchema(step), "payload");
|
|
76
154
|
}
|
|
77
155
|
|
|
78
156
|
// ---------------------------------------------------------------------------
|
|
@@ -104,6 +182,44 @@ export function resolveAgent(step: string, state: PlanState): AgentRouting {
|
|
|
104
182
|
// Build subagent task
|
|
105
183
|
// ---------------------------------------------------------------------------
|
|
106
184
|
|
|
185
|
+
function stepOutputChecklist(step: string): string {
|
|
186
|
+
switch (step) {
|
|
187
|
+
case "clarify":
|
|
188
|
+
return [
|
|
189
|
+
'- Top-level keys: `questions`, `refined_idea`, `intent_summary`.',
|
|
190
|
+
'- `questions` must be an array of objects with `question` and `context`.',
|
|
191
|
+
].join("\n");
|
|
192
|
+
case "plan":
|
|
193
|
+
return [
|
|
194
|
+
'- Top-level keys: `plan`, `questions`, `success_criteria`, `assumptions`.',
|
|
195
|
+
'- `plan` must be a markdown string, not an array or object.',
|
|
196
|
+
].join("\n");
|
|
197
|
+
case "integrate":
|
|
198
|
+
return [
|
|
199
|
+
'- Top-level keys: `plan`, `changes_summary`, `flags_addressed`, `assumptions`, `success_criteria`, `questions`.',
|
|
200
|
+
'- `plan` must be a markdown string.',
|
|
201
|
+
'- `flags_addressed` must contain exact flag IDs from critique.',
|
|
202
|
+
].join("\n");
|
|
203
|
+
case "critique":
|
|
204
|
+
return [
|
|
205
|
+
'- Top-level keys: `flags`, `verified_flag_ids`, `disputed_flag_ids`.',
|
|
206
|
+
'- Use `flags`, not `significant_issues` or any alternate field name.',
|
|
207
|
+
'- Each `flags[]` item must include exactly: `id`, `concern`, `category`, `severity_hint`, `evidence`.',
|
|
208
|
+
].join("\n");
|
|
209
|
+
case "execute":
|
|
210
|
+
return [
|
|
211
|
+
'- Top-level keys: `output`, `files_changed`, `commands_run`, `deviations`.',
|
|
212
|
+
].join("\n");
|
|
213
|
+
case "review":
|
|
214
|
+
return [
|
|
215
|
+
'- Top-level keys: `criteria`, `issues`, `summary`.',
|
|
216
|
+
'- Each `criteria[]` item must include `name`, `pass`, `evidence`.',
|
|
217
|
+
].join("\n");
|
|
218
|
+
default:
|
|
219
|
+
return "- Follow the schema exactly.";
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
|
|
107
223
|
/**
|
|
108
224
|
* Build the full task prompt for a subagent.
|
|
109
225
|
* Includes the step prompt + instructions to write structured output.
|
|
@@ -131,6 +247,9 @@ ${prompt}
|
|
|
131
247
|
You MUST write your response as a valid JSON object to this file:
|
|
132
248
|
\`${outputPath}\`
|
|
133
249
|
|
|
250
|
+
Checklist:
|
|
251
|
+
${stepOutputChecklist(step)}
|
|
252
|
+
|
|
134
253
|
The JSON must conform to this schema:
|
|
135
254
|
\`\`\`json
|
|
136
255
|
${JSON.stringify(strict, null, 2)}
|