create-loopengine 0.1.47 → 0.1.48
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/package.json +1 -1
- package/template/adapters/http.ts +35 -0
package/package.json
CHANGED
|
@@ -104,6 +104,7 @@ import {
|
|
|
104
104
|
ActauthRuleNotFoundError,
|
|
105
105
|
installAbility,
|
|
106
106
|
upgradeAbility,
|
|
107
|
+
removeAbility,
|
|
107
108
|
listInstalledAbilities,
|
|
108
109
|
backfillDependencies,
|
|
109
110
|
AbilityAlreadyInstalledError,
|
|
@@ -1228,6 +1229,34 @@ async function handleAbilityUpgradePost(req: IncomingMessage, res: ServerRespons
|
|
|
1228
1229
|
}
|
|
1229
1230
|
}
|
|
1230
1231
|
|
|
1232
|
+
// Uninstalls an ability — deletes its tool/skill files and actauth
|
|
1233
|
+
// rules (bin/ability-manager.ts's own removeAbility). Same admin-auth
|
|
1234
|
+
// posture as install/upgrade above: this mutates the agent's own tree,
|
|
1235
|
+
// even though — unlike install/upgrade — it never runs new third-party
|
|
1236
|
+
// code. `removed`/`refused` pass straight through on success (not an
|
|
1237
|
+
// error: a dirty file left in place, same as remove-ability's own CLI
|
|
1238
|
+
// behavior, is a normal partial outcome the Admin UI shows and offers
|
|
1239
|
+
// to retry with force, not a failure).
|
|
1240
|
+
async function handleAbilityUninstallDelete(res: ServerResponse, agentName: string, abilityName: string, force: boolean): Promise<void> {
|
|
1241
|
+
if (!adminAuth) {
|
|
1242
|
+
res.writeHead(403, { 'content-type': 'application/json' }).end(
|
|
1243
|
+
JSON.stringify({ error: 'Refusing to uninstall an ability without LOOPENGINE_ADMIN_AUTH configured — set it before uninstalling abilities through this route.' }),
|
|
1244
|
+
)
|
|
1245
|
+
return
|
|
1246
|
+
}
|
|
1247
|
+
if (!getEntry(agentName)) {
|
|
1248
|
+
res.writeHead(404, { 'content-type': 'application/json' }).end(JSON.stringify({ error: `unknown agent '${agentName}'` }))
|
|
1249
|
+
return
|
|
1250
|
+
}
|
|
1251
|
+
try {
|
|
1252
|
+
const result = removeAbility(agentName, abilityName, force)
|
|
1253
|
+
res.writeHead(200, { 'content-type': 'application/json' }).end(JSON.stringify(result))
|
|
1254
|
+
} catch (err) {
|
|
1255
|
+
const status = err instanceof AbilityNotInstalledError ? 404 : 500
|
|
1256
|
+
res.writeHead(status, { 'content-type': 'application/json' }).end(JSON.stringify({ error: err instanceof Error ? err.message : String(err) }))
|
|
1257
|
+
}
|
|
1258
|
+
}
|
|
1259
|
+
|
|
1231
1260
|
const execFileAsync = promisify(execFile)
|
|
1232
1261
|
const NPM_INSTALL_DEPS_TIMEOUT_MS = 180_000
|
|
1233
1262
|
|
|
@@ -2624,6 +2653,12 @@ const server = createServer(async (req, res) => {
|
|
|
2624
2653
|
await handleAbilityInstallDepsPost(req, res, decodeURIComponent(abilityInstallDepsMatch[1]), decodeURIComponent(abilityInstallDepsMatch[2]))
|
|
2625
2654
|
return
|
|
2626
2655
|
}
|
|
2656
|
+
const abilityMatch = pathname.match(/^\/agents\/([^/]+)\/abilities\/([^/]+)$/)
|
|
2657
|
+
if (abilityMatch && req.method === 'DELETE') {
|
|
2658
|
+
const force = new URL(req.url ?? '/', 'http://localhost').searchParams.get('force') === 'true'
|
|
2659
|
+
await handleAbilityUninstallDelete(res, decodeURIComponent(abilityMatch[1]), decodeURIComponent(abilityMatch[2]), force)
|
|
2660
|
+
return
|
|
2661
|
+
}
|
|
2627
2662
|
const abilitiesMatch = pathname.match(/^\/agents\/([^/]+)\/abilities$/)
|
|
2628
2663
|
if (abilitiesMatch && req.method === 'GET') {
|
|
2629
2664
|
await handleAbilitiesGet(res, decodeURIComponent(abilitiesMatch[1]))
|