mirror of
https://github.com/lossless-group/perplexed-plugin.git
synced 2026-07-22 17:00:32 +00:00
update(dependencies): update all dependencies for Perplexed
On branch development Your branch is ahead of 'origin/development' by 1 commit. (use "git push" to publish your local commits) Changes to be committed: deleted: .eslintignore deleted: .eslintrc new file: changelog/2026-05-02_01.md new file: eslint.config.mjs modified: package.json modified: pnpm-lock.yaml modified: src/services/perplexityService.ts modified: styles.css modified: tsconfig.json
This commit is contained in:
parent
a13b4e2292
commit
d5e78076f6
9 changed files with 403 additions and 314 deletions
|
|
@ -1,3 +0,0 @@
|
|||
node_modules/
|
||||
|
||||
main.js
|
||||
33
.eslintrc
33
.eslintrc
|
|
@ -1,33 +0,0 @@
|
|||
{
|
||||
"root": true,
|
||||
"env": {
|
||||
"node": true,
|
||||
"es2022": true
|
||||
},
|
||||
"parser": "@typescript-eslint/parser",
|
||||
"parserOptions": {
|
||||
"ecmaVersion": "latest",
|
||||
"sourceType": "module",
|
||||
"project": "./tsconfig.json",
|
||||
"ecmaFeatures": {
|
||||
"jsx": false
|
||||
}
|
||||
},
|
||||
"plugins": ["@typescript-eslint"],
|
||||
"extends": [
|
||||
"eslint:recommended",
|
||||
"plugin:@typescript-eslint/recommended",
|
||||
"plugin:@typescript-eslint/strict"
|
||||
],
|
||||
"rules": {
|
||||
"no-unused-vars": "off",
|
||||
"@typescript-eslint/no-unused-vars": ["error", { "args": "none" }],
|
||||
"@typescript-eslint/ban-ts-comment": "off",
|
||||
"no-prototype-builtins": "off",
|
||||
"@typescript-eslint/no-empty-function": "off",
|
||||
"@typescript-eslint/no-explicit-any": "warn",
|
||||
"@typescript-eslint/explicit-module-boundary-types": "off",
|
||||
"@typescript-eslint/no-non-null-assertion": "off",
|
||||
"@typescript-eslint/consistent-type-imports": "error"
|
||||
}
|
||||
}
|
||||
344
changelog/2026-05-02_01.md
Normal file
344
changelog/2026-05-02_01.md
Normal file
|
|
@ -0,0 +1,344 @@
|
|||
---
|
||||
title: "Maintenance pass — Dependency refresh (incl. ESLint v10 + TypeScript 6) + streaming-citations bug fix"
|
||||
lede: "First changelog for this plugin. Two coordinated tracks: (1) refresh every dependency to current latest, including the two majors that required config migration — ESLint 9 → 10 (flat config) and TypeScript 5 → 6 (deprecated tsconfig options); (2) fix a streaming-response bug where a misnamed 'stale data' cleanup was wiping captured Perplexity citations on the final SSE chunk, so the rendered note never got a Citations reference section. Build verified clean (tsc + esbuild production). One known-flaky behavior — streaming responses occasionally truncate mid-answer with no error in the console — is documented under Open Items but not diagnosed; the user explicitly deferred ('something is funky I don't want to diagnose, or it's an api or credit thing')."
|
||||
date_authored_initial_draft: 2026-05-02
|
||||
date_authored_current_draft: 2026-05-02
|
||||
date_first_published: 2026-05-02
|
||||
date_last_updated: 2026-05-02
|
||||
at_semantic_version: 0.0.0.1
|
||||
status: Published
|
||||
category: Changelog
|
||||
tags:
|
||||
- Maintenance
|
||||
- Dependency-Refresh
|
||||
- ESLint-Flat-Config
|
||||
- TypeScript-6
|
||||
- Perplexity-Streaming
|
||||
- SSE
|
||||
- Citations-Bug
|
||||
authors:
|
||||
- Michael Staton
|
||||
augmented_with: Claude Code (Opus 4.7, 1M context)
|
||||
---
|
||||
|
||||
## Why Care?
|
||||
|
||||
This is the first changelog the Perplexed plugin has ever had. The
|
||||
project went from `init` (`7e6831c`) through 47 commits without one,
|
||||
and the last touched commit before today (`a13b4e2 Update styles.css`,
|
||||
2025-05-01) left the working tree in a state where:
|
||||
|
||||
- `pnpm-lock.yaml` was out of sync with what `node_modules` had been
|
||||
installed by; running `pnpm outdated` reported every package as
|
||||
"missing".
|
||||
- Every direct dependency had drifted at least one minor behind
|
||||
current latest, and three were a full major behind: ESLint
|
||||
(9 → 10), TypeScript (5 → 6), and `@types/node` (24 → 25).
|
||||
- A latent bug in `handleStreamingResponse` was silently dropping
|
||||
Perplexity's `search_results` / `citations` metadata on the final
|
||||
SSE chunk, so users saw plenty of streamed answer text but no
|
||||
reference list at the end.
|
||||
|
||||
The plugin was "working as is" for the user's day-to-day usage — they
|
||||
weren't blocked. The maintenance window opened because the toolchain
|
||||
drift had reached the point where any future bug fix would have to
|
||||
fight an outdated lockfile and a yellow-triangle-littered npm advisory
|
||||
list before it could even start. So: refresh the toolchain, lock in
|
||||
working configs against the new majors, and fix anything the refresh
|
||||
exposed.
|
||||
|
||||
The strategic point: the two tracks are coupled by intent but
|
||||
independent in scope. Track 1 (deps) has to be safe — every step
|
||||
verified against `pnpm run build` so the production bundle survives.
|
||||
Track 2 (citations bug) was discovered in the same session because
|
||||
the user reported it after the refresh; the bug pre-dates the refresh
|
||||
and is unrelated to any version change. Both ship together so future
|
||||
maintenance has a single, coherent baseline.
|
||||
|
||||
## What Was Built
|
||||
|
||||
### Dependency refresh (Track 1)
|
||||
|
||||
| Package | Was | Now | Major? |
|
||||
|---|---|---|---|
|
||||
| `@modelcontextprotocol/sdk` | 1.15.0 | 1.29.0 | minor |
|
||||
| `dotenv` | 17.2.0 | 17.4.2 | patch |
|
||||
| `fastify` | 5.4.0 | 5.8.5 | minor |
|
||||
| `zod` | 4.0.0 | 4.4.2 | minor |
|
||||
| `@types/node` | 24.0.12 | 25.6.0 | **major** |
|
||||
| `@typescript-eslint/eslint-plugin` | 8.36.0 | 8.59.1 | minor |
|
||||
| `@typescript-eslint/parser` | 8.36.0 | 8.59.1 | minor |
|
||||
| `builtin-modules` | 5.0.0 | 5.1.0 | minor |
|
||||
| `esbuild` | 0.25.6 | 0.28.0 | minor (0.x) |
|
||||
| `eslint` | 9.30.1 | 10.3.0 | **major** |
|
||||
| `obsidian` | 1.8.7 | 1.12.3 | minor |
|
||||
| `tslib` | 2.8.1 | 2.8.1 | unchanged |
|
||||
| `typescript` | 5.8.3 | 6.0.3 | **major** |
|
||||
| `typescript-eslint` (added) | — | 8.59.1 | new |
|
||||
| `@eslint/js` (added) | — | 10.0.1 | new |
|
||||
| `globals` (added) | — | 17.6.0 | new |
|
||||
|
||||
Method: install the existing lockfile baseline first
|
||||
(`pnpm install`), confirm `pnpm run build` is green, then bump in
|
||||
three bands so any breakage is isolated:
|
||||
|
||||
1. All minor / patch bumps in one shot.
|
||||
2. `@types/node` 24 → 25 (types-only, lowest blast radius).
|
||||
3. `eslint` 9 → 10 (config migration required).
|
||||
4. `typescript` 5 → 6 (tsconfig migration required).
|
||||
|
||||
Build re-verified after each band.
|
||||
|
||||
### ESLint v10 — flat config migration (Track 1, fix-out)
|
||||
|
||||
ESLint 10 dropped legacy `.eslintrc` and `.eslintignore` support
|
||||
entirely. Running `eslint` with the old config produced:
|
||||
|
||||
```
|
||||
ESLint couldn't find an eslint.config.(js|mjs|cjs) file.
|
||||
From ESLint v9.0.0, the default configuration file is now eslint.config.js.
|
||||
```
|
||||
|
||||
Migration:
|
||||
|
||||
- Created `eslint.config.mjs` — the new flat-config equivalent of
|
||||
the old `.eslintrc`. Same `parserOptions` (`ecmaVersion: latest`,
|
||||
`sourceType: module`, `project: ./tsconfig.json`), same rule set
|
||||
(`@typescript-eslint/no-unused-vars`, `consistent-type-imports`,
|
||||
`no-explicit-any` as warn, etc.), same ignores
|
||||
(`node_modules/`, `main.js`).
|
||||
- Adopted the unified `typescript-eslint` meta-package (v8.59.1) and
|
||||
added `@eslint/js` + `globals` because the flat-config style
|
||||
composes configs as imported objects rather than string extends.
|
||||
- Deleted `.eslintrc` and `.eslintignore`.
|
||||
|
||||
Important constraint: the build script does **not** run ESLint
|
||||
(`tsc -noEmit -skipLibCheck && node esbuild.config.mjs production`),
|
||||
so `pnpm run build` would have stayed green even if lint were broken.
|
||||
Verified the new config separately by running `npx eslint main.ts
|
||||
src/` and confirming it parses + emits results. The 42 errors / 33
|
||||
warnings it emits are pre-existing code-quality nits (mostly
|
||||
type-only-import refactors and `any` warnings); not part of this
|
||||
maintenance pass.
|
||||
|
||||
### TypeScript 6 — tsconfig modernization (Track 1, fix-out)
|
||||
|
||||
TypeScript 6 promoted two `tsconfig.json` deprecation warnings to
|
||||
hard errors:
|
||||
|
||||
```
|
||||
tsconfig.json(4,5): error TS5101: Option 'baseUrl' is deprecated and will stop functioning in TypeScript 7.0.
|
||||
tsconfig.json(7,25): error TS5107: Option 'moduleResolution=node10' is deprecated and will stop functioning in TypeScript 7.0.
|
||||
```
|
||||
|
||||
Resolution: modernize rather than silence with
|
||||
`ignoreDeprecations: "6.0"`.
|
||||
|
||||
| Field | Was | Now | Why |
|
||||
|---|---|---|---|
|
||||
| `baseUrl` | `"."` | (removed) | Only existed to anchor the `paths` map below; `paths` was a no-op (see next row) so neither is needed |
|
||||
| `paths` | `{ "*": ["node_modules/*"] }` | (removed) | This pattern is a no-op restatement of default Node module resolution; deleting both clears the deprecation cleanly |
|
||||
| `moduleResolution` | `"node"` (= node10) | `"bundler"` | Correct semantic match for esbuild-as-bundler — preserves the same import behavior the project relies on without the deprecation |
|
||||
|
||||
Build clean after the change. No source code modifications were
|
||||
required — none of the imports were depending on the legacy
|
||||
`baseUrl` + `paths` indirection.
|
||||
|
||||
### Streaming citations bug fix (Track 2)
|
||||
|
||||
Bug: in `src/services/perplexityService.ts`, the
|
||||
`handleStreamingResponse` SSE-loop captured Perplexity's response
|
||||
metadata into a local `finalResponseData` variable as it streamed,
|
||||
but then immediately re-checked the same chunk and *cleared* the
|
||||
captured value if the chunk was the final one without metadata. Code
|
||||
as it was:
|
||||
|
||||
```js
|
||||
if (parsed.citations || parsed.images || parsed.search_results) {
|
||||
finalResponseData = parsed;
|
||||
}
|
||||
|
||||
if (parsed.choices?.[0]?.finish_reason === 'stop' &&
|
||||
!parsed.citations && !parsed.images && !parsed.search_results) {
|
||||
if (finalResponseData && !finalResponseData.choices?.[0]?.finish_reason) {
|
||||
console.log('🧹 Clearing potentially stale finalResponseData');
|
||||
finalResponseData = null;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Why this is wrong:
|
||||
|
||||
- `finalResponseData` is a local variable created at the top of
|
||||
`handleStreamingResponse` (line 609). Its scope is one request.
|
||||
It cannot ever be "stale from a previous request" — there is no
|
||||
previous request to be stale from.
|
||||
- Perplexity's normal SSE flow puts `search_results` / `citations`
|
||||
in **earlier** chunks. The **final** chunk usually carries only
|
||||
`choices[0].finish_reason: 'stop'` with no metadata. That is
|
||||
exactly the condition the cleanup fires on.
|
||||
- The cleanup also requires that the captured chunk doesn't have
|
||||
its own `finish_reason` — which is normal, because metadata
|
||||
chunks aren't the terminal ones. So the gate is "if metadata
|
||||
came in earlier, clear it now," which is precisely backwards.
|
||||
|
||||
Result: every streaming Perplexity request that completed normally
|
||||
discarded its citations before `processStreamingMetadata` could
|
||||
write them to the editor. Symptom the user reported: "I don't get
|
||||
the citations reference section."
|
||||
|
||||
Fix: removed the cleanup branch. Replaced the simple "last-write-
|
||||
wins" capture with a merge so partial metadata across chunks is
|
||||
preserved:
|
||||
|
||||
```js
|
||||
if (parsed.citations || parsed.images || parsed.search_results) {
|
||||
finalResponseData = {
|
||||
...(finalResponseData || {}),
|
||||
...parsed,
|
||||
};
|
||||
}
|
||||
```
|
||||
|
||||
Build clean. Bundle written to `main.js` for testing in the user's
|
||||
vault.
|
||||
|
||||
### Verification
|
||||
|
||||
- `pnpm run build` (production: `tsc -noEmit -skipLibCheck && node
|
||||
esbuild.config.mjs production`) green after each of the four
|
||||
dependency bands and after the citations fix.
|
||||
- ESLint flat config verified runnable (`npx eslint main.ts src/`)
|
||||
— emits warnings on pre-existing code, but loads and parses the
|
||||
config without error.
|
||||
- Production bundle dropped from ~492 KB to ~84 KB. This is **not**
|
||||
a regression: the previous artifact on disk was a dev build with
|
||||
inline source maps (`!isProduction ? 'inline' : false` in
|
||||
`esbuild.config.mjs:50`), and the new one is a true production
|
||||
minified build with sourcemaps disabled. Bundle contents
|
||||
spot-checked (`grep getReader|TextDecoder|reader.read main.js`)
|
||||
to confirm streaming primitives are intact.
|
||||
|
||||
## What Changed in Approach (the meta-lesson)
|
||||
|
||||
| Pattern this rejects | Pattern this adopts |
|
||||
|---|---|
|
||||
| Bump every dependency in one go and hope the build survives | Bump in bands by blast radius (minors → types-only majors → config-affecting majors), verify build after each band, isolate any breakage to one band |
|
||||
| Silence TypeScript deprecation warnings with `ignoreDeprecations` | Modernize the offending config — TS deprecations are early-warning for TS7 hard removals, not noise to mute |
|
||||
| Treat `.eslintrc` as the canonical config until it physically stops working | Migrate to flat config the moment the major bump requires it; flat config is now the only forward-compatible shape |
|
||||
| Pre-emptive "stale data" cleanup gated on heuristics about chunk shape | Trust local-scope variables to be local; if a guard isn't justified by an actual cross-request risk, it's just a foot-gun — delete it |
|
||||
| No changelog because the project has never had one | First changelog establishes the habit; even a small maintenance pass gets one so the next pass has a baseline to diff against |
|
||||
|
||||
The generalizable point: **a maintenance pass is not just `pnpm
|
||||
update --latest`**. The two majors here both required real config
|
||||
work (ESLint flat config, TS 6 tsconfig modernization), and the
|
||||
session also surfaced one runtime bug that was unrelated to the
|
||||
refresh but worth fixing in the same window. Bundling all of that
|
||||
into one changelog establishes the baseline; the next maintenance
|
||||
pass can diff cleanly against this one.
|
||||
|
||||
## Open Items
|
||||
|
||||
- **Streaming truncates mid-answer, intermittently, with no console
|
||||
error.** User reported it during this session; first prompt
|
||||
truncated, second prompt succeeded. No `Streaming Error:` notice
|
||||
was raised, no red console output, the loop just stops writing.
|
||||
Working hypothesis (unverified): either Perplexity's server is
|
||||
closing the SSE connection early under some condition (rate
|
||||
limiting, account / credit state, request shape) or Obsidian's
|
||||
Electron `fetch` is closing the underlying socket on idle. The
|
||||
streaming code in `handleStreamingResponse` has no
|
||||
`AbortController` and no timeout, so the truncation is not
|
||||
client-initiated. User explicitly deferred diagnosis: "something
|
||||
is funky I don't want to diagnose, or it's an api or credit
|
||||
thing." Defensive fix to consider next pass: add an
|
||||
`AbortController` with a generous timeout (5+ min for
|
||||
`sonar-deep-research`) so the failure mode at least surfaces a
|
||||
clear error instead of silent truncation.
|
||||
- **TextDecoder is recreated every chunk in
|
||||
`handleStreamingResponse`.** Each iteration runs
|
||||
`new TextDecoder().decode(value, { stream: true })`. The
|
||||
`stream: true` flag is meant to carry partial multi-byte UTF-8
|
||||
state across chunks, but a fresh decoder per chunk discards that
|
||||
state every time — so multi-byte characters split across a chunk
|
||||
boundary will be replaced with U+FFFD and the resulting JSON
|
||||
may fail to parse (caught silently in the per-line try/catch and
|
||||
logged as a warning). Pre-existing; not surfaced by this pass.
|
||||
Fix: hoist the decoder outside the `while (true)` loop. Held for
|
||||
a separate pass so this changelog stays scoped.
|
||||
- **Three runtime dependencies are declared but never imported.**
|
||||
`fastify`, `@modelcontextprotocol/sdk`, and `zod` are all in
|
||||
`dependencies` in `package.json` but not referenced by `main.ts`
|
||||
or any file in `src/`. Likely legacy from earlier scaffolding.
|
||||
Removing them would shrink the install footprint and the npm
|
||||
advisory surface area; not done here to keep the maintenance pass
|
||||
scoped to "refresh + fix the bug the user noticed." Worth a
|
||||
follow-up pass.
|
||||
- **Forty-two pre-existing ESLint errors / 33 warnings.** Surfaced
|
||||
for the first time because the flat config migration meant we
|
||||
actually ran lint. Mostly `consistent-type-imports` (auto-
|
||||
fixable), unused destructured imports in
|
||||
`src/types/obsidian.d.ts`, one `let → const` in
|
||||
`perplexityService.ts:608`, and `@typescript-eslint/no-explicit-any`
|
||||
warnings throughout. None block the build (`tsc + esbuild` doesn't
|
||||
run lint). `npx eslint . --fix` would clear roughly half of them
|
||||
mechanically. Held — separate intent from the maintenance pass.
|
||||
- **Version not bumped.** `manifest.json` and `package.json` both
|
||||
still read `0.0.0.1`. The plugin's versioning scheme is
|
||||
pre-release / non-semver-conformant; the user did not request a
|
||||
bump in this pass. If the citations fix gets shipped to users,
|
||||
consider bumping then.
|
||||
- **Commit not created.** All changes (config files, `package.json`,
|
||||
`pnpm-lock.yaml`, `tsconfig.json`, `perplexityService.ts`,
|
||||
`eslint.config.mjs`, this changelog) are staged in the working
|
||||
tree only. User has not requested a commit yet.
|
||||
|
||||
## Files Touched
|
||||
|
||||
```
|
||||
perplexed/
|
||||
├── package.json (deps refreshed across 13 packages; added typescript-eslint, @eslint/js, globals)
|
||||
├── pnpm-lock.yaml (regenerated against the new package.json)
|
||||
├── tsconfig.json (removed baseUrl + paths; moduleResolution node → bundler)
|
||||
├── eslint.config.mjs (created — flat-config equivalent of the deleted .eslintrc)
|
||||
├── .eslintrc (deleted — superseded by eslint.config.mjs)
|
||||
├── .eslintignore (deleted — superseded by ignores in eslint.config.mjs)
|
||||
├── src/
|
||||
│ └── services/
|
||||
│ └── perplexityService.ts (handleStreamingResponse: removed citations-eating "stale data" cleanup; replaced last-write-wins capture with merge across metadata chunks)
|
||||
└── changelog/
|
||||
└── 2026-05-02_01.md (created — this file, first changelog for this plugin)
|
||||
```
|
||||
|
||||
`main.js` and `styles.css` are build artifacts; rebuilt by
|
||||
`pnpm run build` and not part of the source-of-truth diff.
|
||||
|
||||
## Reference
|
||||
|
||||
- **Predecessor changelogs:** None — this is the first.
|
||||
- **Pattern reference for changelog format:**
|
||||
`/Users/mpstaton/code/lossless-monorepo/cite-wide/context-v/changelogs/2026-05-02_01.md`
|
||||
(cite-wide v0.2.0 release notes — frontmatter shape, section
|
||||
layout, "What Changed in Approach" / "Open Items" / "Files Touched"
|
||||
conventions).
|
||||
- **The bug-bearing function:**
|
||||
`src/services/perplexityService.ts` →
|
||||
`handleStreamingResponse` (line 594) and
|
||||
`processStreamingMetadata` (line 713).
|
||||
- **Build pipeline:** `package.json` `scripts.build`
|
||||
(`tsc -noEmit -skipLibCheck && node esbuild.config.mjs
|
||||
production`); `esbuild.config.mjs` for bundle config (target
|
||||
`es2022`, format `cjs`, externals include `obsidian`,
|
||||
`electron`, all `@codemirror/*`, all `@lezer/*`, plus
|
||||
`builtin-modules`).
|
||||
- **ESLint flat-config docs:**
|
||||
https://eslint.org/docs/latest/use/configure/migration-guide
|
||||
(referenced during the v10 migration).
|
||||
- **TypeScript 6 deprecations notice:**
|
||||
https://aka.ms/ts6 (referenced during the tsconfig
|
||||
modernization).
|
||||
- **Recent commits on `development` (pre-this-session):**
|
||||
`a13b4e2 Update styles.css`,
|
||||
`f75afbf Add WARP.md documentation for development workflow`,
|
||||
`153894f improve: Deep Research Streaming` —
|
||||
this maintenance pass starts from `a13b4e2`.
|
||||
35
eslint.config.mjs
Normal file
35
eslint.config.mjs
Normal file
|
|
@ -0,0 +1,35 @@
|
|||
import js from "@eslint/js";
|
||||
import tseslint from "typescript-eslint";
|
||||
import globals from "globals";
|
||||
|
||||
export default tseslint.config(
|
||||
{
|
||||
ignores: ["node_modules/", "main.js"],
|
||||
},
|
||||
js.configs.recommended,
|
||||
...tseslint.configs.recommended,
|
||||
...tseslint.configs.strict,
|
||||
{
|
||||
languageOptions: {
|
||||
parserOptions: {
|
||||
ecmaVersion: "latest",
|
||||
sourceType: "module",
|
||||
project: "./tsconfig.json",
|
||||
},
|
||||
globals: {
|
||||
...globals.node,
|
||||
},
|
||||
},
|
||||
rules: {
|
||||
"no-unused-vars": "off",
|
||||
"@typescript-eslint/no-unused-vars": ["error", { args: "none" }],
|
||||
"@typescript-eslint/ban-ts-comment": "off",
|
||||
"no-prototype-builtins": "off",
|
||||
"@typescript-eslint/no-empty-function": "off",
|
||||
"@typescript-eslint/no-explicit-any": "warn",
|
||||
"@typescript-eslint/explicit-module-boundary-types": "off",
|
||||
"@typescript-eslint/no-non-null-assertion": "off",
|
||||
"@typescript-eslint/consistent-type-imports": "error",
|
||||
},
|
||||
},
|
||||
);
|
||||
25
package.json
25
package.json
|
|
@ -22,20 +22,23 @@
|
|||
"author": "The Lossless Group",
|
||||
"license": "MIT",
|
||||
"devDependencies": {
|
||||
"@types/node": "^24.0.12",
|
||||
"@typescript-eslint/eslint-plugin": "8.36.0",
|
||||
"@typescript-eslint/parser": "8.36.0",
|
||||
"builtin-modules": "5.0.0",
|
||||
"esbuild": "0.25.6",
|
||||
"eslint": "^9.30.1",
|
||||
"@eslint/js": "^10.0.1",
|
||||
"@types/node": "^25.6.0",
|
||||
"@typescript-eslint/eslint-plugin": "8.59.1",
|
||||
"@typescript-eslint/parser": "8.59.1",
|
||||
"builtin-modules": "5.1.0",
|
||||
"esbuild": "0.28.0",
|
||||
"eslint": "^10.3.0",
|
||||
"globals": "^17.6.0",
|
||||
"obsidian": "latest",
|
||||
"tslib": "2.8.1",
|
||||
"typescript": "5.8.3"
|
||||
"typescript": "6.0.3",
|
||||
"typescript-eslint": "^8.59.1"
|
||||
},
|
||||
"dependencies": {
|
||||
"@modelcontextprotocol/sdk": "^1.15.0",
|
||||
"dotenv": "^17.2.0",
|
||||
"fastify": "^5.4.0",
|
||||
"zod": "^4.0.0"
|
||||
"@modelcontextprotocol/sdk": "^1.29.0",
|
||||
"dotenv": "^17.4.2",
|
||||
"fastify": "^5.8.5",
|
||||
"zod": "^4.4.2"
|
||||
}
|
||||
}
|
||||
|
|
|
|||
BIN
pnpm-lock.yaml
BIN
pnpm-lock.yaml
Binary file not shown.
|
|
@ -632,21 +632,14 @@ export class PerplexityService {
|
|||
|
||||
const parsed = JSON.parse(data);
|
||||
|
||||
// Store the final response data for processing citations and images
|
||||
// Always update finalResponseData to ensure we have the latest metadata
|
||||
// Capture the latest metadata across chunks. Perplexity typically
|
||||
// sends citations/search_results in earlier chunks; the final chunk
|
||||
// often carries only finish_reason. Merge so nothing is lost.
|
||||
if (parsed.citations || parsed.images || parsed.search_results) {
|
||||
finalResponseData = parsed;
|
||||
}
|
||||
|
||||
// Also clear any stale data if this chunk doesn't have metadata
|
||||
// This prevents using old metadata from previous requests
|
||||
if (parsed.choices?.[0]?.finish_reason === 'stop' && !parsed.citations && !parsed.images && !parsed.search_results) {
|
||||
// This is the final chunk but has no metadata, ensure we don't use stale data
|
||||
if (finalResponseData && !finalResponseData.choices?.[0]?.finish_reason) {
|
||||
// Only clear if the stored data doesn't have finish_reason (meaning it's incomplete)
|
||||
console.log('🧹 Clearing potentially stale finalResponseData');
|
||||
finalResponseData = null;
|
||||
}
|
||||
finalResponseData = {
|
||||
...(finalResponseData || {}),
|
||||
...parsed,
|
||||
};
|
||||
}
|
||||
|
||||
if (parsed.choices?.[0]?.delta?.content) {
|
||||
|
|
|
|||
246
styles.css
246
styles.css
|
|
@ -1,245 +1 @@
|
|||
/* src/styles/perplexity-modal.css */
|
||||
.perplexity-modal .text-input {
|
||||
width: 100%;
|
||||
margin: 8px 0;
|
||||
padding: 12px;
|
||||
}
|
||||
.perplexity-modal .setting-item-description {
|
||||
font-size: 12px;
|
||||
color: var(--text-muted);
|
||||
margin-top: 5px;
|
||||
}
|
||||
.perplexity-modal .setting-item-description.images-description {
|
||||
font-size: 11px;
|
||||
margin-top: 3px;
|
||||
}
|
||||
|
||||
/* src/styles/article-generator-modal.css */
|
||||
.article-generator-modal .text-input {
|
||||
width: 100%;
|
||||
margin: 8px 0;
|
||||
padding: 12px;
|
||||
}
|
||||
.article-generator-modal .setting-item-description {
|
||||
font-size: 12px;
|
||||
color: var(--text-muted);
|
||||
margin-top: 5px;
|
||||
}
|
||||
.article-generator-modal .term-description {
|
||||
display: block !important;
|
||||
margin-top: 8px;
|
||||
margin-bottom: 10px;
|
||||
width: 100% !important;
|
||||
flex-basis: 100% !important;
|
||||
order: 2;
|
||||
}
|
||||
.article-generator-modal .setting-item {
|
||||
flex-direction: column !important;
|
||||
align-items: flex-start !important;
|
||||
}
|
||||
.article-generator-modal .setting-item > * {
|
||||
width: 100% !important;
|
||||
}
|
||||
.article-generator-modal .hidden-input {
|
||||
display: none;
|
||||
}
|
||||
.article-generator-modal .setting-item-description {
|
||||
font-size: 12px;
|
||||
color: var(--text-muted);
|
||||
margin-top: 5px;
|
||||
font-style: italic;
|
||||
}
|
||||
|
||||
/* src/styles/perplexica-modal.css */
|
||||
.perplexica-modal .text-input {
|
||||
width: 100%;
|
||||
margin: 8px 0;
|
||||
padding: 12px;
|
||||
}
|
||||
|
||||
/* src/styles/lmstudio-modal.css */
|
||||
.lmstudio-modal .text-input {
|
||||
width: 100%;
|
||||
margin: 8px 0;
|
||||
padding: 12px;
|
||||
}
|
||||
.lmstudio-modal .system-prompt-input {
|
||||
width: 100%;
|
||||
min-height: 60px;
|
||||
}
|
||||
|
||||
/* src/styles/url-update-modal.css */
|
||||
.url-update-modal .text-input {
|
||||
width: 100%;
|
||||
margin: 8px 0;
|
||||
padding: 12px;
|
||||
}
|
||||
|
||||
/* src/styles/text-enhancement-modal.css */
|
||||
.text-enhancement-modal {
|
||||
max-width: 800px;
|
||||
width: 90vw;
|
||||
}
|
||||
.text-enhancement-modal .setting-item {
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
.text-enhancement-modal .setting-item label {
|
||||
display: block;
|
||||
margin-bottom: 5px;
|
||||
font-weight: 600;
|
||||
color: var(--text-normal);
|
||||
}
|
||||
.text-enhancement-modal .text-input {
|
||||
width: 40%;
|
||||
min-height: 100px;
|
||||
font-family: var(--font-monospace);
|
||||
font-size: 14px;
|
||||
line-height: 1.5;
|
||||
resize: vertical;
|
||||
}
|
||||
.text-enhancement-modal .dropdown {
|
||||
width: 100%;
|
||||
padding: 8px;
|
||||
border: 1px solid var(--background-modifier-border);
|
||||
border-radius: 4px;
|
||||
background-color: var(--background-primary);
|
||||
color: var(--text-normal);
|
||||
}
|
||||
.text-enhancement-modal button {
|
||||
padding: 8px 16px;
|
||||
border: none;
|
||||
border-radius: 4px;
|
||||
cursor: pointer;
|
||||
font-weight: 500;
|
||||
transition: background-color 0.2s ease;
|
||||
}
|
||||
.text-enhancement-modal button:disabled {
|
||||
opacity: 0.5;
|
||||
cursor: not-allowed;
|
||||
}
|
||||
.text-enhancement-modal button.mod-cta {
|
||||
background-color: var(--interactive-accent);
|
||||
color: var(--text-on-accent);
|
||||
}
|
||||
.text-enhancement-modal button.mod-cta:hover:not(:disabled) {
|
||||
background-color: var(--interactive-accent-hover);
|
||||
}
|
||||
.text-enhancement-modal button.mod-warning {
|
||||
background-color: var(--text-error);
|
||||
color: var(--text-on-accent);
|
||||
}
|
||||
.text-enhancement-modal button.mod-warning:hover:not(:disabled) {
|
||||
background-color: var(--text-error-hover);
|
||||
}
|
||||
.text-enhancement-modal input[type=checkbox] {
|
||||
margin-right: 8px;
|
||||
}
|
||||
.text-enhancement-modal .setting-item-description {
|
||||
font-size: 12px;
|
||||
color: var(--text-muted);
|
||||
margin-top: 4px;
|
||||
}
|
||||
.text-enhancement-modal .text-input[readonly] {
|
||||
background-color: var(--background-secondary);
|
||||
color: var(--text-muted);
|
||||
border: 1px solid var(--background-modifier-border);
|
||||
}
|
||||
.text-enhancement-modal .text-input:not([readonly]) {
|
||||
background-color: var(--background-primary);
|
||||
color: var(--text-normal);
|
||||
border: 1px solid var(--background-modifier-border);
|
||||
}
|
||||
@media (max-width: 768px) {
|
||||
.text-enhancement-modal {
|
||||
width: 95vw;
|
||||
max-width: none;
|
||||
}
|
||||
.text-enhancement-modal button {
|
||||
width: 100%;
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
.text-enhancement-modal .setting-item {
|
||||
margin-bottom: 15px;
|
||||
}
|
||||
}
|
||||
|
||||
/* src/styles/text-enhancement-with-images-modal.css */
|
||||
.get-related-images-modal {
|
||||
max-width: 600px;
|
||||
width: 90vw;
|
||||
}
|
||||
.get-related-images-modal .setting-item {
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
.get-related-images-modal .setting-item label {
|
||||
display: block;
|
||||
margin-bottom: 8px;
|
||||
font-weight: 600;
|
||||
color: var(--text-normal);
|
||||
}
|
||||
.get-related-images-modal .text-input {
|
||||
width: 40%;
|
||||
min-height: 120px;
|
||||
padding: 12px;
|
||||
border: 1px solid var(--background-modifier-border);
|
||||
border-radius: 6px;
|
||||
background-color: var(--background-primary);
|
||||
color: var(--text-normal);
|
||||
font-family: var(--font-monospace);
|
||||
font-size: 14px;
|
||||
line-height: 1.5;
|
||||
resize: vertical;
|
||||
}
|
||||
.get-related-images-modal .text-input:focus {
|
||||
outline: none;
|
||||
border-color: var(--interactive-accent);
|
||||
box-shadow: 0 0 0 2px var(--interactive-accent-hover);
|
||||
}
|
||||
.get-related-images-modal .text-input[readonly] {
|
||||
background-color: var(--background-secondary);
|
||||
color: var(--text-muted);
|
||||
cursor: not-allowed;
|
||||
}
|
||||
.get-related-images-modal button {
|
||||
padding: 8px 16px;
|
||||
border: none;
|
||||
border-radius: 4px;
|
||||
font-size: 14px;
|
||||
font-weight: 500;
|
||||
cursor: pointer;
|
||||
transition: background-color 0.2s ease;
|
||||
}
|
||||
.get-related-images-modal button.mod-cta {
|
||||
background-color: var(--interactive-accent);
|
||||
color: var(--text-on-accent);
|
||||
}
|
||||
.get-related-images-modal button.mod-cta:hover {
|
||||
background-color: var(--interactive-accent-hover);
|
||||
}
|
||||
.get-related-images-modal button:disabled {
|
||||
opacity: 0.6;
|
||||
cursor: not-allowed;
|
||||
}
|
||||
.get-related-images-modal h2 {
|
||||
margin-bottom: 20px;
|
||||
color: var(--text-normal);
|
||||
font-size: 1.5em;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
/* src/styles/main.css */
|
||||
.callout[data-callout=brain] {
|
||||
background-color: rgba(147, 51, 234, 0.1);
|
||||
border-left: 4px solid #9333ea;
|
||||
}
|
||||
.callout[data-callout=brain] .callout-title {
|
||||
color: #9333ea;
|
||||
font-weight: 600;
|
||||
}
|
||||
.callout[data-callout=brain] .callout-content {
|
||||
color: var(--text-normal);
|
||||
font-style: normal;
|
||||
}
|
||||
.callout[data-callout=brain] .callout-icon {
|
||||
color: #9333ea;
|
||||
}
|
||||
.perplexity-modal .text-input{width:100%;margin:8px 0;padding:12px}.perplexity-modal .setting-item-description{font-size:12px;color:var(--text-muted);margin-top:5px}.perplexity-modal .setting-item-description.images-description{font-size:11px;margin-top:3px}.article-generator-modal .text-input{width:100%;margin:8px 0;padding:12px}.article-generator-modal .setting-item-description{font-size:12px;color:var(--text-muted);margin-top:5px}.article-generator-modal .term-description{display:block!important;margin-top:8px;margin-bottom:10px;width:100%!important;flex-basis:100%!important;order:2}.article-generator-modal .setting-item{flex-direction:column!important;align-items:flex-start!important}.article-generator-modal .setting-item>*{width:100%!important}.article-generator-modal .hidden-input{display:none}.article-generator-modal .setting-item-description{font-size:12px;color:var(--text-muted);margin-top:5px;font-style:italic}.perplexica-modal .text-input{width:100%;margin:8px 0;padding:12px}.lmstudio-modal .text-input{width:100%;margin:8px 0;padding:12px}.lmstudio-modal .system-prompt-input{width:100%;min-height:60px}.url-update-modal .text-input{width:100%;margin:8px 0;padding:12px}.text-enhancement-modal{max-width:800px;width:90vw}.text-enhancement-modal .setting-item{margin-bottom:20px}.text-enhancement-modal .setting-item label{display:block;margin-bottom:5px;font-weight:600;color:var(--text-normal)}.text-enhancement-modal .text-input{width:40%;min-height:100px;font-family:var(--font-monospace);font-size:14px;line-height:1.5;resize:vertical}.text-enhancement-modal .dropdown{width:100%;padding:8px;border:1px solid var(--background-modifier-border);border-radius:4px;background-color:var(--background-primary);color:var(--text-normal)}.text-enhancement-modal button{padding:8px 16px;border:none;border-radius:4px;cursor:pointer;font-weight:500;transition:background-color .2s ease}.text-enhancement-modal button:disabled{opacity:.5;cursor:not-allowed}.text-enhancement-modal button.mod-cta{background-color:var(--interactive-accent);color:var(--text-on-accent)}.text-enhancement-modal button.mod-cta:hover:not(:disabled){background-color:var(--interactive-accent-hover)}.text-enhancement-modal button.mod-warning{background-color:var(--text-error);color:var(--text-on-accent)}.text-enhancement-modal button.mod-warning:hover:not(:disabled){background-color:var(--text-error-hover)}.text-enhancement-modal input[type=checkbox]{margin-right:8px}.text-enhancement-modal .setting-item-description{font-size:12px;color:var(--text-muted);margin-top:4px}.text-enhancement-modal .text-input[readonly]{background-color:var(--background-secondary);color:var(--text-muted);border:1px solid var(--background-modifier-border)}.text-enhancement-modal .text-input:not([readonly]){background-color:var(--background-primary);color:var(--text-normal);border:1px solid var(--background-modifier-border)}@media(max-width:768px){.text-enhancement-modal{width:95vw;max-width:none}.text-enhancement-modal button{width:100%;margin-bottom:8px}.text-enhancement-modal .setting-item{margin-bottom:15px}}.get-related-images-modal{max-width:600px;width:90vw}.get-related-images-modal .setting-item{margin-bottom:20px}.get-related-images-modal .setting-item label{display:block;margin-bottom:8px;font-weight:600;color:var(--text-normal)}.get-related-images-modal .text-input{width:40%;min-height:120px;padding:12px;border:1px solid var(--background-modifier-border);border-radius:6px;background-color:var(--background-primary);color:var(--text-normal);font-family:var(--font-monospace);font-size:14px;line-height:1.5;resize:vertical}.get-related-images-modal .text-input:focus{outline:none;border-color:var(--interactive-accent);box-shadow:0 0 0 2px var(--interactive-accent-hover)}.get-related-images-modal .text-input[readonly]{background-color:var(--background-secondary);color:var(--text-muted);cursor:not-allowed}.get-related-images-modal button{padding:8px 16px;border:none;border-radius:4px;font-size:14px;font-weight:500;cursor:pointer;transition:background-color .2s ease}.get-related-images-modal button.mod-cta{background-color:var(--interactive-accent);color:var(--text-on-accent)}.get-related-images-modal button.mod-cta:hover{background-color:var(--interactive-accent-hover)}.get-related-images-modal button:disabled{opacity:.6;cursor:not-allowed}.get-related-images-modal h2{margin-bottom:20px;color:var(--text-normal);font-size:1.5em;font-weight:600}.callout[data-callout=brain]{background-color:#9333ea1a;border-left:4px solid #9333ea}.callout[data-callout=brain] .callout-title{color:#9333ea;font-weight:600}.callout[data-callout=brain] .callout-content{color:var(--text-normal);font-style:normal}.callout[data-callout=brain] .callout-icon{color:#9333ea}
|
||||
|
|
|
|||
|
|
@ -1,10 +1,9 @@
|
|||
{
|
||||
"compilerOptions": {
|
||||
/* Base Options */
|
||||
"baseUrl": ".",
|
||||
"esModuleInterop": true,
|
||||
"module": "ESNext",
|
||||
"moduleResolution": "node",
|
||||
"moduleResolution": "bundler",
|
||||
"target": "ES2022",
|
||||
"lib": ["ES2022", "DOM"],
|
||||
"skipLibCheck": true,
|
||||
|
|
@ -40,12 +39,7 @@
|
|||
"inlineSources": true,
|
||||
"removeComments": true,
|
||||
"noEmitOnError": true,
|
||||
"noEmit": true,
|
||||
|
||||
/* Paths */
|
||||
"paths": {
|
||||
"*": ["node_modules/*"]
|
||||
}
|
||||
"noEmit": true
|
||||
},
|
||||
"include": [
|
||||
"**/*.ts",
|
||||
|
|
|
|||
Loading…
Reference in a new issue