papiers 0.1.2 → 0.1.4
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 +27 -3
- package/dist/index.js +1090 -402
- package/package.json +3 -2
- package/skills/papiers-research/SKILL.md +119 -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
|
|
@@ -412,23 +412,41 @@ function isNodeError(error) {
|
|
|
412
412
|
return Boolean(error && typeof error === "object" && "code" in error);
|
|
413
413
|
}
|
|
414
414
|
|
|
415
|
+
// ../../src/shared/papiers-resource-locators.ts
|
|
416
|
+
var UUID_PATTERN = "[0-9a-f]{8}-[0-9a-f]{4}-[1-8][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}";
|
|
417
|
+
var PAPIERS_RESOURCE_LOCATOR_PATTERN_SOURCE = `papiers://(?:note|highlight|item|conversation|artifact)/${UUID_PATTERN}`;
|
|
418
|
+
var RESOURCE_LOCATOR_PATTERN = new RegExp(
|
|
419
|
+
`^papiers://(note|highlight|item|conversation|artifact)/(${UUID_PATTERN})$`,
|
|
420
|
+
"u"
|
|
421
|
+
);
|
|
422
|
+
var UUID_REGEX = new RegExp(`^${UUID_PATTERN}$`, "iu");
|
|
423
|
+
var READ_KIND_BY_LOCATOR_KIND = {
|
|
424
|
+
note: "note",
|
|
425
|
+
highlight: "highlight",
|
|
426
|
+
item: "document",
|
|
427
|
+
conversation: "conversation",
|
|
428
|
+
artifact: "artifact"
|
|
429
|
+
};
|
|
430
|
+
function parsePapiersResourceLocator(value) {
|
|
431
|
+
const match = RESOURCE_LOCATOR_PATTERN.exec(value);
|
|
432
|
+
if (!match) return null;
|
|
433
|
+
const kind = match[1];
|
|
434
|
+
return {
|
|
435
|
+
value,
|
|
436
|
+
kind,
|
|
437
|
+
readKind: READ_KIND_BY_LOCATOR_KIND[kind],
|
|
438
|
+
internalId: match[2].toLowerCase()
|
|
439
|
+
};
|
|
440
|
+
}
|
|
441
|
+
|
|
415
442
|
// src/document-contract.ts
|
|
416
443
|
var PUBLIC_KINDS = [
|
|
417
444
|
"document",
|
|
418
445
|
"passage",
|
|
419
446
|
"highlight",
|
|
420
447
|
"conversation",
|
|
421
|
-
"equation"
|
|
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"
|
|
448
|
+
"equation",
|
|
449
|
+
"note"
|
|
432
450
|
];
|
|
433
451
|
var EXPECTED_DOCUMENT_READ_FORMATS = [
|
|
434
452
|
"metadata",
|
|
@@ -450,6 +468,10 @@ var EXPECTED_CONVERSATION_READ_FORMATS = [
|
|
|
450
468
|
var EXPECTED_EQUATION_READ_FORMATS = [
|
|
451
469
|
"metadata"
|
|
452
470
|
];
|
|
471
|
+
var EXPECTED_NOTE_READ_FORMATS = [
|
|
472
|
+
"markdown",
|
|
473
|
+
"plain"
|
|
474
|
+
];
|
|
453
475
|
var DOCUMENT_READ_REQUEST_FORMATS = [
|
|
454
476
|
...EXPECTED_DOCUMENT_READ_FORMATS,
|
|
455
477
|
"auto"
|
|
@@ -478,10 +500,13 @@ var EXPECTED_DOCUMENT_FILTERS = [
|
|
|
478
500
|
"engaged",
|
|
479
501
|
"lastEngagedAt"
|
|
480
502
|
];
|
|
503
|
+
var EXPECTED_CONVERSATION_FILTERS = [
|
|
504
|
+
"lastEngagedAt"
|
|
505
|
+
];
|
|
481
506
|
var EXPECTED_DOCUMENT_FILTER_OPERATORS = {
|
|
482
507
|
id: ["eq", "in"],
|
|
483
508
|
title: ["eq", "contains", "prefix", "in"],
|
|
484
|
-
author: ["eq"],
|
|
509
|
+
author: ["eq", "contains"],
|
|
485
510
|
venue: ["eq", "contains", "prefix", "in"],
|
|
486
511
|
publishedDate: ["eq", "gte", "gt", "lte", "lt", "between"],
|
|
487
512
|
publishedYear: ["eq", "gte", "gt", "lte", "lt", "between", "in"],
|
|
@@ -513,6 +538,7 @@ var PASSAGE_PUBLIC_ID_PATTERN = /^pas_[a-f0-9]{32}$/u;
|
|
|
513
538
|
var HIGHLIGHT_PUBLIC_ID_PATTERN = /^hl_[a-f0-9]{32}$/u;
|
|
514
539
|
var CONVERSATION_PUBLIC_ID_PATTERN = /^cnv_[a-f0-9]{32}$/u;
|
|
515
540
|
var EQUATION_PUBLIC_ID_PATTERN = /^eq_[a-f0-9]{32}$/u;
|
|
541
|
+
var NOTE_PUBLIC_ID_PATTERN = /^nte_[a-f0-9]{32}$/u;
|
|
516
542
|
var SEARCH_RANKING_ID_PATTERN = /^srch_[a-f0-9]{32}$/u;
|
|
517
543
|
function isSearchRankingId(value) {
|
|
518
544
|
return SEARCH_RANKING_ID_PATTERN.test(value);
|
|
@@ -532,6 +558,9 @@ function isConversationPublicId(value) {
|
|
|
532
558
|
function isEquationPublicId(value) {
|
|
533
559
|
return EQUATION_PUBLIC_ID_PATTERN.test(value);
|
|
534
560
|
}
|
|
561
|
+
function isNotePublicId(value) {
|
|
562
|
+
return NOTE_PUBLIC_ID_PATTERN.test(value);
|
|
563
|
+
}
|
|
535
564
|
function publicReadKindForId(value) {
|
|
536
565
|
if (isDocumentPublicId(value)) {
|
|
537
566
|
return "document";
|
|
@@ -548,8 +577,22 @@ function publicReadKindForId(value) {
|
|
|
548
577
|
if (isEquationPublicId(value)) {
|
|
549
578
|
return "equation";
|
|
550
579
|
}
|
|
580
|
+
if (isNotePublicId(value)) {
|
|
581
|
+
return "note";
|
|
582
|
+
}
|
|
551
583
|
return null;
|
|
552
584
|
}
|
|
585
|
+
function readKindForIdentifier(value) {
|
|
586
|
+
const publicKind = publicReadKindForId(value);
|
|
587
|
+
if (publicKind) {
|
|
588
|
+
return publicKind;
|
|
589
|
+
}
|
|
590
|
+
const locatorKind = parsePapiersResourceLocator(value)?.readKind;
|
|
591
|
+
return locatorKind === "artifact" ? null : locatorKind ?? null;
|
|
592
|
+
}
|
|
593
|
+
function isDocumentReadIdentifier(value) {
|
|
594
|
+
return isDocumentPublicId(value) || parsePapiersResourceLocator(value)?.kind === "item";
|
|
595
|
+
}
|
|
553
596
|
function isPublicIdForKind(value, kind) {
|
|
554
597
|
return publicReadKindForId(value) === kind;
|
|
555
598
|
}
|
|
@@ -598,6 +641,27 @@ var PAPIERS_SEARCH_QUALITY_SIGNALS = [
|
|
|
598
641
|
"low",
|
|
599
642
|
"empty"
|
|
600
643
|
];
|
|
644
|
+
var PAPIERS_SEARCH_RESULT_KINDS = [
|
|
645
|
+
"document",
|
|
646
|
+
"conversation",
|
|
647
|
+
"note"
|
|
648
|
+
];
|
|
649
|
+
var PAPIERS_SEARCH_EVIDENCE_KINDS = [
|
|
650
|
+
"passage",
|
|
651
|
+
"highlight",
|
|
652
|
+
"equation"
|
|
653
|
+
];
|
|
654
|
+
var PAPIERS_SEARCH_MATCH_REASONS = [
|
|
655
|
+
"title",
|
|
656
|
+
"doi",
|
|
657
|
+
"arxivId",
|
|
658
|
+
"pmid",
|
|
659
|
+
"passage",
|
|
660
|
+
"highlight",
|
|
661
|
+
"equation",
|
|
662
|
+
"conversation",
|
|
663
|
+
"note"
|
|
664
|
+
];
|
|
601
665
|
var PAPIERS_PUBLIC_NOT_READY_REASONS_BY_FEATURE = {
|
|
602
666
|
document_content_read: ["explicit_enablement_required"],
|
|
603
667
|
non_document_kinds: ["public_id_projection_not_ready"],
|
|
@@ -613,7 +677,10 @@ var PAPIERS_PUBLIC_NOT_READY_REASONS_BY_FEATURE = {
|
|
|
613
677
|
read_section_scopes: ["section_scoped_read_not_ready"],
|
|
614
678
|
read_context: ["read_context_not_ready"],
|
|
615
679
|
ranked_search_cursors: ["search_sessions_not_ready"],
|
|
616
|
-
search_results_browse: [
|
|
680
|
+
search_results_browse: [
|
|
681
|
+
"content_search_not_ready",
|
|
682
|
+
"search_sessions_not_ready"
|
|
683
|
+
]
|
|
617
684
|
};
|
|
618
685
|
var PAPIERS_PUBLIC_ERROR_CODES = [
|
|
619
686
|
"api_disabled",
|
|
@@ -636,6 +703,8 @@ var PAPIERS_PUBLIC_ERROR_CODES = [
|
|
|
636
703
|
"invalid_request",
|
|
637
704
|
"not_found",
|
|
638
705
|
"source_superseded",
|
|
706
|
+
"content_limit_exceeded",
|
|
707
|
+
"request_limit_exceeded",
|
|
639
708
|
"rate_limited",
|
|
640
709
|
"internal_error"
|
|
641
710
|
];
|
|
@@ -746,7 +815,7 @@ var SEARCH_RESPONSE_KEYS = /* @__PURE__ */ new Set([
|
|
|
746
815
|
"requestId",
|
|
747
816
|
"query",
|
|
748
817
|
"quality",
|
|
749
|
-
"
|
|
818
|
+
"results",
|
|
750
819
|
"page",
|
|
751
820
|
"ranking",
|
|
752
821
|
"warnings"
|
|
@@ -760,6 +829,9 @@ var SEARCH_RANKING_KEYS = /* @__PURE__ */ new Set([
|
|
|
760
829
|
]);
|
|
761
830
|
var SEARCH_QUALITY_KEYS = /* @__PURE__ */ new Set(["signal", "suggestions"]);
|
|
762
831
|
var SEARCH_QUALITY_SIGNALS = new Set(PAPIERS_SEARCH_QUALITY_SIGNALS);
|
|
832
|
+
var SEARCH_RESULT_KINDS = new Set(PAPIERS_SEARCH_RESULT_KINDS);
|
|
833
|
+
var SEARCH_EVIDENCE_KINDS = new Set(PAPIERS_SEARCH_EVIDENCE_KINDS);
|
|
834
|
+
var SEARCH_MATCH_REASONS = new Set(PAPIERS_SEARCH_MATCH_REASONS);
|
|
763
835
|
var PUBLIC_WARNING_KEYS = /* @__PURE__ */ new Set(["code", "message"]);
|
|
764
836
|
var DOCUMENT_SEARCH_WARNING_CODE = "metadata_only_search";
|
|
765
837
|
var DOCUMENT_SEARCH_WARNING_MESSAGE = "Public document search currently searches catalog title and metadata, not document body content.";
|
|
@@ -771,6 +843,7 @@ var RANKED_SEARCH_CURSOR_WARNING_MESSAGES = /* @__PURE__ */ new Set([
|
|
|
771
843
|
var DOCUMENT_READ_TRUNCATED_WARNING_CODE = "read_truncated";
|
|
772
844
|
var DOCUMENT_READ_TRUNCATED_WARNING_MESSAGE = "Document content was truncated by public read limits.";
|
|
773
845
|
var PASSAGE_READ_TRUNCATED_WARNING_MESSAGE = "Passage content was truncated by public read limits.";
|
|
846
|
+
var NOTE_READ_TRUNCATED_WARNING_MESSAGE = "Note content was truncated by public read limits.";
|
|
774
847
|
var READ_RESPONSE_KEYS = /* @__PURE__ */ new Set([
|
|
775
848
|
"schemaVersion",
|
|
776
849
|
"requestId",
|
|
@@ -821,6 +894,37 @@ var SEARCH_DOCUMENT_ITEM_KEYS = /* @__PURE__ */ new Set([
|
|
|
821
894
|
"metadata",
|
|
822
895
|
"updatedAt"
|
|
823
896
|
]);
|
|
897
|
+
var SEARCH_RESULT_BASE_KEYS = [
|
|
898
|
+
"id",
|
|
899
|
+
"kind",
|
|
900
|
+
"rank",
|
|
901
|
+
"score",
|
|
902
|
+
"matchedBy",
|
|
903
|
+
"title"
|
|
904
|
+
];
|
|
905
|
+
var SEARCH_DOCUMENT_RESULT_KEYS = /* @__PURE__ */ new Set([
|
|
906
|
+
...SEARCH_RESULT_BASE_KEYS,
|
|
907
|
+
"source",
|
|
908
|
+
"metadata",
|
|
909
|
+
"evidence",
|
|
910
|
+
"evidenceTotal"
|
|
911
|
+
]);
|
|
912
|
+
var SEARCH_CONVERSATION_RESULT_KEYS = /* @__PURE__ */ new Set([
|
|
913
|
+
...SEARCH_RESULT_BASE_KEYS,
|
|
914
|
+
"snippet"
|
|
915
|
+
]);
|
|
916
|
+
var SEARCH_NOTE_RESULT_KEYS = /* @__PURE__ */ new Set([
|
|
917
|
+
...SEARCH_RESULT_BASE_KEYS,
|
|
918
|
+
"snippet",
|
|
919
|
+
"metadata"
|
|
920
|
+
]);
|
|
921
|
+
var SEARCH_EVIDENCE_KEYS = /* @__PURE__ */ new Set([
|
|
922
|
+
"kind",
|
|
923
|
+
"id",
|
|
924
|
+
"rank",
|
|
925
|
+
"snippet",
|
|
926
|
+
"score"
|
|
927
|
+
]);
|
|
824
928
|
var READ_SUCCESS_DOCUMENT_ITEM_KEYS = /* @__PURE__ */ new Set([
|
|
825
929
|
"id",
|
|
826
930
|
"kind",
|
|
@@ -866,6 +970,19 @@ var READ_SUCCESS_EQUATION_ITEM_KEYS = /* @__PURE__ */ new Set([
|
|
|
866
970
|
"format",
|
|
867
971
|
"metadata"
|
|
868
972
|
]);
|
|
973
|
+
var READ_SUCCESS_NOTE_ITEM_KEYS = /* @__PURE__ */ new Set([
|
|
974
|
+
"id",
|
|
975
|
+
"kind",
|
|
976
|
+
"ok",
|
|
977
|
+
"format",
|
|
978
|
+
"content",
|
|
979
|
+
"truncated",
|
|
980
|
+
"charCount",
|
|
981
|
+
"tokenEstimate",
|
|
982
|
+
"metadata",
|
|
983
|
+
"nextCursor",
|
|
984
|
+
"warnings"
|
|
985
|
+
]);
|
|
869
986
|
var READ_ERROR_DOCUMENT_ITEM_KEYS = /* @__PURE__ */ new Set(["id", "kind", "ok", "error"]);
|
|
870
987
|
var READ_ITEM_ERROR_KEYS = /* @__PURE__ */ new Set(["code", "message", "retryable"]);
|
|
871
988
|
var HIGHLIGHT_READ_METADATA_KEYS = /* @__PURE__ */ new Set([
|
|
@@ -875,6 +992,8 @@ var HIGHLIGHT_READ_METADATA_KEYS = /* @__PURE__ */ new Set([
|
|
|
875
992
|
"anchorType",
|
|
876
993
|
"annotationText",
|
|
877
994
|
"quoteContext",
|
|
995
|
+
"quotePrefix",
|
|
996
|
+
"quoteSuffix",
|
|
878
997
|
"createdAt",
|
|
879
998
|
"updatedAt"
|
|
880
999
|
]);
|
|
@@ -896,6 +1015,14 @@ var EQUATION_READ_METADATA_KEYS = /* @__PURE__ */ new Set([
|
|
|
896
1015
|
"nodeType",
|
|
897
1016
|
"updatedAt"
|
|
898
1017
|
]);
|
|
1018
|
+
var NOTE_READ_METADATA_KEYS = /* @__PURE__ */ new Set([
|
|
1019
|
+
"documentId",
|
|
1020
|
+
"attachedTitle",
|
|
1021
|
+
"editedAt",
|
|
1022
|
+
"createdAt",
|
|
1023
|
+
"updatedAt",
|
|
1024
|
+
"title"
|
|
1025
|
+
]);
|
|
899
1026
|
var READ_LOCATIONS_KEYS = /* @__PURE__ */ new Set(["pages", "scope", "truncated"]);
|
|
900
1027
|
var READ_LOCATION_PAGE_KEYS = /* @__PURE__ */ new Set(["page", "sections"]);
|
|
901
1028
|
var READ_LOCATION_SCOPE_KEYS = /* @__PURE__ */ new Set(["pages"]);
|
|
@@ -927,9 +1054,16 @@ var PASSAGE_READ_NOT_FOUND_MESSAGE = "Passage is not available.";
|
|
|
927
1054
|
var HIGHLIGHT_READ_NOT_FOUND_MESSAGE = "Highlight is not available.";
|
|
928
1055
|
var CONVERSATION_READ_NOT_FOUND_MESSAGE = "Conversation is not available.";
|
|
929
1056
|
var EQUATION_READ_NOT_FOUND_MESSAGE = "Equation is not available.";
|
|
1057
|
+
var NOTE_READ_NOT_FOUND_MESSAGE = "Note is not available.";
|
|
930
1058
|
var DOCUMENT_READ_SOURCE_SUPERSEDED_CODE = "source_superseded";
|
|
1059
|
+
var CONVERSATION_READ_CONTENT_LIMIT_CODE = "content_limit_exceeded";
|
|
1060
|
+
var CONVERSATION_READ_REQUEST_LIMIT_CODE = "request_limit_exceeded";
|
|
931
1061
|
var DOCUMENT_READ_SOURCE_SUPERSEDED_MESSAGE = "Document content is not available for the current source.";
|
|
1062
|
+
var NOTE_READ_SOURCE_SUPERSEDED_MESSAGE = "Note content changed since this cursor was issued.";
|
|
932
1063
|
var PASSAGE_READ_CONTENT_UNAVAILABLE_MESSAGE = "Passage content is not available.";
|
|
1064
|
+
var CONVERSATION_READ_SOURCE_SUPERSEDED_MESSAGE = "Conversation source is no longer available. Search again for a current result.";
|
|
1065
|
+
var CONVERSATION_READ_CONTENT_LIMIT_MESSAGE = "Conversation content exceeds the public read limit.";
|
|
1066
|
+
var CONVERSATION_READ_REQUEST_LIMIT_MESSAGE = "Conversation read batch is too large. Retry this item in a smaller batch.";
|
|
933
1067
|
var PUBLIC_CURSOR_BASE64URL_PATTERN = /^[A-Za-z0-9_-]{1,4096}$/u;
|
|
934
1068
|
var PUBLIC_CURSOR_SIGNATURE_PATTERN = /^[A-Za-z0-9_-]{43}$/u;
|
|
935
1069
|
var PUBLIC_CURSOR_HASH_PATTERN = /^[A-Za-z0-9_-]{43}$/u;
|
|
@@ -989,6 +1123,8 @@ var INTERNAL_RESPONSE_KEYS = /* @__PURE__ */ new Set([
|
|
|
989
1123
|
"latexTokens",
|
|
990
1124
|
"library_item_id",
|
|
991
1125
|
"libraryItemId",
|
|
1126
|
+
"note_id",
|
|
1127
|
+
"noteId",
|
|
992
1128
|
"actor_id",
|
|
993
1129
|
"actorId",
|
|
994
1130
|
"owner_user_id",
|
|
@@ -1012,7 +1148,7 @@ var INTERNAL_RESPONSE_KEYS = /* @__PURE__ */ new Set([
|
|
|
1012
1148
|
"last_used_ip_hash",
|
|
1013
1149
|
"lastUsedIpHash"
|
|
1014
1150
|
]);
|
|
1015
|
-
var UNSAFE_PUBLIC_EXCERPT_MARKER_PATTERN = /\b(?:artifact_id|artifactId|astNodeId|atom_id|atomId|branchKey|contentHash|conversation_id|conversationId|current_artifact_id|currentArtifactId|current_internal_target_json|currentInternalTargetJson|internal_locator|internalLocator|latexTokens|library_item_id|libraryItemId|actor_id|actorId|owner_user_id|ownerUserId|secret_hash|secretHash|source_id|sourceId|source_url|sourceUrl|source_locator|sourceLocator|source_locator_hash|sourceLocatorHash|source_locator_json|sourceLocatorJson|projectionHash|search_row_id|searchRowId|last_used_ip_hash|lastUsedIpHash)\b/u;
|
|
1151
|
+
var UNSAFE_PUBLIC_EXCERPT_MARKER_PATTERN = /\b(?:artifact_id|artifactId|astNodeId|atom_id|atomId|branchKey|contentHash|conversation_id|conversationId|current_artifact_id|currentArtifactId|current_internal_target_json|currentInternalTargetJson|internal_locator|internalLocator|latexTokens|library_item_id|libraryItemId|note_id|noteId|actor_id|actorId|owner_user_id|ownerUserId|secret_hash|secretHash|source_id|sourceId|source_url|sourceUrl|source_locator|sourceLocator|source_locator_hash|sourceLocatorHash|source_locator_json|sourceLocatorJson|projectionHash|search_row_id|searchRowId|last_used_ip_hash|lastUsedIpHash)\b/u;
|
|
1016
1152
|
var UNSAFE_PUBLIC_EXCERPT_URL_PATTERN = /\bhttps?:\/\/\S+[?&](?:access_token|key|secret|sig|signature|token)=/iu;
|
|
1017
1153
|
var UNSAFE_PUBLIC_EXCERPT_SIGNED_URL_PATTERN = /\bsigned[_-]?url\b/iu;
|
|
1018
1154
|
var CLI_DOCUMENT_READ_FORMAT_SET = new Set(
|
|
@@ -1050,17 +1186,12 @@ function assertPapiersSearchResponse(label, body, expectedQuery, options = {}) {
|
|
|
1050
1186
|
`${label} did not echo the requested query.`
|
|
1051
1187
|
);
|
|
1052
1188
|
}
|
|
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) {
|
|
1189
|
+
const itemCount = validateSearchResults(label, value.results, options);
|
|
1190
|
+
const searchResults = value.results;
|
|
1191
|
+
for (const [index, result] of searchResults.entries()) {
|
|
1192
|
+
if (result.rank !== index + 1) {
|
|
1062
1193
|
throw new PapiersCliResponseValidationError(
|
|
1063
|
-
`${label}
|
|
1194
|
+
`${label} result ${index} rank was not contiguous from 1.`
|
|
1064
1195
|
);
|
|
1065
1196
|
}
|
|
1066
1197
|
}
|
|
@@ -1080,10 +1211,7 @@ function assertPapiersSearchResultsResponse(label, body, request) {
|
|
|
1080
1211
|
rejectUnexpectedKeys(label, value, SEARCH_RESPONSE_KEYS);
|
|
1081
1212
|
assertPublicRequestId(`${label} requestId`, value.requestId);
|
|
1082
1213
|
assertNonEmptyString(`${label} query`, value.query);
|
|
1083
|
-
const itemCount =
|
|
1084
|
-
mode: "search",
|
|
1085
|
-
requireRank: true
|
|
1086
|
-
});
|
|
1214
|
+
const itemCount = validateSearchResults(label, value.results);
|
|
1087
1215
|
validatePage(label, value.page, itemCount, { cursor: "none" });
|
|
1088
1216
|
validateOptionalSearchQuality(`${label} quality`, value.quality);
|
|
1089
1217
|
if (value.ranking === void 0) {
|
|
@@ -1118,12 +1246,12 @@ function assertPapiersSearchResultsResponse(label, body, request) {
|
|
|
1118
1246
|
`${label} returned more items than the consumed ranking window.`
|
|
1119
1247
|
);
|
|
1120
1248
|
}
|
|
1121
|
-
const items = value.
|
|
1249
|
+
const items = value.results;
|
|
1122
1250
|
let previousRank = expectedOffset;
|
|
1123
1251
|
for (const [index, item] of items.entries()) {
|
|
1124
1252
|
if (typeof item.rank !== "number" || item.rank <= previousRank || item.rank > consumedBound) {
|
|
1125
1253
|
throw new PapiersCliResponseValidationError(
|
|
1126
|
-
`${label}
|
|
1254
|
+
`${label} result ${index} rank was not strictly increasing within the frozen ranking window.`
|
|
1127
1255
|
);
|
|
1128
1256
|
}
|
|
1129
1257
|
previousRank = item.rank;
|
|
@@ -1243,10 +1371,10 @@ function validatePapiersReadResponse(label, body, options = {}) {
|
|
|
1243
1371
|
const expectedInclude = options.expectedInclude ? new Set(options.expectedInclude) : void 0;
|
|
1244
1372
|
for (const [index, rawItem] of items.entries()) {
|
|
1245
1373
|
const item = assertRecord(`${label} item ${index}`, rawItem);
|
|
1246
|
-
const id =
|
|
1374
|
+
const id = assertReadIdentifier(`${label} item ${index} id`, item.id);
|
|
1247
1375
|
if (options.expectedIds !== void 0 && id !== options.expectedIds[index]) {
|
|
1248
1376
|
throw new PapiersCliResponseValidationError(
|
|
1249
|
-
`${label} did not echo the requested
|
|
1377
|
+
`${label} did not echo the requested identifiers in order.`
|
|
1250
1378
|
);
|
|
1251
1379
|
}
|
|
1252
1380
|
const kind = validateReadItemKind(
|
|
@@ -1332,6 +1460,190 @@ function validateTokenSummary(label, rawToken) {
|
|
|
1332
1460
|
validateOptionalTimestamp(`${label} revokedAt`, token.revokedAt);
|
|
1333
1461
|
validateOptionalTimestamp(`${label} lastUsedAt`, token.lastUsedAt);
|
|
1334
1462
|
}
|
|
1463
|
+
function validateSearchResults(label, results, options = {}) {
|
|
1464
|
+
const values = assertArray(`${label} results`, results);
|
|
1465
|
+
for (const [index, rawResult] of values.entries()) {
|
|
1466
|
+
const result = assertRecord(`${label} result ${index}`, rawResult);
|
|
1467
|
+
rejectUnexpectedContent(`${label} result ${index}`, result);
|
|
1468
|
+
const kind = validateSearchResultKind(
|
|
1469
|
+
`${label} result ${index} kind`,
|
|
1470
|
+
result.kind,
|
|
1471
|
+
result.id
|
|
1472
|
+
);
|
|
1473
|
+
if (options.expectedKind !== void 0 && kind !== options.expectedKind) {
|
|
1474
|
+
throw new PapiersCliResponseValidationError(
|
|
1475
|
+
`${label} result ${index} kind did not match the requested kind.`
|
|
1476
|
+
);
|
|
1477
|
+
}
|
|
1478
|
+
if (options.expectedKinds !== void 0 && !options.expectedKinds.has(kind)) {
|
|
1479
|
+
throw new PapiersCliResponseValidationError(
|
|
1480
|
+
`${label} result ${index} kind was not one of the requested kinds.`
|
|
1481
|
+
);
|
|
1482
|
+
}
|
|
1483
|
+
switch (kind) {
|
|
1484
|
+
case "document":
|
|
1485
|
+
validateSearchDocumentResult(`${label} result ${index}`, result);
|
|
1486
|
+
break;
|
|
1487
|
+
case "conversation":
|
|
1488
|
+
validateSearchConversationResult(`${label} result ${index}`, result);
|
|
1489
|
+
break;
|
|
1490
|
+
case "note":
|
|
1491
|
+
validateSearchNoteResult(`${label} result ${index}`, result);
|
|
1492
|
+
break;
|
|
1493
|
+
}
|
|
1494
|
+
}
|
|
1495
|
+
return values.length;
|
|
1496
|
+
}
|
|
1497
|
+
function validateSearchResultKind(label, value, id) {
|
|
1498
|
+
if (typeof id !== "string") {
|
|
1499
|
+
throw new PapiersCliResponseValidationError(`${label} id was invalid.`);
|
|
1500
|
+
}
|
|
1501
|
+
if (!SEARCH_RESULT_KINDS.has(String(value))) {
|
|
1502
|
+
throw new PapiersCliResponseValidationError(
|
|
1503
|
+
`${label} was not a top-level search result kind.`
|
|
1504
|
+
);
|
|
1505
|
+
}
|
|
1506
|
+
if (value === "document") {
|
|
1507
|
+
assertDocId(`${label} id`, id);
|
|
1508
|
+
return "document";
|
|
1509
|
+
}
|
|
1510
|
+
if (value === "conversation" && isPublicIdForKind(id, "conversation")) {
|
|
1511
|
+
return "conversation";
|
|
1512
|
+
}
|
|
1513
|
+
if (value === "note" && isPublicIdForKind(id, "note")) {
|
|
1514
|
+
return "note";
|
|
1515
|
+
}
|
|
1516
|
+
throw new PapiersCliResponseValidationError(
|
|
1517
|
+
`${label} did not match the public id kind.`
|
|
1518
|
+
);
|
|
1519
|
+
}
|
|
1520
|
+
function validateSearchDocumentResult(label, result) {
|
|
1521
|
+
rejectUnexpectedKeys(label, result, SEARCH_DOCUMENT_RESULT_KEYS);
|
|
1522
|
+
assertDocId(`${label} id`, result.id);
|
|
1523
|
+
assertPositiveInteger(`${label} rank`, result.rank);
|
|
1524
|
+
validateSearchScore(`${label} score`, result.score);
|
|
1525
|
+
validateSearchMatchedBy(`${label} matchedBy`, result.matchedBy, {
|
|
1526
|
+
allow: /* @__PURE__ */ new Set([
|
|
1527
|
+
"title",
|
|
1528
|
+
"doi",
|
|
1529
|
+
"arxivId",
|
|
1530
|
+
"pmid",
|
|
1531
|
+
"passage",
|
|
1532
|
+
"highlight",
|
|
1533
|
+
"equation"
|
|
1534
|
+
])
|
|
1535
|
+
});
|
|
1536
|
+
validateOptionalNullableString(`${label} title`, result.title);
|
|
1537
|
+
validateOptionalDocumentCatalogMetadata(`${label} metadata`, result.metadata);
|
|
1538
|
+
validateOptionalMetadataReadSource(`${label} source`, result.source);
|
|
1539
|
+
const evidenceCount = validateSearchEvidenceList(
|
|
1540
|
+
`${label} evidence`,
|
|
1541
|
+
result.evidence
|
|
1542
|
+
);
|
|
1543
|
+
const evidenceTotal = assertNonNegativeInteger(
|
|
1544
|
+
`${label} evidenceTotal`,
|
|
1545
|
+
result.evidenceTotal
|
|
1546
|
+
);
|
|
1547
|
+
if (evidenceTotal < evidenceCount) {
|
|
1548
|
+
throw new PapiersCliResponseValidationError(
|
|
1549
|
+
`${label} evidenceTotal was smaller than evidence.length.`
|
|
1550
|
+
);
|
|
1551
|
+
}
|
|
1552
|
+
}
|
|
1553
|
+
function validateSearchConversationResult(label, result) {
|
|
1554
|
+
rejectUnexpectedKeys(label, result, SEARCH_CONVERSATION_RESULT_KEYS);
|
|
1555
|
+
const id = assertNonEmptyString(`${label} id`, result.id);
|
|
1556
|
+
if (!isPublicIdForKind(id, "conversation")) {
|
|
1557
|
+
throw new PapiersCliResponseValidationError(
|
|
1558
|
+
`${label} id was not a cnv_* public id.`
|
|
1559
|
+
);
|
|
1560
|
+
}
|
|
1561
|
+
assertPositiveInteger(`${label} rank`, result.rank);
|
|
1562
|
+
validateSearchScore(`${label} score`, result.score);
|
|
1563
|
+
validateSearchMatchedBy(`${label} matchedBy`, result.matchedBy, {
|
|
1564
|
+
allow: /* @__PURE__ */ new Set(["conversation"])
|
|
1565
|
+
});
|
|
1566
|
+
validateOptionalNullableString(`${label} title`, result.title);
|
|
1567
|
+
validateOptionalPublicExcerpt(`${label} snippet`, result.snippet);
|
|
1568
|
+
}
|
|
1569
|
+
function validateSearchNoteResult(label, result) {
|
|
1570
|
+
rejectUnexpectedKeys(label, result, SEARCH_NOTE_RESULT_KEYS);
|
|
1571
|
+
const id = assertNonEmptyString(`${label} id`, result.id);
|
|
1572
|
+
if (!isPublicIdForKind(id, "note")) {
|
|
1573
|
+
throw new PapiersCliResponseValidationError(
|
|
1574
|
+
`${label} id was not an nte_* public id.`
|
|
1575
|
+
);
|
|
1576
|
+
}
|
|
1577
|
+
assertPositiveInteger(`${label} rank`, result.rank);
|
|
1578
|
+
validateSearchScore(`${label} score`, result.score);
|
|
1579
|
+
validateSearchMatchedBy(`${label} matchedBy`, result.matchedBy, {
|
|
1580
|
+
allow: /* @__PURE__ */ new Set(["note"])
|
|
1581
|
+
});
|
|
1582
|
+
validateOptionalNullableString(`${label} title`, result.title);
|
|
1583
|
+
validateOptionalPublicExcerpt(`${label} snippet`, result.snippet);
|
|
1584
|
+
validateNoteMetadata(`${label} metadata`, result.metadata, assertDocId);
|
|
1585
|
+
}
|
|
1586
|
+
function validateSearchEvidenceList(label, value) {
|
|
1587
|
+
const evidence = assertArray(label, value);
|
|
1588
|
+
for (const [index, rawEvidence] of evidence.entries()) {
|
|
1589
|
+
const item = assertRecord(`${label} ${index}`, rawEvidence);
|
|
1590
|
+
rejectUnexpectedKeys(`${label} ${index}`, item, SEARCH_EVIDENCE_KEYS);
|
|
1591
|
+
validateSearchEvidenceKind(`${label} ${index} kind`, item.kind, item.id);
|
|
1592
|
+
assertPositiveInteger(`${label} ${index} rank`, item.rank);
|
|
1593
|
+
if (item.rank !== index + 1) {
|
|
1594
|
+
throw new PapiersCliResponseValidationError(
|
|
1595
|
+
`${label} ${index} rank was not contiguous from 1.`
|
|
1596
|
+
);
|
|
1597
|
+
}
|
|
1598
|
+
validateOptionalPublicExcerpt(`${label} ${index} snippet`, item.snippet);
|
|
1599
|
+
validateSearchScore(`${label} ${index} score`, item.score);
|
|
1600
|
+
}
|
|
1601
|
+
return evidence.length;
|
|
1602
|
+
}
|
|
1603
|
+
function validateSearchEvidenceKind(label, value, id) {
|
|
1604
|
+
if (typeof id !== "string") {
|
|
1605
|
+
throw new PapiersCliResponseValidationError(`${label} id was invalid.`);
|
|
1606
|
+
}
|
|
1607
|
+
if (!SEARCH_EVIDENCE_KINDS.has(String(value))) {
|
|
1608
|
+
throw new PapiersCliResponseValidationError(
|
|
1609
|
+
`${label} was not a search evidence kind.`
|
|
1610
|
+
);
|
|
1611
|
+
}
|
|
1612
|
+
if (value === "passage" && isPublicIdForKind(id, "passage") || value === "highlight" && isPublicIdForKind(id, "highlight") || value === "equation" && isPublicIdForKind(id, "equation")) {
|
|
1613
|
+
return value;
|
|
1614
|
+
}
|
|
1615
|
+
throw new PapiersCliResponseValidationError(
|
|
1616
|
+
`${label} did not match the public id kind.`
|
|
1617
|
+
);
|
|
1618
|
+
}
|
|
1619
|
+
function validateSearchMatchedBy(label, value, options) {
|
|
1620
|
+
const values = assertArray(label, value);
|
|
1621
|
+
if (values.length === 0) {
|
|
1622
|
+
throw new PapiersCliResponseValidationError(`${label} was empty.`);
|
|
1623
|
+
}
|
|
1624
|
+
const seen = /* @__PURE__ */ new Set();
|
|
1625
|
+
for (const [index, rawReason] of values.entries()) {
|
|
1626
|
+
const reason = assertNonEmptyString(`${label} ${index}`, rawReason);
|
|
1627
|
+
if (!SEARCH_MATCH_REASONS.has(reason) || !options.allow.has(reason)) {
|
|
1628
|
+
throw new PapiersCliResponseValidationError(
|
|
1629
|
+
`${label} ${index} was not an allowed search match reason.`
|
|
1630
|
+
);
|
|
1631
|
+
}
|
|
1632
|
+
if (seen.has(reason)) {
|
|
1633
|
+
throw new PapiersCliResponseValidationError(
|
|
1634
|
+
`${label} contained duplicate match reasons.`
|
|
1635
|
+
);
|
|
1636
|
+
}
|
|
1637
|
+
seen.add(reason);
|
|
1638
|
+
}
|
|
1639
|
+
}
|
|
1640
|
+
function validateSearchScore(label, value) {
|
|
1641
|
+
if (typeof value !== "number" || !Number.isFinite(value) || value < 0 || value > 1) {
|
|
1642
|
+
throw new PapiersCliResponseValidationError(
|
|
1643
|
+
`${label} was not a finite score in [0, 1].`
|
|
1644
|
+
);
|
|
1645
|
+
}
|
|
1646
|
+
}
|
|
1335
1647
|
function assertNoInternalResponseKeys(label, value, options = {}) {
|
|
1336
1648
|
const stack = [
|
|
1337
1649
|
{ value, isRoot: true }
|
|
@@ -1472,9 +1784,9 @@ function validateOptionalDocumentIdForKind(label, value, kind) {
|
|
|
1472
1784
|
}
|
|
1473
1785
|
return void 0;
|
|
1474
1786
|
}
|
|
1475
|
-
if (kind === "conversation") {
|
|
1787
|
+
if (kind === "conversation" || kind === "note") {
|
|
1476
1788
|
throw new PapiersCliResponseValidationError(
|
|
1477
|
-
`${label} was not supported for
|
|
1789
|
+
`${label} was not supported for ${kind} items.`
|
|
1478
1790
|
);
|
|
1479
1791
|
}
|
|
1480
1792
|
return assertDocId(label, value);
|
|
@@ -1498,12 +1810,15 @@ function validateOptionalListSearchMetadata(label, value, kind) {
|
|
|
1498
1810
|
return validatePassageListSearchMetadata(label, value);
|
|
1499
1811
|
}
|
|
1500
1812
|
if (kind === "highlight") {
|
|
1501
|
-
return
|
|
1813
|
+
return validateHighlightMetadata(label, value, assertDocId);
|
|
1502
1814
|
}
|
|
1503
1815
|
if (kind === "conversation") {
|
|
1504
1816
|
validateConversationReadMetadata(label, value);
|
|
1505
1817
|
return void 0;
|
|
1506
1818
|
}
|
|
1819
|
+
if (kind === "note") {
|
|
1820
|
+
return validateNoteMetadata(label, value, assertDocId);
|
|
1821
|
+
}
|
|
1507
1822
|
return validateEquationReadMetadata(label, value);
|
|
1508
1823
|
}
|
|
1509
1824
|
function validatePassageListSearchMetadata(label, value) {
|
|
@@ -1534,11 +1849,54 @@ function validateReadSuccessItem(label, item, kind, options) {
|
|
|
1534
1849
|
return validateConversationReadSuccessItem(label, item, options);
|
|
1535
1850
|
case "equation":
|
|
1536
1851
|
return validateEquationReadSuccessItem(label, item, options);
|
|
1852
|
+
case "note":
|
|
1853
|
+
return validateNoteReadSuccessItem(label, item, options);
|
|
1537
1854
|
}
|
|
1538
1855
|
}
|
|
1856
|
+
function validateNoteReadSuccessItem(label, item, options) {
|
|
1857
|
+
rejectUnexpectedKeys(label, item, READ_SUCCESS_NOTE_ITEM_KEYS);
|
|
1858
|
+
const itemFormat = validateCliReadFormat(`${label} format`, item.format);
|
|
1859
|
+
if (!EXPECTED_NOTE_READ_FORMATS.some((format) => format === itemFormat)) {
|
|
1860
|
+
throw new PapiersCliResponseValidationError(
|
|
1861
|
+
`${label} format was not supported for note reads.`
|
|
1862
|
+
);
|
|
1863
|
+
}
|
|
1864
|
+
if (options.expectedFormat !== void 0 && !isResolvedReadFormatAllowed(itemFormat, options.expectedFormat)) {
|
|
1865
|
+
throw new PapiersCliResponseValidationError(
|
|
1866
|
+
`${label} did not echo the requested read format.`
|
|
1867
|
+
);
|
|
1868
|
+
}
|
|
1869
|
+
const contentResult = validateReadContent(label, item, itemFormat, {
|
|
1870
|
+
expectedMaxCharsPerItem: options.expectedMaxCharsPerItem
|
|
1871
|
+
});
|
|
1872
|
+
validateReadItemCursor(
|
|
1873
|
+
label,
|
|
1874
|
+
item.nextCursor,
|
|
1875
|
+
itemFormat,
|
|
1876
|
+
contentResult.truncated,
|
|
1877
|
+
options.singleItemRead
|
|
1878
|
+
);
|
|
1879
|
+
validateNoteMetadata(
|
|
1880
|
+
`${label} metadata`,
|
|
1881
|
+
item.metadata,
|
|
1882
|
+
assertDocumentReadIdentifier
|
|
1883
|
+
);
|
|
1884
|
+
const hasReadTruncatedWarning = validateOptionalReadWarnings(
|
|
1885
|
+
`${label} warnings`,
|
|
1886
|
+
item.warnings,
|
|
1887
|
+
itemFormat,
|
|
1888
|
+
"note"
|
|
1889
|
+
);
|
|
1890
|
+
if (hasReadTruncatedWarning && !contentResult.truncated) {
|
|
1891
|
+
throw new PapiersCliResponseValidationError(
|
|
1892
|
+
`${label} returned read_truncated without truncated=true.`
|
|
1893
|
+
);
|
|
1894
|
+
}
|
|
1895
|
+
return { ...contentResult, contentRead: true };
|
|
1896
|
+
}
|
|
1539
1897
|
function validateDocumentReadSuccessItem(label, item, options) {
|
|
1540
1898
|
rejectUnexpectedKeys(label, item, READ_SUCCESS_DOCUMENT_ITEM_KEYS);
|
|
1541
|
-
|
|
1899
|
+
assertDocumentReadIdentifier(`${label} id`, item.id);
|
|
1542
1900
|
const itemFormat = validateCliReadFormat(`${label} format`, item.format);
|
|
1543
1901
|
if (options.expectedFormat !== void 0 && !isResolvedReadFormatAllowed(itemFormat, options.expectedFormat)) {
|
|
1544
1902
|
throw new PapiersCliResponseValidationError(
|
|
@@ -1660,11 +2018,19 @@ function validateHighlightReadSuccessItem(label, item, options) {
|
|
|
1660
2018
|
}
|
|
1661
2019
|
if (itemFormat === "plain") {
|
|
1662
2020
|
const contentResult = validatePlainReadContentFields(label, item);
|
|
1663
|
-
|
|
2021
|
+
validateHighlightMetadata(
|
|
2022
|
+
`${label} metadata`,
|
|
2023
|
+
item.metadata,
|
|
2024
|
+
assertDocumentReadIdentifier
|
|
2025
|
+
);
|
|
1664
2026
|
return { ...contentResult, contentRead: true };
|
|
1665
2027
|
}
|
|
1666
2028
|
rejectMetadataOnlyContentFields(label, item);
|
|
1667
|
-
|
|
2029
|
+
validateHighlightMetadata(
|
|
2030
|
+
`${label} metadata`,
|
|
2031
|
+
item.metadata,
|
|
2032
|
+
assertDocumentReadIdentifier
|
|
2033
|
+
);
|
|
1668
2034
|
return { returnedChars: 0, truncated: false, contentRead: false };
|
|
1669
2035
|
}
|
|
1670
2036
|
function validateConversationReadSuccessItem(label, item, options) {
|
|
@@ -1706,18 +2072,21 @@ function validateEquationReadSuccessItem(label, item, options) {
|
|
|
1706
2072
|
return { returnedChars: 0, truncated: false, contentRead: false };
|
|
1707
2073
|
}
|
|
1708
2074
|
function validateReadItemKind(label, value, id) {
|
|
1709
|
-
const expectedKind =
|
|
1710
|
-
if (expectedKind === null || value !== expectedKind || value !== "document" && value !== "passage" && value !== "highlight" && value !== "conversation" && value !== "equation") {
|
|
2075
|
+
const expectedKind = readKindForIdentifier(id);
|
|
2076
|
+
if (expectedKind === null || value !== expectedKind || value !== "document" && value !== "passage" && value !== "highlight" && value !== "conversation" && value !== "equation" && value !== "note") {
|
|
1711
2077
|
throw new PapiersCliResponseValidationError(
|
|
1712
|
-
`${label} did not match the
|
|
2078
|
+
`${label} did not match the read identifier kind.`
|
|
1713
2079
|
);
|
|
1714
2080
|
}
|
|
1715
2081
|
return value;
|
|
1716
2082
|
}
|
|
1717
|
-
function
|
|
2083
|
+
function validateHighlightMetadata(label, value, validateDocumentId) {
|
|
1718
2084
|
const metadata = assertRecord(label, value);
|
|
1719
2085
|
rejectUnexpectedKeys(label, metadata, HIGHLIGHT_READ_METADATA_KEYS);
|
|
1720
|
-
const documentId =
|
|
2086
|
+
const documentId = validateDocumentId(
|
|
2087
|
+
`${label}.documentId`,
|
|
2088
|
+
metadata.documentId
|
|
2089
|
+
);
|
|
1721
2090
|
validateOptionalNullableString(
|
|
1722
2091
|
`${label}.documentTitle`,
|
|
1723
2092
|
metadata.documentTitle
|
|
@@ -1736,6 +2105,8 @@ function validateHighlightReadMetadata(label, value) {
|
|
|
1736
2105
|
`${label}.quoteContext`,
|
|
1737
2106
|
metadata.quoteContext
|
|
1738
2107
|
);
|
|
2108
|
+
validateOptionalNullableString(`${label}.quotePrefix`, metadata.quotePrefix);
|
|
2109
|
+
validateOptionalNullableString(`${label}.quoteSuffix`, metadata.quoteSuffix);
|
|
1739
2110
|
validateOptionalTimestamp(`${label}.createdAt`, metadata.createdAt);
|
|
1740
2111
|
validateOptionalTimestamp(`${label}.updatedAt`, metadata.updatedAt);
|
|
1741
2112
|
return documentId;
|
|
@@ -1767,6 +2138,21 @@ function validateEquationReadMetadata(label, value) {
|
|
|
1767
2138
|
validateOptionalTimestamp(`${label}.updatedAt`, metadata.updatedAt);
|
|
1768
2139
|
return documentId;
|
|
1769
2140
|
}
|
|
2141
|
+
function validateNoteMetadata(label, value, validateDocumentId) {
|
|
2142
|
+
const metadata = assertRecord(label, value);
|
|
2143
|
+
rejectUnexpectedKeys(label, metadata, NOTE_READ_METADATA_KEYS);
|
|
2144
|
+
const documentId = metadata.documentId === null ? void 0 : validateDocumentId(`${label}.documentId`, metadata.documentId);
|
|
2145
|
+
if (metadata.attachedTitle !== null && typeof metadata.attachedTitle !== "string") {
|
|
2146
|
+
throw new PapiersCliResponseValidationError(
|
|
2147
|
+
`${label}.attachedTitle was not a string or null.`
|
|
2148
|
+
);
|
|
2149
|
+
}
|
|
2150
|
+
assertTimestampString(`${label}.editedAt`, metadata.editedAt);
|
|
2151
|
+
assertTimestampString(`${label}.createdAt`, metadata.createdAt);
|
|
2152
|
+
assertTimestampString(`${label}.updatedAt`, metadata.updatedAt);
|
|
2153
|
+
assertNonEmptyString(`${label}.title`, metadata.title);
|
|
2154
|
+
return documentId;
|
|
2155
|
+
}
|
|
1770
2156
|
function rejectUnexpectedContent(label, item) {
|
|
1771
2157
|
if (item.content !== void 0 && item.content !== null) {
|
|
1772
2158
|
throw new PapiersCliResponseValidationError(
|
|
@@ -1994,19 +2380,20 @@ function validateReadUsage(label, rawUsage, options) {
|
|
|
1994
2380
|
function validateReadItemError(label, value, kind, expectedFormat) {
|
|
1995
2381
|
const error = assertRecord(label, value);
|
|
1996
2382
|
rejectUnexpectedKeys(label, error, READ_ITEM_ERROR_KEYS);
|
|
1997
|
-
|
|
1998
|
-
|
|
1999
|
-
|
|
2000
|
-
|
|
2001
|
-
|
|
2002
|
-
|
|
2383
|
+
const sourceSupersededAllowed = error.code === DOCUMENT_READ_SOURCE_SUPERSEDED_CODE && (kind === "document" || kind === "passage" || kind === "note" || kind === "conversation");
|
|
2384
|
+
const contentLimitAllowed = error.code === CONVERSATION_READ_CONTENT_LIMIT_CODE && kind === "conversation";
|
|
2385
|
+
const requestLimitAllowed = error.code === CONVERSATION_READ_REQUEST_LIMIT_CODE && kind === "conversation";
|
|
2386
|
+
if (error.code !== DOCUMENT_READ_NOT_FOUND_CODE && !sourceSupersededAllowed && !contentLimitAllowed && !requestLimitAllowed) {
|
|
2387
|
+
throw new PapiersCliResponseValidationError(
|
|
2388
|
+
`${label}.code was not a supported read error code.`
|
|
2389
|
+
);
|
|
2003
2390
|
}
|
|
2004
|
-
if (expectedFormat === "metadata" && error.code === DOCUMENT_READ_SOURCE_SUPERSEDED_CODE) {
|
|
2391
|
+
if (expectedFormat === "metadata" && (error.code === DOCUMENT_READ_SOURCE_SUPERSEDED_CODE || error.code === CONVERSATION_READ_CONTENT_LIMIT_CODE || error.code === CONVERSATION_READ_REQUEST_LIMIT_CODE)) {
|
|
2005
2392
|
throw new PapiersCliResponseValidationError(
|
|
2006
2393
|
`${label}.code was not supported for metadata reads.`
|
|
2007
2394
|
);
|
|
2008
2395
|
}
|
|
2009
|
-
const expectedMessage = error.code === DOCUMENT_READ_NOT_FOUND_CODE ? readNotFoundMessageForKind(kind) : kind === "passage" ? PASSAGE_READ_CONTENT_UNAVAILABLE_MESSAGE : DOCUMENT_READ_SOURCE_SUPERSEDED_MESSAGE;
|
|
2396
|
+
const expectedMessage = error.code === DOCUMENT_READ_NOT_FOUND_CODE ? readNotFoundMessageForKind(kind) : error.code === CONVERSATION_READ_CONTENT_LIMIT_CODE ? CONVERSATION_READ_CONTENT_LIMIT_MESSAGE : error.code === CONVERSATION_READ_REQUEST_LIMIT_CODE ? CONVERSATION_READ_REQUEST_LIMIT_MESSAGE : kind === "conversation" ? CONVERSATION_READ_SOURCE_SUPERSEDED_MESSAGE : kind === "passage" ? PASSAGE_READ_CONTENT_UNAVAILABLE_MESSAGE : kind === "note" ? NOTE_READ_SOURCE_SUPERSEDED_MESSAGE : DOCUMENT_READ_SOURCE_SUPERSEDED_MESSAGE;
|
|
2010
2397
|
if (error.message !== expectedMessage) {
|
|
2011
2398
|
throw new PapiersCliResponseValidationError(
|
|
2012
2399
|
`${label}.message was not a supported read error message.`
|
|
@@ -2031,6 +2418,8 @@ function readNotFoundMessageForKind(kind) {
|
|
|
2031
2418
|
return CONVERSATION_READ_NOT_FOUND_MESSAGE;
|
|
2032
2419
|
case "equation":
|
|
2033
2420
|
return EQUATION_READ_NOT_FOUND_MESSAGE;
|
|
2421
|
+
case "note":
|
|
2422
|
+
return NOTE_READ_NOT_FOUND_MESSAGE;
|
|
2034
2423
|
}
|
|
2035
2424
|
}
|
|
2036
2425
|
function validateOptionalSearchQuality(label, value) {
|
|
@@ -2095,7 +2484,7 @@ function validateOptionalReadWarnings(label, value, format, kind) {
|
|
|
2095
2484
|
);
|
|
2096
2485
|
}
|
|
2097
2486
|
hasReadTruncatedWarning = true;
|
|
2098
|
-
const expectedMessage = kind === "document" ? DOCUMENT_READ_TRUNCATED_WARNING_MESSAGE : PASSAGE_READ_TRUNCATED_WARNING_MESSAGE;
|
|
2487
|
+
const expectedMessage = kind === "document" ? DOCUMENT_READ_TRUNCATED_WARNING_MESSAGE : kind === "passage" ? PASSAGE_READ_TRUNCATED_WARNING_MESSAGE : NOTE_READ_TRUNCATED_WARNING_MESSAGE;
|
|
2099
2488
|
if (warning.message !== expectedMessage) {
|
|
2100
2489
|
throw new PapiersCliResponseValidationError(
|
|
2101
2490
|
`${label} ${index}.message was not a supported warning message.`
|
|
@@ -2515,10 +2904,18 @@ function assertDocId(label, value) {
|
|
|
2515
2904
|
}
|
|
2516
2905
|
return value;
|
|
2517
2906
|
}
|
|
2518
|
-
function
|
|
2519
|
-
if (typeof value !== "string" ||
|
|
2907
|
+
function assertDocumentReadIdentifier(label, value) {
|
|
2908
|
+
if (typeof value !== "string" || !isDocumentReadIdentifier(value)) {
|
|
2520
2909
|
throw new PapiersCliResponseValidationError(
|
|
2521
|
-
`${label} was not a
|
|
2910
|
+
`${label} was not a doc_* public id or papiers://item locator.`
|
|
2911
|
+
);
|
|
2912
|
+
}
|
|
2913
|
+
return value;
|
|
2914
|
+
}
|
|
2915
|
+
function assertReadIdentifier(label, value) {
|
|
2916
|
+
if (typeof value !== "string" || readKindForIdentifier(value) === null) {
|
|
2917
|
+
throw new PapiersCliResponseValidationError(
|
|
2918
|
+
`${label} was not a supported read identifier.`
|
|
2522
2919
|
);
|
|
2523
2920
|
}
|
|
2524
2921
|
return value;
|
|
@@ -2662,7 +3059,7 @@ async function readDocuments(config, fetchImpl, request) {
|
|
|
2662
3059
|
"/api/v1/papiers/read",
|
|
2663
3060
|
{ method: "POST", body: request, retryable: true }
|
|
2664
3061
|
);
|
|
2665
|
-
const readKind =
|
|
3062
|
+
const readKind = readKindForIdentifier(request.ids[0] ?? "");
|
|
2666
3063
|
assertPapiersReadResponse("read", body, request.ids, {
|
|
2667
3064
|
// Every kind resolves an omitted format server-side (auto semantics),
|
|
2668
3065
|
// so there is nothing to echo-check unless the caller pinned one;
|
|
@@ -2709,22 +3106,18 @@ function expectedKindForListSearchRequest(request) {
|
|
|
2709
3106
|
function expectedKindsForSearchRequest(request) {
|
|
2710
3107
|
const kinds = request.kinds;
|
|
2711
3108
|
if (kinds === void 0) {
|
|
2712
|
-
return {
|
|
2713
|
-
expectedKinds: /* @__PURE__ */ new Set([
|
|
2714
|
-
"document",
|
|
2715
|
-
"passage",
|
|
2716
|
-
"highlight",
|
|
2717
|
-
"conversation"
|
|
2718
|
-
])
|
|
2719
|
-
};
|
|
3109
|
+
return { expectedKinds: /* @__PURE__ */ new Set(["document", "conversation", "note"]) };
|
|
2720
3110
|
}
|
|
2721
|
-
if (!Array.isArray(kinds) || kinds.length
|
|
2722
|
-
|
|
3111
|
+
if (!Array.isArray(kinds) || kinds.length === 0) {
|
|
3112
|
+
throw new CliUsageError(
|
|
3113
|
+
"Public search requests must specify at least one supported kind."
|
|
3114
|
+
);
|
|
2723
3115
|
}
|
|
2724
|
-
|
|
2725
|
-
|
|
3116
|
+
const rawKinds = kinds;
|
|
3117
|
+
for (const kind of rawKinds) {
|
|
3118
|
+
if (kind === "document") {
|
|
2726
3119
|
throw new CliUsageError(
|
|
2727
|
-
|
|
3120
|
+
"Unified public search does not support kind document; omit kinds to search titles plus content."
|
|
2728
3121
|
);
|
|
2729
3122
|
}
|
|
2730
3123
|
if (!PUBLIC_KINDS.includes(kind)) {
|
|
@@ -2733,14 +3126,19 @@ function expectedKindsForSearchRequest(request) {
|
|
|
2733
3126
|
);
|
|
2734
3127
|
}
|
|
2735
3128
|
}
|
|
2736
|
-
|
|
2737
|
-
|
|
2738
|
-
|
|
3129
|
+
const expectedKinds = /* @__PURE__ */ new Set();
|
|
3130
|
+
for (const kind of rawKinds) {
|
|
3131
|
+
expectedKinds.add(
|
|
3132
|
+
kind === "conversation" || kind === "note" ? kind : "document"
|
|
3133
|
+
);
|
|
3134
|
+
}
|
|
3135
|
+
const [onlyKind] = expectedKinds;
|
|
3136
|
+
return expectedKinds.size === 1 ? { expectedKind: onlyKind } : { expectedKinds };
|
|
2739
3137
|
}
|
|
2740
3138
|
async function requestPapiersApi(config, fetchImpl, path, init) {
|
|
2741
3139
|
if (!config.token) {
|
|
2742
3140
|
throw new CliUsageError(
|
|
2743
|
-
`${TOKEN_ENV_VAR} is
|
|
3141
|
+
`${TOKEN_ENV_VAR} is not set. Run papiers auth login, or set ${TOKEN_ENV_VAR}, then retry.`
|
|
2744
3142
|
);
|
|
2745
3143
|
}
|
|
2746
3144
|
return requestPapiersApiWithBearer(
|
|
@@ -2862,7 +3260,7 @@ var PMID_PATTERN = /^\d+$/u;
|
|
|
2862
3260
|
var YEAR_PATTERN = /^\d{4}$/u;
|
|
2863
3261
|
var MIN_PUBLIC_YEAR = 1;
|
|
2864
3262
|
var MAX_PUBLIC_YEAR = 9999;
|
|
2865
|
-
var
|
|
3263
|
+
var FORMER_FILTER_FIELD_ALIASES = {
|
|
2866
3264
|
arxiv_id: "arxivId",
|
|
2867
3265
|
last_engaged_at: "lastEngagedAt",
|
|
2868
3266
|
published_date: "publishedDate",
|
|
@@ -2871,13 +3269,27 @@ var DOCUMENT_FILTER_FIELD_ALIASES = {
|
|
|
2871
3269
|
source_family: "sourceFamily",
|
|
2872
3270
|
year: "publishedYear"
|
|
2873
3271
|
};
|
|
2874
|
-
|
|
2875
|
-
|
|
2876
|
-
|
|
3272
|
+
function didYouMeanFilterField(field) {
|
|
3273
|
+
const suggestion = FORMER_FILTER_FIELD_ALIASES[field];
|
|
3274
|
+
return suggestion ? ` Did you mean "${suggestion}"?` : "";
|
|
3275
|
+
}
|
|
2877
3276
|
function parseDocumentFilterExpression(expression) {
|
|
3277
|
+
if (isImplicitAuthorEqualityFilterExpression(expression)) {
|
|
3278
|
+
throw new CliUsageError(
|
|
3279
|
+
'Use "author.contains=<name-or-handle>" for author searches, or "author.eq=<full-author-key>" for exact author-key matches.'
|
|
3280
|
+
);
|
|
3281
|
+
}
|
|
2878
3282
|
const filter = parseFilterExpression(expression);
|
|
2879
3283
|
return normalizeSupportedDocumentFilter(filter);
|
|
2880
3284
|
}
|
|
3285
|
+
function isImplicitAuthorEqualityFilterExpression(expression) {
|
|
3286
|
+
const trimmed = expression.trim();
|
|
3287
|
+
const equalsIndex = trimmed.indexOf("=");
|
|
3288
|
+
if (equalsIndex < 0) {
|
|
3289
|
+
return false;
|
|
3290
|
+
}
|
|
3291
|
+
return trimmed.slice(0, equalsIndex).trim() === "author";
|
|
3292
|
+
}
|
|
2881
3293
|
function parseFilterExpression(expression) {
|
|
2882
3294
|
const parsed = parseFilterParts(expression);
|
|
2883
3295
|
const field = parsed.field.trim();
|
|
@@ -2903,57 +3315,52 @@ function parseFilterExpression(expression) {
|
|
|
2903
3315
|
};
|
|
2904
3316
|
}
|
|
2905
3317
|
function normalizeSupportedDocumentFilter(filter) {
|
|
2906
|
-
const
|
|
2907
|
-
const
|
|
2908
|
-
const allowedOperators = EXPECTED_DOCUMENT_FILTER_OPERATORS[canonicalField];
|
|
3318
|
+
const field = filter.field;
|
|
3319
|
+
const allowedOperators = EXPECTED_DOCUMENT_FILTER_OPERATORS[field];
|
|
2909
3320
|
if (!allowedOperators) {
|
|
2910
3321
|
throw new CliUsageError(
|
|
2911
3322
|
`Unsupported public document filter field "${filter.field}". Supported fields: ${Object.keys(
|
|
2912
3323
|
EXPECTED_DOCUMENT_FILTER_OPERATORS
|
|
2913
|
-
).join(", ")}
|
|
3324
|
+
).join(", ")}.${didYouMeanFilterField(filter.field)}`
|
|
2914
3325
|
);
|
|
2915
3326
|
}
|
|
2916
|
-
if (!allowedOperators.includes(
|
|
2917
|
-
canonicalFilter.op
|
|
2918
|
-
)) {
|
|
3327
|
+
if (!allowedOperators.includes(filter.op)) {
|
|
2919
3328
|
throw new CliUsageError(
|
|
2920
|
-
`Operator "${
|
|
3329
|
+
`Operator "${filter.op}" is not supported for public document filter field "${filter.field}". Supported operators: ${allowedOperators.join(
|
|
2921
3330
|
", "
|
|
2922
3331
|
)}.`
|
|
2923
3332
|
);
|
|
2924
3333
|
}
|
|
2925
|
-
|
|
3334
|
+
const documentFilter = { ...filter, field };
|
|
3335
|
+
switch (field) {
|
|
2926
3336
|
case "id":
|
|
2927
3337
|
return normalizeStringDocumentFilter(
|
|
2928
|
-
|
|
3338
|
+
documentFilter,
|
|
2929
3339
|
normalizeDocumentIdValue
|
|
2930
3340
|
);
|
|
2931
3341
|
case "doi":
|
|
2932
|
-
return normalizeStringDocumentFilter(
|
|
3342
|
+
return normalizeStringDocumentFilter(documentFilter, normalizeDoiOrNull);
|
|
2933
3343
|
case "arxivId":
|
|
2934
3344
|
return normalizeStringDocumentFilter(
|
|
2935
|
-
|
|
3345
|
+
documentFilter,
|
|
2936
3346
|
normalizeArxivOrNull
|
|
2937
3347
|
);
|
|
2938
3348
|
case "pmid":
|
|
2939
|
-
return normalizeStringDocumentFilter(
|
|
2940
|
-
canonicalFilter,
|
|
2941
|
-
normalizePmidOrNull
|
|
2942
|
-
);
|
|
3349
|
+
return normalizeStringDocumentFilter(documentFilter, normalizePmidOrNull);
|
|
2943
3350
|
case "publishedDate":
|
|
2944
|
-
return normalizePublishedDateFilter(
|
|
3351
|
+
return normalizePublishedDateFilter(documentFilter);
|
|
2945
3352
|
case "publishedYear":
|
|
2946
|
-
return normalizePublishedYearFilter(
|
|
3353
|
+
return normalizePublishedYearFilter(documentFilter);
|
|
2947
3354
|
case "sourceDomain":
|
|
2948
|
-
return normalizeSourceDomainFilter(
|
|
3355
|
+
return normalizeSourceDomainFilter(documentFilter);
|
|
2949
3356
|
case "annotated":
|
|
2950
3357
|
case "engaged":
|
|
2951
|
-
return normalizeBooleanDocumentFilter(
|
|
3358
|
+
return normalizeBooleanDocumentFilter(documentFilter);
|
|
2952
3359
|
case "lastEngagedAt":
|
|
2953
|
-
return normalizeLastEngagedAtFilter(
|
|
3360
|
+
return normalizeLastEngagedAtFilter(documentFilter);
|
|
2954
3361
|
default:
|
|
2955
3362
|
return normalizeStringDocumentFilter(
|
|
2956
|
-
|
|
3363
|
+
documentFilter,
|
|
2957
3364
|
normalizeNonEmptyString
|
|
2958
3365
|
);
|
|
2959
3366
|
}
|
|
@@ -3001,12 +3408,6 @@ function normalizeBooleanDocumentFilter(filter) {
|
|
|
3001
3408
|
}
|
|
3002
3409
|
throw invalidFilterValue(filter);
|
|
3003
3410
|
}
|
|
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
3411
|
function normalizePublishedDateFilter(filter) {
|
|
3011
3412
|
const normalized = normalizePapiersPublicDateFilter(
|
|
3012
3413
|
filter.op,
|
|
@@ -3293,21 +3694,22 @@ function parseScalar(rawValue) {
|
|
|
3293
3694
|
|
|
3294
3695
|
// src/args.ts
|
|
3295
3696
|
var BOOLEAN_FLAGS = /* @__PURE__ */ new Set([
|
|
3697
|
+
"all",
|
|
3296
3698
|
"force",
|
|
3297
3699
|
"help",
|
|
3298
3700
|
"doc-ids",
|
|
3701
|
+
"evidence-ids",
|
|
3702
|
+
"highlight-ids",
|
|
3299
3703
|
"ids",
|
|
3300
3704
|
"ids0",
|
|
3301
3705
|
"input0",
|
|
3302
3706
|
"json",
|
|
3707
|
+
"passage-ids",
|
|
3303
3708
|
"pretty",
|
|
3304
|
-
"stdin",
|
|
3305
|
-
"token-stdin",
|
|
3306
3709
|
"fail-fast",
|
|
3307
3710
|
"version"
|
|
3308
3711
|
]);
|
|
3309
3712
|
var VALUE_FLAGS = /* @__PURE__ */ new Set([
|
|
3310
|
-
"api-base-url",
|
|
3311
3713
|
"api-url",
|
|
3312
3714
|
"cursor",
|
|
3313
3715
|
"document-id",
|
|
@@ -3326,8 +3728,13 @@ var VALUE_FLAGS = /* @__PURE__ */ new Set([
|
|
|
3326
3728
|
"since"
|
|
3327
3729
|
]);
|
|
3328
3730
|
var SECRET_ARG_FLAGS = /* @__PURE__ */ new Set(["pat", "token", "api-token"]);
|
|
3329
|
-
var GLOBAL_VALUE_FLAGS = /* @__PURE__ */ new Set(["api-
|
|
3731
|
+
var GLOBAL_VALUE_FLAGS = /* @__PURE__ */ new Set(["api-url"]);
|
|
3330
3732
|
var NO_COMMAND_VALUE_FLAGS = /* @__PURE__ */ new Set([...GLOBAL_VALUE_FLAGS]);
|
|
3733
|
+
var REMOVED_FLAG_HINTS = {
|
|
3734
|
+
"api-base-url": "Use --api-url instead.",
|
|
3735
|
+
"token-stdin": "papiers auth login reads the token from stdin \u2014 no flag needed.",
|
|
3736
|
+
stdin: "papiers auth login reads the token from stdin \u2014 no flag needed."
|
|
3737
|
+
};
|
|
3331
3738
|
var NO_COMMAND_BOOLEAN_FLAGS = /* @__PURE__ */ new Set(["help", "json"]);
|
|
3332
3739
|
var IDS_PIPELINE_BOOLEAN_FLAGS = /* @__PURE__ */ new Set([
|
|
3333
3740
|
"help",
|
|
@@ -3338,6 +3745,12 @@ var IDS_PIPELINE_BOOLEAN_FLAGS = /* @__PURE__ */ new Set([
|
|
|
3338
3745
|
"json",
|
|
3339
3746
|
"pretty"
|
|
3340
3747
|
]);
|
|
3748
|
+
var SEARCH_IDS_PIPELINE_BOOLEAN_FLAGS = /* @__PURE__ */ new Set([
|
|
3749
|
+
...IDS_PIPELINE_BOOLEAN_FLAGS,
|
|
3750
|
+
"evidence-ids",
|
|
3751
|
+
"highlight-ids",
|
|
3752
|
+
"passage-ids"
|
|
3753
|
+
]);
|
|
3341
3754
|
var LIST_VALUE_FLAGS = /* @__PURE__ */ new Set([
|
|
3342
3755
|
...GLOBAL_VALUE_FLAGS,
|
|
3343
3756
|
"cursor",
|
|
@@ -3378,122 +3791,320 @@ var READ_BOOLEAN_FLAGS = /* @__PURE__ */ new Set([
|
|
|
3378
3791
|
]);
|
|
3379
3792
|
var AUTH_LOGIN_BOOLEAN_FLAGS = /* @__PURE__ */ new Set([
|
|
3380
3793
|
...NO_COMMAND_BOOLEAN_FLAGS,
|
|
3381
|
-
"force"
|
|
3382
|
-
"stdin",
|
|
3383
|
-
"token-stdin"
|
|
3794
|
+
"force"
|
|
3384
3795
|
]);
|
|
3385
|
-
var
|
|
3386
|
-
var PUBLIC_KIND_ALIASES = /* @__PURE__ */ new Map([
|
|
3387
|
-
["document", "document"],
|
|
3388
|
-
["documents", "document"],
|
|
3796
|
+
var FORMER_KIND_ALIASES = /* @__PURE__ */ new Map([
|
|
3389
3797
|
["doc", "document"],
|
|
3390
3798
|
["docs", "document"],
|
|
3391
|
-
["
|
|
3799
|
+
["documents", "document"],
|
|
3392
3800
|
["passages", "passage"],
|
|
3393
|
-
["highlight", "highlight"],
|
|
3394
|
-
["highlights", "highlight"],
|
|
3395
3801
|
["annotation", "highlight"],
|
|
3396
3802
|
["annotations", "highlight"],
|
|
3397
|
-
["
|
|
3398
|
-
["conversations", "conversation"],
|
|
3803
|
+
["highlights", "highlight"],
|
|
3399
3804
|
["chat", "conversation"],
|
|
3400
3805
|
["chats", "conversation"],
|
|
3401
|
-
["
|
|
3402
|
-
["equations", "equation"]
|
|
3806
|
+
["conversations", "conversation"],
|
|
3807
|
+
["equations", "equation"],
|
|
3808
|
+
["notes", "note"]
|
|
3403
3809
|
]);
|
|
3404
3810
|
var MULTI_SEARCH_KINDS = [
|
|
3405
3811
|
"passage",
|
|
3406
3812
|
"highlight",
|
|
3407
|
-
"conversation"
|
|
3813
|
+
"conversation",
|
|
3814
|
+
"equation",
|
|
3815
|
+
"note"
|
|
3408
3816
|
];
|
|
3409
|
-
var
|
|
3817
|
+
var GLOBAL_HELP = `Papiers CLI: search and read your library from the terminal.
|
|
3818
|
+
Your saved papers, highlights, notes, and conversations (your chats) \u2014 for you or an AI agent.
|
|
3410
3819
|
|
|
3411
|
-
|
|
3412
|
-
|
|
3820
|
+
GETTING STARTED
|
|
3821
|
+
papiers auth login Sign in with a token from Papiers (Settings -> API tokens)
|
|
3822
|
+
papiers list --limit 5 --pretty Your most recent documents
|
|
3823
|
+
papiers search "your topic" --pretty Search across your library
|
|
3413
3824
|
|
|
3414
|
-
|
|
3415
|
-
|
|
3416
|
-
|
|
3417
|
-
|
|
3418
|
-
|
|
3419
|
-
|
|
3420
|
-
|
|
3825
|
+
COMMANDS
|
|
3826
|
+
search Search across your library
|
|
3827
|
+
list List your documents, highlights, notes, and conversations
|
|
3828
|
+
read Print a document, highlight, note, or conversation
|
|
3829
|
+
browse Page through an earlier search's results
|
|
3830
|
+
auth Sign in, check status, or sign out
|
|
3831
|
+
tokens List or revoke your API tokens
|
|
3832
|
+
doctor Check your setup, connection, and what's available
|
|
3833
|
+
version Print the CLI version
|
|
3834
|
+
|
|
3835
|
+
papiers <command> --help full options and examples for a command
|
|
3836
|
+
papiers help --all everything, in one page
|
|
3837
|
+
|
|
3838
|
+
OUTPUT
|
|
3839
|
+
Commands print JSON by default \u2014 built for scripts and agents.
|
|
3840
|
+
--pretty human-readable output
|
|
3841
|
+
--ids / --doc-ids pipe result IDs into the next command
|
|
3842
|
+
|
|
3843
|
+
SIGNING IN
|
|
3844
|
+
Signing in saves your token on this machine.
|
|
3845
|
+
For scripts or an AI agent, set PAPIERS_TOKEN instead.
|
|
3846
|
+
|
|
3847
|
+
Exit codes: 0 ok \xB7 1 command or API failure \xB7 2 bad usage`;
|
|
3848
|
+
var OUTPUT_OPTS = ` --json machine-readable JSON (the default)
|
|
3849
|
+
--pretty human-readable text
|
|
3850
|
+
--ids result/item IDs, one per line, with their native prefix
|
|
3851
|
+
--ids0 the same IDs, NUL-separated, for \`xargs -0\`
|
|
3852
|
+
--doc-ids parent document IDs only (doc_\u2026), deduped; conversation hits are skipped`;
|
|
3853
|
+
var SEARCH_OUTPUT_OPTS = `${OUTPUT_OPTS}
|
|
3854
|
+
--passage-ids matching passage evidence IDs, flattened in result order
|
|
3855
|
+
--highlight-ids matching highlight evidence IDs, flattened in result order
|
|
3856
|
+
--evidence-ids all matching evidence IDs, flattened in result order`;
|
|
3857
|
+
var HELP_TOPICS = {
|
|
3858
|
+
search: `papiers search \u2014 search across your library.
|
|
3859
|
+
|
|
3860
|
+
USAGE
|
|
3861
|
+
papiers search QUERY [--kind KIND ...] [--filter FIELD.OP=VALUE ...] [--limit N] [--pretty|--json|--ids|--ids0|--doc-ids|--passage-ids|--highlight-ids|--evidence-ids]
|
|
3862
|
+
|
|
3863
|
+
OPTIONS
|
|
3864
|
+
--kind KIND what to search. Defaults to all \u2014 your passages, highlights,
|
|
3865
|
+
equations, notes, conversations, and matching titles. Or focus on one:
|
|
3866
|
+
passage \xB7 highlight \xB7 conversation \xB7 equation \xB7 note.
|
|
3867
|
+
--filter FIELD.OP=VALUE narrow parent documents \u2014 repeatable, up to 25.
|
|
3868
|
+
e.g. --filter publishedYear.gte=2020 --filter author.contains=hinton. Fields/ops: help --all.
|
|
3869
|
+
--document-id ID scope to documents: doc_\u2026 (comma-separated or repeated), or @-/@file.
|
|
3870
|
+
--limit N max results, 1\u201350.
|
|
3871
|
+
${SEARCH_OUTPUT_OPTS}
|
|
3872
|
+
|
|
3873
|
+
EXAMPLES
|
|
3874
|
+
papiers search "mixture of experts" --pretty
|
|
3875
|
+
papiers search "capacity factors" --kind passage --document-id doc_<id> --json
|
|
3876
|
+
papiers search "dropout" --filter author.contains=hinton --json
|
|
3877
|
+
papiers search "diffusion" --filter venue.contains=neurips --json
|
|
3878
|
+
papiers search retrieval --kind passage --limit 5 --passage-ids | papiers read @- --format plain --json
|
|
3879
|
+
|
|
3880
|
+
When capabilities.searchResultsBrowse.enabled is true, a search may return ranking.searchId \u2014 pass it to \`papiers browse\` for more pages.`,
|
|
3881
|
+
list: `papiers list \u2014 list your documents, highlights, notes, and conversations.
|
|
3882
|
+
|
|
3883
|
+
USAGE
|
|
3884
|
+
papiers list [--kind KIND] [--limit N] [--cursor CURSOR] [--pretty|--json|--ids|--ids0|--doc-ids]
|
|
3885
|
+
papiers list --kind document [--filter FIELD.OP=VALUE ...] [--order-by KEY] [--document-id doc_\u2026|@-|@file]
|
|
3886
|
+
papiers list --kind highlight|conversation [--since WHEN]
|
|
3887
|
+
|
|
3888
|
+
OPTIONS
|
|
3889
|
+
--kind KIND document (default) \xB7 passage \xB7 highlight \xB7 conversation \xB7 equation \xB7 note.
|
|
3890
|
+
--filter FIELD.OP=VALUE narrow document results \u2014 repeatable, up to 25. document kind only.
|
|
3891
|
+
e.g. --filter lastEngagedAt.gte=30d --filter annotated=true. Fields/ops: help --all.
|
|
3892
|
+
--order-by KEY addedAt:desc (default) or lastEngagedAt:desc. document kind only.
|
|
3893
|
+
--document-id ID scope to documents: doc_\u2026 (comma-separated or repeated), or @-/@file.
|
|
3894
|
+
document and highlight only.
|
|
3895
|
+
--since WHEN only items at or after an ISO 8601 time, or an Nd shorthand (e.g. 30d).
|
|
3896
|
+
highlight and conversation only.
|
|
3897
|
+
--limit N max results, 1\u201350.
|
|
3898
|
+
--cursor CURSOR fetch the next page \u2014 use page.nextCursor from the previous response.
|
|
3899
|
+
${OUTPUT_OPTS}
|
|
3900
|
+
|
|
3901
|
+
EXAMPLES
|
|
3902
|
+
papiers list --limit 5 --pretty
|
|
3903
|
+
papiers list --kind highlight --since 30d --pretty
|
|
3904
|
+
papiers list --kind document --filter lastEngagedAt.gte=30d --json
|
|
3905
|
+
papiers list --kind document --filter annotated=true --json`,
|
|
3906
|
+
read: `papiers read \u2014 print documents, highlights, notes, conversations, passages, or equations.
|
|
3907
|
+
|
|
3908
|
+
USAGE
|
|
3909
|
+
papiers read ID [ID ...] [--format FORMAT] [--max-chars-per-item N] [--fail-fast] [--json|--pretty]
|
|
3910
|
+
papiers read @- | @file [--input0] [--format FORMAT] [--max-chars-per-item N] [--json|--pretty]
|
|
3911
|
+
Read public IDs or papiers://note|highlight|item|conversation/<uuid> locators; don't mix resource kinds.
|
|
3912
|
+
|
|
3913
|
+
OPTIONS
|
|
3914
|
+
--format FORMAT how to render each item. Default auto (equation defaults to metadata).
|
|
3915
|
+
document: auto|metadata|markdown|plain. passage: markdown|plain.
|
|
3916
|
+
highlight, conversation: metadata|plain. note: markdown|plain.
|
|
3917
|
+
equation: metadata.
|
|
3918
|
+
--include SECTION extra sections, comma-separated: metadata, source, locations.
|
|
3919
|
+
document only (highlight/conversation/equation/note: metadata only; passage: none).
|
|
3920
|
+
--pages RANGE restrict a document read to pages, e.g. 1,3-5. document only.
|
|
3921
|
+
--max-chars-per-item N truncate each item's content to N chars, 1\u2013200000.
|
|
3922
|
+
--cursor CURSOR continue one long document or note \u2014 use items[].nextCursor from the
|
|
3923
|
+
previous response. One literal document or note identifier only, with
|
|
3924
|
+
--format auto, markdown, or plain.
|
|
3925
|
+
--fail-fast exit non-zero if any item fails (default: succeed if at least one does).
|
|
3926
|
+
--json machine-readable JSON (the default)
|
|
3927
|
+
--pretty human-readable text
|
|
3928
|
+
|
|
3929
|
+
EXAMPLES
|
|
3930
|
+
papiers read doc_<id> --format markdown --max-chars-per-item 2000 --json
|
|
3931
|
+
papiers read nte_<id> --format markdown --json
|
|
3932
|
+
papiers read hl_<id> --json
|
|
3933
|
+
papiers search retrieval --doc-ids | papiers read @- --format metadata --json`,
|
|
3934
|
+
browse: `papiers browse \u2014 page deeper into an earlier search's results.
|
|
3935
|
+
|
|
3936
|
+
USAGE
|
|
3937
|
+
papiers browse srch_\u2026 [--offset N] [--limit N] [--pretty|--json|--ids|--ids0|--doc-ids|--passage-ids|--highlight-ids|--evidence-ids]
|
|
3938
|
+
|
|
3939
|
+
OPTIONS
|
|
3940
|
+
--offset N start at rank N (0-based) in the frozen ranking.
|
|
3941
|
+
--limit N max results, 1\u201350.
|
|
3942
|
+
${SEARCH_OUTPUT_OPTS}
|
|
3943
|
+
|
|
3944
|
+
When capabilities.searchResultsBrowse.enabled is true, a search response includes
|
|
3945
|
+
ranking.searchId (an srch_\u2026 handle); pass it here to page deeper without
|
|
3946
|
+
re-running the search. The ranking is frozen and expires after a while.
|
|
3947
|
+
|
|
3948
|
+
EXAMPLE
|
|
3949
|
+
papiers browse srch_<id> --offset 10 --json`,
|
|
3950
|
+
auth: `papiers auth \u2014 sign in, check status, or sign out.
|
|
3951
|
+
|
|
3952
|
+
USAGE
|
|
3953
|
+
papiers auth login [--force] [--json] Sign in (paste your token, or pipe it in)
|
|
3954
|
+
papiers auth status [--json] Show whether you're signed in
|
|
3955
|
+
papiers auth inspect [--json] Show details about the saved token
|
|
3956
|
+
papiers auth logout [--json] Forget the saved token
|
|
3957
|
+
|
|
3958
|
+
OPTIONS
|
|
3959
|
+
--force when signing in, replace an already-saved token.
|
|
3960
|
+
|
|
3961
|
+
Signing in saves your token on this machine. For scripts or an AI agent, set PAPIERS_TOKEN instead.`,
|
|
3962
|
+
tokens: `papiers tokens \u2014 list or revoke your API tokens.
|
|
3963
|
+
|
|
3964
|
+
USAGE
|
|
3421
3965
|
papiers tokens list [--json]
|
|
3422
3966
|
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
3967
|
|
|
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
|
|
3968
|
+
Create and name tokens in Papiers (Settings -> API tokens). Revoking is permanent.`,
|
|
3969
|
+
doctor: `papiers doctor \u2014 check your setup, connection, and what's available.
|
|
3460
3970
|
|
|
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.
|
|
3971
|
+
USAGE
|
|
3972
|
+
papiers doctor [--json]
|
|
3469
3973
|
|
|
3470
|
-
|
|
3471
|
-
|
|
3472
|
-
|
|
3974
|
+
Verifies your token, the server connection, and which features are available.
|
|
3975
|
+
Run it first when something isn't working.`,
|
|
3976
|
+
version: `papiers version \u2014 print the CLI version.
|
|
3473
3977
|
|
|
3474
|
-
|
|
3475
|
-
|
|
3476
|
-
|
|
3978
|
+
USAGE
|
|
3979
|
+
papiers version | papiers --version | papiers -V`
|
|
3980
|
+
};
|
|
3981
|
+
var REFERENCE = `REFERENCE \u2014 IDs, piping, pagination, and limits.
|
|
3477
3982
|
|
|
3478
|
-
|
|
3479
|
-
|
|
3480
|
-
|
|
3481
|
-
|
|
3482
|
-
|
|
3983
|
+
ID PREFIXES
|
|
3984
|
+
doc_ document pas_ passage hl_ highlight
|
|
3985
|
+
cnv_ conversation eq_ equation nte_ note
|
|
3986
|
+
srch_ a saved search ranking (for browse)
|
|
3987
|
+
On read, the kind \u2014 and which --format/--include apply \u2014 is read from the prefix.
|
|
3988
|
+
|
|
3989
|
+
RESOURCE LOCATORS
|
|
3990
|
+
papiers://note/<uuid> papiers://highlight/<uuid>
|
|
3991
|
+
papiers://item/<uuid> papiers://conversation/<uuid>
|
|
3992
|
+
Locators are accepted by read and resolved with the same ownership checks as public IDs.
|
|
3993
|
+
|
|
3994
|
+
PIPING IDS BETWEEN COMMANDS
|
|
3995
|
+
--ids result IDs, one per line, with their native prefix
|
|
3996
|
+
--ids0 the same IDs, NUL-separated (for \`xargs -0\`)
|
|
3997
|
+
--doc-ids parent document IDs only (doc_\u2026), deduped; conversation hits are skipped
|
|
3998
|
+
@- read identifiers from stdin @file read identifiers from a file
|
|
3999
|
+
--input0 read piped identifiers NUL-separated instead of whitespace/newlines
|
|
4000
|
+
@- and @file accept IDs, resource locators, or a Papiers JSON envelope, and may be mixed with literals.
|
|
4001
|
+
|
|
4002
|
+
PAGINATION \u2014 three separate mechanisms
|
|
4003
|
+
list response has page.nextCursor \u2192 papiers list \u2026 --cursor CURSOR
|
|
4004
|
+
search response has ranking.searchId \u2192 papiers browse srch_\u2026 --offset N
|
|
4005
|
+
read a truncated item has items[].nextCursor \u2192 papiers read NOTE_OR_DOCUMENT --cursor CURSOR
|
|
4006
|
+
|
|
4007
|
+
LIMITS
|
|
4008
|
+
--limit 1\u201350 \xB7 --max-chars-per-item 1\u2013200000 \xB7 up to 25 filters \xB7 up to 100 IDs per request
|
|
4009
|
+
|
|
4010
|
+
FILTER FIELDS \u2014 document kind, as FIELD.OP=VALUE (or FIELD=VALUE for equality)
|
|
4011
|
+
id title author venue doi arxivId pmid
|
|
4012
|
+
publishedDate publishedYear sourceFamily sourceDomain
|
|
4013
|
+
annotated engaged lastEngagedAt
|
|
4014
|
+
Operators: eq \xB7 in \xB7 contains \xB7 prefix \xB7 gte \xB7 gt \xB7 lte \xB7 lt \xB7 between (which apply depends on the field).`;
|
|
4015
|
+
var HELP_PAGES = {
|
|
4016
|
+
...HELP_TOPICS,
|
|
4017
|
+
reference: REFERENCE
|
|
4018
|
+
};
|
|
4019
|
+
var HELP_TOPIC_NAMES = Object.keys(HELP_PAGES);
|
|
4020
|
+
var HELP_COMMAND_NAMES = Object.keys(HELP_TOPICS);
|
|
4021
|
+
var HELP_TEXT = [GLOBAL_HELP, ...Object.values(HELP_PAGES)].join(
|
|
4022
|
+
"\n\n\n"
|
|
4023
|
+
);
|
|
4024
|
+
function colorizeHelp(text) {
|
|
4025
|
+
return text.replace(/^([A-Z][A-Z ]{2,})$/gm, "\x1B[1;36m$1\x1B[0m").replace(
|
|
4026
|
+
/(^|[\s([|/])(--[a-z0-9-]+|-[A-Za-z])\b/g,
|
|
4027
|
+
"$1\x1B[33m$2\x1B[0m"
|
|
4028
|
+
);
|
|
4029
|
+
}
|
|
4030
|
+
function renderHelp(command, style) {
|
|
4031
|
+
const help = command.type === "help" ? command : void 0;
|
|
4032
|
+
let body = GLOBAL_HELP;
|
|
4033
|
+
if (help?.all) {
|
|
4034
|
+
body = HELP_TEXT;
|
|
4035
|
+
} else if (help?.topic) {
|
|
4036
|
+
body = HELP_PAGES[help.topic] ?? GLOBAL_HELP;
|
|
4037
|
+
}
|
|
4038
|
+
return style ? colorizeHelp(body) : body;
|
|
4039
|
+
}
|
|
4040
|
+
var SUGGESTIBLE_COMMANDS = [
|
|
4041
|
+
"auth",
|
|
4042
|
+
"doctor",
|
|
4043
|
+
"capabilities",
|
|
4044
|
+
"tokens",
|
|
4045
|
+
"list",
|
|
4046
|
+
"search",
|
|
4047
|
+
"browse",
|
|
4048
|
+
"read",
|
|
4049
|
+
"version",
|
|
4050
|
+
"help"
|
|
4051
|
+
];
|
|
4052
|
+
function levenshtein(a, b) {
|
|
4053
|
+
const rows = a.length + 1;
|
|
4054
|
+
const cols = b.length + 1;
|
|
4055
|
+
const dist = Array.from(
|
|
4056
|
+
{ length: rows },
|
|
4057
|
+
() => new Array(cols).fill(0)
|
|
4058
|
+
);
|
|
4059
|
+
for (let i = 0; i < rows; i += 1) dist[i][0] = i;
|
|
4060
|
+
for (let j = 0; j < cols; j += 1) dist[0][j] = j;
|
|
4061
|
+
for (let i = 1; i < rows; i += 1) {
|
|
4062
|
+
for (let j = 1; j < cols; j += 1) {
|
|
4063
|
+
const cost = a[i - 1] === b[j - 1] ? 0 : 1;
|
|
4064
|
+
dist[i][j] = Math.min(
|
|
4065
|
+
dist[i - 1][j] + 1,
|
|
4066
|
+
dist[i][j - 1] + 1,
|
|
4067
|
+
dist[i - 1][j - 1] + cost
|
|
4068
|
+
);
|
|
4069
|
+
}
|
|
4070
|
+
}
|
|
4071
|
+
return dist[rows - 1][cols - 1];
|
|
4072
|
+
}
|
|
4073
|
+
function suggestCommand(input) {
|
|
4074
|
+
let best = null;
|
|
4075
|
+
let bestDistance = Number.POSITIVE_INFINITY;
|
|
4076
|
+
for (const candidate of SUGGESTIBLE_COMMANDS) {
|
|
4077
|
+
const distance = levenshtein(input, candidate);
|
|
4078
|
+
if (distance < bestDistance) {
|
|
4079
|
+
bestDistance = distance;
|
|
4080
|
+
best = candidate;
|
|
4081
|
+
}
|
|
4082
|
+
}
|
|
4083
|
+
return best !== null && bestDistance <= 2 ? best : null;
|
|
4084
|
+
}
|
|
4085
|
+
function unknownCommandMessage(command) {
|
|
4086
|
+
const suggestion = suggestCommand(command);
|
|
4087
|
+
const guess = suggestion ? ` Did you mean "${suggestion}"?` : "";
|
|
4088
|
+
return `Unknown papiers command.${guess} Run papiers --help to see commands.`;
|
|
4089
|
+
}
|
|
3483
4090
|
function parseCliArgs(argv) {
|
|
3484
4091
|
const parsed = parseRawArgv(argv);
|
|
3485
4092
|
const global = parseGlobalOptions(parsed);
|
|
3486
4093
|
if (parsed.booleanFlags.has("version") && !parsed.help) {
|
|
3487
4094
|
return { type: "version", ...global };
|
|
3488
4095
|
}
|
|
3489
|
-
|
|
4096
|
+
const [command, ...rest] = parsed.positionals;
|
|
4097
|
+
if (parsed.help || command === "help" || parsed.positionals.length === 0) {
|
|
4098
|
+
if (parsed.booleanFlags.has("all")) {
|
|
4099
|
+
return { type: "help", all: true, ...global };
|
|
4100
|
+
}
|
|
4101
|
+
const topic = command === "help" ? rest[0] : command;
|
|
4102
|
+
if (topic && HELP_TOPIC_NAMES.includes(topic)) {
|
|
4103
|
+
return { type: "help", topic, ...global };
|
|
4104
|
+
}
|
|
3490
4105
|
return { type: "help", ...global };
|
|
3491
4106
|
}
|
|
3492
|
-
const [command, ...rest] = parsed.positionals;
|
|
3493
4107
|
switch (command) {
|
|
3494
|
-
case "help":
|
|
3495
|
-
case "--help":
|
|
3496
|
-
return { type: "help", ...global };
|
|
3497
4108
|
case "version":
|
|
3498
4109
|
assertNoExtraPositionals(command, rest);
|
|
3499
4110
|
return { type: "version", ...global };
|
|
@@ -3527,7 +4138,7 @@ function parseCliArgs(argv) {
|
|
|
3527
4138
|
type: "list",
|
|
3528
4139
|
...global,
|
|
3529
4140
|
idsOnly: listOutput.idsOnly,
|
|
3530
|
-
...parsePrettyOutput(parsed, listOutput.
|
|
4141
|
+
...parsePrettyOutput(parsed, listOutput.anyIdsOutput) ? { pretty: true } : {},
|
|
3531
4142
|
...listOutput.idsNulDelimited ? { idsNulDelimited: true } : {},
|
|
3532
4143
|
...listOutput.docIdsOnly ? { docIdsOnly: true } : {},
|
|
3533
4144
|
...parsed.booleanFlags.has("input0") ? { inputNulDelimited: true } : {},
|
|
@@ -3537,16 +4148,23 @@ function parseCliArgs(argv) {
|
|
|
3537
4148
|
}
|
|
3538
4149
|
case "search": {
|
|
3539
4150
|
assertAllowedFlags(parsed, SEARCH_VALUE_FLAGS, "search");
|
|
3540
|
-
assertAllowedBooleanFlags(
|
|
4151
|
+
assertAllowedBooleanFlags(
|
|
4152
|
+
parsed,
|
|
4153
|
+
SEARCH_IDS_PIPELINE_BOOLEAN_FLAGS,
|
|
4154
|
+
"search"
|
|
4155
|
+
);
|
|
3541
4156
|
const searchDocumentIds = parseDocumentIdFlagValues(parsed, "search");
|
|
3542
4157
|
const searchOutput = parseIdsOutput(parsed, "search");
|
|
3543
4158
|
return {
|
|
3544
4159
|
type: "search",
|
|
3545
4160
|
...global,
|
|
3546
4161
|
idsOnly: searchOutput.idsOnly,
|
|
3547
|
-
...parsePrettyOutput(parsed, searchOutput.
|
|
4162
|
+
...parsePrettyOutput(parsed, searchOutput.anyIdsOutput) ? { pretty: true } : {},
|
|
3548
4163
|
...searchOutput.idsNulDelimited ? { idsNulDelimited: true } : {},
|
|
3549
4164
|
...searchOutput.docIdsOnly ? { docIdsOnly: true } : {},
|
|
4165
|
+
...searchOutput.passageIdsOnly ? { passageIdsOnly: true } : {},
|
|
4166
|
+
...searchOutput.highlightIdsOnly ? { highlightIdsOnly: true } : {},
|
|
4167
|
+
...searchOutput.evidenceIdsOnly ? { evidenceIdsOnly: true } : {},
|
|
3550
4168
|
...parsed.booleanFlags.has("input0") ? { inputNulDelimited: true } : {},
|
|
3551
4169
|
...searchDocumentIds ? { documentIds: searchDocumentIds } : {},
|
|
3552
4170
|
request: buildSearchRequest(rest, parsed, searchDocumentIds)
|
|
@@ -3554,7 +4172,11 @@ function parseCliArgs(argv) {
|
|
|
3554
4172
|
}
|
|
3555
4173
|
case "browse": {
|
|
3556
4174
|
assertAllowedFlags(parsed, BROWSE_VALUE_FLAGS, "browse");
|
|
3557
|
-
assertAllowedBooleanFlags(
|
|
4175
|
+
assertAllowedBooleanFlags(
|
|
4176
|
+
parsed,
|
|
4177
|
+
SEARCH_IDS_PIPELINE_BOOLEAN_FLAGS,
|
|
4178
|
+
"browse"
|
|
4179
|
+
);
|
|
3558
4180
|
if (parsed.booleanFlags.has("input0")) {
|
|
3559
4181
|
throw new CliUsageError("--input0 is not supported for browse.");
|
|
3560
4182
|
}
|
|
@@ -3563,9 +4185,12 @@ function parseCliArgs(argv) {
|
|
|
3563
4185
|
type: "browse",
|
|
3564
4186
|
...global,
|
|
3565
4187
|
idsOnly: browseOutput.idsOnly,
|
|
3566
|
-
...parsePrettyOutput(parsed, browseOutput.
|
|
4188
|
+
...parsePrettyOutput(parsed, browseOutput.anyIdsOutput) ? { pretty: true } : {},
|
|
3567
4189
|
...browseOutput.idsNulDelimited ? { idsNulDelimited: true } : {},
|
|
3568
4190
|
...browseOutput.docIdsOnly ? { docIdsOnly: true } : {},
|
|
4191
|
+
...browseOutput.passageIdsOnly ? { passageIdsOnly: true } : {},
|
|
4192
|
+
...browseOutput.highlightIdsOnly ? { highlightIdsOnly: true } : {},
|
|
4193
|
+
...browseOutput.evidenceIdsOnly ? { evidenceIdsOnly: true } : {},
|
|
3569
4194
|
request: buildBrowseRequest(rest, parsed)
|
|
3570
4195
|
};
|
|
3571
4196
|
}
|
|
@@ -3584,7 +4209,7 @@ function parseCliArgs(argv) {
|
|
|
3584
4209
|
};
|
|
3585
4210
|
}
|
|
3586
4211
|
default:
|
|
3587
|
-
throw new CliUsageError(
|
|
4212
|
+
throw new CliUsageError(unknownCommandMessage(command));
|
|
3588
4213
|
}
|
|
3589
4214
|
}
|
|
3590
4215
|
function argvWantsJson(argv) {
|
|
@@ -3594,9 +4219,9 @@ function parsePrettyOutput(parsed, idsOnly) {
|
|
|
3594
4219
|
if (!parsed.booleanFlags.has("pretty")) {
|
|
3595
4220
|
return false;
|
|
3596
4221
|
}
|
|
3597
|
-
if (idsOnly || parsed.json
|
|
4222
|
+
if (idsOnly || parsed.json) {
|
|
3598
4223
|
throw new CliUsageError(
|
|
3599
|
-
"--pretty cannot be combined with --json
|
|
4224
|
+
"--pretty cannot be combined with --json or ID projection flags."
|
|
3600
4225
|
);
|
|
3601
4226
|
}
|
|
3602
4227
|
return true;
|
|
@@ -3636,12 +4261,6 @@ function parseAuthCommand(rest, parsed, global) {
|
|
|
3636
4261
|
case "login": {
|
|
3637
4262
|
assertAllowedBooleanFlags(parsed, AUTH_LOGIN_BOOLEAN_FLAGS, "auth login");
|
|
3638
4263
|
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
4264
|
return {
|
|
3646
4265
|
type: "auth-login",
|
|
3647
4266
|
...global,
|
|
@@ -3683,7 +4302,7 @@ function buildReadRequest(parsed) {
|
|
|
3683
4302
|
const ids = orderedReadIdValues(parsed);
|
|
3684
4303
|
if (ids.length === 0) {
|
|
3685
4304
|
throw new CliUsageError(
|
|
3686
|
-
"papiers read requires at least one
|
|
4305
|
+
"papiers read requires at least one public ID or papiers:// resource locator."
|
|
3687
4306
|
);
|
|
3688
4307
|
}
|
|
3689
4308
|
if (ids.filter((id) => id === "@-").length > 1) {
|
|
@@ -3697,7 +4316,7 @@ function buildReadRequest(parsed) {
|
|
|
3697
4316
|
const literalKinds = readKindsForLiteralIds(ids);
|
|
3698
4317
|
if (literalKinds.length > 1) {
|
|
3699
4318
|
throw new CliUsageError(
|
|
3700
|
-
"papiers read
|
|
4319
|
+
"papiers read identifiers must all use the same resource kind."
|
|
3701
4320
|
);
|
|
3702
4321
|
}
|
|
3703
4322
|
const inferredKind = literalKinds[0] ?? requestedKind ?? "document";
|
|
@@ -3713,9 +4332,9 @@ function buildReadRequest(parsed) {
|
|
|
3713
4332
|
}
|
|
3714
4333
|
const format = parseReadFormat(parsed, inferredKind);
|
|
3715
4334
|
const cursor = singleFlagValue(parsed, "cursor");
|
|
3716
|
-
if (cursor !== void 0 && (inferredKind !== "document" || ids.length !== 1 || ids.some((id) => isDocumentIdSource(id)) ||
|
|
4335
|
+
if (cursor !== void 0 && (inferredKind !== "document" && inferredKind !== "note" || ids.length !== 1 || ids.some((id) => isDocumentIdSource(id)) || readKindForIdentifier(ids[0]) !== inferredKind)) {
|
|
3717
4336
|
throw new CliUsageError(
|
|
3718
|
-
"papiers read --cursor requires exactly one literal
|
|
4337
|
+
"papiers read --cursor requires exactly one literal document or note identifier."
|
|
3719
4338
|
);
|
|
3720
4339
|
}
|
|
3721
4340
|
if (cursor !== void 0 && format !== "auto" && !DOCUMENT_CONTENT_READ_FORMATS.some((supported) => supported === format)) {
|
|
@@ -3792,104 +4411,65 @@ function buildSearchRequest(positionals, parsed, documentIds) {
|
|
|
3792
4411
|
"Ranked public search cursors are not available yet."
|
|
3793
4412
|
);
|
|
3794
4413
|
}
|
|
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")) {
|
|
3843
|
-
throw new CliUsageError(
|
|
3844
|
-
"papiers search --since is supported only with --kind highlight or conversation."
|
|
3845
|
-
);
|
|
3846
|
-
}
|
|
3847
|
-
if (queryIn === "latex") {
|
|
4414
|
+
if (parsed.flags.has("query-in")) {
|
|
3848
4415
|
throw new CliUsageError(
|
|
3849
|
-
"papiers search --query-in
|
|
4416
|
+
"papiers search no longer supports --query-in; use free-text query plus --filter FIELD.OP=VALUE for structured attributes."
|
|
3850
4417
|
);
|
|
3851
4418
|
}
|
|
3852
|
-
if (
|
|
4419
|
+
if (parsed.flags.has("since")) {
|
|
3853
4420
|
throw new CliUsageError(
|
|
3854
|
-
"papiers search supports --
|
|
4421
|
+
"papiers search no longer supports --since; use --filter lastEngagedAt.gte=<when> for document recency."
|
|
3855
4422
|
);
|
|
3856
4423
|
}
|
|
4424
|
+
const kinds = parseSearchKindScopes(parsed);
|
|
4425
|
+
const filters = parsed.flags.get("filter")?.map((filter) => parseDocumentFilterExpression(filter));
|
|
4426
|
+
assertFilterCount(filters, "search");
|
|
3857
4427
|
return pruneUndefined({
|
|
3858
4428
|
schemaVersion: PAPIERS_SCHEMA_VERSIONS.searchRequest,
|
|
3859
4429
|
query,
|
|
3860
|
-
|
|
4430
|
+
kinds,
|
|
4431
|
+
filters,
|
|
3861
4432
|
limit: parseLimit(parsed)
|
|
3862
4433
|
});
|
|
3863
4434
|
}
|
|
3864
|
-
function
|
|
3865
|
-
|
|
3866
|
-
|
|
3867
|
-
|
|
3868
|
-
);
|
|
4435
|
+
function parseSearchKindScopes(parsed) {
|
|
4436
|
+
const rawKinds = parsed.flags.get("kind")?.flatMap(splitCommaSeparatedValues);
|
|
4437
|
+
if (rawKinds === void 0) {
|
|
4438
|
+
return void 0;
|
|
3869
4439
|
}
|
|
3870
|
-
if (
|
|
3871
|
-
throw new CliUsageError(
|
|
3872
|
-
"papiers search --since is not supported with --kind all; use --kind highlight or conversation."
|
|
3873
|
-
);
|
|
4440
|
+
if (rawKinds.length === 0) {
|
|
4441
|
+
throw new CliUsageError("papiers search --kind requires a value.");
|
|
3874
4442
|
}
|
|
3875
|
-
|
|
3876
|
-
|
|
3877
|
-
|
|
3878
|
-
|
|
4443
|
+
const sawAll = rawKinds.some((kind) => kind.trim().toLowerCase() === "all");
|
|
4444
|
+
if (sawAll) {
|
|
4445
|
+
if (rawKinds.length > 1) {
|
|
4446
|
+
throw new CliUsageError(
|
|
4447
|
+
"papiers search --kind all cannot be combined with other --kind values."
|
|
4448
|
+
);
|
|
4449
|
+
}
|
|
4450
|
+
return void 0;
|
|
3879
4451
|
}
|
|
3880
|
-
const
|
|
3881
|
-
|
|
3882
|
-
|
|
3883
|
-
|
|
3884
|
-
|
|
4452
|
+
const kinds = [];
|
|
4453
|
+
for (const rawKind of rawKinds) {
|
|
4454
|
+
const kind = normalizeCliPublicKind(rawKind);
|
|
4455
|
+
if (!kind) {
|
|
4456
|
+
throw new CliUsageError(
|
|
4457
|
+
`papiers search supports --kind passage, highlight, conversation, equation, or note; received "${rawKind}".${didYouMeanKind(rawKind)}`
|
|
4458
|
+
);
|
|
4459
|
+
}
|
|
4460
|
+
if (kind === "document") {
|
|
4461
|
+
throw new CliUsageError(
|
|
4462
|
+
"papiers search no longer supports --kind document; omit --kind to search matching titles and content."
|
|
4463
|
+
);
|
|
4464
|
+
}
|
|
4465
|
+
if (!MULTI_SEARCH_KINDS.includes(kind)) {
|
|
4466
|
+
throw new CliUsageError(
|
|
4467
|
+
`papiers search supports --kind passage, highlight, conversation, equation, or note; received "${rawKind}".`
|
|
4468
|
+
);
|
|
4469
|
+
}
|
|
4470
|
+
kinds.push(kind);
|
|
3885
4471
|
}
|
|
3886
|
-
return
|
|
3887
|
-
schemaVersion: PAPIERS_SCHEMA_VERSIONS.searchRequest,
|
|
3888
|
-
query,
|
|
3889
|
-
kinds: [...MULTI_SEARCH_KINDS],
|
|
3890
|
-
queryIn: "content",
|
|
3891
|
-
limit: parseLimit(parsed)
|
|
3892
|
-
});
|
|
4472
|
+
return [...new Set(kinds)];
|
|
3893
4473
|
}
|
|
3894
4474
|
function parseSinceFlag(parsed, kind, command) {
|
|
3895
4475
|
const value = singleFlagValue(parsed, "since");
|
|
@@ -3964,7 +4544,7 @@ function parseReadKind(parsed) {
|
|
|
3964
4544
|
return normalized;
|
|
3965
4545
|
}
|
|
3966
4546
|
throw new CliUsageError(
|
|
3967
|
-
`Public CLI read currently supports --kind document, passage, highlight, conversation, or
|
|
4547
|
+
`Public CLI read currently supports --kind document, passage, highlight, conversation, equation, or note only; received "${kind}".${didYouMeanKind(kind)}`
|
|
3968
4548
|
);
|
|
3969
4549
|
}
|
|
3970
4550
|
function readKindsForLiteralIds(ids) {
|
|
@@ -3973,10 +4553,10 @@ function readKindsForLiteralIds(ids) {
|
|
|
3973
4553
|
if (isDocumentIdSource(id)) {
|
|
3974
4554
|
continue;
|
|
3975
4555
|
}
|
|
3976
|
-
const kind =
|
|
4556
|
+
const kind = readKindForIdentifier(id);
|
|
3977
4557
|
if (!kind) {
|
|
3978
4558
|
throw new CliUsageError(
|
|
3979
|
-
"papiers read
|
|
4559
|
+
"papiers read accepts public IDs or papiers://note, highlight, item, and conversation locators."
|
|
3980
4560
|
);
|
|
3981
4561
|
}
|
|
3982
4562
|
kinds.add(kind);
|
|
@@ -4023,13 +4603,25 @@ function parseIdsOutput(parsed, command) {
|
|
|
4023
4603
|
const idsOnly = parsed.booleanFlags.has("ids");
|
|
4024
4604
|
const idsNulDelimited = parsed.booleanFlags.has("ids0");
|
|
4025
4605
|
const docIdsOnly = parsed.booleanFlags.has("doc-ids");
|
|
4026
|
-
const
|
|
4606
|
+
const passageIdsOnly = parsed.booleanFlags.has("passage-ids");
|
|
4607
|
+
const highlightIdsOnly = parsed.booleanFlags.has("highlight-ids");
|
|
4608
|
+
const evidenceIdsOnly = parsed.booleanFlags.has("evidence-ids");
|
|
4609
|
+
const selectedCount = Number(idsOnly) + Number(idsNulDelimited) + Number(docIdsOnly) + Number(passageIdsOnly) + Number(highlightIdsOnly) + Number(evidenceIdsOnly) + Number(parsed.json);
|
|
4027
4610
|
if (selectedCount > 1) {
|
|
4028
4611
|
throw new CliUsageError(
|
|
4029
|
-
`Use only one of --ids, --ids0, --doc-ids, or --json for papiers ${command}.`
|
|
4612
|
+
`Use only one of --ids, --ids0, --doc-ids, --passage-ids, --highlight-ids, --evidence-ids, or --json for papiers ${command}.`
|
|
4030
4613
|
);
|
|
4031
4614
|
}
|
|
4032
|
-
|
|
4615
|
+
const normalizedIdsOnly = idsOnly || idsNulDelimited;
|
|
4616
|
+
return {
|
|
4617
|
+
idsOnly: normalizedIdsOnly,
|
|
4618
|
+
idsNulDelimited,
|
|
4619
|
+
docIdsOnly,
|
|
4620
|
+
passageIdsOnly,
|
|
4621
|
+
highlightIdsOnly,
|
|
4622
|
+
evidenceIdsOnly,
|
|
4623
|
+
anyIdsOutput: normalizedIdsOnly || docIdsOnly || passageIdsOnly || highlightIdsOnly || evidenceIdsOnly
|
|
4624
|
+
};
|
|
4033
4625
|
}
|
|
4034
4626
|
function parseReadInclude(parsed) {
|
|
4035
4627
|
const rawIncludes = parsed.flags.get("include")?.flatMap(splitCommaSeparatedValues);
|
|
@@ -4072,6 +4664,21 @@ function validateReadOptionsForKind(parsed, kind, format) {
|
|
|
4072
4664
|
});
|
|
4073
4665
|
return;
|
|
4074
4666
|
}
|
|
4667
|
+
if (kind === "note") {
|
|
4668
|
+
if (format !== "auto" && !EXPECTED_NOTE_READ_FORMATS.some((supported) => supported === format)) {
|
|
4669
|
+
throw new CliUsageError(
|
|
4670
|
+
"Public note read supports --format markdown, plain, or auto."
|
|
4671
|
+
);
|
|
4672
|
+
}
|
|
4673
|
+
const includes = parseReadInclude(parsed);
|
|
4674
|
+
if (includes?.some((include) => include !== "metadata")) {
|
|
4675
|
+
throw new CliUsageError(
|
|
4676
|
+
"Public note read supports only --include metadata."
|
|
4677
|
+
);
|
|
4678
|
+
}
|
|
4679
|
+
rejectReadFlagsForKind(parsed, kind, ["pages"]);
|
|
4680
|
+
return;
|
|
4681
|
+
}
|
|
4075
4682
|
validateMetadataReadOptionsForKind(parsed, kind, format, {
|
|
4076
4683
|
supportedFormats: EXPECTED_EQUATION_READ_FORMATS
|
|
4077
4684
|
});
|
|
@@ -4190,7 +4797,8 @@ function parseRawArgv(argv) {
|
|
|
4190
4797
|
continue;
|
|
4191
4798
|
}
|
|
4192
4799
|
if (!VALUE_FLAGS.has(name)) {
|
|
4193
|
-
|
|
4800
|
+
const hint = REMOVED_FLAG_HINTS[name] ?? "Run papiers --help to see options.";
|
|
4801
|
+
throw new CliUsageError(`Unknown option --${name}. ${hint}`);
|
|
4194
4802
|
}
|
|
4195
4803
|
const flagValue = value ?? argv[index + 1];
|
|
4196
4804
|
if (flagValue === void 0 || flagValue.startsWith("--")) {
|
|
@@ -4221,14 +4829,9 @@ function splitLongFlag(arg) {
|
|
|
4221
4829
|
};
|
|
4222
4830
|
}
|
|
4223
4831
|
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
4832
|
return {
|
|
4230
4833
|
json: parsed.json,
|
|
4231
|
-
apiBaseUrl:
|
|
4834
|
+
apiBaseUrl: singleFlagValue(parsed, "api-url")
|
|
4232
4835
|
};
|
|
4233
4836
|
}
|
|
4234
4837
|
function parseListSearchKind(parsed, command) {
|
|
@@ -4243,11 +4846,16 @@ function parseListSearchKind(parsed, command) {
|
|
|
4243
4846
|
);
|
|
4244
4847
|
}
|
|
4245
4848
|
throw new CliUsageError(
|
|
4246
|
-
`papiers ${command} supports --kind document, passage, highlight, conversation, or
|
|
4849
|
+
`papiers ${command} supports --kind document, passage, highlight, conversation, equation, or note; received "${kind}".${didYouMeanKind(kind)}`
|
|
4247
4850
|
);
|
|
4248
4851
|
}
|
|
4249
4852
|
function normalizeCliPublicKind(value) {
|
|
4250
|
-
|
|
4853
|
+
const normalized = value.trim().toLowerCase();
|
|
4854
|
+
return PUBLIC_KINDS.includes(normalized) ? normalized : null;
|
|
4855
|
+
}
|
|
4856
|
+
function didYouMeanKind(value) {
|
|
4857
|
+
const suggestion = FORMER_KIND_ALIASES.get(value.trim().toLowerCase());
|
|
4858
|
+
return suggestion ? ` Did you mean "${suggestion}"?` : "";
|
|
4251
4859
|
}
|
|
4252
4860
|
function assertNoNonDocumentListSearchFlag(parsed, flag, command, kind) {
|
|
4253
4861
|
if (parsed.flags.has(flag)) {
|
|
@@ -4300,34 +4908,6 @@ function parseLimit(parsed) {
|
|
|
4300
4908
|
}
|
|
4301
4909
|
return limit;
|
|
4302
4910
|
}
|
|
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
4911
|
function assertFilterCount(filters, command, reservedFilterCount = 0) {
|
|
4332
4912
|
const totalFilterCount = (filters?.length ?? 0) + reservedFilterCount;
|
|
4333
4913
|
if (totalFilterCount > DOCUMENT_MAX_FILTERS) {
|
|
@@ -4511,26 +5091,7 @@ function assertSupportedDocumentCapabilities(value) {
|
|
|
4511
5091
|
assertSupportedSearchResultsBrowse(capabilities.searchResultsBrowse);
|
|
4512
5092
|
const queryIn = assertRecord2("capabilities queryIn", capabilities.queryIn);
|
|
4513
5093
|
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
|
-
);
|
|
5094
|
+
assertPublicKindStringArrayRecord("capabilities queryIn", queryIn, {});
|
|
4534
5095
|
const readFormats = assertStringArray(
|
|
4535
5096
|
"capabilities readFormats",
|
|
4536
5097
|
capabilities.readFormats
|
|
@@ -4592,6 +5153,13 @@ function assertSupportedDocumentCapabilities(value) {
|
|
|
4592
5153
|
EXPECTED_EQUATION_READ_FORMATS
|
|
4593
5154
|
);
|
|
4594
5155
|
continue;
|
|
5156
|
+
case "note":
|
|
5157
|
+
assertOptionalReadFormats(
|
|
5158
|
+
`capabilities readFormatsByKind.${kind}`,
|
|
5159
|
+
actualFormats,
|
|
5160
|
+
EXPECTED_NOTE_READ_FORMATS
|
|
5161
|
+
);
|
|
5162
|
+
continue;
|
|
4595
5163
|
default:
|
|
4596
5164
|
assertSameStringSet(
|
|
4597
5165
|
`capabilities readFormatsByKind.${kind}`,
|
|
@@ -4619,7 +5187,11 @@ function assertSupportedDocumentCapabilities(value) {
|
|
|
4619
5187
|
`capabilities filters.${kind}`,
|
|
4620
5188
|
filters[kind]
|
|
4621
5189
|
);
|
|
4622
|
-
assertSameStringSet(
|
|
5190
|
+
assertSameStringSet(
|
|
5191
|
+
`capabilities filters.${kind}`,
|
|
5192
|
+
actualFilters,
|
|
5193
|
+
kind === "conversation" ? EXPECTED_CONVERSATION_FILTERS : []
|
|
5194
|
+
);
|
|
4623
5195
|
}
|
|
4624
5196
|
const operatorsByField = assertRecord2(
|
|
4625
5197
|
"capabilities operatorsByField",
|
|
@@ -4723,12 +5295,9 @@ function assertPublicKindStringArrayRecord(label, record, expectedByKind) {
|
|
|
4723
5295
|
}
|
|
4724
5296
|
}
|
|
4725
5297
|
function assertSupportedSearchKinds(searchKinds) {
|
|
4726
|
-
if (!searchKinds.includes("document")) {
|
|
4727
|
-
throw new Error("capabilities searchKinds did not include document.");
|
|
4728
|
-
}
|
|
4729
5298
|
const seen = /* @__PURE__ */ new Set();
|
|
4730
5299
|
for (const kind of searchKinds) {
|
|
4731
|
-
if (seen.has(kind) || !PUBLIC_KINDS.includes(kind)) {
|
|
5300
|
+
if (seen.has(kind) || kind === "document" || !PUBLIC_KINDS.includes(kind)) {
|
|
4732
5301
|
throw new Error(
|
|
4733
5302
|
`capabilities searchKinds advertised unsupported kind: ${kind}.`
|
|
4734
5303
|
);
|
|
@@ -4950,9 +5519,16 @@ function isPublicNotReadyReason(reason, reasons) {
|
|
|
4950
5519
|
}
|
|
4951
5520
|
|
|
4952
5521
|
// src/pretty.ts
|
|
5522
|
+
function warningLines(warnings) {
|
|
5523
|
+
if (!warnings?.length) {
|
|
5524
|
+
return [];
|
|
5525
|
+
}
|
|
5526
|
+
return warnings.map((warning) => warning.message?.trim()).filter((message) => Boolean(message)).map((message) => `! ${message}`);
|
|
5527
|
+
}
|
|
4953
5528
|
function renderPrettyPageOutput(response) {
|
|
4954
5529
|
const lines = [];
|
|
4955
|
-
|
|
5530
|
+
const entries = response.results ?? response.items ?? [];
|
|
5531
|
+
for (const item of entries) {
|
|
4956
5532
|
const rank = item.rank !== void 0 ? `${item.rank}. ` : "";
|
|
4957
5533
|
const title = item.title?.trim() ? ` ${item.title.trim()}` : "";
|
|
4958
5534
|
lines.push(`${rank}${item.id} [${item.kind}]${title}`);
|
|
@@ -4960,21 +5536,36 @@ function renderPrettyPageOutput(response) {
|
|
|
4960
5536
|
if (excerpt?.trim()) {
|
|
4961
5537
|
lines.push(` ${excerpt.trim()}`);
|
|
4962
5538
|
}
|
|
5539
|
+
if (item.evidence?.length) {
|
|
5540
|
+
for (const evidence of item.evidence) {
|
|
5541
|
+
const evidenceRank = evidence.rank !== void 0 ? `${evidence.rank}. ` : "";
|
|
5542
|
+
lines.push(` - ${evidenceRank}${evidence.id} [${evidence.kind}]`);
|
|
5543
|
+
if (evidence.snippet?.trim()) {
|
|
5544
|
+
lines.push(` ${evidence.snippet.trim()}`);
|
|
5545
|
+
}
|
|
5546
|
+
}
|
|
5547
|
+
if (typeof item.evidenceTotal === "number" && item.evidenceTotal > item.evidence.length) {
|
|
5548
|
+
lines.push(
|
|
5549
|
+
` + ${item.evidenceTotal - item.evidence.length} more evidence item${item.evidenceTotal - item.evidence.length === 1 ? "" : "s"}`
|
|
5550
|
+
);
|
|
5551
|
+
}
|
|
5552
|
+
}
|
|
4963
5553
|
}
|
|
4964
5554
|
if (lines.length === 0) {
|
|
4965
5555
|
lines.push("(no items)");
|
|
4966
5556
|
}
|
|
4967
|
-
const itemCount =
|
|
5557
|
+
const itemCount = entries.length;
|
|
4968
5558
|
lines.push(
|
|
4969
5559
|
`(${itemCount} item${itemCount === 1 ? "" : "s"}; ${pagingSummary(response)})`
|
|
4970
5560
|
);
|
|
5561
|
+
lines.push(...warningLines(response.warnings));
|
|
4971
5562
|
return `${lines.join("\n")}
|
|
4972
5563
|
`;
|
|
4973
5564
|
}
|
|
4974
5565
|
function pagingSummary(response) {
|
|
4975
5566
|
const ranking = response.ranking;
|
|
4976
5567
|
if (ranking) {
|
|
4977
|
-
const nextOffset = ranking.nextOffset !== void 0 ? ranking.nextOffset : ranking.totalCount > response.items.length ? response.items.length : null;
|
|
5568
|
+
const nextOffset = ranking.nextOffset !== void 0 ? ranking.nextOffset : ranking.totalCount > (response.results ?? response.items ?? []).length ? (response.results ?? response.items ?? []).length : null;
|
|
4978
5569
|
return nextOffset === null ? `ranking exhausted at ${ranking.totalCount}` : `${ranking.totalCount} ranked in total \u2014 papiers browse ${ranking.searchId} --offset ${nextOffset}`;
|
|
4979
5570
|
}
|
|
4980
5571
|
return response.page.nextCursor ? "more available \u2014 rerun with --json and pass page.nextCursor via --cursor" : "no more pages";
|
|
@@ -5054,7 +5645,9 @@ async function runCli(argv, dependencies = {}) {
|
|
|
5054
5645
|
const command = parseCliArgs(argv);
|
|
5055
5646
|
jsonOutput = command.json;
|
|
5056
5647
|
if (command.type === "help") {
|
|
5057
|
-
stdout.
|
|
5648
|
+
const styled = dependencies.stdout === void 0 && process.stdout.isTTY === true && process.env.NO_COLOR === void 0;
|
|
5649
|
+
stdout.write(`${renderHelp(command, styled)}
|
|
5650
|
+
`);
|
|
5058
5651
|
return 0;
|
|
5059
5652
|
}
|
|
5060
5653
|
if (command.type === "version") {
|
|
@@ -5126,12 +5719,27 @@ async function runCli(argv, dependencies = {}) {
|
|
|
5126
5719
|
json: command.json,
|
|
5127
5720
|
stdout
|
|
5128
5721
|
});
|
|
5129
|
-
case "capabilities":
|
|
5130
|
-
|
|
5131
|
-
|
|
5132
|
-
|
|
5722
|
+
case "capabilities": {
|
|
5723
|
+
const capabilities = await getCapabilities(
|
|
5724
|
+
config,
|
|
5725
|
+
resolveFetch(dependencies.fetch)
|
|
5726
|
+
);
|
|
5727
|
+
if (command.json) {
|
|
5728
|
+
writeJson(stdout, capabilities);
|
|
5729
|
+
return 0;
|
|
5730
|
+
}
|
|
5731
|
+
const caps = capabilities;
|
|
5732
|
+
stdout.write(
|
|
5733
|
+
`${redactSensitiveText(
|
|
5734
|
+
[
|
|
5735
|
+
`Validation: ok requestId=${String(caps.requestId ?? "")}`,
|
|
5736
|
+
...formatCapabilityLines(caps)
|
|
5737
|
+
].join("\n")
|
|
5738
|
+
)}
|
|
5739
|
+
`
|
|
5133
5740
|
);
|
|
5134
5741
|
return 0;
|
|
5742
|
+
}
|
|
5135
5743
|
case "tokens-list":
|
|
5136
5744
|
writeTokenListOutput(
|
|
5137
5745
|
stdout,
|
|
@@ -5198,11 +5806,17 @@ async function runCli(argv, dependencies = {}) {
|
|
|
5198
5806
|
request
|
|
5199
5807
|
);
|
|
5200
5808
|
if (command.idsOnly) {
|
|
5201
|
-
writeIds(stdout, response.
|
|
5809
|
+
writeIds(stdout, response.results, {
|
|
5202
5810
|
nulDelimited: command.idsNulDelimited === true
|
|
5203
5811
|
});
|
|
5204
5812
|
} else if (command.docIdsOnly) {
|
|
5205
|
-
writeParentDocumentIds(stdout, response.
|
|
5813
|
+
writeParentDocumentIds(stdout, response.results);
|
|
5814
|
+
} else if (command.passageIdsOnly) {
|
|
5815
|
+
writeEvidenceIds(stdout, response.results, "passage");
|
|
5816
|
+
} else if (command.highlightIdsOnly) {
|
|
5817
|
+
writeEvidenceIds(stdout, response.results, "highlight");
|
|
5818
|
+
} else if (command.evidenceIdsOnly) {
|
|
5819
|
+
writeEvidenceIds(stdout, response.results);
|
|
5206
5820
|
} else if (command.pretty) {
|
|
5207
5821
|
stdout.write(redactSensitiveText(renderPrettyPageOutput(response)));
|
|
5208
5822
|
} else {
|
|
@@ -5218,11 +5832,17 @@ async function runCli(argv, dependencies = {}) {
|
|
|
5218
5832
|
command.request
|
|
5219
5833
|
);
|
|
5220
5834
|
if (command.idsOnly) {
|
|
5221
|
-
writeIds(stdout, response.
|
|
5835
|
+
writeIds(stdout, response.results, {
|
|
5222
5836
|
nulDelimited: command.idsNulDelimited === true
|
|
5223
5837
|
});
|
|
5224
5838
|
} else if (command.docIdsOnly) {
|
|
5225
|
-
writeParentDocumentIds(stdout, response.
|
|
5839
|
+
writeParentDocumentIds(stdout, response.results);
|
|
5840
|
+
} else if (command.passageIdsOnly) {
|
|
5841
|
+
writeEvidenceIds(stdout, response.results, "passage");
|
|
5842
|
+
} else if (command.highlightIdsOnly) {
|
|
5843
|
+
writeEvidenceIds(stdout, response.results, "highlight");
|
|
5844
|
+
} else if (command.evidenceIdsOnly) {
|
|
5845
|
+
writeEvidenceIds(stdout, response.results);
|
|
5226
5846
|
} else if (command.pretty) {
|
|
5227
5847
|
stdout.write(redactSensitiveText(renderPrettyPageOutput(response)));
|
|
5228
5848
|
} else {
|
|
@@ -5280,16 +5900,13 @@ async function runAuthLogin(params) {
|
|
|
5280
5900
|
}
|
|
5281
5901
|
assertSafeBearerApiBaseUrl(params.config.apiBaseUrl);
|
|
5282
5902
|
const token = await loginWithPatStdin(params);
|
|
5283
|
-
const validationConfig = cliConfigWithToken(
|
|
5284
|
-
|
|
5285
|
-
|
|
5286
|
-
|
|
5903
|
+
const validationConfig = cliConfigWithToken(params.config, token, "stdin");
|
|
5904
|
+
const capabilities = await getCapabilities(
|
|
5905
|
+
validationConfig,
|
|
5906
|
+
params.fetchImpl
|
|
5287
5907
|
);
|
|
5288
|
-
let capabilities;
|
|
5289
|
-
capabilities = await getCapabilities(validationConfig, params.fetchImpl);
|
|
5290
5908
|
assertCliSupportedCapabilities(capabilities);
|
|
5291
|
-
|
|
5292
|
-
update = writeLocalAuthToken({
|
|
5909
|
+
const update = writeLocalAuthToken({
|
|
5293
5910
|
root: params.envRoot,
|
|
5294
5911
|
token,
|
|
5295
5912
|
apiBaseUrl: params.config.apiBaseUrl
|
|
@@ -5351,6 +5968,7 @@ function writeAuthLoginOutput(stdout, output, json) {
|
|
|
5351
5968
|
return;
|
|
5352
5969
|
}
|
|
5353
5970
|
stdout.write("Signed in to Papiers.\n");
|
|
5971
|
+
stdout.write("Next, try: papiers list --limit 5 --pretty\n");
|
|
5354
5972
|
}
|
|
5355
5973
|
function writeAuthLogoutOutput(stdout, output, json) {
|
|
5356
5974
|
if (json) {
|
|
@@ -5369,6 +5987,14 @@ function writeAuthLogoutOutput(stdout, output, json) {
|
|
|
5369
5987
|
stdout.write(`${redactSensitiveText(lines.join("\n"))}
|
|
5370
5988
|
`);
|
|
5371
5989
|
}
|
|
5990
|
+
function formatCapabilityLines(capabilities) {
|
|
5991
|
+
return [
|
|
5992
|
+
`Scopes: ${formatUnknownList(capabilities.scopes)}`,
|
|
5993
|
+
`Search kinds: ${formatUnknownList(capabilities.searchKinds)}`,
|
|
5994
|
+
`Read formats: ${formatUnknownList(capabilities.readFormats)}`,
|
|
5995
|
+
`Not ready: ${formatNotReady(capabilities.notReady)}`
|
|
5996
|
+
];
|
|
5997
|
+
}
|
|
5372
5998
|
function writeAuthInspectOutput(stdout, output, json) {
|
|
5373
5999
|
if (json) {
|
|
5374
6000
|
writeJson(stdout, output);
|
|
@@ -5384,10 +6010,7 @@ function writeAuthInspectOutput(stdout, output, json) {
|
|
|
5384
6010
|
`Account: userId=${String(
|
|
5385
6011
|
capabilities.account?.userId ?? "unknown"
|
|
5386
6012
|
)} 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)}`
|
|
6013
|
+
...formatCapabilityLines(capabilities)
|
|
5391
6014
|
].join("\n")
|
|
5392
6015
|
)}
|
|
5393
6016
|
`
|
|
@@ -5543,13 +6166,13 @@ function normalizeStdinToken(rawInput) {
|
|
|
5543
6166
|
const parts = rawInput.trim().split(/\s+/u).filter(Boolean);
|
|
5544
6167
|
if (parts.length !== 1) {
|
|
5545
6168
|
throw new CliUsageError(
|
|
5546
|
-
"Token stdin must contain exactly one Papiers API token."
|
|
6169
|
+
"Token stdin must contain exactly one Papiers API token (starting with pap_live_), with no surrounding whitespace."
|
|
5547
6170
|
);
|
|
5548
6171
|
}
|
|
5549
6172
|
const token = parts[0];
|
|
5550
6173
|
if (!isPapiersPat(token)) {
|
|
5551
6174
|
throw new CliUsageError(
|
|
5552
|
-
"Token stdin did not contain a valid Papiers API token."
|
|
6175
|
+
"Token stdin did not contain a valid Papiers API token; expected one starting with pap_live_."
|
|
5553
6176
|
);
|
|
5554
6177
|
}
|
|
5555
6178
|
return token;
|
|
@@ -5698,7 +6321,8 @@ function writeParentDocumentIds(stdout, items) {
|
|
|
5698
6321
|
const seen = /* @__PURE__ */ new Set();
|
|
5699
6322
|
const ids = [];
|
|
5700
6323
|
for (const item of items) {
|
|
5701
|
-
const
|
|
6324
|
+
const metadataDocumentId = item.kind === "note" && typeof item.metadata === "object" && item.metadata !== null && !Array.isArray(item.metadata) ? item.metadata.documentId : void 0;
|
|
6325
|
+
const docId = item.kind === "document" ? item.id : item.documentId ?? metadataDocumentId;
|
|
5702
6326
|
if (typeof docId !== "string" || !docId) {
|
|
5703
6327
|
continue;
|
|
5704
6328
|
}
|
|
@@ -5715,6 +6339,27 @@ function writeParentDocumentIds(stdout, items) {
|
|
|
5715
6339
|
stdout.write(ids.length === 0 ? "" : `${ids.join("\n")}
|
|
5716
6340
|
`);
|
|
5717
6341
|
}
|
|
6342
|
+
function writeEvidenceIds(stdout, results, kind) {
|
|
6343
|
+
const ids = [];
|
|
6344
|
+
for (const result of results) {
|
|
6345
|
+
if (result.kind !== "document") {
|
|
6346
|
+
continue;
|
|
6347
|
+
}
|
|
6348
|
+
for (const evidence of result.evidence) {
|
|
6349
|
+
if (kind !== void 0 && evidence.kind !== kind) {
|
|
6350
|
+
continue;
|
|
6351
|
+
}
|
|
6352
|
+
if (publicReadKindForId(evidence.id) !== evidence.kind) {
|
|
6353
|
+
throw new Error(
|
|
6354
|
+
"Papiers API returned an evidence id that did not match its kind in evidence ID output."
|
|
6355
|
+
);
|
|
6356
|
+
}
|
|
6357
|
+
ids.push(evidence.id);
|
|
6358
|
+
}
|
|
6359
|
+
}
|
|
6360
|
+
stdout.write(ids.length === 0 ? "" : `${ids.join("\n")}
|
|
6361
|
+
`);
|
|
6362
|
+
}
|
|
5718
6363
|
async function expandListDocumentIdRequest(request, documentIds, input) {
|
|
5719
6364
|
const ids = await expandDocumentIdPlaceholders(documentIds, "list", input);
|
|
5720
6365
|
if (!ids?.length) {
|
|
@@ -5940,23 +6585,23 @@ function validateReadIds(ids, context, sourceLabel) {
|
|
|
5940
6585
|
}
|
|
5941
6586
|
const kinds = /* @__PURE__ */ new Set();
|
|
5942
6587
|
for (const [index, id] of ids.entries()) {
|
|
5943
|
-
const kind =
|
|
6588
|
+
const kind = readKindForIdentifier(id);
|
|
5944
6589
|
if (!kind) {
|
|
5945
6590
|
throw new CliUsageError(
|
|
5946
|
-
`${context} ${sourceLabel} item ${index + 1} was not a
|
|
6591
|
+
`${context} ${sourceLabel} item ${index + 1} was not a public ID or papiers:// resource locator.`
|
|
5947
6592
|
);
|
|
5948
6593
|
}
|
|
5949
6594
|
kinds.add(kind);
|
|
5950
6595
|
}
|
|
5951
6596
|
if (kinds.size > 1) {
|
|
5952
6597
|
throw new CliUsageError(
|
|
5953
|
-
`${context} ${sourceLabel}
|
|
6598
|
+
`${context} ${sourceLabel} identifiers must all use the same resource kind.`
|
|
5954
6599
|
);
|
|
5955
6600
|
}
|
|
5956
6601
|
return ids;
|
|
5957
6602
|
}
|
|
5958
6603
|
function validateExpandedReadRequest(request, ids, requestedReadKind) {
|
|
5959
|
-
const kind =
|
|
6604
|
+
const kind = readKindForIdentifier(ids[0] ?? "");
|
|
5960
6605
|
if (requestedReadKind && kind && requestedReadKind !== kind) {
|
|
5961
6606
|
throw new CliUsageError(
|
|
5962
6607
|
`papiers read --kind ${requestedReadKind} does not match ${kind} IDs.`
|
|
@@ -5987,6 +6632,25 @@ function validateExpandedReadRequest(request, ids, requestedReadKind) {
|
|
|
5987
6632
|
}
|
|
5988
6633
|
if (kind === "equation") {
|
|
5989
6634
|
validateMetadataOnlyReadRequest(request, kind);
|
|
6635
|
+
return;
|
|
6636
|
+
}
|
|
6637
|
+
if (kind === "note") {
|
|
6638
|
+
validateNoteReadRequest(request);
|
|
6639
|
+
}
|
|
6640
|
+
}
|
|
6641
|
+
function validateNoteReadRequest(request) {
|
|
6642
|
+
if (request.format !== void 0 && request.format !== "auto" && request.format !== "markdown" && request.format !== "plain") {
|
|
6643
|
+
throw new CliUsageError(
|
|
6644
|
+
"Public note read supports --format markdown, plain, or auto."
|
|
6645
|
+
);
|
|
6646
|
+
}
|
|
6647
|
+
if (request.include?.some((include) => include !== "metadata")) {
|
|
6648
|
+
throw new CliUsageError(
|
|
6649
|
+
"Public note read supports only --include metadata."
|
|
6650
|
+
);
|
|
6651
|
+
}
|
|
6652
|
+
if (request.scope?.pages || request.scope?.sectionId) {
|
|
6653
|
+
throw new CliUsageError("Public note read does not support --pages.");
|
|
5990
6654
|
}
|
|
5991
6655
|
}
|
|
5992
6656
|
function validateContentCapableReadRequest(request, kind) {
|
|
@@ -6036,7 +6700,7 @@ function parseJsonEnvelopeIds(input, context, sourceLabel) {
|
|
|
6036
6700
|
}
|
|
6037
6701
|
if (input.startsWith("[")) {
|
|
6038
6702
|
throw new CliUsageError(
|
|
6039
|
-
`${context} JSON ${sourceLabel} must be a Papiers envelope with schemaVersion and items[].id.`
|
|
6703
|
+
`${context} JSON ${sourceLabel} must be a Papiers envelope with schemaVersion and items[].id or results[].id.`
|
|
6040
6704
|
);
|
|
6041
6705
|
}
|
|
6042
6706
|
let parsed;
|
|
@@ -6049,7 +6713,7 @@ function parseJsonEnvelopeIds(input, context, sourceLabel) {
|
|
|
6049
6713
|
}
|
|
6050
6714
|
if (!parsed || typeof parsed !== "object") {
|
|
6051
6715
|
throw new CliUsageError(
|
|
6052
|
-
`${context} JSON ${sourceLabel} must be a Papiers envelope with schemaVersion and items[].id.`
|
|
6716
|
+
`${context} JSON ${sourceLabel} must be a Papiers envelope with schemaVersion and items[].id or results[].id.`
|
|
6053
6717
|
);
|
|
6054
6718
|
}
|
|
6055
6719
|
const envelope = parsed;
|
|
@@ -6062,7 +6726,7 @@ function parseJsonEnvelopeIds(input, context, sourceLabel) {
|
|
|
6062
6726
|
if (envelope.schemaVersion === PAPIERS_SCHEMA_VERSIONS.list) {
|
|
6063
6727
|
assertPapiersListResponse(`${context} list envelope`, parsed);
|
|
6064
6728
|
} else if (envelope.schemaVersion === PAPIERS_SCHEMA_VERSIONS.search) {
|
|
6065
|
-
|
|
6729
|
+
validateSearchPipelineEnvelope(`${context} search envelope`, parsed);
|
|
6066
6730
|
} else {
|
|
6067
6731
|
assertPapiersReadPipelineEnvelope(`${context} read envelope`, parsed);
|
|
6068
6732
|
}
|
|
@@ -6074,10 +6738,10 @@ function parseJsonEnvelopeIds(input, context, sourceLabel) {
|
|
|
6074
6738
|
}
|
|
6075
6739
|
throw error;
|
|
6076
6740
|
}
|
|
6077
|
-
const items = envelope.items;
|
|
6741
|
+
const items = envelope.schemaVersion === PAPIERS_SCHEMA_VERSIONS.search ? envelope.results : envelope.items;
|
|
6078
6742
|
if (!Array.isArray(items)) {
|
|
6079
6743
|
throw new CliUsageError(
|
|
6080
|
-
`${context} JSON ${sourceLabel} must be a Papiers envelope with items[].id.`
|
|
6744
|
+
`${context} JSON ${sourceLabel} must be a Papiers envelope with items[].id or results[].id.`
|
|
6081
6745
|
);
|
|
6082
6746
|
}
|
|
6083
6747
|
return items.map((item, index) => {
|
|
@@ -6093,15 +6757,28 @@ function parseJsonEnvelopeIds(input, context, sourceLabel) {
|
|
|
6093
6757
|
);
|
|
6094
6758
|
}
|
|
6095
6759
|
const kind = item.kind;
|
|
6096
|
-
const idKind = publicReadKindForId(id);
|
|
6760
|
+
const idKind = envelope.schemaVersion === PAPIERS_SCHEMA_VERSIONS.read ? readKindForIdentifier(id) : publicReadKindForId(id);
|
|
6097
6761
|
if (kind !== idKind) {
|
|
6098
6762
|
throw new CliUsageError(
|
|
6099
|
-
`${context} JSON item ${index} kind did not match its
|
|
6763
|
+
`${context} JSON item ${index} kind did not match its identifier.`
|
|
6100
6764
|
);
|
|
6101
6765
|
}
|
|
6102
6766
|
return id;
|
|
6103
6767
|
});
|
|
6104
6768
|
}
|
|
6769
|
+
function validateSearchPipelineEnvelope(label, parsed) {
|
|
6770
|
+
const envelope = parsed;
|
|
6771
|
+
const ranking = envelope.ranking && typeof envelope.ranking === "object" && !Array.isArray(envelope.ranking) ? envelope.ranking : null;
|
|
6772
|
+
if (ranking && ("offset" in ranking || "nextOffset" in ranking)) {
|
|
6773
|
+
assertPapiersSearchResultsResponse(label, parsed, {
|
|
6774
|
+
schemaVersion: PAPIERS_SCHEMA_VERSIONS.searchResultsRequest,
|
|
6775
|
+
searchId: typeof ranking.searchId === "string" ? ranking.searchId : "",
|
|
6776
|
+
offset: typeof ranking.offset === "number" ? ranking.offset : void 0
|
|
6777
|
+
});
|
|
6778
|
+
return;
|
|
6779
|
+
}
|
|
6780
|
+
assertPapiersSearchResponse(label, parsed);
|
|
6781
|
+
}
|
|
6105
6782
|
function parseTextIds(input) {
|
|
6106
6783
|
return input.split(/[\s,]+/u).filter(Boolean);
|
|
6107
6784
|
}
|
|
@@ -6120,9 +6797,20 @@ function writeCliError(error, params) {
|
|
|
6120
6797
|
`${redactSensitiveText(serialized.body.error.message)}
|
|
6121
6798
|
`
|
|
6122
6799
|
);
|
|
6800
|
+
const hint = humanErrorHint(error);
|
|
6801
|
+
if (hint) {
|
|
6802
|
+
params.stderr.write(`${hint}
|
|
6803
|
+
`);
|
|
6804
|
+
}
|
|
6123
6805
|
}
|
|
6124
6806
|
return serialized.exitCode;
|
|
6125
6807
|
}
|
|
6808
|
+
function humanErrorHint(error) {
|
|
6809
|
+
if (error instanceof PapiersCliApiError && error.status === 401) {
|
|
6810
|
+
return "Your token may be expired or revoked. Run papiers auth login --force to replace it.";
|
|
6811
|
+
}
|
|
6812
|
+
return null;
|
|
6813
|
+
}
|
|
6126
6814
|
function serializeCliError(error) {
|
|
6127
6815
|
if (error instanceof PapiersCliApiError) {
|
|
6128
6816
|
return {
|