mono-pilot 0.2.5 → 0.2.6
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.
|
@@ -16,6 +16,7 @@ import switchModeExtension from "../../tools/switch-mode.js";
|
|
|
16
16
|
import applyPatchExtension from "../../tools/apply-patch.js";
|
|
17
17
|
import userMessageExtension from "./user-message.js";
|
|
18
18
|
import systemPromptExtension from "./system-prompt.js";
|
|
19
|
+
import sessionHintsExtension from "./session-hints.js";
|
|
19
20
|
const toolExtensions = [
|
|
20
21
|
shellExtension,
|
|
21
22
|
globExtension,
|
|
@@ -35,6 +36,7 @@ const toolExtensions = [
|
|
|
35
36
|
applyPatchExtension,
|
|
36
37
|
userMessageExtension,
|
|
37
38
|
systemPromptExtension,
|
|
39
|
+
sessionHintsExtension,
|
|
38
40
|
];
|
|
39
41
|
export default function monoPilotExtension(pi) {
|
|
40
42
|
for (const register of toolExtensions) {
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
import { existsSync } from "node:fs";
|
|
2
|
+
import { readdir } from "node:fs/promises";
|
|
3
|
+
import { homedir } from "node:os";
|
|
4
|
+
import { join, resolve } from "node:path";
|
|
5
|
+
import { Text } from "@mariozechner/pi-tui";
|
|
6
|
+
import { hasMessageEntries } from "./mode-runtime.js";
|
|
7
|
+
const SESSION_HINTS_MESSAGE_TYPE = "SessionHints";
|
|
8
|
+
const RULES_RELATIVE_DIR = join(".pi", "rules");
|
|
9
|
+
/** List *.rule.txt full paths from a directory (empty array if dir missing). */
|
|
10
|
+
async function listRuleFiles(dirPath) {
|
|
11
|
+
if (!existsSync(dirPath))
|
|
12
|
+
return [];
|
|
13
|
+
try {
|
|
14
|
+
const entries = await readdir(dirPath, { withFileTypes: true, encoding: "utf8" });
|
|
15
|
+
return entries
|
|
16
|
+
.filter((e) => e.isFile() && e.name.endsWith(".rule.txt"))
|
|
17
|
+
.map((e) => resolve(dirPath, e.name))
|
|
18
|
+
.sort((a, b) => a.localeCompare(b));
|
|
19
|
+
}
|
|
20
|
+
catch {
|
|
21
|
+
return [];
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
/** Discover rules files grouped by scope. */
|
|
25
|
+
async function discoverRules(cwd) {
|
|
26
|
+
const workspaceRulesDir = resolve(cwd, RULES_RELATIVE_DIR);
|
|
27
|
+
const userRulesDir = resolve(homedir(), RULES_RELATIVE_DIR);
|
|
28
|
+
const [workspaceRules, userRules] = await Promise.all([
|
|
29
|
+
listRuleFiles(workspaceRulesDir),
|
|
30
|
+
listRuleFiles(userRulesDir),
|
|
31
|
+
]);
|
|
32
|
+
return { userRules, projectRules: workspaceRules };
|
|
33
|
+
}
|
|
34
|
+
function shortenHome(filePath) {
|
|
35
|
+
const home = homedir();
|
|
36
|
+
if (filePath.startsWith(home)) {
|
|
37
|
+
return `~${filePath.slice(home.length)}`;
|
|
38
|
+
}
|
|
39
|
+
return filePath;
|
|
40
|
+
}
|
|
41
|
+
export default function sessionHintsExtension(pi) {
|
|
42
|
+
// Render hints matching pi's native section style (same colors as [Context], [Skills], etc.)
|
|
43
|
+
pi.registerMessageRenderer(SESSION_HINTS_MESSAGE_TYPE, (message, _options, theme) => {
|
|
44
|
+
const details = message.details;
|
|
45
|
+
const lines = [];
|
|
46
|
+
const userRules = details?.userRules ?? [];
|
|
47
|
+
const projectRules = details?.projectRules ?? [];
|
|
48
|
+
if (userRules.length > 0 || projectRules.length > 0) {
|
|
49
|
+
lines.push(theme.fg("mdHeading", "[Rules]"));
|
|
50
|
+
if (userRules.length > 0) {
|
|
51
|
+
lines.push(` ${theme.fg("accent", "user")}`);
|
|
52
|
+
for (const filePath of userRules) {
|
|
53
|
+
lines.push(theme.fg("dim", ` ${shortenHome(filePath)}`));
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
if (projectRules.length > 0) {
|
|
57
|
+
lines.push(` ${theme.fg("accent", "project")}`);
|
|
58
|
+
for (const filePath of projectRules) {
|
|
59
|
+
lines.push(theme.fg("dim", ` ${shortenHome(filePath)}`));
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
if (lines.length > 0)
|
|
64
|
+
lines.push("");
|
|
65
|
+
lines.push(theme.fg("muted", "Mode switch: use ") + theme.fg("dim", "option+m") + theme.fg("muted", " to toggle Plan/Ask/Agent mode."));
|
|
66
|
+
return new Text(lines.join("\n"), 0, 0);
|
|
67
|
+
});
|
|
68
|
+
pi.on("session_start", async (_event, ctx) => {
|
|
69
|
+
if (!ctx.hasUI)
|
|
70
|
+
return;
|
|
71
|
+
const entries = ctx.sessionManager.getEntries();
|
|
72
|
+
if (hasMessageEntries(entries))
|
|
73
|
+
return;
|
|
74
|
+
const details = await discoverRules(ctx.cwd);
|
|
75
|
+
pi.sendMessage({
|
|
76
|
+
customType: SESSION_HINTS_MESSAGE_TYPE,
|
|
77
|
+
content: "",
|
|
78
|
+
display: true,
|
|
79
|
+
details,
|
|
80
|
+
}, { triggerTurn: false });
|
|
81
|
+
});
|
|
82
|
+
}
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import { truncateToWidth, visibleWidth } from "@mariozechner/pi-tui";
|
|
2
2
|
import { Type } from "@sinclair/typebox";
|
|
3
|
-
import { createModeStateData, deriveInitialModeState,
|
|
4
|
-
const MODE_HINT_MESSAGE_TYPE = "Hints";
|
|
3
|
+
import { createModeStateData, deriveInitialModeState, modeRuntimeStore, MODE_STATE_ENTRY_TYPE, parseModeStateEntry, } from "../src/extensions/mode-runtime.js";
|
|
5
4
|
const MODE_STATUS_KEY = "mono-pilot-mode";
|
|
6
5
|
const DESCRIPTION = `Switch the interaction mode to better match the current task. Each mode is optimized for a specific type of work.
|
|
7
6
|
|
|
@@ -311,13 +310,6 @@ export default function switchModeExtension(pi) {
|
|
|
311
310
|
}
|
|
312
311
|
installModeFooter(ctx);
|
|
313
312
|
updateModeStatus(ctx);
|
|
314
|
-
if (ctx.hasUI && !hasMessageEntries(entries)) {
|
|
315
|
-
pi.sendMessage({
|
|
316
|
-
customType: MODE_HINT_MESSAGE_TYPE,
|
|
317
|
-
content: "Mode switch: use `option+m` to toggle Plan/Ask/Agent mode.",
|
|
318
|
-
display: true,
|
|
319
|
-
}, { triggerTurn: false });
|
|
320
|
-
}
|
|
321
313
|
});
|
|
322
314
|
// System prompt injection is handled centrally by system-prompt extension.
|
|
323
315
|
pi.registerTool({
|