@agentplugins/adapter-pimono 0.1.0
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.
- package/README.md +43 -0
- package/dist/index.cjs +576 -0
- package/dist/index.d.cts +154 -0
- package/dist/index.d.ts +154 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +548 -0
- package/dist/index.js.map +1 -0
- package/package.json +44 -0
- package/src/index.ts +978 -0
package/README.md
ADDED
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
# @agentplugins/adapter-pimono
|
|
2
|
+
|
|
3
|
+
> AgentPlugins platform adapter for [Pi Mono](https://pi.mono/).
|
|
4
|
+
|
|
5
|
+
Generates TypeScript-native extensions for the Pi agent runtime from a universal `PluginManifest`. Pi Mono extensions are regular TS modules, so handlers are emitted as real functions rather than wrapped scripts.
|
|
6
|
+
|
|
7
|
+
## Installation
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
npm install @agentplugins/adapter-pimono
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
Typically installed transitively via [`@agentplugins/cli`](https://www.npmjs.com/package/@agentplugins/cli).
|
|
14
|
+
|
|
15
|
+
## Usage
|
|
16
|
+
|
|
17
|
+
```typescript
|
|
18
|
+
import { createPiMonoAdapter } from '@agentplugins/adapter-pimono';
|
|
19
|
+
|
|
20
|
+
const adapter = createPiMonoAdapter();
|
|
21
|
+
const output = await adapter.compile(manifest);
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
Or via the CLI:
|
|
25
|
+
|
|
26
|
+
```bash
|
|
27
|
+
npx agentplugins build --target pimono
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
## Output shape
|
|
31
|
+
|
|
32
|
+
A successful build writes to `dist/pimono/`:
|
|
33
|
+
|
|
34
|
+
```
|
|
35
|
+
dist/pimono/
|
|
36
|
+
└── <plugin-name>.ts
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
Install with: `cp -r dist/pimono ~/.pi/agent/extensions/`
|
|
40
|
+
|
|
41
|
+
## License
|
|
42
|
+
|
|
43
|
+
MIT
|
package/dist/index.cjs
ADDED
|
@@ -0,0 +1,576 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __export = (target, all) => {
|
|
7
|
+
for (var name in all)
|
|
8
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
+
};
|
|
10
|
+
var __copyProps = (to, from, except, desc) => {
|
|
11
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
+
for (let key of __getOwnPropNames(from))
|
|
13
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
+
}
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
+
|
|
20
|
+
// src/index.ts
|
|
21
|
+
var index_exports = {};
|
|
22
|
+
__export(index_exports, {
|
|
23
|
+
HOOK_TO_EVENT: () => HOOK_TO_EVENT,
|
|
24
|
+
PiMonoAdapter: () => PiMonoAdapter,
|
|
25
|
+
SUPPORTED_HANDLERS: () => SUPPORTED_HANDLERS,
|
|
26
|
+
SUPPORTED_HOOKS: () => SUPPORTED_HOOKS,
|
|
27
|
+
createPiMonoAdapter: () => createPiMonoAdapter,
|
|
28
|
+
piMonoAdapter: () => piMonoAdapter
|
|
29
|
+
});
|
|
30
|
+
module.exports = __toCommonJS(index_exports);
|
|
31
|
+
var import_core = require("@agentplugins/core");
|
|
32
|
+
var PLATFORM_NAME = "pimono";
|
|
33
|
+
var DISPLAY_NAME = "Pi Mono";
|
|
34
|
+
var MANIFEST_PATH = "package.json";
|
|
35
|
+
var MANIFEST_FORMAT = "json";
|
|
36
|
+
var SUPPORTED_HOOKS = [
|
|
37
|
+
"sessionStart",
|
|
38
|
+
"sessionEnd",
|
|
39
|
+
"preToolUse",
|
|
40
|
+
"postToolUse",
|
|
41
|
+
"userPromptSubmit",
|
|
42
|
+
"notification",
|
|
43
|
+
"subagentStart",
|
|
44
|
+
"subagentStop",
|
|
45
|
+
"preCompact",
|
|
46
|
+
"stop"
|
|
47
|
+
];
|
|
48
|
+
var SUPPORTED_HANDLERS = [
|
|
49
|
+
"inline",
|
|
50
|
+
// pi.on(event, async (ctx) => { … })
|
|
51
|
+
"reference"
|
|
52
|
+
// Handled by generating a proxy that calls the named function
|
|
53
|
+
];
|
|
54
|
+
var HOOK_TO_EVENT = {
|
|
55
|
+
sessionStart: "session.SessionStart",
|
|
56
|
+
sessionEnd: "session.SessionEnd",
|
|
57
|
+
preToolUse: "tool.ToolCall",
|
|
58
|
+
postToolUse: "tool.ToolResult",
|
|
59
|
+
userPromptSubmit: "message.MessageReceive",
|
|
60
|
+
notification: "message.Notification",
|
|
61
|
+
subagentStart: "agent.AgentStart",
|
|
62
|
+
subagentStop: "agent.AgentStop",
|
|
63
|
+
preCompact: "session.CompactStart",
|
|
64
|
+
stop: "agent.AgentStop"
|
|
65
|
+
};
|
|
66
|
+
function tsStringLiteral(raw) {
|
|
67
|
+
const escaped = raw.replace(/\\/g, "\\\\").replace(/'/g, "\\'").replace(/\n/g, "\\n").replace(/\r/g, "\\r");
|
|
68
|
+
return `'${escaped}'`;
|
|
69
|
+
}
|
|
70
|
+
function safeIdent(name) {
|
|
71
|
+
const cleaned = name.replace(/[^a-zA-Z0-9_]/g, "_");
|
|
72
|
+
return /^\d/.test(cleaned) ? `_${cleaned}` : cleaned;
|
|
73
|
+
}
|
|
74
|
+
function validatePlugin(plugin) {
|
|
75
|
+
const issues = [];
|
|
76
|
+
if (!plugin.name || typeof plugin.name !== "string") {
|
|
77
|
+
issues.push({
|
|
78
|
+
severity: import_core.Severity.ERROR,
|
|
79
|
+
message: `Plugin "name" is required and must be a non-empty string.`
|
|
80
|
+
});
|
|
81
|
+
}
|
|
82
|
+
if (plugin.hooks) {
|
|
83
|
+
for (const hookKey of Object.keys(plugin.hooks)) {
|
|
84
|
+
const hookName = hookKey;
|
|
85
|
+
if (!SUPPORTED_HOOKS.includes(hookName)) {
|
|
86
|
+
const piMonoEvent = HOOK_TO_EVENT[hookName];
|
|
87
|
+
issues.push({
|
|
88
|
+
severity: import_core.Severity.ERROR,
|
|
89
|
+
message: `Unsupported hook "${hookName}". ` + (piMonoEvent ? `This adapter maps it to "${piMonoEvent}", but the hook is not listed as supported.` : `No Pi Mono event mapping exists for this hook.`)
|
|
90
|
+
});
|
|
91
|
+
}
|
|
92
|
+
const hook = plugin.hooks[hookName];
|
|
93
|
+
if (!hook) continue;
|
|
94
|
+
const hookHandler = hook.handler;
|
|
95
|
+
if (hookHandler.type === "inline") {
|
|
96
|
+
continue;
|
|
97
|
+
}
|
|
98
|
+
if (hookHandler.type === "reference") {
|
|
99
|
+
const refHandler = hookHandler;
|
|
100
|
+
if (!refHandler.target || typeof refHandler.target !== "string") {
|
|
101
|
+
issues.push({
|
|
102
|
+
severity: import_core.Severity.ERROR,
|
|
103
|
+
message: `Handler reference for "${hookName}" must specify a non-empty "target" string.`
|
|
104
|
+
});
|
|
105
|
+
}
|
|
106
|
+
continue;
|
|
107
|
+
}
|
|
108
|
+
issues.push({
|
|
109
|
+
severity: import_core.Severity.WARNING,
|
|
110
|
+
message: `Unknown handler type "${hookHandler.type}" for hook "${hookName}". Will be treated as inline.`
|
|
111
|
+
});
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
if (plugin.tools) {
|
|
115
|
+
for (const tool of plugin.tools) {
|
|
116
|
+
if (!tool.name || typeof tool.name !== "string") {
|
|
117
|
+
issues.push({
|
|
118
|
+
severity: import_core.Severity.ERROR,
|
|
119
|
+
message: `Tool name is required.`
|
|
120
|
+
});
|
|
121
|
+
}
|
|
122
|
+
if (!tool.parameters || typeof tool.parameters !== "object") {
|
|
123
|
+
issues.push({
|
|
124
|
+
severity: import_core.Severity.ERROR,
|
|
125
|
+
message: `Tool "${tool.name ?? "?"}" must have a parameters object (TypeBox-compatible).`
|
|
126
|
+
});
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
if (plugin.commands) {
|
|
131
|
+
for (const cmd of plugin.commands) {
|
|
132
|
+
if (!cmd.name || typeof cmd.name !== "string") {
|
|
133
|
+
issues.push({
|
|
134
|
+
severity: import_core.Severity.ERROR,
|
|
135
|
+
message: `Command name is required.`
|
|
136
|
+
});
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
if (plugin.shortcuts) {
|
|
141
|
+
for (const sc of plugin.shortcuts) {
|
|
142
|
+
if (!sc.key || typeof sc.key !== "string") {
|
|
143
|
+
issues.push({
|
|
144
|
+
severity: import_core.Severity.ERROR,
|
|
145
|
+
message: `Shortcut key is required.`
|
|
146
|
+
});
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
if (plugin.flags) {
|
|
151
|
+
for (const flag of plugin.flags) {
|
|
152
|
+
if (!flag.name || typeof flag.name !== "string") {
|
|
153
|
+
issues.push({
|
|
154
|
+
severity: import_core.Severity.ERROR,
|
|
155
|
+
message: `Flag name is required.`
|
|
156
|
+
});
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
return issues;
|
|
161
|
+
}
|
|
162
|
+
function generateInlineHandlerBody(handler, event) {
|
|
163
|
+
const lines = [];
|
|
164
|
+
lines.push(`// Handler for ${event}`);
|
|
165
|
+
if (handler.code) {
|
|
166
|
+
lines.push(handler.code.trim());
|
|
167
|
+
} else if (handler.source) {
|
|
168
|
+
lines.push(`// NOTE: Handler source "${handler.source}" must be copied into this function.`);
|
|
169
|
+
lines.push(`throw new Error("Handler source not inlined: ${handler.source.replace(/"/g, "\\'")}");`);
|
|
170
|
+
} else {
|
|
171
|
+
lines.push(`ctx.logger?.info?.("[${event}] Hook invoked \u2014 no handler code provided.");`);
|
|
172
|
+
lines.push(`// TODO: Implement handler logic`);
|
|
173
|
+
}
|
|
174
|
+
return lines.join("\n ");
|
|
175
|
+
}
|
|
176
|
+
function generateReferenceHandler(handler) {
|
|
177
|
+
const { target, source } = handler;
|
|
178
|
+
const lines = [];
|
|
179
|
+
if (source) {
|
|
180
|
+
lines.push(`const mod = await import(${tsStringLiteral(source)});`);
|
|
181
|
+
lines.push(`const fn = mod[${tsStringLiteral(target)}] ?? mod.default;`);
|
|
182
|
+
} else {
|
|
183
|
+
lines.push(`const fn = ${safeIdent(target)};`);
|
|
184
|
+
}
|
|
185
|
+
lines.push(`if (typeof fn !== "function") {`);
|
|
186
|
+
lines.push(` throw new Error(\`Handler "${target}" is not a function.\`);`);
|
|
187
|
+
lines.push(`}`);
|
|
188
|
+
lines.push(`return fn(ctx);`);
|
|
189
|
+
return lines.join("\n ");
|
|
190
|
+
}
|
|
191
|
+
function generateEventRegistration(event, handler) {
|
|
192
|
+
const lines = [];
|
|
193
|
+
lines.push(`// ${event}`);
|
|
194
|
+
lines.push(`pi.on(${tsStringLiteral(event)}, async (ctx) => {`);
|
|
195
|
+
if (handler.type === "reference") {
|
|
196
|
+
lines.push(` ${generateReferenceHandler(handler).replace(/\n/g, "\n ")}`);
|
|
197
|
+
} else {
|
|
198
|
+
lines.push(
|
|
199
|
+
` ${generateInlineHandlerBody(handler, event).replace(/\n/g, "\n ")}`
|
|
200
|
+
);
|
|
201
|
+
}
|
|
202
|
+
lines.push(`});`);
|
|
203
|
+
return lines;
|
|
204
|
+
}
|
|
205
|
+
function generateToolRegistrations(tools) {
|
|
206
|
+
const lines = [];
|
|
207
|
+
for (const tool of tools) {
|
|
208
|
+
const toolName = safeIdent(tool.name);
|
|
209
|
+
lines.push(``);
|
|
210
|
+
lines.push(`// Tool: ${tool.name}`);
|
|
211
|
+
lines.push(`pi.registerTool({`);
|
|
212
|
+
lines.push(` name: ${tsStringLiteral(tool.name)},`);
|
|
213
|
+
lines.push(` description: ${tsStringLiteral(tool.description ?? `${tool.name} tool`)},`);
|
|
214
|
+
if (tool.parameters) {
|
|
215
|
+
const schemaJson = JSON.stringify(tool.parameters, null, 2).split("\n").map((l, i) => i === 0 ? l : ` ${l}`).join("\n");
|
|
216
|
+
lines.push(` schema: ${schemaJson},`);
|
|
217
|
+
}
|
|
218
|
+
lines.push(` handler: async (args) => {`);
|
|
219
|
+
if (tool.handler?.source) {
|
|
220
|
+
lines.push(` const mod = await import(${tsStringLiteral(tool.handler.source ?? "")});`);
|
|
221
|
+
lines.push(` return mod[${tsStringLiteral(tool.handler.target ?? "default")}](args);`);
|
|
222
|
+
} else if (tool.handler?.target) {
|
|
223
|
+
lines.push(` return ${safeIdent(tool.handler.target)}(args);`);
|
|
224
|
+
} else {
|
|
225
|
+
lines.push(` // TODO: Implement tool handler for "${tool.name}"`);
|
|
226
|
+
lines.push(` throw new Error("Tool handler not implemented: ${tool.name}");`);
|
|
227
|
+
}
|
|
228
|
+
lines.push(` },`);
|
|
229
|
+
lines.push(`});`);
|
|
230
|
+
}
|
|
231
|
+
return lines;
|
|
232
|
+
}
|
|
233
|
+
function generateCommandRegistrations(commands) {
|
|
234
|
+
const lines = [];
|
|
235
|
+
for (const cmd of commands) {
|
|
236
|
+
lines.push(``);
|
|
237
|
+
lines.push(`// Command: /${cmd.name}`);
|
|
238
|
+
lines.push(`pi.registerCommand(${tsStringLiteral(cmd.name)}, {`);
|
|
239
|
+
if (cmd.description) {
|
|
240
|
+
lines.push(` description: ${tsStringLiteral(cmd.description)},`);
|
|
241
|
+
}
|
|
242
|
+
if (cmd.args && cmd.args.length > 0) {
|
|
243
|
+
const argsSchema = cmd.args.map((a) => ({
|
|
244
|
+
name: a.name,
|
|
245
|
+
type: a.type ?? "string",
|
|
246
|
+
description: a.description,
|
|
247
|
+
required: a.required ?? false
|
|
248
|
+
}));
|
|
249
|
+
const argsJson = JSON.stringify(argsSchema, null, 2).split("\n").map((l, i) => i === 0 ? l : ` ${l}`).join("\n");
|
|
250
|
+
lines.push(` args: ${argsJson},`);
|
|
251
|
+
}
|
|
252
|
+
lines.push(` run: async (ctx, args) => {`);
|
|
253
|
+
if (cmd.handler?.source) {
|
|
254
|
+
lines.push(` const mod = await import(${tsStringLiteral(cmd.handler.source)});`);
|
|
255
|
+
lines.push(` return mod[${tsStringLiteral(cmd.handler.target ?? "default")}](ctx, args);`);
|
|
256
|
+
} else if (cmd.handler?.target) {
|
|
257
|
+
lines.push(` return ${safeIdent(cmd.handler.target)}(ctx, args);`);
|
|
258
|
+
} else {
|
|
259
|
+
lines.push(` // TODO: Implement command handler for "/${cmd.name}"`);
|
|
260
|
+
lines.push(` ctx.ui?.toast?.(\`/${cmd.name} executed\`);`);
|
|
261
|
+
}
|
|
262
|
+
lines.push(` },`);
|
|
263
|
+
lines.push(`});`);
|
|
264
|
+
}
|
|
265
|
+
return lines;
|
|
266
|
+
}
|
|
267
|
+
function generateShortcutRegistrations(shortcuts) {
|
|
268
|
+
const lines = [];
|
|
269
|
+
for (const sc of shortcuts) {
|
|
270
|
+
lines.push(``);
|
|
271
|
+
lines.push(`// Shortcut: ${sc.key}`);
|
|
272
|
+
lines.push(`pi.registerShortcut(${tsStringLiteral(sc.key)}, {`);
|
|
273
|
+
if (sc.description) {
|
|
274
|
+
lines.push(` description: ${tsStringLiteral(sc.description)},`);
|
|
275
|
+
}
|
|
276
|
+
if (sc.when) {
|
|
277
|
+
lines.push(` when: ${tsStringLiteral(sc.when)},`);
|
|
278
|
+
}
|
|
279
|
+
lines.push(` action: async (ctx) => {`);
|
|
280
|
+
if (sc.action) {
|
|
281
|
+
if (typeof sc.action === "string") {
|
|
282
|
+
lines.push(` return ${safeIdent(sc.action)}(ctx);`);
|
|
283
|
+
} else if (sc.action.source) {
|
|
284
|
+
lines.push(` const mod = await import(${tsStringLiteral(sc.action.source)});`);
|
|
285
|
+
lines.push(` return mod[${tsStringLiteral(sc.action.target ?? "default")}](ctx);`);
|
|
286
|
+
} else if (sc.action.target) {
|
|
287
|
+
lines.push(` return ${safeIdent(sc.action.target)}(ctx);`);
|
|
288
|
+
}
|
|
289
|
+
} else {
|
|
290
|
+
lines.push(` // TODO: Implement shortcut action for "${sc.key}"`);
|
|
291
|
+
lines.push(` ctx.logger?.info?.("Shortcut triggered: ${sc.key}");`);
|
|
292
|
+
}
|
|
293
|
+
lines.push(` },`);
|
|
294
|
+
lines.push(`});`);
|
|
295
|
+
}
|
|
296
|
+
return lines;
|
|
297
|
+
}
|
|
298
|
+
function generateFlagRegistrations(flags) {
|
|
299
|
+
const lines = [];
|
|
300
|
+
for (const flag of flags) {
|
|
301
|
+
lines.push(``);
|
|
302
|
+
lines.push(`// Flag: --${flag.name}`);
|
|
303
|
+
lines.push(`pi.registerFlag(${tsStringLiteral(flag.name)}, {`);
|
|
304
|
+
if (flag.description) {
|
|
305
|
+
lines.push(` description: ${tsStringLiteral(flag.description)},`);
|
|
306
|
+
}
|
|
307
|
+
if (flag.alias) {
|
|
308
|
+
lines.push(` alias: ${tsStringLiteral(flag.alias)},`);
|
|
309
|
+
}
|
|
310
|
+
if (flag.type) {
|
|
311
|
+
lines.push(` type: ${tsStringLiteral(flag.type)},`);
|
|
312
|
+
}
|
|
313
|
+
if (flag.defaultValue !== void 0) {
|
|
314
|
+
lines.push(` default: ${JSON.stringify(flag.defaultValue)},`);
|
|
315
|
+
}
|
|
316
|
+
lines.push(` handler: async (ctx, value) => {`);
|
|
317
|
+
if (flag.handler?.source) {
|
|
318
|
+
lines.push(` const mod = await import(${tsStringLiteral(flag.handler.source)});`);
|
|
319
|
+
lines.push(` return mod[${tsStringLiteral(flag.handler.target ?? "default")}](ctx, value);`);
|
|
320
|
+
} else if (flag.handler?.target) {
|
|
321
|
+
lines.push(` return ${safeIdent(flag.handler.target)}(ctx, value);`);
|
|
322
|
+
} else {
|
|
323
|
+
lines.push(` // TODO: Implement flag handler for "--${flag.name}"`);
|
|
324
|
+
lines.push(` ctx.logger?.info?.(\`Flag --${flag.name}=\${value} processed\`);`);
|
|
325
|
+
}
|
|
326
|
+
lines.push(` },`);
|
|
327
|
+
lines.push(`});`);
|
|
328
|
+
}
|
|
329
|
+
return lines;
|
|
330
|
+
}
|
|
331
|
+
function compilePlugin(plugin) {
|
|
332
|
+
const files = [];
|
|
333
|
+
let isMultiFile = false;
|
|
334
|
+
if (plugin.hooks) {
|
|
335
|
+
for (const handler of Object.values(plugin.hooks)) {
|
|
336
|
+
if (handler.type === "reference" && handler.source) {
|
|
337
|
+
isMultiFile = true;
|
|
338
|
+
break;
|
|
339
|
+
}
|
|
340
|
+
if (handler.type === "inline" && handler.source) {
|
|
341
|
+
isMultiFile = true;
|
|
342
|
+
break;
|
|
343
|
+
}
|
|
344
|
+
}
|
|
345
|
+
}
|
|
346
|
+
if (plugin.tools) {
|
|
347
|
+
for (const tool of plugin.tools) {
|
|
348
|
+
if (tool.handler?.source) {
|
|
349
|
+
isMultiFile = true;
|
|
350
|
+
break;
|
|
351
|
+
}
|
|
352
|
+
}
|
|
353
|
+
}
|
|
354
|
+
if (plugin.commands) {
|
|
355
|
+
for (const cmd of plugin.commands) {
|
|
356
|
+
if (cmd.handler?.source) {
|
|
357
|
+
isMultiFile = true;
|
|
358
|
+
break;
|
|
359
|
+
}
|
|
360
|
+
}
|
|
361
|
+
}
|
|
362
|
+
if (plugin.shortcuts) {
|
|
363
|
+
for (const sc of plugin.shortcuts) {
|
|
364
|
+
if (typeof sc.action !== "string" && sc.action?.source) {
|
|
365
|
+
isMultiFile = true;
|
|
366
|
+
break;
|
|
367
|
+
}
|
|
368
|
+
}
|
|
369
|
+
}
|
|
370
|
+
if (plugin.flags) {
|
|
371
|
+
for (const flag of plugin.flags) {
|
|
372
|
+
if (flag.handler?.source) {
|
|
373
|
+
isMultiFile = true;
|
|
374
|
+
break;
|
|
375
|
+
}
|
|
376
|
+
}
|
|
377
|
+
}
|
|
378
|
+
const tsLines = [];
|
|
379
|
+
tsLines.push(`/**`);
|
|
380
|
+
tsLines.push(` * Generated Pi Mono Extension \u2014 ${plugin.name}`);
|
|
381
|
+
tsLines.push(` *`);
|
|
382
|
+
tsLines.push(` * Platform: ${DISPLAY_NAME}`);
|
|
383
|
+
tsLines.push(` * Plugin: ${plugin.name}${plugin.version ? ` v${plugin.version}` : ""}`);
|
|
384
|
+
tsLines.push(` * Generated: ${(/* @__PURE__ */ new Date()).toISOString()}`);
|
|
385
|
+
tsLines.push(` *`);
|
|
386
|
+
tsLines.push(` * This file is auto-generated by @agentplugins/adapter-pimono.`);
|
|
387
|
+
tsLines.push(` * Do not edit manually \u2014 changes will be overwritten on next compile.`);
|
|
388
|
+
tsLines.push(` */`);
|
|
389
|
+
tsLines.push(``);
|
|
390
|
+
tsLines.push(`import type { ExtensionAPI } from "@earendil-works/pi-coding-agent";`);
|
|
391
|
+
const dynamicImports = /* @__PURE__ */ new Set();
|
|
392
|
+
if (plugin.hooks) {
|
|
393
|
+
for (const handler of Object.values(plugin.hooks)) {
|
|
394
|
+
if ("source" in handler && handler.source) {
|
|
395
|
+
dynamicImports.add(handler.source);
|
|
396
|
+
}
|
|
397
|
+
}
|
|
398
|
+
}
|
|
399
|
+
if (plugin.tools) {
|
|
400
|
+
for (const tool of plugin.tools) {
|
|
401
|
+
if (tool.handler?.source) dynamicImports.add(tool.handler.source);
|
|
402
|
+
}
|
|
403
|
+
}
|
|
404
|
+
if (plugin.commands) {
|
|
405
|
+
for (const cmd of plugin.commands) {
|
|
406
|
+
if (cmd.handler?.source) dynamicImports.add(cmd.handler.source);
|
|
407
|
+
}
|
|
408
|
+
}
|
|
409
|
+
if (dynamicImports.size > 0) {
|
|
410
|
+
tsLines.push(``);
|
|
411
|
+
tsLines.push(`// External handler modules (loaded dynamically via jiti)`);
|
|
412
|
+
}
|
|
413
|
+
tsLines.push(``);
|
|
414
|
+
tsLines.push(`/**`);
|
|
415
|
+
tsLines.push(` * Pi Mono extension factory.`);
|
|
416
|
+
tsLines.push(` *`);
|
|
417
|
+
tsLines.push(` * @param pi - The ExtensionAPI instance provided by the Pi Mono runtime.`);
|
|
418
|
+
tsLines.push(` */`);
|
|
419
|
+
tsLines.push(`export default function(pi: ExtensionAPI) {`);
|
|
420
|
+
tsLines.push(` // Extension entry point \u2014 register all hooks, tools, commands, etc.`);
|
|
421
|
+
tsLines.push(` pi.logger?.info?.("[${plugin.name}] Extension loaded on ${DISPLAY_NAME}");`);
|
|
422
|
+
tsLines.push(``);
|
|
423
|
+
if (plugin.hooks && Object.keys(plugin.hooks).length > 0) {
|
|
424
|
+
tsLines.push(` /* \u2500\u2500 Lifecycle Hooks \u2500\u2500 */`);
|
|
425
|
+
for (const [hookName, handler] of Object.entries(plugin.hooks)) {
|
|
426
|
+
const event = HOOK_TO_EVENT[hookName];
|
|
427
|
+
if (!event) {
|
|
428
|
+
tsLines.push(` // WARNING: No Pi Mono event for hook "${hookName}" \u2014 skipping`);
|
|
429
|
+
tsLines.push(``);
|
|
430
|
+
continue;
|
|
431
|
+
}
|
|
432
|
+
const regLines = generateEventRegistration(event, handler);
|
|
433
|
+
for (const line of regLines) {
|
|
434
|
+
tsLines.push(` ${line}`);
|
|
435
|
+
}
|
|
436
|
+
tsLines.push(``);
|
|
437
|
+
}
|
|
438
|
+
}
|
|
439
|
+
if (plugin.tools && plugin.tools.length > 0) {
|
|
440
|
+
tsLines.push(` /* \u2500\u2500 Tools \u2500\u2500 */`);
|
|
441
|
+
for (const line of generateToolRegistrations(plugin.tools)) {
|
|
442
|
+
tsLines.push(` ${line}`);
|
|
443
|
+
}
|
|
444
|
+
tsLines.push(``);
|
|
445
|
+
}
|
|
446
|
+
if (plugin.commands && plugin.commands.length > 0) {
|
|
447
|
+
tsLines.push(` /* \u2500\u2500 Commands \u2500\u2500 */`);
|
|
448
|
+
for (const line of generateCommandRegistrations(plugin.commands)) {
|
|
449
|
+
tsLines.push(` ${line}`);
|
|
450
|
+
}
|
|
451
|
+
tsLines.push(``);
|
|
452
|
+
}
|
|
453
|
+
if (plugin.shortcuts && plugin.shortcuts.length > 0) {
|
|
454
|
+
tsLines.push(` /* \u2500\u2500 Keyboard Shortcuts \u2500\u2500 */`);
|
|
455
|
+
for (const line of generateShortcutRegistrations(plugin.shortcuts)) {
|
|
456
|
+
tsLines.push(` ${line}`);
|
|
457
|
+
}
|
|
458
|
+
tsLines.push(``);
|
|
459
|
+
}
|
|
460
|
+
if (plugin.flags && plugin.flags.length > 0) {
|
|
461
|
+
tsLines.push(` /* \u2500\u2500 CLI Flags \u2500\u2500 */`);
|
|
462
|
+
for (const line of generateFlagRegistrations(plugin.flags)) {
|
|
463
|
+
tsLines.push(` ${line}`);
|
|
464
|
+
}
|
|
465
|
+
tsLines.push(``);
|
|
466
|
+
}
|
|
467
|
+
if (plugin.config?.persist) {
|
|
468
|
+
tsLines.push(` /* \u2500\u2500 Persistent State \u2500\u2500 */`);
|
|
469
|
+
tsLines.push(` pi.appendEntry("${plugin.name}", {`);
|
|
470
|
+
tsLines.push(` loadedAt: new Date().toISOString(),`);
|
|
471
|
+
tsLines.push(` version: ${tsStringLiteral(plugin.version ?? "0.0.0")},`);
|
|
472
|
+
tsLines.push(` });`);
|
|
473
|
+
tsLines.push(``);
|
|
474
|
+
}
|
|
475
|
+
tsLines.push(`}`);
|
|
476
|
+
tsLines.push(``);
|
|
477
|
+
files.push({ path: "index.ts", content: tsLines.join("\n") });
|
|
478
|
+
if (isMultiFile) {
|
|
479
|
+
const pkg = {
|
|
480
|
+
name: plugin.name,
|
|
481
|
+
version: plugin.version ?? "0.0.0",
|
|
482
|
+
description: plugin.description ?? `Pi Mono extension for ${plugin.name}`,
|
|
483
|
+
main: "index.ts",
|
|
484
|
+
pi: {
|
|
485
|
+
name: plugin.name,
|
|
486
|
+
version: plugin.version ?? "0.0.0",
|
|
487
|
+
displayName: plugin.displayName ?? plugin.name,
|
|
488
|
+
description: plugin.description,
|
|
489
|
+
entry: "index.ts",
|
|
490
|
+
author: plugin.author,
|
|
491
|
+
license: plugin.license,
|
|
492
|
+
hooks: Object.keys(plugin.hooks ?? {}).map((h) => ({
|
|
493
|
+
universal: h,
|
|
494
|
+
piEvent: HOOK_TO_EVENT[h] ?? null
|
|
495
|
+
})),
|
|
496
|
+
tools: (plugin.tools ?? []).map((t) => t.name),
|
|
497
|
+
commands: (plugin.commands ?? []).map((c) => c.name),
|
|
498
|
+
shortcuts: (plugin.shortcuts ?? []).map((s) => s.key),
|
|
499
|
+
flags: (plugin.flags ?? []).map((f) => f.name),
|
|
500
|
+
trusted: plugin.config?.trusted ?? true,
|
|
501
|
+
autoLoad: plugin.config?.autoLoad ?? false
|
|
502
|
+
}
|
|
503
|
+
};
|
|
504
|
+
files.push({ path: "package.json", content: JSON.stringify(pkg, null, 2) + "\n" });
|
|
505
|
+
}
|
|
506
|
+
const warnings = [];
|
|
507
|
+
if (plugin.hooks) {
|
|
508
|
+
for (const hookName of Object.keys(plugin.hooks)) {
|
|
509
|
+
if (!SUPPORTED_HOOKS.includes(hookName)) {
|
|
510
|
+
warnings.push(
|
|
511
|
+
`Hook "${hookName}" is not supported by the Pi Mono adapter and was skipped.`
|
|
512
|
+
);
|
|
513
|
+
}
|
|
514
|
+
}
|
|
515
|
+
}
|
|
516
|
+
return {
|
|
517
|
+
files,
|
|
518
|
+
manifest: plugin,
|
|
519
|
+
warnings,
|
|
520
|
+
issues: []
|
|
521
|
+
};
|
|
522
|
+
}
|
|
523
|
+
var PiMonoAdapter = class {
|
|
524
|
+
/** @inheritdoc */
|
|
525
|
+
name = PLATFORM_NAME;
|
|
526
|
+
/** @inheritdoc */
|
|
527
|
+
displayName = DISPLAY_NAME;
|
|
528
|
+
/** @inheritdoc */
|
|
529
|
+
supportedHooks = SUPPORTED_HOOKS;
|
|
530
|
+
/** @inheritdoc */
|
|
531
|
+
supportedHandlers = SUPPORTED_HANDLERS;
|
|
532
|
+
/** @inheritdoc */
|
|
533
|
+
manifestPath = MANIFEST_PATH;
|
|
534
|
+
/** @inheritdoc */
|
|
535
|
+
manifestFormat = MANIFEST_FORMAT;
|
|
536
|
+
/**
|
|
537
|
+
* Validate a plugin manifest for Pi Mono compatibility.
|
|
538
|
+
*
|
|
539
|
+
* @param plugin - The plugin manifest.
|
|
540
|
+
* @returns Array of validation issues (empty if valid).
|
|
541
|
+
*/
|
|
542
|
+
validate(plugin) {
|
|
543
|
+
return validatePlugin(plugin);
|
|
544
|
+
}
|
|
545
|
+
/**
|
|
546
|
+
* Compile a plugin manifest into Pi Mono extension files.
|
|
547
|
+
*
|
|
548
|
+
* @param plugin - The plugin manifest.
|
|
549
|
+
* @returns AdapterOutput containing generated files and metadata.
|
|
550
|
+
*/
|
|
551
|
+
compile(plugin) {
|
|
552
|
+
const issues = this.validate(plugin);
|
|
553
|
+
const errors = issues.filter((i) => i.severity === "error");
|
|
554
|
+
if (errors.length > 0) {
|
|
555
|
+
const errorMessages = errors.map((e) => ` - ${e.message}`).join("\n");
|
|
556
|
+
throw new Error(
|
|
557
|
+
`Pi Mono adapter validation failed with ${errors.length} error(s):
|
|
558
|
+
${errorMessages}`
|
|
559
|
+
);
|
|
560
|
+
}
|
|
561
|
+
return compilePlugin(plugin);
|
|
562
|
+
}
|
|
563
|
+
};
|
|
564
|
+
var piMonoAdapter = new PiMonoAdapter();
|
|
565
|
+
function createPiMonoAdapter() {
|
|
566
|
+
return new PiMonoAdapter();
|
|
567
|
+
}
|
|
568
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
569
|
+
0 && (module.exports = {
|
|
570
|
+
HOOK_TO_EVENT,
|
|
571
|
+
PiMonoAdapter,
|
|
572
|
+
SUPPORTED_HANDLERS,
|
|
573
|
+
SUPPORTED_HOOKS,
|
|
574
|
+
createPiMonoAdapter,
|
|
575
|
+
piMonoAdapter
|
|
576
|
+
});
|