Commit graph

9 commits

Author SHA1 Message Date
sotashimozono
085edf436a
release: 1.1.2 (stable) — validator-clean (#395)
Promotes the validator-cleanup work to a stable release.

- CSS: collapse xterm's text-decoration style (double/wavy/dotted/dashed)
  and simultaneous overline+underline to a plain underline. Obsidian's
  bundled Chromium only partially supports the style and multiple-line
  forms, which the community-plugin validator flagged. Single overline /
  underline / line-through are kept (fully supported).
- Version: 1.1.2-beta.14 -> 1.1.2 (drops -beta; syncs all manifests +
  versions.json, minAppVersion 1.5.0).

Cumulative since 1.1.1: root npm devDeps so the validator resolves plugin
types (#393), obsidian pinned ~1.12.3, and the unsafe-* / CSS warnings
cleared (#394 + this).

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-09 15:28:18 +09:00
sotashimozono
195a3041b4
fix(types): eliminate validator unsafe-* / CSS-portability warnings (#394)
With the root devDeps now resolving types, the validator surfaced a few real
`any` leaks plus a CSS portability note. All fixed:

- ResourceBridge: name the range fetcher's return type (BinaryRange) and
  annotate `let result: BinaryRange`. `let result;` had decayed to `any`
  because evolving-any doesn't survive the try/catch reassignment, so
  result.mtime/.totalSize/.bytes were all unsafe.
- QueueReplayer: same pattern — extract `ReplayOutcome`, annotate
  `let outcome: ReplayOutcome`.
- logger: cast the bound console methods to `ConsoleFn` (the snapshot's
  declared type) rather than `typeof console.warn`.
- AdapterPatcher: replace `fn.bind(x)` (whose typing varied by env) with an
  equivalent arrow wrapper.
- styles.css: fold xterm's text-decoration-line + -style sub-properties into
  the text-decoration shorthand (only the shorthand is fully supported on
  older Obsidian; the sub-properties were flagged partial).

Verified: validator-sim eslint (root deps, cwd=root) -> 0; plugin tsc + lint -> 0.

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-09 15:04:58 +09:00
sotashimozono
a765e8afbc
fix(styles): resolve xterm CSS bot warnings — drop !important, use longhand text-decoration (#383)
Replace .xterm-dim !important with doubled-class specificity (.xterm-dim.xterm-dim).
Split text-decoration shorthand into text-decoration-line + text-decoration-style
longhand properties for Obsidian 1.4.5 compatibility.

Bumps beta to 1.1.2-beta.4.
2026-06-08 23:06:02 +09:00
sotashimozono
4bcda468cf
fix(plugin): resolve Obsidian reviewer findings (CSS / disclosure / dynamic-exec) — 1.1.1-beta.2 (#373)
* fix(plugin): resolve Obsidian reviewer findings (CSS, disclosure, dynamic-exec)

Non-daemon items from the community-plugin validator:
- styles.css: 6-digit hex (#000->#000000, #FFF->#FFFFFF); drop the https
  scheme from the xterm.js license comment
- README: add a "Permissions & data access" disclosure (network / fs /
  system identity / process exec / clipboard; states no telemetry)
- esbuild: strip ssh2's `new Function("return 2n ** 32n")()` BigInt probe
  post-build, so the shipped main.js has zero Dynamic Code Execution
  (eval/new Function = 0). The BigInt value is inlined; behaviour is unchanged.

Deferred to the daemon/build track: release asset split + artifact
attestation. xterm.js vendored CSS warnings (!important, text-decoration)
left as-is to avoid breaking terminal rendering.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* chore(release): bump to 1.1.1-beta.2

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* fix(plugin): address PR review (probe hard-fail, license verbatim, CI guard)

PR #373 review follow-ups:
- esbuild: hard-fail the prod build (warn on dev) when the ssh2 BigInt
  probe string is not found, so a silent no-op cannot ship `new Function`
  unstripped; surface the real error object in the build .catch; correct
  the comment (it is ssh2's MAX_32BIT_BIGINT constant init, not a probe)
- styles.css: restore https:// in the xterm.js MIT license comment to keep
  the attribution notice verbatim
- ci.yml + release.yml: add a "Dynamic code execution guard" asserting
  main.js has 0 new Function / eval after the production build

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-08 17:17:41 +09:00
sotashimozono
e44c476c68
feat: integrated remote terminal pane (xterm.js + ssh2 shell channel) (#149) (#234)
Closes #149. Adds a single-pane remote terminal in the right sidebar,
backed by xterm.js and an ssh2 PTY channel multiplexed onto the
already-authenticated SSH connection that SftpClient owns.

## Files

- `src/ssh/SftpClient.ts` — `openShell({rows, cols, term?, cmd?})`
  method (mirrors existing `openUnixStream` / `exec` shape). When `cmd`
  is supplied, runs it under the PTY (e.g. `/usr/bin/zsh -l`); otherwise
  the remote launches the user's default login shell.
- `src/ssh/RemoteShell.ts` (NEW) — thin lifecycle wrapper around the
  ssh2 ClientChannel. `open() / write() / resize() / close() / isOpen()`.
  Stdout + stderr both surface as a single `onData(chunk)`. Two
  synchronous-flag guards keep `open()` race-free:
  `opening` blocks concurrent open() calls before they reach the
  await; the post-await `if (this.closed) ch.end()` check prevents a
  channel leak when close() runs while open() is pending.
- `src/ui/RemoteTerminalView.ts` (NEW) — `extends ItemView`, renders
  xterm.js + FitAddon, debounced 100 ms ResizeObserver → setWindow,
  graceful "Not connected" / "Failed to open shell" disconnected
  states. Reads font/scrollback/shell from plugin settings each `onOpen`.
  The `onClose` callback logs `reason`/`cause` unconditionally so the
  channel-close audit trail isn't lost when the View has torn down.
  The `shell.open()` catch block disposes + nulls shell/term/fit so
  late channel events can't reach a half-constructed view.
- `src/main.ts` — `registerView(VIEW_TYPE_REMOTE_TERMINAL, ...)` plus
  `addCommand("Open remote terminal")` (checkCallback gates on
  client.isAlive). `disconnect()` calls
  `app.workspace.detachLeavesOfType(VIEW_TYPE_REMOTE_TERMINAL)` so the
  shell channel close fires while ssh2.Client is still around.
  `openRemoteTerminal()` uses `setActiveLeaf` rather than `revealLeaf`
  to keep the minAppVersion 1.4.0 contract (revealLeaf needs 1.7.2).
  `openingTerminal` re-entrant flag prevents two leaves being created
  by rapid command-palette activations.
- `src/types.ts` + `src/constants.ts` — three new optional settings:
  `terminalShell?: string`, `terminalFontSize?: number` (default 12),
  `terminalScrollback?: number` (default 1000).
- `src/settings/SettingsTab.ts` — Terminal section with the three
  inputs (font validated 6-32 px, scrollback 100-100_000 lines).
- `styles.css` — terminal pane host/disconnected styling + inlined
  xterm.js v5 default stylesheet (~3 KB, MIT license preserved) so
  users don't need a separate CSS asset.
- `package.json` — `@xterm/xterm@^5.5` + `@xterm/addon-fit@^0.10`
  added as production dependencies.
- `.github/workflows/release.yml` + `.github/workflows/ci.yml` —
  bundle cap raised 600 -> 800 KB to absorb the bundled xterm
  (770 KB actual). esbuild splitting needs ESM which Obsidian doesn't
  support, so single-bundle is the only option. Comment in workflows
  explains the rationale.
- `tests/RemoteShell.test.ts` (NEW) — 20 unit tests against a fake
  ssh2 ClientChannel: open/double-open guards, concurrent-open guard,
  close-while-pending end()s the channel + bypasses listener-attach,
  stdout+stderr routing, write/resize/close, lifecycle invariants
  (no double-onClose, suppressed-after-close events, etc.).
- `vitest.config.ts` — `RemoteTerminalView.ts` added to coverage
  exclude (xterm.js + ResizeObserver under jsdom is impractical to
  unit-test; covered by manual smoke against a real Obsidian window,
  consistent with the other src/ui/*Modal/Bar exclusions).

## Verified

- `tsc --noEmit` clean
- `npm run lint` clean (sentence-case + active-window-timers
  + no-floating-promises + minAppVersion gates all satisfied)
- `vitest run` 780 pass / 1 Windows-skipped (was 760)
- `node esbuild.config.mjs production` -> 770 KB main.js (under 800 KB cap)

## Out of scope (per #149 v1)

- Multiple terminal tabs
- Persisted scrollback across re-opens
- Split panes
- Search-in-scrollback
- back-pressure on huge pastes (ssh2 handles it; we trust write() return)

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-04 08:17:11 +09:00
Souta
28542d35b6 feat: status-bar indicator for large file transfers (#127)
Show "↑ 5.2 MB · note.pdf · 3s" in the status bar when uploads or
downloads larger than 1 MB are in flight, so users can see something
is happening during slow transfers instead of assuming the editor
froze.

- TransferTracker (in-memory event emitter)
- LargeTransferBar (status bar item, 250 ms tick for elapsed counter)
- SftpDataAdapter.writeBuffer wraps client.writeBinary in begin/end
- SftpDataAdapter.readBuffer wraps the cache-mismatch re-read path
  (uses the stat we already pay for to know size upfront)
- AdapterManager wires the tracker into the adapter
- main.ts constructs tracker + bar; onunload removes the bar
- 12 unit tests for TransferTracker

True chunked progress (≥4 updates per transfer) is deferred — that
needs wire-protocol changes (fs.writeBinaryStream proto method) and
will land separately. This ship eliminates the "editor froze, Cmd-Q"
pain without protocol churn.

Closes #127

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-03 15:40:00 +09:00
Souta
9572826cd2 feat: daemon health panel in settings tab (#128)
Add a "Daemon" section to the settings tab, visible only when
connected via RPC transport:

- Status badge: 🟢 Running (version + capabilities) or 🔴 Down
- View log: reads last 50 lines from ~/.obsidian-remote/server.log
  via SSH exec
- Restart: stops + redeploys the daemon, rebinds the adapter

Also adds CSS classes for the daemon log panel and the remote
path browser modal (from #130).

Closes #128

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-05-01 15:22:52 +09:00
Souta
5b0952cca7 chore(ui): move 68 inline styles to CSS classes (0.4.63)
Obsidian community plugin review guidelines explicitly forbid setting
styles via JavaScript. This is the most-cited reason for review pushback;
clearing it before submitting to obsidianmd/obsidian-releases.

Touched files (5):

- ConnectModal.ts:        3  styles
- PendingEditsBar.ts:     3  styles (+ .is-hidden toggle)
- PendingEditsModal.ts:  13  styles
- PendingPluginsModal.ts: 14  styles
- ThreeWayMergeModal.ts: 35  styles

styles.css is organised by feature with section banners. Diff-line tints
moved verbatim (green rgba(34,197,94,.18) / red rgba(239,68,68,.18));
both render correctly on light + dark themes.

569/569 tests pass, typecheck clean.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-29 11:47:12 +09:00
Souta
21bb70a5d0 chore: monorepo restructure (plugin/ + server/ + proto/)
Move the entire Obsidian plugin tree under plugin/ and add an empty
server/ tree (Go) and proto/ directory so the upcoming
obsidian-remote-server daemon has a home in the same repo. The plugin
remains the only thing that builds today; the server is a hello-world
skeleton that prints "not implemented yet" and exits non-zero, with a
Makefile that knows how to cross-compile for linux/darwin × amd64/arm64
once real code lands.

Background:
  Approach A (vault-adapter monkey-patch) hit structural ceilings —
  vault index frozen at startup, third-party plugins bypass DataAdapter,
  empty-remote .obsidian read failures cascade through Templater/Kanban
  etc. We are pivoting to the VS Code Remote-SSH model: a small Go
  daemon on the remote host, JSON-RPC over a SSH-tunnelled WebSocket,
  fsnotify-driven push events, attachment serving over HTTP on the same
  socket. This restructure is the first mechanical step before the
  protocol and transport land.

Mechanical changes:
- git mv all plugin sources, manifest, configs, scripts, and tests
  into plugin/.
- plugin/scripts/dev-install.mjs walks one extra parent (`pluginRoot`
  → `repoRoot` → `..` for the dev vault) so REMOTE_SSH_DEV_VAULT
  defaulting still resolves to ../SelfArchive-dev relative to the
  repo, not to plugin/.
- CI: ci.yml runs lint/test/build with `working-directory: plugin`
  and a server job that builds + tests the Go module. release.yml
  builds out of plugin/ and uploads plugin/{main.js,manifest.json,
  styles.css}.
- Dependabot: npm directory becomes /plugin; new gomod directory /server.
- Labeler: paths re-anchored to plugin/, with new plugin/server/proto
  area labels.

Verification:
  cd plugin && npm install && npx tsc --noEmit && npm test (76/76)
  cd plugin && npm run build:install (367 KB; dev vault refreshed).
  Go side waits on CI (no Go toolchain on the dev host).
2026-04-25 10:52:52 +09:00
Renamed from styles.css (Browse further)