@scrappycoco/cli 0.6.0 → 0.7.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.
- package/dist/index.js +116 -74
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -1138,77 +1138,7 @@ async function emitExecution(response, options, command) {
|
|
|
1138
1138
|
const jsonMode = globals(command).json || false;
|
|
1139
1139
|
if (options.output) {
|
|
1140
1140
|
await emit(response, jsonMode, options.output, formatRecords(records, options.format));
|
|
1141
|
-
const summary =
|
|
1142
|
-
delete summary.records;
|
|
1143
|
-
delete summary.items;
|
|
1144
|
-
delete summary.normalized_schema;
|
|
1145
|
-
summary.truncated_count = records.filter((record) => {
|
|
1146
|
-
const metadata = record.metadata;
|
|
1147
|
-
return metadata && typeof metadata === "object" && !Array.isArray(metadata) && metadata.truncated === true;
|
|
1148
|
-
}).length;
|
|
1149
|
-
if (summary.usage) {
|
|
1150
|
-
summary.usage = selectFields(summary.usage, [
|
|
1151
|
-
"billing_status",
|
|
1152
|
-
"payg_charge_usd_exact",
|
|
1153
|
-
"provider_cost_usd_exact",
|
|
1154
|
-
"unresolved_cost_count"
|
|
1155
|
-
]);
|
|
1156
|
-
}
|
|
1157
|
-
if (Array.isArray(summary.attempts)) {
|
|
1158
|
-
summary.attempts = summary.attempts.map((attempt) => selectFields(attempt, [
|
|
1159
|
-
"provider",
|
|
1160
|
-
"status",
|
|
1161
|
-
"result_count",
|
|
1162
|
-
"latency_ms",
|
|
1163
|
-
"estimated_cost_usd",
|
|
1164
|
-
"error"
|
|
1165
|
-
]));
|
|
1166
|
-
}
|
|
1167
|
-
const providerResults = summary.provider_results;
|
|
1168
|
-
if (providerResults && typeof providerResults === "object" && !Array.isArray(providerResults)) {
|
|
1169
|
-
const counts = Object.fromEntries(
|
|
1170
|
-
Object.entries(providerResults).map(([provider, values]) => [
|
|
1171
|
-
provider,
|
|
1172
|
-
Array.isArray(values) ? values.length : 0
|
|
1173
|
-
])
|
|
1174
|
-
);
|
|
1175
|
-
if (Object.keys(counts).length) summary.provider_result_counts = counts;
|
|
1176
|
-
delete summary.provider_results;
|
|
1177
|
-
}
|
|
1178
|
-
if (Array.isArray(response.items)) {
|
|
1179
|
-
summary.item_count = response.items.length;
|
|
1180
|
-
}
|
|
1181
|
-
if (Array.isArray(summary.routes)) {
|
|
1182
|
-
summary.routes = summary.routes.map((value) => {
|
|
1183
|
-
if (!value || typeof value !== "object" || Array.isArray(value)) return value;
|
|
1184
|
-
const route = { ...value };
|
|
1185
|
-
const routeResults = route.provider_results;
|
|
1186
|
-
if (routeResults && typeof routeResults === "object" && !Array.isArray(routeResults)) {
|
|
1187
|
-
const counts = Object.fromEntries(
|
|
1188
|
-
Object.entries(routeResults).map(([provider, values]) => [
|
|
1189
|
-
provider,
|
|
1190
|
-
Array.isArray(values) ? values.length : 0
|
|
1191
|
-
])
|
|
1192
|
-
);
|
|
1193
|
-
if (Object.keys(counts).length) route.provider_result_counts = counts;
|
|
1194
|
-
delete route.provider_results;
|
|
1195
|
-
}
|
|
1196
|
-
if (Array.isArray(route.attempts)) {
|
|
1197
|
-
route.attempts = route.attempts.map((attempt) => selectFields(attempt, [
|
|
1198
|
-
"provider",
|
|
1199
|
-
"status",
|
|
1200
|
-
"result_count",
|
|
1201
|
-
"latency_ms",
|
|
1202
|
-
"estimated_cost_usd",
|
|
1203
|
-
"error"
|
|
1204
|
-
]));
|
|
1205
|
-
}
|
|
1206
|
-
return route;
|
|
1207
|
-
});
|
|
1208
|
-
}
|
|
1209
|
-
for (const field of ["cursor", "monitor"]) {
|
|
1210
|
-
if (summary[field] === null) delete summary[field];
|
|
1211
|
-
}
|
|
1141
|
+
const summary = executionSummary(response);
|
|
1212
1142
|
summary.output = {
|
|
1213
1143
|
path: options.output,
|
|
1214
1144
|
format: options.format,
|
|
@@ -1221,6 +1151,96 @@ async function emitExecution(response, options, command) {
|
|
|
1221
1151
|
}
|
|
1222
1152
|
await emit(response, jsonMode);
|
|
1223
1153
|
}
|
|
1154
|
+
function executionSummary(response) {
|
|
1155
|
+
const records = "records" in response && Array.isArray(response.records) ? response.records : response.items;
|
|
1156
|
+
const summary = { ...response };
|
|
1157
|
+
delete summary.records;
|
|
1158
|
+
delete summary.items;
|
|
1159
|
+
delete summary.normalized_schema;
|
|
1160
|
+
summary.truncated_count = records.filter((record) => {
|
|
1161
|
+
const metadata = record.metadata;
|
|
1162
|
+
return metadata && typeof metadata === "object" && !Array.isArray(metadata) && metadata.truncated === true;
|
|
1163
|
+
}).length;
|
|
1164
|
+
if (summary.usage) {
|
|
1165
|
+
summary.usage = selectFields(summary.usage, [
|
|
1166
|
+
"billing_status",
|
|
1167
|
+
"payg_charge_usd_exact",
|
|
1168
|
+
"provider_cost_usd_exact",
|
|
1169
|
+
"unresolved_cost_count"
|
|
1170
|
+
]);
|
|
1171
|
+
}
|
|
1172
|
+
if (Array.isArray(summary.attempts)) {
|
|
1173
|
+
summary.attempts = summary.attempts.map((attempt) => selectFields(attempt, [
|
|
1174
|
+
"provider",
|
|
1175
|
+
"status",
|
|
1176
|
+
"result_count",
|
|
1177
|
+
"latency_ms",
|
|
1178
|
+
"estimated_cost_usd",
|
|
1179
|
+
"error"
|
|
1180
|
+
]));
|
|
1181
|
+
}
|
|
1182
|
+
const providerResults = summary.provider_results;
|
|
1183
|
+
if (providerResults && typeof providerResults === "object" && !Array.isArray(providerResults)) {
|
|
1184
|
+
const counts = Object.fromEntries(
|
|
1185
|
+
Object.entries(providerResults).map(([provider, values]) => [
|
|
1186
|
+
provider,
|
|
1187
|
+
Array.isArray(values) ? values.length : 0
|
|
1188
|
+
])
|
|
1189
|
+
);
|
|
1190
|
+
if (Object.keys(counts).length) summary.provider_result_counts = counts;
|
|
1191
|
+
delete summary.provider_results;
|
|
1192
|
+
}
|
|
1193
|
+
if (Array.isArray(response.items)) summary.item_count = response.items.length;
|
|
1194
|
+
if (Array.isArray(summary.routes)) {
|
|
1195
|
+
summary.routes = summary.routes.map((value) => {
|
|
1196
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) return value;
|
|
1197
|
+
const route = { ...value };
|
|
1198
|
+
const routeResults = route.provider_results;
|
|
1199
|
+
if (routeResults && typeof routeResults === "object" && !Array.isArray(routeResults)) {
|
|
1200
|
+
const counts = Object.fromEntries(
|
|
1201
|
+
Object.entries(routeResults).map(([provider, values]) => [
|
|
1202
|
+
provider,
|
|
1203
|
+
Array.isArray(values) ? values.length : 0
|
|
1204
|
+
])
|
|
1205
|
+
);
|
|
1206
|
+
if (Object.keys(counts).length) route.provider_result_counts = counts;
|
|
1207
|
+
delete route.provider_results;
|
|
1208
|
+
}
|
|
1209
|
+
if (Array.isArray(route.attempts)) {
|
|
1210
|
+
route.attempts = route.attempts.map((attempt) => selectFields(attempt, [
|
|
1211
|
+
"provider",
|
|
1212
|
+
"status",
|
|
1213
|
+
"result_count",
|
|
1214
|
+
"latency_ms",
|
|
1215
|
+
"estimated_cost_usd",
|
|
1216
|
+
"error"
|
|
1217
|
+
]));
|
|
1218
|
+
}
|
|
1219
|
+
return route;
|
|
1220
|
+
});
|
|
1221
|
+
}
|
|
1222
|
+
for (const field of ["cursor", "monitor"]) {
|
|
1223
|
+
if (summary[field] === null) delete summary[field];
|
|
1224
|
+
}
|
|
1225
|
+
return summary;
|
|
1226
|
+
}
|
|
1227
|
+
function compactCatalog(items) {
|
|
1228
|
+
return items.map((item) => ({
|
|
1229
|
+
id: item.id,
|
|
1230
|
+
source: item.source,
|
|
1231
|
+
capability: item.capability,
|
|
1232
|
+
label: item.label,
|
|
1233
|
+
description: item.description,
|
|
1234
|
+
execution_mode: item.execution_mode,
|
|
1235
|
+
providers: Array.isArray(item.providers) ? item.providers.map((provider) => selectFields(provider, [
|
|
1236
|
+
"id",
|
|
1237
|
+
"label",
|
|
1238
|
+
"available",
|
|
1239
|
+
"reason",
|
|
1240
|
+
"pricing"
|
|
1241
|
+
])) : []
|
|
1242
|
+
}));
|
|
1243
|
+
}
|
|
1224
1244
|
async function executeQueuedJob(path, payload, options, command) {
|
|
1225
1245
|
if (options.detach && options.output) {
|
|
1226
1246
|
throw new CliError(
|
|
@@ -1389,13 +1409,13 @@ scrapers.command("inspect <scraper-id>").action(async (scraperId, _options, comm
|
|
|
1389
1409
|
);
|
|
1390
1410
|
});
|
|
1391
1411
|
var catalog = program.command("catalog").description("Inspect capabilities, provider schemas, options, and pricing");
|
|
1392
|
-
catalog.command("list").option("--source <source>", "filter by web, x, reddit, or filings").option("--provider <provider>", "filter by provider implementation").option("--available", "only include
|
|
1412
|
+
catalog.command("list").option("--source <source>", "filter by web, x, reddit, or filings").option("--provider <provider>", "filter by provider implementation").option("--available", "only include configured providers; this is not a live health check").option("--full", "include input/output and provider option schemas in JSON output").action(async (options, command) => {
|
|
1393
1413
|
const query = new URLSearchParams();
|
|
1394
1414
|
if (options.source) query.set("source", options.source);
|
|
1395
1415
|
if (options.provider) query.set("provider", options.provider);
|
|
1396
1416
|
if (options.available) query.set("available_only", "true");
|
|
1397
1417
|
const items = await client(command).get(`/scrapers${query.size ? `?${query}` : ""}`);
|
|
1398
|
-
if (globals(command).json) await emit(items, true);
|
|
1418
|
+
if (globals(command).json) await emit(options.full ? items : compactCatalog(items), true);
|
|
1399
1419
|
else process.stdout.write(formatCatalog(items));
|
|
1400
1420
|
});
|
|
1401
1421
|
catalog.command("inspect <capability-id>").action(async (capabilityId, _options, command) => {
|
|
@@ -1539,7 +1559,7 @@ discoveries.command("delete <discovery-id>").requiredOption("--yes", "confirm pe
|
|
|
1539
1559
|
await client(command).delete(`/discoveries/${encodeURIComponent(discoveryId)}`);
|
|
1540
1560
|
await emit({ deleted: true, discovery_id: discoveryId }, globals(command).json || false);
|
|
1541
1561
|
});
|
|
1542
|
-
program.command("discover").description("Save, sample-test, or finalize an agent-authored configuration").option("-f, --file <path>", "create from agent-authored discovery JSON").option("--id <discovery-id>", "existing discovery ID").option("--test", "run a representative provider sample test").option("--input <json>", "sample runtime input JSON").option("--update <path>", "replace fields or configuration from agent-authored JSON").option("--finalize", "mark the current explicit configuration finalized").option("--idempotency-key <key>", "stable sample retry key").action(async (options, command) => {
|
|
1562
|
+
program.command("discover").description("Save, sample-test, or finalize an agent-authored configuration").option("-f, --file <path>", "create from agent-authored discovery JSON").option("--id <discovery-id>", "existing discovery ID").option("--test", "run a representative provider sample test").option("--input <json>", "sample runtime input JSON").option("--update <path>", "replace fields or configuration from agent-authored JSON").option("--finalize", "mark the current explicit configuration finalized").option("--idempotency-key <key>", "stable sample retry key").option("-o, --output <path>", "write complete sample-test evidence to a JSON file").action(async (options, command) => {
|
|
1543
1563
|
const selected = Number(Boolean(options.file)) + Number(Boolean(options.test)) + Number(Boolean(options.update)) + Number(Boolean(options.finalize));
|
|
1544
1564
|
if (selected !== 1) {
|
|
1545
1565
|
throw new CliError(
|
|
@@ -1547,6 +1567,9 @@ program.command("discover").description("Save, sample-test, or finalize an agent
|
|
|
1547
1567
|
EXIT.usage
|
|
1548
1568
|
);
|
|
1549
1569
|
}
|
|
1570
|
+
if (options.output && !options.test) {
|
|
1571
|
+
throw new CliError("--output is supported only with --test.", EXIT.usage);
|
|
1572
|
+
}
|
|
1550
1573
|
if (options.file) {
|
|
1551
1574
|
await emit(
|
|
1552
1575
|
await client(command).post("/discoveries", await readJsonFile(options.file)),
|
|
@@ -1581,6 +1604,25 @@ program.command("discover").description("Save, sample-test, or finalize an agent
|
|
|
1581
1604
|
{ input, limit: 25 },
|
|
1582
1605
|
options.idempotencyKey || randomUUID4()
|
|
1583
1606
|
);
|
|
1607
|
+
if (options.output) {
|
|
1608
|
+
await emit(
|
|
1609
|
+
response,
|
|
1610
|
+
true,
|
|
1611
|
+
options.output,
|
|
1612
|
+
`${JSON.stringify(response, null, 2)}
|
|
1613
|
+
`
|
|
1614
|
+
);
|
|
1615
|
+
const summary = executionSummary(response);
|
|
1616
|
+
summary.output = {
|
|
1617
|
+
path: options.output,
|
|
1618
|
+
format: "json",
|
|
1619
|
+
kind: "discovery_evidence"
|
|
1620
|
+
};
|
|
1621
|
+
await emit(summary, globals(command).json || false);
|
|
1622
|
+
process.stderr.write(`Saved complete Discovery evidence to ${options.output}
|
|
1623
|
+
`);
|
|
1624
|
+
return;
|
|
1625
|
+
}
|
|
1584
1626
|
await emit(response, globals(command).json || false);
|
|
1585
1627
|
});
|
|
1586
1628
|
program.configureOutput({ writeErr: (text) => process.stderr.write(text) });
|