loopengine 0.1.11 → 0.1.12
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/dist/bin/cli.js +3 -0
- package/dist/bin/package-manager.d.ts +24 -6
- package/dist/bin/package-manager.js +42 -25
- package/package.json +1 -1
package/dist/bin/cli.js
CHANGED
|
@@ -320,6 +320,9 @@ async function main() {
|
|
|
320
320
|
console.log(`Installed into agents/${agent}/:`);
|
|
321
321
|
for (const p of installed)
|
|
322
322
|
console.log(` ${p}`);
|
|
323
|
+
console.log();
|
|
324
|
+
console.log('Already running under `npx loopengine dev`? The new tool becomes active automatically.');
|
|
325
|
+
console.log('Running under `serve` (or nothing yet)? Restart the server to pick it up.');
|
|
323
326
|
}
|
|
324
327
|
catch (err) {
|
|
325
328
|
console.error(err instanceof Error ? err.message : String(err));
|
|
@@ -64,12 +64,30 @@ export interface FetchOptions {
|
|
|
64
64
|
* createHttpTool does), copies each skill directory verbatim (a raw
|
|
65
65
|
* cpSync, not skills-admin.ts's writeSkill — that regenerates
|
|
66
66
|
* frontmatter from scratch and can't carry a package's own
|
|
67
|
-
* frontmatter/assets), appends each actauth rule (addActauthRule)
|
|
68
|
-
*
|
|
69
|
-
*
|
|
70
|
-
* adapters/http.ts's handleHttpToolPost
|
|
71
|
-
*
|
|
72
|
-
*
|
|
67
|
+
* frontmatter/assets), and appends each actauth rule (addActauthRule).
|
|
68
|
+
*
|
|
69
|
+
* Deliberately does *not* attempt a live in-memory registry splice the
|
|
70
|
+
* way adapters/http.ts's own handleHttpToolPost does for an
|
|
71
|
+
* admin-created tool — that works there because the HTTP request
|
|
72
|
+
* creating the tool runs *inside the same process* as the already-running
|
|
73
|
+
* server, so updateAgent's mutation is visible to every later request in
|
|
74
|
+
* that same process immediately. `add-package` is a separate, one-off
|
|
75
|
+
* CLI process with no connection to whatever server might be running
|
|
76
|
+
* elsewhere — even a successful getEntry/updateAgent call here would
|
|
77
|
+
* only mutate *this* CLI invocation's own throwaway registry, then
|
|
78
|
+
* vanish the moment the process exits, having done nothing to the real
|
|
79
|
+
* running server. (Confirmed live: this used to import
|
|
80
|
+
* core/agent-registry.js, whose own discoverAgents does a top-level
|
|
81
|
+
* directory scan relative to *its own compiled file's location* —
|
|
82
|
+
* inside node_modules/loopengine when this runs there, not the
|
|
83
|
+
* consuming project's real agents/ at all, throwing ENOENT immediately.)
|
|
84
|
+
* Same reason add-agent/add-subagent above don't attempt this either —
|
|
85
|
+
* a new tool becomes active the same way a new agent does: the next
|
|
86
|
+
* request under `serve`, or automatically under `npx loopengine dev`'s
|
|
87
|
+
* file watcher once tools/index.ts's own edit is picked up.
|
|
88
|
+
*
|
|
89
|
+
* All-or-nothing: every collision check below runs, and the whole
|
|
90
|
+
* install is refused, before a single file is written. */
|
|
73
91
|
export declare function installPackage(agentName: string, spec: string, options?: FetchOptions): Promise<{
|
|
74
92
|
installed: string[];
|
|
75
93
|
}>;
|
|
@@ -21,12 +21,9 @@ import { execFileSync } from 'node:child_process';
|
|
|
21
21
|
import { basename, join } from 'node:path';
|
|
22
22
|
import { cpSync, existsSync, mkdirSync, mkdtempSync, readFileSync, readdirSync, rmSync, writeFileSync } from 'node:fs';
|
|
23
23
|
import { tmpdir } from 'node:os';
|
|
24
|
-
import { pathToFileURL } from 'node:url';
|
|
25
24
|
import { parse as parseYaml } from 'yaml';
|
|
26
25
|
import semver from 'semver';
|
|
27
26
|
import { agentDir } from '../core/gateway-tools.js';
|
|
28
|
-
import { getEntry, updateAgent } from '../core/agent-registry.js';
|
|
29
|
-
import { loadDefaultTools } from '../core/run-agent.js';
|
|
30
27
|
import { addToolToIndex, toCamelCase } from '../web/http-tool-admin.js';
|
|
31
28
|
import { addActauthRule, updateActauthRule, removeActauthRule, readActauthConfig } from '../web/actauth-admin.js';
|
|
32
29
|
export class PackageManifestError extends Error {
|
|
@@ -137,7 +134,20 @@ function checkLoopengineVersion(manifest, installedRangeOverride) {
|
|
|
137
134
|
throw new PackageVersionError(`This project's package.json has no "loopengine" dependency — can't check compatibility.`);
|
|
138
135
|
}
|
|
139
136
|
}
|
|
140
|
-
|
|
137
|
+
// A non-registry dependency specifier (file:, git:, workspace:, ...) —
|
|
138
|
+
// common for local development against an unpublished loopengine
|
|
139
|
+
// build — isn't a semver range at all, so minVersion throws rather
|
|
140
|
+
// than returning null; nothing meaningful to compare against, so skip
|
|
141
|
+
// the check rather than crash the whole command on it (same "nothing
|
|
142
|
+
// to compare, nothing to refuse" reasoning the this-repo-itself skip
|
|
143
|
+
// above already uses).
|
|
144
|
+
let floor;
|
|
145
|
+
try {
|
|
146
|
+
floor = semver.minVersion(installedRange);
|
|
147
|
+
}
|
|
148
|
+
catch {
|
|
149
|
+
return;
|
|
150
|
+
}
|
|
141
151
|
if (!floor || !semver.satisfies(floor, manifest.loopengineVersion)) {
|
|
142
152
|
throw new PackageVersionError(`Package '${manifest.name}' needs loopengine ${manifest.loopengineVersion}, but this project depends on loopengine ${installedRange} — bump the dependency first.`);
|
|
143
153
|
}
|
|
@@ -162,12 +172,30 @@ function parseActauthRules(packageDir, manifest) {
|
|
|
162
172
|
* createHttpTool does), copies each skill directory verbatim (a raw
|
|
163
173
|
* cpSync, not skills-admin.ts's writeSkill — that regenerates
|
|
164
174
|
* frontmatter from scratch and can't carry a package's own
|
|
165
|
-
* frontmatter/assets), appends each actauth rule (addActauthRule)
|
|
166
|
-
*
|
|
167
|
-
*
|
|
168
|
-
* adapters/http.ts's handleHttpToolPost
|
|
169
|
-
*
|
|
170
|
-
*
|
|
175
|
+
* frontmatter/assets), and appends each actauth rule (addActauthRule).
|
|
176
|
+
*
|
|
177
|
+
* Deliberately does *not* attempt a live in-memory registry splice the
|
|
178
|
+
* way adapters/http.ts's own handleHttpToolPost does for an
|
|
179
|
+
* admin-created tool — that works there because the HTTP request
|
|
180
|
+
* creating the tool runs *inside the same process* as the already-running
|
|
181
|
+
* server, so updateAgent's mutation is visible to every later request in
|
|
182
|
+
* that same process immediately. `add-package` is a separate, one-off
|
|
183
|
+
* CLI process with no connection to whatever server might be running
|
|
184
|
+
* elsewhere — even a successful getEntry/updateAgent call here would
|
|
185
|
+
* only mutate *this* CLI invocation's own throwaway registry, then
|
|
186
|
+
* vanish the moment the process exits, having done nothing to the real
|
|
187
|
+
* running server. (Confirmed live: this used to import
|
|
188
|
+
* core/agent-registry.js, whose own discoverAgents does a top-level
|
|
189
|
+
* directory scan relative to *its own compiled file's location* —
|
|
190
|
+
* inside node_modules/loopengine when this runs there, not the
|
|
191
|
+
* consuming project's real agents/ at all, throwing ENOENT immediately.)
|
|
192
|
+
* Same reason add-agent/add-subagent above don't attempt this either —
|
|
193
|
+
* a new tool becomes active the same way a new agent does: the next
|
|
194
|
+
* request under `serve`, or automatically under `npx loopengine dev`'s
|
|
195
|
+
* file watcher once tools/index.ts's own edit is picked up.
|
|
196
|
+
*
|
|
197
|
+
* All-or-nothing: every collision check below runs, and the whole
|
|
198
|
+
* install is refused, before a single file is written. */
|
|
171
199
|
export async function installPackage(agentName, spec, options = {}) {
|
|
172
200
|
const fetch = options.fetchPackageDir ?? fetchPackageDir;
|
|
173
201
|
const packageDir = fetch(spec);
|
|
@@ -215,19 +243,11 @@ export async function installPackage(agentName, spec, options = {}) {
|
|
|
215
243
|
}
|
|
216
244
|
}
|
|
217
245
|
const contentHashes = {};
|
|
218
|
-
// Write tool files
|
|
219
|
-
//
|
|
220
|
-
//
|
|
221
|
-
//
|
|
222
|
-
// own comment already warns about for a folder-form agent with no
|
|
223
|
-
// cached config.tools (re-reading tools/index.ts after it's already
|
|
224
|
-
// been patched would see the just-added entry a second time).
|
|
246
|
+
// Write tool files and patch tools/index.ts — pure filesystem
|
|
247
|
+
// operations, no dynamic import and no registry interaction (see this
|
|
248
|
+
// function's own doc comment for why: a CLI process can't live-splice
|
|
249
|
+
// into a separate, already-running server).
|
|
225
250
|
if (toolNames.length > 0) {
|
|
226
|
-
const entry = getEntry(agentName);
|
|
227
|
-
if (!entry)
|
|
228
|
-
throw new Error(`Unknown agent '${agentName}'.`);
|
|
229
|
-
const currentTools = entry.config.tools ?? (await loadDefaultTools(entry.config));
|
|
230
|
-
const newTools = [];
|
|
231
251
|
mkdirSync(toolsDir, { recursive: true });
|
|
232
252
|
const indexPath = join(toolsDir, 'index.ts');
|
|
233
253
|
for (const toolFile of toolFiles) {
|
|
@@ -243,10 +263,7 @@ export async function installPackage(agentName, spec, options = {}) {
|
|
|
243
263
|
else {
|
|
244
264
|
writeFileSync(indexPath, `import type { ToolDefinition } from 'loopengine'\nimport { ${exportName} } from './${toolName}.js'\n\nexport const tools: ToolDefinition[] = [${exportName}]\n`);
|
|
245
265
|
}
|
|
246
|
-
const mod = (await import(pathToFileURL(destPath).href));
|
|
247
|
-
newTools.push(mod[exportName]);
|
|
248
266
|
}
|
|
249
|
-
updateAgent(agentName, { config: { tools: [...currentTools, ...newTools] } });
|
|
250
267
|
}
|
|
251
268
|
// Copy skill directories verbatim.
|
|
252
269
|
for (const skillDir of skillDirs) {
|