papilot 0.8.2 → 0.8.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +2 -2
- package/bin/doctor.mjs +1 -1
- package/dist/assets/{_virtual_papilot-licenses-CMfCtEYQ.js → _virtual_papilot-licenses-YJbh9c1G.js} +1 -1
- package/dist/assets/index-0siHHtfz.js +267 -0
- package/dist/assets/index-CxdYm81a.css +1 -0
- package/dist/assets/{math-CEU4m4-H.js → math-ibBpTslk.js} +1 -1
- package/dist/assets/{pdf-view-HWRGBLsZ.js → pdf-view-CD1kNKYH.js} +1 -1
- package/dist/index.html +2 -2
- package/engine/dist/web/assets/FullPaper-DUgLb01O.js +54 -0
- package/engine/dist/web/assets/index-D3_ZFdT8.css +1 -0
- package/engine/dist/web/assets/index-DJywe0wU.js +19 -0
- package/engine/dist/web/assets/pdf.worker.min-CjEcRF4W.mjs +28 -0
- package/{vendor/latex-review → engine}/dist/web/index.html +2 -2
- package/engine/package-lock.json +3390 -0
- package/engine/package.json +50 -0
- package/{vendor/latex-review → engine}/src/core/build.ts +22 -6
- package/engine/src/core/progress.ts +67 -0
- package/{vendor/latex-review → engine}/src/core/review.ts +32 -0
- package/{vendor/latex-review → engine}/src/render/inline.ts +1 -0
- package/{vendor/latex-review → engine}/src/render/locate.ts +26 -16
- package/engine/src/render/positions.ts +34 -0
- package/engine/src/render/synctex.ts +188 -0
- package/engine/src/render/synctex.wasm +0 -0
- package/engine/src/render/synctex.wasm.LICENSE +50 -0
- package/{vendor/latex-review → engine}/src/server.ts +5 -3
- package/{vendor/latex-review → engine}/src/types.ts +13 -0
- package/engine/src/web/FullPaper.tsx +318 -0
- package/{vendor/latex-review → engine}/src/web/locales/de.json +3 -0
- package/{vendor/latex-review → engine}/src/web/locales/es.json +3 -0
- package/{vendor/latex-review → engine}/src/web/locales/fr.json +3 -0
- package/{vendor/latex-review → engine}/src/web/locales/it.json +3 -0
- package/{vendor/latex-review → engine}/src/web/locales/ja.json +3 -0
- package/{vendor/latex-review → engine}/src/web/locales/ko.json +3 -0
- package/{vendor/latex-review → engine}/src/web/locales/pt.json +3 -0
- package/{vendor/latex-review → engine}/src/web/locales/sv.json +3 -0
- package/{vendor/latex-review → engine}/src/web/locales/zh-Hant.json +3 -0
- package/engine/src/web/paper.ts +13 -0
- package/{vendor/latex-review → engine}/src/web/review.tsx +98 -1
- package/{vendor/latex-review → engine}/src/web/style.css +70 -0
- package/engine/src/web/view-preferences.ts +13 -0
- package/{vendor/latex-review → engine}/src/web/zh-CN.ts +3 -0
- package/package.json +10 -8
- package/src/conversation.ts +1 -1
- package/src/server/app.ts +16 -0
- package/src/server/changes.ts +12 -3
- package/src/server/imports.ts +9 -4
- package/src/server/main.ts +3 -2
- package/src/server/manuscript.ts +5 -4
- package/src/server/paths.ts +1 -1
- package/src/server/start.ts +3 -10
- package/src/server/update-install.ts +8 -25
- package/src/server/updates.ts +43 -25
- package/src/shared.ts +6 -3
- package/vendor/latex-review/package-lock.json +4 -3106
- package/vendor/latex-review/package.json +3 -46
- package/README.de.md +0 -110
- package/README.es.md +0 -110
- package/README.fr.md +0 -110
- package/README.it.md +0 -110
- package/README.ja.md +0 -110
- package/README.ko.md +0 -110
- package/README.pt.md +0 -110
- package/README.sv.md +0 -110
- package/README.zh-CN.md +0 -110
- package/README.zh-Hant.md +0 -110
- package/dist/assets/index-oAIkxhfp.js +0 -265
- package/dist/assets/index-t_qCOF_B.css +0 -1
- package/vendor/latex-review/dist/web/assets/index-DVs7cTBl.js +0 -19
- package/vendor/latex-review/dist/web/assets/index-ysOpu05D.css +0 -1
- /package/{vendor/latex-review → engine}/LICENSE +0 -0
- /package/{vendor/latex-review → engine}/dist/web/assets/TeXGyrePagellaX-Bold-CEtYdOXj.otf +0 -0
- /package/{vendor/latex-review → engine}/dist/web/assets/TeXGyrePagellaX-Regular-DQJjZE_L.otf +0 -0
- /package/{vendor/latex-review → engine}/src/cli.ts +0 -0
- /package/{vendor/latex-review → engine}/src/client.ts +0 -0
- /package/{vendor/latex-review → engine}/src/core/bib.ts +0 -0
- /package/{vendor/latex-review → engine}/src/core/changes.ts +0 -0
- /package/{vendor/latex-review → engine}/src/core/config.ts +0 -0
- /package/{vendor/latex-review → engine}/src/core/current-commit.ts +0 -0
- /package/{vendor/latex-review → engine}/src/core/delivery.ts +0 -0
- /package/{vendor/latex-review → engine}/src/core/diff.ts +0 -0
- /package/{vendor/latex-review → engine}/src/core/files.ts +0 -0
- /package/{vendor/latex-review → engine}/src/core/git.ts +0 -0
- /package/{vendor/latex-review → engine}/src/core/outline.ts +0 -0
- /package/{vendor/latex-review → engine}/src/core/process.ts +0 -0
- /package/{vendor/latex-review → engine}/src/core/publish.ts +0 -0
- /package/{vendor/latex-review → engine}/src/core/reconcile.ts +0 -0
- /package/{vendor/latex-review → engine}/src/core/store.ts +0 -0
- /package/{vendor/latex-review → engine}/src/core/tasks.ts +0 -0
- /package/{vendor/latex-review → engine}/src/core/verify.ts +0 -0
- /package/{vendor/latex-review → engine}/src/core/view.ts +0 -0
- /package/{vendor/latex-review → engine}/src/locales.ts +0 -0
- /package/{vendor/latex-review → engine}/src/render/effects.ts +0 -0
- /package/{vendor/latex-review → engine}/src/render/pdf.ts +0 -0
- /package/{vendor/latex-review → engine}/src/render/pdfdiff.ts +0 -0
- /package/{vendor/latex-review → engine}/src/render/round.ts +0 -0
- /package/{vendor/latex-review → engine}/src/render/worker.ts +0 -0
- /package/{vendor/latex-review → engine}/src/runtime.ts +0 -0
- /package/{vendor/latex-review → engine}/src/web/ChangeMap.tsx +0 -0
- /package/{vendor/latex-review → engine}/src/web/PdfStrip.tsx +0 -0
- /package/{vendor/latex-review → engine}/src/web/effect-preferences.ts +0 -0
- /package/{vendor/latex-review → engine}/src/web/fonts/GUST-FONT-LICENSE.txt +0 -0
- /package/{vendor/latex-review → engine}/src/web/fonts/LPPL.txt +0 -0
- /package/{vendor/latex-review → engine}/src/web/fonts/MANIFEST-newpx.txt +0 -0
- /package/{vendor/latex-review → engine}/src/web/fonts/README-newpx.txt +0 -0
- /package/{vendor/latex-review → engine}/src/web/fonts/README.md +0 -0
- /package/{vendor/latex-review → engine}/src/web/fonts/TeXGyrePagellaX-Bold.otf +0 -0
- /package/{vendor/latex-review → engine}/src/web/fonts/TeXGyrePagellaX-Regular.otf +0 -0
- /package/{vendor/latex-review → engine}/src/web/i18n.ts +0 -0
- /package/{vendor/latex-review → engine}/src/web/index.html +0 -0
- /package/{vendor/latex-review → engine}/src/web/locales/index.ts +0 -0
- /package/{vendor/latex-review → engine}/src/web/main.tsx +0 -0
- /package/{vendor/latex-review → engine}/src/web/model.ts +0 -0
- /package/{vendor/latex-review → engine}/src/web/overview.tsx +0 -0
- /package/{vendor/latex-review → engine}/src/web/references.tsx +0 -0
- /package/{vendor/latex-review → engine}/src/web/shortcuts.ts +0 -0
package/src/server/updates.ts
CHANGED
|
@@ -3,16 +3,16 @@ import path from 'node:path';
|
|
|
3
3
|
import { spawn } from 'node:child_process';
|
|
4
4
|
import { randomUUID } from 'node:crypto';
|
|
5
5
|
import { devRevision, newerVersion, readJson, stableVersion, writeJson } from '../../bin/installation.mjs';
|
|
6
|
-
import {
|
|
6
|
+
import { installRelease, loaderFor, npmCli } from './update-install.ts';
|
|
7
7
|
import type { UpdateChannel, UpdateStatus } from '../shared.ts';
|
|
8
8
|
|
|
9
9
|
const activePhases = new Set(['installing', 'waiting', 'restarting']);
|
|
10
10
|
export const alive = (pid: number) => { try { process.kill(pid, 0); return true; } catch { return false; } };
|
|
11
|
-
async function releaseInfo(url: string, fetcher: typeof fetch) {
|
|
11
|
+
async function releaseInfo(url: string, fetcher: typeof fetch, limit = 256000) {
|
|
12
12
|
const response = await fetcher(url, { signal: AbortSignal.timeout(10000), redirect: 'error', headers: { Accept: 'application/json', 'User-Agent': 'Papilot' } });
|
|
13
13
|
if (!response.ok) throw new Error('Could not check for updates.');
|
|
14
14
|
const text = await response.text();
|
|
15
|
-
if (text.length >
|
|
15
|
+
if (text.length > limit) throw new Error('Invalid release information.');
|
|
16
16
|
return JSON.parse(text);
|
|
17
17
|
}
|
|
18
18
|
// The package.json of the newest release on a channel.
|
|
@@ -30,14 +30,29 @@ export async function latestManifest(channel: UpdateChannel = 'stable', fetcher
|
|
|
30
30
|
return pkg;
|
|
31
31
|
}
|
|
32
32
|
export const latestRelease = async (channel: UpdateChannel = 'stable', fetcher = fetch) => (await latestManifest(channel, fetcher)).version as string;
|
|
33
|
+
export const DESKTOP_RELEASES = 'https://github.com/PapilotAI/papilot/releases';
|
|
34
|
+
// npm can be published before desktop builds finish. Only advertise releases
|
|
35
|
+
// with an uploaded installer for this OS and CPU, and link to that exact release.
|
|
36
|
+
export async function latestDesktopRelease(platform = process.platform, arch = process.arch, fetcher = fetch) {
|
|
37
|
+
const releases = await releaseInfo('https://api.github.com/repos/PapilotAI/papilot/releases?per_page=100', fetcher, 4 * 1024 * 1024);
|
|
38
|
+
if (!Array.isArray(releases)) throw new Error('Invalid release information.');
|
|
39
|
+
let latest: { version: string; downloadUrl: string } | null = null;
|
|
40
|
+
for (const release of releases) {
|
|
41
|
+
const version = typeof release.tag_name === 'string' ? release.tag_name.replace(/^v/, '') : '';
|
|
42
|
+
if (release.draft !== false || release.prerelease !== false || !stableVersion(version) || !Array.isArray(release.assets)) continue;
|
|
43
|
+
const names = platform === 'darwin' && ['arm64', 'x64'].includes(arch) ? [`Papilot-${version}-mac-${arch}.dmg`, `Papilot-${version}-mac-${arch}.zip`]
|
|
44
|
+
: platform === 'linux' && ['arm64', 'x64'].includes(arch) ? [`Papilot-${version}-linux-${arch === 'x64' ? 'x86_64' : arch}.AppImage`, `Papilot-${version}-linux-${arch === 'x64' ? 'amd64' : arch}.deb`] : [];
|
|
45
|
+
if (!release.assets.some((asset: any) => asset.state === 'uploaded' && asset.size > 0 && names.includes(asset.name))) continue;
|
|
46
|
+
if (!latest || newerVersion(version, latest.version)) latest = { version, downloadUrl: `${DESKTOP_RELEASES}/tag/${release.tag_name}` };
|
|
47
|
+
}
|
|
48
|
+
return latest;
|
|
49
|
+
}
|
|
33
50
|
const validTarget = (version: unknown, channel: UpdateChannel): version is string => channel === 'dev' ? Boolean(devRevision(version)) : stableVersion(version);
|
|
34
51
|
const available = (next: string, current: string, channel: UpdateChannel) => validTarget(next, channel)
|
|
35
52
|
&& (channel === 'dev' || devRevision(current) ? next !== current : newerVersion(next, current));
|
|
36
53
|
interface Options {
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
// A desktop installer that runs newer releases from npm (see desktop/runtime.ts).
|
|
40
|
-
desktop?: { shell: number; installer: string; downloadUrl: string };
|
|
54
|
+
desktop?: boolean;
|
|
55
|
+
latestDesktop?: () => Promise<{ version: string; downloadUrl: string } | null>;
|
|
41
56
|
root: string; data: string; version: string; port: number;
|
|
42
57
|
busy: () => boolean; shutdown: () => void;
|
|
43
58
|
latest?: (channel: UpdateChannel) => Promise<string | Record<string, any>>; install?: (data: string, version: string) => Promise<string>;
|
|
@@ -55,32 +70,28 @@ export class Updates {
|
|
|
55
70
|
private file: string;
|
|
56
71
|
private lock: string;
|
|
57
72
|
private channel: UpdateChannel;
|
|
58
|
-
|
|
59
|
-
private needsInstaller = false;
|
|
73
|
+
private downloadUrl = DESKTOP_RELEASES;
|
|
60
74
|
constructor(private options: Options) {
|
|
61
|
-
this.file = path.join(options.data, 'updates/status.json'); this.lock = path.join(options.data, 'updates/install.lock');
|
|
75
|
+
this.file = path.join(options.data, options.desktop ? 'updates/desktop/status.json' : 'updates/status.json'); this.lock = path.join(options.data, 'updates/install.lock');
|
|
62
76
|
const preference = readJson(path.join(options.data, 'updates/channel.json'))?.channel;
|
|
63
|
-
this.channel = options.
|
|
64
|
-
let supported = options.supported ?? true;
|
|
65
|
-
if (options.supported === undefined) try { npmCli(); } catch { supported = false; }
|
|
77
|
+
this.channel = options.desktop ? 'stable' : preference === 'dev' || preference === 'stable' ? preference : devRevision(options.version) ? 'dev' : 'stable';
|
|
78
|
+
let supported = options.desktop ? false : options.supported ?? true;
|
|
79
|
+
if (!options.desktop && options.supported === undefined) try { npmCli(); } catch { supported = false; }
|
|
66
80
|
this.state = { currentVersion: options.version, latestVersion: null, phase: 'idle', checkedAt: null, error: null, canUpdate: supported };
|
|
67
|
-
const saved = readJson(this.file);
|
|
81
|
+
const saved = options.desktop ? null : readJson(this.file);
|
|
68
82
|
if (saved && ['failed', 'updated', 'installing', 'waiting', 'restarting'].includes(saved.phase)) this.state = { ...this.state, ...saved, currentVersion: options.version, canUpdate: supported };
|
|
69
83
|
if (saved && activePhases.has(saved.phase) && !alive(saved.pid)) this.change({ phase: 'failed', checkedAt: Date.now(), error: 'The update was interrupted. Your current installation is still available; retry the update.' });
|
|
70
84
|
}
|
|
71
85
|
snapshot(): UpdateStatus {
|
|
72
|
-
if (this.options.downloadUrl) return { currentVersion: this.options.version, latestVersion: null, phase: 'idle', checkedAt: null, error: null, canUpdate: false, channel: 'stable', downloadUrl: this.options.downloadUrl };
|
|
73
86
|
const saved = readJson(this.file);
|
|
74
87
|
if (saved && activePhases.has(this.state.phase) && ['updated', 'failed'].includes(saved.phase)) this.state = { ...this.state, ...saved, currentVersion: this.options.version };
|
|
75
88
|
const { currentVersion, latestVersion, phase, checkedAt, error, canUpdate } = this.state, desktop = this.options.desktop;
|
|
76
|
-
if (desktop) return { currentVersion, latestVersion, phase, checkedAt, error, channel:
|
|
77
|
-
...(this.needsInstaller ? { canUpdate: false, downloadUrl: desktop.downloadUrl } : { canUpdate }) };
|
|
89
|
+
if (desktop) return { currentVersion, latestVersion, phase, checkedAt, error, channel: 'stable', canUpdate: false, downloadUrl: this.downloadUrl };
|
|
78
90
|
return { currentVersion, latestVersion, phase, checkedAt, error, canUpdate, channel: this.channel };
|
|
79
91
|
}
|
|
80
92
|
get restarting() { return this.snapshot().phase === 'restarting'; }
|
|
81
93
|
enter() { this.inFlight++; let released = false; return () => { if (!released) { released = true; this.inFlight--; } }; }
|
|
82
94
|
start() {
|
|
83
|
-
if (this.options.downloadUrl) return;
|
|
84
95
|
if (this.state.phase !== 'failed') void this.check();
|
|
85
96
|
this.timer = setInterval(() => {
|
|
86
97
|
if (this.state.phase === 'waiting') void this.activate();
|
|
@@ -93,7 +104,7 @@ export class Updates {
|
|
|
93
104
|
writeJson(this.file, { ...this.state, pid: process.pid });
|
|
94
105
|
}
|
|
95
106
|
setChannel(channel: unknown) {
|
|
96
|
-
if (this.options.
|
|
107
|
+
if (this.options.desktop) throw new Error('Download desktop updates from GitHub Releases.');
|
|
97
108
|
if (channel !== 'stable' && channel !== 'dev') throw new Error('Choose a valid update channel.');
|
|
98
109
|
if (activePhases.has(this.state.phase)) throw new Error('Wait for the current update to finish before changing channels.');
|
|
99
110
|
if (channel === this.channel) return this.check();
|
|
@@ -104,17 +115,25 @@ export class Updates {
|
|
|
104
115
|
return this.check();
|
|
105
116
|
}
|
|
106
117
|
check(): Promise<UpdateStatus> {
|
|
107
|
-
if (this.options.downloadUrl) return Promise.resolve(this.snapshot());
|
|
108
118
|
if (this.checking) return this.checking;
|
|
109
119
|
if (activePhases.has(this.state.phase)) return Promise.resolve(this.snapshot());
|
|
110
120
|
this.change({ phase: 'checking' });
|
|
111
121
|
const channel = this.channel;
|
|
112
|
-
const
|
|
113
|
-
|
|
122
|
+
const discovery = this.options.desktop ? (this.options.latestDesktop || latestDesktopRelease)() : (this.options.latest || latestManifest)(channel);
|
|
123
|
+
const checking = discovery.then(found => {
|
|
124
|
+
const manifest = typeof found === 'string' ? { version: found } : found;
|
|
125
|
+
if (!manifest && this.options.desktop) {
|
|
126
|
+
if (!this.closed && this.checking === checking) {
|
|
127
|
+
this.downloadUrl = DESKTOP_RELEASES;
|
|
128
|
+
this.change({ latestVersion: null, checkedAt: Date.now(), error: null, phase: 'idle' });
|
|
129
|
+
}
|
|
130
|
+
return this.snapshot();
|
|
131
|
+
}
|
|
132
|
+
const version = manifest?.version;
|
|
114
133
|
if (!validTarget(version, channel)) throw new Error('Invalid release version.');
|
|
115
134
|
if (!this.closed && this.checking === checking && !activePhases.has(this.state.phase)) {
|
|
116
135
|
const newer = available(version, this.options.version, channel);
|
|
117
|
-
|
|
136
|
+
if (this.options.desktop) this.downloadUrl = manifest!.downloadUrl;
|
|
118
137
|
this.change({ latestVersion: version, checkedAt: Date.now(), error: null, phase: newer ? 'available' : 'idle' });
|
|
119
138
|
}
|
|
120
139
|
return this.snapshot();
|
|
@@ -126,9 +145,8 @@ export class Updates {
|
|
|
126
145
|
return this.checking;
|
|
127
146
|
}
|
|
128
147
|
install(version: unknown) {
|
|
129
|
-
if (this.options.
|
|
148
|
+
if (this.options.desktop) throw new Error('Download desktop updates from GitHub Releases.');
|
|
130
149
|
if (activePhases.has(this.state.phase)) return this.snapshot();
|
|
131
|
-
if (this.needsInstaller) throw new Error(NEEDS_INSTALLER);
|
|
132
150
|
if (!this.state.canUpdate) throw new Error('npm is unavailable to Papilot.');
|
|
133
151
|
if (!validTarget(version, this.channel) || version !== this.state.latestVersion || !available(version, this.options.version, this.channel)) throw new Error('Check for a newer release before updating.');
|
|
134
152
|
fs.mkdirSync(path.dirname(this.lock), { recursive: true, mode: 0o700 });
|
package/src/shared.ts
CHANGED
|
@@ -11,8 +11,6 @@ export type UpdateChannel = 'stable' | 'dev';
|
|
|
11
11
|
export interface UpdateStatus {
|
|
12
12
|
// Present when the update must be downloaded as a new desktop app.
|
|
13
13
|
downloadUrl?: string;
|
|
14
|
-
// The desktop app's own Papilot version; newer releases run on top of it.
|
|
15
|
-
installerVersion?: string;
|
|
16
14
|
channel?: UpdateChannel;
|
|
17
15
|
currentVersion: string; latestVersion: string | null;
|
|
18
16
|
phase: 'idle' | 'checking' | 'available' | 'installing' | 'waiting' | 'restarting' | 'updated' | 'failed';
|
|
@@ -126,7 +124,10 @@ export interface GitWorktree {
|
|
|
126
124
|
}
|
|
127
125
|
export interface GitGraphCommit { hash: string; parents: string[]; subject: string; author: string; date: number; refs: string[] }
|
|
128
126
|
export interface GitOverview { worktrees: GitWorktree[]; commits: GitGraphCommit[]; truncated: boolean }
|
|
129
|
-
|
|
127
|
+
// A running compilation, from latexmk's output: its step, the TeX pass, and
|
|
128
|
+
// the pages typeset in that pass against the last known page count.
|
|
129
|
+
export interface BuildProgress { step: 'tex' | 'bibliography' | 'pdf'; pass: number; pages: number; total: number | null; startedAt: number }
|
|
130
|
+
export interface ManuscriptBuild { status: 'building' | 'ready' | 'failed'; key?: string; pages?: [number, number][]; builtAt?: number; error?: string; current: boolean; problems?: BuildProblemCounts; progress?: BuildProgress }
|
|
130
131
|
// What the last finished build reported. Errors stop the build; warnings are
|
|
131
132
|
// mistakes in the PDF (?? and missing citations); minor problems are
|
|
132
133
|
// typesetting (overfull lines) and package remarks, listed but never counted.
|
|
@@ -156,6 +157,8 @@ export interface PaperImport {
|
|
|
156
157
|
id: string; path: string; name: string; copied: boolean; candidates: string[]; main: string; engine: string;
|
|
157
158
|
phase: 'choose' | 'building' | 'failed' | 'ready' | 'repairing';
|
|
158
159
|
error?: string; summary?: string; versioned?: boolean;
|
|
160
|
+
// While building: when it started, and the compilation's progress.
|
|
161
|
+
startedAt?: number; progress?: BuildProgress;
|
|
159
162
|
}
|
|
160
163
|
// The paper's bibliography as the References panel reads it: the review
|
|
161
164
|
// engine's report of every entry, with online checks and the entries the
|