@withbuddi/buddi 0.1.0-pre.30 → 0.1.0-pre.32
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/README.md +58 -368
- package/examples/agents/concierge/agent.md +10 -2
- package/extension/manifest.json +2 -2
- package/node_modules/@buddi/cli/dist/.tsbuildinfo +1 -1
- package/node_modules/@buddi/cli/dist/agents-catalogue-cmd.d.ts +50 -0
- package/node_modules/@buddi/cli/dist/agents-catalogue-cmd.d.ts.map +1 -0
- package/node_modules/@buddi/cli/dist/agents-catalogue-cmd.js +328 -0
- package/node_modules/@buddi/cli/dist/agents-catalogue-cmd.js.map +1 -0
- package/node_modules/@buddi/cli/dist/args.d.ts +5 -0
- package/node_modules/@buddi/cli/dist/args.d.ts.map +1 -1
- package/node_modules/@buddi/cli/dist/args.js +8 -0
- package/node_modules/@buddi/cli/dist/args.js.map +1 -1
- package/node_modules/@buddi/cli/dist/commands.d.ts.map +1 -1
- package/node_modules/@buddi/cli/dist/commands.js +63 -1
- package/node_modules/@buddi/cli/dist/commands.js.map +1 -1
- package/node_modules/@buddi/cli/dist/doctor-probes.d.ts.map +1 -1
- package/node_modules/@buddi/cli/dist/doctor-probes.js +4 -11
- package/node_modules/@buddi/cli/dist/doctor-probes.js.map +1 -1
- package/node_modules/@buddi/cli/dist/doctor.d.ts +16 -0
- package/node_modules/@buddi/cli/dist/doctor.d.ts.map +1 -1
- package/node_modules/@buddi/cli/dist/doctor.js +30 -0
- package/node_modules/@buddi/cli/dist/doctor.js.map +1 -1
- package/node_modules/@buddi/cli/dist/main.d.ts.map +1 -1
- package/node_modules/@buddi/cli/dist/main.js +44 -9
- package/node_modules/@buddi/cli/dist/main.js.map +1 -1
- package/node_modules/@buddi/cli/dist/mcp/tools.d.ts.map +1 -1
- package/node_modules/@buddi/cli/dist/mcp/tools.js +3 -1
- package/node_modules/@buddi/cli/dist/mcp/tools.js.map +1 -1
- package/node_modules/@buddi/cli/dist/skills-cmd.d.ts +15 -0
- package/node_modules/@buddi/cli/dist/skills-cmd.d.ts.map +1 -0
- package/node_modules/@buddi/cli/dist/skills-cmd.js +54 -0
- package/node_modules/@buddi/cli/dist/skills-cmd.js.map +1 -0
- package/node_modules/@buddi/cli/dist/status.d.ts +15 -9
- package/node_modules/@buddi/cli/dist/status.d.ts.map +1 -1
- package/node_modules/@buddi/cli/dist/status.js +6 -11
- package/node_modules/@buddi/cli/dist/status.js.map +1 -1
- package/node_modules/@buddi/core/dist/.tsbuildinfo +1 -1
- package/node_modules/@buddi/core/dist/actions/store.d.ts +8 -0
- package/node_modules/@buddi/core/dist/actions/store.d.ts.map +1 -1
- package/node_modules/@buddi/core/dist/actions/store.js +13 -0
- package/node_modules/@buddi/core/dist/actions/store.js.map +1 -1
- package/node_modules/@buddi/core/dist/agents/catalog.d.ts +11 -3
- package/node_modules/@buddi/core/dist/agents/catalog.d.ts.map +1 -1
- package/node_modules/@buddi/core/dist/agents/catalog.js +58 -10
- package/node_modules/@buddi/core/dist/agents/catalog.js.map +1 -1
- package/node_modules/@buddi/core/dist/agents/frontmatter.d.ts +1 -1
- package/node_modules/@buddi/core/dist/agents/frontmatter.d.ts.map +1 -1
- package/node_modules/@buddi/core/dist/agents/frontmatter.js +1 -1
- package/node_modules/@buddi/core/dist/agents/frontmatter.js.map +1 -1
- package/node_modules/@buddi/core/dist/agents/skills.d.ts +29 -3
- package/node_modules/@buddi/core/dist/agents/skills.d.ts.map +1 -1
- package/node_modules/@buddi/core/dist/agents/skills.js +49 -2
- package/node_modules/@buddi/core/dist/agents/skills.js.map +1 -1
- package/node_modules/@buddi/core/dist/clock-widget.d.ts.map +1 -1
- package/node_modules/@buddi/core/dist/clock-widget.js +5 -3
- package/node_modules/@buddi/core/dist/clock-widget.js.map +1 -1
- package/node_modules/@buddi/core/dist/host/build.d.ts.map +1 -1
- package/node_modules/@buddi/core/dist/host/build.js +11 -0
- package/node_modules/@buddi/core/dist/host/build.js.map +1 -1
- package/node_modules/@buddi/core/dist/host/types.d.ts +7 -0
- package/node_modules/@buddi/core/dist/host/types.d.ts.map +1 -1
- package/node_modules/@buddi/core/dist/learning/store.d.ts +7 -0
- package/node_modules/@buddi/core/dist/learning/store.d.ts.map +1 -1
- package/node_modules/@buddi/core/dist/learning/store.js +6 -0
- package/node_modules/@buddi/core/dist/learning/store.js.map +1 -1
- package/node_modules/@buddi/core/dist/notifications/agent.d.ts +7 -0
- package/node_modules/@buddi/core/dist/notifications/agent.d.ts.map +1 -1
- package/node_modules/@buddi/core/dist/notifications/agent.js +2 -0
- package/node_modules/@buddi/core/dist/notifications/agent.js.map +1 -1
- package/node_modules/@buddi/core/dist/notifications/index.d.ts +1 -0
- package/node_modules/@buddi/core/dist/notifications/index.d.ts.map +1 -1
- package/node_modules/@buddi/core/dist/notifications/index.js +1 -0
- package/node_modules/@buddi/core/dist/notifications/index.js.map +1 -1
- package/node_modules/@buddi/core/dist/notifications/needs.d.ts +49 -0
- package/node_modules/@buddi/core/dist/notifications/needs.d.ts.map +1 -0
- package/node_modules/@buddi/core/dist/notifications/needs.js +41 -0
- package/node_modules/@buddi/core/dist/notifications/needs.js.map +1 -0
- package/node_modules/@buddi/core/dist/notifications/notify.d.ts.map +1 -1
- package/node_modules/@buddi/core/dist/notifications/notify.js +16 -7
- package/node_modules/@buddi/core/dist/notifications/notify.js.map +1 -1
- package/node_modules/@buddi/core/dist/notifications/store.d.ts.map +1 -1
- package/node_modules/@buddi/core/dist/notifications/store.js +2 -1
- package/node_modules/@buddi/core/dist/notifications/store.js.map +1 -1
- package/node_modules/@buddi/core/dist/notifications/types.d.ts +10 -0
- package/node_modules/@buddi/core/dist/notifications/types.d.ts.map +1 -1
- package/node_modules/@buddi/core/dist/notifications/types.js.map +1 -1
- package/node_modules/@buddi/core/dist/offers/store.d.ts.map +1 -1
- package/node_modules/@buddi/core/dist/offers/store.js +9 -4
- package/node_modules/@buddi/core/dist/offers/store.js.map +1 -1
- package/node_modules/@buddi/core/dist/offers/types.d.ts +24 -1
- package/node_modules/@buddi/core/dist/offers/types.d.ts.map +1 -1
- package/node_modules/@buddi/core/dist/offers/types.js +23 -1
- package/node_modules/@buddi/core/dist/offers/types.js.map +1 -1
- package/node_modules/@buddi/core/dist/owner-timezone.d.ts +20 -22
- package/node_modules/@buddi/core/dist/owner-timezone.d.ts.map +1 -1
- package/node_modules/@buddi/core/dist/owner-timezone.js +17 -25
- package/node_modules/@buddi/core/dist/owner-timezone.js.map +1 -1
- package/node_modules/@buddi/core/dist/plugin/version.d.ts +1 -1
- package/node_modules/@buddi/core/dist/plugin/version.js +1 -1
- package/node_modules/@buddi/core/dist/scheduler/missions.d.ts +86 -11
- package/node_modules/@buddi/core/dist/scheduler/missions.d.ts.map +1 -1
- package/node_modules/@buddi/core/dist/scheduler/missions.js +160 -36
- package/node_modules/@buddi/core/dist/scheduler/missions.js.map +1 -1
- package/node_modules/@buddi/core/dist/scheduler/runner.d.ts.map +1 -1
- package/node_modules/@buddi/core/dist/scheduler/runner.js +6 -1
- package/node_modules/@buddi/core/dist/scheduler/runner.js.map +1 -1
- package/node_modules/@buddi/core/dist/scheduler/types.d.ts +22 -0
- package/node_modules/@buddi/core/dist/scheduler/types.d.ts.map +1 -1
- package/node_modules/@buddi/core/dist/scheduler/types.js +6 -0
- package/node_modules/@buddi/core/dist/scheduler/types.js.map +1 -1
- package/node_modules/@buddi/core/dist/web-settings.d.ts +13 -0
- package/node_modules/@buddi/core/dist/web-settings.d.ts.map +1 -1
- package/node_modules/@buddi/core/dist/web-settings.js +26 -0
- package/node_modules/@buddi/core/dist/web-settings.js.map +1 -1
- package/node_modules/@buddi/core/dist/widgets.d.ts +13 -5
- package/node_modules/@buddi/core/dist/widgets.d.ts.map +1 -1
- package/node_modules/@buddi/core/dist/widgets.js +10 -1
- package/node_modules/@buddi/core/dist/widgets.js.map +1 -1
- package/node_modules/@buddi/core/migrations/068_notification_action.sql +12 -0
- package/node_modules/@buddi/core/migrations/069_schedule_zone_explicit.sql +18 -0
- package/node_modules/@buddi/core/migrations/070_offer_handoff.sql +15 -0
- package/node_modules/@buddi/core/migrations/071_mission_lifespan.sql +19 -0
- package/node_modules/@buddi/gateway/dist/.tsbuildinfo +1 -1
- package/node_modules/@buddi/gateway/dist/agents/canvas.d.ts +6 -6
- package/node_modules/@buddi/gateway/dist/agents/catalogue-package.d.ts +313 -0
- package/node_modules/@buddi/gateway/dist/agents/catalogue-package.d.ts.map +1 -0
- package/node_modules/@buddi/gateway/dist/agents/catalogue-package.js +356 -0
- package/node_modules/@buddi/gateway/dist/agents/catalogue-package.js.map +1 -0
- package/node_modules/@buddi/gateway/dist/agents/learning-digest.d.ts +29 -7
- package/node_modules/@buddi/gateway/dist/agents/learning-digest.d.ts.map +1 -1
- package/node_modules/@buddi/gateway/dist/agents/learning-digest.js +87 -38
- package/node_modules/@buddi/gateway/dist/agents/learning-digest.js.map +1 -1
- package/node_modules/@buddi/gateway/dist/agents/owner-tools.d.ts.map +1 -1
- package/node_modules/@buddi/gateway/dist/agents/owner-tools.js +11 -1
- package/node_modules/@buddi/gateway/dist/agents/owner-tools.js.map +1 -1
- package/node_modules/@buddi/gateway/dist/agents/platform-catalogue.d.ts +361 -0
- package/node_modules/@buddi/gateway/dist/agents/platform-catalogue.d.ts.map +1 -0
- package/node_modules/@buddi/gateway/dist/agents/platform-catalogue.js +1021 -0
- package/node_modules/@buddi/gateway/dist/agents/platform-catalogue.js.map +1 -0
- package/node_modules/@buddi/gateway/dist/agents/platform-names.d.ts.map +1 -1
- package/node_modules/@buddi/gateway/dist/agents/platform-names.js +3 -0
- package/node_modules/@buddi/gateway/dist/agents/platform-names.js.map +1 -1
- package/node_modules/@buddi/gateway/dist/agents/platform.d.ts +62 -25
- package/node_modules/@buddi/gateway/dist/agents/platform.d.ts.map +1 -1
- package/node_modules/@buddi/gateway/dist/agents/platform.js +123 -29
- package/node_modules/@buddi/gateway/dist/agents/platform.js.map +1 -1
- package/node_modules/@buddi/gateway/dist/agents-cli.d.ts +1 -1
- package/node_modules/@buddi/gateway/dist/agents-cli.d.ts.map +1 -1
- package/node_modules/@buddi/gateway/dist/agents-cli.js +6 -0
- package/node_modules/@buddi/gateway/dist/agents-cli.js.map +1 -1
- package/node_modules/@buddi/gateway/dist/bootstrap.d.ts.map +1 -1
- package/node_modules/@buddi/gateway/dist/bootstrap.js +13 -1
- package/node_modules/@buddi/gateway/dist/bootstrap.js.map +1 -1
- package/node_modules/@buddi/gateway/dist/index.d.ts +1 -0
- package/node_modules/@buddi/gateway/dist/index.d.ts.map +1 -1
- package/node_modules/@buddi/gateway/dist/index.js +1 -0
- package/node_modules/@buddi/gateway/dist/index.js.map +1 -1
- package/node_modules/@buddi/gateway/dist/missions/defaults.d.ts +0 -6
- package/node_modules/@buddi/gateway/dist/missions/defaults.d.ts.map +1 -1
- package/node_modules/@buddi/gateway/dist/missions/defaults.js +4 -8
- package/node_modules/@buddi/gateway/dist/missions/defaults.js.map +1 -1
- package/node_modules/@buddi/gateway/dist/missions/execute.d.ts +6 -0
- package/node_modules/@buddi/gateway/dist/missions/execute.d.ts.map +1 -1
- package/node_modules/@buddi/gateway/dist/missions/execute.js +74 -2
- package/node_modules/@buddi/gateway/dist/missions/execute.js.map +1 -1
- package/node_modules/@buddi/gateway/dist/missions/reminders.d.ts +10 -0
- package/node_modules/@buddi/gateway/dist/missions/reminders.d.ts.map +1 -1
- package/node_modules/@buddi/gateway/dist/missions/reminders.js +86 -17
- package/node_modules/@buddi/gateway/dist/missions/reminders.js.map +1 -1
- package/node_modules/@buddi/gateway/dist/missions/zone-provenance.d.ts +13 -0
- package/node_modules/@buddi/gateway/dist/missions/zone-provenance.d.ts.map +1 -0
- package/node_modules/@buddi/gateway/dist/missions/zone-provenance.js +31 -0
- package/node_modules/@buddi/gateway/dist/missions/zone-provenance.js.map +1 -0
- package/node_modules/@buddi/gateway/dist/missions-cli.js +2 -2
- package/node_modules/@buddi/gateway/dist/missions-cli.js.map +1 -1
- package/node_modules/@buddi/gateway/dist/plugins/load.d.ts.map +1 -1
- package/node_modules/@buddi/gateway/dist/plugins/load.js +12 -5
- package/node_modules/@buddi/gateway/dist/plugins/load.js.map +1 -1
- package/node_modules/@buddi/gateway/dist/plugins/provenance.d.ts +35 -1
- package/node_modules/@buddi/gateway/dist/plugins/provenance.d.ts.map +1 -1
- package/node_modules/@buddi/gateway/dist/plugins/provenance.js +39 -1
- package/node_modules/@buddi/gateway/dist/plugins/provenance.js.map +1 -1
- package/node_modules/@buddi/gateway/dist/serve.d.ts.map +1 -1
- package/node_modules/@buddi/gateway/dist/serve.js +10 -10
- package/node_modules/@buddi/gateway/dist/serve.js.map +1 -1
- package/node_modules/@buddi/gateway/dist/surfaces/handoff.d.ts +62 -0
- package/node_modules/@buddi/gateway/dist/surfaces/handoff.d.ts.map +1 -0
- package/node_modules/@buddi/gateway/dist/surfaces/handoff.js +121 -0
- package/node_modules/@buddi/gateway/dist/surfaces/handoff.js.map +1 -0
- package/node_modules/@buddi/gateway/dist/surfaces/offered-actions.d.ts +2 -0
- package/node_modules/@buddi/gateway/dist/surfaces/offered-actions.d.ts.map +1 -1
- package/node_modules/@buddi/gateway/dist/surfaces/offered-actions.js +1 -1
- package/node_modules/@buddi/gateway/dist/surfaces/offered-actions.js.map +1 -1
- package/node_modules/@buddi/gateway/dist/telegram/channel.d.ts +11 -1
- package/node_modules/@buddi/gateway/dist/telegram/channel.d.ts.map +1 -1
- package/node_modules/@buddi/gateway/dist/telegram/channel.js +13 -2
- package/node_modules/@buddi/gateway/dist/telegram/channel.js.map +1 -1
- package/node_modules/@buddi/gateway/dist/telegram/main.d.ts.map +1 -1
- package/node_modules/@buddi/gateway/dist/telegram/main.js +7 -1
- package/node_modules/@buddi/gateway/dist/telegram/main.js.map +1 -1
- package/node_modules/@buddi/gateway/dist/telegram/surface.d.ts +9 -1
- package/node_modules/@buddi/gateway/dist/telegram/surface.d.ts.map +1 -1
- package/node_modules/@buddi/gateway/dist/telegram/surface.js +58 -6
- package/node_modules/@buddi/gateway/dist/telegram/surface.js.map +1 -1
- package/node_modules/@buddi/gateway/dist/web/agent-offers.d.ts +0 -30
- package/node_modules/@buddi/gateway/dist/web/agent-offers.d.ts.map +1 -1
- package/node_modules/@buddi/gateway/dist/web/agent-offers.js +1 -64
- package/node_modules/@buddi/gateway/dist/web/agent-offers.js.map +1 -1
- package/node_modules/@buddi/gateway/dist/web/api-routes.d.ts +1 -0
- package/node_modules/@buddi/gateway/dist/web/api-routes.d.ts.map +1 -1
- package/node_modules/@buddi/gateway/dist/web/api-routes.js +126 -7
- package/node_modules/@buddi/gateway/dist/web/api-routes.js.map +1 -1
- package/node_modules/@buddi/gateway/dist/web/catalogue-source.d.ts +33 -0
- package/node_modules/@buddi/gateway/dist/web/catalogue-source.d.ts.map +1 -0
- package/node_modules/@buddi/gateway/dist/web/catalogue-source.js +124 -0
- package/node_modules/@buddi/gateway/dist/web/catalogue-source.js.map +1 -0
- package/node_modules/@buddi/gateway/dist/web/catalogue.d.ts +155 -0
- package/node_modules/@buddi/gateway/dist/web/catalogue.d.ts.map +1 -0
- package/node_modules/@buddi/gateway/dist/web/catalogue.js +734 -0
- package/node_modules/@buddi/gateway/dist/web/catalogue.js.map +1 -0
- package/node_modules/@buddi/gateway/dist/web/chat.d.ts +3 -1
- package/node_modules/@buddi/gateway/dist/web/chat.d.ts.map +1 -1
- package/node_modules/@buddi/gateway/dist/web/chat.js +8 -1
- package/node_modules/@buddi/gateway/dist/web/chat.js.map +1 -1
- package/node_modules/@buddi/gateway/dist/web/client-key.d.ts +24 -0
- package/node_modules/@buddi/gateway/dist/web/client-key.d.ts.map +1 -0
- package/node_modules/@buddi/gateway/dist/web/client-key.js +17 -0
- package/node_modules/@buddi/gateway/dist/web/client-key.js.map +1 -0
- package/node_modules/@buddi/gateway/dist/web/lock.d.ts +5 -1
- package/node_modules/@buddi/gateway/dist/web/lock.d.ts.map +1 -1
- package/node_modules/@buddi/gateway/dist/web/lock.js +4 -15
- package/node_modules/@buddi/gateway/dist/web/lock.js.map +1 -1
- package/node_modules/@buddi/gateway/dist/web/market.d.ts +1 -0
- package/node_modules/@buddi/gateway/dist/web/market.d.ts.map +1 -1
- package/node_modules/@buddi/gateway/dist/web/market.js +6 -0
- package/node_modules/@buddi/gateway/dist/web/market.js.map +1 -1
- package/node_modules/@buddi/gateway/dist/web/needs-you.d.ts +36 -0
- package/node_modules/@buddi/gateway/dist/web/needs-you.d.ts.map +1 -0
- package/node_modules/@buddi/gateway/dist/web/needs-you.js +65 -0
- package/node_modules/@buddi/gateway/dist/web/needs-you.js.map +1 -0
- package/node_modules/@buddi/gateway/dist/web/notifications.d.ts +9 -1
- package/node_modules/@buddi/gateway/dist/web/notifications.d.ts.map +1 -1
- package/node_modules/@buddi/gateway/dist/web/notifications.js +14 -3
- package/node_modules/@buddi/gateway/dist/web/notifications.js.map +1 -1
- package/node_modules/@buddi/gateway/dist/web/read.d.ts +27 -1
- package/node_modules/@buddi/gateway/dist/web/read.d.ts.map +1 -1
- package/node_modules/@buddi/gateway/dist/web/read.js +57 -8
- package/node_modules/@buddi/gateway/dist/web/read.js.map +1 -1
- package/node_modules/@buddi/gateway/dist/web/server.d.ts.map +1 -1
- package/node_modules/@buddi/gateway/dist/web/server.js +165 -13
- package/node_modules/@buddi/gateway/dist/web/server.js.map +1 -1
- package/node_modules/@buddi/gateway/dist/web/skills.d.ts +120 -0
- package/node_modules/@buddi/gateway/dist/web/skills.d.ts.map +1 -0
- package/node_modules/@buddi/gateway/dist/web/skills.js +672 -0
- package/node_modules/@buddi/gateway/dist/web/skills.js.map +1 -0
- package/node_modules/@buddi/gateway/dist/web/take-on.d.ts +35 -1
- package/node_modules/@buddi/gateway/dist/web/take-on.d.ts.map +1 -1
- package/node_modules/@buddi/gateway/dist/web/take-on.js +76 -51
- package/node_modules/@buddi/gateway/dist/web/take-on.js.map +1 -1
- package/node_modules/@buddi/gateway/dist/web/write.d.ts +9 -1
- package/node_modules/@buddi/gateway/dist/web/write.d.ts.map +1 -1
- package/node_modules/@buddi/gateway/dist/web/write.js +39 -2
- package/node_modules/@buddi/gateway/dist/web/write.js.map +1 -1
- package/node_modules/@buddi/gateway/package.json +0 -1
- package/node_modules/@buddi/install/dist/.tsbuildinfo +1 -1
- package/node_modules/@buddi/install/dist/doctor-timezone.d.ts +17 -0
- package/node_modules/@buddi/install/dist/doctor-timezone.d.ts.map +1 -0
- package/node_modules/@buddi/install/dist/doctor-timezone.js +34 -0
- package/node_modules/@buddi/install/dist/doctor-timezone.js.map +1 -0
- package/node_modules/@buddi/install/dist/launcher.d.ts.map +1 -1
- package/node_modules/@buddi/install/dist/launcher.js +3 -0
- package/node_modules/@buddi/install/dist/launcher.js.map +1 -1
- package/node_modules/@buddi/runtime/dist/.tsbuildinfo +1 -1
- package/node_modules/@buddi/tool-artifacts/dist/.tsbuildinfo +1 -1
- package/node_modules/@buddi/tool-browser/dist/.tsbuildinfo +1 -1
- package/node_modules/@buddi/tool-email/dist/.tsbuildinfo +1 -1
- package/node_modules/@buddi/tool-email/dist/needs-you.d.ts +4 -1
- package/node_modules/@buddi/tool-email/dist/needs-you.d.ts.map +1 -1
- package/node_modules/@buddi/tool-email/dist/needs-you.js +2 -0
- package/node_modules/@buddi/tool-email/dist/needs-you.js.map +1 -1
- package/node_modules/@buddi/tool-email/migrations/026_attention_filed.sql +89 -0
- package/node_modules/@buddi/tool-host/dist/.tsbuildinfo +1 -1
- package/node_modules/@buddi/tool-mcp/dist/.tsbuildinfo +1 -1
- package/node_modules/@buddi/tool-memory/dist/.tsbuildinfo +1 -1
- package/node_modules/@buddi/tool-web/dist/.tsbuildinfo +1 -1
- package/package.json +2 -2
- package/packages/cli/dist/.tsbuildinfo +1 -1
- package/packages/cli/dist/agents-catalogue-cmd.d.ts +50 -0
- package/packages/cli/dist/agents-catalogue-cmd.d.ts.map +1 -0
- package/packages/cli/dist/agents-catalogue-cmd.js +328 -0
- package/packages/cli/dist/agents-catalogue-cmd.js.map +1 -0
- package/packages/cli/dist/args.d.ts +5 -0
- package/packages/cli/dist/args.d.ts.map +1 -1
- package/packages/cli/dist/args.js +8 -0
- package/packages/cli/dist/args.js.map +1 -1
- package/packages/cli/dist/commands.d.ts.map +1 -1
- package/packages/cli/dist/commands.js +63 -1
- package/packages/cli/dist/commands.js.map +1 -1
- package/packages/cli/dist/doctor-probes.d.ts.map +1 -1
- package/packages/cli/dist/doctor-probes.js +4 -11
- package/packages/cli/dist/doctor-probes.js.map +1 -1
- package/packages/cli/dist/doctor.d.ts +16 -0
- package/packages/cli/dist/doctor.d.ts.map +1 -1
- package/packages/cli/dist/doctor.js +30 -0
- package/packages/cli/dist/doctor.js.map +1 -1
- package/packages/cli/dist/main.d.ts.map +1 -1
- package/packages/cli/dist/main.js +44 -9
- package/packages/cli/dist/main.js.map +1 -1
- package/packages/cli/dist/mcp/tools.d.ts.map +1 -1
- package/packages/cli/dist/mcp/tools.js +3 -1
- package/packages/cli/dist/mcp/tools.js.map +1 -1
- package/packages/cli/dist/skills-cmd.d.ts +15 -0
- package/packages/cli/dist/skills-cmd.d.ts.map +1 -0
- package/packages/cli/dist/skills-cmd.js +54 -0
- package/packages/cli/dist/skills-cmd.js.map +1 -0
- package/packages/cli/dist/status.d.ts +15 -9
- package/packages/cli/dist/status.d.ts.map +1 -1
- package/packages/cli/dist/status.js +6 -11
- package/packages/cli/dist/status.js.map +1 -1
- package/packages/core/dist/.tsbuildinfo +1 -1
- package/packages/core/dist/actions/store.d.ts +8 -0
- package/packages/core/dist/actions/store.d.ts.map +1 -1
- package/packages/core/dist/actions/store.js +13 -0
- package/packages/core/dist/actions/store.js.map +1 -1
- package/packages/core/dist/agents/catalog.d.ts +11 -3
- package/packages/core/dist/agents/catalog.d.ts.map +1 -1
- package/packages/core/dist/agents/catalog.js +58 -10
- package/packages/core/dist/agents/catalog.js.map +1 -1
- package/packages/core/dist/agents/frontmatter.d.ts +1 -1
- package/packages/core/dist/agents/frontmatter.d.ts.map +1 -1
- package/packages/core/dist/agents/frontmatter.js +1 -1
- package/packages/core/dist/agents/frontmatter.js.map +1 -1
- package/packages/core/dist/agents/skills.d.ts +29 -3
- package/packages/core/dist/agents/skills.d.ts.map +1 -1
- package/packages/core/dist/agents/skills.js +49 -2
- package/packages/core/dist/agents/skills.js.map +1 -1
- package/packages/core/dist/clock-widget.d.ts.map +1 -1
- package/packages/core/dist/clock-widget.js +5 -3
- package/packages/core/dist/clock-widget.js.map +1 -1
- package/packages/core/dist/host/build.d.ts.map +1 -1
- package/packages/core/dist/host/build.js +11 -0
- package/packages/core/dist/host/build.js.map +1 -1
- package/packages/core/dist/host/types.d.ts +7 -0
- package/packages/core/dist/host/types.d.ts.map +1 -1
- package/packages/core/dist/learning/store.d.ts +7 -0
- package/packages/core/dist/learning/store.d.ts.map +1 -1
- package/packages/core/dist/learning/store.js +6 -0
- package/packages/core/dist/learning/store.js.map +1 -1
- package/packages/core/dist/notifications/agent.d.ts +7 -0
- package/packages/core/dist/notifications/agent.d.ts.map +1 -1
- package/packages/core/dist/notifications/agent.js +2 -0
- package/packages/core/dist/notifications/agent.js.map +1 -1
- package/packages/core/dist/notifications/index.d.ts +1 -0
- package/packages/core/dist/notifications/index.d.ts.map +1 -1
- package/packages/core/dist/notifications/index.js +1 -0
- package/packages/core/dist/notifications/index.js.map +1 -1
- package/packages/core/dist/notifications/needs.d.ts +49 -0
- package/packages/core/dist/notifications/needs.d.ts.map +1 -0
- package/packages/core/dist/notifications/needs.js +41 -0
- package/packages/core/dist/notifications/needs.js.map +1 -0
- package/packages/core/dist/notifications/notify.d.ts.map +1 -1
- package/packages/core/dist/notifications/notify.js +16 -7
- package/packages/core/dist/notifications/notify.js.map +1 -1
- package/packages/core/dist/notifications/store.d.ts.map +1 -1
- package/packages/core/dist/notifications/store.js +2 -1
- package/packages/core/dist/notifications/store.js.map +1 -1
- package/packages/core/dist/notifications/types.d.ts +10 -0
- package/packages/core/dist/notifications/types.d.ts.map +1 -1
- package/packages/core/dist/notifications/types.js.map +1 -1
- package/packages/core/dist/offers/store.d.ts.map +1 -1
- package/packages/core/dist/offers/store.js +9 -4
- package/packages/core/dist/offers/store.js.map +1 -1
- package/packages/core/dist/offers/types.d.ts +24 -1
- package/packages/core/dist/offers/types.d.ts.map +1 -1
- package/packages/core/dist/offers/types.js +23 -1
- package/packages/core/dist/offers/types.js.map +1 -1
- package/packages/core/dist/owner-timezone.d.ts +20 -22
- package/packages/core/dist/owner-timezone.d.ts.map +1 -1
- package/packages/core/dist/owner-timezone.js +17 -25
- package/packages/core/dist/owner-timezone.js.map +1 -1
- package/packages/core/dist/plugin/version.d.ts +1 -1
- package/packages/core/dist/plugin/version.js +1 -1
- package/packages/core/dist/scheduler/missions.d.ts +86 -11
- package/packages/core/dist/scheduler/missions.d.ts.map +1 -1
- package/packages/core/dist/scheduler/missions.js +160 -36
- package/packages/core/dist/scheduler/missions.js.map +1 -1
- package/packages/core/dist/scheduler/runner.d.ts.map +1 -1
- package/packages/core/dist/scheduler/runner.js +6 -1
- package/packages/core/dist/scheduler/runner.js.map +1 -1
- package/packages/core/dist/scheduler/types.d.ts +22 -0
- package/packages/core/dist/scheduler/types.d.ts.map +1 -1
- package/packages/core/dist/scheduler/types.js +6 -0
- package/packages/core/dist/scheduler/types.js.map +1 -1
- package/packages/core/dist/web-settings.d.ts +13 -0
- package/packages/core/dist/web-settings.d.ts.map +1 -1
- package/packages/core/dist/web-settings.js +26 -0
- package/packages/core/dist/web-settings.js.map +1 -1
- package/packages/core/dist/widgets.d.ts +13 -5
- package/packages/core/dist/widgets.d.ts.map +1 -1
- package/packages/core/dist/widgets.js +10 -1
- package/packages/core/dist/widgets.js.map +1 -1
- package/packages/core/migrations/068_notification_action.sql +12 -0
- package/packages/core/migrations/069_schedule_zone_explicit.sql +18 -0
- package/packages/core/migrations/070_offer_handoff.sql +15 -0
- package/packages/core/migrations/071_mission_lifespan.sql +19 -0
- package/packages/gateway/dist/.tsbuildinfo +1 -1
- package/packages/gateway/dist/agents/canvas.d.ts +6 -6
- package/packages/gateway/dist/agents/catalogue-package.d.ts +313 -0
- package/packages/gateway/dist/agents/catalogue-package.d.ts.map +1 -0
- package/packages/gateway/dist/agents/catalogue-package.js +356 -0
- package/packages/gateway/dist/agents/catalogue-package.js.map +1 -0
- package/packages/gateway/dist/agents/learning-digest.d.ts +29 -7
- package/packages/gateway/dist/agents/learning-digest.d.ts.map +1 -1
- package/packages/gateway/dist/agents/learning-digest.js +87 -38
- package/packages/gateway/dist/agents/learning-digest.js.map +1 -1
- package/packages/gateway/dist/agents/owner-tools.d.ts.map +1 -1
- package/packages/gateway/dist/agents/owner-tools.js +11 -1
- package/packages/gateway/dist/agents/owner-tools.js.map +1 -1
- package/packages/gateway/dist/agents/platform-catalogue.d.ts +361 -0
- package/packages/gateway/dist/agents/platform-catalogue.d.ts.map +1 -0
- package/packages/gateway/dist/agents/platform-catalogue.js +1021 -0
- package/packages/gateway/dist/agents/platform-catalogue.js.map +1 -0
- package/packages/gateway/dist/agents/platform-names.d.ts.map +1 -1
- package/packages/gateway/dist/agents/platform-names.js +3 -0
- package/packages/gateway/dist/agents/platform-names.js.map +1 -1
- package/packages/gateway/dist/agents/platform.d.ts +62 -25
- package/packages/gateway/dist/agents/platform.d.ts.map +1 -1
- package/packages/gateway/dist/agents/platform.js +123 -29
- package/packages/gateway/dist/agents/platform.js.map +1 -1
- package/packages/gateway/dist/agents-cli.d.ts +1 -1
- package/packages/gateway/dist/agents-cli.d.ts.map +1 -1
- package/packages/gateway/dist/agents-cli.js +6 -0
- package/packages/gateway/dist/agents-cli.js.map +1 -1
- package/packages/gateway/dist/bootstrap.d.ts.map +1 -1
- package/packages/gateway/dist/bootstrap.js +13 -1
- package/packages/gateway/dist/bootstrap.js.map +1 -1
- package/packages/gateway/dist/index.d.ts +1 -0
- package/packages/gateway/dist/index.d.ts.map +1 -1
- package/packages/gateway/dist/index.js +1 -0
- package/packages/gateway/dist/index.js.map +1 -1
- package/packages/gateway/dist/missions/defaults.d.ts +0 -6
- package/packages/gateway/dist/missions/defaults.d.ts.map +1 -1
- package/packages/gateway/dist/missions/defaults.js +4 -8
- package/packages/gateway/dist/missions/defaults.js.map +1 -1
- package/packages/gateway/dist/missions/execute.d.ts +6 -0
- package/packages/gateway/dist/missions/execute.d.ts.map +1 -1
- package/packages/gateway/dist/missions/execute.js +74 -2
- package/packages/gateway/dist/missions/execute.js.map +1 -1
- package/packages/gateway/dist/missions/reminders.d.ts +10 -0
- package/packages/gateway/dist/missions/reminders.d.ts.map +1 -1
- package/packages/gateway/dist/missions/reminders.js +86 -17
- package/packages/gateway/dist/missions/reminders.js.map +1 -1
- package/packages/gateway/dist/missions/zone-provenance.d.ts +13 -0
- package/packages/gateway/dist/missions/zone-provenance.d.ts.map +1 -0
- package/packages/gateway/dist/missions/zone-provenance.js +31 -0
- package/packages/gateway/dist/missions/zone-provenance.js.map +1 -0
- package/packages/gateway/dist/missions-cli.js +2 -2
- package/packages/gateway/dist/missions-cli.js.map +1 -1
- package/packages/gateway/dist/plugins/load.d.ts.map +1 -1
- package/packages/gateway/dist/plugins/load.js +12 -5
- package/packages/gateway/dist/plugins/load.js.map +1 -1
- package/packages/gateway/dist/plugins/provenance.d.ts +35 -1
- package/packages/gateway/dist/plugins/provenance.d.ts.map +1 -1
- package/packages/gateway/dist/plugins/provenance.js +39 -1
- package/packages/gateway/dist/plugins/provenance.js.map +1 -1
- package/packages/gateway/dist/serve.d.ts.map +1 -1
- package/packages/gateway/dist/serve.js +10 -10
- package/packages/gateway/dist/serve.js.map +1 -1
- package/packages/gateway/dist/surfaces/handoff.d.ts +62 -0
- package/packages/gateway/dist/surfaces/handoff.d.ts.map +1 -0
- package/packages/gateway/dist/surfaces/handoff.js +121 -0
- package/packages/gateway/dist/surfaces/handoff.js.map +1 -0
- package/packages/gateway/dist/surfaces/offered-actions.d.ts +2 -0
- package/packages/gateway/dist/surfaces/offered-actions.d.ts.map +1 -1
- package/packages/gateway/dist/surfaces/offered-actions.js +1 -1
- package/packages/gateway/dist/surfaces/offered-actions.js.map +1 -1
- package/packages/gateway/dist/telegram/channel.d.ts +11 -1
- package/packages/gateway/dist/telegram/channel.d.ts.map +1 -1
- package/packages/gateway/dist/telegram/channel.js +13 -2
- package/packages/gateway/dist/telegram/channel.js.map +1 -1
- package/packages/gateway/dist/telegram/main.d.ts.map +1 -1
- package/packages/gateway/dist/telegram/main.js +7 -1
- package/packages/gateway/dist/telegram/main.js.map +1 -1
- package/packages/gateway/dist/telegram/surface.d.ts +9 -1
- package/packages/gateway/dist/telegram/surface.d.ts.map +1 -1
- package/packages/gateway/dist/telegram/surface.js +58 -6
- package/packages/gateway/dist/telegram/surface.js.map +1 -1
- package/packages/gateway/dist/web/agent-offers.d.ts +0 -30
- package/packages/gateway/dist/web/agent-offers.d.ts.map +1 -1
- package/packages/gateway/dist/web/agent-offers.js +1 -64
- package/packages/gateway/dist/web/agent-offers.js.map +1 -1
- package/packages/gateway/dist/web/api-routes.d.ts +1 -0
- package/packages/gateway/dist/web/api-routes.d.ts.map +1 -1
- package/packages/gateway/dist/web/api-routes.js +126 -7
- package/packages/gateway/dist/web/api-routes.js.map +1 -1
- package/packages/gateway/dist/web/catalogue-source.d.ts +33 -0
- package/packages/gateway/dist/web/catalogue-source.d.ts.map +1 -0
- package/packages/gateway/dist/web/catalogue-source.js +124 -0
- package/packages/gateway/dist/web/catalogue-source.js.map +1 -0
- package/packages/gateway/dist/web/catalogue.d.ts +155 -0
- package/packages/gateway/dist/web/catalogue.d.ts.map +1 -0
- package/packages/gateway/dist/web/catalogue.js +734 -0
- package/packages/gateway/dist/web/catalogue.js.map +1 -0
- package/packages/gateway/dist/web/chat.d.ts +3 -1
- package/packages/gateway/dist/web/chat.d.ts.map +1 -1
- package/packages/gateway/dist/web/chat.js +8 -1
- package/packages/gateway/dist/web/chat.js.map +1 -1
- package/packages/gateway/dist/web/client-key.d.ts +24 -0
- package/packages/gateway/dist/web/client-key.d.ts.map +1 -0
- package/packages/gateway/dist/web/client-key.js +17 -0
- package/packages/gateway/dist/web/client-key.js.map +1 -0
- package/packages/gateway/dist/web/lock.d.ts +5 -1
- package/packages/gateway/dist/web/lock.d.ts.map +1 -1
- package/packages/gateway/dist/web/lock.js +4 -15
- package/packages/gateway/dist/web/lock.js.map +1 -1
- package/packages/gateway/dist/web/market.d.ts +1 -0
- package/packages/gateway/dist/web/market.d.ts.map +1 -1
- package/packages/gateway/dist/web/market.js +6 -0
- package/packages/gateway/dist/web/market.js.map +1 -1
- package/packages/gateway/dist/web/needs-you.d.ts +36 -0
- package/packages/gateway/dist/web/needs-you.d.ts.map +1 -0
- package/packages/gateway/dist/web/needs-you.js +65 -0
- package/packages/gateway/dist/web/needs-you.js.map +1 -0
- package/packages/gateway/dist/web/notifications.d.ts +9 -1
- package/packages/gateway/dist/web/notifications.d.ts.map +1 -1
- package/packages/gateway/dist/web/notifications.js +14 -3
- package/packages/gateway/dist/web/notifications.js.map +1 -1
- package/packages/gateway/dist/web/read.d.ts +27 -1
- package/packages/gateway/dist/web/read.d.ts.map +1 -1
- package/packages/gateway/dist/web/read.js +57 -8
- package/packages/gateway/dist/web/read.js.map +1 -1
- package/packages/gateway/dist/web/server.d.ts.map +1 -1
- package/packages/gateway/dist/web/server.js +165 -13
- package/packages/gateway/dist/web/server.js.map +1 -1
- package/packages/gateway/dist/web/skills.d.ts +120 -0
- package/packages/gateway/dist/web/skills.d.ts.map +1 -0
- package/packages/gateway/dist/web/skills.js +672 -0
- package/packages/gateway/dist/web/skills.js.map +1 -0
- package/packages/gateway/dist/web/take-on.d.ts +35 -1
- package/packages/gateway/dist/web/take-on.d.ts.map +1 -1
- package/packages/gateway/dist/web/take-on.js +76 -51
- package/packages/gateway/dist/web/take-on.js.map +1 -1
- package/packages/gateway/dist/web/write.d.ts +9 -1
- package/packages/gateway/dist/web/write.d.ts.map +1 -1
- package/packages/gateway/dist/web/write.js +39 -2
- package/packages/gateway/dist/web/write.js.map +1 -1
- package/packages/gateway/package.json +0 -1
- package/packages/install/dist/.tsbuildinfo +1 -1
- package/packages/install/dist/doctor-timezone.d.ts +17 -0
- package/packages/install/dist/doctor-timezone.d.ts.map +1 -0
- package/packages/install/dist/doctor-timezone.js +34 -0
- package/packages/install/dist/doctor-timezone.js.map +1 -0
- package/packages/install/dist/launcher.d.ts.map +1 -1
- package/packages/install/dist/launcher.js +3 -0
- package/packages/install/dist/launcher.js.map +1 -1
- package/packages/runtime/dist/.tsbuildinfo +1 -1
- package/packages/tools/artifacts/dist/.tsbuildinfo +1 -1
- package/packages/tools/browser/dist/.tsbuildinfo +1 -1
- package/packages/tools/email/dist/.tsbuildinfo +1 -1
- package/packages/tools/email/dist/needs-you.d.ts +4 -1
- package/packages/tools/email/dist/needs-you.d.ts.map +1 -1
- package/packages/tools/email/dist/needs-you.js +2 -0
- package/packages/tools/email/dist/needs-you.js.map +1 -1
- package/packages/tools/email/migrations/026_attention_filed.sql +89 -0
- package/packages/tools/host/dist/.tsbuildinfo +1 -1
- package/packages/tools/mcp/dist/.tsbuildinfo +1 -1
- package/packages/tools/memory/dist/.tsbuildinfo +1 -1
- package/packages/tools/web/dist/.tsbuildinfo +1 -1
- package/packages/web/dist/assets/index-BldmgplG.css +1 -0
- package/packages/web/dist/assets/index-C8GaSH__.js +132 -0
- package/packages/web/dist/assets/{lottie_light-Ls7i1ATS.js → lottie_light-DdwKPR04.js} +1 -1
- package/packages/web/dist/build.json +1 -1
- package/packages/web/dist/index.html +2 -2
- package/packages/web/dist/precache.json +4 -4
- package/node_modules/@buddi/gateway/dist/agents/starter-team.d.ts +0 -59
- package/node_modules/@buddi/gateway/dist/agents/starter-team.d.ts.map +0 -1
- package/node_modules/@buddi/gateway/dist/agents/starter-team.js +0 -156
- package/node_modules/@buddi/gateway/dist/agents/starter-team.js.map +0 -1
- package/node_modules/@buddi/gateway/src/agents/starter/keeper/agent.md +0 -31
- package/node_modules/@buddi/gateway/src/agents/starter/keeper/skills/keeping-a-history.md +0 -22
- package/node_modules/@buddi/gateway/src/agents/starter/planner/agent.md +0 -30
- package/node_modules/@buddi/gateway/src/agents/starter/planner/skills/holding-a-follow-up.md +0 -17
- package/node_modules/@buddi/gateway/src/agents/starter/planner/skills/writing-the-morning-brief.md +0 -32
- package/node_modules/@buddi/gateway/src/agents/starter/scout/agent.md +0 -33
- package/node_modules/@buddi/gateway/src/agents/starter/scout/skills/answering-with-sources.md +0 -23
- package/node_modules/@buddi/gateway/src/agents/starter/scout/skills/the-web-is-evidence.md +0 -25
- package/packages/gateway/dist/agents/starter-team.d.ts +0 -59
- package/packages/gateway/dist/agents/starter-team.d.ts.map +0 -1
- package/packages/gateway/dist/agents/starter-team.js +0 -156
- package/packages/gateway/dist/agents/starter-team.js.map +0 -1
- package/packages/gateway/src/agents/starter/keeper/agent.md +0 -31
- package/packages/gateway/src/agents/starter/keeper/skills/keeping-a-history.md +0 -22
- package/packages/gateway/src/agents/starter/planner/agent.md +0 -30
- package/packages/gateway/src/agents/starter/planner/skills/holding-a-follow-up.md +0 -17
- package/packages/gateway/src/agents/starter/planner/skills/writing-the-morning-brief.md +0 -32
- package/packages/gateway/src/agents/starter/scout/agent.md +0 -33
- package/packages/gateway/src/agents/starter/scout/skills/answering-with-sources.md +0 -23
- package/packages/gateway/src/agents/starter/scout/skills/the-web-is-evidence.md +0 -25
- package/packages/web/dist/assets/index-WS4UjGsy.js +0 -129
- package/packages/web/dist/assets/index-Zrt_o2UG.css +0 -1
|
@@ -0,0 +1,672 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The Skills page's server side (specs/skills-zone.md, part 1): every skill
|
|
3
|
+
* on this computer, grouped, who holds each, and the owner's writes — write a
|
|
4
|
+
* skill, take one from a single `.md`, edit its text, give it to agents or take
|
|
5
|
+
* it away, mark an uploaded one as theirs, download, delete.
|
|
6
|
+
*
|
|
7
|
+
* Skills stay files; nothing here is a store of its own.
|
|
8
|
+
*
|
|
9
|
+
* - **Yours**: the owner's shared skills folder (`private/skills`, or the
|
|
10
|
+
* packaged install's), written by hand, on this page, or uploaded; and a
|
|
11
|
+
* skill the owner put in one agent's own folder by hand.
|
|
12
|
+
* - **Learned**: kept from a learning proposal, in the agent's folder
|
|
13
|
+
* (`learned-skills.ts`); an edit is a new version, a delete keeps them.
|
|
14
|
+
* - **From plugins**: accepted from a plugin (`source: <plugin>@<version>`);
|
|
15
|
+
* its text reads only, and it is deleted with the plugin, not here.
|
|
16
|
+
* - **From the catalogue**: came with a catalogue agent, in its folder
|
|
17
|
+
* (`source: catalogue/<package>@<version>`). The owner's to change; an edit
|
|
18
|
+
* or a delete counts as an owner edit for the catalogue's update drift,
|
|
19
|
+
* because the sidecar records each skill's hash (`plugins/provenance.ts`).
|
|
20
|
+
*
|
|
21
|
+
* Grants are written in the *agent's* file, so the file stays the record: a
|
|
22
|
+
* shared skill given to some agents carries `agents: []` (it loads for nobody
|
|
23
|
+
* by itself) and each holder names it in `skills:`; one given to every agent
|
|
24
|
+
* carries no `agents` key at all. Another agent's own skill is granted by its
|
|
25
|
+
* qualified name, `<agent>/<skill>`. Every write is checked by reloading the
|
|
26
|
+
* catalog; a reload that refuses puts every file back as it was.
|
|
27
|
+
*
|
|
28
|
+
* An uploaded file is `untrusted: true` until the owner marks it as theirs,
|
|
29
|
+
* and until then its text enters the prompt fenced as outside text
|
|
30
|
+
* (`skillsSection` in core).
|
|
31
|
+
*
|
|
32
|
+
* The shipped examples (`examples/agents`, `examples/skills`) belong to the
|
|
33
|
+
* platform and are not listed.
|
|
34
|
+
*/
|
|
35
|
+
import { existsSync, mkdirSync, readdirSync, readFileSync, renameSync, rmSync, statSync } from 'node:fs';
|
|
36
|
+
import path from 'node:path';
|
|
37
|
+
import { applyFrontmatterPatch, currentSkillFile, parseAgentFile, parseSkillFile, parseYamlSubset, serializeYamlValue, skillSlug, skillVersions, skillVersionsDir, splitFrontmatter, SKILLS_DIR, } from '@buddi/core';
|
|
38
|
+
import { readProvenance } from '../plugins/provenance.js';
|
|
39
|
+
import { removeLearnedSkillFromWeb } from '../agents/learned-skills.js';
|
|
40
|
+
import { replaceBody, trashStamp, writeFilesAtomic } from '../agents/platform-files.js';
|
|
41
|
+
/** The largest skill text accepted, in characters. */
|
|
42
|
+
export const SKILL_TEXT_MAX = 50_000;
|
|
43
|
+
const TITLE_MAX = 80;
|
|
44
|
+
const DESCRIPTION_MAX = 300;
|
|
45
|
+
/** `mail@0.1.3`: what `platform.accept_plugin_skill` and a plugin's agent write in `source`. */
|
|
46
|
+
const PLUGIN_SOURCE = /^([a-z0-9][a-z0-9._-]*)@([^\s/]+)$/;
|
|
47
|
+
const CATALOGUE_SOURCE = /^catalogue\/(.+)@([^@\s]+)$/;
|
|
48
|
+
const UPLOAD_SOURCE = /^upload\/(.+)$/;
|
|
49
|
+
const fail = (status, error) => ({ status, body: { error } });
|
|
50
|
+
function readDir(dir, scope) {
|
|
51
|
+
let names;
|
|
52
|
+
try {
|
|
53
|
+
names = readdirSync(dir, { withFileTypes: true })
|
|
54
|
+
.filter((e) => e.isFile() && e.name.endsWith('.md'))
|
|
55
|
+
.map((e) => e.name)
|
|
56
|
+
.sort();
|
|
57
|
+
}
|
|
58
|
+
catch {
|
|
59
|
+
return [];
|
|
60
|
+
}
|
|
61
|
+
const out = [];
|
|
62
|
+
for (const fileName of names) {
|
|
63
|
+
const file = path.join(dir, fileName);
|
|
64
|
+
try {
|
|
65
|
+
out.push(parseSkillFile(readFileSync(file, 'utf8'), { fileName: fileName.slice(0, -3), file, scope }));
|
|
66
|
+
}
|
|
67
|
+
catch {
|
|
68
|
+
// A file the loader refuses is the catalog's to report; it is not a skill anybody holds.
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
return out;
|
|
72
|
+
}
|
|
73
|
+
function agentRecords(catalog) {
|
|
74
|
+
return catalog
|
|
75
|
+
.list()
|
|
76
|
+
.map((summary) => catalog.get(summary.id))
|
|
77
|
+
.filter((a) => a !== undefined)
|
|
78
|
+
.map((agent) => {
|
|
79
|
+
let declared = [];
|
|
80
|
+
try {
|
|
81
|
+
declared = [...(parseAgentFile(readFileSync(agent.file, 'utf8'), { file: agent.file }).frontmatter.skills ?? [])];
|
|
82
|
+
}
|
|
83
|
+
catch {
|
|
84
|
+
declared = [];
|
|
85
|
+
}
|
|
86
|
+
return { id: agent.id, handle: agent.handle, name: agent.name, file: agent.file, writable: agent.source === 'private', declared };
|
|
87
|
+
});
|
|
88
|
+
}
|
|
89
|
+
function inventory(deps, agents) {
|
|
90
|
+
const entries = readDir(deps.skillsDir, 'shared').map((skill) => ({ skill, home: null }));
|
|
91
|
+
for (const agent of agents) {
|
|
92
|
+
if (!agent.writable)
|
|
93
|
+
continue;
|
|
94
|
+
const dir = path.dirname(agent.file);
|
|
95
|
+
const sidecar = readProvenance(dir);
|
|
96
|
+
const catalogueOf = sidecar?.source === 'market' && sidecar.package ? { package: sidecar.package, version: sidecar.version } : undefined;
|
|
97
|
+
for (const skill of readDir(path.join(dir, SKILLS_DIR), 'private')) {
|
|
98
|
+
entries.push({ skill, home: agent.id, ...(catalogueOf ? { catalogueOf } : {}) });
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
return entries;
|
|
102
|
+
}
|
|
103
|
+
function idOf(entry) {
|
|
104
|
+
return entry.home === null ? entry.skill.name : `${entry.home}/${entry.skill.name}`;
|
|
105
|
+
}
|
|
106
|
+
function groupOf(entry) {
|
|
107
|
+
const { skill } = entry;
|
|
108
|
+
if (skill.learned)
|
|
109
|
+
return { group: 'learned', from: null };
|
|
110
|
+
const source = skill.source ?? '';
|
|
111
|
+
const catalogue = CATALOGUE_SOURCE.exec(source);
|
|
112
|
+
if (catalogue && entry.home !== null) {
|
|
113
|
+
return { group: 'catalogue', from: { kind: 'catalogue', package: catalogue[1], version: catalogue[2], agent: entry.home } };
|
|
114
|
+
}
|
|
115
|
+
const plugin = skill.provenance === 'imported' ? PLUGIN_SOURCE.exec(source) : null;
|
|
116
|
+
if (plugin)
|
|
117
|
+
return { group: 'plugin', from: { kind: 'plugin', plugin: plugin[1], version: plugin[2], installed: false } };
|
|
118
|
+
const upload = UPLOAD_SOURCE.exec(source);
|
|
119
|
+
return { group: 'mine', from: upload ? { kind: 'upload', filename: upload[1] } : null };
|
|
120
|
+
}
|
|
121
|
+
/** The first `# heading` of the text, else the name in words. */
|
|
122
|
+
function titleOf(skill) {
|
|
123
|
+
if (skill.title)
|
|
124
|
+
return skill.title;
|
|
125
|
+
const heading = /^#\s+(.+)$/m.exec(skill.body)?.[1]?.trim();
|
|
126
|
+
if (heading)
|
|
127
|
+
return heading;
|
|
128
|
+
const words = skill.name.replace(/-/g, ' ');
|
|
129
|
+
return words.charAt(0).toUpperCase() + words.slice(1);
|
|
130
|
+
}
|
|
131
|
+
function holdersOf(entry, agents) {
|
|
132
|
+
const { skill } = entry;
|
|
133
|
+
if (entry.home !== null) {
|
|
134
|
+
const ref = idOf(entry);
|
|
135
|
+
return {
|
|
136
|
+
every: false,
|
|
137
|
+
holders: [
|
|
138
|
+
{ agent: entry.home, how: 'home' },
|
|
139
|
+
...agents.filter((a) => a.id !== entry.home && a.declared.includes(ref)).map((a) => ({ agent: a.id, how: 'granted' })),
|
|
140
|
+
],
|
|
141
|
+
};
|
|
142
|
+
}
|
|
143
|
+
if (skill.agents === undefined)
|
|
144
|
+
return { every: true, holders: agents.map((a) => ({ agent: a.id, how: 'every' })) };
|
|
145
|
+
const holders = [];
|
|
146
|
+
for (const a of agents) {
|
|
147
|
+
if (skill.agents.includes(a.id))
|
|
148
|
+
holders.push({ agent: a.id, how: 'filter' });
|
|
149
|
+
else if (a.declared.includes(skill.name))
|
|
150
|
+
holders.push({ agent: a.id, how: 'granted' });
|
|
151
|
+
}
|
|
152
|
+
return { every: false, holders };
|
|
153
|
+
}
|
|
154
|
+
function rowOf(entry, agents, installed) {
|
|
155
|
+
const { skill } = entry;
|
|
156
|
+
const grouped = groupOf(entry);
|
|
157
|
+
const from = grouped.from?.kind === 'plugin' ? { ...grouped.from, installed: installed.has(grouped.from.plugin) } : grouped.from;
|
|
158
|
+
let updatedAt = null;
|
|
159
|
+
try {
|
|
160
|
+
updatedAt = statSync(skill.file).mtime.toISOString();
|
|
161
|
+
}
|
|
162
|
+
catch {
|
|
163
|
+
updatedAt = null;
|
|
164
|
+
}
|
|
165
|
+
const { every, holders } = holdersOf(entry, agents);
|
|
166
|
+
return {
|
|
167
|
+
id: idOf(entry),
|
|
168
|
+
name: skill.name,
|
|
169
|
+
title: titleOf(skill),
|
|
170
|
+
description: skill.description,
|
|
171
|
+
group: grouped.group,
|
|
172
|
+
file: skill.file,
|
|
173
|
+
home: entry.home,
|
|
174
|
+
every,
|
|
175
|
+
holders,
|
|
176
|
+
untrusted: !skill.untrusted ? null : skill.learned ? 'page' : 'upload',
|
|
177
|
+
provenance: skill.provenance,
|
|
178
|
+
source: skill.source ?? null,
|
|
179
|
+
created: skill.created ?? null,
|
|
180
|
+
updatedAt,
|
|
181
|
+
learned: skill.learned
|
|
182
|
+
? { by: skill.learned.agent || entry.home || '', version: skill.learned.version, edited: skill.learned.edited, keptAt: skill.learned.keptAt }
|
|
183
|
+
: null,
|
|
184
|
+
from,
|
|
185
|
+
editable: grouped.group !== 'plugin',
|
|
186
|
+
deletable: !(from?.kind === 'plugin' && from.installed),
|
|
187
|
+
shareable: entry.home === null,
|
|
188
|
+
};
|
|
189
|
+
}
|
|
190
|
+
function snapshot(deps) {
|
|
191
|
+
const agents = agentRecords(deps.catalog);
|
|
192
|
+
return { agents, entries: inventory(deps, agents), installed: new Set(deps.plugins()) };
|
|
193
|
+
}
|
|
194
|
+
function find(snap, id) {
|
|
195
|
+
return snap.entries.find((e) => idOf(e) === id);
|
|
196
|
+
}
|
|
197
|
+
const GROUP_ORDER = ['mine', 'learned', 'plugin', 'catalogue'];
|
|
198
|
+
/** `GET /api/skills`: every skill, grouped, and the agents a picker offers. */
|
|
199
|
+
export function listSkillsRoute(deps) {
|
|
200
|
+
const snap = snapshot(deps);
|
|
201
|
+
const skills = snap.entries
|
|
202
|
+
.map((e) => rowOf(e, snap.agents, snap.installed))
|
|
203
|
+
.sort((a, b) => GROUP_ORDER.indexOf(a.group) - GROUP_ORDER.indexOf(b.group) || a.title.localeCompare(b.title));
|
|
204
|
+
return { status: 200, body: { skills, agents: agentsView(snap.agents) } };
|
|
205
|
+
}
|
|
206
|
+
function agentsView(agents) {
|
|
207
|
+
return agents.map(({ id, handle, name, writable }) => ({ id, handle, name, writable }));
|
|
208
|
+
}
|
|
209
|
+
function detail(snap, entry) {
|
|
210
|
+
const row = rowOf(entry, snap.agents, snap.installed);
|
|
211
|
+
const versions = entry.skill.learned && entry.home !== null ? skillVersions(path.dirname(entry.skill.file), entry.skill.name) : [];
|
|
212
|
+
return {
|
|
213
|
+
skill: row,
|
|
214
|
+
body: entry.skill.body,
|
|
215
|
+
text: readFileSync(entry.skill.file, 'utf8'),
|
|
216
|
+
...(versions.length > 0 ? { versions } : {}),
|
|
217
|
+
/*
|
|
218
|
+
* What a delete does, for the confirmation: who stops using it, and what
|
|
219
|
+
* becomes of the file (the trash; a learned one's versions stay and it is
|
|
220
|
+
* not proposed again for 90 days; a catalogue one's next update asks
|
|
221
|
+
* before bringing it back).
|
|
222
|
+
*/
|
|
223
|
+
onDelete: {
|
|
224
|
+
stops: row.holders.map((h) => h.agent),
|
|
225
|
+
every: row.every,
|
|
226
|
+
then: row.group === 'learned' ? 'versions-kept' : row.group === 'catalogue' ? 'catalogue-asks' : 'trash',
|
|
227
|
+
},
|
|
228
|
+
agents: agentsView(snap.agents),
|
|
229
|
+
};
|
|
230
|
+
}
|
|
231
|
+
/** `GET /api/skills/:id`: one skill whole — the row, its text and the file as written. */
|
|
232
|
+
export function skillDetailRoute(deps, id) {
|
|
233
|
+
const snap = snapshot(deps);
|
|
234
|
+
const entry = find(snap, id);
|
|
235
|
+
if (!entry)
|
|
236
|
+
return fail(404, `There is no skill "${id}".`);
|
|
237
|
+
return { status: 200, body: detail(snap, entry) };
|
|
238
|
+
}
|
|
239
|
+
/** `GET /api/skills/:id/download`: the file as it is on disk. Null when there is none. */
|
|
240
|
+
export function skillDownload(deps, id) {
|
|
241
|
+
const entry = find(snapshot(deps), id);
|
|
242
|
+
if (!entry)
|
|
243
|
+
return null;
|
|
244
|
+
return { filename: `${entry.skill.name}.md`, text: readFileSync(entry.skill.file, 'utf8') };
|
|
245
|
+
}
|
|
246
|
+
/* ------------------------------------------------------------------ *
|
|
247
|
+
* Writing, checked by a reload
|
|
248
|
+
* ------------------------------------------------------------------ */
|
|
249
|
+
/**
|
|
250
|
+
* Write every file at once, then reload the catalog. A reload that refuses
|
|
251
|
+
* puts every file back (and removes the ones that were new) and answers 409
|
|
252
|
+
* with the loader's sentence: a write here never leaves an installation whose
|
|
253
|
+
* agents do not load.
|
|
254
|
+
*/
|
|
255
|
+
function commit(deps, writes, removes = []) {
|
|
256
|
+
const before = writes.map((w) => ({ path: w.path, content: existsSync(w.path) ? readFileSync(w.path, 'utf8') : null }));
|
|
257
|
+
writeFilesAtomic(writes);
|
|
258
|
+
const moved = [];
|
|
259
|
+
for (const move of removes) {
|
|
260
|
+
mkdirSync(path.dirname(move.to), { recursive: true });
|
|
261
|
+
renameSync(move.from, move.to);
|
|
262
|
+
moved.push(move);
|
|
263
|
+
}
|
|
264
|
+
if (!deps.catalog.reload)
|
|
265
|
+
return null;
|
|
266
|
+
try {
|
|
267
|
+
deps.catalog.reload();
|
|
268
|
+
return null;
|
|
269
|
+
}
|
|
270
|
+
catch (err) {
|
|
271
|
+
for (const move of moved.reverse())
|
|
272
|
+
renameSync(move.to, move.from);
|
|
273
|
+
writeFilesAtomic(before.filter((b) => b.content !== null).map((b) => ({ path: b.path, content: b.content })));
|
|
274
|
+
for (const b of before)
|
|
275
|
+
if (b.content === null)
|
|
276
|
+
rmQuiet(b.path);
|
|
277
|
+
try {
|
|
278
|
+
deps.catalog.reload();
|
|
279
|
+
}
|
|
280
|
+
catch {
|
|
281
|
+
// The previous catalog is still serving; the next load says what is wrong.
|
|
282
|
+
}
|
|
283
|
+
return err instanceof Error ? err.message : String(err);
|
|
284
|
+
}
|
|
285
|
+
}
|
|
286
|
+
function rmQuiet(file) {
|
|
287
|
+
rmSync(file, { force: true });
|
|
288
|
+
}
|
|
289
|
+
/** An agent file's `skills:` patched to `list`, the whole file checked as the loader reads it. */
|
|
290
|
+
function agentWithSkills(agent, list) {
|
|
291
|
+
const source = readFileSync(agent.file, 'utf8');
|
|
292
|
+
const unique = [...new Set(list)];
|
|
293
|
+
const text = applyFrontmatterPatch(source, { skills: unique.length === 0 ? null : unique }, agent.file);
|
|
294
|
+
parseAgentFile(text, { file: agent.file });
|
|
295
|
+
return { path: agent.file, content: text };
|
|
296
|
+
}
|
|
297
|
+
/** A skill file's front matter patched, its body kept or replaced. */
|
|
298
|
+
function patchedSkill(entry, patch, body) {
|
|
299
|
+
const source = readFileSync(entry.skill.file, 'utf8');
|
|
300
|
+
const patched = applyFrontmatterPatch(source, patch, entry.skill.file);
|
|
301
|
+
const text = body === undefined ? patched : replaceBody(patched, body, entry.skill.file);
|
|
302
|
+
parseSkillFile(text, { fileName: entry.skill.name, file: entry.skill.file });
|
|
303
|
+
return text;
|
|
304
|
+
}
|
|
305
|
+
/**
|
|
306
|
+
* The files a grant changes: the skill's own `agents` key for a shared skill,
|
|
307
|
+
* and the `skills:` line of every agent whose holding changes.
|
|
308
|
+
*/
|
|
309
|
+
function planGrant(snap, entry, every, wanted, skillText) {
|
|
310
|
+
const unknown = wanted.filter((id) => !snap.agents.some((a) => a.id === id));
|
|
311
|
+
if (unknown.length > 0)
|
|
312
|
+
return { writes: [], error: fail(400, `No agent is called ${unknown.join(', ')}.`) };
|
|
313
|
+
const ref = idOf(entry);
|
|
314
|
+
const writes = [];
|
|
315
|
+
const agentWrite = (agent, hold) => {
|
|
316
|
+
const has = agent.declared.includes(ref);
|
|
317
|
+
if (has === hold)
|
|
318
|
+
return null;
|
|
319
|
+
if (!agent.writable) {
|
|
320
|
+
return fail(409, `${agent.name} ships with buddi, so its file is not yours to change. Ask Agent Father to make it yours first; then it can be given skills.`);
|
|
321
|
+
}
|
|
322
|
+
writes.push(agentWithSkills(agent, hold ? [...agent.declared, ref] : agent.declared.filter((s) => s !== ref)));
|
|
323
|
+
return null;
|
|
324
|
+
};
|
|
325
|
+
if (entry.home !== null) {
|
|
326
|
+
if (every)
|
|
327
|
+
return { writes, error: fail(409, `"${titleOf(entry.skill)}" lives in ${entry.home}'s folder, so it is given agent by agent, not to every agent.`) };
|
|
328
|
+
if (!wanted.includes(entry.home)) {
|
|
329
|
+
return { writes, error: fail(409, `"${titleOf(entry.skill)}" lives in ${entry.home}'s folder, so ${entry.home} always uses it. Delete it to stop that.`) };
|
|
330
|
+
}
|
|
331
|
+
for (const agent of snap.agents) {
|
|
332
|
+
if (agent.id === entry.home)
|
|
333
|
+
continue;
|
|
334
|
+
const hold = wanted.includes(agent.id);
|
|
335
|
+
if (hold && !agent.declared.includes(ref)) {
|
|
336
|
+
const clash = snap.entries.find((e) => e.skill.name === entry.skill.name && e !== entry && (e.home === agent.id || (e.home === null && holdersOf(e, snap.agents).holders.some((h) => h.agent === agent.id))));
|
|
337
|
+
if (clash)
|
|
338
|
+
return { writes, error: fail(409, `${agent.name} already has a skill called "${entry.skill.name}"; one name, one procedure.`) };
|
|
339
|
+
}
|
|
340
|
+
const refused = agentWrite(agent, hold);
|
|
341
|
+
if (refused)
|
|
342
|
+
return { writes, error: refused };
|
|
343
|
+
}
|
|
344
|
+
return { writes };
|
|
345
|
+
}
|
|
346
|
+
// A shared skill: its `agents` key says "every agent" (absent) or "those that ask" ([]).
|
|
347
|
+
const patch = { agents: every ? null : [] };
|
|
348
|
+
const source = skillText ?? readFileSync(entry.skill.file, 'utf8');
|
|
349
|
+
const skillFile = applyFrontmatterPatch(source, patch, entry.skill.file);
|
|
350
|
+
parseSkillFile(skillFile, { fileName: entry.skill.name, file: entry.skill.file });
|
|
351
|
+
if (skillFile !== source || skillText !== undefined)
|
|
352
|
+
writes.push({ path: entry.skill.file, content: skillFile });
|
|
353
|
+
for (const agent of snap.agents) {
|
|
354
|
+
const hold = !every && wanted.includes(agent.id);
|
|
355
|
+
if (!agent.writable) {
|
|
356
|
+
// An example's file cannot change; it can only lose the skill by the skill's own key.
|
|
357
|
+
if (hold !== agent.declared.includes(ref) && (hold || agent.declared.includes(ref))) {
|
|
358
|
+
return { writes, error: fail(409, `${agent.name} ships with buddi, so its file is not yours to change. Ask Agent Father to make it yours first; then its skills can change.`) };
|
|
359
|
+
}
|
|
360
|
+
continue;
|
|
361
|
+
}
|
|
362
|
+
const refused = agentWrite(agent, hold);
|
|
363
|
+
if (refused)
|
|
364
|
+
return { writes, error: refused };
|
|
365
|
+
}
|
|
366
|
+
return { writes };
|
|
367
|
+
}
|
|
368
|
+
function parseGrant(body) {
|
|
369
|
+
const every = body.every === true;
|
|
370
|
+
const agents = body.agents ?? [];
|
|
371
|
+
if (!Array.isArray(agents) || !agents.every((a) => typeof a === 'string'))
|
|
372
|
+
return '`agents` must be a list of agent ids.';
|
|
373
|
+
if (body.every !== undefined && typeof body.every !== 'boolean')
|
|
374
|
+
return '`every` must be true or false.';
|
|
375
|
+
return { every, agents: [...new Set(agents)] };
|
|
376
|
+
}
|
|
377
|
+
function answer(deps, id, status = 200, extra = {}) {
|
|
378
|
+
const snap = snapshot(deps);
|
|
379
|
+
const entry = find(snap, id);
|
|
380
|
+
return { status, body: { ...(entry ? { skill: rowOf(entry, snap.agents, snap.installed) } : {}), ...extra } };
|
|
381
|
+
}
|
|
382
|
+
/** `POST /api/skills/:id/grants` `{ every?, agents }`: who uses it, written in each agent's file. */
|
|
383
|
+
export function grantSkillRoute(deps, id, body) {
|
|
384
|
+
const grant = parseGrant(body);
|
|
385
|
+
if (typeof grant === 'string')
|
|
386
|
+
return fail(400, grant);
|
|
387
|
+
const snap = snapshot(deps);
|
|
388
|
+
const entry = find(snap, id);
|
|
389
|
+
if (!entry)
|
|
390
|
+
return fail(404, `There is no skill "${id}".`);
|
|
391
|
+
const plan = planGrant(snap, entry, grant.every, grant.agents);
|
|
392
|
+
if (plan.error)
|
|
393
|
+
return plan.error;
|
|
394
|
+
const refused = commit(deps, plan.writes);
|
|
395
|
+
if (refused)
|
|
396
|
+
return fail(409, refused);
|
|
397
|
+
return answer(deps, id);
|
|
398
|
+
}
|
|
399
|
+
/* ---------------- write a new one, or take one from a .md ---------------- */
|
|
400
|
+
function oneLine(value, field, max) {
|
|
401
|
+
if (typeof value !== 'string' || value.trim() === '')
|
|
402
|
+
return { error: `\`${field}\` is required.` };
|
|
403
|
+
const line = value.replace(/\s+/g, ' ').trim();
|
|
404
|
+
if (line.length > max)
|
|
405
|
+
return { error: `\`${field}\` is at most ${max} characters.` };
|
|
406
|
+
return line;
|
|
407
|
+
}
|
|
408
|
+
/** A free name for a new shared skill: not a shared one, and not any agent's own (that would collide in its prompt). */
|
|
409
|
+
function freeName(snap, wanted) {
|
|
410
|
+
const taken = new Set(snap.entries.map((e) => e.skill.name));
|
|
411
|
+
// The owner's agents' own skills are in the inventory already; the shipped ones' are not.
|
|
412
|
+
for (const agent of snap.agents) {
|
|
413
|
+
if (agent.writable)
|
|
414
|
+
continue;
|
|
415
|
+
for (const s of readDir(path.join(path.dirname(agent.file), SKILLS_DIR), 'private'))
|
|
416
|
+
taken.add(s.name);
|
|
417
|
+
}
|
|
418
|
+
if (!taken.has(wanted))
|
|
419
|
+
return wanted;
|
|
420
|
+
for (let n = 2;; n += 1) {
|
|
421
|
+
const candidate = `${wanted.slice(0, 56)}-${n}`;
|
|
422
|
+
if (!taken.has(candidate))
|
|
423
|
+
return candidate;
|
|
424
|
+
}
|
|
425
|
+
}
|
|
426
|
+
/**
|
|
427
|
+
* `POST /api/skills` `{ title, description, body, every?, agents?, upload?: { filename, mine? } }`.
|
|
428
|
+
* The new file goes in the owner's shared skills folder; an upload not marked
|
|
429
|
+
* as theirs is `untrusted: true`.
|
|
430
|
+
*/
|
|
431
|
+
export function createSkillRoute(deps, body) {
|
|
432
|
+
const title = oneLine(body.title, 'title', TITLE_MAX);
|
|
433
|
+
if (typeof title !== 'string')
|
|
434
|
+
return fail(400, title.error);
|
|
435
|
+
const description = oneLine(body.description, 'description', DESCRIPTION_MAX);
|
|
436
|
+
if (typeof description !== 'string')
|
|
437
|
+
return fail(400, description.error);
|
|
438
|
+
if (typeof body.body !== 'string' || body.body.trim() === '')
|
|
439
|
+
return fail(400, '`body` is required: the steps the skill holds.');
|
|
440
|
+
const text = body.body.replace(/\r\n/g, '\n');
|
|
441
|
+
if (text.length > SKILL_TEXT_MAX)
|
|
442
|
+
return fail(413, `A skill is at most ${SKILL_TEXT_MAX / 1000} KB of text.`);
|
|
443
|
+
const grant = parseGrant(body);
|
|
444
|
+
if (typeof grant === 'string')
|
|
445
|
+
return fail(400, grant);
|
|
446
|
+
let upload = null;
|
|
447
|
+
if (body.upload !== undefined) {
|
|
448
|
+
const u = body.upload;
|
|
449
|
+
if (u === null || typeof u !== 'object' || typeof u.filename !== 'string')
|
|
450
|
+
return fail(400, '`upload` is `{ filename, mine? }`.');
|
|
451
|
+
const filename = path.basename(u.filename).replace(/[\r\n"]/g, '').trim();
|
|
452
|
+
if (!/\.md$/i.test(filename))
|
|
453
|
+
return fail(415, 'Only a Markdown file (.md) can be taken as a skill. Bundles (.zip) come later.');
|
|
454
|
+
upload = { filename, mine: u.mine === true };
|
|
455
|
+
}
|
|
456
|
+
const snap = snapshot(deps);
|
|
457
|
+
const name = freeName(snap, skillSlug(title));
|
|
458
|
+
const file = path.join(deps.skillsDir, `${name}.md`);
|
|
459
|
+
const today = deps.now().toISOString().slice(0, 10);
|
|
460
|
+
const lines = [
|
|
461
|
+
`name: ${name}`,
|
|
462
|
+
`title: ${serializeYamlValue(title)}`,
|
|
463
|
+
`description: ${serializeYamlValue(description)}`,
|
|
464
|
+
`provenance: ${upload && !upload.mine ? 'imported' : 'owner'}`,
|
|
465
|
+
...(upload ? [`source: ${serializeYamlValue(`upload/${upload.filename}`)}`] : []),
|
|
466
|
+
`created: "${today}"`,
|
|
467
|
+
...(grant.every ? [] : ['agents: []']),
|
|
468
|
+
...(upload && !upload.mine ? ['untrusted: true'] : []),
|
|
469
|
+
];
|
|
470
|
+
const content = `---\n${lines.join('\n')}\n---\n\n${text.trim()}\n`;
|
|
471
|
+
let skill;
|
|
472
|
+
try {
|
|
473
|
+
skill = parseSkillFile(content, { fileName: name, file, scope: 'shared' });
|
|
474
|
+
}
|
|
475
|
+
catch (err) {
|
|
476
|
+
return fail(400, err instanceof Error ? err.message : String(err));
|
|
477
|
+
}
|
|
478
|
+
const entry = { skill, home: null };
|
|
479
|
+
const plan = planGrant({ ...snap, entries: [...snap.entries, entry] }, entry, grant.every, grant.agents, content);
|
|
480
|
+
if (plan.error)
|
|
481
|
+
return plan.error;
|
|
482
|
+
const writes = plan.writes.some((w) => w.path === file) ? plan.writes : [{ path: file, content }, ...plan.writes];
|
|
483
|
+
const refused = commit(deps, writes);
|
|
484
|
+
if (refused)
|
|
485
|
+
return fail(409, refused);
|
|
486
|
+
return answer(deps, name, 201);
|
|
487
|
+
}
|
|
488
|
+
/* ---------------- edit the text ---------------- */
|
|
489
|
+
/** What an edit asks for: the whole file as the Source view shows it, or the fields. */
|
|
490
|
+
function editOf(entry, body) {
|
|
491
|
+
if (typeof body.text === 'string') {
|
|
492
|
+
const raw = body.text.replace(/\r\n/g, '\n');
|
|
493
|
+
if (raw.length > SKILL_TEXT_MAX)
|
|
494
|
+
return `A skill is at most ${SKILL_TEXT_MAX / 1000} KB of text.`;
|
|
495
|
+
if (!raw.trimStart().startsWith('---'))
|
|
496
|
+
return { body: raw, ignored: [] };
|
|
497
|
+
let fm;
|
|
498
|
+
let rest;
|
|
499
|
+
try {
|
|
500
|
+
const split = splitFrontmatter(raw.trimStart());
|
|
501
|
+
fm = parseYamlSubset(split.frontmatter);
|
|
502
|
+
rest = split.body;
|
|
503
|
+
}
|
|
504
|
+
catch (err) {
|
|
505
|
+
return err instanceof Error ? err.message : String(err);
|
|
506
|
+
}
|
|
507
|
+
if (fm.name !== undefined && fm.name !== entry.skill.name)
|
|
508
|
+
return `The name is the file's name ("${entry.skill.name}") and stays; change the title instead.`;
|
|
509
|
+
const out = {
|
|
510
|
+
body: rest,
|
|
511
|
+
ignored: Object.keys(fm).filter((k) => !['name', 'description', 'title'].includes(k) && JSON.stringify(fm[k]) !== JSON.stringify(currentKey(entry, k))),
|
|
512
|
+
};
|
|
513
|
+
if (typeof fm.description === 'string')
|
|
514
|
+
out.description = fm.description;
|
|
515
|
+
if (typeof fm.title === 'string')
|
|
516
|
+
out.title = fm.title;
|
|
517
|
+
return out;
|
|
518
|
+
}
|
|
519
|
+
if (typeof body.body !== 'string')
|
|
520
|
+
return 'Send `text` (the whole file) or `body` (the steps), with `description` and `title` if they change.';
|
|
521
|
+
if (body.body.length > SKILL_TEXT_MAX)
|
|
522
|
+
return `A skill is at most ${SKILL_TEXT_MAX / 1000} KB of text.`;
|
|
523
|
+
return {
|
|
524
|
+
body: body.body.replace(/\r\n/g, '\n'),
|
|
525
|
+
ignored: [],
|
|
526
|
+
...(typeof body.description === 'string' ? { description: body.description } : {}),
|
|
527
|
+
...(typeof body.title === 'string' ? { title: body.title } : {}),
|
|
528
|
+
};
|
|
529
|
+
}
|
|
530
|
+
function currentKey(entry, key) {
|
|
531
|
+
try {
|
|
532
|
+
const split = splitFrontmatter(readFileSync(entry.skill.file, 'utf8'));
|
|
533
|
+
return parseYamlSubset(split.frontmatter)[key];
|
|
534
|
+
}
|
|
535
|
+
catch {
|
|
536
|
+
return undefined;
|
|
537
|
+
}
|
|
538
|
+
}
|
|
539
|
+
/**
|
|
540
|
+
* `PUT /api/skills/:id` `{ text }` or `{ body, description?, title? }`.
|
|
541
|
+
* A learned skill's edit is version n+1 marked as the owner's correction (the
|
|
542
|
+
* earlier versions stay); a catalogue skill's counts as an owner edit, so the
|
|
543
|
+
* next update asks before replacing it; a plugin's reads only. The front
|
|
544
|
+
* matter's other keys (who holds it, where it came from, the untrusted mark)
|
|
545
|
+
* are not changed by an edit; they are named back in `ignored`.
|
|
546
|
+
*/
|
|
547
|
+
export function editSkillRoute(deps, id, body) {
|
|
548
|
+
const snap = snapshot(deps);
|
|
549
|
+
const entry = find(snap, id);
|
|
550
|
+
if (!entry)
|
|
551
|
+
return fail(404, `There is no skill "${id}".`);
|
|
552
|
+
const row = rowOf(entry, snap.agents, snap.installed);
|
|
553
|
+
if (!row.editable) {
|
|
554
|
+
return fail(409, `"${row.title}" comes with the ${row.from?.kind === 'plugin' ? row.from.plugin : ''} plugin, so it is changed there. To stop an agent using it, take it away.`);
|
|
555
|
+
}
|
|
556
|
+
const edit = editOf(entry, body);
|
|
557
|
+
if (typeof edit === 'string')
|
|
558
|
+
return fail(400, edit);
|
|
559
|
+
if (edit.body.trim() === '')
|
|
560
|
+
return fail(400, 'A skill needs its steps; to remove it, delete it.');
|
|
561
|
+
const patch = {};
|
|
562
|
+
if (edit.description !== undefined) {
|
|
563
|
+
const d = oneLine(edit.description, 'description', DESCRIPTION_MAX);
|
|
564
|
+
if (typeof d !== 'string')
|
|
565
|
+
return fail(400, d.error);
|
|
566
|
+
patch.description = d;
|
|
567
|
+
}
|
|
568
|
+
if (edit.title !== undefined) {
|
|
569
|
+
const t = oneLine(edit.title, 'title', TITLE_MAX);
|
|
570
|
+
if (typeof t !== 'string')
|
|
571
|
+
return fail(400, t.error);
|
|
572
|
+
patch.title = t;
|
|
573
|
+
}
|
|
574
|
+
const writes = [];
|
|
575
|
+
let version;
|
|
576
|
+
try {
|
|
577
|
+
if (entry.skill.learned && entry.home !== null) {
|
|
578
|
+
const dir = path.dirname(entry.skill.file);
|
|
579
|
+
version = Math.max(entry.skill.learned.version, ...skillVersions(dir, entry.skill.name)) + 1;
|
|
580
|
+
const text = patchedSkill(entry, { ...patch, version, edited: true }, edit.body);
|
|
581
|
+
writes.push({ path: path.join(skillVersionsDir(dir, entry.skill.name), `v${version}.md`), content: text });
|
|
582
|
+
writes.push({ path: currentSkillFile(dir, entry.skill.name), content: text });
|
|
583
|
+
}
|
|
584
|
+
else {
|
|
585
|
+
writes.push({ path: entry.skill.file, content: patchedSkill(entry, patch, edit.body) });
|
|
586
|
+
}
|
|
587
|
+
}
|
|
588
|
+
catch (err) {
|
|
589
|
+
return fail(400, err instanceof Error ? err.message : String(err));
|
|
590
|
+
}
|
|
591
|
+
const refused = commit(deps, writes);
|
|
592
|
+
if (refused)
|
|
593
|
+
return fail(409, refused);
|
|
594
|
+
return answer(deps, id, 200, {
|
|
595
|
+
...(version === undefined ? {} : { version }),
|
|
596
|
+
...(edit.ignored.length > 0 ? { ignored: edit.ignored } : {}),
|
|
597
|
+
});
|
|
598
|
+
}
|
|
599
|
+
/* ---------------- mark as mine ---------------- */
|
|
600
|
+
/** `POST /api/skills/:id/trust`: the owner has read it; its text is composed as theirs from now on. */
|
|
601
|
+
export function trustSkillRoute(deps, id) {
|
|
602
|
+
const snap = snapshot(deps);
|
|
603
|
+
const entry = find(snap, id);
|
|
604
|
+
if (!entry)
|
|
605
|
+
return fail(404, `There is no skill "${id}".`);
|
|
606
|
+
if (!entry.skill.untrusted)
|
|
607
|
+
return answer(deps, id);
|
|
608
|
+
let text;
|
|
609
|
+
try {
|
|
610
|
+
text = patchedSkill(entry, { untrusted: entry.skill.learned ? false : null });
|
|
611
|
+
}
|
|
612
|
+
catch (err) {
|
|
613
|
+
return fail(400, err instanceof Error ? err.message : String(err));
|
|
614
|
+
}
|
|
615
|
+
const refused = commit(deps, [{ path: entry.skill.file, content: text }]);
|
|
616
|
+
if (refused)
|
|
617
|
+
return fail(409, refused);
|
|
618
|
+
return answer(deps, id);
|
|
619
|
+
}
|
|
620
|
+
/* ---------------- delete ---------------- */
|
|
621
|
+
/**
|
|
622
|
+
* `DELETE /api/skills/:id`. Every agent that asked for it by name stops (its
|
|
623
|
+
* `skills:` line loses the name in the same write). A learned one's current
|
|
624
|
+
* file goes and its versions stay, and its proposal counts as discarded, so
|
|
625
|
+
* the agent does not propose it again for 90 days; anything else goes to the
|
|
626
|
+
* trash folder beside the agents. A plugin's is deleted with the plugin.
|
|
627
|
+
*/
|
|
628
|
+
export async function deleteSkillRoute(deps, id) {
|
|
629
|
+
const snap = snapshot(deps);
|
|
630
|
+
const entry = find(snap, id);
|
|
631
|
+
if (!entry)
|
|
632
|
+
return fail(404, `There is no skill "${id}".`);
|
|
633
|
+
const row = rowOf(entry, snap.agents, snap.installed);
|
|
634
|
+
if (!row.deletable && row.from?.kind === 'plugin') {
|
|
635
|
+
return fail(409, `"${row.title}" comes with the ${row.from.plugin} plugin and goes with it. To stop an agent using it, take it away.`);
|
|
636
|
+
}
|
|
637
|
+
const ref = idOf(entry);
|
|
638
|
+
const stopped = row.holders.map((h) => h.agent);
|
|
639
|
+
const writes = [];
|
|
640
|
+
for (const agent of snap.agents) {
|
|
641
|
+
if (!agent.declared.includes(ref))
|
|
642
|
+
continue;
|
|
643
|
+
if (!agent.writable) {
|
|
644
|
+
return fail(409, `${agent.name} ships with buddi and its file asks for "${entry.skill.name}", so it cannot be deleted while that file needs it.`);
|
|
645
|
+
}
|
|
646
|
+
writes.push(agentWithSkills(agent, agent.declared.filter((s) => s !== ref)));
|
|
647
|
+
}
|
|
648
|
+
if (entry.skill.learned && entry.home !== null) {
|
|
649
|
+
if (!deps.pool)
|
|
650
|
+
return fail(503, 'A learned skill is removed with its proposal, and the database is not reachable.');
|
|
651
|
+
// The references first, so the reload that follows the removal finds nothing dangling.
|
|
652
|
+
if (writes.length > 0) {
|
|
653
|
+
const refused = commit(deps, writes);
|
|
654
|
+
if (refused)
|
|
655
|
+
return fail(409, refused);
|
|
656
|
+
}
|
|
657
|
+
const removed = await removeLearnedSkillFromWeb({ pool: deps.pool, catalog: deps.catalog, now: deps.now, reload: () => deps.catalog.reload?.() }, entry.home, entry.skill.name);
|
|
658
|
+
if (!removed.ok)
|
|
659
|
+
return fail(removed.status, removed.error);
|
|
660
|
+
return {
|
|
661
|
+
status: 200,
|
|
662
|
+
body: { deleted: id, stopped, versionsKept: skillVersionsDir(path.dirname(entry.skill.file), entry.skill.name) },
|
|
663
|
+
};
|
|
664
|
+
}
|
|
665
|
+
const stamp = trashStamp(deps.now());
|
|
666
|
+
const movedTo = path.join(deps.trashRoot, 'skills', `${entry.home === null ? '' : `${entry.home}-`}${entry.skill.name}-${stamp}.md`);
|
|
667
|
+
const refused = commit(deps, writes, [{ from: entry.skill.file, to: movedTo }]);
|
|
668
|
+
if (refused)
|
|
669
|
+
return fail(409, refused);
|
|
670
|
+
return { status: 200, body: { deleted: id, stopped, movedTo } };
|
|
671
|
+
}
|
|
672
|
+
//# sourceMappingURL=skills.js.map
|