@senso-ai/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/cli.js +69 -53
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -164,7 +164,7 @@ import pc3 from "picocolors";
|
|
|
164
164
|
// src/lib/api-client.ts
|
|
165
165
|
var ApiError = class extends Error {
|
|
166
166
|
constructor(status, statusText, body) {
|
|
167
|
-
const msg = typeof body === "object" && body
|
|
167
|
+
const msg = typeof body === "object" && body ? "error" in body ? body.error : "message" in body ? body.message : statusText : statusText;
|
|
168
168
|
super(msg);
|
|
169
169
|
this.status = status;
|
|
170
170
|
this.statusText = statusText;
|
|
@@ -230,8 +230,10 @@ function formatApiError(err) {
|
|
|
230
230
|
switch (err.status) {
|
|
231
231
|
case 401:
|
|
232
232
|
return "Authentication failed. Run `senso login` to update your API key.";
|
|
233
|
+
case 402:
|
|
234
|
+
return "Insufficient credits or spending limit reached. Check your plan at https://app.senso.ai.";
|
|
233
235
|
case 403:
|
|
234
|
-
return
|
|
236
|
+
return `Permission denied: ${err.message}`;
|
|
235
237
|
case 404:
|
|
236
238
|
return "Resource not found.";
|
|
237
239
|
case 409:
|
|
@@ -666,12 +668,17 @@ function output(format, data) {
|
|
|
666
668
|
}
|
|
667
669
|
|
|
668
670
|
// src/commands/search.ts
|
|
671
|
+
function parseMaxResults(value) {
|
|
672
|
+
const n = parseInt(value);
|
|
673
|
+
if (isNaN(n) || n < 1) return 5;
|
|
674
|
+
return Math.min(n, 20);
|
|
675
|
+
}
|
|
669
676
|
function registerSearchCommands(program2) {
|
|
670
677
|
const search = program2.command("search").description("Search the knowledge base with natural language queries. Returns AI-generated answers synthesised from matching content chunks, or raw chunks/content IDs.");
|
|
671
|
-
search.argument("<query>", "Search query").option("--max-results <n>", "Maximum number of results", "5").option("--content-ids <ids...>", "Restrict search to specific content item IDs (space-separated UUIDs)").option("--require-scoped-ids", "Only return results from the specified --content-ids (omit to allow fallback to all content)").action(async (query, cmdOpts) => {
|
|
678
|
+
search.argument("<query>", "Search query").option("--max-results <n>", "Maximum number of results (max: 20)", "5").option("--content-ids <ids...>", "Restrict search to specific content item IDs (space-separated UUIDs)").option("--require-scoped-ids", "Only return results from the specified --content-ids (omit to allow fallback to all content)").action(async (query, cmdOpts) => {
|
|
672
679
|
const opts = program2.opts();
|
|
673
680
|
try {
|
|
674
|
-
const body = { query, max_results:
|
|
681
|
+
const body = { query, max_results: parseMaxResults(cmdOpts.maxResults) };
|
|
675
682
|
if (cmdOpts.contentIds) body.content_ids = cmdOpts.contentIds;
|
|
676
683
|
if (cmdOpts.requireScopedIds) body.require_scoped_ids = true;
|
|
677
684
|
const data = await apiRequest({
|
|
@@ -710,10 +717,10 @@ function registerSearchCommands(program2) {
|
|
|
710
717
|
process.exit(1);
|
|
711
718
|
}
|
|
712
719
|
});
|
|
713
|
-
search.command("context <query>").description("Search the knowledge base \u2014 returns matching content chunks only, without AI answer generation. Use this to feed verified chunks into your own LLM pipeline instead of using Senso's generated answer.").option("--max-results <n>", "Maximum results", "5").option("--content-ids <ids...>", "Restrict search to specific content item IDs (space-separated UUIDs)").option("--require-scoped-ids", "Only return results from the specified --content-ids").action(async (query, cmdOpts) => {
|
|
720
|
+
search.command("context <query>").description("Search the knowledge base \u2014 returns matching content chunks only, without AI answer generation. Use this to feed verified chunks into your own LLM pipeline instead of using Senso's generated answer.").option("--max-results <n>", "Maximum results (max: 20)", "5").option("--content-ids <ids...>", "Restrict search to specific content item IDs (space-separated UUIDs)").option("--require-scoped-ids", "Only return results from the specified --content-ids").action(async (query, cmdOpts) => {
|
|
714
721
|
const opts = program2.opts();
|
|
715
722
|
try {
|
|
716
|
-
const body = { query, max_results:
|
|
723
|
+
const body = { query, max_results: parseMaxResults(cmdOpts.maxResults) };
|
|
717
724
|
if (cmdOpts.contentIds) body.content_ids = cmdOpts.contentIds;
|
|
718
725
|
if (cmdOpts.requireScopedIds) body.require_scoped_ids = true;
|
|
719
726
|
const data = await apiRequest({
|
|
@@ -729,10 +736,10 @@ function registerSearchCommands(program2) {
|
|
|
729
736
|
process.exit(1);
|
|
730
737
|
}
|
|
731
738
|
});
|
|
732
|
-
search.command("content <query>").description("Search the knowledge base \u2014 returns deduplicated content IDs and titles only. Use this to discover which documents are relevant before fetching full content with 'content get <id>'.").option("--max-results <n>", "Maximum results", "5").option("--content-ids <ids...>", "Restrict search to specific content item IDs (space-separated UUIDs)").option("--require-scoped-ids", "Only return results from the specified --content-ids").action(async (query, cmdOpts) => {
|
|
739
|
+
search.command("content <query>").description("Search the knowledge base \u2014 returns deduplicated content IDs and titles only. Use this to discover which documents are relevant before fetching full content with 'content get <id>'.").option("--max-results <n>", "Maximum results (max: 20)", "5").option("--content-ids <ids...>", "Restrict search to specific content item IDs (space-separated UUIDs)").option("--require-scoped-ids", "Only return results from the specified --content-ids").action(async (query, cmdOpts) => {
|
|
733
740
|
const opts = program2.opts();
|
|
734
741
|
try {
|
|
735
|
-
const body = { query, max_results:
|
|
742
|
+
const body = { query, max_results: parseMaxResults(cmdOpts.maxResults) };
|
|
736
743
|
if (cmdOpts.contentIds) body.content_ids = cmdOpts.contentIds;
|
|
737
744
|
if (cmdOpts.requireScopedIds) body.require_scoped_ids = true;
|
|
738
745
|
const data = await apiRequest({
|
|
@@ -748,10 +755,10 @@ function registerSearchCommands(program2) {
|
|
|
748
755
|
process.exit(1);
|
|
749
756
|
}
|
|
750
757
|
});
|
|
751
|
-
search.command("full <query>").description("Alias for the default search \u2014 returns AI answer plus matching chunks. Equivalent to 'senso search <query>'.").option("--max-results <n>", "Maximum results", "5").option("--content-ids <ids...>", "Restrict search to specific content item IDs (space-separated UUIDs)").option("--require-scoped-ids", "Only return results from the specified --content-ids").action(async (query, cmdOpts) => {
|
|
758
|
+
search.command("full <query>").description("Alias for the default search \u2014 returns AI answer plus matching chunks. Equivalent to 'senso search <query>'.").option("--max-results <n>", "Maximum results (max: 20)", "5").option("--content-ids <ids...>", "Restrict search to specific content item IDs (space-separated UUIDs)").option("--require-scoped-ids", "Only return results from the specified --content-ids").action(async (query, cmdOpts) => {
|
|
752
759
|
const opts = program2.opts();
|
|
753
760
|
try {
|
|
754
|
-
const body = { query, max_results:
|
|
761
|
+
const body = { query, max_results: parseMaxResults(cmdOpts.maxResults) };
|
|
755
762
|
if (cmdOpts.contentIds) body.content_ids = cmdOpts.contentIds;
|
|
756
763
|
if (cmdOpts.requireScopedIds) body.require_scoped_ids = true;
|
|
757
764
|
const data = await apiRequest({
|
|
@@ -835,60 +842,63 @@ function registerIngestCommands(program2) {
|
|
|
835
842
|
}
|
|
836
843
|
try {
|
|
837
844
|
const fileData = await Promise.all(files.map(getFileMetadata));
|
|
838
|
-
const
|
|
845
|
+
const response = await apiRequest({
|
|
839
846
|
method: "POST",
|
|
840
847
|
path: "/org/kb/upload",
|
|
841
848
|
body: { files: fileData.map((f) => f.meta) },
|
|
842
849
|
apiKey: opts.apiKey,
|
|
843
850
|
baseUrl: opts.baseUrl
|
|
844
851
|
});
|
|
845
|
-
const items =
|
|
852
|
+
const items = response.results ?? [];
|
|
846
853
|
let uploaded = 0;
|
|
847
854
|
for (const item of items) {
|
|
848
855
|
if (item.status === "upload_pending" && item.upload_url) {
|
|
849
856
|
const match = fileData.find((f) => f.meta.filename === item.filename);
|
|
850
|
-
if (match) {
|
|
857
|
+
if (!match) {
|
|
858
|
+
error(`Could not match server filename "${item.filename}" to a local file \u2014 skipping upload.`);
|
|
859
|
+
continue;
|
|
860
|
+
}
|
|
861
|
+
try {
|
|
851
862
|
await uploadToS3(item.upload_url, match.buffer, match.meta.content_type);
|
|
852
863
|
uploaded++;
|
|
853
864
|
success(`Uploaded ${item.filename} (content_id: ${item.content_id})`);
|
|
865
|
+
} catch (uploadErr) {
|
|
866
|
+
error(`S3 upload failed for ${item.filename}: ${uploadErr instanceof Error ? uploadErr.message : String(uploadErr)}`);
|
|
854
867
|
}
|
|
855
868
|
} else {
|
|
856
|
-
warn(`Skipped ${item.filename}: ${item.status}${item.
|
|
869
|
+
warn(`Skipped ${item.filename}: ${item.status}${item.error ? ` \u2014 ${item.error}` : ""}`);
|
|
857
870
|
}
|
|
858
871
|
}
|
|
859
872
|
if (uploaded > 0) {
|
|
860
873
|
success(`${uploaded} file(s) uploaded. Background processing will parse, chunk, and embed them.`);
|
|
861
874
|
}
|
|
862
875
|
if (opts.output === "json") {
|
|
863
|
-
console.log(JSON.stringify(
|
|
876
|
+
console.log(JSON.stringify(response, null, 2));
|
|
864
877
|
}
|
|
865
878
|
} catch (err) {
|
|
866
879
|
error(formatApiError(err));
|
|
867
880
|
process.exit(1);
|
|
868
881
|
}
|
|
869
882
|
});
|
|
870
|
-
ingest.command("reprocess <
|
|
883
|
+
ingest.command("reprocess <nodeId> <file>").description("Re-ingest an existing document with a new file version. Provide the KB node ID (kb_node_id) and the path to the replacement file.").action(async (nodeId, file) => {
|
|
871
884
|
const opts = program2.opts();
|
|
872
885
|
try {
|
|
873
886
|
const { meta, buffer } = await getFileMetadata(file);
|
|
874
|
-
const
|
|
887
|
+
const item = await apiRequest({
|
|
875
888
|
method: "PUT",
|
|
876
|
-
path: `/org/kb/nodes/${
|
|
889
|
+
path: `/org/kb/nodes/${nodeId}/file`,
|
|
877
890
|
body: { file: meta },
|
|
878
891
|
apiKey: opts.apiKey,
|
|
879
892
|
baseUrl: opts.baseUrl
|
|
880
893
|
});
|
|
881
|
-
|
|
882
|
-
|
|
883
|
-
|
|
884
|
-
|
|
885
|
-
|
|
886
|
-
} else {
|
|
887
|
-
warn(`Skipped: ${item.status}${item.message ? ` \u2014 ${item.message}` : ""}`);
|
|
888
|
-
}
|
|
894
|
+
if (item.status === "upload_pending" && item.upload_url) {
|
|
895
|
+
await uploadToS3(item.upload_url, buffer, meta.content_type);
|
|
896
|
+
success(`Uploaded ${meta.filename} for node ${nodeId}. Background re-processing started.`);
|
|
897
|
+
} else {
|
|
898
|
+
warn(`Skipped: ${item.status}${item.error ? ` \u2014 ${item.error}` : ""}`);
|
|
889
899
|
}
|
|
890
900
|
if (opts.output === "json") {
|
|
891
|
-
console.log(JSON.stringify(
|
|
901
|
+
console.log(JSON.stringify(item, null, 2));
|
|
892
902
|
}
|
|
893
903
|
} catch (err) {
|
|
894
904
|
error(formatApiError(err));
|
|
@@ -916,7 +926,7 @@ function registerContentCommands(program2) {
|
|
|
916
926
|
json: data,
|
|
917
927
|
table: {
|
|
918
928
|
rows: rows.map((r) => ({
|
|
919
|
-
id: r.
|
|
929
|
+
id: r.kb_node_id,
|
|
920
930
|
name: r.name,
|
|
921
931
|
type: r.type,
|
|
922
932
|
status: r.processing_status
|
|
@@ -924,7 +934,7 @@ function registerContentCommands(program2) {
|
|
|
924
934
|
columns: ["id", "name", "type", "status"]
|
|
925
935
|
},
|
|
926
936
|
plain: rows.length ? rows.map(
|
|
927
|
-
(r) => ` ${pc6.bold(String(r.name || "Untitled"))} ${pc6.dim(`(${r.
|
|
937
|
+
(r) => ` ${pc6.bold(String(r.name || "Untitled"))} ${pc6.dim(`(${r.kb_node_id})`)} ${r.type ? pc6.dim(`[${r.type}]`) : ""}`
|
|
928
938
|
) : [" No content found."]
|
|
929
939
|
});
|
|
930
940
|
} catch (err) {
|
|
@@ -1049,7 +1059,7 @@ function registerGenerateCommands(program2) {
|
|
|
1049
1059
|
process.exit(1);
|
|
1050
1060
|
}
|
|
1051
1061
|
});
|
|
1052
|
-
gen.command("update-settings").description("Update content generation settings. Control auto-publish, generation toggle, and schedule (days of week 0-6).").requiredOption("--data <json>", 'JSON settings: { "enable_content_generation": bool, "content_auto_publish": bool, "content_schedule": [0-6] }').action(async (cmdOpts) => {
|
|
1062
|
+
gen.command("update-settings").description("Update content generation settings. Control auto-publish, generation toggle, and schedule (days of week 0-6).").requiredOption("--data <json>", 'JSON settings: { "enable_content_generation": bool, "content_auto_publish": bool, "content_schedule": [0-6], "selected_content_type_id": "<uuid>" }').action(async (cmdOpts) => {
|
|
1053
1063
|
const opts = program2.opts();
|
|
1054
1064
|
try {
|
|
1055
1065
|
const body = JSON.parse(cmdOpts.data);
|
|
@@ -1084,11 +1094,14 @@ function registerGenerateCommands(program2) {
|
|
|
1084
1094
|
process.exit(1);
|
|
1085
1095
|
}
|
|
1086
1096
|
});
|
|
1087
|
-
gen.command("run").description("Trigger a content generation run. Processes all prompts (or a specific subset) through the content engine. Runs asynchronously \u2014 use 'generate runs-list' to monitor progress.").option("--prompt-ids <ids...>", "Optional list of prompt IDs to process (omit to run all)").action(async (cmdOpts) => {
|
|
1097
|
+
gen.command("run").description("Trigger a content generation run. Processes all prompts (or a specific subset) through the content engine. Runs asynchronously \u2014 use 'generate runs-list' to monitor progress.").option("--prompt-ids <ids...>", "Optional list of prompt IDs to process (omit to run all)").option("--content-type-id <id>", "Override the org's default content type for this run").option("--publisher-ids <ids...>", "Restrict publishing to specific publisher IDs").action(async (cmdOpts) => {
|
|
1088
1098
|
const opts = program2.opts();
|
|
1089
1099
|
try {
|
|
1090
|
-
const body =
|
|
1091
|
-
|
|
1100
|
+
const body = {};
|
|
1101
|
+
if (cmdOpts.promptIds) body.prompt_ids = cmdOpts.promptIds;
|
|
1102
|
+
if (cmdOpts.contentTypeId) body.content_type_id = cmdOpts.contentTypeId;
|
|
1103
|
+
if (cmdOpts.publisherIds) body.publisher_ids = cmdOpts.publisherIds;
|
|
1104
|
+
const data = await apiRequest({ method: "POST", path: "/org/content-generation/run", body: Object.keys(body).length > 0 ? body : {}, apiKey: opts.apiKey, baseUrl: opts.baseUrl });
|
|
1092
1105
|
success("Content generation run triggered.");
|
|
1093
1106
|
console.log(JSON.stringify(data, null, 2));
|
|
1094
1107
|
} catch (err) {
|
|
@@ -1732,7 +1745,7 @@ function registerKBCommands(program2) {
|
|
|
1732
1745
|
const opts = program2.opts();
|
|
1733
1746
|
try {
|
|
1734
1747
|
const body = { name: cmdOpts.name };
|
|
1735
|
-
if (cmdOpts.parentId) body.
|
|
1748
|
+
if (cmdOpts.parentId) body.parent_id = cmdOpts.parentId;
|
|
1736
1749
|
const data = await apiRequest({ method: "POST", path: "/org/kb/folders", body, apiKey: opts.apiKey, baseUrl: opts.baseUrl });
|
|
1737
1750
|
success(`Folder "${cmdOpts.name}" created.`);
|
|
1738
1751
|
console.log(JSON.stringify(data, null, 2));
|
|
@@ -1755,7 +1768,7 @@ function registerKBCommands(program2) {
|
|
|
1755
1768
|
kb.command("move <id>").description("Move a KB node to a different parent folder.").requiredOption("--parent-id <parentId>", "Target parent folder node ID").action(async (id, cmdOpts) => {
|
|
1756
1769
|
const opts = program2.opts();
|
|
1757
1770
|
try {
|
|
1758
|
-
const data = await apiRequest({ method: "PATCH", path: `/org/kb/nodes/${id}/move`, body: {
|
|
1771
|
+
const data = await apiRequest({ method: "PATCH", path: `/org/kb/nodes/${id}/move`, body: { new_parent_id: cmdOpts.parentId }, apiKey: opts.apiKey, baseUrl: opts.baseUrl });
|
|
1759
1772
|
success(`Node ${id} moved.`);
|
|
1760
1773
|
console.log(JSON.stringify(data, null, 2));
|
|
1761
1774
|
} catch (err) {
|
|
@@ -1773,7 +1786,7 @@ function registerKBCommands(program2) {
|
|
|
1773
1786
|
process.exit(1);
|
|
1774
1787
|
}
|
|
1775
1788
|
});
|
|
1776
|
-
kb.command("create-raw").description("Create a raw (text/markdown) content item in the knowledge base.").requiredOption("--data <json>", 'JSON: { "
|
|
1789
|
+
kb.command("create-raw").description("Create a raw (text/markdown) content item in the knowledge base.").requiredOption("--data <json>", 'JSON: { "title": "My doc", "text": "# Hello", "kb_folder_node_id": "<uuid>", "tag_ids": ["<uuid>"] }').action(async (cmdOpts) => {
|
|
1777
1790
|
const opts = program2.opts();
|
|
1778
1791
|
try {
|
|
1779
1792
|
const body = JSON.parse(cmdOpts.data);
|
|
@@ -1785,7 +1798,7 @@ function registerKBCommands(program2) {
|
|
|
1785
1798
|
process.exit(1);
|
|
1786
1799
|
}
|
|
1787
1800
|
});
|
|
1788
|
-
kb.command("update-raw <id>").description("Fully replace the text content of a raw KB node (creates a new version).").requiredOption("--data <json>", 'JSON: { "text": "# Updated content" }').action(async (id, cmdOpts) => {
|
|
1801
|
+
kb.command("update-raw <id>").description("Fully replace the text content of a raw KB node (creates a new version).").requiredOption("--data <json>", 'JSON: { "title": "Title", "text": "# Updated content", "tag_ids": ["<uuid>"] }').action(async (id, cmdOpts) => {
|
|
1789
1802
|
const opts = program2.opts();
|
|
1790
1803
|
try {
|
|
1791
1804
|
const body = JSON.parse(cmdOpts.data);
|
|
@@ -1797,7 +1810,7 @@ function registerKBCommands(program2) {
|
|
|
1797
1810
|
process.exit(1);
|
|
1798
1811
|
}
|
|
1799
1812
|
});
|
|
1800
|
-
kb.command("patch-raw <id>").description("Partially update the text content of a raw KB node.").requiredOption("--data <json>", 'JSON: { "text": "Updated text", "
|
|
1813
|
+
kb.command("patch-raw <id>").description("Partially update the text content of a raw KB node.").requiredOption("--data <json>", 'JSON: { "title": "New title", "text": "Updated text", "summary": "...", "tag_ids": ["<uuid>"] }').action(async (id, cmdOpts) => {
|
|
1801
1814
|
const opts = program2.opts();
|
|
1802
1815
|
try {
|
|
1803
1816
|
const body = JSON.parse(cmdOpts.data);
|
|
@@ -1819,31 +1832,37 @@ function registerKBCommands(program2) {
|
|
|
1819
1832
|
const fileData = await Promise.all(files.map(getFileMetadata2));
|
|
1820
1833
|
const body = { files: fileData.map((f) => f.meta) };
|
|
1821
1834
|
if (cmdOpts.folderId) body.kb_folder_node_id = cmdOpts.folderId;
|
|
1822
|
-
const
|
|
1835
|
+
const response = await apiRequest({
|
|
1823
1836
|
method: "POST",
|
|
1824
1837
|
path: "/org/kb/upload",
|
|
1825
1838
|
body,
|
|
1826
1839
|
apiKey: opts.apiKey,
|
|
1827
1840
|
baseUrl: opts.baseUrl
|
|
1828
1841
|
});
|
|
1829
|
-
const items =
|
|
1842
|
+
const items = response.results ?? [];
|
|
1830
1843
|
let uploaded = 0;
|
|
1831
1844
|
for (const item of items) {
|
|
1832
1845
|
if (item.status === "upload_pending" && item.upload_url) {
|
|
1833
1846
|
const match = fileData.find((f) => f.meta.filename === item.filename);
|
|
1834
|
-
if (match) {
|
|
1847
|
+
if (!match) {
|
|
1848
|
+
error(`Could not match server filename "${item.filename}" to a local file \u2014 skipping upload.`);
|
|
1849
|
+
continue;
|
|
1850
|
+
}
|
|
1851
|
+
try {
|
|
1835
1852
|
await uploadToS32(item.upload_url, match.buffer, match.meta.content_type);
|
|
1836
1853
|
uploaded++;
|
|
1837
1854
|
success(`Uploaded ${item.filename} (content_id: ${item.content_id})`);
|
|
1855
|
+
} catch (uploadErr) {
|
|
1856
|
+
error(`S3 upload failed for ${item.filename}: ${uploadErr instanceof Error ? uploadErr.message : String(uploadErr)}`);
|
|
1838
1857
|
}
|
|
1839
1858
|
} else {
|
|
1840
|
-
warn(`Skipped ${item.filename}: ${item.status}${item.
|
|
1859
|
+
warn(`Skipped ${item.filename}: ${item.status}${item.error ? ` \u2014 ${item.error}` : ""}`);
|
|
1841
1860
|
}
|
|
1842
1861
|
}
|
|
1843
1862
|
if (uploaded > 0) {
|
|
1844
1863
|
success(`${uploaded} file(s) uploaded. Background processing will parse, chunk, and embed them.`);
|
|
1845
1864
|
}
|
|
1846
|
-
if (opts.output === "json") console.log(JSON.stringify(
|
|
1865
|
+
if (opts.output === "json") console.log(JSON.stringify(response, null, 2));
|
|
1847
1866
|
} catch (err) {
|
|
1848
1867
|
error(formatApiError(err));
|
|
1849
1868
|
process.exit(1);
|
|
@@ -1853,23 +1872,20 @@ function registerKBCommands(program2) {
|
|
|
1853
1872
|
const opts = program2.opts();
|
|
1854
1873
|
try {
|
|
1855
1874
|
const { meta, buffer } = await getFileMetadata2(file);
|
|
1856
|
-
const
|
|
1875
|
+
const item = await apiRequest({
|
|
1857
1876
|
method: "PUT",
|
|
1858
1877
|
path: `/org/kb/nodes/${id}/file`,
|
|
1859
1878
|
body: { file: meta },
|
|
1860
1879
|
apiKey: opts.apiKey,
|
|
1861
1880
|
baseUrl: opts.baseUrl
|
|
1862
1881
|
});
|
|
1863
|
-
|
|
1864
|
-
|
|
1865
|
-
|
|
1866
|
-
|
|
1867
|
-
|
|
1868
|
-
} else {
|
|
1869
|
-
warn(`Skipped: ${item.status}${item.message ? ` \u2014 ${item.message}` : ""}`);
|
|
1870
|
-
}
|
|
1882
|
+
if (item.status === "upload_pending" && item.upload_url) {
|
|
1883
|
+
await uploadToS32(item.upload_url, buffer, meta.content_type);
|
|
1884
|
+
success(`Uploaded ${meta.filename} for node ${id}. Background re-processing started.`);
|
|
1885
|
+
} else {
|
|
1886
|
+
warn(`Skipped: ${item.status}${item.error ? ` \u2014 ${item.error}` : ""}`);
|
|
1871
1887
|
}
|
|
1872
|
-
if (opts.output === "json") console.log(JSON.stringify(
|
|
1888
|
+
if (opts.output === "json") console.log(JSON.stringify(item, null, 2));
|
|
1873
1889
|
} catch (err) {
|
|
1874
1890
|
error(formatApiError(err));
|
|
1875
1891
|
process.exit(1);
|