@schuttdev/kon 0.3.3 → 0.3.5
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/index.js +110 -100
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -234,27 +234,37 @@ async function ensureDispatcher() {
|
|
|
234
234
|
}
|
|
235
235
|
return _dispatcher;
|
|
236
236
|
}
|
|
237
|
-
function createHttpClient(serverUrl, sessionToken) {
|
|
237
|
+
function createHttpClient(serverUrl, sessionToken, onAuthFailure) {
|
|
238
238
|
const baseUrl = serverUrl.replace(/\/$/, "");
|
|
239
|
+
let currentToken = sessionToken;
|
|
240
|
+
async function rawFetch(url, init) {
|
|
241
|
+
const dispatcher = await ensureDispatcher();
|
|
242
|
+
const fetchOpts = { ...init };
|
|
243
|
+
if (dispatcher) fetchOpts.dispatcher = dispatcher;
|
|
244
|
+
return fetch(url, fetchOpts);
|
|
245
|
+
}
|
|
246
|
+
function authHeaders() {
|
|
247
|
+
const h = {};
|
|
248
|
+
if (currentToken) h["Authorization"] = `Bearer ${currentToken}`;
|
|
249
|
+
return h;
|
|
250
|
+
}
|
|
239
251
|
async function request(path, init = {}) {
|
|
240
252
|
const headers = {
|
|
241
|
-
...init.headers ?? {}
|
|
253
|
+
...init.headers ?? {},
|
|
254
|
+
...authHeaders()
|
|
242
255
|
};
|
|
243
|
-
if (sessionToken) {
|
|
244
|
-
headers["Authorization"] = `Bearer ${sessionToken}`;
|
|
245
|
-
}
|
|
246
256
|
if (!headers["Content-Type"] && init.body && typeof init.body === "string") {
|
|
247
257
|
headers["Content-Type"] = "application/json";
|
|
248
258
|
}
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
259
|
+
let res = await rawFetch(`${baseUrl}${path}`, { ...init, headers });
|
|
260
|
+
if (res.status === 401 && onAuthFailure) {
|
|
261
|
+
const newToken = await onAuthFailure();
|
|
262
|
+
if (newToken) {
|
|
263
|
+
currentToken = newToken;
|
|
264
|
+
headers["Authorization"] = `Bearer ${newToken}`;
|
|
265
|
+
res = await rawFetch(`${baseUrl}${path}`, { ...init, headers });
|
|
266
|
+
}
|
|
256
267
|
}
|
|
257
|
-
const res = await fetch(`${baseUrl}${path}`, fetchOpts);
|
|
258
268
|
if (!res.ok) {
|
|
259
269
|
let errorBody;
|
|
260
270
|
try {
|
|
@@ -277,16 +287,20 @@ function createHttpClient(serverUrl, sessionToken) {
|
|
|
277
287
|
});
|
|
278
288
|
},
|
|
279
289
|
async delete(path) {
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
headers
|
|
283
|
-
}
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
290
|
+
let res = await rawFetch(`${baseUrl}${path}`, {
|
|
291
|
+
method: "DELETE",
|
|
292
|
+
headers: authHeaders()
|
|
293
|
+
});
|
|
294
|
+
if (res.status === 401 && onAuthFailure) {
|
|
295
|
+
const newToken = await onAuthFailure();
|
|
296
|
+
if (newToken) {
|
|
297
|
+
currentToken = newToken;
|
|
298
|
+
res = await rawFetch(`${baseUrl}${path}`, {
|
|
299
|
+
method: "DELETE",
|
|
300
|
+
headers: authHeaders()
|
|
301
|
+
});
|
|
302
|
+
}
|
|
288
303
|
}
|
|
289
|
-
const res = await fetch(`${baseUrl}${path}`, fetchOpts);
|
|
290
304
|
if (!res.ok) {
|
|
291
305
|
let errorBody;
|
|
292
306
|
try {
|
|
@@ -297,20 +311,22 @@ function createHttpClient(serverUrl, sessionToken) {
|
|
|
297
311
|
}
|
|
298
312
|
},
|
|
299
313
|
async postMultipart(path, formData) {
|
|
300
|
-
|
|
301
|
-
if (sessionToken) {
|
|
302
|
-
headers["Authorization"] = `Bearer ${sessionToken}`;
|
|
303
|
-
}
|
|
304
|
-
const dispatcher = await ensureDispatcher();
|
|
305
|
-
const fetchOpts = {
|
|
314
|
+
let res = await rawFetch(`${baseUrl}${path}`, {
|
|
306
315
|
method: "POST",
|
|
307
|
-
headers,
|
|
316
|
+
headers: authHeaders(),
|
|
308
317
|
body: formData
|
|
309
|
-
};
|
|
310
|
-
if (
|
|
311
|
-
|
|
318
|
+
});
|
|
319
|
+
if (res.status === 401 && onAuthFailure) {
|
|
320
|
+
const newToken = await onAuthFailure();
|
|
321
|
+
if (newToken) {
|
|
322
|
+
currentToken = newToken;
|
|
323
|
+
res = await rawFetch(`${baseUrl}${path}`, {
|
|
324
|
+
method: "POST",
|
|
325
|
+
headers: authHeaders(),
|
|
326
|
+
body: formData
|
|
327
|
+
});
|
|
328
|
+
}
|
|
312
329
|
}
|
|
313
|
-
const res = await fetch(`${baseUrl}${path}`, fetchOpts);
|
|
314
330
|
if (!res.ok) {
|
|
315
331
|
let errorBody;
|
|
316
332
|
try {
|
|
@@ -322,16 +338,18 @@ function createHttpClient(serverUrl, sessionToken) {
|
|
|
322
338
|
return res.json();
|
|
323
339
|
},
|
|
324
340
|
async getRaw(path) {
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
341
|
+
let res = await rawFetch(`${baseUrl}${path}`, {
|
|
342
|
+
headers: authHeaders()
|
|
343
|
+
});
|
|
344
|
+
if (res.status === 401 && onAuthFailure) {
|
|
345
|
+
const newToken = await onAuthFailure();
|
|
346
|
+
if (newToken) {
|
|
347
|
+
currentToken = newToken;
|
|
348
|
+
res = await rawFetch(`${baseUrl}${path}`, {
|
|
349
|
+
headers: authHeaders()
|
|
350
|
+
});
|
|
351
|
+
}
|
|
333
352
|
}
|
|
334
|
-
const res = await fetch(`${baseUrl}${path}`, fetchOpts);
|
|
335
353
|
if (!res.ok) {
|
|
336
354
|
throw new Error(`HTTP ${res.status}: ${res.statusText}`);
|
|
337
355
|
}
|
|
@@ -341,7 +359,7 @@ function createHttpClient(serverUrl, sessionToken) {
|
|
|
341
359
|
}
|
|
342
360
|
|
|
343
361
|
// ../cli/src/version.ts
|
|
344
|
-
var VERSION = "0.3.
|
|
362
|
+
var VERSION = "0.3.5";
|
|
345
363
|
|
|
346
364
|
// ../cli/src/connect.ts
|
|
347
365
|
async function connect(serverName) {
|
|
@@ -361,15 +379,26 @@ async function connect(serverName) {
|
|
|
361
379
|
throw new Error("No server configured. Run 'gigai pair' first.");
|
|
362
380
|
}
|
|
363
381
|
const { name, entry } = active;
|
|
382
|
+
const onAuthFailure = async () => {
|
|
383
|
+
try {
|
|
384
|
+
const result2 = await doRefreshSession(name, entry.server, entry.token);
|
|
385
|
+
return result2.sessionToken;
|
|
386
|
+
} catch {
|
|
387
|
+
return void 0;
|
|
388
|
+
}
|
|
389
|
+
};
|
|
364
390
|
if (entry.sessionToken && entry.sessionExpiresAt) {
|
|
365
391
|
if (Date.now() < entry.sessionExpiresAt - 5 * 60 * 1e3) {
|
|
366
|
-
await checkAndUpdateServer(entry.server, entry.sessionToken);
|
|
367
|
-
|
|
392
|
+
const token = await checkAndUpdateServer(entry.server, entry.sessionToken, name, entry.token);
|
|
393
|
+
const http2 = createHttpClient(entry.server, token, onAuthFailure);
|
|
394
|
+
return { serverUrl: entry.server, sessionToken: token, http: http2 };
|
|
368
395
|
}
|
|
369
396
|
}
|
|
370
|
-
|
|
397
|
+
const result = await doRefreshSession(name, entry.server, entry.token);
|
|
398
|
+
const http = createHttpClient(entry.server, result.sessionToken, onAuthFailure);
|
|
399
|
+
return { serverUrl: entry.server, sessionToken: result.sessionToken, http };
|
|
371
400
|
}
|
|
372
|
-
async function
|
|
401
|
+
async function doRefreshSession(serverName, serverUrl, encryptedToken) {
|
|
373
402
|
const orgUuid = getOrgUUID();
|
|
374
403
|
const http = createHttpClient(serverUrl);
|
|
375
404
|
const res = await http.post("/auth/connect", {
|
|
@@ -377,10 +406,10 @@ async function refreshSession(serverName, serverUrl, encryptedToken) {
|
|
|
377
406
|
orgUuid
|
|
378
407
|
});
|
|
379
408
|
await updateServerSession(serverName, res.sessionToken, res.expiresAt);
|
|
380
|
-
await checkAndUpdateServer(serverUrl, res.sessionToken);
|
|
381
|
-
return { serverUrl, sessionToken:
|
|
409
|
+
const token = await checkAndUpdateServer(serverUrl, res.sessionToken, serverName, encryptedToken);
|
|
410
|
+
return { serverUrl, sessionToken: token };
|
|
382
411
|
}
|
|
383
|
-
async function checkAndUpdateServer(serverUrl, sessionToken) {
|
|
412
|
+
async function checkAndUpdateServer(serverUrl, sessionToken, serverName, encryptedToken) {
|
|
384
413
|
try {
|
|
385
414
|
const http = createHttpClient(serverUrl);
|
|
386
415
|
const health = await http.get("/health");
|
|
@@ -403,12 +432,23 @@ async function checkAndUpdateServer(serverUrl, sessionToken) {
|
|
|
403
432
|
console.log("Server updated and restarting.");
|
|
404
433
|
await waitForServer(serverUrl, 15e3);
|
|
405
434
|
console.log("Server is back online.");
|
|
435
|
+
if (serverName && encryptedToken) {
|
|
436
|
+
const orgUuid = getOrgUUID();
|
|
437
|
+
const unauthHttp = createHttpClient(serverUrl);
|
|
438
|
+
const connectRes = await unauthHttp.post("/auth/connect", {
|
|
439
|
+
encryptedToken,
|
|
440
|
+
orgUuid
|
|
441
|
+
});
|
|
442
|
+
await updateServerSession(serverName, connectRes.sessionToken, connectRes.expiresAt);
|
|
443
|
+
return connectRes.sessionToken;
|
|
444
|
+
}
|
|
406
445
|
} else {
|
|
407
446
|
console.log(`Server update failed: ${res.error ?? "unknown error"}`);
|
|
408
447
|
}
|
|
409
448
|
}
|
|
410
449
|
} catch {
|
|
411
450
|
}
|
|
451
|
+
return sessionToken;
|
|
412
452
|
}
|
|
413
453
|
async function waitForServer(serverUrl, timeoutMs) {
|
|
414
454
|
const start = Date.now();
|
|
@@ -1018,43 +1058,21 @@ if (firstArg && !firstArg.startsWith("-") && !KNOWN_COMMANDS.has(firstArg)) {
|
|
|
1018
1058
|
const toolName = firstArg;
|
|
1019
1059
|
const toolArgs = process.argv.slice(3);
|
|
1020
1060
|
try {
|
|
1021
|
-
|
|
1022
|
-
|
|
1023
|
-
|
|
1024
|
-
const
|
|
1025
|
-
if (
|
|
1026
|
-
const
|
|
1027
|
-
|
|
1028
|
-
const toolNames = (detail.mcpTools ?? []).map((t) => ` ${t.name} \u2014 ${t.description}`);
|
|
1029
|
-
console.log(`MCP tools for ${toolName}:
|
|
1061
|
+
const { http } = await connect();
|
|
1062
|
+
const { tool: detail } = await fetchToolDetail(http, toolName);
|
|
1063
|
+
if (detail.type === "mcp") {
|
|
1064
|
+
const mcpToolName = toolArgs[0];
|
|
1065
|
+
if (!mcpToolName) {
|
|
1066
|
+
const toolNames = (detail.mcpTools ?? []).map((t) => ` ${t.name} \u2014 ${t.description}`);
|
|
1067
|
+
console.log(`MCP tools for ${toolName}:
|
|
1030
1068
|
${toolNames.join("\n")}`);
|
|
1031
|
-
} else {
|
|
1032
|
-
const jsonArg = toolArgs.slice(1).join(" ");
|
|
1033
|
-
const args = jsonArg ? JSON.parse(jsonArg) : {};
|
|
1034
|
-
await execMcpTool(http, toolName, mcpToolName, args);
|
|
1035
|
-
}
|
|
1036
|
-
} else {
|
|
1037
|
-
await execTool(http, toolName, toolArgs);
|
|
1038
|
-
}
|
|
1039
|
-
};
|
|
1040
|
-
try {
|
|
1041
|
-
await runTool();
|
|
1042
|
-
} catch (e) {
|
|
1043
|
-
const msg = e.message;
|
|
1044
|
-
if (msg.includes("Invalid session") || msg.includes("Session expired") || msg.includes("Authorization")) {
|
|
1045
|
-
const config = await readConfig();
|
|
1046
|
-
const active = getActiveEntry(config);
|
|
1047
|
-
if (active) {
|
|
1048
|
-
const refreshed = await refreshSession(active.name, active.entry.server, active.entry.token);
|
|
1049
|
-
sessionToken = refreshed.sessionToken;
|
|
1050
|
-
http = createHttpClient(serverUrl, sessionToken);
|
|
1051
|
-
await runTool();
|
|
1052
|
-
} else {
|
|
1053
|
-
throw e;
|
|
1054
|
-
}
|
|
1055
1069
|
} else {
|
|
1056
|
-
|
|
1070
|
+
const jsonArg = toolArgs.slice(1).join(" ");
|
|
1071
|
+
const args = jsonArg ? JSON.parse(jsonArg) : {};
|
|
1072
|
+
await execMcpTool(http, toolName, mcpToolName, args);
|
|
1057
1073
|
}
|
|
1074
|
+
} else {
|
|
1075
|
+
await execTool(http, toolName, toolArgs);
|
|
1058
1076
|
}
|
|
1059
1077
|
} catch (e) {
|
|
1060
1078
|
console.error(`Error: ${e.message}`);
|
|
@@ -1087,8 +1105,7 @@ function runCitty() {
|
|
|
1087
1105
|
const listCommand = defineCommand({
|
|
1088
1106
|
meta: { name: "list", description: "List available tools" },
|
|
1089
1107
|
async run() {
|
|
1090
|
-
const {
|
|
1091
|
-
const http = createHttpClient(serverUrl, sessionToken);
|
|
1108
|
+
const { http } = await connect();
|
|
1092
1109
|
const tools = await fetchTools(http);
|
|
1093
1110
|
console.log(formatToolList(tools));
|
|
1094
1111
|
}
|
|
@@ -1099,8 +1116,7 @@ function runCitty() {
|
|
|
1099
1116
|
tool: { type: "positional", description: "Tool name", required: true }
|
|
1100
1117
|
},
|
|
1101
1118
|
async run({ args }) {
|
|
1102
|
-
const {
|
|
1103
|
-
const http = createHttpClient(serverUrl, sessionToken);
|
|
1119
|
+
const { http } = await connect();
|
|
1104
1120
|
const { tool } = await fetchToolDetail(http, args.tool);
|
|
1105
1121
|
console.log(formatToolDetail(tool));
|
|
1106
1122
|
}
|
|
@@ -1118,8 +1134,7 @@ function runCitty() {
|
|
|
1118
1134
|
file: { type: "positional", description: "File path", required: true }
|
|
1119
1135
|
},
|
|
1120
1136
|
async run({ args }) {
|
|
1121
|
-
const {
|
|
1122
|
-
const http = createHttpClient(serverUrl, sessionToken);
|
|
1137
|
+
const { http } = await connect();
|
|
1123
1138
|
await upload(http, args.file);
|
|
1124
1139
|
}
|
|
1125
1140
|
});
|
|
@@ -1130,8 +1145,7 @@ function runCitty() {
|
|
|
1130
1145
|
dest: { type: "positional", description: "Destination path", required: true }
|
|
1131
1146
|
},
|
|
1132
1147
|
async run({ args }) {
|
|
1133
|
-
const {
|
|
1134
|
-
const http = createHttpClient(serverUrl, sessionToken);
|
|
1148
|
+
const { http } = await connect();
|
|
1135
1149
|
await download(http, args.id, args.dest);
|
|
1136
1150
|
}
|
|
1137
1151
|
});
|
|
@@ -1144,8 +1158,7 @@ function runCitty() {
|
|
|
1144
1158
|
const skillCommand = defineCommand({
|
|
1145
1159
|
meta: { name: "skill", description: "Regenerate the skill zip with current tool details" },
|
|
1146
1160
|
async run() {
|
|
1147
|
-
const {
|
|
1148
|
-
const http = createHttpClient(serverUrl, sessionToken);
|
|
1161
|
+
const { http } = await connect();
|
|
1149
1162
|
const tools = await fetchTools(http);
|
|
1150
1163
|
console.log(`Fetching details for ${tools.length} tool(s)...`);
|
|
1151
1164
|
const toolDetails = await Promise.all(
|
|
@@ -1174,8 +1187,7 @@ Skill zip written to: ${outPath}`);
|
|
|
1174
1187
|
at: { type: "string", description: "Human-readable time (e.g. '9:00 AM tomorrow')" }
|
|
1175
1188
|
},
|
|
1176
1189
|
async run({ args }) {
|
|
1177
|
-
const {
|
|
1178
|
-
const http = createHttpClient(serverUrl, sessionToken);
|
|
1190
|
+
const { http } = await connect();
|
|
1179
1191
|
const rawArgs = process.argv.slice(4);
|
|
1180
1192
|
const positional = [];
|
|
1181
1193
|
let atValue = args.at;
|
|
@@ -1232,8 +1244,7 @@ Skill zip written to: ${outPath}`);
|
|
|
1232
1244
|
const cronListCommand = defineCommand({
|
|
1233
1245
|
meta: { name: "list", description: "List scheduled jobs" },
|
|
1234
1246
|
async run() {
|
|
1235
|
-
const {
|
|
1236
|
-
const http = createHttpClient(serverUrl, sessionToken);
|
|
1247
|
+
const { http } = await connect();
|
|
1237
1248
|
const res = await http.get("/cron");
|
|
1238
1249
|
if (res.jobs.length === 0) {
|
|
1239
1250
|
console.log("No scheduled jobs.");
|
|
@@ -1257,8 +1268,7 @@ Skill zip written to: ${outPath}`);
|
|
|
1257
1268
|
id: { type: "positional", description: "Job ID", required: true }
|
|
1258
1269
|
},
|
|
1259
1270
|
async run({ args }) {
|
|
1260
|
-
const {
|
|
1261
|
-
const http = createHttpClient(serverUrl, sessionToken);
|
|
1271
|
+
const { http } = await connect();
|
|
1262
1272
|
await http.delete(`/cron/${encodeURIComponent(args.id)}`);
|
|
1263
1273
|
console.log(`Removed: ${args.id}`);
|
|
1264
1274
|
}
|