@fml-inc/fml 0.8.0-rc.2 → 0.8.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/.claude-plugin/plugin.json +1 -1
- package/README.md +12 -10
- package/dist/{chunk-WZLLO563.js → chunk-7DWFJENY.js} +1 -1
- package/dist/{chunk-56TPYMNK.js → chunk-KBT5RMAU.js} +19 -3
- package/dist/cli.js +414 -209
- package/dist/hook-handler.js +10 -3
- package/dist/observer-server.js +3 -3
- package/dist/pi/extension.js +350 -0
- package/package.json +4 -2
package/dist/hook-handler.js
CHANGED
|
@@ -6,14 +6,13 @@ import {
|
|
|
6
6
|
getActiveHookDestinationBinding
|
|
7
7
|
} from "./chunk-DZKYW327.js";
|
|
8
8
|
import {
|
|
9
|
-
HOOK_TARGETS,
|
|
10
9
|
SHELL_TOOL_NAMES,
|
|
11
10
|
createHookInboxEntry,
|
|
12
11
|
hookInboxDeliveryPayload,
|
|
13
12
|
normalizeObserverHookCapture,
|
|
14
13
|
persistHookInboxEntry,
|
|
15
14
|
readObserverAuthToken
|
|
16
|
-
} from "./chunk-
|
|
15
|
+
} from "./chunk-KBT5RMAU.js";
|
|
17
16
|
import {
|
|
18
17
|
resolveRepositoryRootFromCwd,
|
|
19
18
|
resolveRepositorySlugFromCwd
|
|
@@ -262,8 +261,16 @@ var MAX_HOOK_STDIN_BYTES = 4 * 1024 * 1024;
|
|
|
262
261
|
var HOOK_REQUEST_TIMEOUT_MS = 500;
|
|
263
262
|
var HOOK_STDIN_TIMEOUT_MS = 5e3;
|
|
264
263
|
var HOOK_REPO_RESOLUTION_TIMEOUT_MS = 250;
|
|
264
|
+
var INSTALLED_HOOK_TARGETS = Object.freeze([
|
|
265
|
+
"claude",
|
|
266
|
+
"codex",
|
|
267
|
+
"gemini",
|
|
268
|
+
"grok"
|
|
269
|
+
]);
|
|
265
270
|
function parseHookTarget(value) {
|
|
266
|
-
return
|
|
271
|
+
return INSTALLED_HOOK_TARGETS.includes(
|
|
272
|
+
value
|
|
273
|
+
) ? value : null;
|
|
267
274
|
}
|
|
268
275
|
function observerEndpoint(endpointFile) {
|
|
269
276
|
try {
|
package/dist/observer-server.js
CHANGED
|
@@ -6,7 +6,7 @@ import {
|
|
|
6
6
|
observerLeaseIsOwned,
|
|
7
7
|
removeObserverStateIfOwned,
|
|
8
8
|
updateObserverState
|
|
9
|
-
} from "./chunk-
|
|
9
|
+
} from "./chunk-7DWFJENY.js";
|
|
10
10
|
import {
|
|
11
11
|
createHookSyncLoop,
|
|
12
12
|
getActiveHookDestinationBinding
|
|
@@ -25,7 +25,7 @@ import {
|
|
|
25
25
|
parseHookInboxMetadata,
|
|
26
26
|
readHookInboxStatusAsync,
|
|
27
27
|
retireHookInboxEntry
|
|
28
|
-
} from "./chunk-
|
|
28
|
+
} from "./chunk-KBT5RMAU.js";
|
|
29
29
|
import "./chunk-7V7G7NVF.js";
|
|
30
30
|
import {
|
|
31
31
|
ObserverSyncCycleAbortedError,
|
|
@@ -1239,7 +1239,7 @@ var hookRejectionStatus = () => ({
|
|
|
1239
1239
|
...lastRejectedReason !== void 0 ? { lastRejectedReason } : {},
|
|
1240
1240
|
...lastRejectedTarget !== void 0 ? { lastRejectedTarget } : {}
|
|
1241
1241
|
});
|
|
1242
|
-
var packageVersion = true ? "0.8.0
|
|
1242
|
+
var packageVersion = true ? "0.8.0+246af775" : "dev";
|
|
1243
1243
|
var health = () => ({
|
|
1244
1244
|
status: "ok",
|
|
1245
1245
|
service: OBSERVER_SERVICE_NAME,
|
|
@@ -0,0 +1,350 @@
|
|
|
1
|
+
// src/pi/extension.ts
|
|
2
|
+
import { randomUUID as randomUUID2 } from "node:crypto";
|
|
3
|
+
import fs2 from "node:fs";
|
|
4
|
+
import os from "node:os";
|
|
5
|
+
import path2 from "node:path";
|
|
6
|
+
|
|
7
|
+
// ../../packages/agent-targets/src/install/pi/index.ts
|
|
8
|
+
import fs from "node:fs";
|
|
9
|
+
import path from "node:path";
|
|
10
|
+
import { randomUUID } from "node:crypto";
|
|
11
|
+
var FML_PI_EXTENSION_MARKER = "__FML_PI_EXTENSION_V1__";
|
|
12
|
+
var LEGACY_PI_EXTENSION_MARKER = "__panopticonPiExtensionTest";
|
|
13
|
+
var LEGACY_PI_EXTENSION_SIGNATURES = Object.freeze([
|
|
14
|
+
"PANOPTICON_PORT",
|
|
15
|
+
'"/hooks"',
|
|
16
|
+
"UserPromptSubmit",
|
|
17
|
+
"PreToolUse",
|
|
18
|
+
"PostToolUse",
|
|
19
|
+
"SessionEnd"
|
|
20
|
+
]);
|
|
21
|
+
function pathApiFor(platform) {
|
|
22
|
+
return platform === "win32" ? path.win32 : path.posix;
|
|
23
|
+
}
|
|
24
|
+
function resolvePiAgentDir(context, pathApi) {
|
|
25
|
+
const configured = context.env.PI_CODING_AGENT_DIR?.trim();
|
|
26
|
+
if (!configured) {
|
|
27
|
+
return pathApi.join(context.homeDir, ".pi", "agent");
|
|
28
|
+
}
|
|
29
|
+
if (configured === "~") return context.homeDir;
|
|
30
|
+
if (configured.startsWith("~/") || configured.startsWith("~\\")) {
|
|
31
|
+
return pathApi.join(context.homeDir, configured.slice(2));
|
|
32
|
+
}
|
|
33
|
+
return pathApi.normalize(configured);
|
|
34
|
+
}
|
|
35
|
+
function readFileIfPresent(filePath) {
|
|
36
|
+
try {
|
|
37
|
+
return fs.readFileSync(filePath, "utf8");
|
|
38
|
+
} catch (error) {
|
|
39
|
+
if (error.code === "ENOENT") return null;
|
|
40
|
+
throw error;
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
function isOwnedExtension(source, legacy = false) {
|
|
44
|
+
return source.includes(FML_PI_EXTENSION_MARKER) || legacy && (source.includes(LEGACY_PI_EXTENSION_MARKER) || LEGACY_PI_EXTENSION_SIGNATURES.every(
|
|
45
|
+
(signature) => source.includes(signature)
|
|
46
|
+
));
|
|
47
|
+
}
|
|
48
|
+
function removeLegacyExtension(filePath) {
|
|
49
|
+
const source = readFileIfPresent(filePath);
|
|
50
|
+
if (source === null) return { removed: false, preserved: false };
|
|
51
|
+
if (!isOwnedExtension(source, true)) {
|
|
52
|
+
return { removed: false, preserved: true };
|
|
53
|
+
}
|
|
54
|
+
fs.rmSync(filePath);
|
|
55
|
+
return { removed: true, preserved: false };
|
|
56
|
+
}
|
|
57
|
+
function writeExtensionAtomically(filePath, source) {
|
|
58
|
+
fs.mkdirSync(path.dirname(filePath), { recursive: true, mode: 448 });
|
|
59
|
+
const temporaryPath = path.join(
|
|
60
|
+
path.dirname(filePath),
|
|
61
|
+
`.${path.basename(filePath)}.${process.pid}.${randomUUID()}.tmp`
|
|
62
|
+
);
|
|
63
|
+
try {
|
|
64
|
+
fs.writeFileSync(temporaryPath, source, { encoding: "utf8", mode: 384 });
|
|
65
|
+
if (process.platform === "win32" && fs.existsSync(filePath)) {
|
|
66
|
+
fs.rmSync(filePath);
|
|
67
|
+
}
|
|
68
|
+
fs.renameSync(temporaryPath, filePath);
|
|
69
|
+
} finally {
|
|
70
|
+
fs.rmSync(temporaryPath, { force: true });
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
var PI_EXTENSION_INSTALLER = Object.freeze({
|
|
74
|
+
resolvePaths(context) {
|
|
75
|
+
const pathApi = pathApiFor(context.platform);
|
|
76
|
+
const extensionsDir = pathApi.join(
|
|
77
|
+
resolvePiAgentDir(context, pathApi),
|
|
78
|
+
"extensions"
|
|
79
|
+
);
|
|
80
|
+
return {
|
|
81
|
+
sourcePath: pathApi.join(
|
|
82
|
+
context.packageRoot,
|
|
83
|
+
"dist",
|
|
84
|
+
"pi",
|
|
85
|
+
"extension.js"
|
|
86
|
+
),
|
|
87
|
+
extensionsDir,
|
|
88
|
+
destinationPath: pathApi.join(extensionsDir, "fml.js"),
|
|
89
|
+
legacyDestinationPath: pathApi.join(extensionsDir, "panopticon.js")
|
|
90
|
+
};
|
|
91
|
+
},
|
|
92
|
+
install(paths) {
|
|
93
|
+
const source = fs.readFileSync(paths.sourcePath, "utf8");
|
|
94
|
+
if (!source.includes(FML_PI_EXTENSION_MARKER)) {
|
|
95
|
+
throw new Error(
|
|
96
|
+
`Packaged Pi extension is invalid: ${paths.sourcePath} does not contain the FML ownership marker`
|
|
97
|
+
);
|
|
98
|
+
}
|
|
99
|
+
const existing = readFileIfPresent(paths.destinationPath);
|
|
100
|
+
if (existing !== null && !isOwnedExtension(existing)) {
|
|
101
|
+
const legacy2 = removeLegacyExtension(paths.legacyDestinationPath);
|
|
102
|
+
return {
|
|
103
|
+
status: "preserved",
|
|
104
|
+
destinationPath: paths.destinationPath,
|
|
105
|
+
reason: "an extension not managed by FML already exists at this path",
|
|
106
|
+
legacyRemoved: legacy2.removed,
|
|
107
|
+
legacyPreserved: legacy2.preserved
|
|
108
|
+
};
|
|
109
|
+
}
|
|
110
|
+
const status = existing === null ? "installed" : existing === source ? "unchanged" : "updated";
|
|
111
|
+
if (status !== "unchanged") {
|
|
112
|
+
writeExtensionAtomically(paths.destinationPath, source);
|
|
113
|
+
}
|
|
114
|
+
const legacy = removeLegacyExtension(paths.legacyDestinationPath);
|
|
115
|
+
return {
|
|
116
|
+
status,
|
|
117
|
+
destinationPath: paths.destinationPath,
|
|
118
|
+
legacyRemoved: legacy.removed,
|
|
119
|
+
legacyPreserved: legacy.preserved
|
|
120
|
+
};
|
|
121
|
+
},
|
|
122
|
+
uninstall(paths) {
|
|
123
|
+
const existing = readFileIfPresent(paths.destinationPath);
|
|
124
|
+
const legacy = removeLegacyExtension(paths.legacyDestinationPath);
|
|
125
|
+
if (existing === null) {
|
|
126
|
+
return {
|
|
127
|
+
status: "absent",
|
|
128
|
+
destinationPath: paths.destinationPath,
|
|
129
|
+
legacyRemoved: legacy.removed,
|
|
130
|
+
legacyPreserved: legacy.preserved
|
|
131
|
+
};
|
|
132
|
+
}
|
|
133
|
+
if (!isOwnedExtension(existing)) {
|
|
134
|
+
return {
|
|
135
|
+
status: "preserved",
|
|
136
|
+
destinationPath: paths.destinationPath,
|
|
137
|
+
reason: "the existing extension is not managed by FML",
|
|
138
|
+
legacyRemoved: legacy.removed,
|
|
139
|
+
legacyPreserved: legacy.preserved
|
|
140
|
+
};
|
|
141
|
+
}
|
|
142
|
+
fs.rmSync(paths.destinationPath);
|
|
143
|
+
return {
|
|
144
|
+
status: "removed",
|
|
145
|
+
destinationPath: paths.destinationPath,
|
|
146
|
+
legacyRemoved: legacy.removed,
|
|
147
|
+
legacyPreserved: legacy.preserved
|
|
148
|
+
};
|
|
149
|
+
}
|
|
150
|
+
});
|
|
151
|
+
|
|
152
|
+
// src/pi/extension.ts
|
|
153
|
+
var DEFAULT_REQUEST_TIMEOUT_MS = 500;
|
|
154
|
+
var DEFAULT_SHUTDOWN_FLUSH_TIMEOUT_MS = 5e3;
|
|
155
|
+
var pendingPosts = /* @__PURE__ */ new Set();
|
|
156
|
+
function positiveInteger(value, fallback) {
|
|
157
|
+
if (!value) return fallback;
|
|
158
|
+
const parsed = Number.parseInt(value, 10);
|
|
159
|
+
return Number.isInteger(parsed) && parsed > 0 ? parsed : fallback;
|
|
160
|
+
}
|
|
161
|
+
function absoluteEnvPath(value) {
|
|
162
|
+
if (!value?.trim()) return void 0;
|
|
163
|
+
const trimmed = value.trim();
|
|
164
|
+
if (trimmed === "~") return os.homedir();
|
|
165
|
+
if (trimmed.startsWith("~/") || trimmed.startsWith("~\\")) {
|
|
166
|
+
return path2.join(os.homedir(), trimmed.slice(2));
|
|
167
|
+
}
|
|
168
|
+
return path2.isAbsolute(trimmed) ? path2.normalize(trimmed) : void 0;
|
|
169
|
+
}
|
|
170
|
+
function observerDirectory() {
|
|
171
|
+
const fmlHome = absoluteEnvPath(process.env.FML_HOME);
|
|
172
|
+
return absoluteEnvPath(process.env.FML_OBSERVER_DIR) ?? absoluteEnvPath(process.env.PANOPTICON_HOME) ?? (fmlHome ? path2.join(fmlHome, "panopticon") : path2.join(os.homedir(), ".fml", "panopticon"));
|
|
173
|
+
}
|
|
174
|
+
function readObserverEndpoint(filePath) {
|
|
175
|
+
try {
|
|
176
|
+
const parsed = JSON.parse(fs2.readFileSync(filePath, "utf8"));
|
|
177
|
+
if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) {
|
|
178
|
+
return null;
|
|
179
|
+
}
|
|
180
|
+
const record = parsed;
|
|
181
|
+
if (record.host !== "127.0.0.1" && record.host !== "::1" && record.host !== "localhost" || typeof record.port !== "number" || !Number.isInteger(record.port) || record.port <= 0 || record.port > 65535) {
|
|
182
|
+
return null;
|
|
183
|
+
}
|
|
184
|
+
return { host: record.host, port: record.port };
|
|
185
|
+
} catch {
|
|
186
|
+
return null;
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
function readObserverAuthToken(filePath) {
|
|
190
|
+
try {
|
|
191
|
+
return fs2.readFileSync(filePath, "utf8").trim() || null;
|
|
192
|
+
} catch {
|
|
193
|
+
return null;
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
async function deliver(event) {
|
|
197
|
+
const directory = observerDirectory();
|
|
198
|
+
const endpoint = readObserverEndpoint(path2.join(directory, "endpoint.json"));
|
|
199
|
+
const authToken = readObserverAuthToken(path2.join(directory, "auth-token"));
|
|
200
|
+
if (!endpoint || !authToken) return;
|
|
201
|
+
const host = endpoint.host === "::1" ? "[::1]" : endpoint.host;
|
|
202
|
+
try {
|
|
203
|
+
const response = await fetch(`http://${host}:${endpoint.port}/hooks`, {
|
|
204
|
+
method: "POST",
|
|
205
|
+
headers: {
|
|
206
|
+
Authorization: `Bearer ${authToken}`,
|
|
207
|
+
"Content-Type": "application/json"
|
|
208
|
+
},
|
|
209
|
+
body: JSON.stringify({
|
|
210
|
+
target: "pi",
|
|
211
|
+
payload: event,
|
|
212
|
+
...event.cwd ? { cwd: event.cwd } : {}
|
|
213
|
+
}),
|
|
214
|
+
signal: AbortSignal.timeout(
|
|
215
|
+
positiveInteger(
|
|
216
|
+
process.env.FML_PI_REQUEST_TIMEOUT_MS,
|
|
217
|
+
DEFAULT_REQUEST_TIMEOUT_MS
|
|
218
|
+
)
|
|
219
|
+
)
|
|
220
|
+
});
|
|
221
|
+
await response.arrayBuffer();
|
|
222
|
+
} catch {
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
function post(event) {
|
|
226
|
+
const request = deliver(event);
|
|
227
|
+
pendingPosts.add(request);
|
|
228
|
+
void request.finally(() => pendingPosts.delete(request));
|
|
229
|
+
}
|
|
230
|
+
async function flushPendingPosts(timeoutMs = positiveInteger(
|
|
231
|
+
process.env.FML_PI_SHUTDOWN_FLUSH_TIMEOUT_MS,
|
|
232
|
+
DEFAULT_SHUTDOWN_FLUSH_TIMEOUT_MS
|
|
233
|
+
)) {
|
|
234
|
+
if (pendingPosts.size === 0) return;
|
|
235
|
+
await Promise.race([
|
|
236
|
+
Promise.allSettled([...pendingPosts]),
|
|
237
|
+
new Promise((resolve) => setTimeout(resolve, timeoutMs))
|
|
238
|
+
]);
|
|
239
|
+
}
|
|
240
|
+
function modelLabel(model) {
|
|
241
|
+
if (!model || typeof model !== "object") return void 0;
|
|
242
|
+
const record = model;
|
|
243
|
+
const id = record.id ?? record.name ?? record.model;
|
|
244
|
+
const provider = record.provider ?? record.providerId;
|
|
245
|
+
return [provider, id].filter((value) => typeof value === "string" && value.length > 0).join(":") || void 0;
|
|
246
|
+
}
|
|
247
|
+
function fmlPiExtension(pi) {
|
|
248
|
+
let sessionId = randomUUID2();
|
|
249
|
+
let cwd;
|
|
250
|
+
function emit(event) {
|
|
251
|
+
post({
|
|
252
|
+
...event,
|
|
253
|
+
session_id: sessionId,
|
|
254
|
+
source: "pi",
|
|
255
|
+
cwd
|
|
256
|
+
});
|
|
257
|
+
}
|
|
258
|
+
pi.on("session_start", async (_event, context) => {
|
|
259
|
+
sessionId = context.sessionManager.getSessionId();
|
|
260
|
+
cwd = context.cwd;
|
|
261
|
+
emit({ hook_event_name: "SessionStart" });
|
|
262
|
+
});
|
|
263
|
+
pi.on("input", async (event) => {
|
|
264
|
+
emit({ hook_event_name: "UserPromptSubmit", prompt: event.text });
|
|
265
|
+
});
|
|
266
|
+
pi.on("turn_start", async (event) => {
|
|
267
|
+
emit({
|
|
268
|
+
hook_event_name: "TurnStart",
|
|
269
|
+
turn_index: event.turnIndex,
|
|
270
|
+
pi_timestamp: event.timestamp
|
|
271
|
+
});
|
|
272
|
+
});
|
|
273
|
+
pi.on("turn_end", async (event) => {
|
|
274
|
+
emit({
|
|
275
|
+
hook_event_name: "Stop",
|
|
276
|
+
turn_index: event.turnIndex,
|
|
277
|
+
assistant_message: event.message
|
|
278
|
+
});
|
|
279
|
+
});
|
|
280
|
+
pi.on("tool_call", async (event) => {
|
|
281
|
+
emit({
|
|
282
|
+
hook_event_name: "PreToolUse",
|
|
283
|
+
tool_name: event.toolName,
|
|
284
|
+
tool_call_id: event.toolCallId,
|
|
285
|
+
tool_input: event.input
|
|
286
|
+
});
|
|
287
|
+
});
|
|
288
|
+
pi.on("tool_result", async (event) => {
|
|
289
|
+
emit({
|
|
290
|
+
hook_event_name: event.isError ? "PostToolUseFailure" : "PostToolUse",
|
|
291
|
+
tool_name: event.toolName,
|
|
292
|
+
tool_call_id: event.toolCallId,
|
|
293
|
+
tool_input: event.input,
|
|
294
|
+
tool_result: { content: event.content, details: event.details }
|
|
295
|
+
});
|
|
296
|
+
});
|
|
297
|
+
pi.on("session_before_compact", async (event) => {
|
|
298
|
+
emit({
|
|
299
|
+
hook_event_name: "PreCompact",
|
|
300
|
+
branch_entry_count: event.branchEntries.length,
|
|
301
|
+
custom_instructions: event.customInstructions
|
|
302
|
+
});
|
|
303
|
+
});
|
|
304
|
+
pi.on("session_compact", async (event) => {
|
|
305
|
+
emit({
|
|
306
|
+
hook_event_name: "PostCompact",
|
|
307
|
+
compaction_entry: event.compactionEntry,
|
|
308
|
+
from_extension: event.fromExtension
|
|
309
|
+
});
|
|
310
|
+
});
|
|
311
|
+
pi.on("model_select", async (event) => {
|
|
312
|
+
emit({
|
|
313
|
+
hook_event_name: "ConfigChange",
|
|
314
|
+
config_key: "model",
|
|
315
|
+
config_source: event.source,
|
|
316
|
+
previous_value: modelLabel(event.previousModel),
|
|
317
|
+
new_value: modelLabel(event.model)
|
|
318
|
+
});
|
|
319
|
+
});
|
|
320
|
+
pi.on("thinking_level_select", async (event) => {
|
|
321
|
+
emit({
|
|
322
|
+
hook_event_name: "ConfigChange",
|
|
323
|
+
config_key: "thinking_level",
|
|
324
|
+
previous_value: event.previousLevel,
|
|
325
|
+
new_value: event.level
|
|
326
|
+
});
|
|
327
|
+
});
|
|
328
|
+
pi.on("user_bash", async (event) => {
|
|
329
|
+
emit({
|
|
330
|
+
hook_event_name: "Notification",
|
|
331
|
+
notification_type: "user_bash",
|
|
332
|
+
command: event.command,
|
|
333
|
+
exclude_from_context: event.excludeFromContext,
|
|
334
|
+
event_cwd: event.cwd
|
|
335
|
+
});
|
|
336
|
+
});
|
|
337
|
+
pi.on("session_shutdown", async () => {
|
|
338
|
+
emit({ hook_event_name: "SessionEnd" });
|
|
339
|
+
await flushPendingPosts();
|
|
340
|
+
});
|
|
341
|
+
}
|
|
342
|
+
var __fmlPiExtensionTest = {
|
|
343
|
+
flushPendingPosts,
|
|
344
|
+
pendingPostCount: () => pendingPosts.size
|
|
345
|
+
};
|
|
346
|
+
export {
|
|
347
|
+
FML_PI_EXTENSION_MARKER,
|
|
348
|
+
__fmlPiExtensionTest,
|
|
349
|
+
fmlPiExtension as default
|
|
350
|
+
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@fml-inc/fml",
|
|
3
|
-
"version": "0.8.0
|
|
3
|
+
"version": "0.8.0",
|
|
4
4
|
"description": "FML CLI and agent tools",
|
|
5
5
|
"license": "SEE LICENSE IN LICENSE",
|
|
6
6
|
"type": "module",
|
|
@@ -37,15 +37,17 @@
|
|
|
37
37
|
"zod": "4.1.12"
|
|
38
38
|
},
|
|
39
39
|
"devDependencies": {
|
|
40
|
+
"@earendil-works/pi-coding-agent": "^0.83.0",
|
|
40
41
|
"@sentry/core": "^10.43.0",
|
|
41
42
|
"@types/node": "^22.0.0",
|
|
43
|
+
"esbuild": "^0.27.1",
|
|
42
44
|
"tsup": "^8.0.0",
|
|
43
45
|
"typescript": "^5",
|
|
44
46
|
"@fml/agent-targets": "0.0.0",
|
|
45
47
|
"@fml/panopticon": "0.0.0"
|
|
46
48
|
},
|
|
47
49
|
"scripts": {
|
|
48
|
-
"build": "node scripts/generate-plugin-manifest.js && tsup",
|
|
50
|
+
"build": "node scripts/generate-plugin-manifest.js && tsup && node scripts/build-pi-extension.mjs",
|
|
49
51
|
"dev": "tsup --watch",
|
|
50
52
|
"pack:local": "pnpm pack",
|
|
51
53
|
"type-check": "tsc --noEmit",
|