pi-quests 0.6.0 → 0.6.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/CHANGELOG.md +9 -0
- package/README.md +1 -1
- package/package.json +1 -1
- package/src/config.ts +6 -2
- package/src/index.ts +24 -25
- package/src/prompts/skill.md +42 -45
- package/src/quest/tracker.ts +15 -23
- package/src/renderers/status.ts +6 -1
- package/src/tools/handler.ts +24 -4
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,15 @@
|
|
|
2
2
|
|
|
3
3
|
## [Unreleased]
|
|
4
4
|
|
|
5
|
+
## [0.6.2] - 2026-04-17
|
|
6
|
+
|
|
7
|
+
- fix: system prompt was too weak
|
|
8
|
+
- chore: add more roadmap items
|
|
9
|
+
|
|
10
|
+
## [0.6.1] - 2026-04-17
|
|
11
|
+
|
|
12
|
+
- fix: make quest prompt injection static and cache-friendly with `nudges.enable` and `display.showStatus` toggles
|
|
13
|
+
|
|
5
14
|
## [0.6.0] - 2026-04-17
|
|
6
15
|
|
|
7
16
|
- feat: add footer quest progress indicator with configurable icon
|
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# pi-quests
|
|
2
2
|
|
|
3
|
-
[](CHANGELOG.md)
|
|
4
4
|
[](LICENSE.md)
|
|
5
5
|
[](https://github.com/badlogic/pi-mono/tree/main/packages/coding-agent)
|
|
6
6
|
|
package/package.json
CHANGED
package/src/config.ts
CHANGED
|
@@ -5,8 +5,9 @@ import { getAgentDir } from "@mariozechner/pi-coding-agent";
|
|
|
5
5
|
|
|
6
6
|
export interface ResolvedConfig {
|
|
7
7
|
ids: { length: number };
|
|
8
|
-
display: { pageSize: number; progressBarMaxWidth: number; icon: string };
|
|
8
|
+
display: { pageSize: number; progressBarMaxWidth: number; icon: string; showStatus: boolean };
|
|
9
9
|
nudges: {
|
|
10
|
+
enable: boolean;
|
|
10
11
|
toolCallThreshold: number;
|
|
11
12
|
hintIntervalMinutes: number;
|
|
12
13
|
timeBasedToolCallThreshold: number;
|
|
@@ -35,8 +36,9 @@ export const DEFAULT_FAKE_DONE_PATTERN = String.raw`\s[-\u2013\u2014]\s*(DONE|CO
|
|
|
35
36
|
|
|
36
37
|
export const DEFAULT_CONFIG: ResolvedConfig = {
|
|
37
38
|
ids: { length: 2 },
|
|
38
|
-
display: { pageSize: 10, progressBarMaxWidth: 24, icon: "" },
|
|
39
|
+
display: { pageSize: 10, progressBarMaxWidth: 24, icon: "", showStatus: true },
|
|
39
40
|
nudges: {
|
|
41
|
+
enable: true,
|
|
40
42
|
toolCallThreshold: 8,
|
|
41
43
|
hintIntervalMinutes: 4,
|
|
42
44
|
timeBasedToolCallThreshold: 8,
|
|
@@ -115,8 +117,10 @@ export function getConfig(ctx: Pick<ExtensionContext, "cwd">): ResolvedConfig {
|
|
|
115
117
|
progressBarMaxWidth:
|
|
116
118
|
user.display?.progressBarMaxWidth ?? DEFAULT_CONFIG.display.progressBarMaxWidth,
|
|
117
119
|
icon: user.display?.icon ?? DEFAULT_CONFIG.display.icon,
|
|
120
|
+
showStatus: user.display?.showStatus ?? DEFAULT_CONFIG.display.showStatus,
|
|
118
121
|
},
|
|
119
122
|
nudges: {
|
|
123
|
+
enable: user.nudges?.enable ?? DEFAULT_CONFIG.nudges.enable,
|
|
120
124
|
toolCallThreshold: user.nudges?.toolCallThreshold ?? DEFAULT_CONFIG.nudges.toolCallThreshold,
|
|
121
125
|
hintIntervalMinutes:
|
|
122
126
|
user.nudges?.hintIntervalMinutes ?? DEFAULT_CONFIG.nudges.hintIntervalMinutes,
|
package/src/index.ts
CHANGED
|
@@ -6,7 +6,6 @@ import { DEFAULT_CONFIG, getConfig, type ResolvedConfig } from "./config.js";
|
|
|
6
6
|
import { logger } from "./logger.js";
|
|
7
7
|
import { QUEST_PROMPT_GATE } from "./prompts.js";
|
|
8
8
|
import { QuestLog } from "./quest/dataplane.js";
|
|
9
|
-
import { formatQuestList } from "./quest/formatters.js";
|
|
10
9
|
import { QuestUsageTracker } from "./quest/tracker.js";
|
|
11
10
|
import { questChangelogRenderer } from "./renderers/changelog.js";
|
|
12
11
|
import { QuestStatusWidget } from "./renderers/status.js";
|
|
@@ -22,11 +21,20 @@ import { registerQuestTool } from "./tools/handler.js";
|
|
|
22
21
|
* - Snapshot relevant session state at each quest milestone.
|
|
23
22
|
* - Provide rollback support to restore a previous snapshot.
|
|
24
23
|
*/
|
|
24
|
+
const NO_QUESTS_REMINDER =
|
|
25
|
+
"No active quests. Use the learn_quests tool to understand how to use quests and use quests to track this task. DO THIS NOW and acknowledge it.";
|
|
26
|
+
|
|
27
|
+
const FAKE_DONE_REMINDER =
|
|
28
|
+
"QUEST REMINDER: A quest has a completion marker appended to its description but is not toggled done. Use the list action to find it, then toggle it done. NEVER append completion markers via update.";
|
|
29
|
+
|
|
25
30
|
export default function (pi: ExtensionAPI): void {
|
|
26
31
|
let questLog = new QuestLog();
|
|
27
32
|
let tracker = new QuestUsageTracker(DEFAULT_CONFIG);
|
|
28
33
|
let config: ResolvedConfig = DEFAULT_CONFIG;
|
|
29
|
-
let statusWidget = new QuestStatusWidget(
|
|
34
|
+
let statusWidget = new QuestStatusWidget(
|
|
35
|
+
DEFAULT_CONFIG.display.icon,
|
|
36
|
+
DEFAULT_CONFIG.display.showStatus,
|
|
37
|
+
);
|
|
30
38
|
|
|
31
39
|
const shortcutKey = getConfig({ cwd: process.cwd() }).shortcuts?.openQuests ?? "ctrl+shift+l";
|
|
32
40
|
logger.debug("quests:shortcut", "register", { key: shortcutKey });
|
|
@@ -49,8 +57,9 @@ export default function (pi: ExtensionAPI): void {
|
|
|
49
57
|
config = getConfig(ctx);
|
|
50
58
|
questLog = new QuestLog(config);
|
|
51
59
|
tracker = new QuestUsageTracker(config);
|
|
52
|
-
statusWidget = new QuestStatusWidget(config.display.icon);
|
|
60
|
+
statusWidget = new QuestStatusWidget(config.display.icon, config.display.showStatus);
|
|
53
61
|
questLog.reconstructFromSession(ctx);
|
|
62
|
+
if (questLog.getAll().length > 0) tracker.markQuestToolUsed();
|
|
54
63
|
statusWidget.update(questLog, ctx.ui, ctx.ui.theme);
|
|
55
64
|
|
|
56
65
|
registerQuestTool(pi, questLog, config);
|
|
@@ -66,6 +75,7 @@ export default function (pi: ExtensionAPI): void {
|
|
|
66
75
|
|
|
67
76
|
pi.on("session_tree", async (_event, ctx) => {
|
|
68
77
|
questLog.reconstructFromSession(ctx);
|
|
78
|
+
if (questLog.getAll().length > 0) tracker.markQuestToolUsed();
|
|
69
79
|
statusWidget.update(questLog, ctx.ui, ctx.ui.theme);
|
|
70
80
|
});
|
|
71
81
|
|
|
@@ -79,6 +89,7 @@ export default function (pi: ExtensionAPI): void {
|
|
|
79
89
|
});
|
|
80
90
|
|
|
81
91
|
pi.on("context", async (event) => {
|
|
92
|
+
if (!config.nudges.enable) return undefined;
|
|
82
93
|
const latestPrompt = event.messages
|
|
83
94
|
.filter((m) => m.role === "user")
|
|
84
95
|
.map((m) => (typeof m.content === "string" ? m.content : ""))
|
|
@@ -91,44 +102,32 @@ export default function (pi: ExtensionAPI): void {
|
|
|
91
102
|
const hasTopLevelQuestWithoutSubs = activeTopLevel.some(
|
|
92
103
|
(q) => !allQuests.some((step) => (step as { parentId?: string }).parentId === q.id),
|
|
93
104
|
);
|
|
94
|
-
const nudge = tracker.getNudge(
|
|
95
|
-
activeQuestCount,
|
|
96
|
-
allQuests,
|
|
97
|
-
latestPrompt,
|
|
98
|
-
hasTopLevelQuestWithoutSubs,
|
|
99
|
-
);
|
|
105
|
+
const nudge = tracker.getNudge(activeQuestCount, latestPrompt, hasTopLevelQuestWithoutSubs);
|
|
100
106
|
|
|
101
107
|
const fakeDoneRegex = new RegExp(config.validation.fakeDonePattern, "i");
|
|
102
108
|
const fakeDone = questLog.getAll().find((q) => !q.done && fakeDoneRegex.test(q.description));
|
|
103
109
|
if (!nudge && !fakeDone) return undefined;
|
|
104
110
|
|
|
105
|
-
|
|
106
|
-
if (
|
|
107
|
-
|
|
108
|
-
}
|
|
111
|
+
const parts: string[] = [];
|
|
112
|
+
if (nudge) parts.push(nudge);
|
|
113
|
+
if (fakeDone) parts.push(FAKE_DONE_REMINDER);
|
|
109
114
|
|
|
110
115
|
const reminder: UserMessage = {
|
|
111
116
|
role: "user",
|
|
112
|
-
content:
|
|
117
|
+
content: parts.join("\n"),
|
|
113
118
|
timestamp: Date.now(),
|
|
114
119
|
};
|
|
115
120
|
return { messages: [...event.messages, reminder] };
|
|
116
121
|
});
|
|
117
122
|
|
|
118
123
|
pi.on("before_agent_start", async (event) => {
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
const list = formatQuestList(quests);
|
|
124
|
-
reminder = `Active quests (${remaining}/${quests.length}):\n${list}\n\nKeep quest progress updated as you work.`;
|
|
125
|
-
} else {
|
|
126
|
-
reminder =
|
|
127
|
-
"No active quests. Use the quest tool to track your work. Use action: 'skill' for usage documentation.";
|
|
128
|
-
}
|
|
124
|
+
if (questLog.getAll().length === 0)
|
|
125
|
+
return {
|
|
126
|
+
systemPrompt: `${event.systemPrompt}\n\nUse quests to track this task. DO THIS now and acknowledge it.`,
|
|
127
|
+
};
|
|
129
128
|
|
|
130
129
|
return {
|
|
131
|
-
systemPrompt: `# Quest Management\n${QUEST_PROMPT_GATE}${event.systemPrompt}\n\n## Quest Management\n${
|
|
130
|
+
systemPrompt: `# Quest Management\n${QUEST_PROMPT_GATE}${event.systemPrompt}\n\n## Quest Management\n${NO_QUESTS_REMINDER}`,
|
|
132
131
|
};
|
|
133
132
|
});
|
|
134
133
|
|
package/src/prompts/skill.md
CHANGED
|
@@ -5,56 +5,53 @@ description: Quest management best practices for the pi-quests extension. Use wh
|
|
|
5
5
|
|
|
6
6
|
# Quest Management
|
|
7
7
|
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
|
15
|
-
|
|
16
|
-
| `
|
|
17
|
-
| `
|
|
18
|
-
| `
|
|
19
|
-
| `
|
|
20
|
-
| `
|
|
21
|
-
| `
|
|
22
|
-
| `
|
|
23
|
-
| `
|
|
24
|
-
| `
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
4.
|
|
34
|
-
|
|
35
|
-
### Delegation
|
|
36
|
-
1.
|
|
37
|
-
2.
|
|
38
|
-
3.
|
|
8
|
+
This skill provides guidelines and best practices for using the quest management system in the pi-quests extension. It covers the core actions available for managing quests, recommended workflows for common use cases, and important rules to follow for effective task tracking and progress management.
|
|
9
|
+
|
|
10
|
+
## Action Reference
|
|
11
|
+
|
|
12
|
+
| Action | Required Params | Behavior |
|
|
13
|
+
|--------|----------------|----------|
|
|
14
|
+
| `add` | `descriptions[]` | Create top-level quests. Batch multiple descriptions in one call. |
|
|
15
|
+
| `split` | `id`, `descriptions[]` | Break a quest into steps under it. Alias: `add_step`. |
|
|
16
|
+
| `list` | — | View all quests and steps. |
|
|
17
|
+
| `toggle` | `id` | Flip done status. Blocked if parent has incomplete steps. |
|
|
18
|
+
| `update` | `id`, `description` | Change description. |
|
|
19
|
+
| `delete` | `id` | Remove a quest. Blocked if parent has incomplete steps. Cascade-deletes done steps of a done parent. |
|
|
20
|
+
| `clear` | — | Remove completed quests. `all: true` removes everything. |
|
|
21
|
+
| `reorder` | `id`, `targetId` | Move a top-level quest before `targetId`. Steps cannot be reordered. |
|
|
22
|
+
| `reparent` | `id`, `parentId?` | Demote to step under `parentId`, or promote to top-level if `parentId` omitted. |
|
|
23
|
+
| `revert` | — | Undo the most recent mutating action. One level only. |
|
|
24
|
+
| `rules` / `skill` | — | Return this document. |
|
|
25
|
+
|
|
26
|
+
## Workflows
|
|
27
|
+
|
|
28
|
+
### Multi-step task
|
|
29
|
+
1. `add` top-level quests for the overall goal
|
|
30
|
+
2. `split` them into steps for each deliverable
|
|
31
|
+
3. Execute steps sequentially, `toggle` each done as you finish
|
|
32
|
+
4. `add` other top-level quests for other related work of this goal
|
|
33
|
+
4. `toggle` the parent done only after all steps are complete
|
|
34
|
+
|
|
35
|
+
### Delegation
|
|
36
|
+
1. `add` a quest for the delegated task
|
|
37
|
+
2. `spawn` the minion and assign the work
|
|
38
|
+
3. `toggle` the quest done when the minion returns successfully
|
|
39
39
|
|
|
40
40
|
### Reparenting
|
|
41
41
|
- Promote a step: `reparent <step-id>` (omit `parentId`)
|
|
42
42
|
- Demote a quest: `reparent <quest-id> <parent-id>`
|
|
43
43
|
- Move a step: `reparent <step-id> <new-parent-id>`
|
|
44
44
|
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
- Steps cannot have nested steps. Only top-level quests can be parents.
|
|
48
|
-
- A parent with incomplete steps cannot be toggled done or deleted.
|
|
49
|
-
- Deleting a done parent cascade-deletes its done steps.
|
|
50
|
-
- Revert only undoes the most recent mutating action.
|
|
51
|
-
- Quest IDs are random hex strings shown in square brackets (e.g., `[01]`, `[a3f1]`).
|
|
52
|
-
- Always use the hex ID for actions, never the positional number.
|
|
45
|
+
### Cleanup
|
|
46
|
+
- `clear` completed quests before adding unrelated work. Keeps the log focused.
|
|
53
47
|
|
|
54
|
-
##
|
|
48
|
+
## Rules
|
|
55
49
|
|
|
56
|
-
-
|
|
57
|
-
-
|
|
58
|
-
-
|
|
59
|
-
-
|
|
60
|
-
-
|
|
50
|
+
- ALWAYS use quests for any work that involves multiple turns.
|
|
51
|
+
- NEVER try to nest steps. Only top-level quests can be parents.
|
|
52
|
+
- NEVER mark a parent as done if they have incomplete steps.
|
|
53
|
+
- NEVER delete a quest with incomplete steps.
|
|
54
|
+
- Use revert if you make a mistake to undo an action.
|
|
55
|
+
- ALWAYS use the hex ID, never the positional number when referring to quests in actions.
|
|
56
|
+
- ALWAYS Use `toggle` for done states. NEVER use `update` to append "DONE" or any completion marker to a description.
|
|
57
|
+
- If a parent toggle is blocked, check that all its steps are done first.
|
package/src/quest/tracker.ts
CHANGED
|
@@ -1,20 +1,8 @@
|
|
|
1
1
|
import type { ResolvedConfig } from "../config.js";
|
|
2
2
|
import { logger } from "../logger.js";
|
|
3
|
-
import type { Quest } from "./types.js";
|
|
4
3
|
|
|
5
4
|
const ACKNOWLEDGEMENT = "Update your quest status before continuing.";
|
|
6
5
|
|
|
7
|
-
function formatActiveQuests(allQuests: Quest[], limit = 3): string {
|
|
8
|
-
const active = allQuests.filter((q) => !q.done);
|
|
9
|
-
if (active.length === 0) return "";
|
|
10
|
-
|
|
11
|
-
const shown = active.slice(0, limit);
|
|
12
|
-
const lines = shown.map((q) => ` [${q.id}]: ${q.description}`);
|
|
13
|
-
if (active.length > limit) lines.push(` ... and ${active.length - limit} more`);
|
|
14
|
-
|
|
15
|
-
return `\nActive quests:\n${lines.join("\n")}`;
|
|
16
|
-
}
|
|
17
|
-
|
|
18
6
|
type NudgeCandidate = { index: number; message: string };
|
|
19
7
|
|
|
20
8
|
export class QuestUsageTracker {
|
|
@@ -43,9 +31,17 @@ export class QuestUsageTracker {
|
|
|
43
31
|
this.nudgedThisTurn = false;
|
|
44
32
|
}
|
|
45
33
|
|
|
34
|
+
get hasUsedQuestTool(): boolean {
|
|
35
|
+
return this.hasEverUsedQuestTool;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
markQuestToolUsed(): void {
|
|
39
|
+
this.hasEverUsedQuestTool = true;
|
|
40
|
+
this.lastQuestToolTime = Date.now();
|
|
41
|
+
}
|
|
42
|
+
|
|
46
43
|
getNudge(
|
|
47
44
|
activeQuestCount: number,
|
|
48
|
-
allQuests: Quest[],
|
|
49
45
|
latestPrompt?: string,
|
|
50
46
|
hasTopLevelQuestWithoutSubs?: boolean,
|
|
51
47
|
): string | undefined {
|
|
@@ -67,7 +63,6 @@ export class QuestUsageTracker {
|
|
|
67
63
|
|
|
68
64
|
const eligible = this.getEligibleNudges(
|
|
69
65
|
activeQuestCount,
|
|
70
|
-
allQuests,
|
|
71
66
|
latestPrompt,
|
|
72
67
|
hasTopLevelQuestWithoutSubs,
|
|
73
68
|
);
|
|
@@ -101,7 +96,6 @@ export class QuestUsageTracker {
|
|
|
101
96
|
|
|
102
97
|
private getEligibleNudges(
|
|
103
98
|
activeQuestCount: number,
|
|
104
|
-
allQuests: Quest[],
|
|
105
99
|
latestPrompt?: string,
|
|
106
100
|
hasTopLevelQuestWithoutSubs?: boolean,
|
|
107
101
|
): NudgeCandidate[] {
|
|
@@ -111,7 +105,7 @@ export class QuestUsageTracker {
|
|
|
111
105
|
if (this.totalToolCalls >= this.config.nudges.toolCallThreshold && !this.hasEverUsedQuestTool) {
|
|
112
106
|
candidates.push({
|
|
113
107
|
index: 0,
|
|
114
|
-
message: `QUEST REMINDER: You have made
|
|
108
|
+
message: `QUEST REMINDER: You have made multiple tool calls but have NEVER used the quest tool this session. USE the quest tool to initialize tracking and break your work into concrete steps. ${ACKNOWLEDGEMENT}`,
|
|
115
109
|
});
|
|
116
110
|
}
|
|
117
111
|
|
|
@@ -119,7 +113,7 @@ export class QuestUsageTracker {
|
|
|
119
113
|
if (activeQuestCount === 0 && latestPrompt && this.isComplexPrompt(latestPrompt)) {
|
|
120
114
|
candidates.push({
|
|
121
115
|
index: 1,
|
|
122
|
-
message: `QUEST REMINDER: Your latest prompt
|
|
116
|
+
message: `QUEST REMINDER: Your latest prompt looks like a complex task, but there are 0 active quests. USE the quest tool to break it into concrete, trackable steps. ${ACKNOWLEDGEMENT}`,
|
|
123
117
|
});
|
|
124
118
|
}
|
|
125
119
|
|
|
@@ -130,10 +124,9 @@ export class QuestUsageTracker {
|
|
|
130
124
|
this.consecutiveNonQuestToolCalls >= this.config.nudges.timeBasedToolCallThreshold &&
|
|
131
125
|
Date.now() - this.lastQuestToolTime >= this.config.nudges.hintIntervalMinutes * 60 * 1000
|
|
132
126
|
) {
|
|
133
|
-
const questContext = formatActiveQuests(allQuests);
|
|
134
127
|
candidates.push({
|
|
135
128
|
index: 2,
|
|
136
|
-
message: `QUEST REMINDER: It has been a while since your last quest tool use and
|
|
129
|
+
message: `QUEST REMINDER: It has been a while since your last quest tool use and many tools have been called since then. ALIGN on quest status before continuing. ${ACKNOWLEDGEMENT}`,
|
|
137
130
|
});
|
|
138
131
|
}
|
|
139
132
|
|
|
@@ -144,7 +137,7 @@ export class QuestUsageTracker {
|
|
|
144
137
|
) {
|
|
145
138
|
candidates.push({
|
|
146
139
|
index: 3,
|
|
147
|
-
message: `QUEST REMINDER: You have made
|
|
140
|
+
message: `QUEST REMINDER: You have made several consecutive tool calls without using the quest tool and there are 0 active quests. TRACK your work with specific, actionable quests. ${ACKNOWLEDGEMENT}`,
|
|
148
141
|
});
|
|
149
142
|
}
|
|
150
143
|
|
|
@@ -157,7 +150,7 @@ export class QuestUsageTracker {
|
|
|
157
150
|
) {
|
|
158
151
|
candidates.push({
|
|
159
152
|
index: 4,
|
|
160
|
-
message: `QUEST REMINDER: You have made
|
|
153
|
+
message: `QUEST REMINDER: You have made several consecutive tool calls without using the quest tool and have active top-level quests without steps. Consider whether decomposing them with the \`split\` action would help track progress. ${ACKNOWLEDGEMENT}`,
|
|
161
154
|
});
|
|
162
155
|
}
|
|
163
156
|
|
|
@@ -168,10 +161,9 @@ export class QuestUsageTracker {
|
|
|
168
161
|
this.lastQuestToolTime > 0 &&
|
|
169
162
|
Date.now() - this.lastQuestToolTime >= this.config.nudges.hintIntervalMinutes * 60 * 1000
|
|
170
163
|
) {
|
|
171
|
-
const questContext = formatActiveQuests(allQuests);
|
|
172
164
|
candidates.push({
|
|
173
165
|
index: 5,
|
|
174
|
-
message: `QUEST REMINDER: You have made
|
|
166
|
+
message: `QUEST REMINDER: You have made many consecutive tool calls without using the quest tool despite having active quests. UPDATE your quest progress to reflect current status. ${ACKNOWLEDGEMENT}`,
|
|
175
167
|
});
|
|
176
168
|
}
|
|
177
169
|
|
package/src/renderers/status.ts
CHANGED
|
@@ -5,13 +5,18 @@ export class QuestStatusWidget {
|
|
|
5
5
|
private readonly key = "pi-quests";
|
|
6
6
|
private readonly barWidth = 5;
|
|
7
7
|
|
|
8
|
-
constructor(
|
|
8
|
+
constructor(
|
|
9
|
+
private readonly icon: string,
|
|
10
|
+
private readonly enabled: boolean = true,
|
|
11
|
+
) {}
|
|
9
12
|
|
|
10
13
|
update(
|
|
11
14
|
questLog: QuestLog,
|
|
12
15
|
ui: { setStatus(key: string, text: string | undefined): void },
|
|
13
16
|
theme: Theme,
|
|
14
17
|
): void {
|
|
18
|
+
if (!this.enabled) return;
|
|
19
|
+
|
|
15
20
|
const all = questLog.getAll();
|
|
16
21
|
const total = all.length;
|
|
17
22
|
const done = all.filter((q) => q.done).length;
|
package/src/tools/handler.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { AgentToolResult, ExtensionAPI } from "@mariozechner/pi-coding-agent";
|
|
2
|
-
import type
|
|
2
|
+
import { type Static, Type } from "@sinclair/typebox";
|
|
3
3
|
import type { ResolvedConfig } from "../config.js";
|
|
4
4
|
import { logger } from "../logger.js";
|
|
5
5
|
import { QUEST_PROMPT_GATE, QUEST_PROMPT_REMINDER } from "../prompts.js";
|
|
@@ -106,7 +106,7 @@ function runTool(
|
|
|
106
106
|
? questLog.getAll()
|
|
107
107
|
: result.quest
|
|
108
108
|
? [result.quest]
|
|
109
|
-
:
|
|
109
|
+
: [];
|
|
110
110
|
|
|
111
111
|
return makeToolResult(result.message, questLog, displayQuests);
|
|
112
112
|
}
|
|
@@ -132,10 +132,10 @@ export function registerQuestTool(
|
|
|
132
132
|
label: "Quest",
|
|
133
133
|
description:
|
|
134
134
|
"Manage the session quest log and retrieve the complete quest system documentation. " +
|
|
135
|
-
"Use this VERY frequently to track tasks, plans, and progress. " +
|
|
136
135
|
"When you need to understand quests, steps, rules, or best practices, use action: 'skill' or action: 'rules'.",
|
|
137
136
|
promptSnippet:
|
|
138
|
-
"Manage quests and steps, or retrieve quest rules and best practices via skill/rules"
|
|
137
|
+
"Manage quests and steps, or retrieve quest rules and best practices via skill/rules. " +
|
|
138
|
+
"Use this VERY frequently to track tasks, plans, and progress. ",
|
|
139
139
|
promptGuidelines: [QUEST_PROMPT_GATE, ...QUEST_PROMPT_REMINDER],
|
|
140
140
|
parameters: createQuestParams(config.ids.length),
|
|
141
141
|
execute: (toolCallId, params, _signal, _onUpdate, _ctx) =>
|
|
@@ -143,4 +143,24 @@ export function registerQuestTool(
|
|
|
143
143
|
renderCall: renderQuestCall,
|
|
144
144
|
renderResult: renderQuestResult(config),
|
|
145
145
|
});
|
|
146
|
+
|
|
147
|
+
pi.registerTool({
|
|
148
|
+
name: "learn_quests",
|
|
149
|
+
label: "Learn Quests",
|
|
150
|
+
description: "Learn about the quest system and how to use it effectively.",
|
|
151
|
+
promptSnippet: "Use this tool to learn about the quest system and how to use it effectively.",
|
|
152
|
+
promptGuidelines: [
|
|
153
|
+
"Use this tool when on a session to understand how and when to use quests.",
|
|
154
|
+
"ALWAYS run this tool when on a new session before starting any work.",
|
|
155
|
+
],
|
|
156
|
+
parameters: Type.Object(
|
|
157
|
+
{},
|
|
158
|
+
{ description: "No parameters required for learning about quests" },
|
|
159
|
+
),
|
|
160
|
+
execute: async (_toolCallId, _params, _signal, _onUpdate, _ctx) =>
|
|
161
|
+
questToolExecute(questLog, "learn_quests", { action: QUEST_ACTIONS.skill }),
|
|
162
|
+
renderCall: (_args, theme, context) =>
|
|
163
|
+
renderQuestCall({ action: QUEST_ACTIONS.skill }, theme, context),
|
|
164
|
+
renderResult: renderQuestResult(config),
|
|
165
|
+
});
|
|
146
166
|
}
|