@evref-bl/pharo-agent 0.5.3 → 0.5.4

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.
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "pharo-agent",
3
3
  "displayName": "Pharo Agent",
4
- "version": "0.5.3",
4
+ "version": "0.5.4",
5
5
  "description": "Terminal-first Pharo image setup for coding agents.",
6
6
  "author": {
7
7
  "name": "Evref-BL",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@evref-bl/pharo-agent",
3
- "version": "0.5.3",
3
+ "version": "0.5.4",
4
4
  "private": false,
5
5
  "description": "Terminal-first Pharo integration for coding agents.",
6
6
  "license": "Apache-2.0",
package/plugin.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "$schema": "https://agent-plugins.org/schemas/1.0.0/plugin.schema.json",
3
3
  "name": "pharo-agent",
4
- "version": "0.5.3",
4
+ "version": "0.5.4",
5
5
  "description": "Terminal-first Pharo image setup for coding agents.",
6
6
  "author": {
7
7
  "name": "Evref-BL",
@@ -8,7 +8,7 @@ Run this only when the user asks to enable Pharo tooling in this project.
8
8
  From the project root, run the released CLI that matches this plugin:
9
9
 
10
10
  ```sh
11
- npx --yes @evref-bl/pharo-agent@0.5.3 init --host claude
11
+ npx --yes @evref-bl/pharo-agent@0.5.4 init --host claude
12
12
  ```
13
13
 
14
14
  Name the host this chat runs in: `--host claude` in Claude Code,
package/src/gateway.js CHANGED
@@ -6,7 +6,12 @@ import {
6
6
  CallToolRequestSchema,
7
7
  ListToolsRequestSchema,
8
8
  } from "@modelcontextprotocol/sdk/types.js";
9
- import { readJson, readOpenImage, selectRunningImage } from "./runtime.js";
9
+ import {
10
+ readJson,
11
+ readOpenImage,
12
+ selectRunningImage,
13
+ unappliedPharoMcpPin,
14
+ } from "./runtime.js";
10
15
 
11
16
  // Read rather than restate: a hard-coded version is one more place for a
12
17
  // release to forget, and the host shows this one to the user.
@@ -34,20 +39,33 @@ export async function imageGateway(projectRoot, open) {
34
39
  if (!registered.ok) {
35
40
  throw new Error(registered.error ?? "Cannot register the PLexus route.");
36
41
  }
37
- return { gateway, mcpServerId };
42
+ return { gateway, mcpServerId, image };
43
+ }
44
+
45
+ // An image whose Pharo MCP predates 2.1.0 resolves tools/call against the
46
+ // advertised list, so a tool it holds but does not advertise answers -32601.
47
+ // That is the loudest way an unapplied pin shows itself, and the message
48
+ // alone sends a reader looking for a tool that is right there.
49
+ const methodNotFound = "-32601";
50
+
51
+ export function toolFailureMessage(error, image) {
52
+ const unappliedPin = error.includes(methodNotFound) ? unappliedPharoMcpPin(image) : undefined;
53
+ return unappliedPin ? `${error}\n${unappliedPin}` : error;
38
54
  }
39
55
 
40
56
  export async function callImageTool(projectRoot, open, toolName, argumentsValue) {
41
- const { gateway, mcpServerId } = await imageGateway(projectRoot, open);
57
+ const { gateway, mcpServerId, image } = await imageGateway(projectRoot, open);
42
58
  const result = await gateway.routeToImage({
43
59
  mcpServerId,
44
60
  toolName,
45
61
  arguments: argumentsValue,
46
62
  });
47
- if (!result.ok) {
48
- throw new Error(result.error ?? `Pharo tool ${toolName} failed.`);
63
+ if (result.ok) {
64
+ return result.data;
49
65
  }
50
- return result.data;
66
+ throw new Error(
67
+ toolFailureMessage(result.error ?? `Pharo tool ${toolName} failed.`, image),
68
+ );
51
69
  }
52
70
 
53
71
  export async function listImageTools(projectRoot, open) {
package/src/live.js CHANGED
@@ -18,6 +18,7 @@ import {
18
18
  resolveMountPath,
19
19
  selectRunningImage,
20
20
  smalltalkString,
21
+ unappliedPharoMcpPin,
21
22
  writeOpenImages,
22
23
  } from "./runtime.js";
23
24
 
@@ -238,7 +239,14 @@ export async function openAgentImage(projectRoot, imageId) {
238
239
  throw error;
239
240
  }
240
241
  writeOpenImages(projectRoot, { ...openImages, [resolved]: { ...open, projectionPort } });
241
- return { imageId: image.id, created, mountPath, projectionPort };
242
+ const unappliedPin = unappliedPharoMcpPin(image);
243
+ return {
244
+ imageId: image.id,
245
+ created,
246
+ mountPath,
247
+ projectionPort,
248
+ ...(unappliedPin ? { warning: unappliedPin } : {}),
249
+ };
242
250
  }
243
251
 
244
252
  function unsupportedRunningImage(state, imageId) {
package/src/runtime.js CHANGED
@@ -131,6 +131,18 @@ export function selectRunningImage(state, imageId) {
131
131
  return { image, mcpServerId: image.mcpServers[0].id };
132
132
  }
133
133
 
134
+ // `mcp.loadPolicy` defaults to ifMissing, so an image that already carries a
135
+ // Pharo MCP keeps it and the version this project pins is never loaded. That
136
+ // is a supported way to run — it is what the policy is for — but nothing said
137
+ // so, and the image's tools then quietly differ from the ones the project was
138
+ // written against. PLexus records it; this says it.
139
+ export function unappliedPharoMcpPin(image) {
140
+ if (image?.pharoMcpLoad?.state !== "provided") return undefined;
141
+ return `Image ${image.id} opened with the Pharo MCP it already had, so the version this project pins`
142
+ + " was not loaded and its tools may differ from the ones this project expects."
143
+ + " Recreate the image, or set mcp.loadPolicy to always.";
144
+ }
145
+
134
146
  export function smalltalkString(value) {
135
147
  return `'${String(value).replaceAll("'", "''")}'`;
136
148
  }