papiers 0.1.2 → 0.1.3
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/README.md +26 -3
- package/dist/index.js +784 -352
- package/package.json +3 -2
- package/skills/papiers-research/SKILL.md +116 -0
package/dist/index.js
CHANGED
|
@@ -268,7 +268,7 @@ function resolveCliConfig(params) {
|
|
|
268
268
|
const token = firstNonEmpty([params.env[TOKEN_ENV_VAR]]) ?? null;
|
|
269
269
|
return {
|
|
270
270
|
apiBaseUrl: normalizedBaseUrl,
|
|
271
|
-
apiBaseUrlSource: params.apiBaseUrlOverride ? "--api-
|
|
271
|
+
apiBaseUrlSource: params.apiBaseUrlOverride ? "--api-url" : params.env[API_BASE_URL_ENV_VAR]?.trim() ? API_BASE_URL_ENV_VAR : "default",
|
|
272
272
|
token,
|
|
273
273
|
tokenSource: token ? TOKEN_ENV_VAR : null,
|
|
274
274
|
tokenPreview: token ? redactPapiersToken(token) : null
|
|
@@ -420,16 +420,6 @@ var PUBLIC_KINDS = [
|
|
|
420
420
|
"conversation",
|
|
421
421
|
"equation"
|
|
422
422
|
];
|
|
423
|
-
var EXPECTED_DOCUMENT_QUERY_IN = [
|
|
424
|
-
"title",
|
|
425
|
-
"metadata"
|
|
426
|
-
];
|
|
427
|
-
var EXPECTED_CONTENT_QUERY_IN = [
|
|
428
|
-
"content"
|
|
429
|
-
];
|
|
430
|
-
var EXPECTED_EQUATION_QUERY_IN = [
|
|
431
|
-
"latex"
|
|
432
|
-
];
|
|
433
423
|
var EXPECTED_DOCUMENT_READ_FORMATS = [
|
|
434
424
|
"metadata",
|
|
435
425
|
"markdown",
|
|
@@ -478,10 +468,13 @@ var EXPECTED_DOCUMENT_FILTERS = [
|
|
|
478
468
|
"engaged",
|
|
479
469
|
"lastEngagedAt"
|
|
480
470
|
];
|
|
471
|
+
var EXPECTED_CONVERSATION_FILTERS = [
|
|
472
|
+
"lastEngagedAt"
|
|
473
|
+
];
|
|
481
474
|
var EXPECTED_DOCUMENT_FILTER_OPERATORS = {
|
|
482
475
|
id: ["eq", "in"],
|
|
483
476
|
title: ["eq", "contains", "prefix", "in"],
|
|
484
|
-
author: ["eq"],
|
|
477
|
+
author: ["eq", "contains"],
|
|
485
478
|
venue: ["eq", "contains", "prefix", "in"],
|
|
486
479
|
publishedDate: ["eq", "gte", "gt", "lte", "lt", "between"],
|
|
487
480
|
publishedYear: ["eq", "gte", "gt", "lte", "lt", "between", "in"],
|
|
@@ -598,6 +591,25 @@ var PAPIERS_SEARCH_QUALITY_SIGNALS = [
|
|
|
598
591
|
"low",
|
|
599
592
|
"empty"
|
|
600
593
|
];
|
|
594
|
+
var PAPIERS_SEARCH_RESULT_KINDS = [
|
|
595
|
+
"document",
|
|
596
|
+
"conversation"
|
|
597
|
+
];
|
|
598
|
+
var PAPIERS_SEARCH_EVIDENCE_KINDS = [
|
|
599
|
+
"passage",
|
|
600
|
+
"highlight",
|
|
601
|
+
"equation"
|
|
602
|
+
];
|
|
603
|
+
var PAPIERS_SEARCH_MATCH_REASONS = [
|
|
604
|
+
"title",
|
|
605
|
+
"doi",
|
|
606
|
+
"arxivId",
|
|
607
|
+
"pmid",
|
|
608
|
+
"passage",
|
|
609
|
+
"highlight",
|
|
610
|
+
"equation",
|
|
611
|
+
"conversation"
|
|
612
|
+
];
|
|
601
613
|
var PAPIERS_PUBLIC_NOT_READY_REASONS_BY_FEATURE = {
|
|
602
614
|
document_content_read: ["explicit_enablement_required"],
|
|
603
615
|
non_document_kinds: ["public_id_projection_not_ready"],
|
|
@@ -613,7 +625,10 @@ var PAPIERS_PUBLIC_NOT_READY_REASONS_BY_FEATURE = {
|
|
|
613
625
|
read_section_scopes: ["section_scoped_read_not_ready"],
|
|
614
626
|
read_context: ["read_context_not_ready"],
|
|
615
627
|
ranked_search_cursors: ["search_sessions_not_ready"],
|
|
616
|
-
search_results_browse: [
|
|
628
|
+
search_results_browse: [
|
|
629
|
+
"content_search_not_ready",
|
|
630
|
+
"search_sessions_not_ready"
|
|
631
|
+
]
|
|
617
632
|
};
|
|
618
633
|
var PAPIERS_PUBLIC_ERROR_CODES = [
|
|
619
634
|
"api_disabled",
|
|
@@ -746,7 +761,7 @@ var SEARCH_RESPONSE_KEYS = /* @__PURE__ */ new Set([
|
|
|
746
761
|
"requestId",
|
|
747
762
|
"query",
|
|
748
763
|
"quality",
|
|
749
|
-
"
|
|
764
|
+
"results",
|
|
750
765
|
"page",
|
|
751
766
|
"ranking",
|
|
752
767
|
"warnings"
|
|
@@ -760,6 +775,9 @@ var SEARCH_RANKING_KEYS = /* @__PURE__ */ new Set([
|
|
|
760
775
|
]);
|
|
761
776
|
var SEARCH_QUALITY_KEYS = /* @__PURE__ */ new Set(["signal", "suggestions"]);
|
|
762
777
|
var SEARCH_QUALITY_SIGNALS = new Set(PAPIERS_SEARCH_QUALITY_SIGNALS);
|
|
778
|
+
var SEARCH_RESULT_KINDS = new Set(PAPIERS_SEARCH_RESULT_KINDS);
|
|
779
|
+
var SEARCH_EVIDENCE_KINDS = new Set(PAPIERS_SEARCH_EVIDENCE_KINDS);
|
|
780
|
+
var SEARCH_MATCH_REASONS = new Set(PAPIERS_SEARCH_MATCH_REASONS);
|
|
763
781
|
var PUBLIC_WARNING_KEYS = /* @__PURE__ */ new Set(["code", "message"]);
|
|
764
782
|
var DOCUMENT_SEARCH_WARNING_CODE = "metadata_only_search";
|
|
765
783
|
var DOCUMENT_SEARCH_WARNING_MESSAGE = "Public document search currently searches catalog title and metadata, not document body content.";
|
|
@@ -821,6 +839,32 @@ var SEARCH_DOCUMENT_ITEM_KEYS = /* @__PURE__ */ new Set([
|
|
|
821
839
|
"metadata",
|
|
822
840
|
"updatedAt"
|
|
823
841
|
]);
|
|
842
|
+
var SEARCH_RESULT_BASE_KEYS = [
|
|
843
|
+
"id",
|
|
844
|
+
"kind",
|
|
845
|
+
"rank",
|
|
846
|
+
"score",
|
|
847
|
+
"matchedBy",
|
|
848
|
+
"title"
|
|
849
|
+
];
|
|
850
|
+
var SEARCH_DOCUMENT_RESULT_KEYS = /* @__PURE__ */ new Set([
|
|
851
|
+
...SEARCH_RESULT_BASE_KEYS,
|
|
852
|
+
"source",
|
|
853
|
+
"metadata",
|
|
854
|
+
"evidence",
|
|
855
|
+
"evidenceTotal"
|
|
856
|
+
]);
|
|
857
|
+
var SEARCH_CONVERSATION_RESULT_KEYS = /* @__PURE__ */ new Set([
|
|
858
|
+
...SEARCH_RESULT_BASE_KEYS,
|
|
859
|
+
"snippet"
|
|
860
|
+
]);
|
|
861
|
+
var SEARCH_EVIDENCE_KEYS = /* @__PURE__ */ new Set([
|
|
862
|
+
"kind",
|
|
863
|
+
"id",
|
|
864
|
+
"rank",
|
|
865
|
+
"snippet",
|
|
866
|
+
"score"
|
|
867
|
+
]);
|
|
824
868
|
var READ_SUCCESS_DOCUMENT_ITEM_KEYS = /* @__PURE__ */ new Set([
|
|
825
869
|
"id",
|
|
826
870
|
"kind",
|
|
@@ -1050,17 +1094,12 @@ function assertPapiersSearchResponse(label, body, expectedQuery, options = {}) {
|
|
|
1050
1094
|
`${label} did not echo the requested query.`
|
|
1051
1095
|
);
|
|
1052
1096
|
}
|
|
1053
|
-
const itemCount =
|
|
1054
|
-
|
|
1055
|
-
|
|
1056
|
-
|
|
1057
|
-
requireRank: true
|
|
1058
|
-
});
|
|
1059
|
-
const searchItems = value.items;
|
|
1060
|
-
for (const [index, item] of searchItems.entries()) {
|
|
1061
|
-
if (item.rank !== index + 1) {
|
|
1097
|
+
const itemCount = validateSearchResults(label, value.results, options);
|
|
1098
|
+
const searchResults = value.results;
|
|
1099
|
+
for (const [index, result] of searchResults.entries()) {
|
|
1100
|
+
if (result.rank !== index + 1) {
|
|
1062
1101
|
throw new PapiersCliResponseValidationError(
|
|
1063
|
-
`${label}
|
|
1102
|
+
`${label} result ${index} rank was not contiguous from 1.`
|
|
1064
1103
|
);
|
|
1065
1104
|
}
|
|
1066
1105
|
}
|
|
@@ -1080,10 +1119,7 @@ function assertPapiersSearchResultsResponse(label, body, request) {
|
|
|
1080
1119
|
rejectUnexpectedKeys(label, value, SEARCH_RESPONSE_KEYS);
|
|
1081
1120
|
assertPublicRequestId(`${label} requestId`, value.requestId);
|
|
1082
1121
|
assertNonEmptyString(`${label} query`, value.query);
|
|
1083
|
-
const itemCount =
|
|
1084
|
-
mode: "search",
|
|
1085
|
-
requireRank: true
|
|
1086
|
-
});
|
|
1122
|
+
const itemCount = validateSearchResults(label, value.results);
|
|
1087
1123
|
validatePage(label, value.page, itemCount, { cursor: "none" });
|
|
1088
1124
|
validateOptionalSearchQuality(`${label} quality`, value.quality);
|
|
1089
1125
|
if (value.ranking === void 0) {
|
|
@@ -1118,12 +1154,12 @@ function assertPapiersSearchResultsResponse(label, body, request) {
|
|
|
1118
1154
|
`${label} returned more items than the consumed ranking window.`
|
|
1119
1155
|
);
|
|
1120
1156
|
}
|
|
1121
|
-
const items = value.
|
|
1157
|
+
const items = value.results;
|
|
1122
1158
|
let previousRank = expectedOffset;
|
|
1123
1159
|
for (const [index, item] of items.entries()) {
|
|
1124
1160
|
if (typeof item.rank !== "number" || item.rank <= previousRank || item.rank > consumedBound) {
|
|
1125
1161
|
throw new PapiersCliResponseValidationError(
|
|
1126
|
-
`${label}
|
|
1162
|
+
`${label} result ${index} rank was not strictly increasing within the frozen ranking window.`
|
|
1127
1163
|
);
|
|
1128
1164
|
}
|
|
1129
1165
|
previousRank = item.rank;
|
|
@@ -1332,6 +1368,164 @@ function validateTokenSummary(label, rawToken) {
|
|
|
1332
1368
|
validateOptionalTimestamp(`${label} revokedAt`, token.revokedAt);
|
|
1333
1369
|
validateOptionalTimestamp(`${label} lastUsedAt`, token.lastUsedAt);
|
|
1334
1370
|
}
|
|
1371
|
+
function validateSearchResults(label, results, options = {}) {
|
|
1372
|
+
const values = assertArray(`${label} results`, results);
|
|
1373
|
+
for (const [index, rawResult] of values.entries()) {
|
|
1374
|
+
const result = assertRecord(`${label} result ${index}`, rawResult);
|
|
1375
|
+
rejectUnexpectedContent(`${label} result ${index}`, result);
|
|
1376
|
+
const kind = validateSearchResultKind(
|
|
1377
|
+
`${label} result ${index} kind`,
|
|
1378
|
+
result.kind,
|
|
1379
|
+
result.id
|
|
1380
|
+
);
|
|
1381
|
+
if (options.expectedKind !== void 0 && kind !== options.expectedKind) {
|
|
1382
|
+
throw new PapiersCliResponseValidationError(
|
|
1383
|
+
`${label} result ${index} kind did not match the requested kind.`
|
|
1384
|
+
);
|
|
1385
|
+
}
|
|
1386
|
+
if (options.expectedKinds !== void 0 && !options.expectedKinds.has(kind)) {
|
|
1387
|
+
throw new PapiersCliResponseValidationError(
|
|
1388
|
+
`${label} result ${index} kind was not one of the requested kinds.`
|
|
1389
|
+
);
|
|
1390
|
+
}
|
|
1391
|
+
if (kind === "document") {
|
|
1392
|
+
validateSearchDocumentResult(`${label} result ${index}`, result);
|
|
1393
|
+
} else {
|
|
1394
|
+
validateSearchConversationResult(`${label} result ${index}`, result);
|
|
1395
|
+
}
|
|
1396
|
+
}
|
|
1397
|
+
return values.length;
|
|
1398
|
+
}
|
|
1399
|
+
function validateSearchResultKind(label, value, id) {
|
|
1400
|
+
if (typeof id !== "string") {
|
|
1401
|
+
throw new PapiersCliResponseValidationError(`${label} id was invalid.`);
|
|
1402
|
+
}
|
|
1403
|
+
if (!SEARCH_RESULT_KINDS.has(String(value))) {
|
|
1404
|
+
throw new PapiersCliResponseValidationError(
|
|
1405
|
+
`${label} was not a top-level search result kind.`
|
|
1406
|
+
);
|
|
1407
|
+
}
|
|
1408
|
+
if (value === "document") {
|
|
1409
|
+
assertDocId(`${label} id`, id);
|
|
1410
|
+
return "document";
|
|
1411
|
+
}
|
|
1412
|
+
if (value === "conversation" && isPublicIdForKind(id, "conversation")) {
|
|
1413
|
+
return "conversation";
|
|
1414
|
+
}
|
|
1415
|
+
throw new PapiersCliResponseValidationError(
|
|
1416
|
+
`${label} did not match the public id kind.`
|
|
1417
|
+
);
|
|
1418
|
+
}
|
|
1419
|
+
function validateSearchDocumentResult(label, result) {
|
|
1420
|
+
rejectUnexpectedKeys(label, result, SEARCH_DOCUMENT_RESULT_KEYS);
|
|
1421
|
+
assertDocId(`${label} id`, result.id);
|
|
1422
|
+
assertPositiveInteger(`${label} rank`, result.rank);
|
|
1423
|
+
validateSearchScore(`${label} score`, result.score);
|
|
1424
|
+
validateSearchMatchedBy(`${label} matchedBy`, result.matchedBy, {
|
|
1425
|
+
allow: /* @__PURE__ */ new Set([
|
|
1426
|
+
"title",
|
|
1427
|
+
"doi",
|
|
1428
|
+
"arxivId",
|
|
1429
|
+
"pmid",
|
|
1430
|
+
"passage",
|
|
1431
|
+
"highlight",
|
|
1432
|
+
"equation"
|
|
1433
|
+
])
|
|
1434
|
+
});
|
|
1435
|
+
validateOptionalNullableString(`${label} title`, result.title);
|
|
1436
|
+
validateOptionalDocumentCatalogMetadata(`${label} metadata`, result.metadata);
|
|
1437
|
+
validateOptionalMetadataReadSource(`${label} source`, result.source);
|
|
1438
|
+
const evidenceCount = validateSearchEvidenceList(
|
|
1439
|
+
`${label} evidence`,
|
|
1440
|
+
result.evidence
|
|
1441
|
+
);
|
|
1442
|
+
const evidenceTotal = assertNonNegativeInteger(
|
|
1443
|
+
`${label} evidenceTotal`,
|
|
1444
|
+
result.evidenceTotal
|
|
1445
|
+
);
|
|
1446
|
+
if (evidenceTotal < evidenceCount) {
|
|
1447
|
+
throw new PapiersCliResponseValidationError(
|
|
1448
|
+
`${label} evidenceTotal was smaller than evidence.length.`
|
|
1449
|
+
);
|
|
1450
|
+
}
|
|
1451
|
+
}
|
|
1452
|
+
function validateSearchConversationResult(label, result) {
|
|
1453
|
+
rejectUnexpectedKeys(label, result, SEARCH_CONVERSATION_RESULT_KEYS);
|
|
1454
|
+
const id = assertNonEmptyString(`${label} id`, result.id);
|
|
1455
|
+
if (!isPublicIdForKind(id, "conversation")) {
|
|
1456
|
+
throw new PapiersCliResponseValidationError(
|
|
1457
|
+
`${label} id was not a cnv_* public id.`
|
|
1458
|
+
);
|
|
1459
|
+
}
|
|
1460
|
+
assertPositiveInteger(`${label} rank`, result.rank);
|
|
1461
|
+
validateSearchScore(`${label} score`, result.score);
|
|
1462
|
+
validateSearchMatchedBy(`${label} matchedBy`, result.matchedBy, {
|
|
1463
|
+
allow: /* @__PURE__ */ new Set(["conversation"])
|
|
1464
|
+
});
|
|
1465
|
+
validateOptionalNullableString(`${label} title`, result.title);
|
|
1466
|
+
validateOptionalPublicExcerpt(`${label} snippet`, result.snippet);
|
|
1467
|
+
}
|
|
1468
|
+
function validateSearchEvidenceList(label, value) {
|
|
1469
|
+
const evidence = assertArray(label, value);
|
|
1470
|
+
for (const [index, rawEvidence] of evidence.entries()) {
|
|
1471
|
+
const item = assertRecord(`${label} ${index}`, rawEvidence);
|
|
1472
|
+
rejectUnexpectedKeys(`${label} ${index}`, item, SEARCH_EVIDENCE_KEYS);
|
|
1473
|
+
validateSearchEvidenceKind(`${label} ${index} kind`, item.kind, item.id);
|
|
1474
|
+
assertPositiveInteger(`${label} ${index} rank`, item.rank);
|
|
1475
|
+
if (item.rank !== index + 1) {
|
|
1476
|
+
throw new PapiersCliResponseValidationError(
|
|
1477
|
+
`${label} ${index} rank was not contiguous from 1.`
|
|
1478
|
+
);
|
|
1479
|
+
}
|
|
1480
|
+
validateOptionalPublicExcerpt(`${label} ${index} snippet`, item.snippet);
|
|
1481
|
+
validateSearchScore(`${label} ${index} score`, item.score);
|
|
1482
|
+
}
|
|
1483
|
+
return evidence.length;
|
|
1484
|
+
}
|
|
1485
|
+
function validateSearchEvidenceKind(label, value, id) {
|
|
1486
|
+
if (typeof id !== "string") {
|
|
1487
|
+
throw new PapiersCliResponseValidationError(`${label} id was invalid.`);
|
|
1488
|
+
}
|
|
1489
|
+
if (!SEARCH_EVIDENCE_KINDS.has(String(value))) {
|
|
1490
|
+
throw new PapiersCliResponseValidationError(
|
|
1491
|
+
`${label} was not a search evidence kind.`
|
|
1492
|
+
);
|
|
1493
|
+
}
|
|
1494
|
+
if (value === "passage" && isPublicIdForKind(id, "passage") || value === "highlight" && isPublicIdForKind(id, "highlight") || value === "equation" && isPublicIdForKind(id, "equation")) {
|
|
1495
|
+
return value;
|
|
1496
|
+
}
|
|
1497
|
+
throw new PapiersCliResponseValidationError(
|
|
1498
|
+
`${label} did not match the public id kind.`
|
|
1499
|
+
);
|
|
1500
|
+
}
|
|
1501
|
+
function validateSearchMatchedBy(label, value, options) {
|
|
1502
|
+
const values = assertArray(label, value);
|
|
1503
|
+
if (values.length === 0) {
|
|
1504
|
+
throw new PapiersCliResponseValidationError(`${label} was empty.`);
|
|
1505
|
+
}
|
|
1506
|
+
const seen = /* @__PURE__ */ new Set();
|
|
1507
|
+
for (const [index, rawReason] of values.entries()) {
|
|
1508
|
+
const reason = assertNonEmptyString(`${label} ${index}`, rawReason);
|
|
1509
|
+
if (!SEARCH_MATCH_REASONS.has(reason) || !options.allow.has(reason)) {
|
|
1510
|
+
throw new PapiersCliResponseValidationError(
|
|
1511
|
+
`${label} ${index} was not an allowed search match reason.`
|
|
1512
|
+
);
|
|
1513
|
+
}
|
|
1514
|
+
if (seen.has(reason)) {
|
|
1515
|
+
throw new PapiersCliResponseValidationError(
|
|
1516
|
+
`${label} contained duplicate match reasons.`
|
|
1517
|
+
);
|
|
1518
|
+
}
|
|
1519
|
+
seen.add(reason);
|
|
1520
|
+
}
|
|
1521
|
+
}
|
|
1522
|
+
function validateSearchScore(label, value) {
|
|
1523
|
+
if (typeof value !== "number" || !Number.isFinite(value) || value < 0 || value > 1) {
|
|
1524
|
+
throw new PapiersCliResponseValidationError(
|
|
1525
|
+
`${label} was not a finite score in [0, 1].`
|
|
1526
|
+
);
|
|
1527
|
+
}
|
|
1528
|
+
}
|
|
1335
1529
|
function assertNoInternalResponseKeys(label, value, options = {}) {
|
|
1336
1530
|
const stack = [
|
|
1337
1531
|
{ value, isRoot: true }
|
|
@@ -2709,22 +2903,18 @@ function expectedKindForListSearchRequest(request) {
|
|
|
2709
2903
|
function expectedKindsForSearchRequest(request) {
|
|
2710
2904
|
const kinds = request.kinds;
|
|
2711
2905
|
if (kinds === void 0) {
|
|
2712
|
-
return {
|
|
2713
|
-
expectedKinds: /* @__PURE__ */ new Set([
|
|
2714
|
-
"document",
|
|
2715
|
-
"passage",
|
|
2716
|
-
"highlight",
|
|
2717
|
-
"conversation"
|
|
2718
|
-
])
|
|
2719
|
-
};
|
|
2906
|
+
return { expectedKinds: /* @__PURE__ */ new Set(["document", "conversation"]) };
|
|
2720
2907
|
}
|
|
2721
|
-
if (!Array.isArray(kinds) || kinds.length
|
|
2722
|
-
|
|
2908
|
+
if (!Array.isArray(kinds) || kinds.length === 0) {
|
|
2909
|
+
throw new CliUsageError(
|
|
2910
|
+
"Public search requests must specify at least one supported kind."
|
|
2911
|
+
);
|
|
2723
2912
|
}
|
|
2724
|
-
|
|
2725
|
-
|
|
2913
|
+
const rawKinds = kinds;
|
|
2914
|
+
for (const kind of rawKinds) {
|
|
2915
|
+
if (kind === "document") {
|
|
2726
2916
|
throw new CliUsageError(
|
|
2727
|
-
|
|
2917
|
+
"Unified public search does not support kind document; omit kinds to search titles plus content."
|
|
2728
2918
|
);
|
|
2729
2919
|
}
|
|
2730
2920
|
if (!PUBLIC_KINDS.includes(kind)) {
|
|
@@ -2733,14 +2923,16 @@ function expectedKindsForSearchRequest(request) {
|
|
|
2733
2923
|
);
|
|
2734
2924
|
}
|
|
2735
2925
|
}
|
|
2736
|
-
|
|
2737
|
-
|
|
2738
|
-
|
|
2926
|
+
const normalizedKinds = new Set(rawKinds);
|
|
2927
|
+
if (normalizedKinds.size === 1 && normalizedKinds.has("conversation")) {
|
|
2928
|
+
return { expectedKind: "conversation" };
|
|
2929
|
+
}
|
|
2930
|
+
return normalizedKinds.has("conversation") ? { expectedKinds: /* @__PURE__ */ new Set(["document", "conversation"]) } : { expectedKind: "document" };
|
|
2739
2931
|
}
|
|
2740
2932
|
async function requestPapiersApi(config, fetchImpl, path, init) {
|
|
2741
2933
|
if (!config.token) {
|
|
2742
2934
|
throw new CliUsageError(
|
|
2743
|
-
`${TOKEN_ENV_VAR} is
|
|
2935
|
+
`${TOKEN_ENV_VAR} is not set. Run papiers auth login, or set ${TOKEN_ENV_VAR}, then retry.`
|
|
2744
2936
|
);
|
|
2745
2937
|
}
|
|
2746
2938
|
return requestPapiersApiWithBearer(
|
|
@@ -2862,7 +3054,7 @@ var PMID_PATTERN = /^\d+$/u;
|
|
|
2862
3054
|
var YEAR_PATTERN = /^\d{4}$/u;
|
|
2863
3055
|
var MIN_PUBLIC_YEAR = 1;
|
|
2864
3056
|
var MAX_PUBLIC_YEAR = 9999;
|
|
2865
|
-
var
|
|
3057
|
+
var FORMER_FILTER_FIELD_ALIASES = {
|
|
2866
3058
|
arxiv_id: "arxivId",
|
|
2867
3059
|
last_engaged_at: "lastEngagedAt",
|
|
2868
3060
|
published_date: "publishedDate",
|
|
@@ -2871,13 +3063,27 @@ var DOCUMENT_FILTER_FIELD_ALIASES = {
|
|
|
2871
3063
|
source_family: "sourceFamily",
|
|
2872
3064
|
year: "publishedYear"
|
|
2873
3065
|
};
|
|
2874
|
-
|
|
2875
|
-
|
|
2876
|
-
|
|
3066
|
+
function didYouMeanFilterField(field) {
|
|
3067
|
+
const suggestion = FORMER_FILTER_FIELD_ALIASES[field];
|
|
3068
|
+
return suggestion ? ` Did you mean "${suggestion}"?` : "";
|
|
3069
|
+
}
|
|
2877
3070
|
function parseDocumentFilterExpression(expression) {
|
|
3071
|
+
if (isImplicitAuthorEqualityFilterExpression(expression)) {
|
|
3072
|
+
throw new CliUsageError(
|
|
3073
|
+
'Use "author.contains=<name-or-handle>" for author searches, or "author.eq=<full-author-key>" for exact author-key matches.'
|
|
3074
|
+
);
|
|
3075
|
+
}
|
|
2878
3076
|
const filter = parseFilterExpression(expression);
|
|
2879
3077
|
return normalizeSupportedDocumentFilter(filter);
|
|
2880
3078
|
}
|
|
3079
|
+
function isImplicitAuthorEqualityFilterExpression(expression) {
|
|
3080
|
+
const trimmed = expression.trim();
|
|
3081
|
+
const equalsIndex = trimmed.indexOf("=");
|
|
3082
|
+
if (equalsIndex < 0) {
|
|
3083
|
+
return false;
|
|
3084
|
+
}
|
|
3085
|
+
return trimmed.slice(0, equalsIndex).trim() === "author";
|
|
3086
|
+
}
|
|
2881
3087
|
function parseFilterExpression(expression) {
|
|
2882
3088
|
const parsed = parseFilterParts(expression);
|
|
2883
3089
|
const field = parsed.field.trim();
|
|
@@ -2903,57 +3109,52 @@ function parseFilterExpression(expression) {
|
|
|
2903
3109
|
};
|
|
2904
3110
|
}
|
|
2905
3111
|
function normalizeSupportedDocumentFilter(filter) {
|
|
2906
|
-
const
|
|
2907
|
-
const
|
|
2908
|
-
const allowedOperators = EXPECTED_DOCUMENT_FILTER_OPERATORS[canonicalField];
|
|
3112
|
+
const field = filter.field;
|
|
3113
|
+
const allowedOperators = EXPECTED_DOCUMENT_FILTER_OPERATORS[field];
|
|
2909
3114
|
if (!allowedOperators) {
|
|
2910
3115
|
throw new CliUsageError(
|
|
2911
3116
|
`Unsupported public document filter field "${filter.field}". Supported fields: ${Object.keys(
|
|
2912
3117
|
EXPECTED_DOCUMENT_FILTER_OPERATORS
|
|
2913
|
-
).join(", ")}
|
|
3118
|
+
).join(", ")}.${didYouMeanFilterField(filter.field)}`
|
|
2914
3119
|
);
|
|
2915
3120
|
}
|
|
2916
|
-
if (!allowedOperators.includes(
|
|
2917
|
-
canonicalFilter.op
|
|
2918
|
-
)) {
|
|
3121
|
+
if (!allowedOperators.includes(filter.op)) {
|
|
2919
3122
|
throw new CliUsageError(
|
|
2920
|
-
`Operator "${
|
|
3123
|
+
`Operator "${filter.op}" is not supported for public document filter field "${filter.field}". Supported operators: ${allowedOperators.join(
|
|
2921
3124
|
", "
|
|
2922
3125
|
)}.`
|
|
2923
3126
|
);
|
|
2924
3127
|
}
|
|
2925
|
-
|
|
3128
|
+
const documentFilter = { ...filter, field };
|
|
3129
|
+
switch (field) {
|
|
2926
3130
|
case "id":
|
|
2927
3131
|
return normalizeStringDocumentFilter(
|
|
2928
|
-
|
|
3132
|
+
documentFilter,
|
|
2929
3133
|
normalizeDocumentIdValue
|
|
2930
3134
|
);
|
|
2931
3135
|
case "doi":
|
|
2932
|
-
return normalizeStringDocumentFilter(
|
|
3136
|
+
return normalizeStringDocumentFilter(documentFilter, normalizeDoiOrNull);
|
|
2933
3137
|
case "arxivId":
|
|
2934
3138
|
return normalizeStringDocumentFilter(
|
|
2935
|
-
|
|
3139
|
+
documentFilter,
|
|
2936
3140
|
normalizeArxivOrNull
|
|
2937
3141
|
);
|
|
2938
3142
|
case "pmid":
|
|
2939
|
-
return normalizeStringDocumentFilter(
|
|
2940
|
-
canonicalFilter,
|
|
2941
|
-
normalizePmidOrNull
|
|
2942
|
-
);
|
|
3143
|
+
return normalizeStringDocumentFilter(documentFilter, normalizePmidOrNull);
|
|
2943
3144
|
case "publishedDate":
|
|
2944
|
-
return normalizePublishedDateFilter(
|
|
3145
|
+
return normalizePublishedDateFilter(documentFilter);
|
|
2945
3146
|
case "publishedYear":
|
|
2946
|
-
return normalizePublishedYearFilter(
|
|
3147
|
+
return normalizePublishedYearFilter(documentFilter);
|
|
2947
3148
|
case "sourceDomain":
|
|
2948
|
-
return normalizeSourceDomainFilter(
|
|
3149
|
+
return normalizeSourceDomainFilter(documentFilter);
|
|
2949
3150
|
case "annotated":
|
|
2950
3151
|
case "engaged":
|
|
2951
|
-
return normalizeBooleanDocumentFilter(
|
|
3152
|
+
return normalizeBooleanDocumentFilter(documentFilter);
|
|
2952
3153
|
case "lastEngagedAt":
|
|
2953
|
-
return normalizeLastEngagedAtFilter(
|
|
3154
|
+
return normalizeLastEngagedAtFilter(documentFilter);
|
|
2954
3155
|
default:
|
|
2955
3156
|
return normalizeStringDocumentFilter(
|
|
2956
|
-
|
|
3157
|
+
documentFilter,
|
|
2957
3158
|
normalizeNonEmptyString
|
|
2958
3159
|
);
|
|
2959
3160
|
}
|
|
@@ -3001,12 +3202,6 @@ function normalizeBooleanDocumentFilter(filter) {
|
|
|
3001
3202
|
}
|
|
3002
3203
|
throw invalidFilterValue(filter);
|
|
3003
3204
|
}
|
|
3004
|
-
function canonicalDocumentFilterField(field) {
|
|
3005
|
-
return Object.prototype.hasOwnProperty.call(
|
|
3006
|
-
DOCUMENT_FILTER_FIELD_ALIASES,
|
|
3007
|
-
field
|
|
3008
|
-
) ? DOCUMENT_FILTER_FIELD_ALIASES[field] : field;
|
|
3009
|
-
}
|
|
3010
3205
|
function normalizePublishedDateFilter(filter) {
|
|
3011
3206
|
const normalized = normalizePapiersPublicDateFilter(
|
|
3012
3207
|
filter.op,
|
|
@@ -3293,21 +3488,22 @@ function parseScalar(rawValue) {
|
|
|
3293
3488
|
|
|
3294
3489
|
// src/args.ts
|
|
3295
3490
|
var BOOLEAN_FLAGS = /* @__PURE__ */ new Set([
|
|
3491
|
+
"all",
|
|
3296
3492
|
"force",
|
|
3297
3493
|
"help",
|
|
3298
3494
|
"doc-ids",
|
|
3495
|
+
"evidence-ids",
|
|
3496
|
+
"highlight-ids",
|
|
3299
3497
|
"ids",
|
|
3300
3498
|
"ids0",
|
|
3301
3499
|
"input0",
|
|
3302
3500
|
"json",
|
|
3501
|
+
"passage-ids",
|
|
3303
3502
|
"pretty",
|
|
3304
|
-
"stdin",
|
|
3305
|
-
"token-stdin",
|
|
3306
3503
|
"fail-fast",
|
|
3307
3504
|
"version"
|
|
3308
3505
|
]);
|
|
3309
3506
|
var VALUE_FLAGS = /* @__PURE__ */ new Set([
|
|
3310
|
-
"api-base-url",
|
|
3311
3507
|
"api-url",
|
|
3312
3508
|
"cursor",
|
|
3313
3509
|
"document-id",
|
|
@@ -3326,8 +3522,13 @@ var VALUE_FLAGS = /* @__PURE__ */ new Set([
|
|
|
3326
3522
|
"since"
|
|
3327
3523
|
]);
|
|
3328
3524
|
var SECRET_ARG_FLAGS = /* @__PURE__ */ new Set(["pat", "token", "api-token"]);
|
|
3329
|
-
var GLOBAL_VALUE_FLAGS = /* @__PURE__ */ new Set(["api-
|
|
3525
|
+
var GLOBAL_VALUE_FLAGS = /* @__PURE__ */ new Set(["api-url"]);
|
|
3330
3526
|
var NO_COMMAND_VALUE_FLAGS = /* @__PURE__ */ new Set([...GLOBAL_VALUE_FLAGS]);
|
|
3527
|
+
var REMOVED_FLAG_HINTS = {
|
|
3528
|
+
"api-base-url": "Use --api-url instead.",
|
|
3529
|
+
"token-stdin": "papiers auth login reads the token from stdin \u2014 no flag needed.",
|
|
3530
|
+
stdin: "papiers auth login reads the token from stdin \u2014 no flag needed."
|
|
3531
|
+
};
|
|
3331
3532
|
var NO_COMMAND_BOOLEAN_FLAGS = /* @__PURE__ */ new Set(["help", "json"]);
|
|
3332
3533
|
var IDS_PIPELINE_BOOLEAN_FLAGS = /* @__PURE__ */ new Set([
|
|
3333
3534
|
"help",
|
|
@@ -3338,6 +3539,12 @@ var IDS_PIPELINE_BOOLEAN_FLAGS = /* @__PURE__ */ new Set([
|
|
|
3338
3539
|
"json",
|
|
3339
3540
|
"pretty"
|
|
3340
3541
|
]);
|
|
3542
|
+
var SEARCH_IDS_PIPELINE_BOOLEAN_FLAGS = /* @__PURE__ */ new Set([
|
|
3543
|
+
...IDS_PIPELINE_BOOLEAN_FLAGS,
|
|
3544
|
+
"evidence-ids",
|
|
3545
|
+
"highlight-ids",
|
|
3546
|
+
"passage-ids"
|
|
3547
|
+
]);
|
|
3341
3548
|
var LIST_VALUE_FLAGS = /* @__PURE__ */ new Set([
|
|
3342
3549
|
...GLOBAL_VALUE_FLAGS,
|
|
3343
3550
|
"cursor",
|
|
@@ -3378,122 +3585,309 @@ var READ_BOOLEAN_FLAGS = /* @__PURE__ */ new Set([
|
|
|
3378
3585
|
]);
|
|
3379
3586
|
var AUTH_LOGIN_BOOLEAN_FLAGS = /* @__PURE__ */ new Set([
|
|
3380
3587
|
...NO_COMMAND_BOOLEAN_FLAGS,
|
|
3381
|
-
"force"
|
|
3382
|
-
"stdin",
|
|
3383
|
-
"token-stdin"
|
|
3588
|
+
"force"
|
|
3384
3589
|
]);
|
|
3385
|
-
var
|
|
3386
|
-
var PUBLIC_KIND_ALIASES = /* @__PURE__ */ new Map([
|
|
3387
|
-
["document", "document"],
|
|
3388
|
-
["documents", "document"],
|
|
3590
|
+
var FORMER_KIND_ALIASES = /* @__PURE__ */ new Map([
|
|
3389
3591
|
["doc", "document"],
|
|
3390
3592
|
["docs", "document"],
|
|
3391
|
-
["
|
|
3593
|
+
["documents", "document"],
|
|
3392
3594
|
["passages", "passage"],
|
|
3393
|
-
["highlight", "highlight"],
|
|
3394
|
-
["highlights", "highlight"],
|
|
3395
3595
|
["annotation", "highlight"],
|
|
3396
3596
|
["annotations", "highlight"],
|
|
3397
|
-
["
|
|
3398
|
-
["conversations", "conversation"],
|
|
3597
|
+
["highlights", "highlight"],
|
|
3399
3598
|
["chat", "conversation"],
|
|
3400
3599
|
["chats", "conversation"],
|
|
3401
|
-
["
|
|
3600
|
+
["conversations", "conversation"],
|
|
3402
3601
|
["equations", "equation"]
|
|
3403
3602
|
]);
|
|
3404
3603
|
var MULTI_SEARCH_KINDS = [
|
|
3405
3604
|
"passage",
|
|
3406
3605
|
"highlight",
|
|
3407
|
-
"conversation"
|
|
3606
|
+
"conversation",
|
|
3607
|
+
"equation"
|
|
3408
3608
|
];
|
|
3409
|
-
var
|
|
3609
|
+
var GLOBAL_HELP = `Papiers CLI: search and read your library from the terminal.
|
|
3610
|
+
Your saved papers, highlights, and conversations (your chats) \u2014 for you or an AI agent.
|
|
3410
3611
|
|
|
3411
|
-
|
|
3412
|
-
|
|
3612
|
+
GETTING STARTED
|
|
3613
|
+
papiers auth login Sign in with a token from Papiers (Settings -> API tokens)
|
|
3614
|
+
papiers list --limit 5 --pretty Your most recent documents
|
|
3615
|
+
papiers search "your topic" --pretty Search across your library
|
|
3413
3616
|
|
|
3414
|
-
|
|
3415
|
-
|
|
3416
|
-
|
|
3417
|
-
|
|
3418
|
-
|
|
3419
|
-
|
|
3420
|
-
|
|
3617
|
+
COMMANDS
|
|
3618
|
+
search Search across your library
|
|
3619
|
+
list List your documents, highlights, and conversations
|
|
3620
|
+
read Print a document, highlight, or conversation
|
|
3621
|
+
browse Page through an earlier search's results
|
|
3622
|
+
auth Sign in, check status, or sign out
|
|
3623
|
+
tokens List or revoke your API tokens
|
|
3624
|
+
doctor Check your setup, connection, and what's available
|
|
3625
|
+
version Print the CLI version
|
|
3626
|
+
|
|
3627
|
+
papiers <command> --help full options and examples for a command
|
|
3628
|
+
papiers help --all everything, in one page
|
|
3629
|
+
|
|
3630
|
+
OUTPUT
|
|
3631
|
+
Commands print JSON by default \u2014 built for scripts and agents.
|
|
3632
|
+
--pretty human-readable output
|
|
3633
|
+
--ids / --doc-ids pipe result IDs into the next command
|
|
3634
|
+
|
|
3635
|
+
SIGNING IN
|
|
3636
|
+
Signing in saves your token on this machine.
|
|
3637
|
+
For scripts or an AI agent, set PAPIERS_TOKEN instead.
|
|
3638
|
+
|
|
3639
|
+
Exit codes: 0 ok \xB7 1 command or API failure \xB7 2 bad usage`;
|
|
3640
|
+
var OUTPUT_OPTS = ` --json machine-readable JSON (the default)
|
|
3641
|
+
--pretty human-readable text
|
|
3642
|
+
--ids result/item IDs, one per line, with their native prefix
|
|
3643
|
+
--ids0 the same IDs, NUL-separated, for \`xargs -0\`
|
|
3644
|
+
--doc-ids parent document IDs only (doc_\u2026), deduped; conversation hits are skipped`;
|
|
3645
|
+
var SEARCH_OUTPUT_OPTS = `${OUTPUT_OPTS}
|
|
3646
|
+
--passage-ids matching passage evidence IDs, flattened in result order
|
|
3647
|
+
--highlight-ids matching highlight evidence IDs, flattened in result order
|
|
3648
|
+
--evidence-ids all matching evidence IDs, flattened in result order`;
|
|
3649
|
+
var HELP_TOPICS = {
|
|
3650
|
+
search: `papiers search \u2014 search across your library.
|
|
3651
|
+
|
|
3652
|
+
USAGE
|
|
3653
|
+
papiers search QUERY [--kind KIND ...] [--filter FIELD.OP=VALUE ...] [--limit N] [--pretty|--json|--ids|--ids0|--doc-ids|--passage-ids|--highlight-ids|--evidence-ids]
|
|
3654
|
+
|
|
3655
|
+
OPTIONS
|
|
3656
|
+
--kind KIND what to search. Defaults to all \u2014 your passages, highlights,
|
|
3657
|
+
equations, conversations, and matching titles. Or focus on one:
|
|
3658
|
+
passage \xB7 highlight \xB7 conversation \xB7 equation.
|
|
3659
|
+
--filter FIELD.OP=VALUE narrow parent documents \u2014 repeatable, up to 25.
|
|
3660
|
+
e.g. --filter publishedYear.gte=2020 --filter author.contains=hinton. Fields/ops: help --all.
|
|
3661
|
+
--document-id ID scope to documents: doc_\u2026 (comma-separated or repeated), or @-/@file.
|
|
3662
|
+
--limit N max results, 1\u201350.
|
|
3663
|
+
${SEARCH_OUTPUT_OPTS}
|
|
3664
|
+
|
|
3665
|
+
EXAMPLES
|
|
3666
|
+
papiers search "mixture of experts" --pretty
|
|
3667
|
+
papiers search "capacity factors" --kind passage --document-id doc_<id> --json
|
|
3668
|
+
papiers search "dropout" --filter author.contains=hinton --json
|
|
3669
|
+
papiers search "diffusion" --filter venue.contains=neurips --json
|
|
3670
|
+
papiers search retrieval --kind passage --limit 5 --passage-ids | papiers read @- --format plain --json
|
|
3671
|
+
|
|
3672
|
+
When capabilities.searchResultsBrowse.enabled is true, a search may return ranking.searchId \u2014 pass it to \`papiers browse\` for more pages.`,
|
|
3673
|
+
list: `papiers list \u2014 list your documents, highlights, and conversations.
|
|
3674
|
+
|
|
3675
|
+
USAGE
|
|
3676
|
+
papiers list [--kind KIND] [--limit N] [--cursor CURSOR] [--pretty|--json|--ids|--ids0|--doc-ids]
|
|
3677
|
+
papiers list --kind document [--filter FIELD.OP=VALUE ...] [--order-by KEY] [--document-id doc_\u2026|@-|@file]
|
|
3678
|
+
papiers list --kind highlight|conversation [--since WHEN]
|
|
3679
|
+
|
|
3680
|
+
OPTIONS
|
|
3681
|
+
--kind KIND document (default) \xB7 passage \xB7 highlight \xB7 conversation \xB7 equation.
|
|
3682
|
+
--filter FIELD.OP=VALUE narrow document results \u2014 repeatable, up to 25. document kind only.
|
|
3683
|
+
e.g. --filter lastEngagedAt.gte=30d --filter annotated=true. Fields/ops: help --all.
|
|
3684
|
+
--order-by KEY addedAt:desc (default) or lastEngagedAt:desc. document kind only.
|
|
3685
|
+
--document-id ID scope to documents: doc_\u2026 (comma-separated or repeated), or @-/@file.
|
|
3686
|
+
document and highlight only.
|
|
3687
|
+
--since WHEN only items at or after an ISO 8601 time, or an Nd shorthand (e.g. 30d).
|
|
3688
|
+
highlight and conversation only.
|
|
3689
|
+
--limit N max results, 1\u201350.
|
|
3690
|
+
--cursor CURSOR fetch the next page \u2014 use page.nextCursor from the previous response.
|
|
3691
|
+
${OUTPUT_OPTS}
|
|
3692
|
+
|
|
3693
|
+
EXAMPLES
|
|
3694
|
+
papiers list --limit 5 --pretty
|
|
3695
|
+
papiers list --kind highlight --since 30d --pretty
|
|
3696
|
+
papiers list --kind document --filter lastEngagedAt.gte=30d --json
|
|
3697
|
+
papiers list --kind document --filter annotated=true --json`,
|
|
3698
|
+
read: `papiers read \u2014 print documents, highlights, conversations, passages, or equations.
|
|
3699
|
+
|
|
3700
|
+
USAGE
|
|
3701
|
+
papiers read ID [ID ...] [--format FORMAT] [--max-chars-per-item N] [--fail-fast] [--json|--pretty]
|
|
3702
|
+
papiers read @- | @file [--input0] [--format FORMAT] [--max-chars-per-item N] [--json|--pretty]
|
|
3703
|
+
Each ID is doc_\u2026 / pas_\u2026 / hl_\u2026 / cnv_\u2026 / eq_\u2026 \u2014 the kind is read from the prefix; don't mix kinds.
|
|
3704
|
+
|
|
3705
|
+
OPTIONS
|
|
3706
|
+
--format FORMAT how to render each item. Default auto (equation defaults to metadata).
|
|
3707
|
+
document: auto|metadata|markdown|plain. passage: markdown|plain.
|
|
3708
|
+
highlight, conversation: metadata|plain. equation: metadata.
|
|
3709
|
+
--include SECTION extra sections, comma-separated: metadata, source, locations.
|
|
3710
|
+
document only (highlight/conversation/equation: metadata only; passage: none).
|
|
3711
|
+
--pages RANGE restrict a document read to pages, e.g. 1,3-5. document only.
|
|
3712
|
+
--max-chars-per-item N truncate each item's content to N chars, 1\u2013200000.
|
|
3713
|
+
--cursor CURSOR continue one long document \u2014 use items[].nextCursor from the previous
|
|
3714
|
+
response. One literal doc_\u2026 only, with --format auto, markdown, or plain.
|
|
3715
|
+
--fail-fast exit non-zero if any item fails (default: succeed if at least one does).
|
|
3716
|
+
--json machine-readable JSON (the default)
|
|
3717
|
+
--pretty human-readable text
|
|
3718
|
+
|
|
3719
|
+
EXAMPLES
|
|
3720
|
+
papiers read doc_<id> --format markdown --max-chars-per-item 2000 --json
|
|
3721
|
+
papiers read hl_<id> --json
|
|
3722
|
+
papiers search retrieval --doc-ids | papiers read @- --format metadata --json`,
|
|
3723
|
+
browse: `papiers browse \u2014 page deeper into an earlier search's results.
|
|
3724
|
+
|
|
3725
|
+
USAGE
|
|
3726
|
+
papiers browse srch_\u2026 [--offset N] [--limit N] [--pretty|--json|--ids|--ids0|--doc-ids|--passage-ids|--highlight-ids|--evidence-ids]
|
|
3727
|
+
|
|
3728
|
+
OPTIONS
|
|
3729
|
+
--offset N start at rank N (0-based) in the frozen ranking.
|
|
3730
|
+
--limit N max results, 1\u201350.
|
|
3731
|
+
${SEARCH_OUTPUT_OPTS}
|
|
3732
|
+
|
|
3733
|
+
When capabilities.searchResultsBrowse.enabled is true, a search response includes
|
|
3734
|
+
ranking.searchId (an srch_\u2026 handle); pass it here to page deeper without
|
|
3735
|
+
re-running the search. The ranking is frozen and expires after a while.
|
|
3736
|
+
|
|
3737
|
+
EXAMPLE
|
|
3738
|
+
papiers browse srch_<id> --offset 10 --json`,
|
|
3739
|
+
auth: `papiers auth \u2014 sign in, check status, or sign out.
|
|
3740
|
+
|
|
3741
|
+
USAGE
|
|
3742
|
+
papiers auth login [--force] [--json] Sign in (paste your token, or pipe it in)
|
|
3743
|
+
papiers auth status [--json] Show whether you're signed in
|
|
3744
|
+
papiers auth inspect [--json] Show details about the saved token
|
|
3745
|
+
papiers auth logout [--json] Forget the saved token
|
|
3746
|
+
|
|
3747
|
+
OPTIONS
|
|
3748
|
+
--force when signing in, replace an already-saved token.
|
|
3749
|
+
|
|
3750
|
+
Signing in saves your token on this machine. For scripts or an AI agent, set PAPIERS_TOKEN instead.`,
|
|
3751
|
+
tokens: `papiers tokens \u2014 list or revoke your API tokens.
|
|
3752
|
+
|
|
3753
|
+
USAGE
|
|
3421
3754
|
papiers tokens list [--json]
|
|
3422
3755
|
papiers tokens revoke TOKEN_ID [--json]
|
|
3423
|
-
papiers version | papiers --version | papiers -V
|
|
3424
|
-
papiers list [--kind document] [--limit 20] [--cursor CURSOR] [--filter FIELD.OP=VALUE] [--document-id doc_...|@-|@file] [--input0] [--order-by addedAt:desc|lastEngagedAt:desc] [--json|--ids|--ids0|--doc-ids|--pretty]
|
|
3425
|
-
papiers list --kind passage|highlight|conversation|equation [--document-id doc_... (highlight)] [--since ISO|Nd (highlight/conversation)] [--limit 20] [--cursor CURSOR] [--json|--ids|--ids0|--doc-ids|--pretty]
|
|
3426
|
-
papiers search QUERY [--limit 20] [--json|--ids|--ids0|--doc-ids|--pretty]
|
|
3427
|
-
papiers search QUERY --kind document [--query-in title|metadata] [--limit 20] [--filter FIELD.OP=VALUE] [--document-id doc_...|@-|@file] [--input0] [--json|--ids|--ids0|--doc-ids|--pretty]
|
|
3428
|
-
papiers search QUERY --kind passage|highlight|conversation [--query-in content] [--document-id doc_... (passage/highlight)] [--since ISO|Nd (highlight/conversation)] [--limit 20] [--json|--ids|--ids0|--doc-ids|--pretty]
|
|
3429
|
-
papiers search QUERY --kind all [--limit 20] [--json|--ids|--ids0|--doc-ids|--pretty]
|
|
3430
|
-
papiers search QUERY --kind equation [--query-in latex] [--limit 20] [--json|--ids|--ids0|--doc-ids|--pretty]
|
|
3431
|
-
papiers browse srch_... [--offset N] [--limit 20] [--json|--ids|--ids0|--doc-ids|--pretty]
|
|
3432
|
-
papiers read doc_... [doc_...] [--id doc_...|@file] [--kind document] [--format auto|metadata|markdown|plain] [--include metadata,source,locations] [--pages 1,3-5] [--max-chars-per-item N] [--input0] [--fail-fast] [--json|--pretty]
|
|
3433
|
-
papiers read doc_... --format auto|markdown|plain --cursor CURSOR [--pages 1,3-5] [--max-chars-per-item N] [--json]
|
|
3434
|
-
papiers read pas_... [pas_...] [--format markdown|plain] [--max-chars-per-item N] [--input0] [--fail-fast] [--json|--pretty]
|
|
3435
|
-
papiers read hl_... [hl_...] [--format metadata|plain|auto] [--max-chars-per-item N] [--input0] [--fail-fast] [--json|--pretty]
|
|
3436
|
-
papiers read cnv_... [cnv_...] [--format metadata|plain|auto] [--max-chars-per-item N] [--input0] [--fail-fast] [--json|--pretty]
|
|
3437
|
-
papiers read eq_... [eq_...] [--format metadata|auto] [--include metadata] [--input0] [--fail-fast] [--json|--pretty]
|
|
3438
|
-
papiers read @- [--input0] [--format auto|metadata|markdown|plain] [--include metadata,source,locations] [--pages 1,3-5] [--max-chars-per-item N] [--fail-fast] [--json]
|
|
3439
3756
|
|
|
3440
|
-
|
|
3441
|
-
papiers
|
|
3442
|
-
papiers list --kind document --limit 5 --json
|
|
3443
|
-
papiers list --kind annotations --limit 5 --pretty # your highlights with notes
|
|
3444
|
-
papiers list --kind annotations --since 30d --json # recent highlights
|
|
3445
|
-
papiers list --kind annotations --document-id doc_<id> --json # highlights on one document
|
|
3446
|
-
papiers list --kind document --filter engaged=false --limit 10 --json # unread documents
|
|
3447
|
-
papiers list --kind document --filter annotated=true --json # documents with your notes
|
|
3448
|
-
papiers list --kind document --filter lastEngagedAt.gte=30d --json # recently active documents
|
|
3449
|
-
papiers list --kind document --order-by lastEngagedAt:desc --limit 10 --json # most recently engaged first (engaged docs only)
|
|
3450
|
-
papiers search "router load balancing tradeoffs" --limit 10 --json
|
|
3451
|
-
papiers browse srch_<id> --offset 10 --json
|
|
3452
|
-
papiers search "mixture of experts" --kind passage --limit 5 --json
|
|
3453
|
-
papiers search "capacity factors" --kind passage --document-id doc_<id> --json # search within one document
|
|
3454
|
-
papiers search "evaluation harness" --kind chats --json
|
|
3455
|
-
papiers search "\\\\alpha" --kind equation --query-in latex --json
|
|
3456
|
-
papiers read doc_<id> --format markdown --max-chars-per-item 2000 --json
|
|
3457
|
-
papiers read hl_<id> --json # highlight quote + annotation
|
|
3458
|
-
papiers search retrieval --kind passage --limit 5 --ids | papiers read @- --format plain --json
|
|
3459
|
-
papiers search retrieval --doc-ids | papiers read @- --format metadata --json # resolve hits to their parent documents
|
|
3757
|
+
Create and name tokens in Papiers (Settings -> API tokens). Revoking is permanent.`,
|
|
3758
|
+
doctor: `papiers doctor \u2014 check your setup, connection, and what's available.
|
|
3460
3759
|
|
|
3461
|
-
|
|
3462
|
-
|
|
3463
|
-
Use --pretty for human-readable terminal output.
|
|
3464
|
-
Use --ids or --ids0 to pipe result IDs into another command.
|
|
3465
|
-
Use --doc-ids to pipe parent document IDs where available.
|
|
3466
|
-
Paginated responses include page.nextCursor; pass it back with --cursor.
|
|
3467
|
-
Search responses may include ranking.searchId; pass it to papiers browse.
|
|
3468
|
-
API errors use papiers.error.v1 with error.message and requestId.
|
|
3760
|
+
USAGE
|
|
3761
|
+
papiers doctor [--json]
|
|
3469
3762
|
|
|
3470
|
-
|
|
3471
|
-
|
|
3472
|
-
|
|
3763
|
+
Verifies your token, the server connection, and which features are available.
|
|
3764
|
+
Run it first when something isn't working.`,
|
|
3765
|
+
version: `papiers version \u2014 print the CLI version.
|
|
3473
3766
|
|
|
3474
|
-
|
|
3475
|
-
|
|
3476
|
-
|
|
3767
|
+
USAGE
|
|
3768
|
+
papiers version | papiers --version | papiers -V`
|
|
3769
|
+
};
|
|
3770
|
+
var REFERENCE = `REFERENCE \u2014 IDs, piping, pagination, and limits.
|
|
3477
3771
|
|
|
3478
|
-
|
|
3479
|
-
|
|
3480
|
-
|
|
3481
|
-
|
|
3482
|
-
|
|
3772
|
+
ID PREFIXES
|
|
3773
|
+
doc_ document pas_ passage hl_ highlight
|
|
3774
|
+
cnv_ conversation eq_ equation srch_ a saved search ranking (for browse)
|
|
3775
|
+
On read, the kind \u2014 and which --format/--include apply \u2014 is read from the prefix.
|
|
3776
|
+
|
|
3777
|
+
PIPING IDS BETWEEN COMMANDS
|
|
3778
|
+
--ids result IDs, one per line, with their native prefix
|
|
3779
|
+
--ids0 the same IDs, NUL-separated (for \`xargs -0\`)
|
|
3780
|
+
--doc-ids parent document IDs only (doc_\u2026), deduped; conversation hits are skipped
|
|
3781
|
+
@- read IDs from stdin @file read IDs from a file
|
|
3782
|
+
--input0 read piped IDs NUL-separated instead of whitespace/newlines
|
|
3783
|
+
@- and @file accept plain IDs or a Papiers JSON envelope, and may be mixed with literal IDs.
|
|
3784
|
+
|
|
3785
|
+
PAGINATION \u2014 three separate mechanisms
|
|
3786
|
+
list response has page.nextCursor \u2192 papiers list \u2026 --cursor CURSOR
|
|
3787
|
+
search response has ranking.searchId \u2192 papiers browse srch_\u2026 --offset N
|
|
3788
|
+
read a truncated item has items[].nextCursor \u2192 papiers read doc_\u2026 --cursor CURSOR
|
|
3789
|
+
|
|
3790
|
+
LIMITS
|
|
3791
|
+
--limit 1\u201350 \xB7 --max-chars-per-item 1\u2013200000 \xB7 up to 25 filters \xB7 up to 100 IDs per request
|
|
3792
|
+
|
|
3793
|
+
FILTER FIELDS \u2014 document kind, as FIELD.OP=VALUE (or FIELD=VALUE for equality)
|
|
3794
|
+
id title author venue doi arxivId pmid
|
|
3795
|
+
publishedDate publishedYear sourceFamily sourceDomain
|
|
3796
|
+
annotated engaged lastEngagedAt
|
|
3797
|
+
Operators: eq \xB7 in \xB7 contains \xB7 prefix \xB7 gte \xB7 gt \xB7 lte \xB7 lt \xB7 between (which apply depends on the field).`;
|
|
3798
|
+
var HELP_PAGES = {
|
|
3799
|
+
...HELP_TOPICS,
|
|
3800
|
+
reference: REFERENCE
|
|
3801
|
+
};
|
|
3802
|
+
var HELP_TOPIC_NAMES = Object.keys(HELP_PAGES);
|
|
3803
|
+
var HELP_COMMAND_NAMES = Object.keys(HELP_TOPICS);
|
|
3804
|
+
var HELP_TEXT = [GLOBAL_HELP, ...Object.values(HELP_PAGES)].join(
|
|
3805
|
+
"\n\n\n"
|
|
3806
|
+
);
|
|
3807
|
+
function colorizeHelp(text) {
|
|
3808
|
+
return text.replace(/^([A-Z][A-Z ]{2,})$/gm, "\x1B[1;36m$1\x1B[0m").replace(
|
|
3809
|
+
/(^|[\s([|/])(--[a-z0-9-]+|-[A-Za-z])\b/g,
|
|
3810
|
+
"$1\x1B[33m$2\x1B[0m"
|
|
3811
|
+
);
|
|
3812
|
+
}
|
|
3813
|
+
function renderHelp(command, style) {
|
|
3814
|
+
const help = command.type === "help" ? command : void 0;
|
|
3815
|
+
let body = GLOBAL_HELP;
|
|
3816
|
+
if (help?.all) {
|
|
3817
|
+
body = HELP_TEXT;
|
|
3818
|
+
} else if (help?.topic) {
|
|
3819
|
+
body = HELP_PAGES[help.topic] ?? GLOBAL_HELP;
|
|
3820
|
+
}
|
|
3821
|
+
return style ? colorizeHelp(body) : body;
|
|
3822
|
+
}
|
|
3823
|
+
var SUGGESTIBLE_COMMANDS = [
|
|
3824
|
+
"auth",
|
|
3825
|
+
"doctor",
|
|
3826
|
+
"capabilities",
|
|
3827
|
+
"tokens",
|
|
3828
|
+
"list",
|
|
3829
|
+
"search",
|
|
3830
|
+
"browse",
|
|
3831
|
+
"read",
|
|
3832
|
+
"version",
|
|
3833
|
+
"help"
|
|
3834
|
+
];
|
|
3835
|
+
function levenshtein(a, b) {
|
|
3836
|
+
const rows = a.length + 1;
|
|
3837
|
+
const cols = b.length + 1;
|
|
3838
|
+
const dist = Array.from(
|
|
3839
|
+
{ length: rows },
|
|
3840
|
+
() => new Array(cols).fill(0)
|
|
3841
|
+
);
|
|
3842
|
+
for (let i = 0; i < rows; i += 1) dist[i][0] = i;
|
|
3843
|
+
for (let j = 0; j < cols; j += 1) dist[0][j] = j;
|
|
3844
|
+
for (let i = 1; i < rows; i += 1) {
|
|
3845
|
+
for (let j = 1; j < cols; j += 1) {
|
|
3846
|
+
const cost = a[i - 1] === b[j - 1] ? 0 : 1;
|
|
3847
|
+
dist[i][j] = Math.min(
|
|
3848
|
+
dist[i - 1][j] + 1,
|
|
3849
|
+
dist[i][j - 1] + 1,
|
|
3850
|
+
dist[i - 1][j - 1] + cost
|
|
3851
|
+
);
|
|
3852
|
+
}
|
|
3853
|
+
}
|
|
3854
|
+
return dist[rows - 1][cols - 1];
|
|
3855
|
+
}
|
|
3856
|
+
function suggestCommand(input) {
|
|
3857
|
+
let best = null;
|
|
3858
|
+
let bestDistance = Number.POSITIVE_INFINITY;
|
|
3859
|
+
for (const candidate of SUGGESTIBLE_COMMANDS) {
|
|
3860
|
+
const distance = levenshtein(input, candidate);
|
|
3861
|
+
if (distance < bestDistance) {
|
|
3862
|
+
bestDistance = distance;
|
|
3863
|
+
best = candidate;
|
|
3864
|
+
}
|
|
3865
|
+
}
|
|
3866
|
+
return best !== null && bestDistance <= 2 ? best : null;
|
|
3867
|
+
}
|
|
3868
|
+
function unknownCommandMessage(command) {
|
|
3869
|
+
const suggestion = suggestCommand(command);
|
|
3870
|
+
const guess = suggestion ? ` Did you mean "${suggestion}"?` : "";
|
|
3871
|
+
return `Unknown papiers command.${guess} Run papiers --help to see commands.`;
|
|
3872
|
+
}
|
|
3483
3873
|
function parseCliArgs(argv) {
|
|
3484
3874
|
const parsed = parseRawArgv(argv);
|
|
3485
3875
|
const global = parseGlobalOptions(parsed);
|
|
3486
3876
|
if (parsed.booleanFlags.has("version") && !parsed.help) {
|
|
3487
3877
|
return { type: "version", ...global };
|
|
3488
3878
|
}
|
|
3489
|
-
|
|
3879
|
+
const [command, ...rest] = parsed.positionals;
|
|
3880
|
+
if (parsed.help || command === "help" || parsed.positionals.length === 0) {
|
|
3881
|
+
if (parsed.booleanFlags.has("all")) {
|
|
3882
|
+
return { type: "help", all: true, ...global };
|
|
3883
|
+
}
|
|
3884
|
+
const topic = command === "help" ? rest[0] : command;
|
|
3885
|
+
if (topic && HELP_TOPIC_NAMES.includes(topic)) {
|
|
3886
|
+
return { type: "help", topic, ...global };
|
|
3887
|
+
}
|
|
3490
3888
|
return { type: "help", ...global };
|
|
3491
3889
|
}
|
|
3492
|
-
const [command, ...rest] = parsed.positionals;
|
|
3493
3890
|
switch (command) {
|
|
3494
|
-
case "help":
|
|
3495
|
-
case "--help":
|
|
3496
|
-
return { type: "help", ...global };
|
|
3497
3891
|
case "version":
|
|
3498
3892
|
assertNoExtraPositionals(command, rest);
|
|
3499
3893
|
return { type: "version", ...global };
|
|
@@ -3527,7 +3921,7 @@ function parseCliArgs(argv) {
|
|
|
3527
3921
|
type: "list",
|
|
3528
3922
|
...global,
|
|
3529
3923
|
idsOnly: listOutput.idsOnly,
|
|
3530
|
-
...parsePrettyOutput(parsed, listOutput.
|
|
3924
|
+
...parsePrettyOutput(parsed, listOutput.anyIdsOutput) ? { pretty: true } : {},
|
|
3531
3925
|
...listOutput.idsNulDelimited ? { idsNulDelimited: true } : {},
|
|
3532
3926
|
...listOutput.docIdsOnly ? { docIdsOnly: true } : {},
|
|
3533
3927
|
...parsed.booleanFlags.has("input0") ? { inputNulDelimited: true } : {},
|
|
@@ -3537,16 +3931,23 @@ function parseCliArgs(argv) {
|
|
|
3537
3931
|
}
|
|
3538
3932
|
case "search": {
|
|
3539
3933
|
assertAllowedFlags(parsed, SEARCH_VALUE_FLAGS, "search");
|
|
3540
|
-
assertAllowedBooleanFlags(
|
|
3934
|
+
assertAllowedBooleanFlags(
|
|
3935
|
+
parsed,
|
|
3936
|
+
SEARCH_IDS_PIPELINE_BOOLEAN_FLAGS,
|
|
3937
|
+
"search"
|
|
3938
|
+
);
|
|
3541
3939
|
const searchDocumentIds = parseDocumentIdFlagValues(parsed, "search");
|
|
3542
3940
|
const searchOutput = parseIdsOutput(parsed, "search");
|
|
3543
3941
|
return {
|
|
3544
3942
|
type: "search",
|
|
3545
3943
|
...global,
|
|
3546
3944
|
idsOnly: searchOutput.idsOnly,
|
|
3547
|
-
...parsePrettyOutput(parsed, searchOutput.
|
|
3945
|
+
...parsePrettyOutput(parsed, searchOutput.anyIdsOutput) ? { pretty: true } : {},
|
|
3548
3946
|
...searchOutput.idsNulDelimited ? { idsNulDelimited: true } : {},
|
|
3549
3947
|
...searchOutput.docIdsOnly ? { docIdsOnly: true } : {},
|
|
3948
|
+
...searchOutput.passageIdsOnly ? { passageIdsOnly: true } : {},
|
|
3949
|
+
...searchOutput.highlightIdsOnly ? { highlightIdsOnly: true } : {},
|
|
3950
|
+
...searchOutput.evidenceIdsOnly ? { evidenceIdsOnly: true } : {},
|
|
3550
3951
|
...parsed.booleanFlags.has("input0") ? { inputNulDelimited: true } : {},
|
|
3551
3952
|
...searchDocumentIds ? { documentIds: searchDocumentIds } : {},
|
|
3552
3953
|
request: buildSearchRequest(rest, parsed, searchDocumentIds)
|
|
@@ -3554,7 +3955,11 @@ function parseCliArgs(argv) {
|
|
|
3554
3955
|
}
|
|
3555
3956
|
case "browse": {
|
|
3556
3957
|
assertAllowedFlags(parsed, BROWSE_VALUE_FLAGS, "browse");
|
|
3557
|
-
assertAllowedBooleanFlags(
|
|
3958
|
+
assertAllowedBooleanFlags(
|
|
3959
|
+
parsed,
|
|
3960
|
+
SEARCH_IDS_PIPELINE_BOOLEAN_FLAGS,
|
|
3961
|
+
"browse"
|
|
3962
|
+
);
|
|
3558
3963
|
if (parsed.booleanFlags.has("input0")) {
|
|
3559
3964
|
throw new CliUsageError("--input0 is not supported for browse.");
|
|
3560
3965
|
}
|
|
@@ -3563,9 +3968,12 @@ function parseCliArgs(argv) {
|
|
|
3563
3968
|
type: "browse",
|
|
3564
3969
|
...global,
|
|
3565
3970
|
idsOnly: browseOutput.idsOnly,
|
|
3566
|
-
...parsePrettyOutput(parsed, browseOutput.
|
|
3971
|
+
...parsePrettyOutput(parsed, browseOutput.anyIdsOutput) ? { pretty: true } : {},
|
|
3567
3972
|
...browseOutput.idsNulDelimited ? { idsNulDelimited: true } : {},
|
|
3568
3973
|
...browseOutput.docIdsOnly ? { docIdsOnly: true } : {},
|
|
3974
|
+
...browseOutput.passageIdsOnly ? { passageIdsOnly: true } : {},
|
|
3975
|
+
...browseOutput.highlightIdsOnly ? { highlightIdsOnly: true } : {},
|
|
3976
|
+
...browseOutput.evidenceIdsOnly ? { evidenceIdsOnly: true } : {},
|
|
3569
3977
|
request: buildBrowseRequest(rest, parsed)
|
|
3570
3978
|
};
|
|
3571
3979
|
}
|
|
@@ -3584,7 +3992,7 @@ function parseCliArgs(argv) {
|
|
|
3584
3992
|
};
|
|
3585
3993
|
}
|
|
3586
3994
|
default:
|
|
3587
|
-
throw new CliUsageError(
|
|
3995
|
+
throw new CliUsageError(unknownCommandMessage(command));
|
|
3588
3996
|
}
|
|
3589
3997
|
}
|
|
3590
3998
|
function argvWantsJson(argv) {
|
|
@@ -3594,9 +4002,9 @@ function parsePrettyOutput(parsed, idsOnly) {
|
|
|
3594
4002
|
if (!parsed.booleanFlags.has("pretty")) {
|
|
3595
4003
|
return false;
|
|
3596
4004
|
}
|
|
3597
|
-
if (idsOnly || parsed.json
|
|
4005
|
+
if (idsOnly || parsed.json) {
|
|
3598
4006
|
throw new CliUsageError(
|
|
3599
|
-
"--pretty cannot be combined with --json
|
|
4007
|
+
"--pretty cannot be combined with --json or ID projection flags."
|
|
3600
4008
|
);
|
|
3601
4009
|
}
|
|
3602
4010
|
return true;
|
|
@@ -3636,12 +4044,6 @@ function parseAuthCommand(rest, parsed, global) {
|
|
|
3636
4044
|
case "login": {
|
|
3637
4045
|
assertAllowedBooleanFlags(parsed, AUTH_LOGIN_BOOLEAN_FLAGS, "auth login");
|
|
3638
4046
|
assertNoExtraPositionals("auth login", extra);
|
|
3639
|
-
const patStdinFlagCount = Number(parsed.booleanFlags.has("token-stdin")) + Number(parsed.booleanFlags.has("stdin"));
|
|
3640
|
-
if (patStdinFlagCount !== 1) {
|
|
3641
|
-
throw new CliUsageError(
|
|
3642
|
-
"papiers auth login requires exactly one of --token-stdin or --stdin."
|
|
3643
|
-
);
|
|
3644
|
-
}
|
|
3645
4047
|
return {
|
|
3646
4048
|
type: "auth-login",
|
|
3647
4049
|
...global,
|
|
@@ -3792,104 +4194,65 @@ function buildSearchRequest(positionals, parsed, documentIds) {
|
|
|
3792
4194
|
"Ranked public search cursors are not available yet."
|
|
3793
4195
|
);
|
|
3794
4196
|
}
|
|
3795
|
-
if (
|
|
3796
|
-
return buildMultiKindSearchRequest(parsed, query, documentIds);
|
|
3797
|
-
}
|
|
3798
|
-
if (!parsed.flags.has("kind")) {
|
|
3799
|
-
const defaulted = buildDefaultKindSearchRequest(parsed, query, documentIds);
|
|
3800
|
-
if (defaulted) {
|
|
3801
|
-
return defaulted;
|
|
3802
|
-
}
|
|
3803
|
-
}
|
|
3804
|
-
const kind = parseListSearchKind(parsed, "search");
|
|
3805
|
-
const since = parseSinceFlag(parsed, kind, "search");
|
|
3806
|
-
if (kind !== "document") {
|
|
3807
|
-
if (documentIds?.length && kind !== "highlight" && kind !== "passage") {
|
|
3808
|
-
throw new CliUsageError(
|
|
3809
|
-
"papiers search --document-id is supported only with --kind document, passage, or highlight."
|
|
3810
|
-
);
|
|
3811
|
-
}
|
|
3812
|
-
assertNoNonDocumentListSearchFlag(parsed, "filter", "search", kind);
|
|
3813
|
-
return pruneUndefined({
|
|
3814
|
-
schemaVersion: PAPIERS_SCHEMA_VERSIONS.searchRequest,
|
|
3815
|
-
query,
|
|
3816
|
-
kinds: [kind],
|
|
3817
|
-
queryIn: parseSearchQueryIn(parsed, kind),
|
|
3818
|
-
documentIds: documentIds?.length ? documentIds : void 0,
|
|
3819
|
-
since,
|
|
3820
|
-
limit: parseLimit(parsed)
|
|
3821
|
-
});
|
|
3822
|
-
}
|
|
3823
|
-
const filters = parsed.flags.get("filter")?.map((filter) => parseDocumentFilterExpression(filter));
|
|
3824
|
-
assertFilterCount(filters, "search", documentIds ? 1 : 0);
|
|
3825
|
-
return pruneUndefined({
|
|
3826
|
-
schemaVersion: PAPIERS_SCHEMA_VERSIONS.searchRequest,
|
|
3827
|
-
query,
|
|
3828
|
-
kinds: ["document"],
|
|
3829
|
-
queryIn: parseSearchQueryIn(parsed, kind),
|
|
3830
|
-
filters,
|
|
3831
|
-
limit: parseLimit(parsed)
|
|
3832
|
-
});
|
|
3833
|
-
}
|
|
3834
|
-
function isMultiSearchKindFlag(parsed) {
|
|
3835
|
-
return singleFlagValue(parsed, "kind")?.trim().toLowerCase() === "all";
|
|
3836
|
-
}
|
|
3837
|
-
function buildDefaultKindSearchRequest(parsed, query, documentIds) {
|
|
3838
|
-
const queryIn = singleFlagValue(parsed, "query-in");
|
|
3839
|
-
if (parsed.flags.has("filter") || documentIds?.length || queryIn === "title" || queryIn === "metadata") {
|
|
3840
|
-
return null;
|
|
3841
|
-
}
|
|
3842
|
-
if (parsed.flags.has("since")) {
|
|
4197
|
+
if (parsed.flags.has("query-in")) {
|
|
3843
4198
|
throw new CliUsageError(
|
|
3844
|
-
"papiers search --
|
|
4199
|
+
"papiers search no longer supports --query-in; use free-text query plus --filter FIELD.OP=VALUE for structured attributes."
|
|
3845
4200
|
);
|
|
3846
4201
|
}
|
|
3847
|
-
if (
|
|
3848
|
-
throw new CliUsageError(
|
|
3849
|
-
"papiers search --query-in latex requires --kind equation."
|
|
3850
|
-
);
|
|
3851
|
-
}
|
|
3852
|
-
if (queryIn !== void 0 && queryIn !== "content") {
|
|
4202
|
+
if (parsed.flags.has("since")) {
|
|
3853
4203
|
throw new CliUsageError(
|
|
3854
|
-
"papiers search supports --
|
|
4204
|
+
"papiers search no longer supports --since; use --filter lastEngagedAt.gte=<when> for document recency."
|
|
3855
4205
|
);
|
|
3856
4206
|
}
|
|
4207
|
+
const kinds = parseSearchKindScopes(parsed);
|
|
4208
|
+
const filters = parsed.flags.get("filter")?.map((filter) => parseDocumentFilterExpression(filter));
|
|
4209
|
+
assertFilterCount(filters, "search");
|
|
3857
4210
|
return pruneUndefined({
|
|
3858
4211
|
schemaVersion: PAPIERS_SCHEMA_VERSIONS.searchRequest,
|
|
3859
4212
|
query,
|
|
3860
|
-
|
|
4213
|
+
kinds,
|
|
4214
|
+
filters,
|
|
3861
4215
|
limit: parseLimit(parsed)
|
|
3862
4216
|
});
|
|
3863
4217
|
}
|
|
3864
|
-
function
|
|
3865
|
-
|
|
3866
|
-
|
|
3867
|
-
|
|
3868
|
-
);
|
|
4218
|
+
function parseSearchKindScopes(parsed) {
|
|
4219
|
+
const rawKinds = parsed.flags.get("kind")?.flatMap(splitCommaSeparatedValues);
|
|
4220
|
+
if (rawKinds === void 0) {
|
|
4221
|
+
return void 0;
|
|
3869
4222
|
}
|
|
3870
|
-
if (
|
|
3871
|
-
throw new CliUsageError(
|
|
3872
|
-
"papiers search --since is not supported with --kind all; use --kind highlight or conversation."
|
|
3873
|
-
);
|
|
4223
|
+
if (rawKinds.length === 0) {
|
|
4224
|
+
throw new CliUsageError("papiers search --kind requires a value.");
|
|
3874
4225
|
}
|
|
3875
|
-
|
|
3876
|
-
|
|
3877
|
-
|
|
3878
|
-
|
|
4226
|
+
const sawAll = rawKinds.some((kind) => kind.trim().toLowerCase() === "all");
|
|
4227
|
+
if (sawAll) {
|
|
4228
|
+
if (rawKinds.length > 1) {
|
|
4229
|
+
throw new CliUsageError(
|
|
4230
|
+
"papiers search --kind all cannot be combined with other --kind values."
|
|
4231
|
+
);
|
|
4232
|
+
}
|
|
4233
|
+
return void 0;
|
|
3879
4234
|
}
|
|
3880
|
-
const
|
|
3881
|
-
|
|
3882
|
-
|
|
3883
|
-
|
|
3884
|
-
|
|
4235
|
+
const kinds = [];
|
|
4236
|
+
for (const rawKind of rawKinds) {
|
|
4237
|
+
const kind = normalizeCliPublicKind(rawKind);
|
|
4238
|
+
if (!kind) {
|
|
4239
|
+
throw new CliUsageError(
|
|
4240
|
+
`papiers search supports --kind passage, highlight, conversation, or equation; received "${rawKind}".${didYouMeanKind(rawKind)}`
|
|
4241
|
+
);
|
|
4242
|
+
}
|
|
4243
|
+
if (kind === "document") {
|
|
4244
|
+
throw new CliUsageError(
|
|
4245
|
+
"papiers search no longer supports --kind document; omit --kind to search matching titles and content."
|
|
4246
|
+
);
|
|
4247
|
+
}
|
|
4248
|
+
if (!MULTI_SEARCH_KINDS.includes(kind)) {
|
|
4249
|
+
throw new CliUsageError(
|
|
4250
|
+
`papiers search supports --kind passage, highlight, conversation, or equation; received "${rawKind}".`
|
|
4251
|
+
);
|
|
4252
|
+
}
|
|
4253
|
+
kinds.push(kind);
|
|
3885
4254
|
}
|
|
3886
|
-
return
|
|
3887
|
-
schemaVersion: PAPIERS_SCHEMA_VERSIONS.searchRequest,
|
|
3888
|
-
query,
|
|
3889
|
-
kinds: [...MULTI_SEARCH_KINDS],
|
|
3890
|
-
queryIn: "content",
|
|
3891
|
-
limit: parseLimit(parsed)
|
|
3892
|
-
});
|
|
4255
|
+
return [...new Set(kinds)];
|
|
3893
4256
|
}
|
|
3894
4257
|
function parseSinceFlag(parsed, kind, command) {
|
|
3895
4258
|
const value = singleFlagValue(parsed, "since");
|
|
@@ -3964,7 +4327,7 @@ function parseReadKind(parsed) {
|
|
|
3964
4327
|
return normalized;
|
|
3965
4328
|
}
|
|
3966
4329
|
throw new CliUsageError(
|
|
3967
|
-
`Public CLI read currently supports --kind document, passage, highlight, conversation, or equation only; received "${kind}"
|
|
4330
|
+
`Public CLI read currently supports --kind document, passage, highlight, conversation, or equation only; received "${kind}".${didYouMeanKind(kind)}`
|
|
3968
4331
|
);
|
|
3969
4332
|
}
|
|
3970
4333
|
function readKindsForLiteralIds(ids) {
|
|
@@ -4023,13 +4386,25 @@ function parseIdsOutput(parsed, command) {
|
|
|
4023
4386
|
const idsOnly = parsed.booleanFlags.has("ids");
|
|
4024
4387
|
const idsNulDelimited = parsed.booleanFlags.has("ids0");
|
|
4025
4388
|
const docIdsOnly = parsed.booleanFlags.has("doc-ids");
|
|
4026
|
-
const
|
|
4389
|
+
const passageIdsOnly = parsed.booleanFlags.has("passage-ids");
|
|
4390
|
+
const highlightIdsOnly = parsed.booleanFlags.has("highlight-ids");
|
|
4391
|
+
const evidenceIdsOnly = parsed.booleanFlags.has("evidence-ids");
|
|
4392
|
+
const selectedCount = Number(idsOnly) + Number(idsNulDelimited) + Number(docIdsOnly) + Number(passageIdsOnly) + Number(highlightIdsOnly) + Number(evidenceIdsOnly) + Number(parsed.json);
|
|
4027
4393
|
if (selectedCount > 1) {
|
|
4028
4394
|
throw new CliUsageError(
|
|
4029
|
-
`Use only one of --ids, --ids0, --doc-ids, or --json for papiers ${command}.`
|
|
4395
|
+
`Use only one of --ids, --ids0, --doc-ids, --passage-ids, --highlight-ids, --evidence-ids, or --json for papiers ${command}.`
|
|
4030
4396
|
);
|
|
4031
4397
|
}
|
|
4032
|
-
|
|
4398
|
+
const normalizedIdsOnly = idsOnly || idsNulDelimited;
|
|
4399
|
+
return {
|
|
4400
|
+
idsOnly: normalizedIdsOnly,
|
|
4401
|
+
idsNulDelimited,
|
|
4402
|
+
docIdsOnly,
|
|
4403
|
+
passageIdsOnly,
|
|
4404
|
+
highlightIdsOnly,
|
|
4405
|
+
evidenceIdsOnly,
|
|
4406
|
+
anyIdsOutput: normalizedIdsOnly || docIdsOnly || passageIdsOnly || highlightIdsOnly || evidenceIdsOnly
|
|
4407
|
+
};
|
|
4033
4408
|
}
|
|
4034
4409
|
function parseReadInclude(parsed) {
|
|
4035
4410
|
const rawIncludes = parsed.flags.get("include")?.flatMap(splitCommaSeparatedValues);
|
|
@@ -4190,7 +4565,8 @@ function parseRawArgv(argv) {
|
|
|
4190
4565
|
continue;
|
|
4191
4566
|
}
|
|
4192
4567
|
if (!VALUE_FLAGS.has(name)) {
|
|
4193
|
-
|
|
4568
|
+
const hint = REMOVED_FLAG_HINTS[name] ?? "Run papiers --help to see options.";
|
|
4569
|
+
throw new CliUsageError(`Unknown option --${name}. ${hint}`);
|
|
4194
4570
|
}
|
|
4195
4571
|
const flagValue = value ?? argv[index + 1];
|
|
4196
4572
|
if (flagValue === void 0 || flagValue.startsWith("--")) {
|
|
@@ -4221,14 +4597,9 @@ function splitLongFlag(arg) {
|
|
|
4221
4597
|
};
|
|
4222
4598
|
}
|
|
4223
4599
|
function parseGlobalOptions(parsed) {
|
|
4224
|
-
const apiBaseUrl = singleFlagValue(parsed, "api-base-url");
|
|
4225
|
-
const apiUrlAlias = singleFlagValue(parsed, "api-url");
|
|
4226
|
-
if (apiBaseUrl && apiUrlAlias) {
|
|
4227
|
-
throw new CliUsageError("Use only one of --api-base-url or --api-url.");
|
|
4228
|
-
}
|
|
4229
4600
|
return {
|
|
4230
4601
|
json: parsed.json,
|
|
4231
|
-
apiBaseUrl:
|
|
4602
|
+
apiBaseUrl: singleFlagValue(parsed, "api-url")
|
|
4232
4603
|
};
|
|
4233
4604
|
}
|
|
4234
4605
|
function parseListSearchKind(parsed, command) {
|
|
@@ -4243,11 +4614,16 @@ function parseListSearchKind(parsed, command) {
|
|
|
4243
4614
|
);
|
|
4244
4615
|
}
|
|
4245
4616
|
throw new CliUsageError(
|
|
4246
|
-
`papiers ${command} supports --kind document, passage, highlight, conversation, or equation; received "${kind}"
|
|
4617
|
+
`papiers ${command} supports --kind document, passage, highlight, conversation, or equation; received "${kind}".${didYouMeanKind(kind)}`
|
|
4247
4618
|
);
|
|
4248
4619
|
}
|
|
4249
4620
|
function normalizeCliPublicKind(value) {
|
|
4250
|
-
|
|
4621
|
+
const normalized = value.trim().toLowerCase();
|
|
4622
|
+
return PUBLIC_KINDS.includes(normalized) ? normalized : null;
|
|
4623
|
+
}
|
|
4624
|
+
function didYouMeanKind(value) {
|
|
4625
|
+
const suggestion = FORMER_KIND_ALIASES.get(value.trim().toLowerCase());
|
|
4626
|
+
return suggestion ? ` Did you mean "${suggestion}"?` : "";
|
|
4251
4627
|
}
|
|
4252
4628
|
function assertNoNonDocumentListSearchFlag(parsed, flag, command, kind) {
|
|
4253
4629
|
if (parsed.flags.has(flag)) {
|
|
@@ -4300,34 +4676,6 @@ function parseLimit(parsed) {
|
|
|
4300
4676
|
}
|
|
4301
4677
|
return limit;
|
|
4302
4678
|
}
|
|
4303
|
-
function parseSearchQueryIn(parsed, kind) {
|
|
4304
|
-
const queryIn = singleFlagValue(parsed, "query-in");
|
|
4305
|
-
if (kind === "document") {
|
|
4306
|
-
if (queryIn === void 0) {
|
|
4307
|
-
return void 0;
|
|
4308
|
-
}
|
|
4309
|
-
if (EXPECTED_DOCUMENT_QUERY_IN.some((supported2) => supported2 === queryIn)) {
|
|
4310
|
-
return queryIn;
|
|
4311
|
-
}
|
|
4312
|
-
throw new CliUsageError(
|
|
4313
|
-
"Public document search supports --query-in title or --query-in metadata."
|
|
4314
|
-
);
|
|
4315
|
-
}
|
|
4316
|
-
const defaultsByKind = {
|
|
4317
|
-
passage: EXPECTED_CONTENT_QUERY_IN[0],
|
|
4318
|
-
highlight: EXPECTED_CONTENT_QUERY_IN[0],
|
|
4319
|
-
conversation: EXPECTED_CONTENT_QUERY_IN[0],
|
|
4320
|
-
equation: EXPECTED_EQUATION_QUERY_IN[0]
|
|
4321
|
-
};
|
|
4322
|
-
const resolved = queryIn ?? defaultsByKind[kind];
|
|
4323
|
-
const supported = kind === "equation" ? EXPECTED_EQUATION_QUERY_IN : EXPECTED_CONTENT_QUERY_IN;
|
|
4324
|
-
if (supported.some((value) => value === resolved)) {
|
|
4325
|
-
return resolved;
|
|
4326
|
-
}
|
|
4327
|
-
throw new CliUsageError(
|
|
4328
|
-
kind === "equation" ? "Public equation search supports --query-in latex only." : `Public ${kind} search supports --query-in content only.`
|
|
4329
|
-
);
|
|
4330
|
-
}
|
|
4331
4679
|
function assertFilterCount(filters, command, reservedFilterCount = 0) {
|
|
4332
4680
|
const totalFilterCount = (filters?.length ?? 0) + reservedFilterCount;
|
|
4333
4681
|
if (totalFilterCount > DOCUMENT_MAX_FILTERS) {
|
|
@@ -4511,26 +4859,7 @@ function assertSupportedDocumentCapabilities(value) {
|
|
|
4511
4859
|
assertSupportedSearchResultsBrowse(capabilities.searchResultsBrowse);
|
|
4512
4860
|
const queryIn = assertRecord2("capabilities queryIn", capabilities.queryIn);
|
|
4513
4861
|
assertRecordKeysSubset("capabilities queryIn", queryIn, PUBLIC_KINDS);
|
|
4514
|
-
|
|
4515
|
-
document: EXPECTED_DOCUMENT_QUERY_IN
|
|
4516
|
-
};
|
|
4517
|
-
if (searchKinds.includes("passage")) {
|
|
4518
|
-
expectedQueryInByKind.passage = EXPECTED_CONTENT_QUERY_IN;
|
|
4519
|
-
}
|
|
4520
|
-
if (searchKinds.includes("highlight")) {
|
|
4521
|
-
expectedQueryInByKind.highlight = EXPECTED_CONTENT_QUERY_IN;
|
|
4522
|
-
}
|
|
4523
|
-
if (searchKinds.includes("conversation")) {
|
|
4524
|
-
expectedQueryInByKind.conversation = EXPECTED_CONTENT_QUERY_IN;
|
|
4525
|
-
}
|
|
4526
|
-
if (searchKinds.includes("equation")) {
|
|
4527
|
-
expectedQueryInByKind.equation = EXPECTED_EQUATION_QUERY_IN;
|
|
4528
|
-
}
|
|
4529
|
-
assertPublicKindStringArrayRecord(
|
|
4530
|
-
"capabilities queryIn",
|
|
4531
|
-
queryIn,
|
|
4532
|
-
expectedQueryInByKind
|
|
4533
|
-
);
|
|
4862
|
+
assertPublicKindStringArrayRecord("capabilities queryIn", queryIn, {});
|
|
4534
4863
|
const readFormats = assertStringArray(
|
|
4535
4864
|
"capabilities readFormats",
|
|
4536
4865
|
capabilities.readFormats
|
|
@@ -4619,7 +4948,11 @@ function assertSupportedDocumentCapabilities(value) {
|
|
|
4619
4948
|
`capabilities filters.${kind}`,
|
|
4620
4949
|
filters[kind]
|
|
4621
4950
|
);
|
|
4622
|
-
assertSameStringSet(
|
|
4951
|
+
assertSameStringSet(
|
|
4952
|
+
`capabilities filters.${kind}`,
|
|
4953
|
+
actualFilters,
|
|
4954
|
+
kind === "conversation" ? EXPECTED_CONVERSATION_FILTERS : []
|
|
4955
|
+
);
|
|
4623
4956
|
}
|
|
4624
4957
|
const operatorsByField = assertRecord2(
|
|
4625
4958
|
"capabilities operatorsByField",
|
|
@@ -4723,12 +5056,9 @@ function assertPublicKindStringArrayRecord(label, record, expectedByKind) {
|
|
|
4723
5056
|
}
|
|
4724
5057
|
}
|
|
4725
5058
|
function assertSupportedSearchKinds(searchKinds) {
|
|
4726
|
-
if (!searchKinds.includes("document")) {
|
|
4727
|
-
throw new Error("capabilities searchKinds did not include document.");
|
|
4728
|
-
}
|
|
4729
5059
|
const seen = /* @__PURE__ */ new Set();
|
|
4730
5060
|
for (const kind of searchKinds) {
|
|
4731
|
-
if (seen.has(kind) || !PUBLIC_KINDS.includes(kind)) {
|
|
5061
|
+
if (seen.has(kind) || kind === "document" || !PUBLIC_KINDS.includes(kind)) {
|
|
4732
5062
|
throw new Error(
|
|
4733
5063
|
`capabilities searchKinds advertised unsupported kind: ${kind}.`
|
|
4734
5064
|
);
|
|
@@ -4950,9 +5280,16 @@ function isPublicNotReadyReason(reason, reasons) {
|
|
|
4950
5280
|
}
|
|
4951
5281
|
|
|
4952
5282
|
// src/pretty.ts
|
|
5283
|
+
function warningLines(warnings) {
|
|
5284
|
+
if (!warnings?.length) {
|
|
5285
|
+
return [];
|
|
5286
|
+
}
|
|
5287
|
+
return warnings.map((warning) => warning.message?.trim()).filter((message) => Boolean(message)).map((message) => `! ${message}`);
|
|
5288
|
+
}
|
|
4953
5289
|
function renderPrettyPageOutput(response) {
|
|
4954
5290
|
const lines = [];
|
|
4955
|
-
|
|
5291
|
+
const entries = response.results ?? response.items ?? [];
|
|
5292
|
+
for (const item of entries) {
|
|
4956
5293
|
const rank = item.rank !== void 0 ? `${item.rank}. ` : "";
|
|
4957
5294
|
const title = item.title?.trim() ? ` ${item.title.trim()}` : "";
|
|
4958
5295
|
lines.push(`${rank}${item.id} [${item.kind}]${title}`);
|
|
@@ -4960,21 +5297,36 @@ function renderPrettyPageOutput(response) {
|
|
|
4960
5297
|
if (excerpt?.trim()) {
|
|
4961
5298
|
lines.push(` ${excerpt.trim()}`);
|
|
4962
5299
|
}
|
|
5300
|
+
if (item.evidence?.length) {
|
|
5301
|
+
for (const evidence of item.evidence) {
|
|
5302
|
+
const evidenceRank = evidence.rank !== void 0 ? `${evidence.rank}. ` : "";
|
|
5303
|
+
lines.push(` - ${evidenceRank}${evidence.id} [${evidence.kind}]`);
|
|
5304
|
+
if (evidence.snippet?.trim()) {
|
|
5305
|
+
lines.push(` ${evidence.snippet.trim()}`);
|
|
5306
|
+
}
|
|
5307
|
+
}
|
|
5308
|
+
if (typeof item.evidenceTotal === "number" && item.evidenceTotal > item.evidence.length) {
|
|
5309
|
+
lines.push(
|
|
5310
|
+
` + ${item.evidenceTotal - item.evidence.length} more evidence item${item.evidenceTotal - item.evidence.length === 1 ? "" : "s"}`
|
|
5311
|
+
);
|
|
5312
|
+
}
|
|
5313
|
+
}
|
|
4963
5314
|
}
|
|
4964
5315
|
if (lines.length === 0) {
|
|
4965
5316
|
lines.push("(no items)");
|
|
4966
5317
|
}
|
|
4967
|
-
const itemCount =
|
|
5318
|
+
const itemCount = entries.length;
|
|
4968
5319
|
lines.push(
|
|
4969
5320
|
`(${itemCount} item${itemCount === 1 ? "" : "s"}; ${pagingSummary(response)})`
|
|
4970
5321
|
);
|
|
5322
|
+
lines.push(...warningLines(response.warnings));
|
|
4971
5323
|
return `${lines.join("\n")}
|
|
4972
5324
|
`;
|
|
4973
5325
|
}
|
|
4974
5326
|
function pagingSummary(response) {
|
|
4975
5327
|
const ranking = response.ranking;
|
|
4976
5328
|
if (ranking) {
|
|
4977
|
-
const nextOffset = ranking.nextOffset !== void 0 ? ranking.nextOffset : ranking.totalCount > response.items.length ? response.items.length : null;
|
|
5329
|
+
const nextOffset = ranking.nextOffset !== void 0 ? ranking.nextOffset : ranking.totalCount > (response.results ?? response.items ?? []).length ? (response.results ?? response.items ?? []).length : null;
|
|
4978
5330
|
return nextOffset === null ? `ranking exhausted at ${ranking.totalCount}` : `${ranking.totalCount} ranked in total \u2014 papiers browse ${ranking.searchId} --offset ${nextOffset}`;
|
|
4979
5331
|
}
|
|
4980
5332
|
return response.page.nextCursor ? "more available \u2014 rerun with --json and pass page.nextCursor via --cursor" : "no more pages";
|
|
@@ -5054,7 +5406,9 @@ async function runCli(argv, dependencies = {}) {
|
|
|
5054
5406
|
const command = parseCliArgs(argv);
|
|
5055
5407
|
jsonOutput = command.json;
|
|
5056
5408
|
if (command.type === "help") {
|
|
5057
|
-
stdout.
|
|
5409
|
+
const styled = dependencies.stdout === void 0 && process.stdout.isTTY === true && process.env.NO_COLOR === void 0;
|
|
5410
|
+
stdout.write(`${renderHelp(command, styled)}
|
|
5411
|
+
`);
|
|
5058
5412
|
return 0;
|
|
5059
5413
|
}
|
|
5060
5414
|
if (command.type === "version") {
|
|
@@ -5126,12 +5480,27 @@ async function runCli(argv, dependencies = {}) {
|
|
|
5126
5480
|
json: command.json,
|
|
5127
5481
|
stdout
|
|
5128
5482
|
});
|
|
5129
|
-
case "capabilities":
|
|
5130
|
-
|
|
5131
|
-
|
|
5132
|
-
|
|
5483
|
+
case "capabilities": {
|
|
5484
|
+
const capabilities = await getCapabilities(
|
|
5485
|
+
config,
|
|
5486
|
+
resolveFetch(dependencies.fetch)
|
|
5487
|
+
);
|
|
5488
|
+
if (command.json) {
|
|
5489
|
+
writeJson(stdout, capabilities);
|
|
5490
|
+
return 0;
|
|
5491
|
+
}
|
|
5492
|
+
const caps = capabilities;
|
|
5493
|
+
stdout.write(
|
|
5494
|
+
`${redactSensitiveText(
|
|
5495
|
+
[
|
|
5496
|
+
`Validation: ok requestId=${String(caps.requestId ?? "")}`,
|
|
5497
|
+
...formatCapabilityLines(caps)
|
|
5498
|
+
].join("\n")
|
|
5499
|
+
)}
|
|
5500
|
+
`
|
|
5133
5501
|
);
|
|
5134
5502
|
return 0;
|
|
5503
|
+
}
|
|
5135
5504
|
case "tokens-list":
|
|
5136
5505
|
writeTokenListOutput(
|
|
5137
5506
|
stdout,
|
|
@@ -5198,11 +5567,17 @@ async function runCli(argv, dependencies = {}) {
|
|
|
5198
5567
|
request
|
|
5199
5568
|
);
|
|
5200
5569
|
if (command.idsOnly) {
|
|
5201
|
-
writeIds(stdout, response.
|
|
5570
|
+
writeIds(stdout, response.results, {
|
|
5202
5571
|
nulDelimited: command.idsNulDelimited === true
|
|
5203
5572
|
});
|
|
5204
5573
|
} else if (command.docIdsOnly) {
|
|
5205
|
-
writeParentDocumentIds(stdout, response.
|
|
5574
|
+
writeParentDocumentIds(stdout, response.results);
|
|
5575
|
+
} else if (command.passageIdsOnly) {
|
|
5576
|
+
writeEvidenceIds(stdout, response.results, "passage");
|
|
5577
|
+
} else if (command.highlightIdsOnly) {
|
|
5578
|
+
writeEvidenceIds(stdout, response.results, "highlight");
|
|
5579
|
+
} else if (command.evidenceIdsOnly) {
|
|
5580
|
+
writeEvidenceIds(stdout, response.results);
|
|
5206
5581
|
} else if (command.pretty) {
|
|
5207
5582
|
stdout.write(redactSensitiveText(renderPrettyPageOutput(response)));
|
|
5208
5583
|
} else {
|
|
@@ -5218,11 +5593,17 @@ async function runCli(argv, dependencies = {}) {
|
|
|
5218
5593
|
command.request
|
|
5219
5594
|
);
|
|
5220
5595
|
if (command.idsOnly) {
|
|
5221
|
-
writeIds(stdout, response.
|
|
5596
|
+
writeIds(stdout, response.results, {
|
|
5222
5597
|
nulDelimited: command.idsNulDelimited === true
|
|
5223
5598
|
});
|
|
5224
5599
|
} else if (command.docIdsOnly) {
|
|
5225
|
-
writeParentDocumentIds(stdout, response.
|
|
5600
|
+
writeParentDocumentIds(stdout, response.results);
|
|
5601
|
+
} else if (command.passageIdsOnly) {
|
|
5602
|
+
writeEvidenceIds(stdout, response.results, "passage");
|
|
5603
|
+
} else if (command.highlightIdsOnly) {
|
|
5604
|
+
writeEvidenceIds(stdout, response.results, "highlight");
|
|
5605
|
+
} else if (command.evidenceIdsOnly) {
|
|
5606
|
+
writeEvidenceIds(stdout, response.results);
|
|
5226
5607
|
} else if (command.pretty) {
|
|
5227
5608
|
stdout.write(redactSensitiveText(renderPrettyPageOutput(response)));
|
|
5228
5609
|
} else {
|
|
@@ -5351,6 +5732,7 @@ function writeAuthLoginOutput(stdout, output, json) {
|
|
|
5351
5732
|
return;
|
|
5352
5733
|
}
|
|
5353
5734
|
stdout.write("Signed in to Papiers.\n");
|
|
5735
|
+
stdout.write("Next, try: papiers list --limit 5 --pretty\n");
|
|
5354
5736
|
}
|
|
5355
5737
|
function writeAuthLogoutOutput(stdout, output, json) {
|
|
5356
5738
|
if (json) {
|
|
@@ -5369,6 +5751,14 @@ function writeAuthLogoutOutput(stdout, output, json) {
|
|
|
5369
5751
|
stdout.write(`${redactSensitiveText(lines.join("\n"))}
|
|
5370
5752
|
`);
|
|
5371
5753
|
}
|
|
5754
|
+
function formatCapabilityLines(capabilities) {
|
|
5755
|
+
return [
|
|
5756
|
+
`Scopes: ${formatUnknownList(capabilities.scopes)}`,
|
|
5757
|
+
`Search kinds: ${formatUnknownList(capabilities.searchKinds)}`,
|
|
5758
|
+
`Read formats: ${formatUnknownList(capabilities.readFormats)}`,
|
|
5759
|
+
`Not ready: ${formatNotReady(capabilities.notReady)}`
|
|
5760
|
+
];
|
|
5761
|
+
}
|
|
5372
5762
|
function writeAuthInspectOutput(stdout, output, json) {
|
|
5373
5763
|
if (json) {
|
|
5374
5764
|
writeJson(stdout, output);
|
|
@@ -5384,10 +5774,7 @@ function writeAuthInspectOutput(stdout, output, json) {
|
|
|
5384
5774
|
`Account: userId=${String(
|
|
5385
5775
|
capabilities.account?.userId ?? "unknown"
|
|
5386
5776
|
)} profile=${String(capabilities.account?.profile ?? "unknown")}`,
|
|
5387
|
-
|
|
5388
|
-
`Search kinds: ${formatUnknownList(capabilities.searchKinds)}`,
|
|
5389
|
-
`Read formats: ${formatUnknownList(capabilities.readFormats)}`,
|
|
5390
|
-
`Not ready: ${formatNotReady(capabilities.notReady)}`
|
|
5777
|
+
...formatCapabilityLines(capabilities)
|
|
5391
5778
|
].join("\n")
|
|
5392
5779
|
)}
|
|
5393
5780
|
`
|
|
@@ -5543,13 +5930,13 @@ function normalizeStdinToken(rawInput) {
|
|
|
5543
5930
|
const parts = rawInput.trim().split(/\s+/u).filter(Boolean);
|
|
5544
5931
|
if (parts.length !== 1) {
|
|
5545
5932
|
throw new CliUsageError(
|
|
5546
|
-
"Token stdin must contain exactly one Papiers API token."
|
|
5933
|
+
"Token stdin must contain exactly one Papiers API token (starting with pap_live_), with no surrounding whitespace."
|
|
5547
5934
|
);
|
|
5548
5935
|
}
|
|
5549
5936
|
const token = parts[0];
|
|
5550
5937
|
if (!isPapiersPat(token)) {
|
|
5551
5938
|
throw new CliUsageError(
|
|
5552
|
-
"Token stdin did not contain a valid Papiers API token."
|
|
5939
|
+
"Token stdin did not contain a valid Papiers API token; expected one starting with pap_live_."
|
|
5553
5940
|
);
|
|
5554
5941
|
}
|
|
5555
5942
|
return token;
|
|
@@ -5715,6 +6102,27 @@ function writeParentDocumentIds(stdout, items) {
|
|
|
5715
6102
|
stdout.write(ids.length === 0 ? "" : `${ids.join("\n")}
|
|
5716
6103
|
`);
|
|
5717
6104
|
}
|
|
6105
|
+
function writeEvidenceIds(stdout, results, kind) {
|
|
6106
|
+
const ids = [];
|
|
6107
|
+
for (const result of results) {
|
|
6108
|
+
if (result.kind !== "document") {
|
|
6109
|
+
continue;
|
|
6110
|
+
}
|
|
6111
|
+
for (const evidence of result.evidence) {
|
|
6112
|
+
if (kind !== void 0 && evidence.kind !== kind) {
|
|
6113
|
+
continue;
|
|
6114
|
+
}
|
|
6115
|
+
if (publicReadKindForId(evidence.id) !== evidence.kind) {
|
|
6116
|
+
throw new Error(
|
|
6117
|
+
"Papiers API returned an evidence id that did not match its kind in evidence ID output."
|
|
6118
|
+
);
|
|
6119
|
+
}
|
|
6120
|
+
ids.push(evidence.id);
|
|
6121
|
+
}
|
|
6122
|
+
}
|
|
6123
|
+
stdout.write(ids.length === 0 ? "" : `${ids.join("\n")}
|
|
6124
|
+
`);
|
|
6125
|
+
}
|
|
5718
6126
|
async function expandListDocumentIdRequest(request, documentIds, input) {
|
|
5719
6127
|
const ids = await expandDocumentIdPlaceholders(documentIds, "list", input);
|
|
5720
6128
|
if (!ids?.length) {
|
|
@@ -6036,7 +6444,7 @@ function parseJsonEnvelopeIds(input, context, sourceLabel) {
|
|
|
6036
6444
|
}
|
|
6037
6445
|
if (input.startsWith("[")) {
|
|
6038
6446
|
throw new CliUsageError(
|
|
6039
|
-
`${context} JSON ${sourceLabel} must be a Papiers envelope with schemaVersion and items[].id.`
|
|
6447
|
+
`${context} JSON ${sourceLabel} must be a Papiers envelope with schemaVersion and items[].id or results[].id.`
|
|
6040
6448
|
);
|
|
6041
6449
|
}
|
|
6042
6450
|
let parsed;
|
|
@@ -6049,7 +6457,7 @@ function parseJsonEnvelopeIds(input, context, sourceLabel) {
|
|
|
6049
6457
|
}
|
|
6050
6458
|
if (!parsed || typeof parsed !== "object") {
|
|
6051
6459
|
throw new CliUsageError(
|
|
6052
|
-
`${context} JSON ${sourceLabel} must be a Papiers envelope with schemaVersion and items[].id.`
|
|
6460
|
+
`${context} JSON ${sourceLabel} must be a Papiers envelope with schemaVersion and items[].id or results[].id.`
|
|
6053
6461
|
);
|
|
6054
6462
|
}
|
|
6055
6463
|
const envelope = parsed;
|
|
@@ -6062,7 +6470,7 @@ function parseJsonEnvelopeIds(input, context, sourceLabel) {
|
|
|
6062
6470
|
if (envelope.schemaVersion === PAPIERS_SCHEMA_VERSIONS.list) {
|
|
6063
6471
|
assertPapiersListResponse(`${context} list envelope`, parsed);
|
|
6064
6472
|
} else if (envelope.schemaVersion === PAPIERS_SCHEMA_VERSIONS.search) {
|
|
6065
|
-
|
|
6473
|
+
validateSearchPipelineEnvelope(`${context} search envelope`, parsed);
|
|
6066
6474
|
} else {
|
|
6067
6475
|
assertPapiersReadPipelineEnvelope(`${context} read envelope`, parsed);
|
|
6068
6476
|
}
|
|
@@ -6074,10 +6482,10 @@ function parseJsonEnvelopeIds(input, context, sourceLabel) {
|
|
|
6074
6482
|
}
|
|
6075
6483
|
throw error;
|
|
6076
6484
|
}
|
|
6077
|
-
const items = envelope.items;
|
|
6485
|
+
const items = envelope.schemaVersion === PAPIERS_SCHEMA_VERSIONS.search ? envelope.results : envelope.items;
|
|
6078
6486
|
if (!Array.isArray(items)) {
|
|
6079
6487
|
throw new CliUsageError(
|
|
6080
|
-
`${context} JSON ${sourceLabel} must be a Papiers envelope with items[].id.`
|
|
6488
|
+
`${context} JSON ${sourceLabel} must be a Papiers envelope with items[].id or results[].id.`
|
|
6081
6489
|
);
|
|
6082
6490
|
}
|
|
6083
6491
|
return items.map((item, index) => {
|
|
@@ -6102,6 +6510,19 @@ function parseJsonEnvelopeIds(input, context, sourceLabel) {
|
|
|
6102
6510
|
return id;
|
|
6103
6511
|
});
|
|
6104
6512
|
}
|
|
6513
|
+
function validateSearchPipelineEnvelope(label, parsed) {
|
|
6514
|
+
const envelope = parsed;
|
|
6515
|
+
const ranking = envelope.ranking && typeof envelope.ranking === "object" && !Array.isArray(envelope.ranking) ? envelope.ranking : null;
|
|
6516
|
+
if (ranking && ("offset" in ranking || "nextOffset" in ranking)) {
|
|
6517
|
+
assertPapiersSearchResultsResponse(label, parsed, {
|
|
6518
|
+
schemaVersion: PAPIERS_SCHEMA_VERSIONS.searchResultsRequest,
|
|
6519
|
+
searchId: typeof ranking.searchId === "string" ? ranking.searchId : "",
|
|
6520
|
+
offset: typeof ranking.offset === "number" ? ranking.offset : void 0
|
|
6521
|
+
});
|
|
6522
|
+
return;
|
|
6523
|
+
}
|
|
6524
|
+
assertPapiersSearchResponse(label, parsed);
|
|
6525
|
+
}
|
|
6105
6526
|
function parseTextIds(input) {
|
|
6106
6527
|
return input.split(/[\s,]+/u).filter(Boolean);
|
|
6107
6528
|
}
|
|
@@ -6120,9 +6541,20 @@ function writeCliError(error, params) {
|
|
|
6120
6541
|
`${redactSensitiveText(serialized.body.error.message)}
|
|
6121
6542
|
`
|
|
6122
6543
|
);
|
|
6544
|
+
const hint = humanErrorHint(error);
|
|
6545
|
+
if (hint) {
|
|
6546
|
+
params.stderr.write(`${hint}
|
|
6547
|
+
`);
|
|
6548
|
+
}
|
|
6123
6549
|
}
|
|
6124
6550
|
return serialized.exitCode;
|
|
6125
6551
|
}
|
|
6552
|
+
function humanErrorHint(error) {
|
|
6553
|
+
if (error instanceof PapiersCliApiError && error.status === 401) {
|
|
6554
|
+
return "Your token may be expired or revoked. Run papiers auth login --force to replace it.";
|
|
6555
|
+
}
|
|
6556
|
+
return null;
|
|
6557
|
+
}
|
|
6126
6558
|
function serializeCliError(error) {
|
|
6127
6559
|
if (error instanceof PapiersCliApiError) {
|
|
6128
6560
|
return {
|