@henryqw/pi-prompt-creator 3.1.0 → 3.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/README.md +1 -1
- package/extensions/prompt-creator.ts +12 -24
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -6,7 +6,7 @@ Automatic analysis only prepares a candidate; the extension never saves it witho
|
|
|
6
6
|
|
|
7
7
|
## Install
|
|
8
8
|
|
|
9
|
-
Requires Pi 1.1.0 or later. Older Pi releases are no longer supported.
|
|
9
|
+
Requires Pi 1.1.0 or later in the 1.x series. Older Pi releases are no longer supported.
|
|
10
10
|
|
|
11
11
|
```bash
|
|
12
12
|
pi install npm:@henryqw/pi-task-models
|
|
@@ -35,7 +35,7 @@ const READY_WIDGET = "Prompt ready — /promptor";
|
|
|
35
35
|
const FAILURE_WIDGET = "Prompt analysis failed — /promptor";
|
|
36
36
|
const REFINEMENT_GUIDANCE = "Refine this candidate conversationally with the user. When the user approves it, Main must emit only the complete Final Prompt Draft. Then run /promptor save to use the suggested name, or /promptor save <name>.";
|
|
37
37
|
|
|
38
|
-
|
|
38
|
+
const DRAFT_TASK = {
|
|
39
39
|
id: "pi-prompt-creator/draft",
|
|
40
40
|
label: "Prompt draft",
|
|
41
41
|
purpose: "Find a reusable prompt candidate in the current conversation.",
|
|
@@ -61,15 +61,16 @@ The object must have exactly these keys. name must start with a lowercase ASCII
|
|
|
61
61
|
} satisfies Role;
|
|
62
62
|
|
|
63
63
|
type Config = { automatic: boolean; inputThreshold: number };
|
|
64
|
-
|
|
64
|
+
type PromptCandidate = { name: string; markdown: string };
|
|
65
65
|
type ConversationItem = { role: "summary" | "user" | "assistant"; text: string };
|
|
66
66
|
type ContextMessage = ReturnType<typeof buildSessionContext>["messages"][number];
|
|
67
|
+
type MessageContent = Extract<ContextMessage, { role: "user" | "assistant" }>["content"];
|
|
67
68
|
type ExistingPrompt = { name: string; description: string };
|
|
68
69
|
type AnalysisPayload = { currentConversation: ConversationItem[]; existingPrompts: ExistingPrompt[] };
|
|
69
70
|
type ActiveRun = { controller: AbortController; branchGeneration: number };
|
|
70
71
|
type ReviewBoundary = { entryId: string };
|
|
71
72
|
|
|
72
|
-
|
|
73
|
+
interface PromptCreatorOptions {
|
|
73
74
|
agentDir?: string;
|
|
74
75
|
executor?: EphemeralSubagentExecutor;
|
|
75
76
|
}
|
|
@@ -94,11 +95,11 @@ function parseConfig(value: unknown): Config {
|
|
|
94
95
|
return { automatic, inputThreshold };
|
|
95
96
|
}
|
|
96
97
|
|
|
97
|
-
|
|
98
|
+
function isPromptName(value: unknown): value is string {
|
|
98
99
|
return typeof value === "string" && value.length <= MAX_NAME_CHARS && NAME.test(value);
|
|
99
100
|
}
|
|
100
101
|
|
|
101
|
-
|
|
102
|
+
function isPromptMarkdown(value: unknown): value is string {
|
|
102
103
|
return typeof value === "string"
|
|
103
104
|
&& value.trim().length > 0
|
|
104
105
|
&& Buffer.byteLength(value, "utf8") <= MAX_MARKDOWN_BYTES
|
|
@@ -121,18 +122,10 @@ export function parseDraftOutput(output: string): PromptCandidate | null {
|
|
|
121
122
|
return { name: candidate.name, markdown: candidate.markdown };
|
|
122
123
|
}
|
|
123
124
|
|
|
124
|
-
function messageText(content:
|
|
125
|
+
function messageText(content: MessageContent): string {
|
|
125
126
|
if (typeof content === "string") return content;
|
|
126
127
|
if (!Array.isArray(content)) return "";
|
|
127
|
-
return content
|
|
128
|
-
.flatMap((part) =>
|
|
129
|
-
part && typeof part === "object" && !Array.isArray(part)
|
|
130
|
-
&& (part as Record<string, unknown>).type === "text"
|
|
131
|
-
&& typeof (part as Record<string, unknown>).text === "string"
|
|
132
|
-
? [(part as { text: string }).text]
|
|
133
|
-
: [],
|
|
134
|
-
)
|
|
135
|
-
.join("\n");
|
|
128
|
+
return content.flatMap((part) => (part.type === "text" ? [part.text] : [])).join("\n");
|
|
136
129
|
}
|
|
137
130
|
|
|
138
131
|
function conversationItem(message: ContextMessage): ConversationItem | undefined {
|
|
@@ -229,11 +222,7 @@ ${quotedMarkdown}
|
|
|
229
222
|
${REFINEMENT_GUIDANCE}`;
|
|
230
223
|
}
|
|
231
224
|
|
|
232
|
-
function
|
|
233
|
-
return error && typeof error === "object" && "code" in error ? String(error.code) : undefined;
|
|
234
|
-
}
|
|
235
|
-
|
|
236
|
-
export async function createPromptFile(path: string, markdown: string): Promise<void> {
|
|
225
|
+
async function createPromptFile(path: string, markdown: string): Promise<void> {
|
|
237
226
|
await mkdir(dirname(path), { recursive: true });
|
|
238
227
|
let file: Awaited<ReturnType<typeof open>> | undefined;
|
|
239
228
|
let created = false;
|
|
@@ -289,10 +278,10 @@ export default function promptCreatorExtension(pi: ExtensionAPI, options: Prompt
|
|
|
289
278
|
const showFailure = (ctx: ExtensionContext) => {
|
|
290
279
|
failure = true;
|
|
291
280
|
candidate = undefined;
|
|
292
|
-
|
|
281
|
+
ctx.ui.setWidget(WIDGET_KEY, [FAILURE_WIDGET]);
|
|
293
282
|
};
|
|
294
283
|
const isCurrent = (run: ActiveRun) =>
|
|
295
|
-
activeRun === run && branchGeneration === run.branchGeneration
|
|
284
|
+
activeRun === run && branchGeneration === run.branchGeneration;
|
|
296
285
|
const resetBranch = (ctx: ExtensionContext) => {
|
|
297
286
|
branchGeneration += 1;
|
|
298
287
|
inputCount = 0;
|
|
@@ -322,7 +311,6 @@ export default function promptCreatorExtension(pi: ExtensionAPI, options: Prompt
|
|
|
322
311
|
reviewBoundary = boundaryId ? { entryId: boundaryId } : undefined;
|
|
323
312
|
};
|
|
324
313
|
const startAnalysis = (ctx: ExtensionContext, manual: boolean) => {
|
|
325
|
-
if (ctx.mode !== "tui" || activeRun || candidate) return;
|
|
326
314
|
if (manual) automaticConsumed = true;
|
|
327
315
|
failure = false;
|
|
328
316
|
candidateNameHint = undefined;
|
|
@@ -391,7 +379,7 @@ export default function promptCreatorExtension(pi: ExtensionAPI, options: Prompt
|
|
|
391
379
|
await createPromptFile(path, draft);
|
|
392
380
|
} catch (error) {
|
|
393
381
|
ctx.ui.notify(
|
|
394
|
-
|
|
382
|
+
(error as NodeJS.ErrnoException).code === "EEXIST" ? `Prompt /${name} already exists.` : `Could not save /${name}.`,
|
|
395
383
|
"error",
|
|
396
384
|
);
|
|
397
385
|
return;
|