@mjasnikovs/pi-task 0.2.1 → 0.2.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/README.md +29 -0
- package/dist/index.js +2 -0
- package/dist/shared/child-process.js +25 -4
- package/dist/task/auto-commit.d.ts +20 -0
- package/dist/task/auto-commit.js +56 -0
- package/dist/task/auto-io.d.ts +17 -0
- package/dist/task/auto-io.js +124 -0
- package/dist/task/auto-orchestrator.d.ts +28 -0
- package/dist/task/auto-orchestrator.js +298 -0
- package/dist/task/auto-prompts.d.ts +15 -0
- package/dist/task/auto-prompts.js +66 -0
- package/dist/task/inline-markdown.d.ts +18 -0
- package/dist/task/inline-markdown.js +28 -0
- package/dist/task/orchestrator.d.ts +28 -0
- package/dist/task/orchestrator.js +42 -9
- package/dist/task/parsers.d.ts +16 -0
- package/dist/task/parsers.js +70 -0
- package/dist/task/phases.d.ts +2 -1
- package/dist/task/phases.js +126 -100
- package/dist/task/prompts.d.ts +24 -1
- package/dist/task/prompts.js +40 -5
- package/dist/task/widget.d.ts +19 -0
- package/dist/task/widget.js +73 -15
- package/package.json +1 -1
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Prompts for /task-auto's two feature-level child calls. These produce a task
|
|
3
|
+
* LIST only; all research/spec depth is /task's job, run per-title later.
|
|
4
|
+
*/
|
|
5
|
+
/**
|
|
6
|
+
* Clarify: asks ONE question at a time. Output MUST match parseClarifyList — a
|
|
7
|
+
* single numbered question followed by a "SUGGESTED: <default>" line, or the
|
|
8
|
+
* literal token NONE when no clarification remains. priorQA carries the
|
|
9
|
+
* questions already answered so each next question adapts to them.
|
|
10
|
+
*/
|
|
11
|
+
export declare const AUTO_CLARIFY_PROMPT: (feature: string, priorQA: string) => string;
|
|
12
|
+
/**
|
|
13
|
+
* Decompose: output a markdown checkbox list of task titles (one line each).
|
|
14
|
+
*/
|
|
15
|
+
export declare const AUTO_DECOMPOSE_PROMPT: (feature: string, clarifications: string) => string;
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Prompts for /task-auto's two feature-level child calls. These produce a task
|
|
3
|
+
* LIST only; all research/spec depth is /task's job, run per-title later.
|
|
4
|
+
*/
|
|
5
|
+
/**
|
|
6
|
+
* Clarify: asks ONE question at a time. Output MUST match parseClarifyList — a
|
|
7
|
+
* single numbered question followed by a "SUGGESTED: <default>" line, or the
|
|
8
|
+
* literal token NONE when no clarification remains. priorQA carries the
|
|
9
|
+
* questions already answered so each next question adapts to them.
|
|
10
|
+
*/
|
|
11
|
+
export const AUTO_CLARIFY_PROMPT = (feature, priorQA) => `You are planning how to split a feature into separate implementation tasks, one clarifying question at a time.
|
|
12
|
+
|
|
13
|
+
FEATURE REQUEST:
|
|
14
|
+
${feature.trim()}
|
|
15
|
+
|
|
16
|
+
ANSWERS SO FAR:
|
|
17
|
+
${priorQA.trim() || '(none yet)'}
|
|
18
|
+
|
|
19
|
+
You may use the read tool to inspect the repo and any referenced docs so your
|
|
20
|
+
question and recommendation are grounded in what already exists.
|
|
21
|
+
|
|
22
|
+
Output the SINGLE most important clarifying question that REMAINS — the one whose
|
|
23
|
+
answer would most change HOW this feature is split into tasks (scope boundaries,
|
|
24
|
+
which subsystems are in/out, ordering, the cross-cutting technical choices that
|
|
25
|
+
fork the breakdown). Account for the answers so far:
|
|
26
|
+
- Never re-ask something already answered above.
|
|
27
|
+
- If an answer introduced a new fork or contradicts an assumption (for example,
|
|
28
|
+
the user chose a framework or tool the request did not anticipate), ask about
|
|
29
|
+
the most important consequence of that choice next — how it is built, what
|
|
30
|
+
extra dependencies it pulls in, how it changes the other subsystems.
|
|
31
|
+
- When the feature spans multiple subsystems, work through its forks one at a
|
|
32
|
+
time (file/blob storage, client/rendering strategy, auth and session model,
|
|
33
|
+
real-time vs polling transport, search, deployment).
|
|
34
|
+
- Skip anything /task will naturally resolve per-task during its own research.
|
|
35
|
+
|
|
36
|
+
Also propose the single most sensible default answer for this question, inferred
|
|
37
|
+
from the repo, the referenced docs, and any stated philosophy or constraints —
|
|
38
|
+
concrete and decisive, shown to the user as a recommendation they can accept or
|
|
39
|
+
override.
|
|
40
|
+
|
|
41
|
+
OUTPUT FORMAT (exact):
|
|
42
|
+
- One clarifying question as a single numbered line: "1. ...".
|
|
43
|
+
- On the NEXT line (never inline), a line that begins with "SUGGESTED: <your recommended default>".
|
|
44
|
+
- Put the core question in **bold**, followed by a short one-line rationale in plain prose. Backticks around code/identifiers are fine. Avoid other markdown (headings, bullet lists, links).
|
|
45
|
+
- Only when the spec already pins down every choice that would change the task breakdown — nothing decision-changing is left to ask — output exactly:
|
|
46
|
+
NONE`;
|
|
47
|
+
/**
|
|
48
|
+
* Decompose: output a markdown checkbox list of task titles (one line each).
|
|
49
|
+
*/
|
|
50
|
+
export const AUTO_DECOMPOSE_PROMPT = (feature, clarifications) => `Split this feature into an ordered list of implementation tasks. Each task
|
|
51
|
+
will be handed, by its title, to a separate pipeline that does its own research
|
|
52
|
+
and writes its own spec — so here you produce TITLES ONLY, not specs.
|
|
53
|
+
|
|
54
|
+
FEATURE REQUEST:
|
|
55
|
+
${feature.trim()}
|
|
56
|
+
|
|
57
|
+
CLARIFICATIONS:
|
|
58
|
+
${clarifications.trim() || '(none)'}
|
|
59
|
+
|
|
60
|
+
RULES:
|
|
61
|
+
- One task per line, as a markdown checkbox: "- [ ] <title>".
|
|
62
|
+
- Each title is a short imperative phrase; optionally add " — <one key detail>".
|
|
63
|
+
- Order tasks so earlier ones unblock later ones (foundations first).
|
|
64
|
+
- Each task should be independently implementable as a single /task run.
|
|
65
|
+
- Prefer a handful of substantial tasks over many trivial ones.
|
|
66
|
+
- Output the checkbox list and NOTHING else (no preamble, no numbering).`;
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Inline-markdown helpers for the clarify/grill question dialogs.
|
|
3
|
+
*
|
|
4
|
+
* The model often wraps the core question in **bold** (and code in backticks)
|
|
5
|
+
* because it makes the question easier to read at a glance. ctx.ui.input titles
|
|
6
|
+
* accept ANSI styling, so we RENDER those spans to terminal bold/code for the
|
|
7
|
+
* displayed prompt, and STRIP them to plain text for the editable input default
|
|
8
|
+
* and the persisted task file (which must stay ANSI-free).
|
|
9
|
+
*/
|
|
10
|
+
/** Minimal theme surface we need; ExtensionCommandContext['ui'].theme satisfies it. */
|
|
11
|
+
export interface InlineMarkdownTheme {
|
|
12
|
+
bold(text: string): string;
|
|
13
|
+
fg(color: 'mdCode', text: string): string;
|
|
14
|
+
}
|
|
15
|
+
/** Render **bold** and `code` spans to themed terminal styling for display. */
|
|
16
|
+
export declare function renderInlineMarkdown(text: string, theme: InlineMarkdownTheme): string;
|
|
17
|
+
/** Strip **bold** and `code` markers to plain text (for defaults and storage). */
|
|
18
|
+
export declare function stripInlineMarkdown(text: string): string;
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Inline-markdown helpers for the clarify/grill question dialogs.
|
|
3
|
+
*
|
|
4
|
+
* The model often wraps the core question in **bold** (and code in backticks)
|
|
5
|
+
* because it makes the question easier to read at a glance. ctx.ui.input titles
|
|
6
|
+
* accept ANSI styling, so we RENDER those spans to terminal bold/code for the
|
|
7
|
+
* displayed prompt, and STRIP them to plain text for the editable input default
|
|
8
|
+
* and the persisted task file (which must stay ANSI-free).
|
|
9
|
+
*/
|
|
10
|
+
const BOLD_SPAN = /\*\*(.+?)\*\*/g;
|
|
11
|
+
const CODE_SPAN = /`([^`]+)`/g;
|
|
12
|
+
/** Render **bold** and `code` spans to themed terminal styling for display. */
|
|
13
|
+
export function renderInlineMarkdown(text, theme) {
|
|
14
|
+
return text
|
|
15
|
+
.replace(BOLD_SPAN, (_, b) => theme.bold(b))
|
|
16
|
+
.replace(CODE_SPAN, (_, c) => theme.fg('mdCode', c))
|
|
17
|
+
.replace(/\*\*/g, '') // drop stray/unbalanced bold markers
|
|
18
|
+
.replace(/`/g, ''); // drop stray backticks
|
|
19
|
+
}
|
|
20
|
+
/** Strip **bold** and `code` markers to plain text (for defaults and storage). */
|
|
21
|
+
export function stripInlineMarkdown(text) {
|
|
22
|
+
return text
|
|
23
|
+
.replace(BOLD_SPAN, '$1')
|
|
24
|
+
.replace(CODE_SPAN, '$1')
|
|
25
|
+
.replace(/\*\*/g, '')
|
|
26
|
+
.replace(/`/g, '')
|
|
27
|
+
.trim();
|
|
28
|
+
}
|
|
@@ -51,4 +51,32 @@ export declare class TaskRunner {
|
|
|
51
51
|
run(): Promise<void>;
|
|
52
52
|
private _deliverSpec;
|
|
53
53
|
}
|
|
54
|
+
export interface RunSingleTaskOptions {
|
|
55
|
+
/** Await the session going idle after the spec is delivered, so the caller
|
|
56
|
+
* blocks until the agent has implemented it. Default false. */
|
|
57
|
+
waitForImplementation?: boolean;
|
|
58
|
+
/** Test seam: spawn function forwarded to TaskRunner. */
|
|
59
|
+
spawnFn?: SpawnFn;
|
|
60
|
+
}
|
|
61
|
+
export interface RunSingleTaskResult {
|
|
62
|
+
taskId: string;
|
|
63
|
+
ok: boolean;
|
|
64
|
+
sessionCancelled: boolean;
|
|
65
|
+
/**
|
|
66
|
+
* The session context the caller must use for any work after this call. A
|
|
67
|
+
* successful run replaces the session via ctx.newSession(), which leaves the
|
|
68
|
+
* caller's original ctx stale — this is the fresh replacement ctx and callers
|
|
69
|
+
* MUST adopt it (using the original throws "stale ctx"). On cancellation no
|
|
70
|
+
* replacement happened, so this is the original, still-live ctx. Optional
|
|
71
|
+
* only so test fakes that don't model session replacement can omit it.
|
|
72
|
+
*/
|
|
73
|
+
ctx?: ExtensionCommandContext;
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* Run one prompt through the full single-task pipeline in a fresh session and
|
|
77
|
+
* deliver its spec. With waitForImplementation, block until the agent finishes
|
|
78
|
+
* implementing the delivered spec. Success is read off the produced task file's
|
|
79
|
+
* front-matter state (TaskRunner.run never throws).
|
|
80
|
+
*/
|
|
81
|
+
export declare function runSingleTask(ctx: ExtensionCommandContext, cwd: string, rawPrompt: string, opts?: RunSingleTaskOptions): Promise<RunSingleTaskResult>;
|
|
54
82
|
export declare function registerTask(pi: ExtensionAPI): void;
|
|
@@ -256,6 +256,46 @@ export class TaskRunner {
|
|
|
256
256
|
}
|
|
257
257
|
}
|
|
258
258
|
}
|
|
259
|
+
/**
|
|
260
|
+
* Run one prompt through the full single-task pipeline in a fresh session and
|
|
261
|
+
* deliver its spec. With waitForImplementation, block until the agent finishes
|
|
262
|
+
* implementing the delivered spec. Success is read off the produced task file's
|
|
263
|
+
* front-matter state (TaskRunner.run never throws).
|
|
264
|
+
*/
|
|
265
|
+
export async function runSingleTask(ctx, cwd, rawPrompt, opts = {}) {
|
|
266
|
+
let taskId = '';
|
|
267
|
+
// The newSession replacement ctx, captured so the caller can keep driving the
|
|
268
|
+
// UI after the original ctx is torn down. Defaults to the original for the
|
|
269
|
+
// cancellation path (where no replacement occurs).
|
|
270
|
+
let freshCtx = ctx;
|
|
271
|
+
const result = await ctx.newSession({
|
|
272
|
+
withSession: async (newCtx) => {
|
|
273
|
+
freshCtx = newCtx;
|
|
274
|
+
const runner = new TaskRunner(newCtx, cwd, rawPrompt, undefined, async (spec) => {
|
|
275
|
+
await newCtx.sendUserMessage(spec);
|
|
276
|
+
if (opts.waitForImplementation)
|
|
277
|
+
await newCtx.waitForIdle();
|
|
278
|
+
}, opts.spawnFn);
|
|
279
|
+
await runner.run();
|
|
280
|
+
taskId = runner.taskId;
|
|
281
|
+
}
|
|
282
|
+
});
|
|
283
|
+
if (result.cancelled) {
|
|
284
|
+
// No replacement happened — the original ctx is still live.
|
|
285
|
+
return { taskId, ok: false, sessionCancelled: true, ctx };
|
|
286
|
+
}
|
|
287
|
+
let ok = false;
|
|
288
|
+
if (taskId) {
|
|
289
|
+
try {
|
|
290
|
+
const { frontMatter } = await readTaskFile(cwd, taskId);
|
|
291
|
+
ok = frontMatter.state === 'completed';
|
|
292
|
+
}
|
|
293
|
+
catch {
|
|
294
|
+
ok = false;
|
|
295
|
+
}
|
|
296
|
+
}
|
|
297
|
+
return { taskId, ok, sessionCancelled: false, ctx: freshCtx };
|
|
298
|
+
}
|
|
259
299
|
// ─── Command handlers ────────────────────────────────────────────────────────
|
|
260
300
|
async function handleTask(args, ctx) {
|
|
261
301
|
await ctx.waitForIdle();
|
|
@@ -266,15 +306,8 @@ async function handleTask(args, ctx) {
|
|
|
266
306
|
ctx.ui.notify('Type your prompt after /task (use @ for file completion).', 'info');
|
|
267
307
|
return;
|
|
268
308
|
}
|
|
269
|
-
const
|
|
270
|
-
|
|
271
|
-
const runner = new TaskRunner(newCtx, cwd, raw, undefined, async (spec) => {
|
|
272
|
-
await newCtx.sendUserMessage(spec);
|
|
273
|
-
});
|
|
274
|
-
await runner.run();
|
|
275
|
-
}
|
|
276
|
-
});
|
|
277
|
-
if (result.cancelled) {
|
|
309
|
+
const { sessionCancelled } = await runSingleTask(ctx, cwd, raw);
|
|
310
|
+
if (sessionCancelled) {
|
|
278
311
|
ctx.ui.notify('Could not start a fresh session for /task.', 'warning');
|
|
279
312
|
}
|
|
280
313
|
}
|
package/dist/task/parsers.d.ts
CHANGED
|
@@ -15,10 +15,17 @@ export type AutoAnswer = {
|
|
|
15
15
|
suggested?: string;
|
|
16
16
|
raw: string;
|
|
17
17
|
};
|
|
18
|
+
/** One /task-auto clarify question with its model-recommended default answer. */
|
|
19
|
+
export interface ClarifyQuestion {
|
|
20
|
+
question: string;
|
|
21
|
+
suggested?: string;
|
|
22
|
+
}
|
|
18
23
|
export declare const GRILL_LINE_RE: RegExp;
|
|
24
|
+
export declare const SUGGESTED_LINE_RE: RegExp;
|
|
19
25
|
export declare const TITLE_MAX_CHARS = 120;
|
|
20
26
|
export declare function parseVerifyBlock(spec: string): VerifyCommand[] | null;
|
|
21
27
|
export declare function parseGrillQuestions(raw: string): string[];
|
|
28
|
+
export declare function parseClarifyList(raw: string): ClarifyQuestion[];
|
|
22
29
|
export declare function parseAutoAnswer(raw: string): AutoAnswer;
|
|
23
30
|
export declare function parseVerifyToolingOutput(output: string): {
|
|
24
31
|
verified: string[];
|
|
@@ -28,5 +35,14 @@ export declare function parseVerifyToolingOutput(output: string): {
|
|
|
28
35
|
}>;
|
|
29
36
|
};
|
|
30
37
|
export declare function isCritiqueClean(text: string): boolean;
|
|
38
|
+
/**
|
|
39
|
+
* Drop any preamble the model emitted before the spec's GOAL header. The
|
|
40
|
+
* thinking model sometimes narrates ("Now I have all the context. Here's the
|
|
41
|
+
* rewritten spec:") before GOAL — the prompts forbid it, but the critique
|
|
42
|
+
* validator only checks for a VERIFY block, so it leaked into the delivered
|
|
43
|
+
* spec. We slice from the first line that begins a GOAL section so the spec
|
|
44
|
+
* starts at GOAL. No GOAL line → returned unchanged (validation then flags it).
|
|
45
|
+
*/
|
|
46
|
+
export declare function stripSpecPreamble(spec: string): string;
|
|
31
47
|
export declare function validateSpecShape(spec: string): string | null;
|
|
32
48
|
export declare function deriveTitle(refined: string): string;
|
package/dist/task/parsers.js
CHANGED
|
@@ -6,6 +6,7 @@
|
|
|
6
6
|
import { MAX_GRILL_QUESTIONS } from './phases.js';
|
|
7
7
|
// ─── Constants ───────────────────────────────────────────────────────────────
|
|
8
8
|
export const GRILL_LINE_RE = /^\s*\d+[.)]\s+(.+)$/;
|
|
9
|
+
export const SUGGESTED_LINE_RE = /^\s*SUGGESTED:\s*(.*)$/i;
|
|
9
10
|
export const TITLE_MAX_CHARS = 120;
|
|
10
11
|
// ─── Verify block parser ─────────────────────────────────────────────────────
|
|
11
12
|
export function parseVerifyBlock(spec) {
|
|
@@ -49,6 +50,53 @@ export function parseGrillQuestions(raw) {
|
|
|
49
50
|
}
|
|
50
51
|
return out;
|
|
51
52
|
}
|
|
53
|
+
// ─── Clarify (/task-auto) parser ─────────────────────────────────────────────
|
|
54
|
+
// Matches a "SUGGESTED:" marker anywhere in a string (not just line-start), so
|
|
55
|
+
// we can recover a recommendation the model wrote inline on the question line
|
|
56
|
+
// (e.g. "1. ...so this must be resolved. SUGGESTED: use polling.") rather than
|
|
57
|
+
// on its own line.
|
|
58
|
+
const INLINE_SUGGESTED_RE = /\bSUGGESTED:\s*/i;
|
|
59
|
+
/** Split a question line's text into the question and any inline SUGGESTED default. */
|
|
60
|
+
function splitInlineSuggested(text) {
|
|
61
|
+
const m = INLINE_SUGGESTED_RE.exec(text);
|
|
62
|
+
if (!m)
|
|
63
|
+
return { question: text.trim() };
|
|
64
|
+
const question = text.slice(0, m.index).trim();
|
|
65
|
+
const suggested = text.slice(m.index + m[0].length).trim();
|
|
66
|
+
return suggested.length > 0 ? { question, suggested } : { question };
|
|
67
|
+
}
|
|
68
|
+
// Parses the /task-auto clarify output: a numbered question list where each
|
|
69
|
+
// question carries a "SUGGESTED: <default>" recommendation — either on its own
|
|
70
|
+
// line below the question, or inline at the end of the question line. The first
|
|
71
|
+
// SUGGESTED for a question wins; later ones are ignored. The literal token NONE
|
|
72
|
+
// (its own line) means "no clarification needed" → [].
|
|
73
|
+
//
|
|
74
|
+
// Question/suggested text is returned VERBATIM (markdown intact). Inline
|
|
75
|
+
// markdown is rendered for display / stripped for storage at the call site via
|
|
76
|
+
// the helpers in inline-markdown.ts.
|
|
77
|
+
export function parseClarifyList(raw) {
|
|
78
|
+
if (/^\s*NONE\s*$/m.test(raw))
|
|
79
|
+
return [];
|
|
80
|
+
const out = [];
|
|
81
|
+
for (const line of raw.split('\n')) {
|
|
82
|
+
const q = GRILL_LINE_RE.exec(line);
|
|
83
|
+
if (q) {
|
|
84
|
+
if (out.length >= MAX_GRILL_QUESTIONS)
|
|
85
|
+
break;
|
|
86
|
+
out.push(splitInlineSuggested(q[1].trim()));
|
|
87
|
+
continue;
|
|
88
|
+
}
|
|
89
|
+
const s = SUGGESTED_LINE_RE.exec(line);
|
|
90
|
+
if (s && out.length > 0) {
|
|
91
|
+
const suggested = s[1].trim();
|
|
92
|
+
const last = out[out.length - 1];
|
|
93
|
+
if (suggested.length > 0 && last.suggested === undefined) {
|
|
94
|
+
last.suggested = suggested;
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
return out;
|
|
99
|
+
}
|
|
52
100
|
// ─── Auto-answer parser ──────────────────────────────────────────────────────
|
|
53
101
|
export function parseAutoAnswer(raw) {
|
|
54
102
|
const lines = raw
|
|
@@ -120,6 +168,28 @@ export function isCritiqueClean(text) {
|
|
|
120
168
|
return /^CLEAN[.!]?$/i.test(firstLine);
|
|
121
169
|
}
|
|
122
170
|
// ─── Spec shape validator ────────────────────────────────────────────────────
|
|
171
|
+
/**
|
|
172
|
+
* Drop any preamble the model emitted before the spec's GOAL header. The
|
|
173
|
+
* thinking model sometimes narrates ("Now I have all the context. Here's the
|
|
174
|
+
* rewritten spec:") before GOAL — the prompts forbid it, but the critique
|
|
175
|
+
* validator only checks for a VERIFY block, so it leaked into the delivered
|
|
176
|
+
* spec. We slice from the first line that begins a GOAL section so the spec
|
|
177
|
+
* starts at GOAL. No GOAL line → returned unchanged (validation then flags it).
|
|
178
|
+
*/
|
|
179
|
+
export function stripSpecPreamble(spec) {
|
|
180
|
+
const lines = spec.split('\n');
|
|
181
|
+
const idx = lines.findIndex(l => /^GOAL\b/i.test(l));
|
|
182
|
+
if (idx <= 0)
|
|
183
|
+
return spec;
|
|
184
|
+
// Only strip plain narration. If the lead-in is a markdown fence or a
|
|
185
|
+
// cat-heredoc wrapper, leave it untouched — that's a malformation
|
|
186
|
+
// validateSpecShape must reject (and compose must retry on), not something
|
|
187
|
+
// to silently unwrap into a passing spec.
|
|
188
|
+
const preamble = lines.slice(0, idx);
|
|
189
|
+
if (preamble.some(l => /^\s*```/.test(l) || /^\s*cat\s*<</.test(l)))
|
|
190
|
+
return spec;
|
|
191
|
+
return lines.slice(idx).join('\n');
|
|
192
|
+
}
|
|
123
193
|
export function validateSpecShape(spec) {
|
|
124
194
|
const trimmed = spec.trim();
|
|
125
195
|
if (trimmed.length === 0)
|
package/dist/task/phases.d.ts
CHANGED
|
@@ -6,11 +6,12 @@ import type { ExtensionCommandContext } from '@earendil-works/pi-coding-agent';
|
|
|
6
6
|
import { docsRaw, docsFocused } from '../workers/docs-core.js';
|
|
7
7
|
import { fetchRaw, fetchFocused } from '../workers/fetch-core.js';
|
|
8
8
|
import type { SearchCoreInput, SearchCoreResult } from '../workers/search-core.js';
|
|
9
|
+
import { MAX_GRILL_QUESTIONS } from './prompts.js';
|
|
9
10
|
import { type PhaseName } from './task-file.js';
|
|
10
11
|
import { type WidgetState } from './widget.js';
|
|
11
12
|
import { type AutoAnswer } from './parsers.js';
|
|
12
13
|
import { type PhaseDeps } from './child-runner.js';
|
|
13
|
-
export { MAX_GRILL_QUESTIONS }
|
|
14
|
+
export { MAX_GRILL_QUESTIONS };
|
|
14
15
|
export interface PhaseContext {
|
|
15
16
|
cwd: string;
|
|
16
17
|
id: string;
|