@llmindset/hf-mcp 0.2.32 → 0.2.34

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.
Files changed (91) hide show
  1. package/dist/docs-search/docs-semantic-search.d.ts +2 -2
  2. package/dist/docs-search/docs-semantic-search.d.ts.map +1 -1
  3. package/dist/docs-search/docs-semantic-search.js +56 -21
  4. package/dist/docs-search/docs-semantic-search.js.map +1 -1
  5. package/dist/hf-api-call.d.ts.map +1 -1
  6. package/dist/hf-api-call.js +4 -0
  7. package/dist/hf-api-call.js.map +1 -1
  8. package/dist/index.d.ts +1 -0
  9. package/dist/index.d.ts.map +1 -1
  10. package/dist/index.js +1 -0
  11. package/dist/index.js.map +1 -1
  12. package/dist/jobs/api-client.d.ts +19 -0
  13. package/dist/jobs/api-client.d.ts.map +1 -0
  14. package/dist/jobs/api-client.js +104 -0
  15. package/dist/jobs/api-client.js.map +1 -0
  16. package/dist/jobs/commands/inspect.d.ts +5 -0
  17. package/dist/jobs/commands/inspect.d.ts.map +1 -0
  18. package/dist/jobs/commands/inspect.js +21 -0
  19. package/dist/jobs/commands/inspect.js.map +1 -0
  20. package/dist/jobs/commands/logs.d.ts +4 -0
  21. package/dist/jobs/commands/logs.d.ts.map +1 -0
  22. package/dist/jobs/commands/logs.js +24 -0
  23. package/dist/jobs/commands/logs.js.map +1 -0
  24. package/dist/jobs/commands/ps.d.ts +4 -0
  25. package/dist/jobs/commands/ps.d.ts.map +1 -0
  26. package/dist/jobs/commands/ps.js +23 -0
  27. package/dist/jobs/commands/ps.js.map +1 -0
  28. package/dist/jobs/commands/run.d.ts +5 -0
  29. package/dist/jobs/commands/run.d.ts.map +1 -0
  30. package/dist/jobs/commands/run.js +89 -0
  31. package/dist/jobs/commands/run.js.map +1 -0
  32. package/dist/jobs/commands/scheduled.d.ts +10 -0
  33. package/dist/jobs/commands/scheduled.d.ts.map +1 -0
  34. package/dist/jobs/commands/scheduled.js +111 -0
  35. package/dist/jobs/commands/scheduled.js.map +1 -0
  36. package/dist/jobs/commands/utils.d.ts +19 -0
  37. package/dist/jobs/commands/utils.d.ts.map +1 -0
  38. package/dist/jobs/commands/utils.js +99 -0
  39. package/dist/jobs/commands/utils.js.map +1 -0
  40. package/dist/jobs/formatters.d.ts +6 -0
  41. package/dist/jobs/formatters.d.ts.map +1 -0
  42. package/dist/jobs/formatters.js +98 -0
  43. package/dist/jobs/formatters.js.map +1 -0
  44. package/dist/jobs/sse-handler.d.ts +12 -0
  45. package/dist/jobs/sse-handler.d.ts.map +1 -0
  46. package/dist/jobs/sse-handler.js +80 -0
  47. package/dist/jobs/sse-handler.js.map +1 -0
  48. package/dist/jobs/tool.d.ts +35 -0
  49. package/dist/jobs/tool.d.ts.map +1 -0
  50. package/dist/jobs/tool.js +333 -0
  51. package/dist/jobs/tool.js.map +1 -0
  52. package/dist/jobs/types.d.ts +295 -0
  53. package/dist/jobs/types.d.ts.map +1 -0
  54. package/dist/jobs/types.js +95 -0
  55. package/dist/jobs/types.js.map +1 -0
  56. package/dist/tool-ids.d.ts +3 -2
  57. package/dist/tool-ids.d.ts.map +1 -1
  58. package/dist/tool-ids.js +10 -2
  59. package/dist/tool-ids.js.map +1 -1
  60. package/dist/types/tool-result.d.ts +1 -0
  61. package/dist/types/tool-result.d.ts.map +1 -1
  62. package/dist/use-space.d.ts +0 -1
  63. package/dist/use-space.d.ts.map +1 -1
  64. package/dist/use-space.js +0 -1
  65. package/dist/use-space.js.map +1 -1
  66. package/package.json +4 -2
  67. package/src/docs-search/docs-semantic-search.ts +71 -20
  68. package/src/hf-api-call.ts +6 -0
  69. package/src/index.ts +1 -0
  70. package/src/jobs/api-client.ts +195 -0
  71. package/src/jobs/commands/inspect.ts +38 -0
  72. package/src/jobs/commands/logs.ts +36 -0
  73. package/src/jobs/commands/ps.ts +40 -0
  74. package/src/jobs/commands/run.ts +134 -0
  75. package/src/jobs/commands/scheduled.ts +189 -0
  76. package/src/jobs/commands/utils.ts +158 -0
  77. package/src/jobs/formatters.ts +149 -0
  78. package/src/jobs/sse-handler.ts +144 -0
  79. package/src/jobs/tool.ts +435 -0
  80. package/src/jobs/types.ts +237 -0
  81. package/src/tool-ids.ts +11 -1
  82. package/src/types/tool-result.ts +6 -0
  83. package/src/use-space.ts +0 -1
  84. package/test/jobs/command-translation.spec.ts +277 -0
  85. package/test/jobs/formatters.spec.ts +267 -0
  86. package/test/jobs/uv-command.spec.ts +81 -0
  87. package/dist/types/mcp-ui-server-shim.d.ts +0 -37
  88. package/dist/types/mcp-ui-server-shim.d.ts.map +0 -1
  89. package/dist/types/mcp-ui-server-shim.js +0 -2
  90. package/dist/types/mcp-ui-server-shim.js.map +0 -1
  91. package/src/types/mcp-ui-server-shim.ts +0 -35
