Commit graph

106 commits

Author SHA1 Message Date
Your Name 6219e03c35 fix(core): refresh file listing when the device queue drains
File operations are pushed onto the device's command queue and run
asynchronously, but FileBrowser only re-listed the directory when dev,
path, or updateIndex changed -- and updateIndex was only ever bumped by
a breadcrumb click. The listing stayed stale after an upload, delete,
rename, or directory creation.

Watch the device's running flag and queue length, and re-list on the
busy -> idle transition so a multi-file delete refreshes once at the end
rather than per queued command. The refresh is silent: it skips the
loading flag so the current icons stay on screen instead of flashing the
spinner, and keeps the old listing if the re-fetch fails.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-22 17:05:04 -04:00
Your Name f2c2844079 chore: add cargo.lock to git ignore file 2026-07-22 16:42:53 -04:00
Josip Jureta a0d955d3e7
fix(cx2): checksum NNSE packets over their declared length (#2)
Long CX II operations — listing a folder with many entries, downloading a
file of any size — failed with a reported `Busy`.

readPacket checksummed `transferred`, the byte count libusb returned, rather
than `completeLength`, the length the packet declares. The calculator can
hand back more bytes than the packet occupies (a 64-byte packet arriving as
65 was what showed up in tracing), and the stray byte failed the checksum.
The packet was dropped and so never acked, the calculator retransmitted the
same sequence number indefinitely, and the receive loop gave up after 40
reads. `transferred` was also wrong after the multi-chunk continuation loop,
where it holds only the final chunk's size — the reason large stream
transfers were unreliable.

Also add NNSE retransmission to packet_send_cx2. A lost packet or lost ack
was previously fatal, since the packet was written exactly once. Retries now
carry the "not the first try" bit (reqAck bit 3) that TI's own stack sets,
keeping the same seqno so the calculator can drop a duplicate. This path did
not trigger in testing — every packet acked on the first attempt once the
checksum was fixed — so its timeouts are deliberately generous to avoid
retransmitting during slow flash writes.

While here, zero `misc` and `unknown` instead of sending malloc garbage
inside a checksummed header, and handle allocation failure.

Verified against CX II firmware (0451:e022): `ls /` returns all 51 entries
across 8 runs, a 193 KB download is byte-identical across two runs, and
mkdir/rmdir round-trips.

Note the error was never actually Busy. The libnspire crate (0.2.3) matches
its positive NSPIRE_ERR_* constants against libnspire's negative return
codes, so every error falls through to the libusb table and is mislabelled;
-NSPIRE_ERR_INVALPKT and LIBUSB_ERROR_BUSY are both -6. That mismapping is
upstream in the crate and is not addressed here.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-22 16:35:23 -04:00
Josip Jureta f6410b5591
Merge pull request #1 from jjureta/port/tauri2-vue3
Port/tauri2 vue3
2026-07-22 08:21:21 -04:00
Your Name 4b9096250b fix(desktop): commit the app shell files Task 9 left unstaged
The app-shell commit (f45e893) added Home.vue, About.vue, and the router
but never staged App.vue, main.ts, or index.html. HEAD therefore still
contained Plan A's debug harness and a main.ts that wired neither the
router nor the device store — a fresh checkout would have built the
harness, not the real UI.

The working tree had the correct content all along, which is why the
running app was right and the verification (a grep against the working
tree, not the commit) passed.

- App.vue: harness replaced by router-view + tailwind import
- main.ts: router, globalProperties.$devices, provide(DEVICES_KEY)
- index.html: drop the scaffold's vite.svg favicon link

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-22 08:16:58 -04:00
Your Name bbe97e4d30 docs(desktop): README no longer needs --legacy-peer-deps; document web exclusion 2026-07-22 08:06:06 -04:00
Your Name b2b102b1b9 fix(build): drop web from npm workspaces to unbreak Tailwind resolution
web/ declares @nuxtjs/tailwindcss, which pulls tailwindcss 1.9.6. npm
hoisted that to the root, where @tailwindcss/forms resolved it instead of
the 3.4.19 desktop needs, breaking the CSS build.

Task 9 worked around this by copying a package into node_modules, which
would not survive npm ci. Removing web from the workspaces array is the
durable fix and is consistent with the spec, which declares web knowingly
broken and out of scope for this port. Restore the entry when web is
migrated to Nuxt 3.

Verified from a clean install: root tailwindcss is 3.4.19 and the build
emits 33KB of real CSS.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-22 08:02:59 -04:00
Your Name f45e893bba feat(desktop): port app shell to Vue 3, replace verification harness
Router to vue-router 4 with hash history (custom protocol has no server
for path-based deep links). createApp replaces new Vue. The device store
is registered on globalProperties so n-link-core templates keep resolving
$devices, and also provided via DEVICES_KEY for <script setup> injection.
Removes Plan A's temporary harness and scaffold assets.

Also renames desktop/postcss.config.js and tailwind.config.js to .cjs:
with "type": "module" in desktop/package.json, Node treated their
`module.exports`/`require` as ES module syntax and errored. This was
latent since the Vue 3 foundation task because nothing previously
imported n-link-core/assets/tailwind.css for real; this task's App.vue
is the first to trigger postcss processing during the build.
2026-07-22 07:35:33 -04:00
Your Name a21eead456 feat(desktop): port device store to Vue 3 reactive
Replaces the Vue 2 component-as-store (new Devices() extending Vue) with
reactive(). All ~10 $set/$delete calls are deleted -- Vue 3 proxy
reactivity tracks plain assignment and delete. Tauri 2 import paths
(@tauri-apps/api/core, @tauri-apps/plugin-dialog). runQueue/addToQueue
become module-scope helpers closing over the reactive state, since they
are internal to the store and not part of GenericDevices.

Adds a null guard in promptUploadFiles before iterating the dialog
result (the Vue 2 original would throw if the user cancelled the
dialog). Implements uploadFiles/uploadOsFile as intentional no-ops,
matching the original desktop store -- the desktop app resolves uploads
through a native path-based dialog instead of browser File objects.
2026-07-22 06:03:33 -04:00
Your Name 1198f6f511 feat(core): port FileBrowser to Vue 3, drop vue-async-computed
Replaces the Vue 2-only async computed with an explicit watch + refs,
preserving the path/updateIndex re-fetch triggers and the loading flag.
2026-07-21 21:13:37 -04:00
Your Name 9359f11e6c feat(core): port FileData to Vue 3 + element-plus 2026-07-21 21:09:32 -04:00
Your Name 69871e71f1 fix(core): correct two CalcInfo type errors missed by the build
npm run build only type-checks components something imports, so the three
tasks that ported components in isolation were never actually checked. A
temporary probe importing all five surfaced these:

- uploadNative declared its param as Event & {target: HTMLInputElement},
  which is not assignable to the DOM's (payload: Event) => void handler.
  Cast inside the function instead.
- info.os_extension.split('.').pop() is string | undefined but uploadOs
  takes string. Extracted to an osExtension computed with a '' fallback.

Only CalcInfo was affected; FileIcon, FileView, DeviceSelect, and
DeviceQueue all passed.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-21 21:06:27 -04:00
Your Name fec8fa2695 feat(core): port DeviceSelect and DeviceQueue to Vue 3 + element-plus
@PropSync -> defineModel, element-ui popover -> element-plus
(v-model:visible), slot="reference" -> #reference, and webpack tilde
image paths -> ESM imports.
2026-07-21 21:05:02 -04:00
Your Name 3ee9925f91 feat(core): port CalcInfo and FileView to Vue 3 script setup 2026-07-21 20:55:52 -04:00
Your Name 7869a747bc feat(core): port FileIcon to Vue 3, replace require() with import.meta.glob
30 webpack require() calls replaced by a single eager import.meta.glob.
The extension-to-icon mapping is preserved exactly, restructured from a
switch chain into lookup tables. Fixes alt="name" rendering the literal
string 'name'.
2026-07-21 20:49:27 -04:00
Your Name 49e9e3879e feat(frontend): Vue 3 foundation — Tailwind 3, Vite alias, shared types
Migrates n-link-core's Tailwind config from 1.x to 3.x (drops future/
variants/purge, swaps custom-forms for @tailwindcss/forms) and replaces
the Vue 2 'vue/types/vue' augmentation with Vue 3
ComponentCustomProperties. Deletes the Vue 2 shims.
2026-07-21 20:44:28 -04:00
Your Name 15f219bd43 fix(desktop): run blocking USB commands on the blocking pool
Plan A verification found close_device timing out despite doing no I/O:
all commands were synchronous, Tauri runs sync commands on the main
thread, so a hung list_dir blocked every subsequent command.

