polygram 0.8.0-rc.48 → 0.8.0-rc.49

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
  "$schema": "https://anthropic.com/claude-code/plugin.schema.json",
3
3
  "name": "polygram",
4
- "version": "0.8.0-rc.48",
4
+ "version": "0.8.0-rc.49",
5
5
  "description": "Telegram integration for Claude Code that preserves the OpenClaw per-chat session model. Migration target for OpenClaw users. Multi-bot, multi-chat, per-topic isolation; SQLite transcripts; inline-keyboard approvals. Bundles /polygram:status|logs|pair-code|approvals admin commands and a history skill.",
6
6
  "keywords": [
7
7
  "telegram",
@@ -56,10 +56,69 @@ const cache = new Map(); // cacheKey → AgentBundle
56
56
  // consecutive dots, slashes, NUL.
57
57
  const AGENT_NAME_RE = /^[A-Za-z0-9_]+(?:[.-][A-Za-z0-9_]+)*$/;
58
58
 
59
+ // rc.49: parse `<plugin>:<agent>` qualified names. Each side must
60
+ // independently satisfy AGENT_NAME_RE. Returns { plugin, agent } or
61
+ // null if not qualified or malformed.
62
+ function parseQualifiedName(name) {
63
+ if (typeof name !== 'string' || !name.includes(':')) return null;
64
+ const parts = name.split(':');
65
+ if (parts.length !== 2) return null;
66
+ const [plugin, agent] = parts;
67
+ if (!AGENT_NAME_RE.test(plugin) || !AGENT_NAME_RE.test(agent)) return null;
68
+ return { plugin, agent };
69
+ }
70
+
71
+ // rc.49: look up a plugin's installPath in
72
+ // ~/.claude/plugins/installed_plugins.json. Keys are
73
+ // `<name>@<marketplace>` — match by the bare `<name>` prefix and
74
+ // return the first installed entry's `installPath`. Returns null if
75
+ // not enrolled or registry unreadable.
76
+ function lookupInstalledPlugin(pluginName, homeDir) {
77
+ const registryPath = path.join(homeDir, '.claude', 'plugins', 'installed_plugins.json');
78
+ if (!fs.existsSync(registryPath)) return null;
79
+ let registry;
80
+ try {
81
+ registry = JSON.parse(fs.readFileSync(registryPath, 'utf8'));
82
+ } catch {
83
+ return null;
84
+ }
85
+ const plugins = registry?.plugins || {};
86
+ const prefix = pluginName + '@';
87
+ for (const key of Object.keys(plugins)) {
88
+ if (key.startsWith(prefix)) {
89
+ const entries = plugins[key];
90
+ if (Array.isArray(entries) && entries[0]?.installPath) {
91
+ return entries[0].installPath;
92
+ }
93
+ }
94
+ }
95
+ return null;
96
+ }
97
+
59
98
  function resolveAgentLocation(agentName, homeDir, cwd) {
60
- if (typeof agentName !== 'string' || !AGENT_NAME_RE.test(agentName)) {
99
+ if (typeof agentName !== 'string') return null;
100
+
101
+ // rc.49: plugin-qualified `<plugin>:<agent>` names look up the plugin
102
+ // from the installed registry (with fallback to ~/.claude-plugins-local/).
103
+ // Resolution is intentionally NARROW — only the qualified form
104
+ // searches plugin directories. Plain unqualified names keep the
105
+ // pre-rc.49 ~/.claude/agents/ + <cwd>/.claude/agents/ behaviour.
106
+ const qualified = parseQualifiedName(agentName);
107
+ if (qualified) {
108
+ const { plugin, agent } = qualified;
109
+ const installPath = lookupInstalledPlugin(plugin, homeDir);
110
+ if (installPath) {
111
+ const p = path.join(installPath, 'agents', agent + '.md');
112
+ if (fs.existsSync(p)) return { kind: 'file', path: p, dir: null };
113
+ }
114
+ // Fallback: ~/.claude-plugins-local/<plugin>/agents/<agent>.md
115
+ const localPath = path.join(homeDir, '.claude-plugins-local', plugin, 'agents', agent + '.md');
116
+ if (fs.existsSync(localPath)) return { kind: 'file', path: localPath, dir: null };
61
117
  return null;
62
118
  }
119
+
120
+ if (!AGENT_NAME_RE.test(agentName)) return null;
121
+
63
122
  const fileCandidates = [];
64
123
  if (cwd) fileCandidates.push(path.join(cwd, '.claude', 'agents', agentName + '.md'));
65
124
  fileCandidates.push(path.join(homeDir, '.claude', 'agents', agentName + '.md'));
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "polygram",
3
- "version": "0.8.0-rc.48",
3
+ "version": "0.8.0-rc.49",
4
4
  "description": "Telegram daemon for Claude Code that preserves the OpenClaw per-chat session model. Migration path for OpenClaw users moving to Claude Code.",
5
5
  "main": "lib/ipc-client.js",
6
6
  "bin": {