@tessar/plugins 0.0.0-stage → 0.1.0-alpha.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 +35 -2
- package/dist/index.d.ts +34 -0
- package/dist/index.js +308 -0
- package/dist/index.js.map +1 -0
- package/dist/logger.d.ts +19 -0
- package/dist/logger.js +55 -0
- package/dist/logger.js.map +1 -0
- package/package.json +43 -3
package/README.md
CHANGED
|
@@ -1,3 +1,36 @@
|
|
|
1
|
-
#
|
|
1
|
+
# @tessar/plugins
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Optional Node host utilities for loading plugins after an application is packaged,
|
|
4
|
+
managing npm plugin packages, and structured logging. Requires Node 24.14 or newer.
|
|
5
|
+
|
|
6
|
+
```sh
|
|
7
|
+
npm install @tessar/core@next @tessar/plugins@next
|
|
8
|
+
```
|
|
9
|
+
|
|
10
|
+
```ts
|
|
11
|
+
import { PluginManager } from "@tessar/plugins";
|
|
12
|
+
import { LoggerPlugin } from "@tessar/plugins/logger";
|
|
13
|
+
|
|
14
|
+
const manager = new PluginManager({
|
|
15
|
+
directory: ".my-cli",
|
|
16
|
+
hostUrl: import.meta.url,
|
|
17
|
+
});
|
|
18
|
+
const plugins = [new LoggerPlugin(), ...await manager.load()];
|
|
19
|
+
// Pass plugins to new Controller({ id, agent, plugins }).
|
|
20
|
+
// Dispose Controller first, then call manager.dispose() in finally.
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
Custom files under `plugins/`, or folders with an index entry, default-export a
|
|
24
|
+
plugin instance. The manager supplies the host's public `@tessar/core` imports.
|
|
25
|
+
Erasable TypeScript custom files are supported; npm packages publish JavaScript.
|
|
26
|
+
|
|
27
|
+
`install(source)`, `update(name?)` and `remove(name)` use npm in the managed `npm/`
|
|
28
|
+
subdirectory. Installed package names are recorded in `plugins.json` under
|
|
29
|
+
`packages`; custom files are discovered automatically. `load()` never installs
|
|
30
|
+
missing dependencies. A consuming CLI chooses its own command name and directory.
|
|
31
|
+
|
|
32
|
+
Logger writes JSON lifecycle/error entries to stderr by default. Use
|
|
33
|
+
`new LoggerPlugin({ write: entry => yourLogger.write(entry) })` for another sink.
|
|
34
|
+
|
|
35
|
+
This is an alpha release. See the
|
|
36
|
+
[repository](https://github.com/hphucdev-04/tessar) for usage and contracts.
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import type { Plugin } from "@tessar/core";
|
|
2
|
+
export interface PluginManagerOptions {
|
|
3
|
+
directory: string;
|
|
4
|
+
/** A host module URL from which public SDK imports resolve. */
|
|
5
|
+
hostUrl?: string;
|
|
6
|
+
}
|
|
7
|
+
/** Opt-in Node host utilities; PluginHost still owns setup and resource cleanup. */
|
|
8
|
+
export declare class PluginManager {
|
|
9
|
+
readonly directory: string;
|
|
10
|
+
private readonly npmDirectory;
|
|
11
|
+
private readonly hostUrl;
|
|
12
|
+
private readonly prefix;
|
|
13
|
+
private readonly graph;
|
|
14
|
+
private resolver?;
|
|
15
|
+
private disposed;
|
|
16
|
+
private mutation;
|
|
17
|
+
constructor(options: PluginManagerOptions);
|
|
18
|
+
private check;
|
|
19
|
+
private readJson;
|
|
20
|
+
private manifest;
|
|
21
|
+
private configuration;
|
|
22
|
+
discover(): Promise<string[]>;
|
|
23
|
+
private registerResolver;
|
|
24
|
+
load(sources?: readonly string[]): Promise<Plugin[]>;
|
|
25
|
+
private mutate;
|
|
26
|
+
private saveConfiguration;
|
|
27
|
+
private npm;
|
|
28
|
+
install(source: string, options?: {
|
|
29
|
+
name?: string;
|
|
30
|
+
}): Promise<string>;
|
|
31
|
+
update(name?: string): Promise<void>;
|
|
32
|
+
remove(name: string): Promise<void>;
|
|
33
|
+
dispose(): void;
|
|
34
|
+
}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,308 @@
|
|
|
1
|
+
import { readFile, readdir, mkdir, writeFile, stat } from "node:fs/promises";
|
|
2
|
+
import { existsSync } from "node:fs";
|
|
3
|
+
import { createRequire, registerHooks } from "node:module";
|
|
4
|
+
import { isAbsolute, join, resolve, dirname, delimiter } from "node:path";
|
|
5
|
+
import { pathToFileURL } from "node:url";
|
|
6
|
+
import { randomUUID } from "node:crypto";
|
|
7
|
+
import { execFile } from "node:child_process";
|
|
8
|
+
import { promisify } from "node:util";
|
|
9
|
+
const extensions = [".mjs", ".js", ".cjs", ".mts", ".ts", ".cts"];
|
|
10
|
+
const isEntry = (name) => extensions.some((ext) => name.endsWith(ext)) &&
|
|
11
|
+
!/\.d\.(?:ts|mts|cts)$/.test(name);
|
|
12
|
+
const missing = (error) => error.code === "ENOENT";
|
|
13
|
+
const execute = promisify(execFile);
|
|
14
|
+
const packageName = /^(@[a-z0-9._-]+\/[a-z0-9._-]+|[a-z0-9][a-z0-9._-]*)(?:@.+)?$/i;
|
|
15
|
+
function validName(name) {
|
|
16
|
+
if (packageName.exec(name)?.[1] !== name)
|
|
17
|
+
throw Error("Invalid plugin package name: " + name);
|
|
18
|
+
}
|
|
19
|
+
/** Opt-in Node host utilities; PluginHost still owns setup and resource cleanup. */
|
|
20
|
+
export class PluginManager {
|
|
21
|
+
directory;
|
|
22
|
+
npmDirectory;
|
|
23
|
+
hostUrl;
|
|
24
|
+
prefix = "tessar-plugin:" + randomUUID() + "/";
|
|
25
|
+
graph = new Set();
|
|
26
|
+
resolver;
|
|
27
|
+
disposed = false;
|
|
28
|
+
mutation = Promise.resolve();
|
|
29
|
+
constructor(options) {
|
|
30
|
+
if (!options.directory.trim())
|
|
31
|
+
throw Error("Plugin directory must be nonempty");
|
|
32
|
+
this.directory = resolve(options.directory);
|
|
33
|
+
this.npmDirectory = join(this.directory, "npm");
|
|
34
|
+
this.hostUrl = options.hostUrl ?? import.meta.url;
|
|
35
|
+
}
|
|
36
|
+
check() {
|
|
37
|
+
if (this.disposed)
|
|
38
|
+
throw Error("PluginManager is disposed");
|
|
39
|
+
}
|
|
40
|
+
async readJson(filename) {
|
|
41
|
+
let data;
|
|
42
|
+
try {
|
|
43
|
+
data = JSON.parse(await readFile(filename, "utf8"));
|
|
44
|
+
}
|
|
45
|
+
catch (error) {
|
|
46
|
+
if (missing(error))
|
|
47
|
+
return {};
|
|
48
|
+
throw new Error("Invalid JSON file " + filename, { cause: error });
|
|
49
|
+
}
|
|
50
|
+
if (!data || typeof data !== "object" || Array.isArray(data))
|
|
51
|
+
throw Error("Expected a JSON object in " + filename);
|
|
52
|
+
return data;
|
|
53
|
+
}
|
|
54
|
+
manifest() {
|
|
55
|
+
return this.readJson(join(this.npmDirectory, "package.json"));
|
|
56
|
+
}
|
|
57
|
+
async configuration() {
|
|
58
|
+
const filename = join(this.directory, "plugins.json");
|
|
59
|
+
const data = await this.readJson(filename);
|
|
60
|
+
if (data.packages !== undefined &&
|
|
61
|
+
(!Array.isArray(data.packages) ||
|
|
62
|
+
data.packages.some(value => typeof value !== "string" || !value.trim())))
|
|
63
|
+
throw Error("Invalid packages in " + filename);
|
|
64
|
+
return data;
|
|
65
|
+
}
|
|
66
|
+
async discover() {
|
|
67
|
+
this.check();
|
|
68
|
+
const directory = join(this.directory, "plugins");
|
|
69
|
+
let entries;
|
|
70
|
+
try {
|
|
71
|
+
entries = await readdir(directory, { withFileTypes: true });
|
|
72
|
+
}
|
|
73
|
+
catch (error) {
|
|
74
|
+
if (!missing(error))
|
|
75
|
+
throw error;
|
|
76
|
+
entries = [];
|
|
77
|
+
}
|
|
78
|
+
const sources = [];
|
|
79
|
+
for (const entry of entries.sort((a, b) => a.name < b.name ? -1 : a.name > b.name ? 1 : 0)) {
|
|
80
|
+
if (entry.isFile() && isEntry(entry.name))
|
|
81
|
+
sources.push(join(directory, entry.name));
|
|
82
|
+
else if (entry.isDirectory()) {
|
|
83
|
+
const files = await readdir(join(directory, entry.name));
|
|
84
|
+
const indexes = extensions
|
|
85
|
+
.map((ext) => "index" + ext)
|
|
86
|
+
.filter((name) => files.includes(name));
|
|
87
|
+
if (indexes.length > 1)
|
|
88
|
+
throw Error("Ambiguous plugin entry: " + join(directory, entry.name));
|
|
89
|
+
if (indexes[0])
|
|
90
|
+
sources.push(join(directory, entry.name, indexes[0]));
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
const config = await this.configuration();
|
|
94
|
+
this.check();
|
|
95
|
+
return [...sources, ...(config.packages ?? [])];
|
|
96
|
+
}
|
|
97
|
+
registerResolver() {
|
|
98
|
+
if (this.resolver)
|
|
99
|
+
return;
|
|
100
|
+
this.resolver = registerHooks({
|
|
101
|
+
resolve: (specifier, context, nextResolve) => {
|
|
102
|
+
const sdkPrefix = this.prefix + "sdk/";
|
|
103
|
+
if (specifier.startsWith(sdkPrefix))
|
|
104
|
+
return nextResolve(decodeURIComponent(specifier.slice(sdkPrefix.length)), { ...context, parentURL: this.hostUrl });
|
|
105
|
+
if (specifier.startsWith(this.prefix)) {
|
|
106
|
+
const source = decodeURIComponent(specifier.slice(this.prefix.length));
|
|
107
|
+
const result = nextResolve(source, {
|
|
108
|
+
...context,
|
|
109
|
+
parentURL: pathToFileURL(join(this.npmDirectory, "package.json")).href,
|
|
110
|
+
});
|
|
111
|
+
this.graph.add(result.url);
|
|
112
|
+
return result;
|
|
113
|
+
}
|
|
114
|
+
if (context.parentURL && this.graph.has(context.parentURL)) {
|
|
115
|
+
if (specifier === "@tessar/core" ||
|
|
116
|
+
specifier.startsWith("@tessar/core/"))
|
|
117
|
+
// Resolve through ESM: require's default resolver retains caller search paths.
|
|
118
|
+
return {
|
|
119
|
+
url: import.meta.resolve(sdkPrefix + encodeURIComponent(specifier)),
|
|
120
|
+
shortCircuit: true,
|
|
121
|
+
};
|
|
122
|
+
try {
|
|
123
|
+
const result = nextResolve(specifier, context);
|
|
124
|
+
this.graph.add(result.url);
|
|
125
|
+
return result;
|
|
126
|
+
}
|
|
127
|
+
catch (error) {
|
|
128
|
+
const code = error.code;
|
|
129
|
+
if ((code !== "ERR_MODULE_NOT_FOUND" && code !== "MODULE_NOT_FOUND") ||
|
|
130
|
+
specifier.startsWith(".") || isAbsolute(specifier) ||
|
|
131
|
+
specifier.includes(":") || specifier.startsWith("#"))
|
|
132
|
+
throw error;
|
|
133
|
+
// Custom files can also use dependencies in the managed npm environment.
|
|
134
|
+
const url = context.conditions.includes("require")
|
|
135
|
+
? pathToFileURL(createRequire(join(this.npmDirectory, "package.json")).resolve(specifier)).href
|
|
136
|
+
: import.meta.resolve(this.prefix + encodeURIComponent(specifier));
|
|
137
|
+
this.graph.add(url);
|
|
138
|
+
return {
|
|
139
|
+
url,
|
|
140
|
+
shortCircuit: true,
|
|
141
|
+
};
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
return nextResolve(specifier, context);
|
|
145
|
+
},
|
|
146
|
+
});
|
|
147
|
+
}
|
|
148
|
+
async load(sources) {
|
|
149
|
+
this.check();
|
|
150
|
+
const entries = sources ?? (await this.discover());
|
|
151
|
+
this.check();
|
|
152
|
+
if (entries.length)
|
|
153
|
+
this.registerResolver();
|
|
154
|
+
const plugins = [], ids = new Set();
|
|
155
|
+
for (const source of entries) {
|
|
156
|
+
try {
|
|
157
|
+
const specifier = isAbsolute(source) || source.startsWith(".")
|
|
158
|
+
? pathToFileURL(resolve(this.directory, source)).href
|
|
159
|
+
: source;
|
|
160
|
+
const module = await import(this.prefix + encodeURIComponent(specifier));
|
|
161
|
+
this.check();
|
|
162
|
+
const plugin = module.default;
|
|
163
|
+
if (!plugin ||
|
|
164
|
+
typeof plugin !== "object" ||
|
|
165
|
+
typeof plugin.id !== "string" ||
|
|
166
|
+
!plugin.id.trim() ||
|
|
167
|
+
typeof plugin.setup !== "function")
|
|
168
|
+
throw Error("Expected a default Plugin export with id and setup(tessar)");
|
|
169
|
+
if (ids.has(plugin.id))
|
|
170
|
+
throw Error("Duplicate plugin ID: " + plugin.id);
|
|
171
|
+
ids.add(plugin.id);
|
|
172
|
+
plugins.push(plugin);
|
|
173
|
+
}
|
|
174
|
+
catch (error) {
|
|
175
|
+
throw new Error("Cannot load plugin " +
|
|
176
|
+
source +
|
|
177
|
+
": " +
|
|
178
|
+
(error instanceof Error ? error.message : String(error)), { cause: error });
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
return plugins;
|
|
182
|
+
}
|
|
183
|
+
mutate(operation) {
|
|
184
|
+
const next = this.mutation.then(() => {
|
|
185
|
+
this.check();
|
|
186
|
+
return operation();
|
|
187
|
+
});
|
|
188
|
+
this.mutation = next.catch(() => { });
|
|
189
|
+
return next;
|
|
190
|
+
}
|
|
191
|
+
async saveConfiguration(config) {
|
|
192
|
+
await writeFile(join(this.directory, "plugins.json"), JSON.stringify(config, null, 2) + "\n");
|
|
193
|
+
}
|
|
194
|
+
async npm(args) {
|
|
195
|
+
const parameters = [
|
|
196
|
+
...args,
|
|
197
|
+
"--prefix",
|
|
198
|
+
this.npmDirectory,
|
|
199
|
+
"--no-audit",
|
|
200
|
+
"--no-fund",
|
|
201
|
+
];
|
|
202
|
+
// Windows .cmd launchers require a shell; invoke npm's JS entry with Node instead.
|
|
203
|
+
if (process.platform === "win32") {
|
|
204
|
+
const directories = [
|
|
205
|
+
dirname(process.execPath),
|
|
206
|
+
...(process.env.PATH ?? "").split(delimiter),
|
|
207
|
+
];
|
|
208
|
+
const cli = directories
|
|
209
|
+
.map((dir) => join(dir, "node_modules/npm/bin/npm-cli.js"))
|
|
210
|
+
.find(existsSync);
|
|
211
|
+
if (!cli)
|
|
212
|
+
throw Error("npm is not installed alongside Node or on PATH");
|
|
213
|
+
return (await execute(process.execPath, [cli, ...parameters], {
|
|
214
|
+
cwd: this.npmDirectory,
|
|
215
|
+
windowsHide: true,
|
|
216
|
+
})).stdout;
|
|
217
|
+
}
|
|
218
|
+
else
|
|
219
|
+
return (await execute("npm", parameters, {
|
|
220
|
+
cwd: this.npmDirectory,
|
|
221
|
+
windowsHide: true,
|
|
222
|
+
})).stdout;
|
|
223
|
+
}
|
|
224
|
+
install(source, options = {}) {
|
|
225
|
+
return this.mutate(async () => {
|
|
226
|
+
if (!source.trim() || source.startsWith("-"))
|
|
227
|
+
throw Error("Invalid plugin source");
|
|
228
|
+
const local = isAbsolute(source) ||
|
|
229
|
+
source.startsWith(".") ||
|
|
230
|
+
source.startsWith("file:");
|
|
231
|
+
const target = local
|
|
232
|
+
? resolve(this.directory, source.replace(/^file:/, ""))
|
|
233
|
+
: source;
|
|
234
|
+
let sourceName = local
|
|
235
|
+
? (await stat(target)).isDirectory()
|
|
236
|
+
? JSON.parse(await readFile(join(target, "package.json"), "utf8")).name
|
|
237
|
+
: undefined
|
|
238
|
+
: packageName.exec(source)?.[1];
|
|
239
|
+
const name = options.name ?? sourceName;
|
|
240
|
+
if (typeof name !== "string")
|
|
241
|
+
throw Error("Provide a package name for Git, tarball or URL sources");
|
|
242
|
+
validName(name);
|
|
243
|
+
const config = await this.configuration();
|
|
244
|
+
await mkdir(this.npmDirectory, { recursive: true });
|
|
245
|
+
if (!existsSync(join(this.npmDirectory, "package.json")))
|
|
246
|
+
await writeFile(join(this.npmDirectory, "package.json"), JSON.stringify({ private: true, type: "module" }, null, 2) + "\n");
|
|
247
|
+
if (!sourceName) {
|
|
248
|
+
const packed = JSON.parse(await this.npm([
|
|
249
|
+
"pack",
|
|
250
|
+
"--dry-run",
|
|
251
|
+
"--ignore-scripts",
|
|
252
|
+
"--json",
|
|
253
|
+
target,
|
|
254
|
+
]));
|
|
255
|
+
sourceName = packed[0]?.name;
|
|
256
|
+
}
|
|
257
|
+
if (sourceName !== name)
|
|
258
|
+
throw Error("Requested name " +
|
|
259
|
+
name +
|
|
260
|
+
" differs from source package " +
|
|
261
|
+
sourceName);
|
|
262
|
+
await this.npm(["install", "--save-exact", "--install-links", target]);
|
|
263
|
+
const manifest = await this.manifest();
|
|
264
|
+
if (!manifest.dependencies?.[name])
|
|
265
|
+
throw Error("Installed source did not provide requested package " + name);
|
|
266
|
+
config.packages = [...new Set([...(config.packages ?? []), name])];
|
|
267
|
+
await this.saveConfiguration(config);
|
|
268
|
+
return name;
|
|
269
|
+
});
|
|
270
|
+
}
|
|
271
|
+
update(name) {
|
|
272
|
+
return this.mutate(async () => {
|
|
273
|
+
const manifest = await this.manifest();
|
|
274
|
+
const config = await this.configuration();
|
|
275
|
+
const names = name
|
|
276
|
+
? [name]
|
|
277
|
+
: (config.packages ?? []).filter((value) => manifest.dependencies?.[value]);
|
|
278
|
+
for (const value of names) {
|
|
279
|
+
validName(value);
|
|
280
|
+
if (!config.packages?.includes(value) ||
|
|
281
|
+
!manifest.dependencies?.[value])
|
|
282
|
+
throw Error("Not an installed plugin: " + value);
|
|
283
|
+
}
|
|
284
|
+
if (names.length)
|
|
285
|
+
await this.npm(["update", ...names]);
|
|
286
|
+
});
|
|
287
|
+
}
|
|
288
|
+
remove(name) {
|
|
289
|
+
return this.mutate(async () => {
|
|
290
|
+
validName(name);
|
|
291
|
+
const before = await this.manifest();
|
|
292
|
+
const config = await this.configuration();
|
|
293
|
+
if (!config.packages?.includes(name) ||
|
|
294
|
+
!before.dependencies?.[name])
|
|
295
|
+
throw Error("Not an installed plugin: " + name);
|
|
296
|
+
await this.npm(["uninstall", name]);
|
|
297
|
+
config.packages = (config.packages ?? []).filter(value => value !== name);
|
|
298
|
+
await this.saveConfiguration(config);
|
|
299
|
+
});
|
|
300
|
+
}
|
|
301
|
+
dispose() {
|
|
302
|
+
this.disposed = true;
|
|
303
|
+
this.resolver?.deregister();
|
|
304
|
+
this.resolver = undefined;
|
|
305
|
+
this.graph.clear();
|
|
306
|
+
}
|
|
307
|
+
}
|
|
308
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
package/dist/logger.d.ts
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { type EventContext, type Plugin, type PluginContext } from "@tessar/core";
|
|
2
|
+
export interface LogEntry extends EventContext {
|
|
3
|
+
level: "info" | "warn" | "error";
|
|
4
|
+
type: string;
|
|
5
|
+
timestamp: string;
|
|
6
|
+
payload: unknown;
|
|
7
|
+
}
|
|
8
|
+
export interface LoggerOptions {
|
|
9
|
+
write?: (entry: LogEntry) => void | Promise<void>;
|
|
10
|
+
}
|
|
11
|
+
/** Structured lifecycle/error logs. Destinations and formatting belong to the host. */
|
|
12
|
+
export declare class LoggerPlugin implements Plugin {
|
|
13
|
+
readonly id = "logger";
|
|
14
|
+
private readonly write;
|
|
15
|
+
constructor(options?: LoggerOptions);
|
|
16
|
+
setup(tessar: PluginContext): void;
|
|
17
|
+
}
|
|
18
|
+
declare const _default: LoggerPlugin;
|
|
19
|
+
export default _default;
|
package/dist/logger.js
ADDED
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import { AgentEvents, SessionEvents, } from "@tessar/core";
|
|
2
|
+
const events = [
|
|
3
|
+
AgentEvents.Ready,
|
|
4
|
+
AgentEvents.ThreadStarted,
|
|
5
|
+
AgentEvents.ThreadShutdown,
|
|
6
|
+
AgentEvents.StreamStarted,
|
|
7
|
+
AgentEvents.StreamEnd,
|
|
8
|
+
AgentEvents.StreamError,
|
|
9
|
+
AgentEvents.StreamSuspended,
|
|
10
|
+
AgentEvents.StreamResumed,
|
|
11
|
+
AgentEvents.StreamCancel,
|
|
12
|
+
AgentEvents.TurnStart,
|
|
13
|
+
AgentEvents.TurnEnd,
|
|
14
|
+
AgentEvents.ModelStart,
|
|
15
|
+
AgentEvents.ModelEnd,
|
|
16
|
+
AgentEvents.ModelError,
|
|
17
|
+
AgentEvents.ToolStart,
|
|
18
|
+
AgentEvents.ToolEnd,
|
|
19
|
+
AgentEvents.ToolError,
|
|
20
|
+
AgentEvents.Diagnostic,
|
|
21
|
+
SessionEvents.Created,
|
|
22
|
+
SessionEvents.ModelChanged,
|
|
23
|
+
SessionEvents.ThreadCreated,
|
|
24
|
+
SessionEvents.ThreadSwitched,
|
|
25
|
+
SessionEvents.ThreadRenamed,
|
|
26
|
+
SessionEvents.ThreadForked,
|
|
27
|
+
SessionEvents.ThreadDeleted,
|
|
28
|
+
SessionEvents.InputQueued,
|
|
29
|
+
SessionEvents.InputDiscarded,
|
|
30
|
+
SessionEvents.Closed,
|
|
31
|
+
];
|
|
32
|
+
/** Structured lifecycle/error logs. Destinations and formatting belong to the host. */
|
|
33
|
+
export class LoggerPlugin {
|
|
34
|
+
id = "logger";
|
|
35
|
+
write;
|
|
36
|
+
constructor(options = {}) {
|
|
37
|
+
this.write = options.write ?? ((entry) => {
|
|
38
|
+
console.error(JSON.stringify(entry));
|
|
39
|
+
});
|
|
40
|
+
}
|
|
41
|
+
setup(tessar) {
|
|
42
|
+
for (const name of events)
|
|
43
|
+
tessar.hook(name, (event) => this.write(Object.freeze({
|
|
44
|
+
...event,
|
|
45
|
+
timestamp: event.timestamp ?? new Date().toISOString(),
|
|
46
|
+
level: "error" in event.payload && event.payload.error
|
|
47
|
+
? "error"
|
|
48
|
+
: event.type === AgentEvents.StreamSuspended
|
|
49
|
+
? "warn"
|
|
50
|
+
: "info",
|
|
51
|
+
})));
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
export default new LoggerPlugin();
|
|
55
|
+
//# sourceMappingURL=logger.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"logger.js","sourceRoot":"","sources":["../src/logger.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,WAAW,EACX,aAAa,GAId,MAAM,cAAc,CAAC;AAUtB,MAAM,MAAM,GAAG;IACb,WAAW,CAAC,KAAK;IACjB,WAAW,CAAC,aAAa;IACzB,WAAW,CAAC,cAAc;IAC1B,WAAW,CAAC,aAAa;IACzB,WAAW,CAAC,SAAS;IACrB,WAAW,CAAC,WAAW;IACvB,WAAW,CAAC,eAAe;IAC3B,WAAW,CAAC,aAAa;IACzB,WAAW,CAAC,YAAY;IACxB,WAAW,CAAC,SAAS;IACrB,WAAW,CAAC,OAAO;IACnB,WAAW,CAAC,UAAU;IACtB,WAAW,CAAC,QAAQ;IACpB,WAAW,CAAC,UAAU;IACtB,WAAW,CAAC,SAAS;IACrB,WAAW,CAAC,OAAO;IACnB,WAAW,CAAC,SAAS;IACrB,WAAW,CAAC,UAAU;IACtB,aAAa,CAAC,OAAO;IACrB,aAAa,CAAC,YAAY;IAC1B,aAAa,CAAC,aAAa;IAC3B,aAAa,CAAC,cAAc;IAC5B,aAAa,CAAC,aAAa;IAC3B,aAAa,CAAC,YAAY;IAC1B,aAAa,CAAC,aAAa;IAC3B,aAAa,CAAC,WAAW;IACzB,aAAa,CAAC,cAAc;IAC5B,aAAa,CAAC,MAAM;CACZ,CAAC;AAEX,uFAAuF;AACvF,MAAM,OAAO,YAAY;IACd,EAAE,GAAG,QAAQ,CAAC;IACN,KAAK,CAAsC;IAE5D,YAAY,OAAO,GAAkB,EAAE;QACrC,IAAI,CAAC,KAAK,GAAG,OAAO,CAAC,KAAK,IAAI,CAAC,CAAC,KAAK,EAAE,EAAE;YACvC,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC,CAAC;QACvC,CAAC,CAAC,CAAC;IACL,CAAC;IAED,KAAK,CAAC,MAAqB;QACzB,KAAK,MAAM,IAAI,IAAI,MAAM;YACvB,MAAM,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC,KAAK,EAAE,EAAE,CAC1B,IAAI,CAAC,KAAK,CACR,MAAM,CAAC,MAAM,CAAC;gBACZ,GAAG,KAAK;gBACR,SAAS,EAAE,KAAK,CAAC,SAAS,IAAI,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;gBACtD,KAAK,EACH,OAAO,IAAI,KAAK,CAAC,OAAO,IAAI,KAAK,CAAC,OAAO,CAAC,KAAK;oBAC7C,CAAC,CAAC,OAAO;oBACT,CAAC,CAAC,KAAK,CAAC,IAAI,KAAK,WAAW,CAAC,eAAe;wBAC1C,CAAC,CAAC,MAAM;wBACR,CAAC,CAAC,MAAM;aACf,CAAC,CACH,CACF,CAAC;IACN,CAAC;CACF;AAED,eAAe,IAAI,YAAY,EAAE,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,46 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tessar/plugins",
|
|
3
|
-
"version": "0.0.0
|
|
4
|
-
"
|
|
5
|
-
"
|
|
3
|
+
"version": "0.1.0-alpha.0",
|
|
4
|
+
"description": "Node plugin loading, npm package management and a built-in logger for Tessar.",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"repository": {
|
|
7
|
+
"type": "git",
|
|
8
|
+
"url": "git+https://github.com/hphucdev-04/tessar.git",
|
|
9
|
+
"directory": "packages/plugins"
|
|
10
|
+
},
|
|
11
|
+
"publishConfig": {
|
|
12
|
+
"access": "public",
|
|
13
|
+
"registry": "https://registry.npmjs.org/"
|
|
14
|
+
},
|
|
15
|
+
"exports": {
|
|
16
|
+
".": {
|
|
17
|
+
"types": "./dist/index.d.ts",
|
|
18
|
+
"import": "./dist/index.js"
|
|
19
|
+
},
|
|
20
|
+
"./logger": {
|
|
21
|
+
"types": "./dist/logger.d.ts",
|
|
22
|
+
"import": "./dist/logger.js"
|
|
23
|
+
}
|
|
24
|
+
},
|
|
25
|
+
"files": [
|
|
26
|
+
"dist"
|
|
27
|
+
],
|
|
28
|
+
"engines": {
|
|
29
|
+
"node": ">=24.14.0"
|
|
30
|
+
},
|
|
31
|
+
"peerDependencies": {
|
|
32
|
+
"@tessar/core": "^0.1.0-alpha.0"
|
|
33
|
+
},
|
|
34
|
+
"peerDependenciesMeta": {
|
|
35
|
+
"@tessar/core": {
|
|
36
|
+
"optional": true
|
|
37
|
+
}
|
|
38
|
+
},
|
|
39
|
+
"devDependencies": {
|
|
40
|
+
"@tessar/core": "0.1.0-alpha.0"
|
|
41
|
+
},
|
|
42
|
+
"scripts": {
|
|
43
|
+
"build": "tsc -p tsconfig.json",
|
|
44
|
+
"typecheck": "tsc --noEmit -p tsconfig.json"
|
|
45
|
+
}
|
|
6
46
|
}
|