neoctl 0.2.29 → 0.2.31
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 +40 -4
- package/dist/context/compaction.d.ts +20 -4
- package/dist/context/compaction.js +377 -186
- package/dist/context/compaction.js.map +1 -1
- package/dist/context/context-manager.d.ts +7 -1
- package/dist/context/context-manager.js +15 -11
- package/dist/context/context-manager.js.map +1 -1
- package/dist/context/prompts.js +2 -0
- package/dist/context/prompts.js.map +1 -1
- package/dist/context/smoke-context.js +266 -17
- package/dist/context/smoke-context.js.map +1 -1
- package/dist/core/assistant-output-filter.d.ts +1 -0
- package/dist/core/assistant-output-filter.js +54 -2
- package/dist/core/assistant-output-filter.js.map +1 -1
- package/dist/core/context-metrics.d.ts +1 -0
- package/dist/core/context-metrics.js +18 -12
- package/dist/core/context-metrics.js.map +1 -1
- package/dist/core/image-registry.d.ts +16 -3
- package/dist/core/image-registry.js +65 -30
- package/dist/core/image-registry.js.map +1 -1
- package/dist/core/image-storage.d.ts +15 -1
- package/dist/core/image-storage.js +140 -17
- package/dist/core/image-storage.js.map +1 -1
- package/dist/core/message-pipeline.js +18 -4
- package/dist/core/message-pipeline.js.map +1 -1
- package/dist/core/query-engine.d.ts +12 -2
- package/dist/core/query-engine.js +57 -8
- package/dist/core/query-engine.js.map +1 -1
- package/dist/core/query.d.ts +13 -2
- package/dist/core/query.js +56 -21
- package/dist/core/query.js.map +1 -1
- package/dist/core/smoke-core-loop.js +68 -3
- package/dist/core/smoke-core-loop.js.map +1 -1
- package/dist/core/smoke-image-integrity.d.ts +1 -0
- package/dist/core/smoke-image-integrity.js +67 -0
- package/dist/core/smoke-image-integrity.js.map +1 -0
- package/dist/core/state.d.ts +1 -1
- package/dist/core/state.js.map +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.js +1 -0
- package/dist/index.js.map +1 -1
- package/dist/model/model-metadata.json +4 -4
- package/dist/plugins/plugin-system.d.ts +61 -0
- package/dist/plugins/plugin-system.js +189 -0
- package/dist/plugins/plugin-system.js.map +1 -0
- package/dist/plugins/smoke-plugin-system.d.ts +1 -0
- package/dist/plugins/smoke-plugin-system.js +63 -0
- package/dist/plugins/smoke-plugin-system.js.map +1 -0
- package/dist/repl/index.js +8 -3
- package/dist/repl/index.js.map +1 -1
- package/dist/session/session-export.d.ts +2 -0
- package/dist/session/session-export.js +10 -0
- package/dist/session/session-export.js.map +1 -1
- package/dist/session/session-store.d.ts +41 -0
- package/dist/session/session-store.js +292 -59
- package/dist/session/session-store.js.map +1 -1
- package/dist/session/smoke-session.js +127 -7
- package/dist/session/smoke-session.js.map +1 -1
- package/dist/tools/builtins/exec-process-manager.d.ts +16 -2
- package/dist/tools/builtins/exec-process-manager.js +119 -25
- package/dist/tools/builtins/exec-process-manager.js.map +1 -1
- package/dist/tools/builtins/exec-tool.js +11 -2
- package/dist/tools/builtins/exec-tool.js.map +1 -1
- package/dist/tools/builtins/image-generation-tool.js +32 -42
- package/dist/tools/builtins/image-generation-tool.js.map +1 -1
- package/dist/tools/builtins/image-loader-tool.js +10 -4
- package/dist/tools/builtins/image-loader-tool.js.map +1 -1
- package/dist/tools/builtins/image-note-tool.js +8 -3
- package/dist/tools/builtins/image-note-tool.js.map +1 -1
- package/dist/tools/registry.d.ts +8 -1
- package/dist/tools/registry.js +37 -13
- package/dist/tools/registry.js.map +1 -1
- package/dist/tools/smoke-exec-process.js +88 -4
- package/dist/tools/smoke-exec-process.js.map +1 -1
- package/dist/tools/smoke-tool-system.js +24 -6
- package/dist/tools/smoke-tool-system.js.map +1 -1
- package/dist/types/events.d.ts +5 -1
- package/dist/types/messages.d.ts +13 -5
- package/dist/types/messages.js +4 -0
- package/dist/types/messages.js.map +1 -1
- package/dist/ui/display-message.d.ts +10 -2
- package/dist/ui/display-message.js +18 -9
- package/dist/ui/display-message.js.map +1 -1
- package/dist/web/index.d.ts +176 -11
- package/dist/web/index.js +986 -106
- package/dist/web/index.js.map +1 -1
- package/dist/web/runtime-context-protocol.d.ts +12 -1
- package/dist/web/runtime-context-protocol.js +16 -1
- package/dist/web/runtime-context-protocol.js.map +1 -1
- package/dist/web/smoke-runtime-context-protocol.js +3 -0
- package/dist/web/smoke-runtime-context-protocol.js.map +1 -1
- package/dist/web/smoke-web-history.d.ts +1 -0
- package/dist/web/smoke-web-history.js +121 -0
- package/dist/web/smoke-web-history.js.map +1 -0
- package/dist/web/smoke-web-terminal-tasks.d.ts +1 -0
- package/dist/web/smoke-web-terminal-tasks.js +90 -0
- package/dist/web/smoke-web-terminal-tasks.js.map +1 -0
- package/package.json +5 -1
|
@@ -0,0 +1,189 @@
|
|
|
1
|
+
import { readdir, readFile } from "node:fs/promises";
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
import { pathToFileURL } from "node:url";
|
|
4
|
+
export const NEO_PLUGIN_PROTOCOL = "neo-plugin/v1";
|
|
5
|
+
export const NEO_PLUGIN_MANIFEST = "neo-plugin.json";
|
|
6
|
+
export async function loadNeoPlugins(options) {
|
|
7
|
+
const roots = normalizeRoots(options.directories);
|
|
8
|
+
const plugins = [];
|
|
9
|
+
for (const root of roots)
|
|
10
|
+
plugins.push(...await loadPluginRoot(root, options));
|
|
11
|
+
plugins.sort((left, right) => left.id.localeCompare(right.id));
|
|
12
|
+
assertUnique(plugins.map((plugin) => plugin.id), "duplicate plugin id");
|
|
13
|
+
assertUnique(plugins.flatMap((plugin) => plugin.tools ?? []).map((tool) => tool.name), "duplicate tool name across plugins");
|
|
14
|
+
return plugins;
|
|
15
|
+
}
|
|
16
|
+
export function validateNeoPluginManifest(value, manifestPath = NEO_PLUGIN_MANIFEST) {
|
|
17
|
+
if (!isRecord(value))
|
|
18
|
+
throw new Error(`invalid plugin manifest ${manifestPath}: expected an object`);
|
|
19
|
+
if (value.protocol !== NEO_PLUGIN_PROTOCOL) {
|
|
20
|
+
throw new Error(`invalid plugin manifest ${manifestPath}: protocol must be ${NEO_PLUGIN_PROTOCOL}`);
|
|
21
|
+
}
|
|
22
|
+
const id = requireText(value.id, "id", manifestPath);
|
|
23
|
+
if (!/^[a-z0-9][a-z0-9._-]*$/u.test(id)) {
|
|
24
|
+
throw new Error(`invalid plugin manifest ${manifestPath}: invalid id ${id}`);
|
|
25
|
+
}
|
|
26
|
+
const entry = requireText(value.entry, "entry", manifestPath);
|
|
27
|
+
if (path.isAbsolute(entry))
|
|
28
|
+
throw new Error(`invalid plugin manifest ${manifestPath}: entry must be relative`);
|
|
29
|
+
return {
|
|
30
|
+
protocol: NEO_PLUGIN_PROTOCOL,
|
|
31
|
+
id,
|
|
32
|
+
name: requireText(value.name, "name", manifestPath),
|
|
33
|
+
version: requireText(value.version, "version", manifestPath),
|
|
34
|
+
entry,
|
|
35
|
+
...(typeof value.defaultEnabled === "boolean" ? { defaultEnabled: value.defaultEnabled } : {}),
|
|
36
|
+
...(typeof value.description === "string" && value.description.trim() ? { description: value.description.trim() } : {}),
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
async function loadPluginRoot(root, options) {
|
|
40
|
+
let entries;
|
|
41
|
+
try {
|
|
42
|
+
entries = await readdir(root, { withFileTypes: true });
|
|
43
|
+
}
|
|
44
|
+
catch (error) {
|
|
45
|
+
if (isNodeError(error) && error.code === "ENOENT")
|
|
46
|
+
return [];
|
|
47
|
+
throw error;
|
|
48
|
+
}
|
|
49
|
+
const directories = entries.filter((entry) => entry.isDirectory()).sort((left, right) => left.name.localeCompare(right.name));
|
|
50
|
+
const plugins = [];
|
|
51
|
+
for (const entry of directories) {
|
|
52
|
+
const pluginDir = path.resolve(root, entry.name);
|
|
53
|
+
const manifestPath = path.join(pluginDir, NEO_PLUGIN_MANIFEST);
|
|
54
|
+
let rawManifest;
|
|
55
|
+
try {
|
|
56
|
+
rawManifest = await readFile(manifestPath, "utf8");
|
|
57
|
+
}
|
|
58
|
+
catch (error) {
|
|
59
|
+
if (isNodeError(error) && error.code === "ENOENT")
|
|
60
|
+
continue;
|
|
61
|
+
throw error;
|
|
62
|
+
}
|
|
63
|
+
let parsedManifest;
|
|
64
|
+
try {
|
|
65
|
+
parsedManifest = JSON.parse(rawManifest);
|
|
66
|
+
}
|
|
67
|
+
catch (error) {
|
|
68
|
+
throw new Error(`invalid plugin manifest ${manifestPath}: ${error instanceof Error ? error.message : String(error)}`, { cause: error });
|
|
69
|
+
}
|
|
70
|
+
const manifest = validateNeoPluginManifest(parsedManifest, manifestPath);
|
|
71
|
+
const entryPath = resolveContainedEntry(pluginDir, manifest.entry, manifestPath);
|
|
72
|
+
const module = await import(pathToFileURL(entryPath).href);
|
|
73
|
+
const factory = module.createPlugin ?? module.default;
|
|
74
|
+
if (typeof factory !== "function") {
|
|
75
|
+
throw new Error(`invalid plugin module ${entryPath}: export createPlugin(context) or a default factory`);
|
|
76
|
+
}
|
|
77
|
+
const context = Object.freeze({
|
|
78
|
+
manifest: Object.freeze({ ...manifest }),
|
|
79
|
+
pluginDir,
|
|
80
|
+
...(options.appDataDir ? { appDataDir: path.resolve(options.appDataDir) } : {}),
|
|
81
|
+
env: Object.freeze({ ...(options.env ?? process.env) }),
|
|
82
|
+
});
|
|
83
|
+
const capabilities = normalizeCapabilities(await factory(context), entryPath);
|
|
84
|
+
plugins.push({
|
|
85
|
+
id: manifest.id,
|
|
86
|
+
name: manifest.name,
|
|
87
|
+
version: manifest.version,
|
|
88
|
+
description: manifest.description,
|
|
89
|
+
defaultEnabled: manifest.defaultEnabled !== false,
|
|
90
|
+
sourceDir: pluginDir,
|
|
91
|
+
manifestPath,
|
|
92
|
+
...capabilities,
|
|
93
|
+
});
|
|
94
|
+
}
|
|
95
|
+
return plugins;
|
|
96
|
+
}
|
|
97
|
+
function normalizeCapabilities(value, entryPath) {
|
|
98
|
+
if (!isRecord(value))
|
|
99
|
+
throw new Error(`invalid plugin module ${entryPath}: factory must return an object`);
|
|
100
|
+
const tools = value.tools === undefined ? [] : requireArray(value.tools, "tools", entryPath);
|
|
101
|
+
const promptSections = value.promptSections === undefined ? [] : requireArray(value.promptSections, "promptSections", entryPath);
|
|
102
|
+
for (const [index, tool] of tools.entries())
|
|
103
|
+
validateTool(tool, index, entryPath);
|
|
104
|
+
for (const [index, section] of promptSections.entries())
|
|
105
|
+
validatePromptSection(section, index, entryPath);
|
|
106
|
+
if (value.route !== undefined && typeof value.route !== "function") {
|
|
107
|
+
throw new Error(`invalid plugin module ${entryPath}: route must be a function`);
|
|
108
|
+
}
|
|
109
|
+
if (value.presentToolResult !== undefined && typeof value.presentToolResult !== "function") {
|
|
110
|
+
throw new Error(`invalid plugin module ${entryPath}: presentToolResult must be a function`);
|
|
111
|
+
}
|
|
112
|
+
const normalizedTools = tools;
|
|
113
|
+
const normalizedSections = promptSections;
|
|
114
|
+
assertUnique(normalizedTools.map((tool) => tool.name), `duplicate tool name in plugin module ${entryPath}`);
|
|
115
|
+
return {
|
|
116
|
+
tools: [...normalizedTools],
|
|
117
|
+
promptSections: normalizedSections.map((section) => ({ ...section })),
|
|
118
|
+
...(typeof value.presentToolResult === "function" ? { presentToolResult: value.presentToolResult } : {}),
|
|
119
|
+
...(typeof value.route === "function" ? { route: value.route } : {}),
|
|
120
|
+
};
|
|
121
|
+
}
|
|
122
|
+
function validateTool(value, index, entryPath) {
|
|
123
|
+
if (!isRecord(value))
|
|
124
|
+
throw new Error(`invalid plugin module ${entryPath}: tools[${index}] must be an object`);
|
|
125
|
+
if (!requireOptionalText(value.name))
|
|
126
|
+
throw new Error(`invalid plugin module ${entryPath}: tools[${index}].name is required`);
|
|
127
|
+
if (!(typeof value.description === "string" || typeof value.description === "function")) {
|
|
128
|
+
throw new Error(`invalid plugin module ${entryPath}: tools[${index}].description is required`);
|
|
129
|
+
}
|
|
130
|
+
if (!isRecord(value.inputSchema))
|
|
131
|
+
throw new Error(`invalid plugin module ${entryPath}: tools[${index}].inputSchema is required`);
|
|
132
|
+
if (!isRecord(value.metadata))
|
|
133
|
+
throw new Error(`invalid plugin module ${entryPath}: tools[${index}].metadata is required`);
|
|
134
|
+
if (typeof value.execute !== "function" && typeof value.call !== "function") {
|
|
135
|
+
throw new Error(`invalid plugin module ${entryPath}: tools[${index}] must implement execute or call`);
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
function validatePromptSection(value, index, entryPath) {
|
|
139
|
+
if (!isRecord(value) || !requireOptionalText(value.name) || typeof value.content !== "string") {
|
|
140
|
+
throw new Error(`invalid plugin module ${entryPath}: promptSections[${index}] must contain name and content`);
|
|
141
|
+
}
|
|
142
|
+
if (value.cacheStable !== undefined && typeof value.cacheStable !== "boolean") {
|
|
143
|
+
throw new Error(`invalid plugin module ${entryPath}: promptSections[${index}].cacheStable must be boolean`);
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
function resolveContainedEntry(pluginDir, entry, manifestPath) {
|
|
147
|
+
const resolved = path.resolve(pluginDir, entry);
|
|
148
|
+
const relative = path.relative(pluginDir, resolved);
|
|
149
|
+
if (!relative || relative === ".." || relative.startsWith(`..${path.sep}`) || path.isAbsolute(relative)) {
|
|
150
|
+
throw new Error(`invalid plugin manifest ${manifestPath}: entry must resolve inside the plugin directory`);
|
|
151
|
+
}
|
|
152
|
+
return resolved;
|
|
153
|
+
}
|
|
154
|
+
function normalizeRoots(value) {
|
|
155
|
+
const roots = (Array.isArray(value) ? value : [value])
|
|
156
|
+
.map((root) => String(root || "").trim())
|
|
157
|
+
.filter(Boolean)
|
|
158
|
+
.map((root) => path.resolve(root));
|
|
159
|
+
return [...new Set(roots)];
|
|
160
|
+
}
|
|
161
|
+
function requireText(value, field, manifestPath) {
|
|
162
|
+
const text = typeof value === "string" ? value.trim() : "";
|
|
163
|
+
if (!text)
|
|
164
|
+
throw new Error(`invalid plugin manifest ${manifestPath}: ${field} is required`);
|
|
165
|
+
return text;
|
|
166
|
+
}
|
|
167
|
+
function requireArray(value, field, entryPath) {
|
|
168
|
+
if (!Array.isArray(value))
|
|
169
|
+
throw new Error(`invalid plugin module ${entryPath}: ${field} must be an array`);
|
|
170
|
+
return value;
|
|
171
|
+
}
|
|
172
|
+
function requireOptionalText(value) {
|
|
173
|
+
return typeof value === "string" && Boolean(value.trim());
|
|
174
|
+
}
|
|
175
|
+
function assertUnique(values, message) {
|
|
176
|
+
const seen = new Set();
|
|
177
|
+
for (const value of values) {
|
|
178
|
+
if (seen.has(value))
|
|
179
|
+
throw new Error(`${message}: ${value}`);
|
|
180
|
+
seen.add(value);
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
function isRecord(value) {
|
|
184
|
+
return Boolean(value) && typeof value === "object" && !Array.isArray(value);
|
|
185
|
+
}
|
|
186
|
+
function isNodeError(error) {
|
|
187
|
+
return error instanceof Error && "code" in error;
|
|
188
|
+
}
|
|
189
|
+
//# sourceMappingURL=plugin-system.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"plugin-system.js","sourceRoot":"","sources":["../../src/plugins/plugin-system.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AACrD,OAAO,IAAI,MAAM,WAAW,CAAC;AAE7B,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AAIzC,MAAM,CAAC,MAAM,mBAAmB,GAAG,eAAe,CAAC;AACnD,MAAM,CAAC,MAAM,mBAAmB,GAAG,iBAAiB,CAAC;AAwErD,MAAM,CAAC,KAAK,UAAU,cAAc,CAAC,OAA8B;IACjE,MAAM,KAAK,GAAG,cAAc,CAAC,OAAO,CAAC,WAAW,CAAC,CAAC;IAClD,MAAM,OAAO,GAAwB,EAAE,CAAC;IACxC,KAAK,MAAM,IAAI,IAAI,KAAK;QAAE,OAAO,CAAC,IAAI,CAAC,GAAG,MAAM,cAAc,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC,CAAC;IAC/E,OAAO,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,KAAK,EAAE,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC,aAAa,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC,CAAC;IAC/D,YAAY,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,MAAM,CAAC,EAAE,CAAC,EAAE,qBAAqB,CAAC,CAAC;IACxE,YAAY,CACV,OAAO,CAAC,OAAO,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,MAAM,CAAC,KAAK,IAAI,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,EACxE,oCAAoC,CACrC,CAAC;IACF,OAAO,OAAO,CAAC;AACjB,CAAC;AAED,MAAM,UAAU,yBAAyB,CAAC,KAAc,EAAE,YAAY,GAAG,mBAAmB;IAC1F,IAAI,CAAC,QAAQ,CAAC,KAAK,CAAC;QAAE,MAAM,IAAI,KAAK,CAAC,2BAA2B,YAAY,sBAAsB,CAAC,CAAC;IACrG,IAAI,KAAK,CAAC,QAAQ,KAAK,mBAAmB,EAAE,CAAC;QAC3C,MAAM,IAAI,KAAK,CAAC,2BAA2B,YAAY,sBAAsB,mBAAmB,EAAE,CAAC,CAAC;IACtG,CAAC;IACD,MAAM,EAAE,GAAG,WAAW,CAAC,KAAK,CAAC,EAAE,EAAE,IAAI,EAAE,YAAY,CAAC,CAAC;IACrD,IAAI,CAAC,yBAAyB,CAAC,IAAI,CAAC,EAAE,CAAC,EAAE,CAAC;QACxC,MAAM,IAAI,KAAK,CAAC,2BAA2B,YAAY,gBAAgB,EAAE,EAAE,CAAC,CAAC;IAC/E,CAAC;IACD,MAAM,KAAK,GAAG,WAAW,CAAC,KAAK,CAAC,KAAK,EAAE,OAAO,EAAE,YAAY,CAAC,CAAC;IAC9D,IAAI,IAAI,CAAC,UAAU,CAAC,KAAK,CAAC;QAAE,MAAM,IAAI,KAAK,CAAC,2BAA2B,YAAY,0BAA0B,CAAC,CAAC;IAC/G,OAAO;QACL,QAAQ,EAAE,mBAAmB;QAC7B,EAAE;QACF,IAAI,EAAE,WAAW,CAAC,KAAK,CAAC,IAAI,EAAE,MAAM,EAAE,YAAY,CAAC;QACnD,OAAO,EAAE,WAAW,CAAC,KAAK,CAAC,OAAO,EAAE,SAAS,EAAE,YAAY,CAAC;QAC5D,KAAK;QACL,GAAG,CAAC,OAAO,KAAK,CAAC,cAAc,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,cAAc,EAAE,KAAK,CAAC,cAAc,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QAC9F,GAAG,CAAC,OAAO,KAAK,CAAC,WAAW,KAAK,QAAQ,IAAI,KAAK,CAAC,WAAW,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,WAAW,EAAE,KAAK,CAAC,WAAW,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;KACxH,CAAC;AACJ,CAAC;AAED,KAAK,UAAU,cAAc,CAAC,IAAY,EAAE,OAA8B;IACxE,IAAI,OAAO,CAAC;IACZ,IAAI,CAAC;QACH,OAAO,GAAG,MAAM,OAAO,CAAC,IAAI,EAAE,EAAE,aAAa,EAAE,IAAI,EAAE,CAAC,CAAC;IACzD,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,IAAI,WAAW,CAAC,KAAK,CAAC,IAAI,KAAK,CAAC,IAAI,KAAK,QAAQ;YAAE,OAAO,EAAE,CAAC;QAC7D,MAAM,KAAK,CAAC;IACd,CAAC;IACD,MAAM,WAAW,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,WAAW,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,KAAK,EAAE,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,aAAa,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC;IAC9H,MAAM,OAAO,GAAwB,EAAE,CAAC;IACxC,KAAK,MAAM,KAAK,IAAI,WAAW,EAAE,CAAC;QAChC,MAAM,SAAS,GAAG,IAAI,CAAC,OAAO,CAAC,IAAI,EAAE,KAAK,CAAC,IAAI,CAAC,CAAC;QACjD,MAAM,YAAY,GAAG,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,mBAAmB,CAAC,CAAC;QAC/D,IAAI,WAAmB,CAAC;QACxB,IAAI,CAAC;YACH,WAAW,GAAG,MAAM,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC,CAAC;QACrD,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,IAAI,WAAW,CAAC,KAAK,CAAC,IAAI,KAAK,CAAC,IAAI,KAAK,QAAQ;gBAAE,SAAS;YAC5D,MAAM,KAAK,CAAC;QACd,CAAC;QACD,IAAI,cAAuB,CAAC;QAC5B,IAAI,CAAC;YACH,cAAc,GAAG,IAAI,CAAC,KAAK,CAAC,WAAW,CAAC,CAAC;QAC3C,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,MAAM,IAAI,KAAK,CAAC,2BAA2B,YAAY,KAAK,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,CAAC,CAAC;QAC1I,CAAC;QACD,MAAM,QAAQ,GAAG,yBAAyB,CAAC,cAAc,EAAE,YAAY,CAAC,CAAC;QACzE,MAAM,SAAS,GAAG,qBAAqB,CAAC,SAAS,EAAE,QAAQ,CAAC,KAAK,EAAE,YAAY,CAAC,CAAC;QACjF,MAAM,MAAM,GAAG,MAAM,MAAM,CAAC,aAAa,CAAC,SAAS,CAAC,CAAC,IAAI,CAAC,CAAC;QAC3D,MAAM,OAAO,GAAG,MAAM,CAAC,YAAY,IAAI,MAAM,CAAC,OAAO,CAAC;QACtD,IAAI,OAAO,OAAO,KAAK,UAAU,EAAE,CAAC;YAClC,MAAM,IAAI,KAAK,CAAC,yBAAyB,SAAS,qDAAqD,CAAC,CAAC;QAC3G,CAAC;QACD,MAAM,OAAO,GAA4B,MAAM,CAAC,MAAM,CAAC;YACrD,QAAQ,EAAE,MAAM,CAAC,MAAM,CAAC,EAAE,GAAG,QAAQ,EAAE,CAAC;YACxC,SAAS;YACT,GAAG,CAAC,OAAO,CAAC,UAAU,CAAC,CAAC,CAAC,EAAE,UAAU,EAAE,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,UAAU,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;YAC/E,GAAG,EAAE,MAAM,CAAC,MAAM,CAAC,EAAE,GAAG,CAAC,OAAO,CAAC,GAAG,IAAI,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC;SACxD,CAAC,CAAC;QACH,MAAM,YAAY,GAAG,qBAAqB,CAAC,MAAO,OAA4B,CAAC,OAAO,CAAC,EAAE,SAAS,CAAC,CAAC;QACpG,OAAO,CAAC,IAAI,CAAC;YACX,EAAE,EAAE,QAAQ,CAAC,EAAE;YACf,IAAI,EAAE,QAAQ,CAAC,IAAI;YACnB,OAAO,EAAE,QAAQ,CAAC,OAAO;YACzB,WAAW,EAAE,QAAQ,CAAC,WAAW;YACjC,cAAc,EAAE,QAAQ,CAAC,cAAc,KAAK,KAAK;YACjD,SAAS,EAAE,SAAS;YACpB,YAAY;YACZ,GAAG,YAAY;SAChB,CAAC,CAAC;IACL,CAAC;IACD,OAAO,OAAO,CAAC;AACjB,CAAC;AAED,SAAS,qBAAqB,CAAC,KAAc,EAAE,SAAiB;IAC9D,IAAI,CAAC,QAAQ,CAAC,KAAK,CAAC;QAAE,MAAM,IAAI,KAAK,CAAC,yBAAyB,SAAS,iCAAiC,CAAC,CAAC;IAC3G,MAAM,KAAK,GAAG,KAAK,CAAC,KAAK,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,YAAY,CAAU,KAAK,CAAC,KAAK,EAAE,OAAO,EAAE,SAAS,CAAC,CAAC;IACtG,MAAM,cAAc,GAAG,KAAK,CAAC,cAAc,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,YAAY,CAAU,KAAK,CAAC,cAAc,EAAE,gBAAgB,EAAE,SAAS,CAAC,CAAC;IAC1I,KAAK,MAAM,CAAC,KAAK,EAAE,IAAI,CAAC,IAAI,KAAK,CAAC,OAAO,EAAE;QAAE,YAAY,CAAC,IAAI,EAAE,KAAK,EAAE,SAAS,CAAC,CAAC;IAClF,KAAK,MAAM,CAAC,KAAK,EAAE,OAAO,CAAC,IAAI,cAAc,CAAC,OAAO,EAAE;QAAE,qBAAqB,CAAC,OAAO,EAAE,KAAK,EAAE,SAAS,CAAC,CAAC;IAC1G,IAAI,KAAK,CAAC,KAAK,KAAK,SAAS,IAAI,OAAO,KAAK,CAAC,KAAK,KAAK,UAAU,EAAE,CAAC;QACnE,MAAM,IAAI,KAAK,CAAC,yBAAyB,SAAS,4BAA4B,CAAC,CAAC;IAClF,CAAC;IACD,IAAI,KAAK,CAAC,iBAAiB,KAAK,SAAS,IAAI,OAAO,KAAK,CAAC,iBAAiB,KAAK,UAAU,EAAE,CAAC;QAC3F,MAAM,IAAI,KAAK,CAAC,yBAAyB,SAAS,wCAAwC,CAAC,CAAC;IAC9F,CAAC;IACD,MAAM,eAAe,GAAG,KAAe,CAAC;IACxC,MAAM,kBAAkB,GAAG,cAAiC,CAAC;IAC7D,YAAY,CAAC,eAAe,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,wCAAwC,SAAS,EAAE,CAAC,CAAC;IAC5G,OAAO;QACL,KAAK,EAAE,CAAC,GAAG,eAAe,CAAC;QAC3B,cAAc,EAAE,kBAAkB,CAAC,GAAG,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC,EAAE,GAAG,OAAO,EAAE,CAAC,CAAC;QACrE,GAAG,CAAC,OAAO,KAAK,CAAC,iBAAiB,KAAK,UAAU,CAAC,CAAC,CAAC,EAAE,iBAAiB,EAAE,KAAK,CAAC,iBAA+D,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QACtJ,GAAG,CAAC,OAAO,KAAK,CAAC,KAAK,KAAK,UAAU,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,KAAK,CAAC,KAAuC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;KACvG,CAAC;AACJ,CAAC;AAED,SAAS,YAAY,CAAC,KAAc,EAAE,KAAa,EAAE,SAAiB;IACpE,IAAI,CAAC,QAAQ,CAAC,KAAK,CAAC;QAAE,MAAM,IAAI,KAAK,CAAC,yBAAyB,SAAS,WAAW,KAAK,qBAAqB,CAAC,CAAC;IAC/G,IAAI,CAAC,mBAAmB,CAAC,KAAK,CAAC,IAAI,CAAC;QAAE,MAAM,IAAI,KAAK,CAAC,yBAAyB,SAAS,WAAW,KAAK,oBAAoB,CAAC,CAAC;IAC9H,IAAI,CAAC,CAAC,OAAO,KAAK,CAAC,WAAW,KAAK,QAAQ,IAAI,OAAO,KAAK,CAAC,WAAW,KAAK,UAAU,CAAC,EAAE,CAAC;QACxF,MAAM,IAAI,KAAK,CAAC,yBAAyB,SAAS,WAAW,KAAK,2BAA2B,CAAC,CAAC;IACjG,CAAC;IACD,IAAI,CAAC,QAAQ,CAAC,KAAK,CAAC,WAAW,CAAC;QAAE,MAAM,IAAI,KAAK,CAAC,yBAAyB,SAAS,WAAW,KAAK,2BAA2B,CAAC,CAAC;IACjI,IAAI,CAAC,QAAQ,CAAC,KAAK,CAAC,QAAQ,CAAC;QAAE,MAAM,IAAI,KAAK,CAAC,yBAAyB,SAAS,WAAW,KAAK,wBAAwB,CAAC,CAAC;IAC3H,IAAI,OAAO,KAAK,CAAC,OAAO,KAAK,UAAU,IAAI,OAAO,KAAK,CAAC,IAAI,KAAK,UAAU,EAAE,CAAC;QAC5E,MAAM,IAAI,KAAK,CAAC,yBAAyB,SAAS,WAAW,KAAK,kCAAkC,CAAC,CAAC;IACxG,CAAC;AACH,CAAC;AAED,SAAS,qBAAqB,CAAC,KAAc,EAAE,KAAa,EAAE,SAAiB;IAC7E,IAAI,CAAC,QAAQ,CAAC,KAAK,CAAC,IAAI,CAAC,mBAAmB,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,OAAO,KAAK,CAAC,OAAO,KAAK,QAAQ,EAAE,CAAC;QAC9F,MAAM,IAAI,KAAK,CAAC,yBAAyB,SAAS,oBAAoB,KAAK,iCAAiC,CAAC,CAAC;IAChH,CAAC;IACD,IAAI,KAAK,CAAC,WAAW,KAAK,SAAS,IAAI,OAAO,KAAK,CAAC,WAAW,KAAK,SAAS,EAAE,CAAC;QAC9E,MAAM,IAAI,KAAK,CAAC,yBAAyB,SAAS,oBAAoB,KAAK,+BAA+B,CAAC,CAAC;IAC9G,CAAC;AACH,CAAC;AAED,SAAS,qBAAqB,CAAC,SAAiB,EAAE,KAAa,EAAE,YAAoB;IACnF,MAAM,QAAQ,GAAG,IAAI,CAAC,OAAO,CAAC,SAAS,EAAE,KAAK,CAAC,CAAC;IAChD,MAAM,QAAQ,GAAG,IAAI,CAAC,QAAQ,CAAC,SAAS,EAAE,QAAQ,CAAC,CAAC;IACpD,IAAI,CAAC,QAAQ,IAAI,QAAQ,KAAK,IAAI,IAAI,QAAQ,CAAC,UAAU,CAAC,KAAK,IAAI,CAAC,GAAG,EAAE,CAAC,IAAI,IAAI,CAAC,UAAU,CAAC,QAAQ,CAAC,EAAE,CAAC;QACxG,MAAM,IAAI,KAAK,CAAC,2BAA2B,YAAY,kDAAkD,CAAC,CAAC;IAC7G,CAAC;IACD,OAAO,QAAQ,CAAC;AAClB,CAAC;AAED,SAAS,cAAc,CAAC,KAAiC;IACvD,MAAM,KAAK,GAAG,CAAC,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC;SACnD,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,MAAM,CAAC,IAAI,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC;SACxC,MAAM,CAAC,OAAO,CAAC;SACf,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC;IACrC,OAAO,CAAC,GAAG,IAAI,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC;AAC7B,CAAC;AAED,SAAS,WAAW,CAAC,KAAc,EAAE,KAAa,EAAE,YAAoB;IACtE,MAAM,IAAI,GAAG,OAAO,KAAK,KAAK,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;IAC3D,IAAI,CAAC,IAAI;QAAE,MAAM,IAAI,KAAK,CAAC,2BAA2B,YAAY,KAAK,KAAK,cAAc,CAAC,CAAC;IAC5F,OAAO,IAAI,CAAC;AACd,CAAC;AAED,SAAS,YAAY,CAAI,KAAc,EAAE,KAAa,EAAE,SAAiB;IACvE,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC;QAAE,MAAM,IAAI,KAAK,CAAC,yBAAyB,SAAS,KAAK,KAAK,mBAAmB,CAAC,CAAC;IAC5G,OAAO,KAAY,CAAC;AACtB,CAAC;AAED,SAAS,mBAAmB,CAAC,KAAc;IACzC,OAAO,OAAO,KAAK,KAAK,QAAQ,IAAI,OAAO,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC,CAAC;AAC5D,CAAC;AAED,SAAS,YAAY,CAAC,MAAyB,EAAE,OAAe;IAC9D,MAAM,IAAI,GAAG,IAAI,GAAG,EAAU,CAAC;IAC/B,KAAK,MAAM,KAAK,IAAI,MAAM,EAAE,CAAC;QAC3B,IAAI,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC;YAAE,MAAM,IAAI,KAAK,CAAC,GAAG,OAAO,KAAK,KAAK,EAAE,CAAC,CAAC;QAC7D,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;IAClB,CAAC;AACH,CAAC;AAED,SAAS,QAAQ,CAAC,KAAc;IAC9B,OAAO,OAAO,CAAC,KAAK,CAAC,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;AAC9E,CAAC;AAED,SAAS,WAAW,CAAC,KAAc;IACjC,OAAO,KAAK,YAAY,KAAK,IAAI,MAAM,IAAI,KAAK,CAAC;AACnD,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import assert from "node:assert/strict";
|
|
2
|
+
import { mkdtemp, mkdir, rm, writeFile } from "node:fs/promises";
|
|
3
|
+
import os from "node:os";
|
|
4
|
+
import path from "node:path";
|
|
5
|
+
import { loadNeoPlugins, NEO_PLUGIN_PROTOCOL, validateNeoPluginManifest } from "./plugin-system.js";
|
|
6
|
+
async function main() {
|
|
7
|
+
const root = await mkdtemp(path.join(os.tmpdir(), "neo-plugin-smoke-"));
|
|
8
|
+
const dataDir = path.join(root, "data");
|
|
9
|
+
try {
|
|
10
|
+
await createPlugin(root, "beta", false, "beta_tool");
|
|
11
|
+
await createPlugin(root, "alpha", true, "alpha_tool");
|
|
12
|
+
await mkdir(path.join(root, "not-a-plugin"), { recursive: true });
|
|
13
|
+
const plugins = await loadNeoPlugins({
|
|
14
|
+
directories: root,
|
|
15
|
+
appDataDir: dataDir,
|
|
16
|
+
env: { SMOKE_VALUE: "available" },
|
|
17
|
+
});
|
|
18
|
+
assert.deepEqual(plugins.map((plugin) => plugin.id), ["alpha", "beta"]);
|
|
19
|
+
assert.deepEqual(plugins.map((plugin) => plugin.defaultEnabled), [true, false]);
|
|
20
|
+
assert.deepEqual(plugins.flatMap((plugin) => plugin.tools.map((tool) => tool.name)), ["alpha_tool", "beta_tool"]);
|
|
21
|
+
assert.equal(plugins[0]?.promptSections[0]?.content, `available:${path.resolve(dataDir)}`);
|
|
22
|
+
assert.equal(await plugins[0]?.route?.({ method: "GET" }, {}, new URL("http://localhost/alpha"), {}), true);
|
|
23
|
+
assert.throws(() => validateNeoPluginManifest({ protocol: "other", id: "bad", name: "Bad", version: "1", entry: "index.mjs" }), /protocol must be neo-plugin\/v1/);
|
|
24
|
+
const missing = await loadNeoPlugins({ directories: path.join(root, "missing") });
|
|
25
|
+
assert.deepEqual(missing, []);
|
|
26
|
+
console.log(JSON.stringify({ ok: true, protocol: NEO_PLUGIN_PROTOCOL, plugins: plugins.map((plugin) => plugin.id) }, null, 2));
|
|
27
|
+
}
|
|
28
|
+
finally {
|
|
29
|
+
await rm(root, { recursive: true, force: true });
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
async function createPlugin(root, id, defaultEnabled, toolName) {
|
|
33
|
+
const pluginDir = path.join(root, id);
|
|
34
|
+
await mkdir(pluginDir, { recursive: true });
|
|
35
|
+
await writeFile(path.join(pluginDir, "neo-plugin.json"), JSON.stringify({
|
|
36
|
+
protocol: NEO_PLUGIN_PROTOCOL,
|
|
37
|
+
id,
|
|
38
|
+
name: id.toUpperCase(),
|
|
39
|
+
version: "1.0.0",
|
|
40
|
+
entry: "index.mjs",
|
|
41
|
+
defaultEnabled,
|
|
42
|
+
}, null, 2));
|
|
43
|
+
await writeFile(path.join(pluginDir, "index.mjs"), `
|
|
44
|
+
export function createPlugin(context) {
|
|
45
|
+
return {
|
|
46
|
+
tools: [{
|
|
47
|
+
name: ${JSON.stringify(toolName)},
|
|
48
|
+
description: "smoke tool",
|
|
49
|
+
inputSchema: { type: "object" },
|
|
50
|
+
metadata: { readOnly: true, concurrent: true, visible: true },
|
|
51
|
+
async execute() { return { ok: true, output: context.manifest.id }; },
|
|
52
|
+
}],
|
|
53
|
+
promptSections: [{ name: "Smoke", content: context.env.SMOKE_VALUE + ":" + context.appDataDir, cacheStable: true }],
|
|
54
|
+
route(request, response, url) { return url.pathname === "/" + context.manifest.id; },
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
`, "utf8");
|
|
58
|
+
}
|
|
59
|
+
main().catch((error) => {
|
|
60
|
+
console.error(error);
|
|
61
|
+
process.exitCode = 1;
|
|
62
|
+
});
|
|
63
|
+
//# sourceMappingURL=smoke-plugin-system.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"smoke-plugin-system.js","sourceRoot":"","sources":["../../src/plugins/smoke-plugin-system.ts"],"names":[],"mappings":"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"}
|
package/dist/repl/index.js
CHANGED
|
@@ -894,6 +894,7 @@ function InkRepl({ runtime, initialCommandLine }) {
|
|
|
894
894
|
if (event.type === "state")
|
|
895
895
|
return;
|
|
896
896
|
if (event.type === "context.metrics" ||
|
|
897
|
+
event.type === "context.compacted" ||
|
|
897
898
|
event.type === "usage" ||
|
|
898
899
|
event.type === "tool_call.delta" ||
|
|
899
900
|
event.type === "assistant.delta" ||
|
|
@@ -943,6 +944,7 @@ function InkRepl({ runtime, initialCommandLine }) {
|
|
|
943
944
|
if (event.type === "tool.started") {
|
|
944
945
|
finalizeLiveLine(assistantLineId.current);
|
|
945
946
|
finalizeThinkingLine();
|
|
947
|
+
assistantLineId.current = undefined;
|
|
946
948
|
return;
|
|
947
949
|
}
|
|
948
950
|
if (event.type === "tool.finished")
|
|
@@ -1231,7 +1233,7 @@ function InkRepl({ runtime, initialCommandLine }) {
|
|
|
1231
1233
|
if (runtime.engine !== engine)
|
|
1232
1234
|
continue;
|
|
1233
1235
|
if (suppressReattachedStreamingRef.current.has(engine)) {
|
|
1234
|
-
if (event.type === "message" || event.type === "terminal" || event.type === "error" || event.type === "context.metrics" || event.type === "usage") {
|
|
1236
|
+
if (event.type === "message" || event.type === "terminal" || event.type === "error" || event.type === "context.metrics" || event.type === "context.compacted" || event.type === "usage") {
|
|
1235
1237
|
if (event.type === "message" || event.type === "terminal" || event.type === "error")
|
|
1236
1238
|
suppressReattachedStreamingRef.current.delete(engine);
|
|
1237
1239
|
handleEvent(event);
|
|
@@ -2862,6 +2864,8 @@ function thinkingText(message) {
|
|
|
2862
2864
|
return text.length > 0 ? text : undefined;
|
|
2863
2865
|
}
|
|
2864
2866
|
function reduceStatus(status, event) {
|
|
2867
|
+
if (event.type === "context.compacted")
|
|
2868
|
+
return { ...status, phase: "compacting", detail: `${event.compaction.newWindowMessages} messages in new window`, activityTick: status.activityTick + 1 };
|
|
2865
2869
|
if (event.type === "state") {
|
|
2866
2870
|
return {
|
|
2867
2871
|
...status,
|
|
@@ -3551,8 +3555,9 @@ function formatUsageTotals(totals) {
|
|
|
3551
3555
|
}
|
|
3552
3556
|
function formatManualCompaction(result) {
|
|
3553
3557
|
if (!result.changed)
|
|
3554
|
-
return "No
|
|
3555
|
-
|
|
3558
|
+
return "No conversation context available to compact.";
|
|
3559
|
+
const preservedUsers = result.report?.preservedUserMessages ?? result.messages.filter((message) => message.metadata?.compactPreservedUser === true).length;
|
|
3560
|
+
return `manual context compacted: ${result.messages.length} messages in new window, ${preservedUsers} user message(s) preserved`;
|
|
3556
3561
|
}
|
|
3557
3562
|
function formatPureCompaction(result) {
|
|
3558
3563
|
if (!result.changed)
|