loopengine 0.1.60 → 0.1.61

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/index.d.ts CHANGED
@@ -59,7 +59,7 @@ export { listDeclaredEnvVars, setEnvVar, unsetEnvVar, agentScopedEnvVarName, Env
59
59
  export type { DeclaredEnvVar } from './web/env-admin.js';
60
60
  export { readActauthConfig, addActauthRule, updateActauthRule, removeActauthRule, setDefaultDecision, ActauthRuleExistsError, ActauthRuleNotFoundError, } from './web/actauth-admin.js';
61
61
  export type { ActauthRuleInput, ActauthConfigView } from './web/actauth-admin.js';
62
- export { installAbility, upgradeAbility, listInstalledAbilities, backfillDependencies, AbilityManifestError, AbilityVersionError, AbilityCollisionError, AbilityAlreadyInstalledError, AbilityNotInstalledError, } from './bin/ability-manager.js';
62
+ export { installAbility, upgradeAbility, removeAbility, listInstalledAbilities, backfillDependencies, AbilityManifestError, AbilityVersionError, AbilityCollisionError, AbilityAlreadyInstalledError, AbilityNotInstalledError, } from './bin/ability-manager.js';
63
63
  export type { InstalledAbilityRecord, AbilityEnvDecl, UpgradeFileResult } from './bin/ability-manager.js';
64
64
  export { searchPublicAbilities, fetchLatestAbilityVersion } from './web/abilities-admin.js';
65
65
  export type { PublicAbilitySearchResult } from './web/abilities-admin.js';
package/dist/index.js CHANGED
@@ -52,7 +52,7 @@ export { playgroundHtml } from './web/playground.js';
52
52
  export { readSkill, writeSkill, deleteSkill, SkillInvalidIdError, SkillNotFoundError } from './web/skills-admin.js';
53
53
  export { listDeclaredEnvVars, setEnvVar, unsetEnvVar, agentScopedEnvVarName, EnvVarNameError } from './web/env-admin.js';
54
54
  export { readActauthConfig, addActauthRule, updateActauthRule, removeActauthRule, setDefaultDecision, ActauthRuleExistsError, ActauthRuleNotFoundError, } from './web/actauth-admin.js';
55
- export { installAbility, upgradeAbility, listInstalledAbilities, backfillDependencies, AbilityManifestError, AbilityVersionError, AbilityCollisionError, AbilityAlreadyInstalledError, AbilityNotInstalledError, } from './bin/ability-manager.js';
55
+ export { installAbility, upgradeAbility, removeAbility, listInstalledAbilities, backfillDependencies, AbilityManifestError, AbilityVersionError, AbilityCollisionError, AbilityAlreadyInstalledError, AbilityNotInstalledError, } from './bin/ability-manager.js';
56
56
  export { searchPublicAbilities, fetchLatestAbilityVersion } from './web/abilities-admin.js';
57
57
  export { describeModelProviders, describeGateways } from './web/global-config.js';
58
58
  export { createTrackedApprover, listApprovals, decideApproval, findApproval } from './web/web-approver.js';
@@ -1379,6 +1379,7 @@ export const agentsConfigPageHtml = `<!doctype html>
1379
1379
  if (deps.length) {
1380
1380
  actionHtml += ' <button type="button" class="ability-install-deps-btn" data-name="' + escapeHtml(a.name) + '" title="npm install ' + escapeHtml(deps.join(' ')) + '">Install deps</button>';
1381
1381
  }
1382
+ actionHtml += ' <button type="button" class="ability-uninstall-btn" data-name="' + escapeHtml(a.name) + '">Uninstall</button>';
1382
1383
  return '<tr>' +
1383
1384
  '<td><code>' + escapeHtml(a.name) + '</code></td>' +
1384
1385
  '<td>' + escapeHtml(a.version) + '</td>' +
@@ -1544,6 +1545,49 @@ export const agentsConfigPageHtml = `<!doctype html>
1544
1545
  });
1545
1546
  }
1546
1547
 
