pi-code 1.0.38 → 1.0.39
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 * as fs from 'node:fs'
|
|
|
16
16
|
import * as path from 'node:path'
|
|
17
17
|
|
|
18
18
|
import { claudeConfigDir } from './config-dir.js'
|
|
19
|
+
import { readManagedSettings } from './managed-settings.js'
|
|
19
20
|
|
|
20
21
|
export interface InstalledPlugin {
|
|
21
22
|
name: string
|
|
@@ -169,16 +170,30 @@ export function installedPlugins(home: string, extraSettingsFiles: string[] = []
|
|
|
169
170
|
return plugins
|
|
170
171
|
}
|
|
171
172
|
|
|
173
|
+
/** The plugin's effective enablement per Claude's precedence: a managed
|
|
174
|
+
* enabledPlugins entry force-enables or blocks, then the user's setting, then the
|
|
175
|
+
* manifest's defaultEnabled, which defaults to true ("starts in an enabled state
|
|
176
|
+
* when the user has not set one"). */
|
|
177
|
+
function pluginEnabled(qualified: string, pluginDir: string, enabled: Record<string, boolean>, manifest: Record<string, unknown>): boolean {
|
|
178
|
+
const managedEntry = readManagedSettings().enabledPlugins
|
|
179
|
+
if (managedEntry !== null && typeof managedEntry === 'object') {
|
|
180
|
+
const managedState = (managedEntry as Record<string, unknown>)[qualified] ?? (managedEntry as Record<string, unknown>)[pluginDir]
|
|
181
|
+
if (typeof managedState === 'boolean') return managedState
|
|
182
|
+
}
|
|
183
|
+
const userState = enabled[qualified] ?? enabled[pluginDir]
|
|
184
|
+
if (typeof userState === 'boolean') return userState
|
|
185
|
+
return manifest.defaultEnabled !== false
|
|
186
|
+
}
|
|
187
|
+
|
|
172
188
|
/** Resolve one cached plugin directory into an enabled InstalledPlugin, or null to skip
|
|
173
|
-
* it:
|
|
189
|
+
* it: turned off by managed/user settings or defaultEnabled, or no version yet. */
|
|
174
190
|
function resolvePlugin(home: string, cacheDir: string, marketplace: string, pluginDir: string, enabled: Record<string, boolean>, configs: Record<string, Record<string, string>>): InstalledPlugin | null {
|
|
175
191
|
const qualified = `${pluginDir}@${marketplace}`
|
|
176
|
-
const state = enabled[qualified] ?? enabled[pluginDir]
|
|
177
|
-
if (state !== true) return null
|
|
178
192
|
const version = newestVersion(listDirs(path.join(cacheDir, marketplace, pluginDir)))
|
|
179
193
|
if (!version) return null
|
|
180
194
|
const root = path.join(cacheDir, marketplace, pluginDir, version)
|
|
181
195
|
const manifest = readJson(path.join(root, '.claude-plugin', 'plugin.json'))
|
|
196
|
+
if (!pluginEnabled(qualified, pluginDir, enabled, manifest)) return null
|
|
182
197
|
const name = typeof manifest.name === 'string' && manifest.name.length > 0 ? manifest.name : pluginDir
|
|
183
198
|
// Claude: "{id} is the plugin identifier with characters outside a-z, A-Z, 0-9,
|
|
184
199
|
// _, and - replaced by -", one dash per character, underscores kept.
|
package/extensions/mcp/index.ts
CHANGED
|
@@ -595,6 +595,34 @@ export default async function mcpExtension(pi: ExtensionAPI) {
|
|
|
595
595
|
status.clear()
|
|
596
596
|
})
|
|
597
597
|
|
|
598
|
+
// Claude references MCP resources with @server:uri mentions, fetched into the
|
|
599
|
+
// conversation when referenced. Only mentions naming a connected server expand;
|
|
600
|
+
// anything else (an email, a handle) stays untouched.
|
|
601
|
+
pi.on('input', async (event) => {
|
|
602
|
+
if (event.source === 'extension') return
|
|
603
|
+
const mentions = [...event.text.matchAll(/@([A-Za-z0-9_-]+):(\S+)/g)].filter((match) => clients.has(match[1]))
|
|
604
|
+
if (mentions.length === 0) return
|
|
605
|
+
const sections: string[] = []
|
|
606
|
+
for (const match of mentions) {
|
|
607
|
+
const [, server, uri] = match
|
|
608
|
+
try {
|
|
609
|
+
const client = clients.get(server)
|
|
610
|
+
if (!client) continue
|
|
611
|
+
const wall = callTimeoutMs()
|
|
612
|
+
const result = await withTimeout(client.readResource({ uri }, callRequestOptions(wall, callTuning(server))), wall, `read ${uri}`)
|
|
613
|
+
const text = (result.contents as Array<{ text?: string }>)
|
|
614
|
+
.map((entry) => entry.text)
|
|
615
|
+
.filter((value): value is string => typeof value === 'string')
|
|
616
|
+
.join('\n')
|
|
617
|
+
if (text) sections.push(capForContext(`<mcp-resource server="${server}" uri="${uri}">\n${text}\n</mcp-resource>`))
|
|
618
|
+
} catch {
|
|
619
|
+
// An unreadable resource leaves the mention as plain text.
|
|
620
|
+
}
|
|
621
|
+
}
|
|
622
|
+
if (sections.length === 0) return
|
|
623
|
+
return { action: 'transform', text: `${event.text}\n\n${sections.join('\n\n')}` }
|
|
624
|
+
})
|
|
625
|
+
|
|
598
626
|
pi.registerCommand('mcp', {
|
|
599
627
|
description: 'Show MCP server status and tools',
|
|
600
628
|
handler: async (_args, ctx) => {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "pi-code",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.39",
|
|
4
4
|
"description": "Claude Code experience for the pi coding agent: reads your .claude config (rules, commands, skills, hooks, output styles, MCP servers, agents) and adds todo, checkpoints, memory, web, and subagents",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"pi",
|