@jovie/cli 26.9.15
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 +203 -0
- package/README.md +108 -0
- package/dist/cli.d.ts +17 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +234 -0
- package/dist/cli.js.map +1 -0
- package/dist/client.d.ts +45 -0
- package/dist/client.d.ts.map +1 -0
- package/dist/client.js +174 -0
- package/dist/client.js.map +1 -0
- package/dist/commands.d.ts +21 -0
- package/dist/commands.d.ts.map +1 -0
- package/dist/commands.js +52 -0
- package/dist/commands.js.map +1 -0
- package/dist/index.d.ts +7 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +7 -0
- package/dist/index.js.map +1 -0
- package/dist/init.d.ts +24 -0
- package/dist/init.d.ts.map +1 -0
- package/dist/init.js +36 -0
- package/dist/init.js.map +1 -0
- package/dist/mcp.d.ts +22 -0
- package/dist/mcp.d.ts.map +1 -0
- package/dist/mcp.js +148 -0
- package/dist/mcp.js.map +1 -0
- package/dist/skill.d.ts +3 -0
- package/dist/skill.d.ts.map +1 -0
- package/dist/skill.js +53 -0
- package/dist/skill.js.map +1 -0
- package/package.json +72 -0
package/dist/client.js
ADDED
|
@@ -0,0 +1,174 @@
|
|
|
1
|
+
export const DEFAULT_BASE_URL = 'https://jov.ie';
|
|
2
|
+
export const DEFAULT_TIMEOUT_MS = 30_000;
|
|
3
|
+
export const DEFAULT_USER_AGENT = 'jovie-cli';
|
|
4
|
+
export class JovieInputError extends Error {
|
|
5
|
+
code = 'INVALID_INPUT';
|
|
6
|
+
constructor(message) {
|
|
7
|
+
super(message);
|
|
8
|
+
this.name = 'JovieInputError';
|
|
9
|
+
}
|
|
10
|
+
}
|
|
11
|
+
export class JovieRequestError extends Error {
|
|
12
|
+
url;
|
|
13
|
+
status;
|
|
14
|
+
responseBody;
|
|
15
|
+
retryAfterSeconds;
|
|
16
|
+
apiCode;
|
|
17
|
+
code = 'REQUEST_FAILED';
|
|
18
|
+
constructor(message, url, status, responseBody, retryAfterSeconds,
|
|
19
|
+
/** Stable server error code (e.g. RATE_LIMITED) when the API sent one. */
|
|
20
|
+
apiCode) {
|
|
21
|
+
super(message);
|
|
22
|
+
this.url = url;
|
|
23
|
+
this.status = status;
|
|
24
|
+
this.responseBody = responseBody;
|
|
25
|
+
this.retryAfterSeconds = retryAfterSeconds;
|
|
26
|
+
this.apiCode = apiCode;
|
|
27
|
+
this.name = 'JovieRequestError';
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
function errorMessage(error) {
|
|
31
|
+
return error instanceof Error ? error.message : String(error);
|
|
32
|
+
}
|
|
33
|
+
/** Normalize a deployment root without accepting credentials or query state. */
|
|
34
|
+
export function normalizeBaseUrl(baseUrl = DEFAULT_BASE_URL) {
|
|
35
|
+
let url;
|
|
36
|
+
try {
|
|
37
|
+
url = new URL(baseUrl);
|
|
38
|
+
}
|
|
39
|
+
catch {
|
|
40
|
+
throw new JovieInputError(`Invalid base URL: ${baseUrl}`);
|
|
41
|
+
}
|
|
42
|
+
if (!['http:', 'https:'].includes(url.protocol) ||
|
|
43
|
+
url.username ||
|
|
44
|
+
url.password ||
|
|
45
|
+
url.search ||
|
|
46
|
+
url.hash ||
|
|
47
|
+
(url.pathname !== '/' && url.pathname !== '')) {
|
|
48
|
+
throw new JovieInputError('Base URL must be an http(s) origin without credentials, a path, or query parameters.');
|
|
49
|
+
}
|
|
50
|
+
return url.origin;
|
|
51
|
+
}
|
|
52
|
+
function resourceUrl(baseUrl, pathname) {
|
|
53
|
+
return new URL(pathname, `${normalizeBaseUrl(baseUrl)}/`).toString();
|
|
54
|
+
}
|
|
55
|
+
function requestSignal(options) {
|
|
56
|
+
const timeoutSignal = AbortSignal.timeout(options.timeoutMs ?? DEFAULT_TIMEOUT_MS);
|
|
57
|
+
return options.signal
|
|
58
|
+
? AbortSignal.any([options.signal, timeoutSignal])
|
|
59
|
+
: timeoutSignal;
|
|
60
|
+
}
|
|
61
|
+
function getFetch(options) {
|
|
62
|
+
return options.fetchImpl ?? ((input, init) => globalThis.fetch(input, init));
|
|
63
|
+
}
|
|
64
|
+
function parseRetryAfterSeconds(value, nowMs = Date.now()) {
|
|
65
|
+
if (!value)
|
|
66
|
+
return undefined;
|
|
67
|
+
if (/^\d+$/.test(value.trim())) {
|
|
68
|
+
const seconds = Number(value);
|
|
69
|
+
return Number.isSafeInteger(seconds) ? seconds : undefined;
|
|
70
|
+
}
|
|
71
|
+
const retryAtMs = Date.parse(value);
|
|
72
|
+
if (!Number.isFinite(retryAtMs))
|
|
73
|
+
return undefined;
|
|
74
|
+
return Math.max(0, Math.ceil((retryAtMs - nowMs) / 1000));
|
|
75
|
+
}
|
|
76
|
+
function parseApiCode(body) {
|
|
77
|
+
try {
|
|
78
|
+
const code = JSON.parse(body).error
|
|
79
|
+
?.code;
|
|
80
|
+
return typeof code === 'string' ? code : undefined;
|
|
81
|
+
}
|
|
82
|
+
catch {
|
|
83
|
+
return undefined;
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
async function request(pathname, accept, options, jsonBody) {
|
|
87
|
+
const baseUrl = normalizeBaseUrl(options.baseUrl);
|
|
88
|
+
const url = resourceUrl(baseUrl, pathname);
|
|
89
|
+
const method = jsonBody === undefined ? 'GET' : 'POST';
|
|
90
|
+
let response;
|
|
91
|
+
try {
|
|
92
|
+
response = await getFetch(options)(url, {
|
|
93
|
+
method,
|
|
94
|
+
headers: {
|
|
95
|
+
Accept: accept,
|
|
96
|
+
'User-Agent': options.userAgent ?? DEFAULT_USER_AGENT,
|
|
97
|
+
...(jsonBody === undefined
|
|
98
|
+
? {}
|
|
99
|
+
: { 'Content-Type': 'application/json' }),
|
|
100
|
+
},
|
|
101
|
+
...(jsonBody === undefined ? {} : { body: JSON.stringify(jsonBody) }),
|
|
102
|
+
signal: requestSignal(options),
|
|
103
|
+
});
|
|
104
|
+
}
|
|
105
|
+
catch (error) {
|
|
106
|
+
throw new JovieRequestError(`${method} ${url} failed: ${errorMessage(error)}`, url);
|
|
107
|
+
}
|
|
108
|
+
const body = await response.text();
|
|
109
|
+
if (!response.ok) {
|
|
110
|
+
throw new JovieRequestError(`${method} ${url} returned HTTP ${response.status}`, url, response.status, body.slice(0, 1_000), parseRetryAfterSeconds(response.headers.get('retry-after')), parseApiCode(body));
|
|
111
|
+
}
|
|
112
|
+
return { body, url };
|
|
113
|
+
}
|
|
114
|
+
async function requestJson(pathname, options, jsonBody) {
|
|
115
|
+
const { body, url } = await request(pathname, 'application/json', options, jsonBody);
|
|
116
|
+
try {
|
|
117
|
+
return JSON.parse(body);
|
|
118
|
+
}
|
|
119
|
+
catch {
|
|
120
|
+
throw new JovieRequestError(`${jsonBody === undefined ? 'GET' : 'POST'} ${url} returned invalid JSON`, url, undefined, body.slice(0, 1_000));
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
async function requestText(pathname, options) {
|
|
124
|
+
const { body } = await request(pathname, 'text/plain', options);
|
|
125
|
+
return body;
|
|
126
|
+
}
|
|
127
|
+
export function validateUsername(username) {
|
|
128
|
+
const normalized = username.trim();
|
|
129
|
+
if (normalized.length < 3 ||
|
|
130
|
+
normalized.length > 30 ||
|
|
131
|
+
!/^[a-zA-Z0-9._-]+$/.test(normalized)) {
|
|
132
|
+
throw new JovieInputError('Username must be 3-30 characters and contain only letters, numbers, dots, underscores, or hyphens.');
|
|
133
|
+
}
|
|
134
|
+
return normalized;
|
|
135
|
+
}
|
|
136
|
+
/** Fetch the public, unauthenticated artist API response. */
|
|
137
|
+
export function fetchArtist(username, options = {}) {
|
|
138
|
+
const normalized = validateUsername(username);
|
|
139
|
+
return requestJson(`/api/v1/${encodeURIComponent(normalized)}`, options);
|
|
140
|
+
}
|
|
141
|
+
/** Fetch the canonical public OpenAPI 3.1 contract. */
|
|
142
|
+
export function fetchOpenApi(options = {}) {
|
|
143
|
+
return requestJson('/api/v1/openapi.json', options);
|
|
144
|
+
}
|
|
145
|
+
/** Fetch the site-level machine-readable agent guide. */
|
|
146
|
+
export function fetchSiteLlms(full, options = {}) {
|
|
147
|
+
return requestText(full ? '/llms-full.txt' : '/llms.txt', options);
|
|
148
|
+
}
|
|
149
|
+
/** Fetch the machine-readable guide for one public artist. */
|
|
150
|
+
export function fetchArtistLlms(username, options = {}) {
|
|
151
|
+
const normalized = validateUsername(username);
|
|
152
|
+
return requestText(`/${encodeURIComponent(normalized)}/llms.txt`, options);
|
|
153
|
+
}
|
|
154
|
+
/**
|
|
155
|
+
* Create (or find) a Jovie profile for a Spotify artist. Returns the public
|
|
156
|
+
* profile URL and, when unclaimed, a claim URL the human opens to verify
|
|
157
|
+
* ownership. Anonymous and rate limited per IP.
|
|
158
|
+
*/
|
|
159
|
+
export function createProfile(spotifyArtistUrl, options = {}) {
|
|
160
|
+
let url;
|
|
161
|
+
try {
|
|
162
|
+
url = new URL(spotifyArtistUrl.trim());
|
|
163
|
+
}
|
|
164
|
+
catch {
|
|
165
|
+
throw new JovieInputError(`Invalid URL: ${spotifyArtistUrl}`);
|
|
166
|
+
}
|
|
167
|
+
if (url.protocol !== 'https:' ||
|
|
168
|
+
!/(^|\.)spotify\.com$/.test(url.hostname) ||
|
|
169
|
+
!/^\/(intl-[a-z-]+\/)?artist\/[A-Za-z0-9]+\/?$/.test(url.pathname)) {
|
|
170
|
+
throw new JovieInputError('Expected a Spotify artist URL like https://open.spotify.com/artist/<id>.');
|
|
171
|
+
}
|
|
172
|
+
return requestJson('/api/agents/profiles', options, { url: url.toString() });
|
|
173
|
+
}
|
|
174
|
+
//# sourceMappingURL=client.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"client.js","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { type ResourceOptions } from './client.js';
|
|
2
|
+
export interface CommandInput {
|
|
3
|
+
readonly arg?: string;
|
|
4
|
+
readonly full?: boolean;
|
|
5
|
+
}
|
|
6
|
+
/** One definition drives CLI dispatch, `--help`, and MCP tools. */
|
|
7
|
+
export interface CommandSpec {
|
|
8
|
+
readonly path: readonly [string, string];
|
|
9
|
+
readonly tool: string;
|
|
10
|
+
readonly summary: string;
|
|
11
|
+
readonly arg?: {
|
|
12
|
+
readonly name: string;
|
|
13
|
+
readonly description: string;
|
|
14
|
+
};
|
|
15
|
+
readonly acceptsFull?: boolean;
|
|
16
|
+
readonly readOnly: boolean;
|
|
17
|
+
readonly run: (input: CommandInput, options: ResourceOptions) => Promise<unknown>;
|
|
18
|
+
}
|
|
19
|
+
export declare const COMMANDS: readonly CommandSpec[];
|
|
20
|
+
export declare function findCommand(positionals: readonly string[]): CommandSpec | undefined;
|
|
21
|
+
//# sourceMappingURL=commands.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"commands.d.ts","sourceRoot":"","sources":["../src/commands.ts"],"names":[],"mappings":"AAAA,OAAO,EAML,KAAK,eAAe,EACrB,MAAM,aAAa,CAAC;AAErB,MAAM,WAAW,YAAY;IAC3B,QAAQ,CAAC,GAAG,CAAC,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,IAAI,CAAC,EAAE,OAAO,CAAC;CACzB;AAED,mEAAmE;AACnE,MAAM,WAAW,WAAW;IAC1B,QAAQ,CAAC,IAAI,EAAE,SAAS,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACzC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,GAAG,CAAC,EAAE;QAAE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAA;KAAE,CAAC;IACvE,QAAQ,CAAC,WAAW,CAAC,EAAE,OAAO,CAAC;IAC/B,QAAQ,CAAC,QAAQ,EAAE,OAAO,CAAC;IAC3B,QAAQ,CAAC,GAAG,EAAE,CACZ,KAAK,EAAE,YAAY,EACnB,OAAO,EAAE,eAAe,KACrB,OAAO,CAAC,OAAO,CAAC,CAAC;CACvB;AAMD,eAAO,MAAM,QAAQ,EAAE,SAAS,WAAW,EA+C1C,CAAC;AAEF,wBAAgB,WAAW,CACzB,WAAW,EAAE,SAAS,MAAM,EAAE,GAC7B,WAAW,GAAG,SAAS,CAKzB"}
|
package/dist/commands.js
ADDED
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import { createProfile, fetchArtist, fetchArtistLlms, fetchOpenApi, fetchSiteLlms, } from './client.js';
|
|
2
|
+
function required(input) {
|
|
3
|
+
return input.arg ?? '';
|
|
4
|
+
}
|
|
5
|
+
export const COMMANDS = [
|
|
6
|
+
{
|
|
7
|
+
path: ['profile', 'create'],
|
|
8
|
+
tool: 'create_profile',
|
|
9
|
+
summary: 'Create (or find) a Jovie profile for a Spotify artist. Returns profileUrl and, when unclaimed, a claimUrl the artist opens to take ownership.',
|
|
10
|
+
arg: {
|
|
11
|
+
name: 'url',
|
|
12
|
+
description: 'Spotify artist URL, e.g. https://open.spotify.com/artist/<id>',
|
|
13
|
+
},
|
|
14
|
+
readOnly: false,
|
|
15
|
+
run: (input, options) => createProfile(required(input), options),
|
|
16
|
+
},
|
|
17
|
+
{
|
|
18
|
+
path: ['artist', 'get'],
|
|
19
|
+
tool: 'get_artist',
|
|
20
|
+
summary: 'Fetch a public artist profile: bio, links, releases, events, merch.',
|
|
21
|
+
arg: { name: 'username', description: 'Jovie username, e.g. radiohead' },
|
|
22
|
+
readOnly: true,
|
|
23
|
+
run: (input, options) => fetchArtist(required(input), options),
|
|
24
|
+
},
|
|
25
|
+
{
|
|
26
|
+
path: ['artist', 'llms'],
|
|
27
|
+
tool: 'get_artist_guide',
|
|
28
|
+
summary: "Fetch an artist's machine-readable guide (llms.txt).",
|
|
29
|
+
arg: { name: 'username', description: 'Jovie username' },
|
|
30
|
+
readOnly: true,
|
|
31
|
+
run: (input, options) => fetchArtistLlms(required(input), options),
|
|
32
|
+
},
|
|
33
|
+
{
|
|
34
|
+
path: ['api', 'openapi'],
|
|
35
|
+
tool: 'get_openapi',
|
|
36
|
+
summary: 'Fetch the public Jovie OpenAPI contract.',
|
|
37
|
+
readOnly: true,
|
|
38
|
+
run: (_input, options) => fetchOpenApi(options),
|
|
39
|
+
},
|
|
40
|
+
{
|
|
41
|
+
path: ['docs', 'llms'],
|
|
42
|
+
tool: 'get_docs',
|
|
43
|
+
summary: 'Fetch the Jovie agent guide (llms.txt; full=true for llms-full.txt).',
|
|
44
|
+
acceptsFull: true,
|
|
45
|
+
readOnly: true,
|
|
46
|
+
run: (input, options) => fetchSiteLlms(input.full === true, options),
|
|
47
|
+
},
|
|
48
|
+
];
|
|
49
|
+
export function findCommand(positionals) {
|
|
50
|
+
return COMMANDS.find(command => command.path[0] === positionals[0] && command.path[1] === positionals[1]);
|
|
51
|
+
}
|
|
52
|
+
//# sourceMappingURL=commands.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"commands.js","sourceRoot":"","sources":["../src/commands.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,aAAa,EACb,WAAW,EACX,eAAe,EACf,YAAY,EACZ,aAAa,GAEd,MAAM,aAAa,CAAC;AAqBrB,SAAS,QAAQ,CAAC,KAAmB;IACnC,OAAO,KAAK,CAAC,GAAG,IAAI,EAAE,CAAC;AACzB,CAAC;AAED,MAAM,CAAC,MAAM,QAAQ,GAA2B;IAC9C;QACE,IAAI,EAAE,CAAC,SAAS,EAAE,QAAQ,CAAC;QAC3B,IAAI,EAAE,gBAAgB;QACtB,OAAO,EACL,+IAA+I;QACjJ,GAAG,EAAE;YACH,IAAI,EAAE,KAAK;YACX,WAAW,EACT,+DAA+D;SAClE;QACD,QAAQ,EAAE,KAAK;QACf,GAAG,EAAE,CAAC,KAAK,EAAE,OAAO,EAAE,EAAE,CAAC,aAAa,CAAC,QAAQ,CAAC,KAAK,CAAC,EAAE,OAAO,CAAC;KACjE;IACD;QACE,IAAI,EAAE,CAAC,QAAQ,EAAE,KAAK,CAAC;QACvB,IAAI,EAAE,YAAY;QAClB,OAAO,EACL,qEAAqE;QACvE,GAAG,EAAE,EAAE,IAAI,EAAE,UAAU,EAAE,WAAW,EAAE,gCAAgC,EAAE;QACxE,QAAQ,EAAE,IAAI;QACd,GAAG,EAAE,CAAC,KAAK,EAAE,OAAO,EAAE,EAAE,CAAC,WAAW,CAAC,QAAQ,CAAC,KAAK,CAAC,EAAE,OAAO,CAAC;KAC/D;IACD;QACE,IAAI,EAAE,CAAC,QAAQ,EAAE,MAAM,CAAC;QACxB,IAAI,EAAE,kBAAkB;QACxB,OAAO,EAAE,sDAAsD;QAC/D,GAAG,EAAE,EAAE,IAAI,EAAE,UAAU,EAAE,WAAW,EAAE,gBAAgB,EAAE;QACxD,QAAQ,EAAE,IAAI;QACd,GAAG,EAAE,CAAC,KAAK,EAAE,OAAO,EAAE,EAAE,CAAC,eAAe,CAAC,QAAQ,CAAC,KAAK,CAAC,EAAE,OAAO,CAAC;KACnE;IACD;QACE,IAAI,EAAE,CAAC,KAAK,EAAE,SAAS,CAAC;QACxB,IAAI,EAAE,aAAa;QACnB,OAAO,EAAE,0CAA0C;QACnD,QAAQ,EAAE,IAAI;QACd,GAAG,EAAE,CAAC,MAAM,EAAE,OAAO,EAAE,EAAE,CAAC,YAAY,CAAC,OAAO,CAAC;KAChD;IACD;QACE,IAAI,EAAE,CAAC,MAAM,EAAE,MAAM,CAAC;QACtB,IAAI,EAAE,UAAU;QAChB,OAAO,EACL,sEAAsE;QACxE,WAAW,EAAE,IAAI;QACjB,QAAQ,EAAE,IAAI;QACd,GAAG,EAAE,CAAC,KAAK,EAAE,OAAO,EAAE,EAAE,CAAC,aAAa,CAAC,KAAK,CAAC,IAAI,KAAK,IAAI,EAAE,OAAO,CAAC;KACrE;CACF,CAAC;AAEF,MAAM,UAAU,WAAW,CACzB,WAA8B;IAE9B,OAAO,QAAQ,CAAC,IAAI,CAClB,OAAO,CAAC,EAAE,CACR,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,KAAK,WAAW,CAAC,CAAC,CAAC,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,KAAK,WAAW,CAAC,CAAC,CAAC,CAC3E,CAAC;AACJ,CAAC"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
export { type CliDependencies, type CliOutput, runCli, } from './cli.js';
|
|
2
|
+
export { createProfile, DEFAULT_BASE_URL, DEFAULT_TIMEOUT_MS, fetchArtist, fetchArtistLlms, fetchOpenApi, fetchSiteLlms, JovieInputError, JovieRequestError, normalizeBaseUrl, validateUsername, } from './client.js';
|
|
3
|
+
export { COMMANDS, type CommandSpec } from './commands.js';
|
|
4
|
+
export { installSkill } from './init.js';
|
|
5
|
+
export { handleMcpMessage, serveMcp } from './mcp.js';
|
|
6
|
+
export { SKILL_MD } from './skill.js';
|
|
7
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,KAAK,eAAe,EACpB,KAAK,SAAS,EACd,MAAM,GACP,MAAM,UAAU,CAAC;AAClB,OAAO,EACL,aAAa,EACb,gBAAgB,EAChB,kBAAkB,EAClB,WAAW,EACX,eAAe,EACf,YAAY,EACZ,aAAa,EACb,eAAe,EACf,iBAAiB,EACjB,gBAAgB,EAChB,gBAAgB,GACjB,MAAM,aAAa,CAAC;AACrB,OAAO,EAAE,QAAQ,EAAE,KAAK,WAAW,EAAE,MAAM,eAAe,CAAC;AAC3D,OAAO,EAAE,YAAY,EAAE,MAAM,WAAW,CAAC;AACzC,OAAO,EAAE,gBAAgB,EAAE,QAAQ,EAAE,MAAM,UAAU,CAAC;AACtD,OAAO,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
export { runCli, } from './cli.js';
|
|
2
|
+
export { createProfile, DEFAULT_BASE_URL, DEFAULT_TIMEOUT_MS, fetchArtist, fetchArtistLlms, fetchOpenApi, fetchSiteLlms, JovieInputError, JovieRequestError, normalizeBaseUrl, validateUsername, } from './client.js';
|
|
3
|
+
export { COMMANDS } from './commands.js';
|
|
4
|
+
export { installSkill } from './init.js';
|
|
5
|
+
export { handleMcpMessage, serveMcp } from './mcp.js';
|
|
6
|
+
export { SKILL_MD } from './skill.js';
|
|
7
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAGL,MAAM,GACP,MAAM,UAAU,CAAC;AAClB,OAAO,EACL,aAAa,EACb,gBAAgB,EAChB,kBAAkB,EAClB,WAAW,EACX,eAAe,EACf,YAAY,EACZ,aAAa,EACb,eAAe,EACf,iBAAiB,EACjB,gBAAgB,EAChB,gBAAgB,GACjB,MAAM,aAAa,CAAC;AACrB,OAAO,EAAE,QAAQ,EAAoB,MAAM,eAAe,CAAC;AAC3D,OAAO,EAAE,YAAY,EAAE,MAAM,WAAW,CAAC;AACzC,OAAO,EAAE,gBAAgB,EAAE,QAAQ,EAAE,MAAM,UAAU,CAAC;AACtD,OAAO,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC"}
|
package/dist/init.d.ts
ADDED
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/** Agent homes whose `skills/` dir loads SKILL.md folders. */
|
|
2
|
+
export declare const SKILL_TARGETS: readonly [{
|
|
3
|
+
readonly agent: "claude";
|
|
4
|
+
readonly home: ".claude";
|
|
5
|
+
}, {
|
|
6
|
+
readonly agent: "codex";
|
|
7
|
+
readonly home: ".codex";
|
|
8
|
+
}, {
|
|
9
|
+
readonly agent: "openclaw";
|
|
10
|
+
readonly home: ".openclaw";
|
|
11
|
+
}, {
|
|
12
|
+
readonly agent: "hermes";
|
|
13
|
+
readonly home: ".hermes";
|
|
14
|
+
}];
|
|
15
|
+
export interface InitResult {
|
|
16
|
+
readonly installed: readonly string[];
|
|
17
|
+
readonly skipped: readonly string[];
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Write `jovie/SKILL.md` into every installed agent's skills dir, or only into
|
|
21
|
+
* `dir` when given. Agents that aren't installed are skipped, never created.
|
|
22
|
+
*/
|
|
23
|
+
export declare function installSkill(homeDir: string, dir?: string): InitResult;
|
|
24
|
+
//# sourceMappingURL=init.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"init.d.ts","sourceRoot":"","sources":["../src/init.ts"],"names":[],"mappings":"AAKA,8DAA8D;AAC9D,eAAO,MAAM,aAAa;;;;;;;;;;;;EAKhB,CAAC;AAEX,MAAM,WAAW,UAAU;IACzB,QAAQ,CAAC,SAAS,EAAE,SAAS,MAAM,EAAE,CAAC;IACtC,QAAQ,CAAC,OAAO,EAAE,SAAS,MAAM,EAAE,CAAC;CACrC;AAED;;;GAGG;AACH,wBAAgB,YAAY,CAAC,OAAO,EAAE,MAAM,EAAE,GAAG,CAAC,EAAE,MAAM,GAAG,UAAU,CAmBtE"}
|
package/dist/init.js
ADDED
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { existsSync, mkdirSync, writeFileSync } from 'node:fs';
|
|
2
|
+
import { join } from 'node:path';
|
|
3
|
+
import { SKILL_MD } from './skill.js';
|
|
4
|
+
/** Agent homes whose `skills/` dir loads SKILL.md folders. */
|
|
5
|
+
export const SKILL_TARGETS = [
|
|
6
|
+
{ agent: 'claude', home: '.claude' },
|
|
7
|
+
{ agent: 'codex', home: '.codex' },
|
|
8
|
+
{ agent: 'openclaw', home: '.openclaw' },
|
|
9
|
+
{ agent: 'hermes', home: '.hermes' },
|
|
10
|
+
];
|
|
11
|
+
/**
|
|
12
|
+
* Write `jovie/SKILL.md` into every installed agent's skills dir, or only into
|
|
13
|
+
* `dir` when given. Agents that aren't installed are skipped, never created.
|
|
14
|
+
*/
|
|
15
|
+
export function installSkill(homeDir, dir) {
|
|
16
|
+
const write = (skillsDir) => {
|
|
17
|
+
const target = join(skillsDir, 'jovie');
|
|
18
|
+
mkdirSync(target, { recursive: true });
|
|
19
|
+
const file = join(target, 'SKILL.md');
|
|
20
|
+
writeFileSync(file, SKILL_MD);
|
|
21
|
+
return file;
|
|
22
|
+
};
|
|
23
|
+
if (dir)
|
|
24
|
+
return { installed: [write(dir)], skipped: [] };
|
|
25
|
+
const installed = [];
|
|
26
|
+
const skipped = [];
|
|
27
|
+
for (const { agent, home } of SKILL_TARGETS) {
|
|
28
|
+
const agentHome = join(homeDir, home);
|
|
29
|
+
if (existsSync(agentHome))
|
|
30
|
+
installed.push(write(join(agentHome, 'skills')));
|
|
31
|
+
else
|
|
32
|
+
skipped.push(agent);
|
|
33
|
+
}
|
|
34
|
+
return { installed, skipped };
|
|
35
|
+
}
|
|
36
|
+
//# sourceMappingURL=init.js.map
|
package/dist/init.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"init.js","sourceRoot":"","sources":["../src/init.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,SAAS,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AAC/D,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAEjC,OAAO,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAEtC,8DAA8D;AAC9D,MAAM,CAAC,MAAM,aAAa,GAAG;IAC3B,EAAE,KAAK,EAAE,QAAQ,EAAE,IAAI,EAAE,SAAS,EAAE;IACpC,EAAE,KAAK,EAAE,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE;IAClC,EAAE,KAAK,EAAE,UAAU,EAAE,IAAI,EAAE,WAAW,EAAE;IACxC,EAAE,KAAK,EAAE,QAAQ,EAAE,IAAI,EAAE,SAAS,EAAE;CAC5B,CAAC;AAOX;;;GAGG;AACH,MAAM,UAAU,YAAY,CAAC,OAAe,EAAE,GAAY;IACxD,MAAM,KAAK,GAAG,CAAC,SAAiB,EAAE,EAAE;QAClC,MAAM,MAAM,GAAG,IAAI,CAAC,SAAS,EAAE,OAAO,CAAC,CAAC;QACxC,SAAS,CAAC,MAAM,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;QACvC,MAAM,IAAI,GAAG,IAAI,CAAC,MAAM,EAAE,UAAU,CAAC,CAAC;QACtC,aAAa,CAAC,IAAI,EAAE,QAAQ,CAAC,CAAC;QAC9B,OAAO,IAAI,CAAC;IACd,CAAC,CAAC;IAEF,IAAI,GAAG;QAAE,OAAO,EAAE,SAAS,EAAE,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,EAAE,OAAO,EAAE,EAAE,EAAE,CAAC;IAEzD,MAAM,SAAS,GAAa,EAAE,CAAC;IAC/B,MAAM,OAAO,GAAa,EAAE,CAAC;IAC7B,KAAK,MAAM,EAAE,KAAK,EAAE,IAAI,EAAE,IAAI,aAAa,EAAE,CAAC;QAC5C,MAAM,SAAS,GAAG,IAAI,CAAC,OAAO,EAAE,IAAI,CAAC,CAAC;QACtC,IAAI,UAAU,CAAC,SAAS,CAAC;YAAE,SAAS,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,SAAS,EAAE,QAAQ,CAAC,CAAC,CAAC,CAAC;;YACvE,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IAC3B,CAAC;IACD,OAAO,EAAE,SAAS,EAAE,OAAO,EAAE,CAAC;AAChC,CAAC"}
|
package/dist/mcp.d.ts
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import type { Readable } from 'node:stream';
|
|
2
|
+
import type { FetchImplementation } from './client.js';
|
|
3
|
+
type JsonRpcId = string | number | null;
|
|
4
|
+
interface JsonRpcMessage {
|
|
5
|
+
readonly jsonrpc?: string;
|
|
6
|
+
readonly id?: JsonRpcId;
|
|
7
|
+
readonly method?: string;
|
|
8
|
+
readonly params?: Record<string, unknown>;
|
|
9
|
+
}
|
|
10
|
+
export interface McpContext {
|
|
11
|
+
readonly version: string;
|
|
12
|
+
readonly baseUrl: string;
|
|
13
|
+
readonly fetchImpl?: FetchImplementation;
|
|
14
|
+
}
|
|
15
|
+
/** Handle one JSON-RPC message; returns the response, or null for notifications. */
|
|
16
|
+
export declare function handleMcpMessage(message: JsonRpcMessage, context: McpContext): Promise<Record<string, unknown> | null>;
|
|
17
|
+
/** Serve MCP over newline-delimited JSON-RPC until input closes. */
|
|
18
|
+
export declare function serveMcp(input: Readable, output: {
|
|
19
|
+
write(chunk: string): unknown;
|
|
20
|
+
}, context: McpContext): Promise<void>;
|
|
21
|
+
export {};
|
|
22
|
+
//# sourceMappingURL=mcp.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mcp.d.ts","sourceRoot":"","sources":["../src/mcp.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AAE5C,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,aAAa,CAAC;AAYvD,KAAK,SAAS,GAAG,MAAM,GAAG,MAAM,GAAG,IAAI,CAAC;AAExC,UAAU,cAAc;IACtB,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,EAAE,CAAC,EAAE,SAAS,CAAC;IACxB,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CAC3C;AAED,MAAM,WAAW,UAAU;IACzB,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,SAAS,CAAC,EAAE,mBAAmB,CAAC;CAC1C;AA0FD,oFAAoF;AACpF,wBAAsB,gBAAgB,CACpC,OAAO,EAAE,cAAc,EACvB,OAAO,EAAE,UAAU,GAClB,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,CAAC,CAoCzC;AAED,oEAAoE;AACpE,wBAAsB,QAAQ,CAC5B,KAAK,EAAE,QAAQ,EACf,MAAM,EAAE;IAAE,KAAK,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAA;CAAE,EACzC,OAAO,EAAE,UAAU,GAClB,OAAO,CAAC,IAAI,CAAC,CAoBf"}
|
package/dist/mcp.js
ADDED
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
import { createInterface } from 'node:readline';
|
|
2
|
+
import { COMMANDS } from './commands.js';
|
|
3
|
+
// ponytail: hand-rolled stdio JSON-RPC (tools only). Adopt
|
|
4
|
+
// @modelcontextprotocol/sdk when we need resources, prompts, or HTTP transport.
|
|
5
|
+
const SUPPORTED_PROTOCOL_VERSIONS = [
|
|
6
|
+
'2025-11-25',
|
|
7
|
+
'2025-06-18',
|
|
8
|
+
'2025-03-26',
|
|
9
|
+
'2024-11-05',
|
|
10
|
+
];
|
|
11
|
+
function toolDefinition(command) {
|
|
12
|
+
const properties = {};
|
|
13
|
+
if (command.arg) {
|
|
14
|
+
properties[command.arg.name] = {
|
|
15
|
+
type: 'string',
|
|
16
|
+
description: command.arg.description,
|
|
17
|
+
};
|
|
18
|
+
}
|
|
19
|
+
if (command.acceptsFull) {
|
|
20
|
+
properties.full = { type: 'boolean', description: 'Fetch the full guide' };
|
|
21
|
+
}
|
|
22
|
+
return {
|
|
23
|
+
name: command.tool,
|
|
24
|
+
description: command.summary,
|
|
25
|
+
inputSchema: {
|
|
26
|
+
type: 'object',
|
|
27
|
+
properties,
|
|
28
|
+
...(command.arg ? { required: [command.arg.name] } : {}),
|
|
29
|
+
additionalProperties: false,
|
|
30
|
+
},
|
|
31
|
+
annotations: {
|
|
32
|
+
readOnlyHint: command.readOnly,
|
|
33
|
+
destructiveHint: false,
|
|
34
|
+
idempotentHint: true,
|
|
35
|
+
openWorldHint: true,
|
|
36
|
+
},
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
function errorText(error) {
|
|
40
|
+
const { code, apiCode, status, retryAfterSeconds, responseBody } = (error ??
|
|
41
|
+
{});
|
|
42
|
+
return JSON.stringify({
|
|
43
|
+
error: {
|
|
44
|
+
code: code ?? 'CLI_ERROR',
|
|
45
|
+
message: error instanceof Error ? error.message : String(error),
|
|
46
|
+
...(apiCode === undefined ? {} : { apiCode }),
|
|
47
|
+
...(status === undefined ? {} : { status }),
|
|
48
|
+
...(retryAfterSeconds === undefined ? {} : { retryAfterSeconds }),
|
|
49
|
+
...(typeof responseBody === 'string' ? { responseBody } : {}),
|
|
50
|
+
},
|
|
51
|
+
});
|
|
52
|
+
}
|
|
53
|
+
async function callTool(params, context) {
|
|
54
|
+
const command = COMMANDS.find(entry => entry.tool === params?.name);
|
|
55
|
+
if (!command) {
|
|
56
|
+
return {
|
|
57
|
+
content: [
|
|
58
|
+
{ type: 'text', text: `Unknown tool: ${String(params?.name)}` },
|
|
59
|
+
],
|
|
60
|
+
isError: true,
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
const args = (params?.arguments ?? {});
|
|
64
|
+
try {
|
|
65
|
+
const result = await command.run({
|
|
66
|
+
arg: command.arg ? String(args[command.arg.name] ?? '') : undefined,
|
|
67
|
+
full: args.full === true,
|
|
68
|
+
}, {
|
|
69
|
+
baseUrl: context.baseUrl,
|
|
70
|
+
fetchImpl: context.fetchImpl,
|
|
71
|
+
userAgent: `jovie-cli/${context.version} mcp`,
|
|
72
|
+
});
|
|
73
|
+
return typeof result === 'string'
|
|
74
|
+
? { content: [{ type: 'text', text: result }] }
|
|
75
|
+
: {
|
|
76
|
+
content: [{ type: 'text', text: JSON.stringify(result) }],
|
|
77
|
+
...(result !== null &&
|
|
78
|
+
typeof result === 'object' &&
|
|
79
|
+
!Array.isArray(result)
|
|
80
|
+
? { structuredContent: result }
|
|
81
|
+
: {}),
|
|
82
|
+
};
|
|
83
|
+
}
|
|
84
|
+
catch (error) {
|
|
85
|
+
return {
|
|
86
|
+
content: [{ type: 'text', text: errorText(error) }],
|
|
87
|
+
isError: true,
|
|
88
|
+
};
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
/** Handle one JSON-RPC message; returns the response, or null for notifications. */
|
|
92
|
+
export async function handleMcpMessage(message, context) {
|
|
93
|
+
if (message.id === undefined)
|
|
94
|
+
return null;
|
|
95
|
+
const reply = (result) => ({
|
|
96
|
+
jsonrpc: '2.0',
|
|
97
|
+
id: message.id,
|
|
98
|
+
result,
|
|
99
|
+
});
|
|
100
|
+
switch (message.method) {
|
|
101
|
+
case 'initialize': {
|
|
102
|
+
const requested = message.params?.protocolVersion;
|
|
103
|
+
return reply({
|
|
104
|
+
protocolVersion: typeof requested === 'string' &&
|
|
105
|
+
SUPPORTED_PROTOCOL_VERSIONS.includes(requested)
|
|
106
|
+
? requested
|
|
107
|
+
: SUPPORTED_PROTOCOL_VERSIONS[0],
|
|
108
|
+
capabilities: { tools: {} },
|
|
109
|
+
serverInfo: { name: 'jovie', title: 'Jovie', version: context.version },
|
|
110
|
+
instructions: 'Create a Jovie artist profile from a Spotify artist URL with create_profile, then give the artist the claimUrl.',
|
|
111
|
+
});
|
|
112
|
+
}
|
|
113
|
+
case 'ping':
|
|
114
|
+
return reply({});
|
|
115
|
+
case 'tools/list':
|
|
116
|
+
return reply({ tools: COMMANDS.map(toolDefinition) });
|
|
117
|
+
case 'tools/call':
|
|
118
|
+
return reply(await callTool(message.params, context));
|
|
119
|
+
default:
|
|
120
|
+
return {
|
|
121
|
+
jsonrpc: '2.0',
|
|
122
|
+
id: message.id,
|
|
123
|
+
error: { code: -32601, message: `Method not found: ${message.method}` },
|
|
124
|
+
};
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
/** Serve MCP over newline-delimited JSON-RPC until input closes. */
|
|
128
|
+
export async function serveMcp(input, output, context) {
|
|
129
|
+
const pending = [];
|
|
130
|
+
for await (const line of createInterface({ input, crlfDelay: Infinity })) {
|
|
131
|
+
if (!line.trim())
|
|
132
|
+
continue;
|
|
133
|
+
let message;
|
|
134
|
+
try {
|
|
135
|
+
message = JSON.parse(line);
|
|
136
|
+
}
|
|
137
|
+
catch {
|
|
138
|
+
output.write(`${JSON.stringify({ jsonrpc: '2.0', id: null, error: { code: -32700, message: 'Parse error' } })}\n`);
|
|
139
|
+
continue;
|
|
140
|
+
}
|
|
141
|
+
pending.push(handleMcpMessage(message, context).then(response => {
|
|
142
|
+
if (response)
|
|
143
|
+
output.write(`${JSON.stringify(response)}\n`);
|
|
144
|
+
}));
|
|
145
|
+
}
|
|
146
|
+
await Promise.all(pending);
|
|
147
|
+
}
|
|
148
|
+
//# sourceMappingURL=mcp.js.map
|
package/dist/mcp.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mcp.js","sourceRoot":"","sources":["../src/mcp.ts"],"names":[],"mappings":"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"}
|
package/dist/skill.d.ts
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
/** The agent skill shipped by `jovie skill` and installed by `jovie init`. */
|
|
2
|
+
export declare const SKILL_MD = "---\nname: jovie\ndescription: Give a music artist a Jovie profile (link-in-bio page with their music, links, events, and merch) from their Spotify artist URL, and look up existing Jovie artist profiles. Use when a user or artist wants a link-in-bio / artist page / smart profile, or asks about an artist on Jovie.\n---\n\n# Jovie\n\nJovie builds a public artist profile (jov.ie/<username>) from a Spotify\nartist URL. No account or API key is needed to create one. The artist later\nclaims it by opening the claim URL and verifying ownership.\n\n## Create a profile for an artist\n\n```sh\nnpx -y @jovie/cli profile create https://open.spotify.com/artist/<id> --json\n```\n\nReturns:\n\n```json\n{\"username\":\"...\",\"profileUrl\":\"https://jov.ie/...\",\"claimUrl\":\"https://jov.ie/.../claim\",\"claimed\":false,\"public\":true,\"created\":true}\n```\n\n- Give the human the `profileUrl` to see the page and the `claimUrl` to\n take ownership. Opening the claim URL requires the artist to verify they\n own the Spotify artist, so share it with the artist only.\n- `created: false` means the profile already existed and was not changed.\n- `claimUrl: null` means the artist already owns the profile.\n- Only Spotify artist URLs work. Find one by searching Spotify for the artist.\n\n## Look up an artist\n\n```sh\nnpx -y @jovie/cli artist get <username> --json # structured profile\nnpx -y @jovie/cli artist llms <username> # markdown guide\n```\n\n## Errors\n\nWith `--json`, failures print `{\"error\":{\"code\":\"...\",\"message\":\"...\"}}`.\nExit codes: 0 ok, 1 request failed, 2 bad input. API failures carry a\nstable `apiCode`; branch on it, never on the message:\n`RATE_LIMITED` (wait `retryAfterSeconds`), `UNSUPPORTED_URL`,\n`ARTIST_NOT_FOUND`, `FEATURE_DISABLED`.\n\n## MCP\n\nThe same tools are available as an MCP server: `npx -y @jovie/cli mcp`\n(stdio). Tools: create_profile, get_artist, get_artist_guide, get_openapi,\nget_docs.\n";
|
|
3
|
+
//# sourceMappingURL=skill.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"skill.d.ts","sourceRoot":"","sources":["../src/skill.ts"],"names":[],"mappings":"AAAA,8EAA8E;AAC9E,eAAO,MAAM,QAAQ,i7DAkDpB,CAAC"}
|
package/dist/skill.js
ADDED
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
/** The agent skill shipped by `jovie skill` and installed by `jovie init`. */
|
|
2
|
+
export const SKILL_MD = `---
|
|
3
|
+
name: jovie
|
|
4
|
+
description: Give a music artist a Jovie profile (link-in-bio page with their music, links, events, and merch) from their Spotify artist URL, and look up existing Jovie artist profiles. Use when a user or artist wants a link-in-bio / artist page / smart profile, or asks about an artist on Jovie.
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# Jovie
|
|
8
|
+
|
|
9
|
+
Jovie builds a public artist profile (jov.ie/<username>) from a Spotify
|
|
10
|
+
artist URL. No account or API key is needed to create one. The artist later
|
|
11
|
+
claims it by opening the claim URL and verifying ownership.
|
|
12
|
+
|
|
13
|
+
## Create a profile for an artist
|
|
14
|
+
|
|
15
|
+
\`\`\`sh
|
|
16
|
+
npx -y @jovie/cli profile create https://open.spotify.com/artist/<id> --json
|
|
17
|
+
\`\`\`
|
|
18
|
+
|
|
19
|
+
Returns:
|
|
20
|
+
|
|
21
|
+
\`\`\`json
|
|
22
|
+
{"username":"...","profileUrl":"https://jov.ie/...","claimUrl":"https://jov.ie/.../claim","claimed":false,"public":true,"created":true}
|
|
23
|
+
\`\`\`
|
|
24
|
+
|
|
25
|
+
- Give the human the \`profileUrl\` to see the page and the \`claimUrl\` to
|
|
26
|
+
take ownership. Opening the claim URL requires the artist to verify they
|
|
27
|
+
own the Spotify artist, so share it with the artist only.
|
|
28
|
+
- \`created: false\` means the profile already existed and was not changed.
|
|
29
|
+
- \`claimUrl: null\` means the artist already owns the profile.
|
|
30
|
+
- Only Spotify artist URLs work. Find one by searching Spotify for the artist.
|
|
31
|
+
|
|
32
|
+
## Look up an artist
|
|
33
|
+
|
|
34
|
+
\`\`\`sh
|
|
35
|
+
npx -y @jovie/cli artist get <username> --json # structured profile
|
|
36
|
+
npx -y @jovie/cli artist llms <username> # markdown guide
|
|
37
|
+
\`\`\`
|
|
38
|
+
|
|
39
|
+
## Errors
|
|
40
|
+
|
|
41
|
+
With \`--json\`, failures print \`{"error":{"code":"...","message":"..."}}\`.
|
|
42
|
+
Exit codes: 0 ok, 1 request failed, 2 bad input. API failures carry a
|
|
43
|
+
stable \`apiCode\`; branch on it, never on the message:
|
|
44
|
+
\`RATE_LIMITED\` (wait \`retryAfterSeconds\`), \`UNSUPPORTED_URL\`,
|
|
45
|
+
\`ARTIST_NOT_FOUND\`, \`FEATURE_DISABLED\`.
|
|
46
|
+
|
|
47
|
+
## MCP
|
|
48
|
+
|
|
49
|
+
The same tools are available as an MCP server: \`npx -y @jovie/cli mcp\`
|
|
50
|
+
(stdio). Tools: create_profile, get_artist, get_artist_guide, get_openapi,
|
|
51
|
+
get_docs.
|
|
52
|
+
`;
|
|
53
|
+
//# sourceMappingURL=skill.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"skill.js","sourceRoot":"","sources":["../src/skill.ts"],"names":[],"mappings":"AAAA,8EAA8E;AAC9E,MAAM,CAAC,MAAM,QAAQ,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAkDvB,CAAC"}
|