@llmindset/hf-mcp 0.2.39 → 0.2.41
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/docs-search/docs-semantic-search.test.js +20 -44
- package/dist/docs-search/docs-semantic-search.test.js.map +1 -1
- package/dist/hf-api-call.d.ts.map +1 -1
- package/dist/hf-api-call.js +21 -7
- package/dist/hf-api-call.js.map +1 -1
- package/dist/jobs/commands/inspect.js +1 -1
- package/dist/jobs/commands/inspect.js.map +1 -1
- package/dist/jobs/commands/logs.js +3 -3
- package/dist/jobs/commands/logs.js.map +1 -1
- package/dist/jobs/commands/ps.js +1 -1
- package/dist/jobs/commands/ps.js.map +1 -1
- package/dist/jobs/commands/run.js +6 -6
- package/dist/jobs/commands/run.js.map +1 -1
- package/dist/jobs/commands/scheduled.js +5 -5
- package/dist/jobs/commands/scheduled.js.map +1 -1
- package/dist/jobs/jobs-tool.d.ts +4 -4
- package/dist/jobs/jobs-tool.d.ts.map +1 -1
- package/dist/jobs/jobs-tool.js +202 -137
- package/dist/jobs/jobs-tool.js.map +1 -1
- package/dist/jobs/schema-help.d.ts +1 -2
- package/dist/jobs/schema-help.d.ts.map +1 -1
- package/dist/jobs/sse-handler.d.ts +3 -0
- package/dist/jobs/sse-handler.d.ts.map +1 -1
- package/dist/jobs/sse-handler.js +4 -1
- package/dist/jobs/sse-handler.js.map +1 -1
- package/dist/jobs/types.d.ts +4 -4
- package/dist/jobs/types.d.ts.map +1 -1
- package/dist/jobs/types.js +8 -4
- package/dist/jobs/types.js.map +1 -1
- package/package.json +1 -1
- package/src/docs-search/docs-semantic-search.test.ts +22 -44
- package/src/hf-api-call.ts +30 -8
- package/src/jobs/commands/inspect.ts +1 -1
- package/src/jobs/commands/logs.ts +3 -3
- package/src/jobs/commands/ps.ts +1 -1
- package/src/jobs/commands/run.ts +6 -6
- package/src/jobs/commands/scheduled.ts +5 -5
- package/src/jobs/jobs-tool.ts +231 -149
- package/src/jobs/schema-help.ts +1 -1
- package/src/jobs/sse-handler.ts +16 -1
- package/src/jobs/types.ts +8 -4
package/dist/jobs/types.js
CHANGED
|
@@ -24,7 +24,11 @@ const commonArgsSchema = z.object({
|
|
|
24
24
|
namespace: z.string().optional().describe('Target namespace (username or organization). Defaults to current user.'),
|
|
25
25
|
});
|
|
26
26
|
export const runArgsSchema = commonArgsSchema.extend({
|
|
27
|
-
image: z
|
|
27
|
+
image: z
|
|
28
|
+
.string()
|
|
29
|
+
.describe('Docker image or HF Space URL (e.g., "python:3.12" or "hf.co/spaces/user/space")')
|
|
30
|
+
.optional()
|
|
31
|
+
.default('python:3.12'),
|
|
28
32
|
command: z
|
|
29
33
|
.union([z.string(), z.array(z.string())])
|
|
30
34
|
.describe('Command to execute. Array format recommended (e.g., ["python", "script.py"]). ' +
|
|
@@ -44,8 +48,8 @@ export const runArgsSchema = commonArgsSchema.extend({
|
|
|
44
48
|
detach: z
|
|
45
49
|
.boolean()
|
|
46
50
|
.optional()
|
|
47
|
-
.default(
|
|
48
|
-
.describe('
|
|
51
|
+
.default(false)
|
|
52
|
+
.describe('If true, return immediately with job ID. If false (default), tail logs for up to 10 seconds.'),
|
|
49
53
|
});
|
|
50
54
|
export const uvArgsSchema = commonArgsSchema.extend({
|
|
51
55
|
script: z
|
|
@@ -61,7 +65,7 @@ export const uvArgsSchema = commonArgsSchema.extend({
|
|
|
61
65
|
.optional()
|
|
62
66
|
.describe('Secrets as key-value pairs. Use HF_TOKEN=$HF_TOKEN to include your token'),
|
|
63
67
|
timeout: z.string().optional().default('30m').describe('Max duration'),
|
|
64
|
-
detach: z.boolean().optional().default(
|
|
68
|
+
detach: z.boolean().optional().default(false).describe('If true, return immediately with job ID. If false (default), tail logs for up to 10 seconds.'),
|
|
65
69
|
});
|
|
66
70
|
export const psArgsSchema = commonArgsSchema.extend({
|
|
67
71
|
all: z.boolean().optional().default(false).describe('Show all jobs (default: only running)'),
|
package/dist/jobs/types.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/jobs/types.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAKxB,MAAM,CAAC,MAAM,WAAW,GAAG,CAAC,WAAW,EAAE,aAAa,EAAE,iBAAiB,EAAE,QAAQ,CAAU,CAAC;AAE9F,MAAM,CAAC,MAAM,WAAW,GAAG;IAC1B,OAAO;IACP,WAAW;IACX,UAAU;IACV,WAAW;IACX,MAAM;IACN,MAAM;IACN,QAAQ;IACR,QAAQ;IACR,QAAQ;IACR,YAAY;IACZ,YAAY;IACZ,cAAc;IACd,cAAc;IACd,YAAY;IACZ,MAAM;IACN,QAAQ;CACC,CAAC;AAEX,MAAM,CAAC,MAAM,mBAAmB,GAAG,CAAC,QAAQ,CAAU,CAAC;AAEvD,MAAM,CAAC,MAAM,WAAW,GAAG,CAAC,GAAG,WAAW,EAAE,GAAG,WAAW,EAAE,GAAG,mBAAmB,CAAU,CAAC;AAqG7F,MAAM,gBAAgB,GAAG,CAAC,CAAC,MAAM,CAAC;IACjC,SAAS,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,wEAAwE,CAAC;CACnH,CAAC,CAAC;AAGH,MAAM,CAAC,MAAM,aAAa,GAAG,gBAAgB,CAAC,MAAM,CAAC;IACpD,KAAK,EAAE,CAAC,
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/jobs/types.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -6,6 +6,17 @@ import { DOC_FETCH_CONFIG } from './doc-fetch.js';
|
|
|
6
6
|
const mockFetch = vi.fn();
|
|
7
7
|
global.fetch = mockFetch as typeof fetch;
|
|
8
8
|
|
|
9
|
+
// Helper to create a proper mock Response
|
|
10
|
+
function createMockResponse(data: unknown) {
|
|
11
|
+
const jsonString = JSON.stringify(data);
|
|
12
|
+
return {
|
|
13
|
+
ok: true,
|
|
14
|
+
text: () => Promise.resolve(jsonString),
|
|
15
|
+
json: () => Promise.resolve(data),
|
|
16
|
+
headers: new Headers({ 'content-type': 'application/json' }),
|
|
17
|
+
};
|
|
18
|
+
}
|
|
19
|
+
|
|
9
20
|
describe('DocSearchTool', () => {
|
|
10
21
|
let docSearchTool: DocSearchTool;
|
|
11
22
|
|
|
@@ -20,10 +31,7 @@ describe('DocSearchTool', () => {
|
|
|
20
31
|
});
|
|
21
32
|
|
|
22
33
|
it('should return no results message when API returns empty array', async () => {
|
|
23
|
-
mockFetch.mockResolvedValueOnce(
|
|
24
|
-
ok: true,
|
|
25
|
-
json: () => Promise.resolve([]),
|
|
26
|
-
});
|
|
34
|
+
mockFetch.mockResolvedValueOnce(createMockResponse([]));
|
|
27
35
|
|
|
28
36
|
const result = await docSearchTool.search({ query: 'nonexistent' });
|
|
29
37
|
expect(result.formatted).toBe(`No documentation found for query 'nonexistent'`);
|
|
@@ -32,10 +40,7 @@ describe('DocSearchTool', () => {
|
|
|
32
40
|
});
|
|
33
41
|
|
|
34
42
|
it('should return no results message with product filter', async () => {
|
|
35
|
-
mockFetch.mockResolvedValueOnce(
|
|
36
|
-
ok: true,
|
|
37
|
-
json: () => Promise.resolve([]),
|
|
38
|
-
});
|
|
43
|
+
mockFetch.mockResolvedValueOnce(createMockResponse([]));
|
|
39
44
|
|
|
40
45
|
const result = await docSearchTool.search({ query: 'nonexistent', product: 'hub' });
|
|
41
46
|
expect(result.formatted).toBe(`No documentation found for query 'nonexistent' in product 'hub'`);
|
|
@@ -70,10 +75,7 @@ describe('DocSearchTool', () => {
|
|
|
70
75
|
},
|
|
71
76
|
];
|
|
72
77
|
|
|
73
|
-
mockFetch.mockResolvedValueOnce(
|
|
74
|
-
ok: true,
|
|
75
|
-
json: () => Promise.resolve(sampleResults),
|
|
76
|
-
});
|
|
78
|
+
mockFetch.mockResolvedValueOnce(createMockResponse(sampleResults));
|
|
77
79
|
|
|
78
80
|
const result = await docSearchTool.search({ query: 'analytics' });
|
|
79
81
|
|
|
@@ -124,10 +126,7 @@ describe('DocSearchTool', () => {
|
|
|
124
126
|
},
|
|
125
127
|
];
|
|
126
128
|
|
|
127
|
-
mockFetch.mockResolvedValueOnce(
|
|
128
|
-
ok: true,
|
|
129
|
-
json: () => Promise.resolve(sampleResults),
|
|
130
|
-
});
|
|
129
|
+
mockFetch.mockResolvedValueOnce(createMockResponse(sampleResults));
|
|
131
130
|
|
|
132
131
|
const result = await docSearchTool.search({ query: 'transformers' });
|
|
133
132
|
|
|
@@ -150,10 +149,7 @@ describe('DocSearchTool', () => {
|
|
|
150
149
|
},
|
|
151
150
|
];
|
|
152
151
|
|
|
153
|
-
mockFetch.mockResolvedValueOnce(
|
|
154
|
-
ok: true,
|
|
155
|
-
json: () => Promise.resolve(sampleResults),
|
|
156
|
-
});
|
|
152
|
+
mockFetch.mockResolvedValueOnce(createMockResponse(sampleResults));
|
|
157
153
|
|
|
158
154
|
const result = await docSearchTool.search({ query: 'special' });
|
|
159
155
|
|
|
@@ -176,10 +172,7 @@ describe('DocSearchTool', () => {
|
|
|
176
172
|
},
|
|
177
173
|
];
|
|
178
174
|
|
|
179
|
-
mockFetch.mockResolvedValueOnce(
|
|
180
|
-
ok: true,
|
|
181
|
-
json: () => Promise.resolve(sampleResults),
|
|
182
|
-
});
|
|
175
|
+
mockFetch.mockResolvedValueOnce(createMockResponse(sampleResults));
|
|
183
176
|
|
|
184
177
|
const result = await docSearchTool.search({ query: 'html' });
|
|
185
178
|
|
|
@@ -233,10 +226,7 @@ describe('DocSearchTool', () => {
|
|
|
233
226
|
},
|
|
234
227
|
];
|
|
235
228
|
|
|
236
|
-
mockFetch.mockResolvedValueOnce(
|
|
237
|
-
ok: true,
|
|
238
|
-
json: () => Promise.resolve(sampleResults),
|
|
239
|
-
});
|
|
229
|
+
mockFetch.mockResolvedValueOnce(createMockResponse(sampleResults));
|
|
240
230
|
|
|
241
231
|
const result = await docSearchTool.search({ query: 'test' });
|
|
242
232
|
|
|
@@ -263,10 +253,7 @@ describe('DocSearchTool', () => {
|
|
|
263
253
|
});
|
|
264
254
|
|
|
265
255
|
it('should include product filter in API call when provided', async () => {
|
|
266
|
-
mockFetch.mockResolvedValueOnce(
|
|
267
|
-
ok: true,
|
|
268
|
-
json: () => Promise.resolve([]),
|
|
269
|
-
});
|
|
256
|
+
mockFetch.mockResolvedValueOnce(createMockResponse([]));
|
|
270
257
|
|
|
271
258
|
await docSearchTool.search({ query: 'test', product: 'hub' });
|
|
272
259
|
|
|
@@ -301,10 +288,7 @@ describe('DocSearchTool', () => {
|
|
|
301
288
|
},
|
|
302
289
|
];
|
|
303
290
|
|
|
304
|
-
mockFetch.mockResolvedValueOnce(
|
|
305
|
-
ok: true,
|
|
306
|
-
json: () => Promise.resolve(sampleResults),
|
|
307
|
-
});
|
|
291
|
+
mockFetch.mockResolvedValueOnce(createMockResponse(sampleResults));
|
|
308
292
|
|
|
309
293
|
const result = await docSearchTool.search({ query: 'analytics' });
|
|
310
294
|
|
|
@@ -357,10 +341,7 @@ describe('DocSearchTool', () => {
|
|
|
357
341
|
});
|
|
358
342
|
}
|
|
359
343
|
|
|
360
|
-
mockFetch.mockResolvedValueOnce(
|
|
361
|
-
ok: true,
|
|
362
|
-
json: () => Promise.resolve(manyResults),
|
|
363
|
-
});
|
|
344
|
+
mockFetch.mockResolvedValueOnce(createMockResponse(manyResults));
|
|
364
345
|
|
|
365
346
|
const result = await smallBudgetTool.search({ query: 'test' });
|
|
366
347
|
|
|
@@ -423,10 +404,7 @@ describe('DocSearchTool', () => {
|
|
|
423
404
|
},
|
|
424
405
|
];
|
|
425
406
|
|
|
426
|
-
mockFetch.mockResolvedValueOnce(
|
|
427
|
-
ok: true,
|
|
428
|
-
json: () => Promise.resolve(sampleResults),
|
|
429
|
-
});
|
|
407
|
+
mockFetch.mockResolvedValueOnce(createMockResponse(sampleResults));
|
|
430
408
|
|
|
431
409
|
const result = await docSearchTool.search({ query: 'test' });
|
|
432
410
|
|
package/src/hf-api-call.ts
CHANGED
|
@@ -111,14 +111,11 @@ export class HfApiCall<TParams = Record<string, string | undefined>, TResponse =
|
|
|
111
111
|
|
|
112
112
|
clearTimeout(timeoutId);
|
|
113
113
|
|
|
114
|
+
const responseBodyText = await response.text();
|
|
115
|
+
|
|
114
116
|
if (!response.ok) {
|
|
115
117
|
// Try to get error details from response body
|
|
116
|
-
|
|
117
|
-
try {
|
|
118
|
-
responseBody = await response.text();
|
|
119
|
-
} catch {
|
|
120
|
-
// Ignore if we can't read the body
|
|
121
|
-
}
|
|
118
|
+
const responseBody: string | undefined = responseBodyText || undefined;
|
|
122
119
|
|
|
123
120
|
// Log the error for debugging
|
|
124
121
|
console.error(`[API Error] ${response.status} ${response.statusText}`);
|
|
@@ -134,7 +131,33 @@ export class HfApiCall<TParams = Record<string, string | undefined>, TResponse =
|
|
|
134
131
|
);
|
|
135
132
|
}
|
|
136
133
|
|
|
137
|
-
|
|
134
|
+
const contentType = response.headers.get('content-type') ?? '';
|
|
135
|
+
const trimmedBody = responseBodyText.trim();
|
|
136
|
+
const looksLikeJson =
|
|
137
|
+
contentType.includes('application/json') || trimmedBody.startsWith('{') || trimmedBody.startsWith('[');
|
|
138
|
+
|
|
139
|
+
if (trimmedBody.length === 0) {
|
|
140
|
+
return undefined as T;
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
if (looksLikeJson) {
|
|
144
|
+
try {
|
|
145
|
+
return JSON.parse(responseBodyText) as T;
|
|
146
|
+
} catch (error) {
|
|
147
|
+
throw new Error(
|
|
148
|
+
`API request failed: Unable to parse JSON response (${error instanceof Error ? error.message : 'unknown error'})`
|
|
149
|
+
);
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
if (trimmedBody.toUpperCase() === 'OK') {
|
|
154
|
+
return undefined as T;
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
const truncatedBody = trimmedBody.length > 200 ? `${trimmedBody.slice(0, 200)}…` : trimmedBody;
|
|
158
|
+
throw new Error(
|
|
159
|
+
`API request failed: Unexpected non-JSON response${contentType ? ` (content-type: ${contentType})` : ''}: ${truncatedBody}`
|
|
160
|
+
);
|
|
138
161
|
} catch (error) {
|
|
139
162
|
// Re-throw HfApiError as-is to preserve status information
|
|
140
163
|
if (error instanceof HfApiError) {
|
|
@@ -184,5 +207,4 @@ export class HfApiCall<TParams = Record<string, string | undefined>, TResponse =
|
|
|
184
207
|
const url = this.buildUrl(params);
|
|
185
208
|
return this.fetchFromApi<T>(url, options);
|
|
186
209
|
}
|
|
187
|
-
|
|
188
210
|
}
|
|
@@ -34,5 +34,5 @@ export async function cancelCommand(args: CancelArgs, client: JobsApiClient): Pr
|
|
|
34
34
|
|
|
35
35
|
return `✓ Job ${args.job_id} has been cancelled.
|
|
36
36
|
|
|
37
|
-
To verify
|
|
37
|
+
To verify, call this tool with \`{"operation": "inspect", "args": {"job_id": "${args.job_id}"}}\``;
|
|
38
38
|
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { LogsArgs } from '../types.js';
|
|
2
2
|
import type { JobsApiClient } from '../api-client.js';
|
|
3
|
-
import { fetchJobLogs } from '../sse-handler.js';
|
|
3
|
+
import { fetchJobLogs, DEFAULT_LOG_WAIT_MS, DEFAULT_LOG_WAIT_SECONDS } from '../sse-handler.js';
|
|
4
4
|
|
|
5
5
|
/**
|
|
6
6
|
* Execute the 'logs' command
|
|
@@ -14,7 +14,7 @@ export async function logsCommand(args: LogsArgs, client: JobsApiClient, token?:
|
|
|
14
14
|
// Fetch logs with timeout and line limit
|
|
15
15
|
const result = await fetchJobLogs(logsUrl, {
|
|
16
16
|
token,
|
|
17
|
-
maxDuration:
|
|
17
|
+
maxDuration: DEFAULT_LOG_WAIT_MS,
|
|
18
18
|
maxLines: args.tail,
|
|
19
19
|
});
|
|
20
20
|
|
|
@@ -29,7 +29,7 @@ export async function logsCommand(args: LogsArgs, client: JobsApiClient, token?:
|
|
|
29
29
|
if (result.finished) {
|
|
30
30
|
response += '\n\n✓ Job finished.';
|
|
31
31
|
} else if (result.truncated) {
|
|
32
|
-
response +=
|
|
32
|
+
response += `\n\n⚠ Log collection stopped after ${DEFAULT_LOG_WAIT_SECONDS} seconds. Job may still be running.`;
|
|
33
33
|
}
|
|
34
34
|
|
|
35
35
|
return response;
|
package/src/jobs/commands/ps.ts
CHANGED
|
@@ -31,7 +31,7 @@ export async function psCommand(args: PsArgs, client: JobsApiClient): Promise<st
|
|
|
31
31
|
if (args.all) {
|
|
32
32
|
return 'No jobs found.';
|
|
33
33
|
}
|
|
34
|
-
return 'No running jobs found. Use `{"all": true}` to show all jobs.';
|
|
34
|
+
return 'No running jobs found. Use `{"args": {"all": true}}` to show all jobs.';
|
|
35
35
|
}
|
|
36
36
|
|
|
37
37
|
return `**Jobs (${jobs.length} of ${allJobs.length} total):**
|
package/src/jobs/commands/run.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import type { RunArgs, UvArgs } from '../types.js';
|
|
2
2
|
import type { JobsApiClient } from '../api-client.js';
|
|
3
3
|
import { createJobSpec } from './utils.js';
|
|
4
|
-
import { fetchJobLogs } from '../sse-handler.js';
|
|
4
|
+
import { fetchJobLogs, DEFAULT_LOG_WAIT_MS, DEFAULT_MAX_LOG_LINES, DEFAULT_LOG_WAIT_SECONDS } from '../sse-handler.js';
|
|
5
5
|
import { resolveUvCommand, UV_DEFAULT_IMAGE } from './uv-utils.js';
|
|
6
6
|
|
|
7
7
|
/**
|
|
@@ -33,18 +33,18 @@ export async function runCommand(args: RunArgs, client: JobsApiClient, token?: s
|
|
|
33
33
|
**Status:** ${job.status.stage}
|
|
34
34
|
**View at:** ${jobUrl}
|
|
35
35
|
|
|
36
|
-
To check logs
|
|
37
|
-
To inspect
|
|
36
|
+
To check logs, call this tool with \`{"operation": "logs", "args": {"job_id": "${job.id}"}}\`
|
|
37
|
+
To inspect, call this tool with \`{"operation": "inspect", "args": {"job_id": "${job.id}"}}\``;
|
|
38
38
|
}
|
|
39
39
|
|
|
40
40
|
// Not detached - fetch logs
|
|
41
41
|
const logsUrl = client.getLogsUrl(job.id, job.owner.name);
|
|
42
|
-
const logResult = await fetchJobLogs(logsUrl, { token, maxDuration:
|
|
42
|
+
const logResult = await fetchJobLogs(logsUrl, { token, maxDuration: DEFAULT_LOG_WAIT_MS, maxLines: DEFAULT_MAX_LOG_LINES });
|
|
43
43
|
|
|
44
44
|
let response = `Job started: ${job.id}\n\n`;
|
|
45
45
|
|
|
46
46
|
if (logResult.logs.length > 0) {
|
|
47
|
-
response +=
|
|
47
|
+
response += `**Logs (last ${DEFAULT_MAX_LOG_LINES} lines):**\n\`\`\`\n`;
|
|
48
48
|
response += logResult.logs.join('\n');
|
|
49
49
|
response += '\n```\n\n';
|
|
50
50
|
}
|
|
@@ -52,7 +52,7 @@ To inspect: \`hf_jobs("inspect", {"job_id": "${job.id}"})\``;
|
|
|
52
52
|
if (logResult.finished) {
|
|
53
53
|
response += `Job finished. Full details: ${jobUrl}`;
|
|
54
54
|
} else if (logResult.truncated) {
|
|
55
|
-
response += `Log collection stopped after
|
|
55
|
+
response += `Log collection stopped after ${DEFAULT_LOG_WAIT_SECONDS}s. Job may still be running.\n`;
|
|
56
56
|
response += `View full logs: ${jobUrl}`;
|
|
57
57
|
}
|
|
58
58
|
|
|
@@ -47,8 +47,8 @@ export async function scheduledRunCommand(
|
|
|
47
47
|
**Suspended:** ${scheduledJob.suspend ? 'Yes' : 'No'}
|
|
48
48
|
**Next Run:** ${scheduledJob.nextRun || 'N/A'}
|
|
49
49
|
|
|
50
|
-
To inspect
|
|
51
|
-
To list all
|
|
50
|
+
To inspect, call this tool with \`{"operation": "scheduled inspect", "args": {"scheduled_job_id": "${scheduledJob.id}"}}\`
|
|
51
|
+
To list all, call this tool with \`{"operation": "scheduled ps"}\``;
|
|
52
52
|
}
|
|
53
53
|
|
|
54
54
|
/**
|
|
@@ -106,7 +106,7 @@ export async function scheduledPsCommand(args: ScheduledPsArgs, client: JobsApiC
|
|
|
106
106
|
if (args.all) {
|
|
107
107
|
return 'No scheduled jobs found.';
|
|
108
108
|
}
|
|
109
|
-
return 'No active scheduled jobs found. Use `{"all": true}` to show suspended jobs.';
|
|
109
|
+
return 'No active scheduled jobs found. Use `{"args": {"all": true}}` to show suspended jobs.';
|
|
110
110
|
}
|
|
111
111
|
|
|
112
112
|
return `**Scheduled Jobs (${jobs.length} of ${allJobs.length} total):**
|
|
@@ -143,7 +143,7 @@ export async function scheduledSuspendCommand(args: ScheduledJobArgs, client: Jo
|
|
|
143
143
|
|
|
144
144
|
return `✓ Scheduled job ${args.scheduled_job_id} has been suspended.
|
|
145
145
|
|
|
146
|
-
To resume
|
|
146
|
+
To resume, call this tool with \`{"operation": "scheduled resume", "args": {"scheduled_job_id": "${args.scheduled_job_id}"}}\``;
|
|
147
147
|
}
|
|
148
148
|
|
|
149
149
|
/**
|
|
@@ -155,5 +155,5 @@ export async function scheduledResumeCommand(args: ScheduledJobArgs, client: Job
|
|
|
155
155
|
|
|
156
156
|
return `✓ Scheduled job ${args.scheduled_job_id} has been resumed.
|
|
157
157
|
|
|
158
|
-
To inspect
|
|
158
|
+
To inspect, call this tool with \`{"operation": "scheduled inspect", "args": {"scheduled_job_id": "${args.scheduled_job_id}"}}\``;
|
|
159
159
|
}
|