loopengine 0.1.31 → 0.1.33
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.
|
@@ -27,6 +27,17 @@ export interface AbilityManifest {
|
|
|
27
27
|
skills?: string[];
|
|
28
28
|
actauth?: string;
|
|
29
29
|
env?: AbilityEnvDecl[];
|
|
30
|
+
/** Real npm package names (dependencies + optionalDependencies) the
|
|
31
|
+
* ability's own tool files import — read off package.json, not
|
|
32
|
+
* declared in loopengine.ability.json itself. installAbility only
|
|
33
|
+
* ever copies the ability's *files* into the consuming project, never
|
|
34
|
+
* touches its package.json/node_modules (see installAbility's own
|
|
35
|
+
* doc comment for why), so a tool that imports a real package like
|
|
36
|
+
* `sharp` will fail at runtime with a bare "Cannot find package"
|
|
37
|
+
* error unless the operator separately runs `npm install` for it —
|
|
38
|
+
* this is what lets a caller (the Admin UI's Abilities tab) warn
|
|
39
|
+
* about that up front instead of leaving it as a silent trap. */
|
|
40
|
+
dependencies?: string[];
|
|
30
41
|
}
|
|
31
42
|
/** One agent's record of one installed ability — the merge base a
|
|
32
43
|
* future upgrade needs, what remove needs to know is safe to delete,
|
|
@@ -112,6 +123,7 @@ export interface FetchOptions {
|
|
|
112
123
|
* install is refused, before a single file is written. */
|
|
113
124
|
export declare function installAbility(agentName: string, spec: string, options?: FetchOptions): Promise<{
|
|
114
125
|
installed: string[];
|
|
126
|
+
dependencies: string[];
|
|
115
127
|
}>;
|
|
116
128
|
export interface UpgradeFileResult {
|
|
117
129
|
path: string;
|
|
@@ -212,7 +212,8 @@ function readManifest(abilityDir) {
|
|
|
212
212
|
if (!pkgJson.name || !pkgJson.version) {
|
|
213
213
|
throw new AbilityManifestError(`${pkgJsonPath} must have "name" and "version".`);
|
|
214
214
|
}
|
|
215
|
-
|
|
215
|
+
const dependencies = [...Object.keys(pkgJson.dependencies ?? {}), ...Object.keys(pkgJson.optionalDependencies ?? {})];
|
|
216
|
+
return { ...declared, name: pkgJson.name, version: pkgJson.version, dependencies };
|
|
216
217
|
}
|
|
217
218
|
// The installing project's own dependencies.loopengine is itself a
|
|
218
219
|
// range (e.g. "^0.1.10"), not a concrete installed version — checking
|
|
@@ -456,7 +457,10 @@ export async function installAbility(agentName, spec, options = {}) {
|
|
|
456
457
|
contentHashes,
|
|
457
458
|
};
|
|
458
459
|
writeProvenance(agentName, provenance);
|
|
459
|
-
return {
|
|
460
|
+
return {
|
|
461
|
+
installed: [...toolNames.map((n) => `tools/${n}.ts`), ...skillIds.map((id) => `skills/${id}/`), ...ruleNames.map((n) => `actauth:${n}`)],
|
|
462
|
+
dependencies: manifest.dependencies ?? [],
|
|
463
|
+
};
|
|
460
464
|
}
|
|
461
465
|
// ---- Upgrade ----
|
|
462
466
|
// git merge-file's own exit code *is* its conflict count (0 = clean),
|
|
@@ -18,9 +18,23 @@ export async function searchPublicAbilities(query) {
|
|
|
18
18
|
if (!res.ok)
|
|
19
19
|
throw new Error(`npm registry search failed (HTTP ${res.status})`);
|
|
20
20
|
const data = (await res.json());
|
|
21
|
-
|
|
21
|
+
const results = (data.objects ?? []).map((o) => ({
|
|
22
22
|
name: o.package.name,
|
|
23
23
|
description: o.package.description ?? '',
|
|
24
24
|
version: o.package.version,
|
|
25
25
|
}));
|
|
26
|
+
// npm's own search is a relevance *ranker*, not a filter — a query
|
|
27
|
+
// like "keywords:loopengine-ability docs" boosts a matching package's
|
|
28
|
+
// score but doesn't drop the non-matching ones from the response at
|
|
29
|
+
// all (confirmed live: every ability in this ecosystem still came
|
|
30
|
+
// back regardless of the extra query text, just reordered). With this
|
|
31
|
+
// few, brand-new, all-zero-download packages, that reordering barely
|
|
32
|
+
// moves, so an operator typing a search term would otherwise see the
|
|
33
|
+
// exact same full list every time. Filtering here on name/description
|
|
34
|
+
// gives the strict, expected "search box" behavior npm's own API
|
|
35
|
+
// doesn't provide on its own.
|
|
36
|
+
if (!query)
|
|
37
|
+
return results;
|
|
38
|
+
const needle = query.toLowerCase();
|
|
39
|
+
return results.filter((r) => r.name.toLowerCase().includes(needle) || r.description.toLowerCase().includes(needle));
|
|
26
40
|
}
|
|
@@ -1285,7 +1285,19 @@ export const agentsConfigPageHtml = `<!doctype html>
|
|
|
1285
1285
|
// doesn't splice into an already-running server's in-memory
|
|
1286
1286
|
// registry any more than the CLI does (see installAbility's own
|
|
1287
1287
|
// doc comment on why), so the operator needs the same nudge here.
|
|
1288
|
-
|
|
1288
|
+
var message = 'Installed: ' + escapeHtml(result.body.installed.join(', ')) + '. Already running under npx loopengine dev? It becomes active automatically. Running under serve (or nothing yet)? Restart the server to pick it up.';
|
|
1289
|
+
var deps = result.body.dependencies || [];
|
|
1290
|
+
if (deps.length) {
|
|
1291
|
+
// installAbility only ever copies the ability's own files —
|
|
1292
|
+
// never touches package.json/node_modules — so a real npm
|
|
1293
|
+
// dependency the ability's own tool code imports (e.g. sharp)
|
|
1294
|
+
// has to be installed separately, or the tool fails at runtime
|
|
1295
|
+
// with an opaque "Cannot find package" the very next time this
|
|
1296
|
+
// agent's config is loaded. Surfaced here, loudly, instead of
|
|
1297
|
+
// leaving that as a silent trap discovered later.
|
|
1298
|
+
message += ' <strong>This ability also needs: <code>npm install ' + escapeHtml(deps.join(' ')) + '</code></strong> in your own project before it will actually work.';
|
|
1299
|
+
}
|
|
1300
|
+
statusEl.innerHTML = message;
|
|
1289
1301
|
loadAbilitiesTab(name);
|
|
1290
1302
|
})
|
|
1291
1303
|
.catch(function (err) {
|