@lnittman/pi-interview 0.4.0
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 +33 -0
- package/dist/adapters/model-client.d.ts +20 -0
- package/dist/adapters/model-client.d.ts.map +1 -0
- package/dist/adapters/model-client.js +129 -0
- package/dist/adapters/model-client.js.map +1 -0
- package/dist/core/demo.d.ts +9 -0
- package/dist/core/demo.d.ts.map +1 -0
- package/dist/core/demo.js +118 -0
- package/dist/core/demo.js.map +1 -0
- package/dist/core/project-context.d.ts +31 -0
- package/dist/core/project-context.d.ts.map +1 -0
- package/dist/core/project-context.js +82 -0
- package/dist/core/project-context.js.map +1 -0
- package/dist/core/signals.d.ts +43 -0
- package/dist/core/signals.d.ts.map +1 -0
- package/dist/core/signals.js +160 -0
- package/dist/core/signals.js.map +1 -0
- package/dist/core/state.d.ts +33 -0
- package/dist/core/state.d.ts.map +1 -0
- package/dist/core/state.js +62 -0
- package/dist/core/state.js.map +1 -0
- package/dist/core/types.d.ts +71 -0
- package/dist/core/types.d.ts.map +1 -0
- package/dist/core/types.js +18 -0
- package/dist/core/types.js.map +1 -0
- package/dist/index.d.ts +9 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +301 -0
- package/dist/index.js.map +1 -0
- package/dist/prompts/compose-template.d.ts +8 -0
- package/dist/prompts/compose-template.d.ts.map +1 -0
- package/dist/prompts/compose-template.js +40 -0
- package/dist/prompts/compose-template.js.map +1 -0
- package/dist/prompts/interview-template.d.ts +24 -0
- package/dist/prompts/interview-template.d.ts.map +1 -0
- package/dist/prompts/interview-template.js +101 -0
- package/dist/prompts/interview-template.js.map +1 -0
- package/dist/ui/interview-ui.d.ts +14 -0
- package/dist/ui/interview-ui.d.ts.map +1 -0
- package/dist/ui/interview-ui.js +285 -0
- package/dist/ui/interview-ui.js.map +1 -0
- package/package.json +51 -0
|
@@ -0,0 +1,160 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Conversation signal extraction — builds TurnContext from pi session data.
|
|
3
|
+
* Adapted from pi-prompt-suggester's conversation-signals.ts with simplifications.
|
|
4
|
+
*/
|
|
5
|
+
function textFromContent(content) {
|
|
6
|
+
if (content == null)
|
|
7
|
+
return "";
|
|
8
|
+
if (typeof content === "string")
|
|
9
|
+
return content;
|
|
10
|
+
if (!Array.isArray(content))
|
|
11
|
+
return "";
|
|
12
|
+
return content
|
|
13
|
+
.map((block) => {
|
|
14
|
+
if (block &&
|
|
15
|
+
typeof block === "object" &&
|
|
16
|
+
"type" in block &&
|
|
17
|
+
block.type === "text" &&
|
|
18
|
+
"text" in block) {
|
|
19
|
+
return String(block.text ?? "");
|
|
20
|
+
}
|
|
21
|
+
return "";
|
|
22
|
+
})
|
|
23
|
+
.join("\n")
|
|
24
|
+
.trim();
|
|
25
|
+
}
|
|
26
|
+
function extractToolSignals(messages) {
|
|
27
|
+
const toolSignals = [];
|
|
28
|
+
const touchedFiles = new Set();
|
|
29
|
+
for (const message of messages) {
|
|
30
|
+
if (message.role === "assistant" && Array.isArray(message.content)) {
|
|
31
|
+
for (const block of message.content) {
|
|
32
|
+
if (block.type === "toolCall") {
|
|
33
|
+
const args = block.arguments;
|
|
34
|
+
const path = typeof args.path === "string" ? args.path : undefined;
|
|
35
|
+
const file = typeof args.file === "string" ? args.file : undefined;
|
|
36
|
+
const command = typeof args.command === "string" ? args.command : undefined;
|
|
37
|
+
const target = path ?? file ?? command;
|
|
38
|
+
toolSignals.push(`${block.name}${target ? `(${target})` : ""}`);
|
|
39
|
+
if (path)
|
|
40
|
+
touchedFiles.add(path.replace(/^@/, ""));
|
|
41
|
+
if (file)
|
|
42
|
+
touchedFiles.add(file.replace(/^@/, ""));
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
if (message.role === "toolResult" && message.isError) {
|
|
47
|
+
toolSignals.push(`${message.toolName}:error`);
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
return { toolSignals, touchedFiles: Array.from(touchedFiles) };
|
|
51
|
+
}
|
|
52
|
+
function extractUnresolvedQuestions(text) {
|
|
53
|
+
return text
|
|
54
|
+
.split(/\n+/)
|
|
55
|
+
.map((line) => line.trim())
|
|
56
|
+
.filter((line) => line.endsWith("?") && line.length > 10 && line.length < 300);
|
|
57
|
+
}
|
|
58
|
+
function extractUsage(message) {
|
|
59
|
+
const usage = message.usage;
|
|
60
|
+
if (!usage)
|
|
61
|
+
return undefined;
|
|
62
|
+
return {
|
|
63
|
+
inputTokens: Number(usage.input ?? 0),
|
|
64
|
+
outputTokens: Number(usage.output ?? 0),
|
|
65
|
+
totalTokens: Number(usage.totalTokens ?? 0),
|
|
66
|
+
costTotal: Number(usage.cost?.total ?? 0),
|
|
67
|
+
};
|
|
68
|
+
}
|
|
69
|
+
function extractRecentUserPrompts(messages) {
|
|
70
|
+
return [...messages]
|
|
71
|
+
.reverse()
|
|
72
|
+
.filter((m) => m.role === "user")
|
|
73
|
+
.map((m) => textFromContent(m.content))
|
|
74
|
+
.filter(Boolean)
|
|
75
|
+
.slice(0, 10);
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* Build turn context from agent_end event messages + full branch.
|
|
79
|
+
* Returns null if no usable assistant message found.
|
|
80
|
+
*/
|
|
81
|
+
export function buildTurnContext(params) {
|
|
82
|
+
const lastMessage = params.messagesFromPrompt.at(-1);
|
|
83
|
+
if (!lastMessage)
|
|
84
|
+
return null;
|
|
85
|
+
const recentUserPrompts = extractRecentUserPrompts(params.branchMessages);
|
|
86
|
+
const { toolSignals, touchedFiles } = extractToolSignals(params.messagesFromPrompt);
|
|
87
|
+
if (lastMessage.role !== "assistant") {
|
|
88
|
+
// Non-assistant ending (tool result, etc)
|
|
89
|
+
return {
|
|
90
|
+
turnId: params.turnId,
|
|
91
|
+
sourceLeafId: params.sourceLeafId,
|
|
92
|
+
assistantText: lastMessage.role === "toolResult" ? "[tool result]" : "[empty]",
|
|
93
|
+
assistantUsage: undefined,
|
|
94
|
+
status: lastMessage.isError ? "error" : "success",
|
|
95
|
+
occurredAt: params.occurredAt,
|
|
96
|
+
recentUserPrompts,
|
|
97
|
+
toolSignals,
|
|
98
|
+
touchedFiles,
|
|
99
|
+
unresolvedQuestions: [],
|
|
100
|
+
abortContextNote: undefined,
|
|
101
|
+
};
|
|
102
|
+
}
|
|
103
|
+
const assistantText = textFromContent(lastMessage.content);
|
|
104
|
+
const status = lastMessage.stopReason === "error"
|
|
105
|
+
? "error"
|
|
106
|
+
: lastMessage.stopReason === "aborted"
|
|
107
|
+
? "aborted"
|
|
108
|
+
: "success";
|
|
109
|
+
return {
|
|
110
|
+
turnId: params.turnId,
|
|
111
|
+
sourceLeafId: params.sourceLeafId,
|
|
112
|
+
assistantText,
|
|
113
|
+
assistantUsage: extractUsage(lastMessage),
|
|
114
|
+
status,
|
|
115
|
+
occurredAt: params.occurredAt,
|
|
116
|
+
recentUserPrompts,
|
|
117
|
+
toolSignals,
|
|
118
|
+
touchedFiles,
|
|
119
|
+
unresolvedQuestions: extractUnresolvedQuestions(assistantText),
|
|
120
|
+
abortContextNote: status === "aborted"
|
|
121
|
+
? "User interrupted the previous turn. Ask about next direction."
|
|
122
|
+
: undefined,
|
|
123
|
+
};
|
|
124
|
+
}
|
|
125
|
+
/**
|
|
126
|
+
* Build turn context from the latest branch entries (for session restore).
|
|
127
|
+
*/
|
|
128
|
+
export function buildTurnContextFromBranch(branchEntries) {
|
|
129
|
+
// Find the last non-user message
|
|
130
|
+
let lastRelevantIndex = -1;
|
|
131
|
+
for (let i = branchEntries.length - 1; i >= 0; i--) {
|
|
132
|
+
if (branchEntries[i]?.message.role !== "user") {
|
|
133
|
+
lastRelevantIndex = i;
|
|
134
|
+
break;
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
if (lastRelevantIndex === -1)
|
|
138
|
+
return null;
|
|
139
|
+
const latestEntry = branchEntries[lastRelevantIndex];
|
|
140
|
+
const branchMessages = branchEntries.map((e) => e.message);
|
|
141
|
+
// Find where this prompt group starts
|
|
142
|
+
let startIndex = 0;
|
|
143
|
+
for (let i = lastRelevantIndex - 1; i >= 0; i--) {
|
|
144
|
+
if (branchEntries[i]?.message.role === "user") {
|
|
145
|
+
startIndex = i + 1;
|
|
146
|
+
break;
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
const occurredAt = typeof latestEntry.message.timestamp === "number"
|
|
150
|
+
? new Date(latestEntry.message.timestamp).toISOString()
|
|
151
|
+
: new Date().toISOString();
|
|
152
|
+
return buildTurnContext({
|
|
153
|
+
turnId: latestEntry.id,
|
|
154
|
+
sourceLeafId: latestEntry.id,
|
|
155
|
+
messagesFromPrompt: branchMessages.slice(startIndex, lastRelevantIndex + 1),
|
|
156
|
+
branchMessages,
|
|
157
|
+
occurredAt,
|
|
158
|
+
});
|
|
159
|
+
}
|
|
160
|
+
//# sourceMappingURL=signals.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"signals.js","sourceRoot":"","sources":["../../src/core/signals.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Session state for pi-quiz.
|
|
3
|
+
*
|
|
4
|
+
* Persisted via pi.appendEntry() so it survives session restores.
|
|
5
|
+
* Tracks usage, skip patterns, and last quiz context.
|
|
6
|
+
*/
|
|
7
|
+
import type { TokenUsage } from "./types.js";
|
|
8
|
+
export interface QuizUsageStats {
|
|
9
|
+
calls: number;
|
|
10
|
+
skips: number;
|
|
11
|
+
cancels: number;
|
|
12
|
+
completions: number;
|
|
13
|
+
totalInputTokens: number;
|
|
14
|
+
totalOutputTokens: number;
|
|
15
|
+
totalCost: number;
|
|
16
|
+
}
|
|
17
|
+
export interface QuizSessionState {
|
|
18
|
+
version: 1;
|
|
19
|
+
usage: QuizUsageStats;
|
|
20
|
+
/** Last quiz turn ID to avoid re-triggering */
|
|
21
|
+
lastQuizTurnId?: string;
|
|
22
|
+
/** Consecutive skips — if too many, back off */
|
|
23
|
+
consecutiveSkips: number;
|
|
24
|
+
}
|
|
25
|
+
export declare function emptyState(): QuizSessionState;
|
|
26
|
+
export declare function recordQuizCall(state: QuizSessionState, usage: TokenUsage | undefined, outcome: "skipped" | "cancelled" | "completed", turnId: string): QuizSessionState;
|
|
27
|
+
/**
|
|
28
|
+
* Should we back off from auto-quizzing?
|
|
29
|
+
* After 3+ consecutive skips/cancels, pause auto mode for this session.
|
|
30
|
+
*/
|
|
31
|
+
export declare function shouldBackOff(state: QuizSessionState): boolean;
|
|
32
|
+
export declare function formatUsageStatus(state: QuizSessionState): string | undefined;
|
|
33
|
+
//# sourceMappingURL=state.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"state.d.ts","sourceRoot":"","sources":["../../src/core/state.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAE7C,MAAM,WAAW,cAAc;IAC7B,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,CAAC;IAChB,WAAW,EAAE,MAAM,CAAC;IACpB,gBAAgB,EAAE,MAAM,CAAC;IACzB,iBAAiB,EAAE,MAAM,CAAC;IAC1B,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,gBAAgB;IAC/B,OAAO,EAAE,CAAC,CAAC;IACX,KAAK,EAAE,cAAc,CAAC;IACtB,+CAA+C;IAC/C,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,gDAAgD;IAChD,gBAAgB,EAAE,MAAM,CAAC;CAC1B;AAED,wBAAgB,UAAU,IAAI,gBAAgB,CAe7C;AAED,wBAAgB,cAAc,CAC5B,KAAK,EAAE,gBAAgB,EACvB,KAAK,EAAE,UAAU,GAAG,SAAS,EAC7B,OAAO,EAAE,SAAS,GAAG,WAAW,GAAG,WAAW,EAC9C,MAAM,EAAE,MAAM,GACb,gBAAgB,CA2BlB;AAED;;;GAGG;AACH,wBAAgB,aAAa,CAAC,KAAK,EAAE,gBAAgB,GAAG,OAAO,CAE9D;AAED,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,gBAAgB,GAAG,MAAM,GAAG,SAAS,CAK7E"}
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Session state for pi-quiz.
|
|
3
|
+
*
|
|
4
|
+
* Persisted via pi.appendEntry() so it survives session restores.
|
|
5
|
+
* Tracks usage, skip patterns, and last quiz context.
|
|
6
|
+
*/
|
|
7
|
+
export function emptyState() {
|
|
8
|
+
return {
|
|
9
|
+
version: 1,
|
|
10
|
+
usage: {
|
|
11
|
+
calls: 0,
|
|
12
|
+
skips: 0,
|
|
13
|
+
cancels: 0,
|
|
14
|
+
completions: 0,
|
|
15
|
+
totalInputTokens: 0,
|
|
16
|
+
totalOutputTokens: 0,
|
|
17
|
+
totalCost: 0,
|
|
18
|
+
},
|
|
19
|
+
lastQuizTurnId: undefined,
|
|
20
|
+
consecutiveSkips: 0,
|
|
21
|
+
};
|
|
22
|
+
}
|
|
23
|
+
export function recordQuizCall(state, usage, outcome, turnId) {
|
|
24
|
+
const next = { ...state, usage: { ...state.usage } };
|
|
25
|
+
next.usage.calls++;
|
|
26
|
+
next.lastQuizTurnId = turnId;
|
|
27
|
+
if (usage) {
|
|
28
|
+
next.usage.totalInputTokens += usage.inputTokens;
|
|
29
|
+
next.usage.totalOutputTokens += usage.outputTokens;
|
|
30
|
+
next.usage.totalCost += usage.costTotal ?? 0;
|
|
31
|
+
}
|
|
32
|
+
switch (outcome) {
|
|
33
|
+
case "skipped":
|
|
34
|
+
next.usage.skips++;
|
|
35
|
+
next.consecutiveSkips++;
|
|
36
|
+
break;
|
|
37
|
+
case "cancelled":
|
|
38
|
+
next.usage.cancels++;
|
|
39
|
+
next.consecutiveSkips++;
|
|
40
|
+
break;
|
|
41
|
+
case "completed":
|
|
42
|
+
next.usage.completions++;
|
|
43
|
+
next.consecutiveSkips = 0;
|
|
44
|
+
break;
|
|
45
|
+
}
|
|
46
|
+
return next;
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* Should we back off from auto-quizzing?
|
|
50
|
+
* After 3+ consecutive skips/cancels, pause auto mode for this session.
|
|
51
|
+
*/
|
|
52
|
+
export function shouldBackOff(state) {
|
|
53
|
+
return state.consecutiveSkips >= 3;
|
|
54
|
+
}
|
|
55
|
+
export function formatUsageStatus(state) {
|
|
56
|
+
if (state.usage.calls === 0)
|
|
57
|
+
return undefined;
|
|
58
|
+
const cost = state.usage.totalCost > 0 ? ` $${state.usage.totalCost.toFixed(4)}` : "";
|
|
59
|
+
const tokens = state.usage.totalInputTokens + state.usage.totalOutputTokens;
|
|
60
|
+
return `✦ quiz: ${state.usage.completions}/${state.usage.calls} used · ${tokens} tok${cost}`;
|
|
61
|
+
}
|
|
62
|
+
//# sourceMappingURL=state.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"state.js","sourceRoot":"","sources":["../../src/core/state.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAuBH,MAAM,UAAU,UAAU;IACxB,OAAO;QACL,OAAO,EAAE,CAAC;QACV,KAAK,EAAE;YACL,KAAK,EAAE,CAAC;YACR,KAAK,EAAE,CAAC;YACR,OAAO,EAAE,CAAC;YACV,WAAW,EAAE,CAAC;YACd,gBAAgB,EAAE,CAAC;YACnB,iBAAiB,EAAE,CAAC;YACpB,SAAS,EAAE,CAAC;SACb;QACD,cAAc,EAAE,SAAS;QACzB,gBAAgB,EAAE,CAAC;KACpB,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,cAAc,CAC5B,KAAuB,EACvB,KAA6B,EAC7B,OAA8C,EAC9C,MAAc;IAEd,MAAM,IAAI,GAAG,EAAE,GAAG,KAAK,EAAE,KAAK,EAAE,EAAE,GAAG,KAAK,CAAC,KAAK,EAAE,EAAE,CAAC;IACrD,IAAI,CAAC,KAAK,CAAC,KAAK,EAAE,CAAC;IACnB,IAAI,CAAC,cAAc,GAAG,MAAM,CAAC;IAE7B,IAAI,KAAK,EAAE,CAAC;QACV,IAAI,CAAC,KAAK,CAAC,gBAAgB,IAAI,KAAK,CAAC,WAAW,CAAC;QACjD,IAAI,CAAC,KAAK,CAAC,iBAAiB,IAAI,KAAK,CAAC,YAAY,CAAC;QACnD,IAAI,CAAC,KAAK,CAAC,SAAS,IAAI,KAAK,CAAC,SAAS,IAAI,CAAC,CAAC;IAC/C,CAAC;IAED,QAAQ,OAAO,EAAE,CAAC;QAChB,KAAK,SAAS;YACZ,IAAI,CAAC,KAAK,CAAC,KAAK,EAAE,CAAC;YACnB,IAAI,CAAC,gBAAgB,EAAE,CAAC;YACxB,MAAM;QACR,KAAK,WAAW;YACd,IAAI,CAAC,KAAK,CAAC,OAAO,EAAE,CAAC;YACrB,IAAI,CAAC,gBAAgB,EAAE,CAAC;YACxB,MAAM;QACR,KAAK,WAAW;YACd,IAAI,CAAC,KAAK,CAAC,WAAW,EAAE,CAAC;YACzB,IAAI,CAAC,gBAAgB,GAAG,CAAC,CAAC;YAC1B,MAAM;IACV,CAAC;IAED,OAAO,IAAI,CAAC;AACd,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,aAAa,CAAC,KAAuB;IACnD,OAAO,KAAK,CAAC,gBAAgB,IAAI,CAAC,CAAC;AACrC,CAAC;AAED,MAAM,UAAU,iBAAiB,CAAC,KAAuB;IACvD,IAAI,KAAK,CAAC,KAAK,CAAC,KAAK,KAAK,CAAC;QAAE,OAAO,SAAS,CAAC;IAC9C,MAAM,IAAI,GAAG,KAAK,CAAC,KAAK,CAAC,SAAS,GAAG,CAAC,CAAC,CAAC,CAAC,KAAK,KAAK,CAAC,KAAK,CAAC,SAAS,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;IACtF,MAAM,MAAM,GAAG,KAAK,CAAC,KAAK,CAAC,gBAAgB,GAAG,KAAK,CAAC,KAAK,CAAC,iBAAiB,CAAC;IAC5E,OAAO,WAAW,KAAK,CAAC,KAAK,CAAC,WAAW,IAAI,KAAK,CAAC,KAAK,CAAC,KAAK,WAAW,MAAM,OAAO,IAAI,EAAE,CAAC;AAC/F,CAAC"}
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* pi-quiz core types
|
|
3
|
+
*
|
|
4
|
+
* Every question is multiple choice. Always.
|
|
5
|
+
* "Type something else..." is the escape hatch for freeform.
|
|
6
|
+
*/
|
|
7
|
+
export interface TurnContext {
|
|
8
|
+
turnId: string;
|
|
9
|
+
sourceLeafId: string;
|
|
10
|
+
assistantText: string;
|
|
11
|
+
assistantUsage?: TokenUsage;
|
|
12
|
+
status: "success" | "error" | "aborted";
|
|
13
|
+
occurredAt: string;
|
|
14
|
+
recentUserPrompts: string[];
|
|
15
|
+
toolSignals: string[];
|
|
16
|
+
touchedFiles: string[];
|
|
17
|
+
unresolvedQuestions: string[];
|
|
18
|
+
abortContextNote?: string;
|
|
19
|
+
}
|
|
20
|
+
export interface TokenUsage {
|
|
21
|
+
inputTokens: number;
|
|
22
|
+
outputTokens: number;
|
|
23
|
+
totalTokens: number;
|
|
24
|
+
costTotal?: number;
|
|
25
|
+
}
|
|
26
|
+
export type QuestionType = "single" | "multi";
|
|
27
|
+
export interface QuizOption {
|
|
28
|
+
label: string;
|
|
29
|
+
description?: string;
|
|
30
|
+
}
|
|
31
|
+
export interface QuizQuestion {
|
|
32
|
+
id: string;
|
|
33
|
+
text: string;
|
|
34
|
+
/** single = pick one, multi = pick several */
|
|
35
|
+
type: QuestionType;
|
|
36
|
+
/** Always present — every question is multiple choice */
|
|
37
|
+
options: QuizOption[];
|
|
38
|
+
}
|
|
39
|
+
export interface QuizResult {
|
|
40
|
+
questions: QuizQuestion[];
|
|
41
|
+
skipped: boolean;
|
|
42
|
+
skipReason?: string;
|
|
43
|
+
usage?: TokenUsage;
|
|
44
|
+
}
|
|
45
|
+
export interface QuizAnswer {
|
|
46
|
+
questionId: string;
|
|
47
|
+
/** Selected option labels */
|
|
48
|
+
selectedOptions?: string[];
|
|
49
|
+
/** Freeform text from "Type something else..." */
|
|
50
|
+
text?: string;
|
|
51
|
+
skipped: boolean;
|
|
52
|
+
}
|
|
53
|
+
export interface QuizSubmission {
|
|
54
|
+
answers: QuizAnswer[];
|
|
55
|
+
composedPrompt: string;
|
|
56
|
+
cancelled: boolean;
|
|
57
|
+
durationMs: number;
|
|
58
|
+
}
|
|
59
|
+
export interface QuizConfig {
|
|
60
|
+
model: string;
|
|
61
|
+
maxQuestions: number;
|
|
62
|
+
maxOptions: number;
|
|
63
|
+
maxPromptChars: number;
|
|
64
|
+
autoSubmitSingle: boolean;
|
|
65
|
+
mode: "auto" | "manual";
|
|
66
|
+
skipOnSimpleResponse: boolean;
|
|
67
|
+
thinkingLevel: "off" | "minimal" | "low";
|
|
68
|
+
customInstruction: string;
|
|
69
|
+
}
|
|
70
|
+
export declare const DEFAULT_CONFIG: QuizConfig;
|
|
71
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/core/types.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAIH,MAAM,WAAW,WAAW;IAC1B,MAAM,EAAE,MAAM,CAAC;IACf,YAAY,EAAE,MAAM,CAAC;IACrB,aAAa,EAAE,MAAM,CAAC;IACtB,cAAc,CAAC,EAAE,UAAU,CAAC;IAC5B,MAAM,EAAE,SAAS,GAAG,OAAO,GAAG,SAAS,CAAC;IACxC,UAAU,EAAE,MAAM,CAAC;IACnB,iBAAiB,EAAE,MAAM,EAAE,CAAC;IAC5B,WAAW,EAAE,MAAM,EAAE,CAAC;IACtB,YAAY,EAAE,MAAM,EAAE,CAAC;IACvB,mBAAmB,EAAE,MAAM,EAAE,CAAC;IAC9B,gBAAgB,CAAC,EAAE,MAAM,CAAC;CAC3B;AAED,MAAM,WAAW,UAAU;IACzB,WAAW,EAAE,MAAM,CAAC;IACpB,YAAY,EAAE,MAAM,CAAC;IACrB,WAAW,EAAE,MAAM,CAAC;IACpB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAID,MAAM,MAAM,YAAY,GAAG,QAAQ,GAAG,OAAO,CAAC;AAE9C,MAAM,WAAW,UAAU;IACzB,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED,MAAM,WAAW,YAAY;IAC3B,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,8CAA8C;IAC9C,IAAI,EAAE,YAAY,CAAC;IACnB,yDAAyD;IACzD,OAAO,EAAE,UAAU,EAAE,CAAC;CACvB;AAED,MAAM,WAAW,UAAU;IACzB,SAAS,EAAE,YAAY,EAAE,CAAC;IAC1B,OAAO,EAAE,OAAO,CAAC;IACjB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,KAAK,CAAC,EAAE,UAAU,CAAC;CACpB;AAID,MAAM,WAAW,UAAU;IACzB,UAAU,EAAE,MAAM,CAAC;IACnB,6BAA6B;IAC7B,eAAe,CAAC,EAAE,MAAM,EAAE,CAAC;IAC3B,kDAAkD;IAClD,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,OAAO,CAAC;CAClB;AAED,MAAM,WAAW,cAAc;IAC7B,OAAO,EAAE,UAAU,EAAE,CAAC;IACtB,cAAc,EAAE,MAAM,CAAC;IACvB,SAAS,EAAE,OAAO,CAAC;IACnB,UAAU,EAAE,MAAM,CAAC;CACpB;AAID,MAAM,WAAW,UAAU;IACzB,KAAK,EAAE,MAAM,CAAC;IACd,YAAY,EAAE,MAAM,CAAC;IACrB,UAAU,EAAE,MAAM,CAAC;IACnB,cAAc,EAAE,MAAM,CAAC;IACvB,gBAAgB,EAAE,OAAO,CAAC;IAC1B,IAAI,EAAE,MAAM,GAAG,QAAQ,CAAC;IACxB,oBAAoB,EAAE,OAAO,CAAC;IAC9B,aAAa,EAAE,KAAK,GAAG,SAAS,GAAG,KAAK,CAAC;IACzC,iBAAiB,EAAE,MAAM,CAAC;CAC3B;AAED,eAAO,MAAM,cAAc,EAAE,UAU5B,CAAC"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* pi-quiz core types
|
|
3
|
+
*
|
|
4
|
+
* Every question is multiple choice. Always.
|
|
5
|
+
* "Type something else..." is the escape hatch for freeform.
|
|
6
|
+
*/
|
|
7
|
+
export const DEFAULT_CONFIG = {
|
|
8
|
+
model: "anthropic/claude-haiku-4-5-20251001",
|
|
9
|
+
maxQuestions: 3,
|
|
10
|
+
maxOptions: 5,
|
|
11
|
+
maxPromptChars: 500,
|
|
12
|
+
autoSubmitSingle: true,
|
|
13
|
+
mode: "auto",
|
|
14
|
+
skipOnSimpleResponse: true,
|
|
15
|
+
thinkingLevel: "off",
|
|
16
|
+
customInstruction: "",
|
|
17
|
+
};
|
|
18
|
+
//# sourceMappingURL=types.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/core/types.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAkFH,MAAM,CAAC,MAAM,cAAc,GAAe;IACxC,KAAK,EAAE,qCAAqC;IAC5C,YAAY,EAAE,CAAC;IACf,UAAU,EAAE,CAAC;IACb,cAAc,EAAE,GAAG;IACnB,gBAAgB,EAAE,IAAI;IACtB,IAAI,EAAE,MAAM;IACZ,oBAAoB,EAAE,IAAI;IAC1B,aAAa,EAAE,KAAK;IACpB,iBAAiB,EAAE,EAAE;CACtB,CAAC"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* pi-quiz — Multiple-choice next-prompt quiz for pi.
|
|
3
|
+
*
|
|
4
|
+
* Every question is multiple choice. Grounded in specific files, errors, signals.
|
|
5
|
+
* Ctrl+Q to trigger. /quiz for commands. Haiku by default.
|
|
6
|
+
*/
|
|
7
|
+
import type { ExtensionAPI } from "@mariozechner/pi-coding-agent";
|
|
8
|
+
export default function interview(pi: ExtensionAPI): void;
|
|
9
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EACV,YAAY,EAEb,MAAM,+BAA+B,CAAC;AAuBvC,MAAM,CAAC,OAAO,UAAU,SAAS,CAAC,EAAE,EAAE,YAAY,QAoUjD"}
|