ship the capabilities repository, and update it from the same button as plugins
capabilities/ is the file-based item store, and most of it belongs to the owner: the six item directories are created by the platform at boot and extensions/tool-loader is written from platform source, so neither is tracked anywhere. What IS tracked is the small set the platform ships — today one affordance, telling an agent that markdown images render and that the USER'S DEVICE fetches the URL, which it cannot discover from the filesystem. That now lives in officerdev/capabilities, public so a fresh install can clone it without credentials. Two ways in. The setup script syncs it during the layout step — non-fatal, and it says what an install without it costs rather than failing: agents go back to guessing, which is what they did before this existed. And "Update all" on the marketplace screen carries it alongside the plugins, because it is the same question — get me what has been published since I installed — and a second different gesture for it is one nobody remembers. Three states in both places, and the third is the normal one on an existing machine: a checkout is pulled, an empty directory is cloned into, and a directory that already holds the platform's generated items gets a repository initialised around them. UNTRACKED files never block a pull, because the owner's own skills and tools living here is the ordinary state — only tracked changes do. `cloned` and `adopted` are reported in the UI where `pulled` is not: they mean this machine had no affordances at all until the button was pressed. Verified against the real checkout: sync reports pulled, and the loader finds officer/core/image-rendering afterwards. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
@@ -15,7 +15,7 @@ import {
|
||||
uninstallPlugin,
|
||||
type PluginActionResult,
|
||||
} from '../../plugins/install';
|
||||
import { updatePlugin } from '../../plugins/update';
|
||||
import { updatePlugin, syncCapabilities } from '../../plugins/update';
|
||||
|
||||
// /api/plugins — what is on this machine, what is installed, and the four verbs that change it.
|
||||
//
|
||||
@@ -195,10 +195,21 @@ pluginsRouter.post('/update-all', async (ctx) => {
|
||||
for (const appName of installed) {
|
||||
results.push(await updatePlugin(appName, undefined, userId));
|
||||
}
|
||||
|
||||
// The capabilities repository rides along. It is the same question the button asks — "get me what has
|
||||
// been published since I installed" — and a second, different gesture for it is one nobody remembers.
|
||||
// On a machine installed before affordances existed there is no checkout at all, so this is also how it
|
||||
// first arrives.
|
||||
const capabilities = await syncCapabilities();
|
||||
|
||||
return ctx.json({
|
||||
results,
|
||||
capabilities,
|
||||
updated: results.filter((r) => r.ok).length,
|
||||
failed: results.filter((r) => !r.ok).map((r) => ({ appName: r.appName, error: r.error })),
|
||||
failed: [
|
||||
...results.filter((r) => !r.ok).map((r) => ({ appName: r.appName, error: r.error })),
|
||||
...(capabilities.ok ? [] : [{ appName: 'capabilities', error: capabilities.error }]),
|
||||
],
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
Reference in New Issue
Block a user