proxmox-mcps 0.1.0

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 (217) hide show
  1. package/.env.example +60 -0
  2. package/.mcp.json.example +19 -0
  3. package/LICENSE +21 -0
  4. package/README.md +72 -0
  5. package/dist/cli/check-config.d.ts +3 -0
  6. package/dist/cli/check-config.d.ts.map +1 -0
  7. package/dist/cli/check-config.js +29 -0
  8. package/dist/cli/check-config.js.map +1 -0
  9. package/dist/cli/print-tools.d.ts +4 -0
  10. package/dist/cli/print-tools.d.ts.map +1 -0
  11. package/dist/cli/print-tools.js +45 -0
  12. package/dist/cli/print-tools.js.map +1 -0
  13. package/dist/config/env.d.ts +183 -0
  14. package/dist/config/env.d.ts.map +1 -0
  15. package/dist/config/env.js +149 -0
  16. package/dist/config/env.js.map +1 -0
  17. package/dist/config/index.d.ts +26 -0
  18. package/dist/config/index.d.ts.map +1 -0
  19. package/dist/config/index.js +42 -0
  20. package/dist/config/index.js.map +1 -0
  21. package/dist/config/types.d.ts +60 -0
  22. package/dist/config/types.d.ts.map +1 -0
  23. package/dist/config/types.js +50 -0
  24. package/dist/config/types.js.map +1 -0
  25. package/dist/format/response.d.ts +40 -0
  26. package/dist/format/response.d.ts.map +1 -0
  27. package/dist/format/response.js +109 -0
  28. package/dist/format/response.js.map +1 -0
  29. package/dist/index.d.ts +3 -0
  30. package/dist/index.d.ts.map +1 -0
  31. package/dist/index.js +200 -0
  32. package/dist/index.js.map +1 -0
  33. package/dist/jobs/sqlite-store.d.ts +34 -0
  34. package/dist/jobs/sqlite-store.d.ts.map +1 -0
  35. package/dist/jobs/sqlite-store.js +282 -0
  36. package/dist/jobs/sqlite-store.js.map +1 -0
  37. package/dist/jobs/store.d.ts +66 -0
  38. package/dist/jobs/store.d.ts.map +1 -0
  39. package/dist/jobs/store.js +101 -0
  40. package/dist/jobs/store.js.map +1 -0
  41. package/dist/log.d.ts +24 -0
  42. package/dist/log.d.ts.map +1 -0
  43. package/dist/log.js +64 -0
  44. package/dist/log.js.map +1 -0
  45. package/dist/proxmox/auth.d.ts +30 -0
  46. package/dist/proxmox/auth.d.ts.map +1 -0
  47. package/dist/proxmox/auth.js +39 -0
  48. package/dist/proxmox/auth.js.map +1 -0
  49. package/dist/proxmox/client.d.ts +28 -0
  50. package/dist/proxmox/client.d.ts.map +1 -0
  51. package/dist/proxmox/client.js +192 -0
  52. package/dist/proxmox/client.js.map +1 -0
  53. package/dist/proxmox/errors.d.ts +51 -0
  54. package/dist/proxmox/errors.d.ts.map +1 -0
  55. package/dist/proxmox/errors.js +80 -0
  56. package/dist/proxmox/errors.js.map +1 -0
  57. package/dist/proxmox/paths.d.ts +126 -0
  58. package/dist/proxmox/paths.d.ts.map +1 -0
  59. package/dist/proxmox/paths.js +157 -0
  60. package/dist/proxmox/paths.js.map +1 -0
  61. package/dist/proxmox/types.d.ts +255 -0
  62. package/dist/proxmox/types.d.ts.map +1 -0
  63. package/dist/proxmox/types.js +9 -0
  64. package/dist/proxmox/types.js.map +1 -0
  65. package/dist/retry.d.ts +18 -0
  66. package/dist/retry.d.ts.map +1 -0
  67. package/dist/retry.js +50 -0
  68. package/dist/retry.js.map +1 -0
  69. package/dist/safety/policy.d.ts +23 -0
  70. package/dist/safety/policy.d.ts.map +1 -0
  71. package/dist/safety/policy.js +81 -0
  72. package/dist/safety/policy.js.map +1 -0
  73. package/dist/safety/risk.d.ts +3 -0
  74. package/dist/safety/risk.d.ts.map +1 -0
  75. package/dist/safety/risk.js +234 -0
  76. package/dist/safety/risk.js.map +1 -0
  77. package/dist/security/url-guard.d.ts +22 -0
  78. package/dist/security/url-guard.d.ts.map +1 -0
  79. package/dist/security/url-guard.js +166 -0
  80. package/dist/security/url-guard.js.map +1 -0
  81. package/dist/server.d.ts +24 -0
  82. package/dist/server.d.ts.map +1 -0
  83. package/dist/server.js +74 -0
  84. package/dist/server.js.map +1 -0
  85. package/dist/ssh/client.d.ts +32 -0
  86. package/dist/ssh/client.d.ts.map +1 -0
  87. package/dist/ssh/client.js +128 -0
  88. package/dist/ssh/client.js.map +1 -0
  89. package/dist/tools/backup-schedule.d.ts +10 -0
  90. package/dist/tools/backup-schedule.d.ts.map +1 -0
  91. package/dist/tools/backup-schedule.js +194 -0
  92. package/dist/tools/backup-schedule.js.map +1 -0
  93. package/dist/tools/backup.d.ts +7 -0
  94. package/dist/tools/backup.d.ts.map +1 -0
  95. package/dist/tools/backup.js +163 -0
  96. package/dist/tools/backup.js.map +1 -0
  97. package/dist/tools/cluster.d.ts +7 -0
  98. package/dist/tools/cluster.d.ts.map +1 -0
  99. package/dist/tools/cluster.js +20 -0
  100. package/dist/tools/cluster.js.map +1 -0
  101. package/dist/tools/container/config.d.ts +7 -0
  102. package/dist/tools/container/config.d.ts.map +1 -0
  103. package/dist/tools/container/config.js +97 -0
  104. package/dist/tools/container/config.js.map +1 -0
  105. package/dist/tools/container/console.d.ts +7 -0
  106. package/dist/tools/container/console.d.ts.map +1 -0
  107. package/dist/tools/container/console.js +65 -0
  108. package/dist/tools/container/console.js.map +1 -0
  109. package/dist/tools/container/crud.d.ts +7 -0
  110. package/dist/tools/container/crud.d.ts.map +1 -0
  111. package/dist/tools/container/crud.js +362 -0
  112. package/dist/tools/container/crud.js.map +1 -0
  113. package/dist/tools/container/diagnostics.d.ts +7 -0
  114. package/dist/tools/container/diagnostics.d.ts.map +1 -0
  115. package/dist/tools/container/diagnostics.js +115 -0
  116. package/dist/tools/container/diagnostics.js.map +1 -0
  117. package/dist/tools/container/migration.d.ts +7 -0
  118. package/dist/tools/container/migration.d.ts.map +1 -0
  119. package/dist/tools/container/migration.js +134 -0
  120. package/dist/tools/container/migration.js.map +1 -0
  121. package/dist/tools/context.d.ts +21 -0
  122. package/dist/tools/context.d.ts.map +1 -0
  123. package/dist/tools/context.js +2 -0
  124. package/dist/tools/context.js.map +1 -0
  125. package/dist/tools/ha.d.ts +7 -0
  126. package/dist/tools/ha.d.ts.map +1 -0
  127. package/dist/tools/ha.js +241 -0
  128. package/dist/tools/ha.js.map +1 -0
  129. package/dist/tools/helpers.d.ts +15 -0
  130. package/dist/tools/helpers.d.ts.map +1 -0
  131. package/dist/tools/helpers.js +7 -0
  132. package/dist/tools/helpers.js.map +1 -0
  133. package/dist/tools/index.d.ts +10 -0
  134. package/dist/tools/index.d.ts.map +1 -0
  135. package/dist/tools/index.js +66 -0
  136. package/dist/tools/index.js.map +1 -0
  137. package/dist/tools/iso.d.ts +7 -0
  138. package/dist/tools/iso.d.ts.map +1 -0
  139. package/dist/tools/iso.js +131 -0
  140. package/dist/tools/iso.js.map +1 -0
  141. package/dist/tools/jobs.d.ts +11 -0
  142. package/dist/tools/jobs.d.ts.map +1 -0
  143. package/dist/tools/jobs.js +173 -0
  144. package/dist/tools/jobs.js.map +1 -0
  145. package/dist/tools/node-admin.d.ts +10 -0
  146. package/dist/tools/node-admin.d.ts.map +1 -0
  147. package/dist/tools/node-admin.js +361 -0
  148. package/dist/tools/node-admin.js.map +1 -0
  149. package/dist/tools/node-certs.d.ts +7 -0
  150. package/dist/tools/node-certs.d.ts.map +1 -0
  151. package/dist/tools/node-certs.js +36 -0
  152. package/dist/tools/node-certs.js.map +1 -0
  153. package/dist/tools/node-disks.d.ts +7 -0
  154. package/dist/tools/node-disks.d.ts.map +1 -0
  155. package/dist/tools/node-disks.js +100 -0
  156. package/dist/tools/node-disks.js.map +1 -0
  157. package/dist/tools/node-network.d.ts +7 -0
  158. package/dist/tools/node-network.d.ts.map +1 -0
  159. package/dist/tools/node-network.js +102 -0
  160. package/dist/tools/node-network.js.map +1 -0
  161. package/dist/tools/node-services.d.ts +7 -0
  162. package/dist/tools/node-services.d.ts.map +1 -0
  163. package/dist/tools/node-services.js +39 -0
  164. package/dist/tools/node-services.js.map +1 -0
  165. package/dist/tools/node.d.ts +7 -0
  166. package/dist/tools/node.d.ts.map +1 -0
  167. package/dist/tools/node.js +85 -0
  168. package/dist/tools/node.js.map +1 -0
  169. package/dist/tools/pools.d.ts +10 -0
  170. package/dist/tools/pools.d.ts.map +1 -0
  171. package/dist/tools/pools.js +111 -0
  172. package/dist/tools/pools.js.map +1 -0
  173. package/dist/tools/replication.d.ts +7 -0
  174. package/dist/tools/replication.d.ts.map +1 -0
  175. package/dist/tools/replication.js +116 -0
  176. package/dist/tools/replication.js.map +1 -0
  177. package/dist/tools/sdn.d.ts +7 -0
  178. package/dist/tools/sdn.d.ts.map +1 -0
  179. package/dist/tools/sdn.js +358 -0
  180. package/dist/tools/sdn.js.map +1 -0
  181. package/dist/tools/snapshot.d.ts +10 -0
  182. package/dist/tools/snapshot.d.ts.map +1 -0
  183. package/dist/tools/snapshot.js +115 -0
  184. package/dist/tools/snapshot.js.map +1 -0
  185. package/dist/tools/storage-admin.d.ts +9 -0
  186. package/dist/tools/storage-admin.d.ts.map +1 -0
  187. package/dist/tools/storage-admin.js +126 -0
  188. package/dist/tools/storage-admin.js.map +1 -0
  189. package/dist/tools/storage.d.ts +7 -0
  190. package/dist/tools/storage.d.ts.map +1 -0
  191. package/dist/tools/storage.js +20 -0
  192. package/dist/tools/storage.js.map +1 -0
  193. package/dist/tools/tasks.d.ts +11 -0
  194. package/dist/tools/tasks.d.ts.map +1 -0
  195. package/dist/tools/tasks.js +85 -0
  196. package/dist/tools/tasks.js.map +1 -0
  197. package/dist/tools/vm/config.d.ts +28 -0
  198. package/dist/tools/vm/config.d.ts.map +1 -0
  199. package/dist/tools/vm/config.js +221 -0
  200. package/dist/tools/vm/config.js.map +1 -0
  201. package/dist/tools/vm/console.d.ts +9 -0
  202. package/dist/tools/vm/console.d.ts.map +1 -0
  203. package/dist/tools/vm/console.js +141 -0
  204. package/dist/tools/vm/console.js.map +1 -0
  205. package/dist/tools/vm/crud.d.ts +10 -0
  206. package/dist/tools/vm/crud.d.ts.map +1 -0
  207. package/dist/tools/vm/crud.js +333 -0
  208. package/dist/tools/vm/crud.js.map +1 -0
  209. package/dist/tools/vm/diagnostics.d.ts +10 -0
  210. package/dist/tools/vm/diagnostics.d.ts.map +1 -0
  211. package/dist/tools/vm/diagnostics.js +256 -0
  212. package/dist/tools/vm/diagnostics.js.map +1 -0
  213. package/dist/tools/vm/migration.d.ts +7 -0
  214. package/dist/tools/vm/migration.d.ts.map +1 -0
  215. package/dist/tools/vm/migration.js +131 -0
  216. package/dist/tools/vm/migration.js.map +1 -0
  217. package/package.json +74 -0
