@longtable/cli 0.1.28 → 0.1.30
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 +7 -0
- package/dist/cli.js +202 -6
- package/dist/search/index.d.ts +6 -0
- package/dist/search/index.js +6 -0
- package/dist/search/publisher-access.d.ts +23 -0
- package/dist/search/publisher-access.js +577 -0
- package/dist/search/query.d.ts +6 -0
- package/dist/search/query.js +179 -0
- package/dist/search/rank.d.ts +2 -0
- package/dist/search/rank.js +173 -0
- package/dist/search/run.d.ts +2 -0
- package/dist/search/run.js +114 -0
- package/dist/search/sources.d.ts +5 -0
- package/dist/search/sources.js +537 -0
- package/dist/search/types.d.ts +187 -0
- package/dist/search/types.js +16 -0
- package/package.json +7 -8
package/README.md
CHANGED
|
@@ -200,11 +200,18 @@ deduplicates, ranks, and labels results as evidence cards. Some sources work
|
|
|
200
200
|
without keys, some require a contact email, and some need API keys for reliable
|
|
201
201
|
use.
|
|
202
202
|
|
|
203
|
+
Publisher access is configured separately through environment variables and
|
|
204
|
+
DOI probes. `longtable search setup` checks Elsevier, Springer Nature, Wiley,
|
|
205
|
+
and Taylor & Francis credentials or TDM tokens without storing secrets.
|
|
206
|
+
|
|
203
207
|
Citation support should be checked explicitly. A reference can be useful as
|
|
204
208
|
background while still failing to support the specific claim attached to it.
|
|
205
209
|
|
|
206
210
|
```bash
|
|
211
|
+
longtable search setup
|
|
212
|
+
longtable search probe --doi "10.1016/example" --publisher elsevier
|
|
207
213
|
longtable search --query "trust calibration measurement" --intent measurement
|
|
214
|
+
longtable search --query "trust calibration measurement" --publisher-access --json
|
|
208
215
|
longtable search --query "trust calibration citation support" --intent citation --record
|
|
209
216
|
```
|
|
210
217
|
|
package/dist/cli.js
CHANGED
|
@@ -8,7 +8,7 @@ import { stdin as input, stdout as output, cwd, env, exit } from "node:process";
|
|
|
8
8
|
import { dirname, join, resolve } from "node:path";
|
|
9
9
|
import { homedir } from "node:os";
|
|
10
10
|
import { classifyCheckpointTrigger } from "@longtable/checkpoints";
|
|
11
|
-
import { assessSearchSourceCapabilities, buildResearchSearchIntent, runResearchSearch } from "
|
|
11
|
+
import { assessSearchSourceCapabilities, buildResearchSearchIntent, buildSearchCapabilitySnapshot, parsePublisherTarget, probePublisherAccess, publisherConfigs, runResearchSearch, searchCapabilitySnapshotPath, summarizeConfiguredPublisherAccess } from "./search/index.js";
|
|
12
12
|
import { buildProviderChoices, buildQuickSetupFlow, createPersistedSetupOutput, installRuntimeConfigFromStoredSetup, loadSetupOutput, renderInstallSummary, renderSetupSummary, resolveDefaultRuntimeConfigPath, resolveDefaultSetupPath, saveSetupOutput, saveSetupAndRuntimeConfig, serializeSetupOutput, writeRuntimeConfig } from "@longtable/setup";
|
|
13
13
|
import { buildCodexSkillSpecs, buildCodexThinWrappedPrompt, installCodexSkills, listInstalledCodexSkills, renderQuestionRecordPrompt, removeCodexSkills, resolveCodexSkillsDir, runCodexThinWrapper } from "@longtable/provider-codex";
|
|
14
14
|
import { buildClaudeSkillSpecs, installClaudeSkills, listInstalledClaudeSkills, renderQuestionRecordInput, removeClaudeSkills, resolveClaudeSkillsDir } from "@longtable/provider-claude";
|
|
@@ -43,7 +43,7 @@ const ANSI = {
|
|
|
43
43
|
green: "\u001B[32m"
|
|
44
44
|
};
|
|
45
45
|
const LONGTABLE_MCP_SERVER_NAME = "longtable-state";
|
|
46
|
-
const LONGTABLE_MCP_PACKAGE_VERSION = "0.1.
|
|
46
|
+
const LONGTABLE_MCP_PACKAGE_VERSION = "0.1.30";
|
|
47
47
|
const LONGTABLE_MCP_MARKER_START = "# LongTable state MCP START";
|
|
48
48
|
const LONGTABLE_MCP_MARKER_END = "# LongTable state MCP END";
|
|
49
49
|
function style(text, prefix) {
|
|
@@ -89,7 +89,10 @@ function usage() {
|
|
|
89
89
|
" longtable show [--json] [--path <file>]",
|
|
90
90
|
" longtable install [--json] [--path <file>] [--runtime-path <file>]",
|
|
91
91
|
" longtable mcp install [--provider codex|claude|all] [--write] [--checkpoint-ui off|interactive|strong] [--json] [--codex-config <path>] [--claude-settings <path>] [--package <spec>]",
|
|
92
|
-
" longtable search --query <text> [--intent literature|theory|measurement|citation|metadata|venue] [--field <text>] [--source all|crossref,arxiv,openalex,semantic_scholar,pubmed,eric,doaj,unpaywall] [--must <term[,term]>] [--exclude <term[,term]>] [--limit <n>] [--allow-partial] [--record] [--cwd <path>] [--json]",
|
|
92
|
+
" longtable search --query <text> [--intent literature|theory|measurement|citation|metadata|venue] [--field <text>] [--source all|crossref,arxiv,openalex,semantic_scholar,pubmed,eric,doaj,unpaywall] [--must <term[,term]>] [--exclude <term[,term]>] [--limit <n>] [--allow-partial] [--publisher-access] [--record] [--cwd <path>] [--json]",
|
|
93
|
+
" longtable search setup [--doi <doi>] [--json]",
|
|
94
|
+
" longtable search doctor [--doi <doi>] [--publisher auto|elsevier|springer_nature|wiley|taylor_francis|all] [--json]",
|
|
95
|
+
" longtable search probe --doi <doi> [--publisher auto|elsevier|springer_nature|wiley|taylor_francis] [--json]",
|
|
93
96
|
" longtable sentinel --prompt <text> [--cwd <path>] [--json] [--record]",
|
|
94
97
|
" longtable team --prompt <text> [--role <role[,role]>] [--debate] [--rounds 3|5] [--cwd <path>] [--json]",
|
|
95
98
|
" longtable ask [--prompt <text>] [--print] [--json] [--setup <path>] [--cwd <path>]",
|
|
@@ -136,6 +139,10 @@ function parseArgs(argv) {
|
|
|
136
139
|
else if (command === "codex" || command === "claude" || command === "mcp") {
|
|
137
140
|
startIndex = 2;
|
|
138
141
|
}
|
|
142
|
+
else if (command === "search" && maybeSubcommand && !maybeSubcommand.startsWith("--")) {
|
|
143
|
+
subcommand = maybeSubcommand;
|
|
144
|
+
startIndex = 2;
|
|
145
|
+
}
|
|
139
146
|
else if (directCommand) {
|
|
140
147
|
subcommand = undefined;
|
|
141
148
|
startIndex = 1;
|
|
@@ -2013,6 +2020,7 @@ function renderEvidenceRunSummary(run, recordedPath) {
|
|
|
2013
2020
|
].filter(Boolean).join(", ");
|
|
2014
2021
|
lines.push(` - ${card.title}`);
|
|
2015
2022
|
lines.push(` score: ${card.relevanceScore}; support: ${card.citationSupportStatus}; depth: ${card.evidenceDepth}; sources: ${card.sourceRoutes.join(", ")}`);
|
|
2023
|
+
lines.push(` access: ${card.accessStatus}; verification: ${card.verificationNote}`);
|
|
2016
2024
|
if (identifiers) {
|
|
2017
2025
|
lines.push(` ids: ${identifiers}`);
|
|
2018
2026
|
}
|
|
@@ -2056,7 +2064,194 @@ async function recordEvidenceRun(run, workingDirectory) {
|
|
|
2056
2064
|
await syncCurrentWorkspaceView(context);
|
|
2057
2065
|
return evidencePath;
|
|
2058
2066
|
}
|
|
2059
|
-
|
|
2067
|
+
function renderPublisherAccessRecord(record) {
|
|
2068
|
+
const envSummary = record.missingEnv.length > 0
|
|
2069
|
+
? `missing ${record.missingEnv.join(", ")}`
|
|
2070
|
+
: `configured ${record.presentEnv.join(", ") || "none"}`;
|
|
2071
|
+
const lines = [
|
|
2072
|
+
`${record.publisher}:`,
|
|
2073
|
+
` credential: ${record.credentialStatus} (${envSummary})`,
|
|
2074
|
+
` entitlement: ${record.entitlementStatus}; tdm: ${record.tdmStatus}; depth: ${record.collectionDepth}`,
|
|
2075
|
+
` verification: ${record.verificationNote}`
|
|
2076
|
+
];
|
|
2077
|
+
if (record.testedDoi) {
|
|
2078
|
+
lines.push(` tested doi: ${record.testedDoi}`);
|
|
2079
|
+
}
|
|
2080
|
+
if (record.endpoint) {
|
|
2081
|
+
lines.push(` endpoint: ${record.endpoint}`);
|
|
2082
|
+
}
|
|
2083
|
+
if (record.licenseNote) {
|
|
2084
|
+
lines.push(` license: ${record.licenseNote}`);
|
|
2085
|
+
}
|
|
2086
|
+
if (record.setupHint) {
|
|
2087
|
+
lines.push(` setup: ${record.setupHint}`);
|
|
2088
|
+
}
|
|
2089
|
+
return lines.join("\n");
|
|
2090
|
+
}
|
|
2091
|
+
function renderPublisherAccessRecords(title, records, capabilityPath) {
|
|
2092
|
+
const lines = [title];
|
|
2093
|
+
if (capabilityPath) {
|
|
2094
|
+
lines.push(`- capability file: ${capabilityPath}`);
|
|
2095
|
+
}
|
|
2096
|
+
for (const record of records) {
|
|
2097
|
+
lines.push(renderPublisherAccessRecord(record));
|
|
2098
|
+
}
|
|
2099
|
+
return lines.join("\n");
|
|
2100
|
+
}
|
|
2101
|
+
async function saveSearchCapabilityRecords(records) {
|
|
2102
|
+
const snapshotPath = searchCapabilitySnapshotPath();
|
|
2103
|
+
await mkdir(dirname(snapshotPath), { recursive: true });
|
|
2104
|
+
await writeJsonFile(snapshotPath, buildSearchCapabilitySnapshot(records, env));
|
|
2105
|
+
return snapshotPath;
|
|
2106
|
+
}
|
|
2107
|
+
async function probeAllPublishers(doi) {
|
|
2108
|
+
const records = [];
|
|
2109
|
+
for (const publisher of publisherConfigs()) {
|
|
2110
|
+
records.push(await probePublisherAccess({
|
|
2111
|
+
doi,
|
|
2112
|
+
publisher: publisher.publisher,
|
|
2113
|
+
env
|
|
2114
|
+
}));
|
|
2115
|
+
}
|
|
2116
|
+
return records;
|
|
2117
|
+
}
|
|
2118
|
+
async function runSearchProbe(args) {
|
|
2119
|
+
if (typeof args.doi !== "string" || !args.doi.trim()) {
|
|
2120
|
+
throw new Error("`longtable search probe` requires --doi <doi>.");
|
|
2121
|
+
}
|
|
2122
|
+
const publisher = parsePublisherTarget(args.publisher);
|
|
2123
|
+
const record = await probePublisherAccess({
|
|
2124
|
+
doi: args.doi,
|
|
2125
|
+
publisher,
|
|
2126
|
+
env
|
|
2127
|
+
});
|
|
2128
|
+
if (args.json === true) {
|
|
2129
|
+
console.log(JSON.stringify({ record }, null, 2));
|
|
2130
|
+
}
|
|
2131
|
+
else {
|
|
2132
|
+
console.log(renderPublisherAccessRecord(record));
|
|
2133
|
+
}
|
|
2134
|
+
return [record];
|
|
2135
|
+
}
|
|
2136
|
+
async function runSearchDoctor(args) {
|
|
2137
|
+
let records;
|
|
2138
|
+
if (typeof args.doi === "string" && args.doi.trim()) {
|
|
2139
|
+
if (args.publisher === "all") {
|
|
2140
|
+
records = await probeAllPublishers(args.doi);
|
|
2141
|
+
}
|
|
2142
|
+
else {
|
|
2143
|
+
const publisher = parsePublisherTarget(args.publisher);
|
|
2144
|
+
records = [await probePublisherAccess({
|
|
2145
|
+
doi: args.doi,
|
|
2146
|
+
publisher,
|
|
2147
|
+
env
|
|
2148
|
+
})];
|
|
2149
|
+
}
|
|
2150
|
+
}
|
|
2151
|
+
else {
|
|
2152
|
+
records = summarizeConfiguredPublisherAccess(env);
|
|
2153
|
+
}
|
|
2154
|
+
const snapshotPath = searchCapabilitySnapshotPath();
|
|
2155
|
+
const snapshotExists = existsSync(snapshotPath);
|
|
2156
|
+
if (args.json === true) {
|
|
2157
|
+
console.log(JSON.stringify({
|
|
2158
|
+
capabilityFile: snapshotPath,
|
|
2159
|
+
capabilityFileExists: snapshotExists,
|
|
2160
|
+
records
|
|
2161
|
+
}, null, 2));
|
|
2162
|
+
}
|
|
2163
|
+
else {
|
|
2164
|
+
console.log(renderPublisherAccessRecords("LongTable Search Publisher Access Doctor", records, snapshotPath));
|
|
2165
|
+
if (!snapshotExists) {
|
|
2166
|
+
console.log("- saved capabilities: none yet; run `longtable search setup` to record non-secret capability status.");
|
|
2167
|
+
}
|
|
2168
|
+
}
|
|
2169
|
+
return records;
|
|
2170
|
+
}
|
|
2171
|
+
async function promptPublisherDoi(rl, label, defaultDoi) {
|
|
2172
|
+
const prompt = defaultDoi
|
|
2173
|
+
? `${label} test DOI [${defaultDoi}, Enter to reuse, skip to skip]: `
|
|
2174
|
+
: `${label} test DOI (Enter to skip): `;
|
|
2175
|
+
const answer = (await rl.question(prompt)).trim();
|
|
2176
|
+
if (!answer && defaultDoi) {
|
|
2177
|
+
return defaultDoi;
|
|
2178
|
+
}
|
|
2179
|
+
if (!answer || /^skip$/i.test(answer)) {
|
|
2180
|
+
return undefined;
|
|
2181
|
+
}
|
|
2182
|
+
return answer;
|
|
2183
|
+
}
|
|
2184
|
+
async function runInteractiveSearchSetup(defaultDoi) {
|
|
2185
|
+
const rl = createInterface({ input, output });
|
|
2186
|
+
const records = [];
|
|
2187
|
+
try {
|
|
2188
|
+
console.log("LongTable publisher access setup");
|
|
2189
|
+
console.log("LongTable does not store API keys or TDM tokens. It reads environment variables and records only non-secret capability results.");
|
|
2190
|
+
console.log("");
|
|
2191
|
+
for (const publisher of publisherConfigs()) {
|
|
2192
|
+
console.log(`${publisher.label}`);
|
|
2193
|
+
console.log(` required env: ${publisher.requiredEnv.join(", ")}`);
|
|
2194
|
+
if (publisher.optionalEnv.length > 0) {
|
|
2195
|
+
console.log(` optional env: ${publisher.optionalEnv.join(", ")}`);
|
|
2196
|
+
}
|
|
2197
|
+
console.log(` ${publisher.setupHint}`);
|
|
2198
|
+
const doi = await promptPublisherDoi(rl, publisher.label, defaultDoi);
|
|
2199
|
+
if (doi) {
|
|
2200
|
+
records.push(await probePublisherAccess({
|
|
2201
|
+
doi,
|
|
2202
|
+
publisher: publisher.publisher,
|
|
2203
|
+
env
|
|
2204
|
+
}));
|
|
2205
|
+
}
|
|
2206
|
+
else {
|
|
2207
|
+
const summary = summarizeConfiguredPublisherAccess(env)
|
|
2208
|
+
.find((record) => record.publisher === publisher.publisher);
|
|
2209
|
+
if (summary) {
|
|
2210
|
+
records.push(summary);
|
|
2211
|
+
}
|
|
2212
|
+
}
|
|
2213
|
+
console.log(renderPublisherAccessRecord(records[records.length - 1]));
|
|
2214
|
+
console.log("");
|
|
2215
|
+
}
|
|
2216
|
+
}
|
|
2217
|
+
finally {
|
|
2218
|
+
rl.close();
|
|
2219
|
+
}
|
|
2220
|
+
return records;
|
|
2221
|
+
}
|
|
2222
|
+
async function runSearchSetup(args) {
|
|
2223
|
+
const defaultDoi = typeof args.doi === "string" ? args.doi : undefined;
|
|
2224
|
+
const records = input.isTTY && output.isTTY && args.json !== true
|
|
2225
|
+
? await runInteractiveSearchSetup(defaultDoi)
|
|
2226
|
+
: defaultDoi
|
|
2227
|
+
? await probeAllPublishers(defaultDoi)
|
|
2228
|
+
: summarizeConfiguredPublisherAccess(env);
|
|
2229
|
+
const snapshotPath = await saveSearchCapabilityRecords(records);
|
|
2230
|
+
if (args.json === true) {
|
|
2231
|
+
console.log(JSON.stringify({
|
|
2232
|
+
capabilityFile: snapshotPath,
|
|
2233
|
+
snapshot: buildSearchCapabilitySnapshot(records, env)
|
|
2234
|
+
}, null, 2));
|
|
2235
|
+
return;
|
|
2236
|
+
}
|
|
2237
|
+
console.log(renderPublisherAccessRecords("LongTable Search Publisher Access Setup", records, snapshotPath));
|
|
2238
|
+
}
|
|
2239
|
+
async function runSearch(subcommand, args) {
|
|
2240
|
+
if (subcommand === "probe") {
|
|
2241
|
+
await runSearchProbe(args);
|
|
2242
|
+
return;
|
|
2243
|
+
}
|
|
2244
|
+
if (subcommand === "doctor" || subcommand === "status") {
|
|
2245
|
+
await runSearchDoctor(args);
|
|
2246
|
+
return;
|
|
2247
|
+
}
|
|
2248
|
+
if (subcommand === "setup") {
|
|
2249
|
+
await runSearchSetup(args);
|
|
2250
|
+
return;
|
|
2251
|
+
}
|
|
2252
|
+
if (subcommand) {
|
|
2253
|
+
throw new Error(`Unknown search subcommand: ${subcommand}`);
|
|
2254
|
+
}
|
|
2060
2255
|
const workingDirectory = typeof args.cwd === "string" ? args.cwd : cwd();
|
|
2061
2256
|
const projectContext = await loadProjectContextFromDirectory(workingDirectory);
|
|
2062
2257
|
const searchInput = {
|
|
@@ -2082,7 +2277,8 @@ async function runSearch(args) {
|
|
|
2082
2277
|
const run = await runResearchSearch({
|
|
2083
2278
|
...searchInput,
|
|
2084
2279
|
env,
|
|
2085
|
-
allowPartial
|
|
2280
|
+
allowPartial,
|
|
2281
|
+
publisherAccess: args["publisher-access"] === true
|
|
2086
2282
|
});
|
|
2087
2283
|
let recordedPath;
|
|
2088
2284
|
if (args.record === true && run.status !== "blocked") {
|
|
@@ -2907,7 +3103,7 @@ async function main() {
|
|
|
2907
3103
|
return;
|
|
2908
3104
|
}
|
|
2909
3105
|
if (command === "search") {
|
|
2910
|
-
await runSearch(values);
|
|
3106
|
+
await runSearch(subcommand, values);
|
|
2911
3107
|
return;
|
|
2912
3108
|
}
|
|
2913
3109
|
if (command === "ask") {
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { type CrossrefTdmDiscovery, type EvidenceCard, type Publisher, type PublisherAccessRecord, type PublisherProbeInput, type PublisherProbeTarget, type SearchCapabilitySnapshot, type SearchFetch } from "./types.js";
|
|
2
|
+
interface PublisherConfig {
|
|
3
|
+
publisher: Publisher;
|
|
4
|
+
label: string;
|
|
5
|
+
requiredEnv: string[];
|
|
6
|
+
optionalEnv: string[];
|
|
7
|
+
setupHint: string;
|
|
8
|
+
}
|
|
9
|
+
export declare function normalizeDoi(value: string): string;
|
|
10
|
+
export declare function parsePublisherTarget(value?: string | boolean): PublisherProbeTarget;
|
|
11
|
+
export declare function discoverCrossrefTdm(doi: string, env?: Record<string, string | undefined>, httpFetch?: SearchFetch): Promise<CrossrefTdmDiscovery>;
|
|
12
|
+
export declare function publisherConfigs(): PublisherConfig[];
|
|
13
|
+
export declare function probePublisherAccess(input: PublisherProbeInput): Promise<PublisherAccessRecord>;
|
|
14
|
+
export declare function summarizeConfiguredPublisherAccess(env?: Record<string, string | undefined>): PublisherAccessRecord[];
|
|
15
|
+
export declare function buildSearchCapabilitySnapshot(records: PublisherAccessRecord[], env?: Record<string, string | undefined>): SearchCapabilitySnapshot;
|
|
16
|
+
export declare function searchCapabilitySnapshotPath(home?: string): string;
|
|
17
|
+
export declare function enrichCardsWithPublisherAccess(input: {
|
|
18
|
+
cards: EvidenceCard[];
|
|
19
|
+
env?: Record<string, string | undefined>;
|
|
20
|
+
fetch?: SearchFetch;
|
|
21
|
+
limit?: number;
|
|
22
|
+
}): Promise<EvidenceCard[]>;
|
|
23
|
+
export {};
|