@audiofool/moondog 0.1.0 → 0.2.0-beta.3
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/LICENSE +202 -0
- package/README.md +156 -68
- package/contracts/v1/definitions.schema.json +1 -169
- package/package.json +7 -23
- package/scripts/contract-lib.mjs +0 -7
- package/scripts/contract-semantics.mjs +0 -1904
- package/scripts/moondog.mjs +285 -74
- package/src/core/apple-library-source-status.mjs +0 -16
- package/src/core/apple-projection-domain-services.mjs +253 -53
- package/src/core/application-update.mjs +320 -0
- package/src/core/capability-catalog.mjs +290 -55
- package/src/core/listener-avoids.mjs +101 -0
- package/src/core/listening-now.mjs +108 -0
- package/src/core/listening-profile-domain-services.mjs +189 -41
- package/src/core/listening-upkeep.mjs +31 -0
- package/src/core/moondog-application.mjs +2115 -107
- package/src/core/playback-preferences.mjs +97 -0
- package/src/core/spotify-listening-intent.mjs +124 -0
- package/src/core/synthetic-domain-services.mjs +24 -3
- package/src/core/track-title.mjs +107 -0
- package/src/demo/moondog-demo.mjs +4 -22
- package/src/i18n/index.mjs +285 -0
- package/src/i18n/messages/de.mjs +135 -0
- package/src/i18n/messages/en.mjs +136 -0
- package/src/i18n/messages/es.mjs +135 -0
- package/src/i18n/messages/fr.mjs +135 -0
- package/src/i18n/messages/it.mjs +135 -0
- package/src/i18n/messages/ja.mjs +135 -0
- package/src/i18n/messages/ko.mjs +135 -0
- package/src/i18n/messages/pt.mjs +135 -0
- package/src/i18n/messages/zh-Hant.mjs +135 -0
- package/src/i18n/messages/zh.mjs +135 -0
- package/src/i18n/preferences.mjs +34 -0
- package/src/i18n/screen/es.mjs +967 -0
- package/src/i18n/screen/ja.mjs +967 -0
- package/src/i18n/screen/pt.mjs +967 -0
- package/src/i18n/screen/zh.mjs +967 -0
- package/src/importers/apple-music-library/index.mjs +0 -16
- package/src/importers/apple-music-library/sqlite-projection.mjs +51 -9
- package/src/integrations/apple-music/catalog.mjs +166 -14
- package/src/integrations/apple-music/music-app.mjs +232 -0
- package/src/integrations/apple-music/storefront.mjs +28 -0
- package/src/integrations/apple-music/terminal-preview-player.mjs +221 -0
- package/src/integrations/lastfm/history.mjs +221 -0
- package/src/integrations/lastfm/settings.mjs +75 -0
- package/src/integrations/netease/ncm-cli-player.mjs +328 -0
- package/src/integrations/open-music-similarity/artist-radio.mjs +26 -18
- package/src/integrations/public-playlists.mjs +2 -1
- package/src/integrations/spotify/account-data-profile.mjs +14 -6
- package/src/integrations/spotify/authentication.mjs +149 -15
- package/src/integrations/spotify/catalog-resolver.mjs +9 -6
- package/src/integrations/spotify/connection.mjs +2 -1
- package/src/integrations/spotify/credential-store.mjs +4 -0
- package/src/integrations/spotify/extended-streaming-history.mjs +11 -11
- package/src/integrations/spotify/history-archive.mjs +1 -1
- package/src/integrations/spotify/library-snapshot.mjs +227 -0
- package/src/integrations/spotify/recent-activity.mjs +2 -0
- package/src/integrations/spotify/service.mjs +873 -69
- package/src/integrations/spotify/web-api-client.mjs +410 -127
- package/src/integrations/web/brave-web.mjs +45 -0
- package/src/integrations/web/codex-web.mjs +15 -82
- package/src/integrations/web/deepseek-web.mjs +81 -0
- package/src/integrations/web/web-research.mjs +119 -0
- package/src/integrations/web/web-result.mjs +215 -0
- package/src/integrations/youtube-music/takeout.mjs +3 -1
- package/src/memory/local-memory-store.mjs +542 -57
- package/src/profile/history-import.mjs +42 -6
- package/src/profile/listener-corrections.mjs +22 -0
- package/src/profile/listener-profile-build.mjs +461 -0
- package/src/profile/listener-profile-store.mjs +130 -0
- package/src/profile/listener-profile-verification.mjs +68 -0
- package/src/profile/listener-profile-worker.mjs +179 -0
- package/src/profile/listening-history-store.mjs +640 -17
- package/src/profile/listening-profile-projection.mjs +454 -86
- package/src/profile/local-music-data.mjs +1 -1
- package/src/profile/moondog-suggestions.mjs +184 -0
- package/src/profile/music-providers.mjs +11 -7
- package/src/profile/profile-exploration.mjs +92 -0
- package/src/profile/recorded-measures.mjs +24 -0
- package/src/profile/spotify-archive-taste.mjs +0 -4
- package/src/runtime/pi/agent-runtime.mjs +2536 -692
- package/src/runtime/pi/authentication.mjs +34 -1
- package/src/runtime/pi/configured-runtime.mjs +22 -6
- package/src/runtime/pi/conversation-name.mjs +53 -0
- package/src/runtime/pi/memory-agent-runtime.mjs +2 -2
- package/src/runtime/pi/model-catalog.mjs +28 -5
- package/src/runtime/pi/model-settings.mjs +202 -0
- package/src/runtime/pi/model-transport.mjs +10 -0
- package/src/runtime/pi/persistent-credential-store.mjs +67 -31
- package/src/runtime/pi/profile-build-runtime.mjs +161 -0
- package/src/runtime/pi/public-model-catalog.mjs +288 -0
- package/src/runtime/pi/runtime-settings.mjs +10 -2
- package/src/runtime/pi/skills/listener-profile/SKILL.md +48 -0
- package/src/runtime/pi/tool-trace.mjs +37 -0
- package/src/surfaces/cli/auth-command.mjs +12 -4
- package/src/surfaces/cli/brand-components.mjs +310 -132
- package/src/surfaces/cli/brand-theme.mjs +51 -28
- package/src/surfaces/cli/command-completions.mjs +58 -42
- package/src/surfaces/cli/format-output.mjs +199 -388
- package/src/surfaces/cli/history-import-view.mjs +292 -139
- package/src/surfaces/cli/import-guides.mjs +2 -0
- package/src/surfaces/cli/listener-profile-command.mjs +92 -0
- package/src/surfaces/cli/listening-menu.mjs +7 -4
- package/src/surfaces/cli/profile-command.mjs +30 -21
- package/src/surfaces/cli/seasons-chart.mjs +87 -0
- package/src/surfaces/cli/spotify-command.mjs +54 -6
- package/src/surfaces/cli/taste-profile-model.mjs +78 -79
- package/src/surfaces/cli/taste-profile-view.mjs +33 -26
- package/src/surfaces/cli/terminal-art.mjs +140 -35
- package/src/surfaces/cli/tui.mjs +1066 -357
- package/src/surfaces/cli/update-command.mjs +32 -0
- package/src/surfaces/cli/web-command.mjs +53 -14
- package/src/surfaces/html/tasteprint.mjs +43 -70
- package/contracts/v1/capability-policy.schema.json +0 -572
- package/contracts/v1/profile-evidence.schema.json +0 -237
- package/contracts/v1/tool-invocation.schema.json +0 -318
- package/contracts/v1/tool-receipt.schema.json +0 -1066
- package/scripts/demo-studio.mjs +0 -58
- package/src/core/apple-data-migration.mjs +0 -50
- package/src/demo/moondog-interactive-tasteprint-demo.mjs +0 -293
- package/src/demo/moondog-tasteprint-demo.mjs +0 -631
- package/src/integrations/spotify/index.mjs +0 -80
- package/src/surfaces/web/showcase.mjs +0 -272
- package/src/surfaces/web/studio-page.mjs +0 -4148
- package/src/surfaces/web/studio.mjs +0 -2288
|
@@ -1,15 +1,33 @@
|
|
|
1
|
+
import { N_ } from "../i18n/index.mjs";
|
|
2
|
+
|
|
3
|
+
// Tool labels are marked English; screens translate them when shown.
|
|
1
4
|
const catalog = [
|
|
5
|
+
{
|
|
6
|
+
id: "playback.service", version: "1", state: "enabled", effect: "write_local",
|
|
7
|
+
description: "Inspect or change the current music service through the same saved selection as the host's service picker.",
|
|
8
|
+
agent_tool: { name: "moondog_playback_service", label: N_("Choose a music service") },
|
|
9
|
+
},
|
|
10
|
+
{
|
|
11
|
+
id: "spotify.discovery.search", version: "1", state: "enabled", effect: "read_external", requires_spotify: true,
|
|
12
|
+
description: "Verify open-world music hypotheses with bounded Spotify queries, retaining a shared candidate pool.",
|
|
13
|
+
agent_tool: { name: "moondog_spotify_discover", label: N_("Discover verified Spotify tracks") },
|
|
14
|
+
},
|
|
15
|
+
{
|
|
16
|
+
id: "spotify.queue.batch", version: "1", state: "enabled", effect: "write_external", requires_spotify: true,
|
|
17
|
+
description: "Queue up to twelve verified tracks for an explicit listener request with Avoid, deduplication and partial receipts.",
|
|
18
|
+
agent_tool: { name: "moondog_spotify_queue_batch", label: N_("Queue the verified selection") },
|
|
19
|
+
},
|
|
2
20
|
{
|
|
3
21
|
id: "web.search", version: "1", state: "enabled", effect: "read_external",
|
|
4
|
-
description: "Search public music reviews, news, interviews and event information through
|
|
5
|
-
|
|
6
|
-
agent_tool: { name: "moondog_web_search", label: "Search the public web" },
|
|
22
|
+
description: "Search public music reviews, news, interviews and event information through {provider}.",
|
|
23
|
+
requires_web: "search",
|
|
24
|
+
agent_tool: { name: "moondog_web_search", label: N_("Search the public web") },
|
|
7
25
|
},
|
|
8
26
|
{
|
|
9
27
|
id: "web.read", version: "1", state: "enabled", effect: "read_external",
|
|
10
|
-
description: "Read
|
|
11
|
-
|
|
12
|
-
agent_tool: { name: "moondog_web_read", label: "Read a public web page" },
|
|
28
|
+
description: "Read a public web page with dated source attribution through {provider}.",
|
|
29
|
+
requires_web: "read",
|
|
30
|
+
agent_tool: { name: "moondog_web_read", label: N_("Read a public web page") },
|
|
13
31
|
},
|
|
14
32
|
{
|
|
15
33
|
id: "source.apple_music.status",
|
|
@@ -19,7 +37,7 @@ const catalog = [
|
|
|
19
37
|
description: "Inspect aggregate Apple Music import readiness.",
|
|
20
38
|
agent_tool: {
|
|
21
39
|
name: "moondog_source_status",
|
|
22
|
-
label: "Check your music sources",
|
|
40
|
+
label: N_("Check your music sources"),
|
|
23
41
|
},
|
|
24
42
|
},
|
|
25
43
|
{
|
|
@@ -30,7 +48,7 @@ const catalog = [
|
|
|
30
48
|
description: "Inspect evidence-backed profile readiness.",
|
|
31
49
|
agent_tool: {
|
|
32
50
|
name: "moondog_profile_status",
|
|
33
|
-
label: "Check your profile",
|
|
51
|
+
label: N_("Check your profile"),
|
|
34
52
|
},
|
|
35
53
|
},
|
|
36
54
|
{
|
|
@@ -41,7 +59,7 @@ const catalog = [
|
|
|
41
59
|
description: "Inspect conversation and long-term memory readiness.",
|
|
42
60
|
agent_tool: {
|
|
43
61
|
name: "moondog_memory_status",
|
|
44
|
-
label: "Check what I remember",
|
|
62
|
+
label: N_("Check what I remember"),
|
|
45
63
|
},
|
|
46
64
|
},
|
|
47
65
|
{
|
|
@@ -52,7 +70,7 @@ const catalog = [
|
|
|
52
70
|
description: "Inspect the Moondog capability registry.",
|
|
53
71
|
agent_tool: {
|
|
54
72
|
name: "moondog_capability_status",
|
|
55
|
-
label: "Check what I can do",
|
|
73
|
+
label: N_("Check what I can do"),
|
|
56
74
|
},
|
|
57
75
|
},
|
|
58
76
|
{
|
|
@@ -63,7 +81,7 @@ const catalog = [
|
|
|
63
81
|
description: "Inspect the configured model runtime.",
|
|
64
82
|
agent_tool: {
|
|
65
83
|
name: "moondog_runtime_status",
|
|
66
|
-
label: "Check the model connection",
|
|
84
|
+
label: N_("Check the model connection"),
|
|
67
85
|
},
|
|
68
86
|
},
|
|
69
87
|
{
|
|
@@ -75,7 +93,7 @@ const catalog = [
|
|
|
75
93
|
requires_domain_services: true,
|
|
76
94
|
agent_tool: {
|
|
77
95
|
name: "moondog_library_search",
|
|
78
|
-
label: "Search your music library",
|
|
96
|
+
label: N_("Search your music library"),
|
|
79
97
|
},
|
|
80
98
|
},
|
|
81
99
|
{
|
|
@@ -87,9 +105,27 @@ const catalog = [
|
|
|
87
105
|
requires_profile_services: true,
|
|
88
106
|
agent_tool: {
|
|
89
107
|
name: "moondog_profile_summary",
|
|
90
|
-
label: "Read your music profile",
|
|
108
|
+
label: N_("Read your music profile"),
|
|
91
109
|
},
|
|
92
110
|
},
|
|
111
|
+
{
|
|
112
|
+
id: "profile.saved", version: "1", state: "enabled", effect: "read_local",
|
|
113
|
+
description: "Read a durable listener-profile revision and trace a finding to its frozen evidence.",
|
|
114
|
+
requires_profile_build: true,
|
|
115
|
+
agent_tool: { name: "moondog_profile_saved", label: N_("Read your saved listening profile") },
|
|
116
|
+
},
|
|
117
|
+
{
|
|
118
|
+
id: "profile.build", version: "1", state: "enabled", effect: "write_local",
|
|
119
|
+
description: "Build or resume a grounded local listener-profile revision with the configured model.",
|
|
120
|
+
requires_profile_build: true,
|
|
121
|
+
agent_tool: { name: "moondog_profile_build", label: N_("Build your saved listening profile") },
|
|
122
|
+
},
|
|
123
|
+
{
|
|
124
|
+
id: "profile.explore", version: "1", state: "enabled", effect: "read_local",
|
|
125
|
+
description: "Analyze all retained profile evidence with coverage, full-library facets, search, and pagination.",
|
|
126
|
+
requires_profile_exploration: true,
|
|
127
|
+
agent_tool: { name: "moondog_profile_explore", label: N_("Explore your complete music profile") },
|
|
128
|
+
},
|
|
93
129
|
{
|
|
94
130
|
id: "profile.rediscovery",
|
|
95
131
|
version: "1",
|
|
@@ -100,7 +136,7 @@ const catalog = [
|
|
|
100
136
|
requires_rediscovery_services: true,
|
|
101
137
|
agent_tool: {
|
|
102
138
|
name: "moondog_rediscovery_candidates",
|
|
103
|
-
label: "Find music worth another listen",
|
|
139
|
+
label: N_("Find music worth another listen"),
|
|
104
140
|
},
|
|
105
141
|
},
|
|
106
142
|
{
|
|
@@ -113,7 +149,7 @@ const catalog = [
|
|
|
113
149
|
requires_historical_return_services: true,
|
|
114
150
|
agent_tool: {
|
|
115
151
|
name: "moondog_historical_return_candidates",
|
|
116
|
-
label: "Find music that came back",
|
|
152
|
+
label: N_("Find music that came back"),
|
|
117
153
|
},
|
|
118
154
|
},
|
|
119
155
|
{
|
|
@@ -126,7 +162,7 @@ const catalog = [
|
|
|
126
162
|
requires_time_capsule_services: true,
|
|
127
163
|
agent_tool: {
|
|
128
164
|
name: "moondog_time_capsule_candidates",
|
|
129
|
-
label: "Travel through your years",
|
|
165
|
+
label: N_("Travel through your years"),
|
|
130
166
|
},
|
|
131
167
|
},
|
|
132
168
|
{
|
|
@@ -139,7 +175,7 @@ const catalog = [
|
|
|
139
175
|
requires_back_to_back_services: true,
|
|
140
176
|
agent_tool: {
|
|
141
177
|
name: "moondog_back_to_back_candidates",
|
|
142
|
-
label: "Find music played back to back",
|
|
178
|
+
label: N_("Find music played back to back"),
|
|
143
179
|
},
|
|
144
180
|
},
|
|
145
181
|
{
|
|
@@ -151,7 +187,7 @@ const catalog = [
|
|
|
151
187
|
requires_profile_services: true,
|
|
152
188
|
agent_tool: {
|
|
153
189
|
name: "moondog_profile_explain",
|
|
154
|
-
label: "Look at why it's in your profile",
|
|
190
|
+
label: N_("Look at why it's in your profile"),
|
|
155
191
|
},
|
|
156
192
|
},
|
|
157
193
|
{
|
|
@@ -163,7 +199,7 @@ const catalog = [
|
|
|
163
199
|
requires_playlist_services: true,
|
|
164
200
|
agent_tool: {
|
|
165
201
|
name: "moondog_playlist_plan",
|
|
166
|
-
label: "Build a playlist plan",
|
|
202
|
+
label: N_("Build a playlist plan"),
|
|
167
203
|
},
|
|
168
204
|
},
|
|
169
205
|
{
|
|
@@ -176,7 +212,7 @@ const catalog = [
|
|
|
176
212
|
requires_music_catalog: true,
|
|
177
213
|
agent_tool: {
|
|
178
214
|
name: "moondog_music_artist_releases",
|
|
179
|
-
label: "Find current artist releases",
|
|
215
|
+
label: N_("Find current artist releases"),
|
|
180
216
|
},
|
|
181
217
|
},
|
|
182
218
|
{
|
|
@@ -189,9 +225,72 @@ const catalog = [
|
|
|
189
225
|
requires_music_discovery: true,
|
|
190
226
|
agent_tool: {
|
|
191
227
|
name: "moondog_music_catalog_search",
|
|
192
|
-
label: "Search outside your library",
|
|
228
|
+
label: N_("Search outside your library"),
|
|
193
229
|
},
|
|
194
230
|
},
|
|
231
|
+
{
|
|
232
|
+
id: "music.preview.play",
|
|
233
|
+
version: "1",
|
|
234
|
+
state: "enabled",
|
|
235
|
+
effect: "play_preview",
|
|
236
|
+
description:
|
|
237
|
+
"Play 30-second Apple Music previews of named songs or one album, as a queue in the host's player.",
|
|
238
|
+
requires_music_preview: true,
|
|
239
|
+
agent_tool: {
|
|
240
|
+
name: "moondog_music_preview",
|
|
241
|
+
label: N_("Play previews"),
|
|
242
|
+
},
|
|
243
|
+
},
|
|
244
|
+
// NetEase Cloud Music through ncm-cli. The application offers these only while NetEase is the
|
|
245
|
+
// chosen service and ncm-cli is signed in.
|
|
246
|
+
{
|
|
247
|
+
id: "netease.search",
|
|
248
|
+
version: "1",
|
|
249
|
+
state: "enabled",
|
|
250
|
+
effect: "read_external",
|
|
251
|
+
description: "Search NetEase Music for songs, with whether each one can be played.",
|
|
252
|
+
agent_tool: { name: "moondog_netease_search", label: N_("Search NetEase Music") },
|
|
253
|
+
},
|
|
254
|
+
{
|
|
255
|
+
id: "netease.play",
|
|
256
|
+
version: "1",
|
|
257
|
+
state: "enabled",
|
|
258
|
+
effect: "write_external",
|
|
259
|
+
description: "Play or queue songs on NetEase Music through ncm-cli.",
|
|
260
|
+
agent_tool: { name: "moondog_netease_play", label: N_("Play on NetEase Music") },
|
|
261
|
+
},
|
|
262
|
+
{
|
|
263
|
+
id: "netease.control",
|
|
264
|
+
version: "1",
|
|
265
|
+
state: "enabled",
|
|
266
|
+
effect: "write_external",
|
|
267
|
+
description: "Pause, resume, skip, go back, move in the song or stop NetEase Music.",
|
|
268
|
+
agent_tool: { name: "moondog_netease_control", label: N_("Control NetEase Music") },
|
|
269
|
+
},
|
|
270
|
+
{
|
|
271
|
+
id: "netease.now_playing",
|
|
272
|
+
version: "1",
|
|
273
|
+
state: "enabled",
|
|
274
|
+
effect: "read_external",
|
|
275
|
+
description: "Read what NetEase Music is playing and what is queued after it.",
|
|
276
|
+
agent_tool: { name: "moondog_netease_now_playing", label: N_("See what is playing") },
|
|
277
|
+
},
|
|
278
|
+
{
|
|
279
|
+
id: "listening.now",
|
|
280
|
+
version: "1",
|
|
281
|
+
state: "enabled",
|
|
282
|
+
effect: "read_external",
|
|
283
|
+
description: "Read what the listener plays right now in the Music app, on Spotify's active device or on NetEase, and the playlist it plays from.",
|
|
284
|
+
agent_tool: { name: "moondog_listening_now", label: N_("See what you're listening to") },
|
|
285
|
+
},
|
|
286
|
+
{
|
|
287
|
+
id: "music_app.control",
|
|
288
|
+
version: "1",
|
|
289
|
+
state: "enabled",
|
|
290
|
+
effect: "write_local",
|
|
291
|
+
description: "Pause, resume, skip or go back in the Music app on this Mac, which the listener plays themselves.",
|
|
292
|
+
agent_tool: { name: "moondog_music_app_control", label: N_("Control the Music app") },
|
|
293
|
+
},
|
|
195
294
|
{
|
|
196
295
|
id: "music.discovery.artist_similarity",
|
|
197
296
|
version: "1",
|
|
@@ -202,7 +301,7 @@ const catalog = [
|
|
|
202
301
|
requires_music_similarity: true,
|
|
203
302
|
agent_tool: {
|
|
204
303
|
name: "moondog_music_artist_similarity",
|
|
205
|
-
label: "Find music nearby",
|
|
304
|
+
label: N_("Find music nearby"),
|
|
206
305
|
},
|
|
207
306
|
},
|
|
208
307
|
{
|
|
@@ -214,7 +313,7 @@ const catalog = [
|
|
|
214
313
|
requires_memory: true,
|
|
215
314
|
agent_tool: {
|
|
216
315
|
name: "moondog_memory_recall",
|
|
217
|
-
label: "Remember what you've told me",
|
|
316
|
+
label: N_("Remember what you've told me"),
|
|
218
317
|
},
|
|
219
318
|
},
|
|
220
319
|
{
|
|
@@ -227,7 +326,7 @@ const catalog = [
|
|
|
227
326
|
requires_memory: true,
|
|
228
327
|
agent_tool: {
|
|
229
328
|
name: "moondog_memory_remember",
|
|
230
|
-
label: "Remember something you said",
|
|
329
|
+
label: N_("Remember something you said"),
|
|
231
330
|
},
|
|
232
331
|
},
|
|
233
332
|
{
|
|
@@ -239,9 +338,15 @@ const catalog = [
|
|
|
239
338
|
requires_memory: true,
|
|
240
339
|
agent_tool: {
|
|
241
340
|
name: "moondog_memory_forget",
|
|
242
|
-
label: "Forget something",
|
|
341
|
+
label: N_("Forget something"),
|
|
243
342
|
},
|
|
244
343
|
},
|
|
344
|
+
{
|
|
345
|
+
id: "taste.choice", version: "1", state: "enabled", effect: "write_local",
|
|
346
|
+
description: "Save a lasting Like or Avoid for an artist or song, or undo one, when the listener states it in their own words.",
|
|
347
|
+
requires_taste_choices: true,
|
|
348
|
+
agent_tool: { name: "moondog_taste_choice", label: N_("Save your choice") },
|
|
349
|
+
},
|
|
245
350
|
{
|
|
246
351
|
id: "spotify.history.import",
|
|
247
352
|
version: "1",
|
|
@@ -255,11 +360,24 @@ const catalog = [
|
|
|
255
360
|
version: "1",
|
|
256
361
|
state: "enabled",
|
|
257
362
|
effect: "read_external",
|
|
258
|
-
description: "Inspect
|
|
363
|
+
description: "Inspect bounded Spotify playback metadata, device capabilities, and state.",
|
|
259
364
|
requires_spotify: true,
|
|
260
365
|
agent_tool: {
|
|
261
366
|
name: "moondog_spotify_player_status",
|
|
262
|
-
label: "Check what Spotify is playing",
|
|
367
|
+
label: N_("Check what Spotify is playing"),
|
|
368
|
+
},
|
|
369
|
+
},
|
|
370
|
+
{
|
|
371
|
+
id: "spotify.player.now_playing",
|
|
372
|
+
version: "1",
|
|
373
|
+
state: "enabled",
|
|
374
|
+
effect: "read_external",
|
|
375
|
+
description:
|
|
376
|
+
"Read full Spotify now-playing metadata: track, artists, album, progress, and device.",
|
|
377
|
+
requires_spotify: true,
|
|
378
|
+
agent_tool: {
|
|
379
|
+
name: "moondog_spotify_now_playing",
|
|
380
|
+
label: N_("See what's playing in detail"),
|
|
263
381
|
},
|
|
264
382
|
},
|
|
265
383
|
{
|
|
@@ -271,7 +389,7 @@ const catalog = [
|
|
|
271
389
|
requires_spotify: true,
|
|
272
390
|
agent_tool: {
|
|
273
391
|
name: "moondog_spotify_player_control",
|
|
274
|
-
label: "Control Spotify playback",
|
|
392
|
+
label: N_("Control Spotify playback"),
|
|
275
393
|
},
|
|
276
394
|
},
|
|
277
395
|
{
|
|
@@ -279,11 +397,48 @@ const catalog = [
|
|
|
279
397
|
version: "1",
|
|
280
398
|
state: "enabled",
|
|
281
399
|
effect: "write_external",
|
|
282
|
-
description:
|
|
400
|
+
description:
|
|
401
|
+
"Add one resolved track, one explicit Spotify URI, or the pending plan to the playback queue.",
|
|
283
402
|
requires_spotify: true,
|
|
284
403
|
agent_tool: {
|
|
285
404
|
name: "moondog_spotify_queue_add",
|
|
286
|
-
label: "Add to Spotify queue",
|
|
405
|
+
label: N_("Add to Spotify queue"),
|
|
406
|
+
},
|
|
407
|
+
},
|
|
408
|
+
{
|
|
409
|
+
id: "spotify.queue.similar",
|
|
410
|
+
version: "1",
|
|
411
|
+
state: "enabled",
|
|
412
|
+
effect: "write_external",
|
|
413
|
+
description: "Queue a bounded artist-similarity selection from current Spotify playback, with filtering and partial receipts.",
|
|
414
|
+
requires_spotify: true,
|
|
415
|
+
requires_music_similarity: true,
|
|
416
|
+
agent_tool: { name: "moondog_spotify_queue_similar", label: N_("Queue more like this on Spotify") },
|
|
417
|
+
},
|
|
418
|
+
{
|
|
419
|
+
id: "spotify.queue.status",
|
|
420
|
+
version: "1",
|
|
421
|
+
state: "enabled",
|
|
422
|
+
effect: "read_external",
|
|
423
|
+
description:
|
|
424
|
+
"Inspect the current Spotify playback queue with track metadata.",
|
|
425
|
+
requires_spotify: true,
|
|
426
|
+
agent_tool: {
|
|
427
|
+
name: "moondog_spotify_queue_status",
|
|
428
|
+
label: N_("See what's queued on Spotify"),
|
|
429
|
+
},
|
|
430
|
+
},
|
|
431
|
+
{
|
|
432
|
+
id: "spotify.device.list",
|
|
433
|
+
version: "1",
|
|
434
|
+
state: "enabled",
|
|
435
|
+
effect: "read_external",
|
|
436
|
+
description:
|
|
437
|
+
"List visible Spotify Connect devices by name and type, without device identifiers.",
|
|
438
|
+
requires_spotify: true,
|
|
439
|
+
agent_tool: {
|
|
440
|
+
name: "moondog_spotify_devices",
|
|
441
|
+
label: N_("See your Spotify devices"),
|
|
287
442
|
},
|
|
288
443
|
},
|
|
289
444
|
{
|
|
@@ -291,11 +446,12 @@ const catalog = [
|
|
|
291
446
|
version: "1",
|
|
292
447
|
state: "enabled",
|
|
293
448
|
effect: "write_external",
|
|
294
|
-
description:
|
|
449
|
+
description:
|
|
450
|
+
"Transfer Spotify playback to a device the user named, or to a device ID the user pasted.",
|
|
295
451
|
requires_spotify: true,
|
|
296
452
|
agent_tool: {
|
|
297
453
|
name: "moondog_spotify_device_transfer",
|
|
298
|
-
label: "Move Spotify playback",
|
|
454
|
+
label: N_("Move Spotify playback"),
|
|
299
455
|
},
|
|
300
456
|
},
|
|
301
457
|
{
|
|
@@ -304,12 +460,54 @@ const catalog = [
|
|
|
304
460
|
state: "enabled",
|
|
305
461
|
effect: "read_external",
|
|
306
462
|
description:
|
|
307
|
-
"Resolve trusted library tracks to
|
|
463
|
+
"Resolve trusted library, history, and external catalog tracks to Spotify catalog identities by title, artist, and release.",
|
|
308
464
|
requires_spotify: true,
|
|
309
465
|
requires_playlist_services: true,
|
|
310
466
|
agent_tool: {
|
|
311
467
|
name: "moondog_spotify_resolve_tracks",
|
|
312
|
-
label: "Find your songs on Spotify",
|
|
468
|
+
label: N_("Find your songs on Spotify"),
|
|
469
|
+
},
|
|
470
|
+
},
|
|
471
|
+
{
|
|
472
|
+
id: "spotify.top",
|
|
473
|
+
version: "1",
|
|
474
|
+
state: "enabled",
|
|
475
|
+
effect: "read_external",
|
|
476
|
+
description: "Read bounded Spotify top artists or tracks as transient calculated-affinity evidence.",
|
|
477
|
+
requires_spotify: true,
|
|
478
|
+
agent_tool: { name: "moondog_spotify_top", label: N_("Your Spotify top artists and tracks") },
|
|
479
|
+
},
|
|
480
|
+
{
|
|
481
|
+
id: "spotify.library.browse", version: "1", state: "enabled", effect: "read_external", requires_spotify: true,
|
|
482
|
+
description: "Browse bounded pages of saved Spotify tracks, albums, and shows.",
|
|
483
|
+
agent_tool: { name: "moondog_spotify_library_browse", label: N_("Browse your Spotify library") },
|
|
484
|
+
},
|
|
485
|
+
{
|
|
486
|
+
id: "spotify.history.recent", version: "1", state: "enabled", effect: "read_external", requires_spotify: true,
|
|
487
|
+
description: "Read a bounded page of recent Spotify listening with timestamps and cursors.",
|
|
488
|
+
agent_tool: { name: "moondog_spotify_history_recent", label: N_("Read recent Spotify listening") },
|
|
489
|
+
},
|
|
490
|
+
{
|
|
491
|
+
id: "spotify.catalog.items", version: "1", state: "enabled", effect: "read_external", requires_spotify: true,
|
|
492
|
+
description: "Read bounded album tracks or podcast episodes from a selected host reference.",
|
|
493
|
+
agent_tool: { name: "moondog_spotify_catalog_items", label: N_("Browse album tracks or podcast episodes") },
|
|
494
|
+
},
|
|
495
|
+
{
|
|
496
|
+
id: "spotify.library.remove", version: "1", state: "enabled", effect: "write_external", requires_spotify: true,
|
|
497
|
+
description: "Confirm removal of one selected saved track, album, episode, show, or owned private playlist.",
|
|
498
|
+
agent_tool: { name: "moondog_spotify_library_remove", label: N_("Remove a saved Spotify item") },
|
|
499
|
+
},
|
|
500
|
+
{
|
|
501
|
+
id: "spotify.search",
|
|
502
|
+
version: "1",
|
|
503
|
+
state: "enabled",
|
|
504
|
+
effect: "read_external",
|
|
505
|
+
description:
|
|
506
|
+
"Search the Spotify catalog for tracks by free text, with bounded results.",
|
|
507
|
+
requires_spotify: true,
|
|
508
|
+
agent_tool: {
|
|
509
|
+
name: "moondog_spotify_search",
|
|
510
|
+
label: N_("Search Spotify"),
|
|
313
511
|
},
|
|
314
512
|
},
|
|
315
513
|
{
|
|
@@ -319,10 +517,9 @@ const catalog = [
|
|
|
319
517
|
effect: "read_external",
|
|
320
518
|
description: "Check whether resolved tracks are already saved in the Spotify library.",
|
|
321
519
|
requires_spotify: true,
|
|
322
|
-
requires_playlist_services: true,
|
|
323
520
|
agent_tool: {
|
|
324
521
|
name: "moondog_spotify_library_check",
|
|
325
|
-
label: "Check Spotify saved tracks",
|
|
522
|
+
label: N_("Check Spotify saved tracks"),
|
|
326
523
|
},
|
|
327
524
|
},
|
|
328
525
|
{
|
|
@@ -332,10 +529,9 @@ const catalog = [
|
|
|
332
529
|
effect: "write_external",
|
|
333
530
|
description: "Save explicitly requested resolved tracks to the Spotify library.",
|
|
334
531
|
requires_spotify: true,
|
|
335
|
-
requires_playlist_services: true,
|
|
336
532
|
agent_tool: {
|
|
337
533
|
name: "moondog_spotify_library_save",
|
|
338
|
-
label: "Save tracks to Spotify library",
|
|
534
|
+
label: N_("Save tracks to Spotify library"),
|
|
339
535
|
},
|
|
340
536
|
},
|
|
341
537
|
{
|
|
@@ -348,9 +544,23 @@ const catalog = [
|
|
|
348
544
|
requires_spotify: true,
|
|
349
545
|
agent_tool: {
|
|
350
546
|
name: "moondog_spotify_playlist_read",
|
|
351
|
-
label: "Look at your Spotify playlists",
|
|
547
|
+
label: N_("Look at your Spotify playlists"),
|
|
352
548
|
},
|
|
353
549
|
},
|
|
550
|
+
{
|
|
551
|
+
id: "spotify.playlist.edit.quick",
|
|
552
|
+
version: "1",
|
|
553
|
+
state: "enabled",
|
|
554
|
+
effect: "write_external",
|
|
555
|
+
description: "Apply one exact user-authorized rename or unambiguous single-track removal to an inspected owned private playlist.",
|
|
556
|
+
requires_spotify: true,
|
|
557
|
+
agent_tool: { name: "moondog_spotify_playlist_edit_quick", label: N_("Make an exact playlist edit") },
|
|
558
|
+
},
|
|
559
|
+
{
|
|
560
|
+
id: "spotify.playlist.remove", version: "1", state: "enabled", effect: "write_external", requires_spotify: true,
|
|
561
|
+
description: "Confirm and remove an owned private playlist from the current user's library without claiming global deletion.",
|
|
562
|
+
agent_tool: { name: "moondog_spotify_playlist_remove", label: N_("Remove a playlist from your library") },
|
|
563
|
+
},
|
|
354
564
|
{
|
|
355
565
|
id: "spotify.playlist.edit.preview",
|
|
356
566
|
version: "1",
|
|
@@ -361,7 +571,7 @@ const catalog = [
|
|
|
361
571
|
requires_spotify: true,
|
|
362
572
|
agent_tool: {
|
|
363
573
|
name: "moondog_spotify_playlist_edit_preview",
|
|
364
|
-
label: "Preview a playlist change",
|
|
574
|
+
label: N_("Preview a playlist change"),
|
|
365
575
|
},
|
|
366
576
|
},
|
|
367
577
|
{
|
|
@@ -374,7 +584,7 @@ const catalog = [
|
|
|
374
584
|
requires_spotify: true,
|
|
375
585
|
agent_tool: {
|
|
376
586
|
name: "moondog_spotify_playlist_edit_apply",
|
|
377
|
-
label: "Change a Spotify playlist",
|
|
587
|
+
label: N_("Change a Spotify playlist"),
|
|
378
588
|
},
|
|
379
589
|
},
|
|
380
590
|
{
|
|
@@ -388,7 +598,7 @@ const catalog = [
|
|
|
388
598
|
requires_playlist_services: true,
|
|
389
599
|
agent_tool: {
|
|
390
600
|
name: "moondog_spotify_playlist_write",
|
|
391
|
-
label: "Save the playlist to Spotify",
|
|
601
|
+
label: N_("Save the playlist to Spotify"),
|
|
392
602
|
},
|
|
393
603
|
},
|
|
394
604
|
{
|
|
@@ -421,10 +631,27 @@ function withRuntimeAvailability(
|
|
|
421
631
|
musicCatalogReady,
|
|
422
632
|
musicDiscoveryReady,
|
|
423
633
|
musicSimilarityReady,
|
|
424
|
-
|
|
634
|
+
webProviders,
|
|
635
|
+
profileExplorationReady,
|
|
636
|
+
profileBuildReady,
|
|
637
|
+
musicPreviewReady,
|
|
638
|
+
tasteChoicesReady,
|
|
425
639
|
) {
|
|
426
|
-
if (capability.
|
|
427
|
-
return { ...capability, state: "blocked", blocked_by: "
|
|
640
|
+
if (capability.requires_taste_choices && !tasteChoicesReady) {
|
|
641
|
+
return { ...capability, state: "blocked", blocked_by: "taste_choices_not_ready" };
|
|
642
|
+
}
|
|
643
|
+
if (capability.requires_profile_build && !profileBuildReady) {
|
|
644
|
+
return { ...capability, state: "blocked", blocked_by: "profile_build_not_ready" };
|
|
645
|
+
}
|
|
646
|
+
if (capability.requires_profile_exploration && !profileExplorationReady) {
|
|
647
|
+
return { ...capability, state: "blocked", blocked_by: "profile_exploration_not_ready" };
|
|
648
|
+
}
|
|
649
|
+
if (capability.requires_web) {
|
|
650
|
+
// The description names the service in use, or the ones that could be set up.
|
|
651
|
+
const provider = webProviders[capability.requires_web];
|
|
652
|
+
capability = { ...capability, description: capability.description.replace("{provider}", provider ??
|
|
653
|
+
(capability.requires_web === "search" ? "DeepSeek, Brave Search or the Codex CLI, once one is set up" : "DeepSeek or the Codex CLI, once one is set up")) };
|
|
654
|
+
if (!provider) return { ...capability, state: "blocked", blocked_by: `web_${capability.requires_web}_not_ready` };
|
|
428
655
|
}
|
|
429
656
|
if (capability.requires_domain_services && !domainServicesReady) {
|
|
430
657
|
return {
|
|
@@ -513,6 +740,13 @@ function withRuntimeAvailability(
|
|
|
513
740
|
blocked_by: "music_similarity_not_ready",
|
|
514
741
|
};
|
|
515
742
|
}
|
|
743
|
+
if (capability.requires_music_preview && !musicPreviewReady) {
|
|
744
|
+
return {
|
|
745
|
+
...capability,
|
|
746
|
+
state: "blocked",
|
|
747
|
+
blocked_by: "music_preview_not_ready",
|
|
748
|
+
};
|
|
749
|
+
}
|
|
516
750
|
return capability;
|
|
517
751
|
}
|
|
518
752
|
|
|
@@ -529,7 +763,12 @@ export function listCapabilities({
|
|
|
529
763
|
musicCatalogReady = false,
|
|
530
764
|
musicDiscoveryReady = false,
|
|
531
765
|
musicSimilarityReady = false,
|
|
532
|
-
|
|
766
|
+
webSearchProvider = null,
|
|
767
|
+
webReadProvider = null,
|
|
768
|
+
profileExplorationReady = false,
|
|
769
|
+
profileBuildReady = false,
|
|
770
|
+
musicPreviewReady = false,
|
|
771
|
+
tasteChoicesReady = false,
|
|
533
772
|
} = {}) {
|
|
534
773
|
return structuredClone(
|
|
535
774
|
catalog.map((capability) =>
|
|
@@ -547,7 +786,11 @@ export function listCapabilities({
|
|
|
547
786
|
musicCatalogReady,
|
|
548
787
|
musicDiscoveryReady,
|
|
549
788
|
musicSimilarityReady,
|
|
550
|
-
|
|
789
|
+
{ search: webSearchProvider, read: webReadProvider },
|
|
790
|
+
profileExplorationReady,
|
|
791
|
+
profileBuildReady,
|
|
792
|
+
musicPreviewReady,
|
|
793
|
+
tasteChoicesReady,
|
|
551
794
|
),
|
|
552
795
|
),
|
|
553
796
|
);
|
|
@@ -567,11 +810,3 @@ export function listAgentCapabilityDescriptors(options = {}) {
|
|
|
567
810
|
label: capability.agent_tool.label,
|
|
568
811
|
}));
|
|
569
812
|
}
|
|
570
|
-
|
|
571
|
-
export function getAgentCapabilityByToolName(toolName, options = {}) {
|
|
572
|
-
return (
|
|
573
|
-
listAgentCapabilityDescriptors(options).find(
|
|
574
|
-
(capability) => capability.tool_name === toolName,
|
|
575
|
-
) ?? null
|
|
576
|
-
);
|
|
577
|
-
}
|