@poco-ai/agentero-dsh-pdf 0.1.1 → 0.1.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/client/index.d.ts +1 -0
- package/lib/client/pdf-panel.d.ts +2 -0
- package/lib/client/resource-path.d.ts +43 -0
- package/lib/client.js +83 -7
- package/package.json +1 -1
package/lib/client/index.d.ts
CHANGED
|
@@ -51,6 +51,8 @@ export interface PdfInjected {
|
|
|
51
51
|
loadPdf: (ref: string) => Promise<ArrayBuffer>;
|
|
52
52
|
loadMarks: (ref: string) => Promise<PaintMark[]>;
|
|
53
53
|
addMark: (body: MarkAdd) => Promise<string | undefined>;
|
|
54
|
+
/** Vault-relative ref for a file-resource address, or an empty string outside the vault. */
|
|
55
|
+
resolveAddress: (address: string) => string;
|
|
54
56
|
/** Send a question and citation as a new conversation turn. */
|
|
55
57
|
ask: (text: string) => Promise<void>;
|
|
56
58
|
/** Write the PDF outline back to the file; resolves after the host saved it. */
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* File resources the right Sidebar routes to this plugin.
|
|
3
|
+
*
|
|
4
|
+
* PDF links and mentions arrive as `dsh-resource://file/...` addresses. A
|
|
5
|
+
* Session-scoped address keeps the path as the caller wrote it (workspace
|
|
6
|
+
* relative or absolute); the absolute form drops the leading slash. The host
|
|
7
|
+
* only reads files inside the vault, so an address has to be mapped back to a
|
|
8
|
+
* vault-relative ref before the panel can open it.
|
|
9
|
+
*/
|
|
10
|
+
/** A file address split into its scope and decoded path. */
|
|
11
|
+
export type FileResource = {
|
|
12
|
+
readonly scope: 'session';
|
|
13
|
+
readonly sessionId: string;
|
|
14
|
+
/** Absolute or workspace-relative path; `/`-separated. */
|
|
15
|
+
readonly path: string;
|
|
16
|
+
} | {
|
|
17
|
+
readonly scope: 'absolute';
|
|
18
|
+
/** Absolute path: `/a/b` on POSIX, `C:/a/b` on Windows, `//server/share/a` for UNC. */
|
|
19
|
+
readonly path: string;
|
|
20
|
+
};
|
|
21
|
+
/**
|
|
22
|
+
* Parse one `dsh-resource://file/` address.
|
|
23
|
+
* @param address - candidate address.
|
|
24
|
+
* @returns its scope and decoded path, or undefined for another resource or a malformed address.
|
|
25
|
+
*/
|
|
26
|
+
export declare function parseFileResource(address: string): FileResource | undefined;
|
|
27
|
+
/** Whether a path is absolute in either spelling the host accepts. */
|
|
28
|
+
export declare function isAbsolutePath(value: string): boolean;
|
|
29
|
+
/** Join a relative path onto an absolute base, using `/` separators. */
|
|
30
|
+
export declare function joinPath(base: string, relative: string): string;
|
|
31
|
+
/**
|
|
32
|
+
* Strip the vault root from an absolute path.
|
|
33
|
+
* @param vaultPath - configured vault directory.
|
|
34
|
+
* @param absolutePath - absolute path to test.
|
|
35
|
+
* @returns the vault-relative path, or undefined when it lies outside the vault.
|
|
36
|
+
*/
|
|
37
|
+
export declare function vaultRelative(vaultPath: string, absolutePath: string): string | undefined;
|
|
38
|
+
/**
|
|
39
|
+
* Final path segment of a file-resource address.
|
|
40
|
+
* @param address - candidate address.
|
|
41
|
+
* @returns the decoded basename, or undefined when the address is not a file resource.
|
|
42
|
+
*/
|
|
43
|
+
export declare function resourceName(address: string): string | undefined;
|
package/lib/client.js
CHANGED
|
@@ -49177,6 +49177,57 @@ function PdfPage(props) {
|
|
|
49177
49177
|
);
|
|
49178
49178
|
}
|
|
49179
49179
|
|
|
49180
|
+
// src/client/resource-path.ts
|
|
49181
|
+
var FILE_PREFIX = "dsh-resource://file/";
|
|
49182
|
+
function isDriveSegment(segment) {
|
|
49183
|
+
return segment !== void 0 && /^[A-Za-z]:$/.test(segment);
|
|
49184
|
+
}
|
|
49185
|
+
function parseFileResource(address) {
|
|
49186
|
+
if (!address.startsWith(FILE_PREFIX)) return void 0;
|
|
49187
|
+
try {
|
|
49188
|
+
const end = address.search(/[?#]/);
|
|
49189
|
+
const [scope, ...rest] = address.slice(FILE_PREFIX.length, end === -1 ? void 0 : end).split("/");
|
|
49190
|
+
if (scope === "session") {
|
|
49191
|
+
const [sessionId, ...segments] = rest;
|
|
49192
|
+
if (sessionId === void 0 || sessionId === "" || segments.length === 0) return void 0;
|
|
49193
|
+
return { scope, sessionId: decodeURIComponent(sessionId), path: segments.map(decodeURIComponent).join("/") };
|
|
49194
|
+
}
|
|
49195
|
+
if (scope === "absolute") {
|
|
49196
|
+
const unc = rest[0] === "" && rest.length > 1;
|
|
49197
|
+
const segments = (unc ? rest.slice(1) : rest).map(decodeURIComponent);
|
|
49198
|
+
if (segments.length === 0 || segments[0] === "") return void 0;
|
|
49199
|
+
if (unc) return { scope, path: `//${segments.join("/")}` };
|
|
49200
|
+
return { scope, path: isDriveSegment(segments[0]) ? segments.join("/") : `/${segments.join("/")}` };
|
|
49201
|
+
}
|
|
49202
|
+
return void 0;
|
|
49203
|
+
} catch {
|
|
49204
|
+
return void 0;
|
|
49205
|
+
}
|
|
49206
|
+
}
|
|
49207
|
+
function isAbsolutePath(value) {
|
|
49208
|
+
return value.startsWith("/") || /^[A-Za-z]:[/\\]/.test(value) || value.startsWith("\\\\");
|
|
49209
|
+
}
|
|
49210
|
+
function joinPath(base, relative) {
|
|
49211
|
+
return `${base.replace(/\\/g, "/").replace(/\/+$/, "")}/${relative.replace(/\\/g, "/").replace(/^(?:\.\/)+/, "")}`;
|
|
49212
|
+
}
|
|
49213
|
+
function vaultRelative(vaultPath, absolutePath) {
|
|
49214
|
+
const root = vaultPath.replace(/\\/g, "/").replace(/\/+$/, "");
|
|
49215
|
+
if (root === "") return void 0;
|
|
49216
|
+
const normalized = absolutePath.replace(/\\/g, "/");
|
|
49217
|
+
const windows = /^[A-Za-z]:/.test(root);
|
|
49218
|
+
const prefix = `${root}/`;
|
|
49219
|
+
const candidate = windows ? normalized.toLowerCase() : normalized;
|
|
49220
|
+
const expected = windows ? prefix.toLowerCase() : prefix;
|
|
49221
|
+
if (!candidate.startsWith(expected)) return void 0;
|
|
49222
|
+
return normalized.slice(prefix.length);
|
|
49223
|
+
}
|
|
49224
|
+
function resourceName(address) {
|
|
49225
|
+
const file = parseFileResource(address);
|
|
49226
|
+
if (file === void 0) return void 0;
|
|
49227
|
+
const name2 = file.path.slice(file.path.lastIndexOf("/") + 1);
|
|
49228
|
+
return name2 === "" ? void 0 : name2;
|
|
49229
|
+
}
|
|
49230
|
+
|
|
49180
49231
|
// src/client/selection-menu.tsx
|
|
49181
49232
|
var import_react85 = require("react");
|
|
49182
49233
|
|
|
@@ -57977,13 +58028,15 @@ function paperRef(params) {
|
|
|
57977
58028
|
return typeof ref === "string" ? ref : "";
|
|
57978
58029
|
}
|
|
57979
58030
|
function PdfTitle({ useTabInfo, t }) {
|
|
57980
|
-
const
|
|
57981
|
-
const
|
|
58031
|
+
const navigation = useTabInfo().tab.navigation;
|
|
58032
|
+
const ref = paperRef(navigation.params);
|
|
58033
|
+
const name2 = ref !== "" ? ref.split("/").filter((part) => part !== "").pop() : resourceName(navigation.address);
|
|
57982
58034
|
return /* @__PURE__ */ (0, import_jsx_runtime37.jsx)("span", { children: name2 === void 0 || name2 === "" ? t("title") : name2 });
|
|
57983
58035
|
}
|
|
57984
58036
|
function PdfPanel(props) {
|
|
57985
|
-
const { t, sessionId, useTabInfo, loadPdf, loadMarks, addMark, ask, saveBookmarks, translate, loadLayout } = props;
|
|
57986
|
-
const
|
|
58037
|
+
const { t, sessionId, useTabInfo, loadPdf, loadMarks, addMark, ask, saveBookmarks, translate, loadLayout, resolveAddress } = props;
|
|
58038
|
+
const navigation = useTabInfo().tab.navigation;
|
|
58039
|
+
const paperPath = paperRef(navigation.params) || resolveAddress(navigation.address);
|
|
57987
58040
|
const [status, setStatus] = (0, import_react86.useState)("empty");
|
|
57988
58041
|
const [message, setMessage] = (0, import_react86.useState)("");
|
|
57989
58042
|
const [bytes, setBytes] = (0, import_react86.useState)(void 0);
|
|
@@ -58035,8 +58088,12 @@ function PdfPanel(props) {
|
|
|
58035
58088
|
if (cancelled) return;
|
|
58036
58089
|
setBytes(next);
|
|
58037
58090
|
setStatus("ready");
|
|
58038
|
-
|
|
58039
|
-
|
|
58091
|
+
try {
|
|
58092
|
+
const painted = await loadMarks(paperPath);
|
|
58093
|
+
if (!cancelled) setMarks(painted);
|
|
58094
|
+
} catch {
|
|
58095
|
+
if (!cancelled) setMarks([]);
|
|
58096
|
+
}
|
|
58040
58097
|
}).catch((error) => {
|
|
58041
58098
|
if (cancelled) return;
|
|
58042
58099
|
const text = error instanceof Error ? error.message : "";
|
|
@@ -58316,18 +58373,37 @@ var inject = ["slots", "locale", "agentero", "sidebarRight", "sidebarRightTabs",
|
|
|
58316
58373
|
function apply(ctx) {
|
|
58317
58374
|
const source = ctx.agentero;
|
|
58318
58375
|
const request = source.request.bind(source);
|
|
58376
|
+
let vaultPath;
|
|
58377
|
+
void source.getVault().then((info) => {
|
|
58378
|
+
vaultPath = info.path;
|
|
58379
|
+
}).catch(() => {
|
|
58380
|
+
});
|
|
58381
|
+
const vaultRefOf = (address) => {
|
|
58382
|
+
const file = parseFileResource(address);
|
|
58383
|
+
if (file === void 0 || vaultPath === void 0) return void 0;
|
|
58384
|
+
if (file.scope === "absolute") return vaultRelative(vaultPath, file.path);
|
|
58385
|
+
if (file.path.startsWith("papers/")) return vaultRelative(vaultPath, joinPath(vaultPath, file.path));
|
|
58386
|
+
const cwd = ctx.sessions.list.getSnapshot().byId[file.sessionId]?.cwd;
|
|
58387
|
+
if (cwd === void 0 || cwd === "" || !isAbsolutePath(cwd)) return void 0;
|
|
58388
|
+
return vaultRelative(vaultPath, joinPath(cwd, file.path));
|
|
58389
|
+
};
|
|
58319
58390
|
ctx.effect(() => ctx.locale.register(NS, { zh, en }));
|
|
58320
58391
|
const t = ctx.locale.bind(NS);
|
|
58321
58392
|
ctx.effect(() => ctx.sidebarRightTabs.register({
|
|
58322
58393
|
id: TAB_ID,
|
|
58323
58394
|
kind: TAB_KIND,
|
|
58324
58395
|
keepMounted: true,
|
|
58325
|
-
|
|
58396
|
+
// Claim vault PDFs at the extension band so the builtin text preview stops
|
|
58397
|
+
// drawing them. Addresses outside the vault stay with the builtin viewer.
|
|
58398
|
+
patterns: ["*.pdf"],
|
|
58399
|
+
canOpen: (address) => vaultRefOf(address) !== void 0,
|
|
58400
|
+
title: (address) => resourceName(address) ?? t("title")
|
|
58326
58401
|
}));
|
|
58327
58402
|
ctx.effect(() => ctx.agentero.registerOpener("paper", (id3) => {
|
|
58328
58403
|
ctx.sidebarRight.openTab(TAB_KIND, { params: { ref: id3 } });
|
|
58329
58404
|
}));
|
|
58330
58405
|
const face = {
|
|
58406
|
+
resolveAddress: (address) => vaultRefOf(address) ?? "",
|
|
58331
58407
|
async loadPdf(ref) {
|
|
58332
58408
|
const response = await request(`/agentero/api/pdf?ref=${encodeURIComponent(ref)}`, { cache: "no-store" });
|
|
58333
58409
|
if (!response.ok) {
|