@aurora-foundation/obsidian-next 0.4.8 → 0.4.10
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/chunk-2JWDGXTR.js +42 -0
- package/dist/chunk-3UCL6RYE.js +7272 -0
- package/dist/chunk-3VZGPA3N.js +42 -0
- package/dist/chunk-3XR3GZLX.js +7809 -0
- package/dist/chunk-6YJSTQKN.js +7817 -0
- package/dist/chunk-7XFP3ZUD.js +42 -0
- package/dist/chunk-ASDVTRIQ.js +7805 -0
- package/dist/chunk-BAKREPY2.js +439 -0
- package/dist/chunk-BFRO5BO2.js +42 -0
- package/dist/chunk-CHNVBJN3.js +7272 -0
- package/dist/chunk-DAR45YDV.js +42 -0
- package/dist/chunk-FNXAI27K.js +7812 -0
- package/dist/chunk-HKPL675M.js +42 -0
- package/dist/chunk-INEXRRON.js +42 -0
- package/dist/chunk-ISO6GNIB.js +429 -0
- package/dist/chunk-MGDY5JUY.js +581 -0
- package/dist/chunk-OFTKVOQ2.js +7828 -0
- package/dist/chunk-PD4ZKYTJ.js +7838 -0
- package/dist/chunk-PQSPCOJ7.js +7616 -0
- package/dist/chunk-QSEH5NXV.js +7807 -0
- package/dist/chunk-RUEIA6Z5.js +42 -0
- package/dist/chunk-S5IDXE2L.js +42 -0
- package/dist/chunk-UG3HWGIO.js +42 -0
- package/dist/chunk-UOESII6R.js +42 -0
- package/dist/chunk-VWMT4HCP.js +7668 -0
- package/dist/chunk-YFQI44IA.js +42 -0
- package/dist/chunk-ZR7MEF3B.js +7605 -0
- package/dist/context-NI6N46WG.js +10 -0
- package/dist/index.js +585 -345
- package/dist/memory-GXW2OA2T.js +13 -0
- package/dist/resume-EA6ISWW2.js +15 -0
- package/dist/resume-EIM5FN42.js +15 -0
- package/dist/resume-FBVK6NAI.js +15 -0
- package/dist/resume-H6J5PQIA.js +15 -0
- package/dist/resume-JDDVTMM4.js +15 -0
- package/dist/resume-JFYYR7DJ.js +15 -0
- package/dist/resume-KGFAZY34.js +15 -0
- package/dist/resume-MF5TM2ZB.js +15 -0
- package/dist/resume-O6PLICAA.js +15 -0
- package/dist/resume-PZU3PWCJ.js +15 -0
- package/dist/resume-YD76GI2J.js +15 -0
- package/dist/resume-YKAKOXWV.js +15 -0
- package/dist/session-37MDDCWV.js +14 -0
- package/dist/session-56ZI3GZV.js +14 -0
- package/dist/session-5OFIDWGU.js +14 -0
- package/dist/session-7LPACLRV.js +14 -0
- package/dist/session-CJ6HSKDI.js +14 -0
- package/dist/session-CUXGN26I.js +14 -0
- package/dist/session-DCGNGGMV.js +14 -0
- package/dist/session-LEVSW6JH.js +14 -0
- package/dist/session-MHZAYMLC.js +14 -0
- package/dist/session-NNU7OW5K.js +14 -0
- package/dist/session-R5UG5PZR.js +14 -0
- package/dist/session-T64DMDAU.js +14 -0
- package/dist/settings-4ALCRT5S.js +8 -0
- package/dist/skills/defaults/clipboard.mjs +46 -0
- package/dist/skills/defaults/notify.mjs +36 -0
- package/dist/skills/defaults/open_app.mjs +53 -0
- package/dist/skills/defaults/speak.mjs +47 -0
- package/dist/skills/defaults/spotify_control.mjs +187 -0
- package/package.json +7 -4
|
@@ -0,0 +1,187 @@
|
|
|
1
|
+
export default {
|
|
2
|
+
name: 'spotify_control',
|
|
3
|
+
description: 'Control Spotify playback on macOS - play music by name, pause, resume, skip, get current track. Uses AppleScript for native control.',
|
|
4
|
+
inputSchema: {
|
|
5
|
+
action: {
|
|
6
|
+
type: 'string',
|
|
7
|
+
description: 'Action: play, pause, resume, next, previous, current, search_and_play, volume, shuffle'
|
|
8
|
+
},
|
|
9
|
+
query: {
|
|
10
|
+
type: 'string',
|
|
11
|
+
description: 'Search query for play/search_and_play (e.g. "lofi beats", "Drake - Gods Plan")'
|
|
12
|
+
},
|
|
13
|
+
volume: {
|
|
14
|
+
type: 'number',
|
|
15
|
+
description: 'Volume level 0-100 (for volume action)'
|
|
16
|
+
}
|
|
17
|
+
},
|
|
18
|
+
requiredParams: ['action'],
|
|
19
|
+
|
|
20
|
+
async execute(args) {
|
|
21
|
+
const { execSync } = await import('child_process');
|
|
22
|
+
const action = (args.action || '').toLowerCase().trim();
|
|
23
|
+
const query = args.query || '';
|
|
24
|
+
|
|
25
|
+
const osascript = (script) => {
|
|
26
|
+
try {
|
|
27
|
+
return execSync(`osascript -e '${script.replace(/'/g, "'\\''")}'`, {
|
|
28
|
+
encoding: 'utf-8',
|
|
29
|
+
timeout: 10000
|
|
30
|
+
}).trim();
|
|
31
|
+
} catch (e) {
|
|
32
|
+
throw new Error(`AppleScript failed: ${e.message}`);
|
|
33
|
+
}
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
// Ensure Spotify is running
|
|
37
|
+
const ensureRunning = () => {
|
|
38
|
+
try {
|
|
39
|
+
osascript('tell application "Spotify" to activate');
|
|
40
|
+
} catch {
|
|
41
|
+
// Spotify not installed
|
|
42
|
+
throw new Error('Spotify is not installed');
|
|
43
|
+
}
|
|
44
|
+
};
|
|
45
|
+
|
|
46
|
+
// Search via Spotify AppleScript and play track URI directly
|
|
47
|
+
const searchAndPlay = async (searchQuery) => {
|
|
48
|
+
ensureRunning();
|
|
49
|
+
|
|
50
|
+
// Use open with spotify URI to trigger search
|
|
51
|
+
// Then use keyboard simulation via AppleScript to play the first result
|
|
52
|
+
const encoded = encodeURIComponent(searchQuery);
|
|
53
|
+
|
|
54
|
+
// Method 1: Use spotify:search URI then simulate keyboard to play first result
|
|
55
|
+
execSync(`open "spotify:search:${encoded}"`, { timeout: 5000 });
|
|
56
|
+
|
|
57
|
+
// Wait for Spotify to load search results
|
|
58
|
+
await new Promise(r => setTimeout(r, 2500));
|
|
59
|
+
|
|
60
|
+
// Simulate pressing Enter/Return to play the first result
|
|
61
|
+
// This works because Spotify focuses the first result after search
|
|
62
|
+
osascript(`
|
|
63
|
+
tell application "System Events"
|
|
64
|
+
tell process "Spotify"
|
|
65
|
+
set frontmost to true
|
|
66
|
+
delay 0.5
|
|
67
|
+
key code 36
|
|
68
|
+
end tell
|
|
69
|
+
end tell
|
|
70
|
+
`);
|
|
71
|
+
|
|
72
|
+
// Wait for track to start
|
|
73
|
+
await new Promise(r => setTimeout(r, 1500));
|
|
74
|
+
|
|
75
|
+
// Verify playback started
|
|
76
|
+
try {
|
|
77
|
+
const state = osascript('tell application "Spotify" to player state as string');
|
|
78
|
+
if (state === 'playing') {
|
|
79
|
+
const track = osascript('tell application "Spotify" to name of current track');
|
|
80
|
+
const artist = osascript('tell application "Spotify" to artist of current track');
|
|
81
|
+
return {
|
|
82
|
+
success: true,
|
|
83
|
+
output: `Now playing: "${track}" by ${artist}\nSearched for: ${searchQuery}`
|
|
84
|
+
};
|
|
85
|
+
}
|
|
86
|
+
} catch { /* fall through */ }
|
|
87
|
+
|
|
88
|
+
// Fallback: try clicking play button via AppleScript
|
|
89
|
+
try {
|
|
90
|
+
osascript('tell application "Spotify" to play');
|
|
91
|
+
await new Promise(r => setTimeout(r, 1000));
|
|
92
|
+
const track = osascript('tell application "Spotify" to name of current track');
|
|
93
|
+
const artist = osascript('tell application "Spotify" to artist of current track');
|
|
94
|
+
return {
|
|
95
|
+
success: true,
|
|
96
|
+
output: `Playing: "${track}" by ${artist}\nNote: Searched for "${searchQuery}" - verify this is the right track`
|
|
97
|
+
};
|
|
98
|
+
} catch {
|
|
99
|
+
return {
|
|
100
|
+
success: true,
|
|
101
|
+
output: `Opened Spotify search for "${searchQuery}". Press play on the result you want.`
|
|
102
|
+
};
|
|
103
|
+
}
|
|
104
|
+
};
|
|
105
|
+
|
|
106
|
+
try {
|
|
107
|
+
switch (action) {
|
|
108
|
+
case 'play':
|
|
109
|
+
case 'search_and_play': {
|
|
110
|
+
if (!query) {
|
|
111
|
+
ensureRunning();
|
|
112
|
+
osascript('tell application "Spotify" to play');
|
|
113
|
+
const track = osascript('tell application "Spotify" to name of current track');
|
|
114
|
+
const artist = osascript('tell application "Spotify" to artist of current track');
|
|
115
|
+
return { success: true, output: `Resumed: "${track}" by ${artist}` };
|
|
116
|
+
}
|
|
117
|
+
return await searchAndPlay(query);
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
case 'pause':
|
|
121
|
+
osascript('tell application "Spotify" to pause');
|
|
122
|
+
return { success: true, output: 'Paused playback' };
|
|
123
|
+
|
|
124
|
+
case 'resume':
|
|
125
|
+
osascript('tell application "Spotify" to play');
|
|
126
|
+
return { success: true, output: 'Resumed playback' };
|
|
127
|
+
|
|
128
|
+
case 'next': {
|
|
129
|
+
osascript('tell application "Spotify" to next track');
|
|
130
|
+
await new Promise(r => setTimeout(r, 500));
|
|
131
|
+
const nTrack = osascript('tell application "Spotify" to name of current track');
|
|
132
|
+
const nArtist = osascript('tell application "Spotify" to artist of current track');
|
|
133
|
+
return { success: true, output: `Skipped to: "${nTrack}" by ${nArtist}` };
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
case 'previous': {
|
|
137
|
+
osascript('tell application "Spotify" to previous track');
|
|
138
|
+
await new Promise(r => setTimeout(r, 500));
|
|
139
|
+
const pTrack = osascript('tell application "Spotify" to name of current track');
|
|
140
|
+
const pArtist = osascript('tell application "Spotify" to artist of current track');
|
|
141
|
+
return { success: true, output: `Back to: "${pTrack}" by ${pArtist}` };
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
case 'current': {
|
|
145
|
+
const state = osascript('tell application "Spotify" to player state as string');
|
|
146
|
+
if (state === 'stopped') {
|
|
147
|
+
return { success: true, output: 'Spotify is stopped - nothing playing' };
|
|
148
|
+
}
|
|
149
|
+
const name = osascript('tell application "Spotify" to name of current track');
|
|
150
|
+
const art = osascript('tell application "Spotify" to artist of current track');
|
|
151
|
+
const album = osascript('tell application "Spotify" to album of current track');
|
|
152
|
+
const pos = osascript('tell application "Spotify" to player position');
|
|
153
|
+
const dur = osascript('tell application "Spotify" to duration of current track');
|
|
154
|
+
const durSec = Math.round(parseInt(dur) / 1000);
|
|
155
|
+
return {
|
|
156
|
+
success: true,
|
|
157
|
+
output: `${state === 'playing' ? '[PLAYING]' : '[PAUSED]'} "${name}" by ${art}\nAlbum: ${album}\nPosition: ${Math.round(parseFloat(pos))}s / ${durSec}s`
|
|
158
|
+
};
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
case 'volume': {
|
|
162
|
+
const vol = Math.max(0, Math.min(100, parseInt(args.volume) || 50));
|
|
163
|
+
osascript(`tell application "Spotify" to set sound volume to ${vol}`);
|
|
164
|
+
return { success: true, output: `Volume set to ${vol}%` };
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
case 'shuffle': {
|
|
168
|
+
const current = osascript('tell application "Spotify" to shuffling');
|
|
169
|
+
const newState = current === 'true' ? false : true;
|
|
170
|
+
osascript(`tell application "Spotify" to set shuffling to ${newState}`);
|
|
171
|
+
return { success: true, output: `Shuffle ${newState ? 'ON' : 'OFF'}` };
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
default:
|
|
175
|
+
return {
|
|
176
|
+
success: false,
|
|
177
|
+
error: `Unknown action: ${action}. Use: play, pause, resume, next, previous, current, search_and_play, volume, shuffle`
|
|
178
|
+
};
|
|
179
|
+
}
|
|
180
|
+
} catch (error) {
|
|
181
|
+
return {
|
|
182
|
+
success: false,
|
|
183
|
+
error: `Spotify control failed: ${error.message}. Is Spotify installed and running?`
|
|
184
|
+
};
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@aurora-foundation/obsidian-next",
|
|
3
|
-
"version": "0.4.
|
|
3
|
+
"version": "0.4.10",
|
|
4
4
|
"description": "Next-gen AI Agent CLI",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"type": "module",
|
|
@@ -33,14 +33,17 @@
|
|
|
33
33
|
},
|
|
34
34
|
"scripts": {
|
|
35
35
|
"dev": "tsup src/index.ts --format esm --watch",
|
|
36
|
-
"build": "tsup src/index.ts src/mcp/index.ts --format esm",
|
|
36
|
+
"build": "tsup src/index.ts src/mcp/index.ts --format esm && cp -r src/skills dist/",
|
|
37
|
+
"build:check": "npm run lint && npm run format:check && tsup src/index.ts src/mcp/index.ts --format esm",
|
|
37
38
|
"start": "node dist/index.js",
|
|
38
39
|
"mcp": "node dist/mcp/index.js",
|
|
39
40
|
"test": "vitest",
|
|
41
|
+
"test:ci": "vitest run --reporter=verbose",
|
|
40
42
|
"format": "prettier --write \"src/**/*.{ts,tsx}\"",
|
|
41
43
|
"format:check": "prettier --check \"src/**/*.{ts,tsx}\"",
|
|
42
|
-
"lint": "eslint
|
|
43
|
-
"lint:fix": "eslint
|
|
44
|
+
"lint": "eslint .",
|
|
45
|
+
"lint:fix": "eslint . --fix",
|
|
46
|
+
"precommit": "npm run lint:fix && npm run format && npm test"
|
|
44
47
|
},
|
|
45
48
|
"dependencies": {
|
|
46
49
|
"@anthropic-ai/sandbox-runtime": "^0.0.32",
|