mcp-for-i 0.1.10 → 0.1.11
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/mcp/tools.js +53 -20
- package/package.json +1 -1
package/dist/mcp/tools.js
CHANGED
|
@@ -1277,7 +1277,26 @@ export async function handleTool(ctx, name, args) {
|
|
|
1277
1277
|
}
|
|
1278
1278
|
case "ibmi.qsys.sourcefiles.list": {
|
|
1279
1279
|
const conn = await ctx.ensureActive(args?.connectionName);
|
|
1280
|
-
|
|
1280
|
+
let files;
|
|
1281
|
+
try {
|
|
1282
|
+
files = await conn.content.getObjectList(args.library, ["*FILE"]);
|
|
1283
|
+
}
|
|
1284
|
+
catch {
|
|
1285
|
+
try {
|
|
1286
|
+
const allObjects = await conn.content.getObjectList(args.library, ["*ALL"]);
|
|
1287
|
+
files = allObjects.filter((obj) => String(obj?.type || "").toUpperCase() === "*FILE");
|
|
1288
|
+
}
|
|
1289
|
+
catch {
|
|
1290
|
+
const rows = await conn.runSQL(`select system_table_name as name, coalesce(table_text, '') as text from qsys2.systables where upper(system_table_schema)=${Tools.sqlString(String(args.library || "").toUpperCase())} fetch first 5000 rows only`);
|
|
1291
|
+
files = rows.map((row) => ({
|
|
1292
|
+
library: String(args.library || "").toUpperCase(),
|
|
1293
|
+
name: String(row?.NAME || row?.SYSTEM_TABLE_NAME || ""),
|
|
1294
|
+
type: "*FILE",
|
|
1295
|
+
text: String(row?.TEXT || row?.TABLE_TEXT || ""),
|
|
1296
|
+
attribute: ""
|
|
1297
|
+
}));
|
|
1298
|
+
}
|
|
1299
|
+
}
|
|
1281
1300
|
const sourceByAttr = files.filter((obj) => {
|
|
1282
1301
|
const attr = String(obj?.attribute || "").toUpperCase();
|
|
1283
1302
|
return attr === "PF-SRC" || attr === "SOURCE";
|
|
@@ -2632,28 +2651,33 @@ async function queryJournalEntries(conn, options) {
|
|
|
2632
2651
|
}
|
|
2633
2652
|
async function queryJobs(conn, options) {
|
|
2634
2653
|
const scanLimit = Math.min(options.limit * 5, 5000);
|
|
2635
|
-
|
|
2654
|
+
const rows = [];
|
|
2655
|
+
const activeWhere = buildJobWhereClause(options, {
|
|
2656
|
+
subsystem: "SUBSYSTEM",
|
|
2657
|
+
userName: "AUTHORIZATION_NAME",
|
|
2658
|
+
status: "JOB_STATUS"
|
|
2659
|
+
});
|
|
2636
2660
|
try {
|
|
2637
|
-
activeRows = await conn.runSQL(`select * from table(qsys2.active_job_info()) fetch first ${scanLimit} rows only`);
|
|
2661
|
+
const activeRows = await conn.runSQL(`select * from table(qsys2.active_job_info())${activeWhere} fetch first ${scanLimit} rows only`);
|
|
2662
|
+
rows.push(...activeRows.map((row) => normalizeActiveJobRow(row)));
|
|
2638
2663
|
}
|
|
2639
2664
|
catch {
|
|
2640
2665
|
// Continue with job_info fallback.
|
|
2641
2666
|
}
|
|
2642
|
-
|
|
2643
|
-
|
|
2644
|
-
|
|
2667
|
+
const allWhere = buildJobWhereClause(options, {
|
|
2668
|
+
subsystem: "JOB_SUBSYSTEM",
|
|
2669
|
+
userName: "JOB_USER",
|
|
2670
|
+
status: "JOB_STATUS"
|
|
2671
|
+
});
|
|
2645
2672
|
try {
|
|
2646
|
-
const allRows = await conn.runSQL(`select * from table(qsys2.job_info('*ALL')) fetch first ${scanLimit} rows only`);
|
|
2647
|
-
const fallback = filterNormalizedJobs(allRows.map((row) => normalizeActiveJobRow(row)), options);
|
|
2673
|
+
const allRows = await conn.runSQL(`select * from table(qsys2.job_info('*ALL'))${allWhere} fetch first ${scanLimit} rows only`);
|
|
2648
2674
|
const seen = new Set(rows.map((row) => String(row.jobName || "")));
|
|
2649
|
-
for (const row of
|
|
2675
|
+
for (const row of allRows.map((raw) => normalizeActiveJobRow(raw))) {
|
|
2650
2676
|
const key = String(row.jobName || "");
|
|
2651
2677
|
if (!key || seen.has(key))
|
|
2652
2678
|
continue;
|
|
2653
2679
|
rows.push(row);
|
|
2654
2680
|
seen.add(key);
|
|
2655
|
-
if (rows.length >= options.limit)
|
|
2656
|
-
break;
|
|
2657
2681
|
}
|
|
2658
2682
|
}
|
|
2659
2683
|
catch {
|
|
@@ -2661,21 +2685,24 @@ async function queryJobs(conn, options) {
|
|
|
2661
2685
|
}
|
|
2662
2686
|
return rows.slice(0, options.limit);
|
|
2663
2687
|
}
|
|
2664
|
-
function
|
|
2665
|
-
|
|
2688
|
+
function buildJobWhereClause(options, columns) {
|
|
2689
|
+
const predicates = [];
|
|
2666
2690
|
if (options.subsystem) {
|
|
2667
2691
|
const subsystem = String(options.subsystem).trim().toUpperCase();
|
|
2668
|
-
|
|
2692
|
+
if (subsystem)
|
|
2693
|
+
predicates.push(`upper(${columns.subsystem})=${Tools.sqlString(subsystem)}`);
|
|
2669
2694
|
}
|
|
2670
2695
|
if (options.userName) {
|
|
2671
2696
|
const userName = String(options.userName).trim().toUpperCase();
|
|
2672
|
-
|
|
2697
|
+
if (userName)
|
|
2698
|
+
predicates.push(`upper(${columns.userName})=${Tools.sqlString(userName)}`);
|
|
2673
2699
|
}
|
|
2674
2700
|
if (options.status) {
|
|
2675
|
-
const status = String(options.status).trim().toUpperCase();
|
|
2676
|
-
|
|
2701
|
+
const status = String(options.status).trim().toUpperCase().replace(/'/g, "''");
|
|
2702
|
+
if (status)
|
|
2703
|
+
predicates.push(`upper(${columns.status}) like '%${status}%'`);
|
|
2677
2704
|
}
|
|
2678
|
-
return
|
|
2705
|
+
return predicates.length > 0 ? ` where ${predicates.join(" and ")}` : "";
|
|
2679
2706
|
}
|
|
2680
2707
|
async function querySubsystemSummary(conn, limit) {
|
|
2681
2708
|
const jobs = await queryJobs(conn, { limit: 5000 });
|
|
@@ -2713,11 +2740,14 @@ async function queryMessageQueueEntries(conn, options) {
|
|
|
2713
2740
|
}
|
|
2714
2741
|
async function querySpoolEntries(conn, limit) {
|
|
2715
2742
|
const queries = [
|
|
2743
|
+
`select * from qsys2.output_queue_entries fetch first ${limit} rows only`,
|
|
2744
|
+
`select * from table(qsys2.output_queue_entries()) fetch first ${limit} rows only`,
|
|
2716
2745
|
`select job_name, spooled_file_name, spooled_file_number, output_queue_name, total_pages, file_status from qsys2.output_queue_entries fetch first ${limit} rows only`,
|
|
2717
2746
|
`select job_name, spooled_file_name, spooled_file_number, output_queue_name, total_pages, cast('' as varchar(10)) as file_status from qsys2.output_queue_entries fetch first ${limit} rows only`,
|
|
2718
2747
|
`select job_name, spooled_file_name, cast(0 as integer) as spooled_file_number, output_queue_name, total_pages, file_status from qsys2.output_queue_entries fetch first ${limit} rows only`,
|
|
2719
2748
|
`select job_name, spooled_file_name, cast(0 as integer) as spooled_file_number, output_queue_name, total_pages, cast('' as varchar(10)) as file_status from qsys2.output_queue_entries fetch first ${limit} rows only`,
|
|
2720
|
-
`select * from qsys2.
|
|
2749
|
+
`select * from qsys2.spooled_file_info fetch first ${limit} rows only`,
|
|
2750
|
+
`select * from table(qsys2.spooled_file_info()) fetch first ${limit} rows only`
|
|
2721
2751
|
];
|
|
2722
2752
|
let lastError;
|
|
2723
2753
|
for (const sql of queries) {
|
|
@@ -2848,7 +2878,10 @@ function normalizeDataAreaInfoRow(row) {
|
|
|
2848
2878
|
function buildSpoolCommand(commandName, args) {
|
|
2849
2879
|
const jobName = requireJobName(args.jobName);
|
|
2850
2880
|
const spooledFileName = requireIbmObjectName(args.spooledFileName, "spooledFileName");
|
|
2851
|
-
const
|
|
2881
|
+
const rawNumber = Number(args.spooledFileNumber);
|
|
2882
|
+
const spooledFileNumber = Number.isFinite(rawNumber) && rawNumber > 0
|
|
2883
|
+
? String(Math.floor(rawNumber))
|
|
2884
|
+
: "*LAST";
|
|
2852
2885
|
return `${commandName} FILE(${spooledFileName}) JOB(${jobName}) SPLNBR(${spooledFileNumber})`;
|
|
2853
2886
|
}
|
|
2854
2887
|
async function queryJournalEntriesViaDisplayJournal(conn, options) {
|