@@ -0,0 +1,149 @@
1
+ import type { JobInfo, ScheduledJobInfo } from './types.js';
2
+
3
+ /**
4
+ * Truncate a string to a maximum length with ellipsis
5
+ */
6
+ function truncate(str: string, maxLength: number): string {
7
+ if (str.length <= maxLength) {
8
+ return str;
9
+ }
10
+ return str.substring(0, maxLength - 3) + '...';
11
+ }
12
+
13
+ /**
14
+ * Format a date string to a readable format
15
+ */
16
+ function formatDate(dateStr: string | undefined): string {
17
+ if (!dateStr) {
18
+ return 'N/A';
19
+ }
20
+ try {
21
+ const date = new Date(dateStr);
22
+ return date.toISOString().replace('T', ' ').substring(0, 19);
23
+ } catch {
24
+ return dateStr;
25
+ }
26
+ }
27
+
28
+ /**
29
+ * Format command array as a single string
30
+ */
31
+ function formatCommand(command?: string[]): string {
32
+ if (!command || command.length === 0) {
33
+ return 'N/A';
34
+ }
35
+ return command.join(' ');
36
+ }
37
+
38
+ /**
39
+ * Get image/space identifier from job
40
+ */
41
+ function getImageOrSpace(job: JobInfo | { dockerImage?: string; spaceId?: string }): string {
42
+ if (job.spaceId) {
43
+ return job.spaceId;
44
+ }
45
+ if (job.dockerImage) {
46
+ return job.dockerImage;
47
+ }
48
+ return 'N/A';
49
+ }
50
+
51
+ /**
52
+ * Format jobs as a markdown table
53
+ */
54
+ export function formatJobsTable(jobs: JobInfo[]): string {
55
+ if (jobs.length === 0) {
56
+ return 'No jobs found.';
57
+ }
58
+
59
+ // Calculate dynamic ID column width - never truncate IDs!
60
+ const longestIdLength = Math.max(...jobs.map((job) => job.id.length));
61
+ const idColumnWidth = Math.max(longestIdLength, 'JOB ID'.length);
62
+
63
+ // Define column widths
64
+ const colWidths = {
65
+ id: idColumnWidth,
66
+ image: 20,
67
+ command: 30,
68
+ created: 19,
69
+ status: 12,
70
+ };
71
+
72
+ // Build header
73
+ const header = `| ${'JOB ID'.padEnd(colWidths.id)} | ${'IMAGE/SPACE'.padEnd(colWidths.image)} | ${'COMMAND'.padEnd(colWidths.command)} | ${'CREATED'.padEnd(colWidths.created)} | ${'STATUS'.padEnd(colWidths.status)} |`;
74
+ const separator = `|${'-'.repeat(colWidths.id + 2)}|${'-'.repeat(colWidths.image + 2)}|${'-'.repeat(colWidths.command + 2)}|${'-'.repeat(colWidths.created + 2)}|${'-'.repeat(colWidths.status + 2)}|`;
75
+
76
+ // Build rows
77
+ const rows = jobs.map((job) => {
78
+ const id = job.id; // Never truncate IDs!
79
+ const image = truncate(getImageOrSpace(job), colWidths.image);
80
+ const command = truncate(formatCommand(job.command), colWidths.command);
81
+ const created = truncate(formatDate(job.createdAt), colWidths.created);
82
+ const status = truncate(job.status.stage, colWidths.status);
83
+
84
+ return `| ${id.padEnd(colWidths.id)} | ${image.padEnd(colWidths.image)} | ${command.padEnd(colWidths.command)} | ${created.padEnd(colWidths.created)} | ${status.padEnd(colWidths.status)} |`;
85
+ });
86
+
87
+ return [header, separator, ...rows].join('\n');
88
+ }
89
+
90
+ /**
91
+ * Format scheduled jobs as a markdown table
92
+ */
93
+ export function formatScheduledJobsTable(jobs: ScheduledJobInfo[]): string {
94
+ if (jobs.length === 0) {
95
+ return 'No scheduled jobs found.';
96
+ }
97
+
98
+ // Calculate dynamic ID column width - never truncate IDs!
99
+ const longestIdLength = Math.max(...jobs.map((job) => job.id.length));
100
+ const idColumnWidth = Math.max(longestIdLength, 'ID'.length);
101
+
102
+ // Define column widths
103
+ const colWidths = {
104
+ id: idColumnWidth,
105
+ schedule: 12,
106
+ image: 18,
107
+ command: 25,
108
+ lastRun: 19,
109
+ nextRun: 19,
110
+ suspend: 9,
111
+ };
112
+
113
+ // Build header
114
+ const header = `| ${'ID'.padEnd(colWidths.id)} | ${'SCHEDULE'.padEnd(colWidths.schedule)} | ${'IMAGE/SPACE'.padEnd(colWidths.image)} | ${'COMMAND'.padEnd(colWidths.command)} | ${'LAST RUN'.padEnd(colWidths.lastRun)} | ${'NEXT RUN'.padEnd(colWidths.nextRun)} | ${'SUSPENDED'.padEnd(colWidths.suspend)} |`;
115
+ const separator = `|${'-'.repeat(colWidths.id + 2)}|${'-'.repeat(colWidths.schedule + 2)}|${'-'.repeat(colWidths.image + 2)}|${'-'.repeat(colWidths.command + 2)}|${'-'.repeat(colWidths.lastRun + 2)}|${'-'.repeat(colWidths.nextRun + 2)}|${'-'.repeat(colWidths.suspend + 2)}|`;
116
+
117
+ // Build rows
118
+ const rows = jobs.map((job) => {
119
+ const id = job.id; // Never truncate IDs!
120
+ const schedule = truncate(job.schedule, colWidths.schedule);
121
+ const image = truncate(getImageOrSpace(job.jobSpec), colWidths.image);
122
+ const command = truncate(formatCommand(job.jobSpec.command), colWidths.command);
123
+ const lastRun = truncate(formatDate(job.lastRun), colWidths.lastRun);
124
+ const nextRun = truncate(formatDate(job.nextRun), colWidths.nextRun);
125
+ const suspend = job.suspend ? 'Yes' : 'No';
126
+
127
+ return `| ${id.padEnd(colWidths.id)} | ${schedule.padEnd(colWidths.schedule)} | ${image.padEnd(colWidths.image)} | ${command.padEnd(colWidths.command)} | ${lastRun.padEnd(colWidths.lastRun)} | ${nextRun.padEnd(colWidths.nextRun)} | ${suspend.padEnd(colWidths.suspend)} |`;
128
+ });
129
+
130
+ return [header, separator, ...rows].join('\n');
131
+ }
132
+
133
+ /**
134
+ * Format job details as JSON in a markdown code block
135
+ */
136
+ export function formatJobDetails(jobs: JobInfo | JobInfo[]): string {
137
+ const jobArray = Array.isArray(jobs) ? jobs : [jobs];
138
+ const json = JSON.stringify(jobArray, null, 2);
139
+ return `\`\`\`json\n${json}\n\`\`\``;
140
+ }
141
+
142
+ /**
143
+ * Format scheduled job details as JSON in a markdown code block
144
+ */
145
+ export function formatScheduledJobDetails(jobs: ScheduledJobInfo | ScheduledJobInfo[]): string {
146
+ const jobArray = Array.isArray(jobs) ? jobs : [jobs];
147
+ const json = JSON.stringify(jobArray, null, 2);
148
+ return `\`\`\`json\n${json}\n\`\`\``;
149
+ }
@@ -0,0 +1,144 @@
1
+ import type { LogEvent } from './types.js';
2
+
3
+ /**
4
+ * Options for fetching logs via SSE
5
+ */
6
+ export interface SseLogOptions {
7
+ /** Maximum time to collect logs in milliseconds (default: 10000 = 10s) */
8
+ maxDuration?: number;
9
+ /** Maximum number of lines to return (default: 20) */
10
+ maxLines?: number;
11
+ /** HF API token for authentication */
12
+ token?: string;
13
+ }
14
+
15
+ /**
16
+ * Result from fetching logs
17
+ */
18
+ export interface SseLogResult {
19
+ /** Log lines collected */
20
+ logs: string[];
21
+ /** Whether the job finished during collection */
22
+ finished: boolean;
23
+ /** Whether collection was truncated due to timeout */
24
+ truncated: boolean;
25
+ }
26
+
27
+ /**
28
+ * Fetch logs from a job via Server-Sent Events (SSE)
29
+ * Collects logs for a maximum duration and returns the last N lines
30
+ *
31
+ * @param url - The SSE endpoint URL for job logs
32
+ * @param options - Options for log collection
33
+ * @returns Log result with collected lines and status
34
+ */
35
+ export async function fetchJobLogs(url: string, options: SseLogOptions = {}): Promise<SseLogResult> {
36
+ const { maxDuration = 10000, maxLines = 20, token } = options;
37
+
38
+ const logLines: string[] = [];
39
+ let finished = false;
40
+ let truncated = false;
41
+
42
+ // Create abort controller for timeout
43
+ const controller = new AbortController();
44
+ const timeoutId = setTimeout(() => {
45
+ controller.abort();
46
+ truncated = true;
47
+ }, maxDuration);
48
+
49
+ try {
50
+ const headers: Record<string, string> = {
51
+ Accept: 'text/event-stream',
52
+ };
53
+ if (token) {
54
+ headers['Authorization'] = `Bearer ${token}`;
55
+ }
56
+
57
+ const response = await fetch(url, {
58
+ headers,
59
+ signal: controller.signal,
60
+ });
61
+
62
+ if (!response.ok) {
63
+ throw new Error(`Failed to fetch logs: ${response.status} ${response.statusText}`);
64
+ }
65
+
66
+ if (!response.body) {
67
+ throw new Error('Response body is null');
68
+ }
69
+
70
+ // Process the SSE stream
71
+ const reader = response.body.getReader();
72
+ const decoder = new TextDecoder();
73
+ let buffer = '';
74
+
75
+ while (true) {
76
+ const { done, value } = await reader.read();
77
+
78
+ if (done) {
79
+ break;
80
+ }
81
+
82
+ // Decode chunk and add to buffer
83
+ buffer += decoder.decode(value, { stream: true });
84
+
85
+ // Process complete lines
86
+ const lines = buffer.split('\n');
87
+ buffer = lines.pop() || ''; // Keep incomplete line in buffer
88
+
89
+ for (const line of lines) {
90
+ // SSE format: "data: {json}"
91
+ if (line.startsWith('data: ')) {
92
+ try {
93
+ const jsonStr = line.substring(6); // Remove "data: " prefix
94
+ const event = JSON.parse(jsonStr) as LogEvent;
95
+
96
+ // Filter out system messages
97
+ if (event.data.startsWith('===== Job started')) {
98
+ continue;
99
+ }
100
+
101
+ // Check for job finished message
102
+ if (event.data.startsWith('===== Job finished')) {
103
+ finished = true;
104
+ // Extract status from message if present
105
+ // e.g., "===== Job finished: status=COMPLETED ====="
106
+ logLines.push(event.data);
107
+ break;
108
+ }
109
+
110
+ // Add log line
111
+ logLines.push(event.data);
112
+ } catch {
113
+ // Ignore malformed JSON
114
+ continue;
115
+ }
116
+ }
117
+ }
118
+
119
+ // Break if job finished
120
+ if (finished) {
121
+ break;
122
+ }
123
+ }
124
+
125
+ // Close the reader
126
+ await reader.cancel();
127
+ } catch (error) {
128
+ // If aborted due to timeout, that's expected
129
+ if ((error as Error).name !== 'AbortError') {
130
+ throw error;
131
+ }
132
+ } finally {
133
+ clearTimeout(timeoutId);
134
+ }
135
+
136
+ // Return last N lines
137
+ const lastLines = logLines.slice(-maxLines);
138
+
139
+ return {
140
+ logs: lastLines,
141
+ finished,
142
+ truncated: truncated && !finished,
143
+ };
144
+ }