@@ -0,0 +1,282 @@
1
+ /**
2
+ * SQLite-backed JobStore.
3
+ *
4
+ * Persists long-running Proxmox jobs across restarts. Schema is migrated
5
+ * forward by version — see `migrate()` for the canonical list of changes.
6
+ *
7
+ * Backed by `better-sqlite3` (synchronous, fast, single-process). For multi-
8
+ * process use, enable WAL mode (set by default) and serialize via a mutex.
9
+ */
10
+ import BetterSqlite3 from "better-sqlite3";
11
+ import { randomUUID } from "node:crypto";
12
+ import { mkdirSync } from "node:fs";
13
+ import { dirname } from "node:path";
14
+ const SCHEMA_VERSION = 1;
15
+ const SCHEMA_DDL = {
16
+ 1: `
17
+ CREATE TABLE IF NOT EXISTS jobs (
18
+ job_id TEXT PRIMARY KEY,
19
+ upid TEXT,
20
+ tool TEXT NOT NULL,
21
+ args_json TEXT NOT NULL,
22
+ node TEXT,
23
+ status TEXT NOT NULL,
24
+ started_at INTEGER NOT NULL,
25
+ ended_at INTEGER,
26
+ progress INTEGER,
27
+ exit_status TEXT,
28
+ result_json TEXT,
29
+ last_error TEXT,
30
+ retry_count INTEGER NOT NULL DEFAULT 0,
31
+ previous_upids_json TEXT NOT NULL DEFAULT '[]',
32
+ retry_spec_json TEXT
33
+ );
34
+ CREATE INDEX IF NOT EXISTS idx_jobs_started_at ON jobs(started_at DESC);
35
+ CREATE INDEX IF NOT EXISTS idx_jobs_status_started ON jobs(status, started_at DESC);
36
+ CREATE INDEX IF NOT EXISTS idx_jobs_tool_started ON jobs(tool, started_at DESC);
37
+ `,
38
+ };
39
+ export class SqliteJobStore {
40
+ db;
41
+ ttlMs;
42
+ logger;
43
+ // Prepared statements (cached for perf)
44
+ stmtInsert;
45
+ stmtGet;
46
+ stmtList;
47
+ stmtUpdate;
48
+ stmtDelete;
49
+ stmtEvict;
50
+ stmtSetUpid;
51
+ constructor(opts) {
52
+ this.ttlMs = opts.ttlHours * 60 * 60 * 1000;
53
+ this.logger = opts.logger;
54
+ // Ensure parent directory exists
55
+ mkdirSync(dirname(opts.sqlitePath), { recursive: true });
56
+ this.db = new BetterSqlite3(opts.sqlitePath);
57
+ this.db.pragma("journal_mode = WAL");
58
+ this.db.pragma("synchronous = NORMAL");
59
+ this.db.pragma("busy_timeout = 5000");
60
+ this.db.pragma("foreign_keys = ON");
61
+ this.migrate();
62
+ this.stmtInsert = this.db.prepare(`
63
+ INSERT INTO jobs (
64
+ job_id, upid, tool, args_json, node, status, started_at, retry_count,
65
+ previous_upids_json, retry_spec_json
66
+ ) VALUES (
67
+ @job_id, @upid, @tool, @args_json, @node, @status, @started_at, @retry_count,
68
+ @previous_upids_json, @retry_spec_json
69
+ )
70
+ `);
71
+ this.stmtGet = this.db.prepare(`SELECT * FROM jobs WHERE job_id = ?`);
72
+ this.stmtList = this.db.prepare(`
73
+ SELECT * FROM jobs
74
+ WHERE (@status IS NULL OR status = @status)
75
+ AND (@tool IS NULL OR tool = @tool)
76
+ ORDER BY started_at DESC
77
+ LIMIT @limit
78
+ `);
79
+ this.stmtUpdate = this.db.prepare(`
80
+ UPDATE jobs SET
81
+ started_at = COALESCE(@started_at, started_at),
82
+ upid = COALESCE(@upid, upid),
83
+ status = COALESCE(@status, status),
84
+ progress = COALESCE(@progress, progress),
85
+ exit_status = COALESCE(@exit_status, exit_status),
86
+ ended_at = COALESCE(@ended_at, ended_at),
87
+ result_json = COALESCE(@result_json, result_json),
88
+ last_error = COALESCE(@last_error, last_error),
89
+ retry_count = COALESCE(@retry_count, retry_count),
90
+ previous_upids_json = COALESCE(@previous_upids_json, previous_upids_json),
91
+ retry_spec_json = COALESCE(@retry_spec_json, retry_spec_json)
92
+ WHERE job_id = @job_id
93
+ `);
94
+ this.stmtDelete = this.db.prepare(`DELETE FROM jobs WHERE job_id = ?`);
95
+ this.stmtEvict = this.db.prepare(`DELETE FROM jobs WHERE COALESCE(ended_at, started_at) < ?`);
96
+ this.stmtSetUpid = this.db.prepare(`
97
+ UPDATE jobs SET
98
+ previous_upids_json = @previous_upids_json,
99
+ upid = @upid,
100
+ status = 'running'
101
+ WHERE job_id = @job_id
102
+ `);
103
+ }
104
+ // ---- JobStore interface --------------------------------------------------
105
+ create(opts) {
106
+ const job = {
107
+ job_id: randomUUID(),
108
+ upid: opts.upid ?? null,
109
+ tool: opts.tool,
110
+ args: scrubArgs(opts.args),
111
+ node: opts.node ?? null,
112
+ status: opts.upid ? "running" : "queued",
113
+ started_at: Date.now(),
114
+ ended_at: null,
115
+ progress: null,
116
+ exit_status: null,
117
+ result: null,
118
+ last_error: null,
119
+ retry_count: 0,
120
+ previous_upids: [],
121
+ retry_spec: { tool: opts.tool, args: scrubArgs(opts.args) },
122
+ };
123
+ this.stmtInsert.run({
124
+ job_id: job.job_id,
125
+ upid: job.upid,
126
+ tool: job.tool,
127
+ args_json: JSON.stringify(job.args),
128
+ node: job.node,
129
+ status: job.status,
130
+ started_at: job.started_at,
131
+ retry_count: job.retry_count,
132
+ previous_upids_json: JSON.stringify(job.previous_upids),
133
+ retry_spec_json: JSON.stringify(job.retry_spec),
134
+ });
135
+ this.logger?.debug({ job_id: job.job_id, tool: job.tool, upid: job.upid }, "jobs.created");
136
+ return job;
137
+ }
138
+ get(jobId) {
139
+ const row = this.stmtGet.get(jobId);
140
+ return row ? rowToJob(row) : null;
141
+ }
142
+ list(filter = {}) {
143
+ const rows = this.stmtList.all({
144
+ status: filter.status ?? null,
145
+ tool: filter.tool ?? null,
146
+ limit: filter.limit ?? 100,
147
+ });
148
+ return rows.map(rowToJob);
149
+ }
150
+ setUpid(jobId, upid) {
151
+ const existing = this.get(jobId);
152
+ if (!existing)
153
+ return;
154
+ const previous = [...existing.previous_upids];
155
+ if (existing.upid)
156
+ previous.push(existing.upid);
157
+ this.stmtSetUpid.run({
158
+ job_id: jobId,
159
+ upid,
160
+ previous_upids_json: JSON.stringify(previous),
161
+ });
162
+ }
163
+ update(jobId, patch) {
164
+ // prepared statement has all named params; provide null for any field
165
+ // we're not updating so better-sqlite3 doesn't throw "Missing parameter".
166
+ const row = {
167
+ job_id: jobId,
168
+ started_at: patch.started_at !== undefined ? patch.started_at : null,
169
+ upid: patch.upid !== undefined ? patch.upid : null,
170
+ status: patch.status !== undefined ? patch.status : null,
171
+ progress: patch.progress !== undefined ? patch.progress : null,
172
+ exit_status: patch.exit_status !== undefined ? patch.exit_status : null,
173
+ ended_at: patch.ended_at !== undefined ? patch.ended_at : null,
174
+ result_json: patch.result !== undefined ? JSON.stringify(patch.result) : null,
175
+ last_error: patch.last_error !== undefined ? patch.last_error : null,
176
+ retry_count: patch.retry_count !== undefined ? patch.retry_count : null,
177
+ previous_upids_json: patch.previous_upids !== undefined ? JSON.stringify(patch.previous_upids) : null,
178
+ retry_spec_json: patch.retry_spec !== undefined ? JSON.stringify(patch.retry_spec) : null,
179
+ };
180
+ this.stmtUpdate.run(row);
181
+ }
182
+ delete(jobId) {
183
+ const result = this.stmtDelete.run(jobId);
184
+ return result.changes > 0;
185
+ }
186
+ evictExpired() {
187
+ const cutoff = Date.now() - this.ttlMs;
188
+ const result = this.stmtEvict.run(cutoff);
189
+ if (result.changes > 0) {
190
+ this.logger?.debug({ removed: result.changes }, "jobs.evicted");
191
+ }
192
+ return result.changes;
193
+ }
194
+ close() {
195
+ this.db.close();
196
+ }
197
+ // ---- Internals -----------------------------------------------------------
198
+ migrate() {
199
+ // Bootstrap schema_migrations table
200
+ this.db.exec(`
201
+ CREATE TABLE IF NOT EXISTS schema_migrations (
202
+ version INTEGER PRIMARY KEY,
203
+ applied_at INTEGER NOT NULL
204
+ );
205
+ `);
206
+ const applied = this.db.prepare(`SELECT MAX(version) AS v FROM schema_migrations`).get().v ?? 0;
207
+ for (let v = applied + 1; v <= SCHEMA_VERSION; v++) {
208
+ const ddl = SCHEMA_DDL[v];
209
+ if (!ddl)
210
+ continue;
211
+ this.db.transaction(() => {
212
+ this.db.exec(ddl);
213
+ this.db.prepare(`INSERT INTO schema_migrations (version, applied_at) VALUES (?, ?)`).run(v, Date.now());
214
+ })();
215
+ this.logger?.info({ version: v }, "jobs.migration_applied");
216
+ }
217
+ }
218
+ }
219
+ function rowToJob(row) {
220
+ let result = null;
221
+ try {
222
+ if (row.result_json)
223
+ result = JSON.parse(row.result_json);
224
+ }
225
+ catch {
226
+ /* ignore malformed */
227
+ }
228
+ let retrySpec = null;
229
+ try {
230
+ if (row.retry_spec_json)
231
+ retrySpec = JSON.parse(row.retry_spec_json);
232
+ }
233
+ catch {
234
+ /* ignore */
235
+ }
236
+ let previousUpids = [];
237
+ try {
238
+ if (row.previous_upids_json)
239
+ previousUpids = JSON.parse(row.previous_upids_json);
240
+ }
241
+ catch {
242
+ /* ignore */
243
+ }
244
+ let args = {};
245
+ try {
246
+ if (row.args_json)
247
+ args = JSON.parse(row.args_json);
248
+ }
249
+ catch {
250
+ /* ignore */
251
+ }
252
+ return {
253
+ job_id: row.job_id,
254
+ upid: row.upid,
255
+ tool: row.tool,
256
+ args,
257
+ node: row.node,
258
+ status: row.status,
259
+ started_at: row.started_at,
260
+ ended_at: row.ended_at,
261
+ progress: row.progress,
262
+ exit_status: row.exit_status,
263
+ result,
264
+ last_error: row.last_error,
265
+ retry_count: row.retry_count,
266
+ previous_upids: previousUpids,
267
+ retry_spec: retrySpec,
268
+ };
269
+ }
270
+ function scrubArgs(args) {
271
+ const out = {};
272
+ for (const [k, v] of Object.entries(args)) {
273
+ if (k === "approval_token" || k === "password" || k === "new_password" || k === "cipassword") {
274
+ out[k] = "[REDACTED]";
275
+ }
276
+ else {
277
+ out[k] = v;
278
+ }
279
+ }
280
+ return out;
281
+ }
282
+ //# sourceMappingURL=sqlite-store.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sqlite-store.js","sourceRoot":"","sources":["../../src/jobs/sqlite-store.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,66 @@
1
+ import type { Logger } from "../log.js";
2
+ export type JobStatus = "queued" | "running" | "completed" | "failed" | "cancelled";
3
+ export interface JobRecord {
4
+ job_id: string;
5
+ upid: string | null;
6
+ tool: string;
7
+ args: Record<string, unknown>;
8
+ node: string | null;
9
+ status: JobStatus;
10
+ started_at: number;
11
+ ended_at: number | null;
12
+ progress: number | null;
13
+ exit_status: string | null;
14
+ result: unknown;
15
+ last_error: string | null;
16
+ retry_count: number;
17
+ previous_upids: string[];
18
+ /** Stored recipe to re-invoke the tool on retry. */
19
+ retry_spec: RetrySpec | null;
20
+ }
21
+ export interface RetrySpec {
22
+ tool: string;
23
+ args: Record<string, unknown>;
24
+ }
25
+ export interface CreateJobOpts {
26
+ tool: string;
27
+ args: Record<string, unknown>;
28
+ node?: string | null;
29
+ upid?: string | null;
30
+ }
31
+ export interface JobStore {
32
+ create(opts: CreateJobOpts): JobRecord;
33
+ get(jobId: string): JobRecord | null;
34
+ list(filter?: {
35
+ status?: JobStatus;
36
+ tool?: string;
37
+ limit?: number;
38
+ }): JobRecord[];
39
+ setUpid(jobId: string, upid: string): void;
40
+ update(jobId: string, patch: Partial<JobRecord>): void;
41
+ delete(jobId: string): boolean;
42
+ /** Remove jobs older than `ttlHours`. */
43
+ evictExpired(): number;
44
+ }
45
+ export interface InMemoryJobStoreOptions {
46
+ ttlHours: number;
47
+ logger?: Logger;
48
+ }
49
+ export declare class InMemoryJobStore implements JobStore {
50
+ private readonly jobs;
51
+ private readonly ttlMs;
52
+ private readonly logger;
53
+ constructor(opts: InMemoryJobStoreOptions);
54
+ create(opts: CreateJobOpts): JobRecord;
55
+ get(jobId: string): JobRecord | null;
56
+ list(filter?: {
57
+ status?: JobStatus;
58
+ tool?: string;
59
+ limit?: number;
60
+ }): JobRecord[];
61
+ setUpid(jobId: string, upid: string): void;
62
+ update(jobId: string, patch: Partial<JobRecord>): void;
63
+ delete(jobId: string): boolean;
64
+ evictExpired(): number;
65
+ }
66
+ //# sourceMappingURL=store.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"store.d.ts","sourceRoot":"","sources":["../../src/jobs/store.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,101 @@
1
+ /**
2
+ * JobStore — track long-running Proxmox tasks behind stable job_ids.
3
+ *
4
+ * Phase 1 ships an in-memory implementation behind a JobStore interface, so
5
+ * Phase 2 can swap in SQLite-backed persistence without changing tool code.
6
+ */
7
+ import { randomUUID } from "node:crypto";
8
+ export class InMemoryJobStore {
9
+ jobs = new Map();
10
+ ttlMs;
11
+ logger;
12
+ constructor(opts) {
13
+ this.ttlMs = opts.ttlHours * 60 * 60 * 1000;
14
+ this.logger = opts.logger;
15
+ }
16
+ create(opts) {
17
+ const job = {
18
+ job_id: randomUUID(),
19
+ upid: opts.upid ?? null,
20
+ tool: opts.tool,
21
+ args: scrubArgs(opts.args),
22
+ node: opts.node ?? null,
23
+ status: opts.upid ? "running" : "queued",
24
+ started_at: Date.now(),
25
+ ended_at: null,
26
+ progress: null,
27
+ exit_status: null,
28
+ result: null,
29
+ last_error: null,
30
+ retry_count: 0,
31
+ previous_upids: [],
32
+ retry_spec: { tool: opts.tool, args: scrubArgs(opts.args) },
33
+ };
34
+ this.jobs.set(job.job_id, job);
35
+ this.logger?.debug({ job_id: job.job_id, tool: job.tool, upid: job.upid }, "jobs.created");
36
+ return job;
37
+ }
38
+ get(jobId) {
39
+ return this.jobs.get(jobId) ?? null;
40
+ }
41
+ list(filter = {}) {
42
+ const all = Array.from(this.jobs.values());
43
+ const filtered = all.filter((j) => {
44
+ if (filter.status && j.status !== filter.status)
45
+ return false;
46
+ if (filter.tool && j.tool !== filter.tool)
47
+ return false;
48
+ return true;
49
+ });
50
+ // Newest first
51
+ filtered.sort((a, b) => b.started_at - a.started_at);
52
+ return filter.limit ? filtered.slice(0, filter.limit) : filtered;
53
+ }
54
+ setUpid(jobId, upid) {
55
+ const job = this.jobs.get(jobId);
56
+ if (!job)
57
+ return;
58
+ if (job.upid) {
59
+ job.previous_upids.push(job.upid);
60
+ }
61
+ job.upid = upid;
62
+ job.status = "running";
63
+ }
64
+ update(jobId, patch) {
65
+ const job = this.jobs.get(jobId);
66
+ if (!job)
67
+ return;
68
+ Object.assign(job, patch);
69
+ }
70
+ delete(jobId) {
71
+ return this.jobs.delete(jobId);
72
+ }
73
+ evictExpired() {
74
+ const cutoff = Date.now() - this.ttlMs;
75
+ let removed = 0;
76
+ for (const [id, job] of this.jobs) {
77
+ const referenceTime = job.ended_at ?? job.started_at;
78
+ if (referenceTime < cutoff) {
79
+ this.jobs.delete(id);
80
+ removed++;
81
+ }
82
+ }
83
+ if (removed > 0) {
84
+ this.logger?.debug({ removed }, "jobs.evicted");
85
+ }
86
+ return removed;
87
+ }
88
+ }
89
+ function scrubArgs(args) {
90
+ const out = {};
91
+ for (const [k, v] of Object.entries(args)) {
92
+ if (k === "approval_token" || k === "password" || k === "new_password" || k === "cipassword") {
93
+ out[k] = "[REDACTED]";
94
+ }
95
+ else {
96
+ out[k] = v;
97
+ }
98
+ }
99
+ return out;
100
+ }
101
+ //# sourceMappingURL=store.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"store.js","sourceRoot":"","sources":["../../src/jobs/store.ts"],"names":[],"mappings":"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"}
package/dist/log.d.ts ADDED
@@ -0,0 +1,24 @@
1
+ /**
2
+ * Logger singleton — pino configured for stdio MCP transport.
3
+ *
4
+ * All log lines go to **stderr** (stdout is reserved for JSON-RPC).
5
+ * Sensitive fields (tokens, passwords, SSH keys) are redacted automatically.
6
+ */
7
+ import { type Logger } from "pino";
8
+ export type { Logger };
9
+ export interface LoggerConfig {
10
+ level: "debug" | "info" | "warn" | "error";
11
+ pretty: boolean;
12
+ }
13
+ /**
14
+ * Build (or return cached) logger instance.
15
+ *
16
+ * @param cfg.level - pino log level
17
+ * @param cfg.pretty - pretty-print via pino-pretty (dev only)
18
+ */
19
+ export declare function getLogger(cfg?: LoggerConfig): Logger;
20
+ /**
21
+ * Reset the cached logger. Useful for tests.
22
+ */
23
+ export declare function resetLogger(): void;
24
+ //# sourceMappingURL=log.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"log.d.ts","sourceRoot":"","sources":["../src/log.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,OAAa,EAAE,KAAK,MAAM,EAAsB,MAAM,MAAM,CAAC;AAE7D,YAAY,EAAE,MAAM,EAAE,CAAC;AA0BvB,MAAM,WAAW,YAAY;IAC3B,KAAK,EAAE,OAAO,GAAG,MAAM,GAAG,MAAM,GAAG,OAAO,CAAC;IAC3C,MAAM,EAAE,OAAO,CAAC;CACjB;AAID;;;;;GAKG;AACH,wBAAgB,SAAS,CAAC,GAAG,GAAE,YAA+C,GAAG,MAAM,CAuBtF;AAED;;GAEG;AACH,wBAAgB,WAAW,IAAI,IAAI,CAElC"}
package/dist/log.js ADDED
@@ -0,0 +1,64 @@
1
+ /**
2
+ * Logger singleton — pino configured for stdio MCP transport.
3
+ *
4
+ * All log lines go to **stderr** (stdout is reserved for JSON-RPC).
5
+ * Sensitive fields (tokens, passwords, SSH keys) are redacted automatically.
6
+ */
7
+ import pino from "pino";
8
+ /** Fields that should never appear in log output. */
9
+ const REDACT_PATHS = [
10
+ "*.token_value",
11
+ "*.token",
12
+ "*.tokenValue",
13
+ "*.password",
14
+ "*.ssh_password",
15
+ "*.ssh_private_key",
16
+ "*.approval_token",
17
+ "*.approvalToken",
18
+ "*.new_password",
19
+ "*.cipassword",
20
+ "api.token",
21
+ "config.PROXMOX_TOKEN_VALUE",
22
+ "config.PROXMOX_SSH_PASSWORD",
23
+ "config.PROXMOX_MCP_APPROVAL_TOKEN",
24
+ "config.proxmox.tokenValue",
25
+ "config.safety.approvalToken",
26
+ "config.proxmox.tokenName",
27
+ "env.PROXMOX_TOKEN_VALUE",
28
+ "env.PROXMOX_SSH_PASSWORD",
29
+ "env.PROXMOX_MCP_APPROVAL_TOKEN",
30
+ ];
31
+ let _logger = null;
32
+ /**
33
+ * Build (or return cached) logger instance.
34
+ *
35
+ * @param cfg.level - pino log level
36
+ * @param cfg.pretty - pretty-print via pino-pretty (dev only)
37
+ */
38
+ export function getLogger(cfg = { level: "info", pretty: false }) {
39
+ if (_logger)
40
+ return _logger;
41
+ const options = {
42
+ level: cfg.level,
43
+ redact: { paths: REDACT_PATHS, censor: "[REDACTED]" },
44
+ base: { service: "proxmox-mcp" },
45
+ timestamp: pino.stdTimeFunctions.isoTime,
46
+ };
47
+ if (cfg.pretty) {
48
+ _logger = pino(options, pino.transport({
49
+ target: "pino-pretty",
50
+ options: { colorize: true, translateTime: "SYS:HH:MM:ss.l" },
51
+ }));
52
+ }
53
+ else {
54
+ _logger = pino(options);
55
+ }
56
+ return _logger;
57
+ }
58
+ /**
59
+ * Reset the cached logger. Useful for tests.
60
+ */
61
+ export function resetLogger() {
62
+ _logger = null;
63
+ }
64
+ //# sourceMappingURL=log.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"log.js","sourceRoot":"","sources":["../src/log.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,OAAO,IAAyC,MAAM,MAAM,CAAC;AAI7D,qDAAqD;AACrD,MAAM,YAAY,GAAG;IACnB,eAAe;IACf,SAAS;IACT,cAAc;IACd,YAAY;IACZ,gBAAgB;IAChB,mBAAmB;IACnB,kBAAkB;IAClB,iBAAiB;IACjB,gBAAgB;IAChB,cAAc;IACd,WAAW;IACX,4BAA4B;IAC5B,6BAA6B;IAC7B,mCAAmC;IACnC,2BAA2B;IAC3B,6BAA6B;IAC7B,0BAA0B;IAC1B,yBAAyB;IACzB,0BAA0B;IAC1B,gCAAgC;CACjC,CAAC;AAOF,IAAI,OAAO,GAAkB,IAAI,CAAC;AAElC;;;;;GAKG;AACH,MAAM,UAAU,SAAS,CAAC,MAAoB,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE;IAC5E,IAAI,OAAO;QAAE,OAAO,OAAO,CAAC;IAE5B,MAAM,OAAO,GAAkB;QAC7B,KAAK,EAAE,GAAG,CAAC,KAAK;QAChB,MAAM,EAAE,EAAE,KAAK,EAAE,YAAY,EAAE,MAAM,EAAE,YAAY,EAAE;QACrD,IAAI,EAAE,EAAE,OAAO,EAAE,aAAa,EAAE;QAChC,SAAS,EAAE,IAAI,CAAC,gBAAgB,CAAC,OAAO;KACzC,CAAC;IAEF,IAAI,GAAG,CAAC,MAAM,EAAE,CAAC;QACf,OAAO,GAAG,IAAI,CACZ,OAAO,EACP,IAAI,CAAC,SAAS,CAAC;YACb,MAAM,EAAE,aAAa;YACrB,OAAO,EAAE,EAAE,QAAQ,EAAE,IAAI,EAAE,aAAa,EAAE,gBAAgB,EAAE;SAC7D,CAAsC,CACxC,CAAC;IACJ,CAAC;SAAM,CAAC;QACN,OAAO,GAAG,IAAI,CAAC,OAAO,CAAC,CAAC;IAC1B,CAAC;IAED,OAAO,OAAO,CAAC;AACjB,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,WAAW;IACzB,OAAO,GAAG,IAAI,CAAC;AACjB,CAAC"}
@@ -0,0 +1,30 @@
1
+ /**
2
+ * Proxmox API authentication helpers.
3
+ *
4
+ * API token format: PVEAPIToken=<user>@<realm>!<tokenname>=<token-value>
5
+ * See: https://pve.proxmox.com/pve-docs/api-viewer/#/access/users/userid/token
6
+ */
7
+ /**
8
+ * Construct the full token string used in the Authorization header.
9
+ *
10
+ * @example
11
+ * buildPveApiToken("root@pam", "mcp", "abc-def-...")
12
+ * // => "root@pam!mcp=abc-def-..."
13
+ */
14
+ export declare function buildPveApiToken(user: string, tokenName: string, tokenValue: string): string;
15
+ /**
16
+ * Construct the full Authorization header value.
17
+ *
18
+ * @example
19
+ * authHeader("root@pam", "mcp", "abc-def-...")
20
+ * // => "PVEAPIToken=root@pam!mcp=abc-def-..."
21
+ */
22
+ export declare function authHeader(user: string, tokenName: string, tokenValue: string): string;
23
+ /**
24
+ * Extract the user portion from an API token string (sanity check / display).
25
+ *
26
+ * @example
27
+ * parseTokenUser("root@pam!mcp=abc-def") => "root@pam"
28
+ */
29
+ export declare function parseTokenUser(tokenStr: string): string | null;
30
+ //# sourceMappingURL=auth.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"auth.d.ts","sourceRoot":"","sources":["../../src/proxmox/auth.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH;;;;;;GAMG;AACH,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,MAAM,CAE5F;AAED;;;;;;GAMG;AACH,wBAAgB,UAAU,CAAC,IAAI,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,MAAM,CAEtF;AAED;;;;;GAKG;AACH,wBAAgB,cAAc,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAI9D"}
@@ -0,0 +1,39 @@
1
+ /**
2
+ * Proxmox API authentication helpers.
3
+ *
4
+ * API token format: PVEAPIToken=<user>@<realm>!<tokenname>=<token-value>
5
+ * See: https://pve.proxmox.com/pve-docs/api-viewer/#/access/users/userid/token
6
+ */
7
+ /**
8
+ * Construct the full token string used in the Authorization header.
9
+ *
10
+ * @example
11
+ * buildPveApiToken("root@pam", "mcp", "abc-def-...")
12
+ * // => "root@pam!mcp=abc-def-..."
13
+ */
14
+ export function buildPveApiToken(user, tokenName, tokenValue) {
15
+ return `${user}!${tokenName}=${tokenValue}`;
16
+ }
17
+ /**
18
+ * Construct the full Authorization header value.
19
+ *
20
+ * @example
21
+ * authHeader("root@pam", "mcp", "abc-def-...")
22
+ * // => "PVEAPIToken=root@pam!mcp=abc-def-..."
23
+ */
24
+ export function authHeader(user, tokenName, tokenValue) {
25
+ return `PVEAPIToken=${buildPveApiToken(user, tokenName, tokenValue)}`;
26
+ }
27
+ /**
28
+ * Extract the user portion from an API token string (sanity check / display).
29
+ *
30
+ * @example
31
+ * parseTokenUser("root@pam!mcp=abc-def") => "root@pam"
32
+ */
33
+ export function parseTokenUser(tokenStr) {
34
+ const bang = tokenStr.indexOf("!");
35
+ if (bang < 0)
36
+ return null;
37
+ return tokenStr.slice(0, bang);
38
+ }
39
+ //# sourceMappingURL=auth.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"auth.js","sourceRoot":"","sources":["../../src/proxmox/auth.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH;;;;;;GAMG;AACH,MAAM,UAAU,gBAAgB,CAAC,IAAY,EAAE,SAAiB,EAAE,UAAkB;IAClF,OAAO,GAAG,IAAI,IAAI,SAAS,IAAI,UAAU,EAAE,CAAC;AAC9C,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,UAAU,CAAC,IAAY,EAAE,SAAiB,EAAE,UAAkB;IAC5E,OAAO,eAAe,gBAAgB,CAAC,IAAI,EAAE,SAAS,EAAE,UAAU,CAAC,EAAE,CAAC;AACxE,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,cAAc,CAAC,QAAgB;IAC7C,MAAM,IAAI,GAAG,QAAQ,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;IACnC,IAAI,IAAI,GAAG,CAAC;QAAE,OAAO,IAAI,CAAC;IAC1B,OAAO,QAAQ,CAAC,KAAK,CAAC,CAAC,EAAE,IAAI,CAAC,CAAC;AACjC,CAAC"}