1548
+ // Deletes an ability's tool/skill files and actauth rules
1549
+ // (handleAbilityUninstallDelete / bin/ability-manager.ts's own
1550
+ // removeAbility). A file hand-modified since install is left in place
1551
+ // and reported back as refused rather than silently deleted — the
1552
+ // confirm() below offers to retry with force once the operator has
1553
+ // seen exactly which files those are, same two-step the CLI itself
1554
+ // takes with --force. Always reloads the tab afterward: a partial
1555
+ // uninstall (some files refused) still changes what is installed,
1556
+ // it just does not remove the ability entirely from provenance.
1557
+ function uninstallAbility(name, abilityName, statusEl, btn, force) {
1558
+ if (btn) { btn.disabled = true; }
1559
+ statusEl.className = 'hint';
1560
+ statusEl.textContent = 'Uninstalling ' + abilityName + '...';
1561
+ var url = '/agents/' + encodeURIComponent(name) + '/abilities/' + encodeURIComponent(abilityName) + (force ? '?force=true' : '');
1562
+ fetch(url, { method: 'DELETE' })
1563
+ .then(function (r) { return r.json().then(function (j) { return { ok: r.ok, body: j }; }); })
1564
+ .then(function (result) {
1565
+ if (!result.ok) throw new Error(result.body.error || 'request failed');
1566
+ var removed = result.body.removed || [];
1567
+ var refused = result.body.refused || [];
1568
+ if (refused.length && !force) {
1569
+ var retry = confirm(
1570
+ abilityName + ': ' + refused.length + ' file(s) were hand-modified since install and left in place (' + refused.join(', ') + '). Remove them anyway?',
1571
+ );
1572
+ if (retry) {
1573
+ uninstallAbility(name, abilityName, statusEl, btn, true);
1574
+ return;
1575
+ }
1576
+ }
1577
+ statusEl.className = refused.length ? 'error' : 'hint';
1578
+ statusEl.textContent = removed.length
1579
+ ? 'Removed ' + removed.join(', ') + '.' + (refused.length ? ' Left in place (hand-modified): ' + refused.join(', ') + '.' : '')
1580
+ : 'Nothing removed.';
1581
+ if (btn) { btn.disabled = false; }
1582
+ loadAbilitiesTab(name);
1583
+ })
1584
+ .catch(function (err) {
1585
+ statusEl.className = 'error';
1586
+ statusEl.textContent = 'Could not uninstall: ' + err.message;
1587
+ if (btn) { btn.disabled = false; }
1588
+ });
1589
+ }
1590
+
1547
1591
  // Shared by the initial (empty-query) load right after the tab opens
1548
1592
  // and the search form's own submit — the empty-query case is just
1549
1593
  // "list every published ability" (the keyword filter alone, no extra
@@ -1593,6 +1637,16 @@ export const agentsConfigPageHtml = `<!doctype html>
1593
1637
  });
1594
1638
  }
1595
1639
 
1640
+ var uninstallBtns = content.querySelectorAll('.ability-uninstall-btn');
1641
+ for (var r = 0; r < uninstallBtns.length; r++) {
1642
+ uninstallBtns[r].addEventListener('click', function (ev) {
1643
+ var btn = ev.currentTarget;
1644
+ var abilityName = btn.dataset.name;
1645
+ if (!confirm('Uninstall ' + abilityName + '? This deletes its tool and skill files and actauth rules from this agent.')) return;
1646
+ uninstallAbility(name, abilityName, upgradeStatusEl, btn, false);
1647
+ });
1648
+ }
1649
+
1596
1650
  var searchForm = content.querySelector('#abilitySearchForm');
1597
1651
  var resultsEl = content.querySelector('#abilitySearchResults');
1598
1652
  if (searchForm && resultsEl) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "loopengine",
3
- "version": "0.1.60",
3
+ "version": "0.1.61",
4
4
  "type": "module",
5
5
  "description": "Runtime for tool-using AI agents with a transparent ReAct loop.",
6
6
  "license": "MIT",