The 11 libnspire-touching commands now spawn_blocking. enumerate and
close_device stay sync — neither performs a transfer. Return types become
concrete because impl Serialize cannot cross the async boundary. No
change to command names or payloads.
2026-07-21 20:37:09 -04:00
Your Name 81a77f1bcd Add Plan B: Vue 3 frontend port implementation plan
Ten tasks: async-command backend fix, Tailwind 3 + Vite foundation, the
8 n-link-core components, the device store, the app shell, verification.

Grounded in the real scaffold rather than assumptions. Reading the actual
sources surfaced three hazards missing from the earlier follow-on notes:
vue-async-computed (Vue 2 only, drives FileBrowser's listing and spinner),
30 require() calls in FileIcon, and @tailwindcss/custom-forms.

Tailwind 3 chosen over 4: the theme is a JS config with 16 @apply/theme()
uses in scoped SCSS, and 4's CSS-first rewrite would layer a second
migration onto the Vue one.

Task 1 fixes the command-serialization defect found during Plan A
verification: all commands were sync, so a hung list_dir blocked the whole
queue. It goes first because the UI is otherwise untestable on this
hardware.

Core components inject the store via an InjectionKey rather than importing
it, so n-link-core stays decoupled from the desktop implementation and the
web consumer remains portable.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-21 20:24:09 -04:00
Your Name 320a24022c docs+chore: address final review findings
- Correct the vendored libnspire-sys retry limit in spec and plan: the
  actual constant in vendor/libnspire-sys/libnspire/src/cx2.cpp:391 is 30,
  not 100. The '10 -> 100' claim originated in nlink-cli's own Cargo.toml
  comment and was propagated into both documents unverified.
- Drop @tauri-apps/plugin-opener from desktop/package.json; the Rust plugin
  and its capability entry were removed in Task 3, leaving this dangling.
- Reconcile desktop/package.json version 0.1.0 -> 0.1.6 to match Cargo.toml
  and tauri.conf.json.
- Rewrite desktop/README.md, which still instructed users to
  'sudo apt install webkit2gtk-4.0' -- the exact unavailable package this
  port exists to move off. Now documents npm workspaces, the --legacy-peer-deps
  requirement, the dist/-before-cargo gotcha, snap LD_LIBRARY_PATH breakage,
  AppImage FUSE fallback, and the vendored patch.

Disclosure note: commit 4626858 also committed the previously untracked
nlink-cli/ and vendor/ trees (~5900 lines). Committing vendor/ is required --
the [patch.crates-io] override cannot resolve without it -- but the commit
message did not say so. Recorded here rather than rewriting branch history.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-19 21:41:28 -04:00
Your Name 0c9fd4d86c build(desktop): regenerate icons from n-link artwork
Replaces Tauri scaffold placeholder icons with app-icon.png. Android/iOS
variants emitted by the icon tool are gitignored — this is a Linux-only
build per the plan's scope.

Verified: deb depends only on libwebkit2gtk-4.1-0 + libgtk-3-0, with no
webkit2gtk-4.0 or libssl1.1 reference — the failure this port exists to fix.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-19 20:01:13 -04:00
Your Name 0dad5fa035 test(desktop): add temporary backend verification harness
Adds a throwaway App.vue that exercises enumerate/open_device/list_dir/
close_device over Tauri 2 IPC and logs addDevice/removeDevice/progress
events. open_device, list_dir, and close_device are wrapped with a 10s
client-side timeout each so a hang or Busy response from the CX II's
known firmware issue can't block the other calls from reporting;
enumerate only reads USB descriptors and is left untimed.

Installs @tauri-apps/plugin-dialog and @tauri-apps/plugin-shell per the
task-7 brief's Step 1. Manual GUI verification against a connected
device (brief Steps 3-4) is out of scope here and left to the user;
download_file/sha256 cross-check is intentionally omitted since any
libnspire transfer against this CX II is known to hang. Replaced by
the real UI in Plan B.
2026-07-19 19:48:03 -04:00
Your Name 9dc2ac8c7a feat(desktop): restore headless CLI mode on clap 4
Reuses nlink-cli's already-migrated cli.rs rather than repeating the
clap 3-beta -> 4 migration. Also copies NOTICE.txt alongside cli.rs
since its include_str! path is relative to the file's own directory.
2026-07-19 19:43:53 -04:00
Your Name 4c629aaf53 feat(desktop): wire Tauri 2 builder, hotplug, and capabilities
Hotplug registration moves from on_page_load to setup (runs once, so the
AtomicBool guard is dropped). v1 allowlist replaced by a capability file
granting dialog:allow-open and shell:allow-open. CSP from 0472908 carried
forward to app.security.csp; bundle targets narrowed to deb + appimage.

Also derives Clone on device::AddDevice: Tauri 2's Emitter::emit requires
Serialize + Clone (v1's did not), and the addDevice event payload was
missing the derive. No wire-format or IPC contract change.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-19 19:38:31 -04:00
Your Name b54976fd28 feat(desktop): port all 13 IPC commands to Tauri 2
Window -> WebviewWindow, emit now requires the Emitter trait, and
hashbrown's drain_filter is replaced by an explicit collect-then-remove
on std HashMap. IPC contract unchanged.

Also derive Clone on ProgressUpdate (device.rs): Tauri 2's
Emitter::emit requires Serialize + Clone, unlike Tauri 1's
Window::emit which only required Serialize. Required for
progress_sender's window.emit("progress", ProgressUpdate { .. })
call to compile. No change to serialized shape or field names.
2026-07-19 19:00:35 -04:00
Your Name 816300fbcc feat(desktop): port device registry and error type to Tauri 2
Splits the former 478-line main.rs into focused modules. Drops hashbrown
in favour of std HashMap (the drain_filter API it was used for was
renamed with changed semantics) and drops vendored libusb1-sys in favour
of the system library, matching nlink-cli.

Also removes the Task 2 scaffold's lib.rs/tauri-plugin-opener indirection
(the brief's module layout is a plain binary with no lib target) and drops
the now-dangling "opener:default" permission from capabilities/default.json,
which otherwise fails the Tauri build script with an unresolved permission
error.
2026-07-19 09:44:22 -04:00
Your Name 4626858fa5 feat(desktop): replace Tauri 1 / Vue CLI tree with Tauri 2 + Vue 3 + Vite scaffold
Tauri 1.0.0-beta.8 links webkit2gtk-4.0, unavailable on Ubuntu 26.04.
Verified: builds and links libwebkit2gtk-4.1.so.0, libsoup-3.0.so.0,
libjavascriptcoregtk-4.1.so.0 with no webkit-4.0 or libssl.1.1 refs.

Workspace moved from yarn to npm; yarn.lock invalidated by this port.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-19 09:36:36 -04:00
Your Name 94c62e810b docs(plan): amend Plan A verification for unavailable oracle
n-link-cli ls / returns Busy then hangs (known CX II firmware issue,
owned by the user, out of scope here). Transfer-dependent gates are
downgraded to non-blocking; enumerate remains a full verification of the
IPC path since it reads USB descriptors only and does no libnspire
transfer.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-19 09:23:10 -04:00
Your Name 8db940edc8 Add Plan A: Tauri 2 backend port implementation plan
Eight tasks from system-dep install through verified deb/appimage
bundles, with a webkit2gtk-4.1 go/no-go gate at Task 2 and n-link-cli
used as the verification oracle against the connected CX II.

Splits the spec's two phases into two plans; Plan B (frontend) is
written after Plan A is verified so it can be grounded in the real
scaffold output rather than assumptions.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-19 09:08:53 -04:00
Your Name 754fbf9c70 Add design spec for Tauri 2 + Vue 3 desktop port
Ports desktop from Tauri 1.0.0-beta.8 (webkit2gtk-4.0, unavailable on
Ubuntu 26.04) to Tauri 2.x (webkit2gtk-4.1), alongside Vue 2 -> Vue 3 and
Vue CLI -> Vite. Wires in the locally patched libnspire-sys already proven
by nlink-cli.

Scoped to Linux (deb + appimage). The web/ package shares n-link-core and
is knowingly left broken, deferred to its own project.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-19 09:01:06 -04:00
lights0123 0472908ef4
Fix csp causing blank screen in release mode 2021-11-13 12:42:10 -05:00
lights0123 89a613d25a switch to tauri-build 2021-10-31 15:57:03 -04:00
lights0123 a8dddd1756 Small tweaks 2021-10-27 16:59:52 -04:00
JandereDev 3311e0d358 Check OS update file extension 2021-10-27 16:59:52 -04:00
JandereDev abd8797751 Added upload-os, copy, move subcommands 2021-10-27 16:59:52 -04:00
JandereDev cdd06cb3e6 Added download and ls, formatted cli.rs 2021-10-27 16:59:52 -04:00
JandereDev fd6d7d87b6 Added error handling to upload subcommand 2021-10-27 16:59:52 -04:00
JandereDev a08eb0b791 Added mkdir and rmdir subcommands 2021-10-27 16:59:52 -04:00
lights0123 5ce4d8a560
Workaround CI issue on Windows 2021-08-30 19:55:16 -04:00
lights0123 ade24ce050
Workaround CI issue 2021-08-30 17:57:59 -04:00
lights0123 eb961b8973
Port to tauri beta 2021-08-30 16:49:54 -04:00
lights0123 35cc07f0ed
Bump version 2021-04-06 17:39:41 -04:00
lights0123 75ef04b742
Show errors when udev rules are required on desktop 2021-04-06 17:38:45 -04:00
lights0123 4b90a1a8da
Error messages during passive operation 2021-04-06 17:26:08 -04:00
lights0123 ac1a26a797
Error messages 2021-04-06 17:01:54 -04:00
lights0123 5d5b98dd59
Ensure cache is valid: change the restore keys... 2021-04-05 18:07:40 -04:00
lights0123 b555130353
Ensure cache is valid: bump cache key 2021-04-05 17:59:56 -04:00
lights0123 fd07af00e7
Ensure cache is valid: ok, fix for new changes 2021-04-05 17:55:00 -04:00
lights0123 4c0b2277c6
Ensure cache is valid: wtf actions/cache#403 2021-04-05 17:49:51 -04:00
lights0123 a07d785ca1
Ensure cache is valid: ah, it's the target directory 2021-04-05 17:36:43 -04:00
lights0123 6823ee76f6
Ensure cache is valid... again 2021-04-05 17:33:32 -04:00