Skip to content

Commit ab86d8e

Browse files
fix(pi): show actionable status for ambiguous project errors (#439)
Replace the generic '· error' status bar label with '· ambiguous project' when the underlying failure is an ambiguous project detection (multiple git repos in cwd). Adds `errorStatusLabel()` to map known error patterns to actionable labels so users can distinguish backend errors from project resolution problems. Closes #384
1 parent 4337354 commit ab86d8e

3 files changed

Lines changed: 26 additions & 1 deletion

File tree

plugin/pi/README.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,13 @@ Pi-native compact tools use the same HTTP server path as event capture, includin
112112

113113
Normal memory activity also updates the status bar with short progress/result text such as `🧠 engram · search…` and `🧠 engram · ✓ 4 results`. The extension does not use notifications for normal memory operations.
114114

115+
When a tool call fails because Engram cannot determine which project to use, the status bar shows an actionable label instead of the generic `error`:
116+
117+
| Status bar label | Meaning |
118+
| -------------------------- | ----------------------------------------------------------------------------------------------------- |
119+
| `🧠 repos · ambiguous project` | Pi was started from a directory that contains multiple git repos. Run Pi from inside a single repo, or add `.engram/config.json` with `project_name` to the parent directory. |
120+
| `🧠 repos · error` | A different tool or network error occurred. Expand the tool output in Pi for the full error message. |
121+
115122
Full tool details remain available by expanding the tool output in Pi. If `gentle-engram` or the Engram server is not installed/running, the compact tool reports an error instead of implying memory is available.
116123

117124
## What Pi can remember
@@ -231,6 +238,7 @@ MCP tool calls still use Engram core's canonical project resolver at call time.
231238
| Existing MCP config was not replaced | Run `pi-engram init --force`. |
232239
| `mem_current_project` reports `/project/current` unsupported | Restart or upgrade the running `engram serve`; check `ENGRAM_URL`/`ENGRAM_BIN`. If `.engram/config.json` exists, Pi uses it as a temporary fallback. |
233240
| `mem_session_summary` cannot detect a project | Ask the user which project should receive the summary, then retry `mem_session_summary` with `project: "name"`. |
241+
| Status bar shows `🧠 repos · ambiguous project` | Pi was started from a parent directory that contains multiple git repos. Run Pi from inside a single repo, or add `.engram/config.json` with `"project_name": "my-project"` to the ambiguous directory. |
234242

235243
## Next steps
236244

plugin/pi/index.ts

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -261,6 +261,11 @@ function truncate(str: string, max: number): string {
261261
return str.length > max ? `${str.slice(0, max)}...` : str;
262262
}
263263

264+
function errorStatusLabel(message: string): string {
265+
if (/ambiguous project/i.test(message)) return "ambiguous project";
266+
return "error";
267+
}
268+
264269
function stripPrivateTags(str: string): string {
265270
return redactPrivateTags(str).trim();
266271
}
@@ -686,7 +691,7 @@ async function executeMemoryTool(toolName: string, params: Record<string, unknow
686691
const details = error instanceof EngramHttpError
687692
? { error: message, http_status: error.status, data: error.data }
688693
: { error: message };
689-
ctx.ui?.setStatus?.("engram", `🧠 ${project} · error`);
694+
ctx.ui?.setStatus?.("engram", `🧠 ${project} · ${errorStatusLabel(message)}`);
690695
return { content: [{ type: "text" as const, text: message }], details, isError: true };
691696
}
692697
}

plugin/pi/test/index-source.test.mjs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,3 +15,15 @@ test("project detection 404 falls back to local config or diagnostic", () => {
1515
assert.match(source, /error\.status === 404[\s\S]*detectLocalConfigProject\(cwd\) \|\| projectCurrentUnsupportedError\(cwd\)/);
1616
assert.match(source, /does not support \/project\/current/);
1717
});
18+
19+
test("ambiguous_project error maps to actionable status label, not generic 'error'", () => {
20+
// The status bar must NOT show the generic 'error' label for ambiguous project conditions.
21+
// Instead it should show an actionable label such as 'ambiguous project'.
22+
assert.match(source, /function errorStatusLabel\(/);
23+
// Verify the function maps ambiguous project messages to the actionable label
24+
assert.match(source, /ambiguous project/);
25+
// Verify executeMemoryTool uses errorStatusLabel instead of the bare 'error' string
26+
assert.match(source, /errorStatusLabel\(message\)/);
27+
// The bare '· error' hardcoded string should no longer be present in the catch block
28+
assert.doesNotMatch(source, /setStatus\?\.\("engram",\s*`🧠 \$\{project\} · error`\)/);
29+
});

0 commit comments

Comments
 (0)