mono-pilot 0.2.3 → 0.2.5

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.
@@ -2,6 +2,7 @@ import { existsSync, readFileSync } from "node:fs";
2
2
  import { dirname, join, resolve } from "node:path";
3
3
  import process from "node:process";
4
4
  import { fileURLToPath } from "node:url";
5
+ import { formatSkillsForPrompt, loadSkills } from "@mariozechner/pi-coding-agent";
5
6
  const NO_DESCRIPTION_PLACEHOLDER = "No short description provided.";
6
7
  const PROJECT_CONTEXT_HEADER = "# Project Context";
7
8
  const CURRENT_DATETIME_PREFIX = "Current date and time:";
@@ -13,6 +14,7 @@ const CURRENT_WORKING_DIRECTORY_TOKEN = "{{CURRENT_WORKING_DIRECTORY}}";
13
14
  const PI_README_PATH_TOKEN = "{{PI_README_PATH}}";
14
15
  const PI_DOCS_PATH_TOKEN = "{{PI_DOCS_PATH}}";
15
16
  const PI_EXAMPLES_PATH_TOKEN = "{{PI_EXAMPLES_PATH}}";
17
+ const SKILLS_BLOCK_TOKEN = "{{SKILLS_BLOCK}}";
16
18
  const UNIFIED_SYSTEM_PROMPT_TEMPLATE = `You are an expert coding assistant operating inside MonoPilot (a pi-coding-agent compatibility harness) on a user's computer.
17
19
  You help users by reading files, executing commands, editing code, and writing new files.
18
20
 
@@ -166,7 +168,8 @@ Your main goal is to follow the USER's instructions at each message, denoted by
166
168
  <runtime_context>
167
169
  Current date and time: ${CURRENT_DATETIME_TOKEN}
168
170
  Current working directory: ${CURRENT_WORKING_DIRECTORY_TOKEN}
169
- </runtime_context>`;
171
+ </runtime_context>
172
+ ${SKILLS_BLOCK_TOKEN}`;
170
173
  function getFirstDescriptionLine(description) {
171
174
  if (!description)
172
175
  return NO_DESCRIPTION_PLACEHOLDER;
@@ -228,7 +231,9 @@ function renderTemplate(template, values) {
228
231
  .split(PI_DOCS_PATH_TOKEN)
229
232
  .join(values.piDocsPath)
230
233
  .split(PI_EXAMPLES_PATH_TOKEN)
231
- .join(values.piExamplesPath);
234
+ .join(values.piExamplesPath)
235
+ .split(SKILLS_BLOCK_TOKEN)
236
+ .join(values.skillsBlock);
232
237
  }
233
238
  function getFallbackDateTimeText() {
234
239
  return new Date().toString();
@@ -284,6 +289,10 @@ export default function systemPromptExtension(pi) {
284
289
  const projectContext = extractProjectContextBlock(event.systemPrompt) ?? "Project-specific instructions were not provided.";
285
290
  const currentDateTime = extractValueAfterPrefix(event.systemPrompt, CURRENT_DATETIME_PREFIX) ?? getFallbackDateTimeText();
286
291
  const cwd = extractValueAfterPrefix(event.systemPrompt, CURRENT_WORKING_DIRECTORY_PREFIX) ?? process.cwd();
292
+ // Load skills directly since pi-mono skips injection when "read" tool
293
+ // is not in the base tool set (mono-pilot uses "ReadFile" instead).
294
+ const { skills } = loadSkills({ cwd });
295
+ const skillsBlock = formatSkillsForPrompt(skills);
287
296
  const unifiedPrompt = renderTemplate(UNIFIED_SYSTEM_PROMPT_TEMPLATE, {
288
297
  tools,
289
298
  projectContext,
@@ -292,6 +301,7 @@ export default function systemPromptExtension(pi) {
292
301
  piReadmePath: piDocsPaths.readmePath,
293
302
  piDocsPath: piDocsPaths.docsPath,
294
303
  piExamplesPath: piDocsPaths.examplesPath,
304
+ skillsBlock,
295
305
  });
296
306
  if (unifiedPrompt === event.systemPrompt) {
297
307
  return undefined;
@@ -1,5 +1,6 @@
1
1
  import { existsSync } from "node:fs";
2
2
  import { readdir, readFile } from "node:fs/promises";
3
+ import { homedir } from "node:os";
3
4
  import { dirname, join, resolve } from "node:path";
4
5
  import process from "node:process";
5
6
  import { fileURLToPath, pathToFileURL } from "node:url";
@@ -138,37 +139,48 @@ async function buildMcpInstructionsEnvelope(workspaceCwd) {
138
139
  }
139
140
  async function buildRulesEnvelope(workspaceCwd) {
140
141
  const rulesDirPath = resolve(workspaceCwd, RULES_RELATIVE_DIR);
141
- if (!existsSync(rulesDirPath))
142
- return undefined;
143
- let directoryEntries;
144
- try {
145
- directoryEntries = await readdir(rulesDirPath, { withFileTypes: true, encoding: "utf8" });
146
- }
147
- catch {
148
- return undefined;
149
- }
150
- const ruleFileNames = directoryEntries
151
- .filter((entry) => entry.isFile() && entry.name.endsWith(".rule.txt"))
152
- .map((entry) => entry.name)
153
- .sort((a, b) => a.localeCompare(b));
154
- if (ruleFileNames.length === 0)
155
- return undefined;
156
- const rules = [];
157
- for (const ruleFileName of ruleFileNames) {
158
- const ruleFilePath = resolve(rulesDirPath, ruleFileName);
142
+ const userRulesDirPath = resolve(homedir(), RULES_RELATIVE_DIR);
143
+ const loadRulesFromDir = async (dirPath) => {
144
+ if (!existsSync(dirPath))
145
+ return new Map();
146
+ let directoryEntries;
159
147
  try {
160
- const content = await readFile(ruleFilePath, "utf-8");
161
- const normalized = content.trim();
162
- if (normalized.length > 0) {
163
- rules.push(normalized);
164
- }
148
+ directoryEntries = await readdir(dirPath, { withFileTypes: true, encoding: "utf8" });
165
149
  }
166
150
  catch {
167
- // Ignore unreadable rule files.
151
+ return new Map();
152
+ }
153
+ const ruleFileNames = directoryEntries
154
+ .filter((entry) => entry.isFile() && entry.name.endsWith(".rule.txt"))
155
+ .map((entry) => entry.name)
156
+ .sort((a, b) => a.localeCompare(b));
157
+ const rules = new Map();
158
+ for (const ruleFileName of ruleFileNames) {
159
+ const ruleFilePath = resolve(dirPath, ruleFileName);
160
+ try {
161
+ const content = await readFile(ruleFilePath, "utf-8");
162
+ const normalized = content.trim();
163
+ if (normalized.length > 0) {
164
+ rules.set(ruleFileName, normalized);
165
+ }
166
+ }
167
+ catch {
168
+ // Ignore unreadable rule files.
169
+ }
168
170
  }
171
+ return rules;
172
+ };
173
+ const userRules = await loadRulesFromDir(userRulesDirPath);
174
+ const workspaceRules = await loadRulesFromDir(rulesDirPath);
175
+ const mergedRules = new Map(userRules);
176
+ for (const [fileName, content] of workspaceRules) {
177
+ mergedRules.set(fileName, content);
169
178
  }
170
- if (rules.length === 0)
179
+ if (mergedRules.size === 0)
171
180
  return undefined;
181
+ const rules = Array.from(mergedRules.entries())
182
+ .sort(([a], [b]) => a.localeCompare(b))
183
+ .map(([, content]) => content);
172
184
  const lines = ["<rules>"];
173
185
  for (const rule of rules) {
174
186
  lines.push("<user_rule>");
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "mono-pilot",
3
- "version": "0.2.3",
3
+ "version": "0.2.5",
4
4
  "description": "Cursor-compatible coding agent powered by pi-mono",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -44,10 +44,10 @@
44
44
  "node": ">=20"
45
45
  },
46
46
  "dependencies": {
47
- "@mariozechner/pi-agent-core": "^0.55.0",
48
- "@mariozechner/pi-ai": "^0.55.0",
49
- "@mariozechner/pi-coding-agent": "^0.55.0",
50
- "@mariozechner/pi-tui": "^0.55.0",
47
+ "@mariozechner/pi-agent-core": "^0.55.1",
48
+ "@mariozechner/pi-ai": "^0.55.1",
49
+ "@mariozechner/pi-coding-agent": "^0.55.1",
50
+ "@mariozechner/pi-tui": "^0.55.1",
51
51
  "@sinclair/typebox": "^0.34.13",
52
52
  "glob": "^13.0.1"
53
53
  },