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>
This commit is contained in:
Your Name 2026-07-22 08:16:58 -04:00
parent bbe97e4d30
commit 4b9096250b
3 changed files with 26 additions and 80 deletions

View file

@ -2,7 +2,6 @@
<html lang="en"> <html lang="en">
<head> <head>
<meta charset="UTF-8" /> <meta charset="UTF-8" />
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Tauri + Vue + Typescript App</title> <title>Tauri + Vue + Typescript App</title>
</head> </head>

View file

@ -1,81 +1,17 @@
<template> <template>
<main style="font-family: monospace; padding: 1rem"> <div id="app" class="h-screen">
<button @click="run">Run backend check</button> <router-view/>
<pre>{{ log }}</pre> </div>
</main>
</template> </template>
<script setup lang="ts"> <style lang="scss">
import { ref } from 'vue'; @import 'n-link-core/assets/tailwind.css';
import { invoke } from '@tauri-apps/api/core';
import { listen } from '@tauri-apps/api/event';
const log = ref(''); #app {
const add = (line: string) => (log.value += line + '\n'); user-select: none;
font-family: Avenir, Helvetica, Arial, sans-serif;
listen('addDevice', (e) => add('event addDevice: ' + JSON.stringify(e.payload))); -webkit-font-smoothing: antialiased;
listen('removeDevice', (e) => add('event removeDevice: ' + JSON.stringify(e.payload))); -moz-osx-font-smoothing: grayscale;
listen('progress', (e) => add('event progress: ' + JSON.stringify(e.payload))); color: #2c3e50;
// libnspire transfer commands can hang indefinitely against the CX II's
// known firmware Busy issue. Give those calls a client-side timeout so a
// hang on one call never prevents the rest of the harness from reporting.
const TRANSFER_TIMEOUT_MS = 10_000;
function withTimeout<T>(promise: Promise<T>, ms: number): Promise<T> {
return new Promise<T>((resolve, reject) => {
const timer = setTimeout(() => reject(new Error('TIMED_OUT')), ms);
promise.then(
(value) => {
clearTimeout(timer);
resolve(value);
},
(err) => {
clearTimeout(timer);
reject(err);
},
);
});
} }
</style>
// Runs one invoke call, reporting its outcome without ever throwing
// a failure or timeout here must not stop the remaining steps from running.
async function step<T>(label: string, call: () => Promise<T>, timeoutMs?: number) {
try {
const result = timeoutMs ? await withTimeout(call(), timeoutMs) : await call();
add(`${label} -> ` + JSON.stringify(result, null, 2));
return { ok: true as const, result };
} catch (e) {
if (e instanceof Error && e.message === 'TIMED_OUT') {
add(`${label} -> TIMED OUT (expected — known CX II firmware issue)`);
} else {
add(`${label} ERROR: ` + String(e));
}
return { ok: false as const, result: undefined };
}
}
async function run() {
log.value = '';
// enumerate only reads USB descriptors, no device transfer it never
// hangs, so it gets no timeout and always reports before anything else runs.
const enumerateResult = await step('enumerate', () => invoke<any[]>('enumerate'));
if (!enumerateResult.ok) return;
const devices = enumerateResult.result;
if (!devices.length) {
add('NO DEVICES FOUND');
return;
}
const { busNumber, address } = devices[0];
add(`opening ${busNumber}:${address}`);
// The remaining commands perform real libnspire transfers and are the
// ones known to hang or return Busy on this machine's CX II firmware.
await step('open_device', () => invoke('open_device', { busNumber, address }), TRANSFER_TIMEOUT_MS);
await step('list_dir /', () => invoke('list_dir', { busNumber, address, path: '/' }), TRANSFER_TIMEOUT_MS);
await step('close_device', () => invoke('close_device', { busNumber, address }), TRANSFER_TIMEOUT_MS);
}
</script>

View file

@ -1,4 +1,15 @@
import { createApp } from "vue"; import { createApp } from 'vue';
import App from "./App.vue"; import App from './App.vue';
import router from './router';
import devices from './components/devices';
import { DEVICES_KEY } from 'n-link-core/components/devices';
import 'n-link-core/assets/tailwind.css';
createApp(App).mount("#app"); const app = createApp(App);
app.use(router);
// Two registrations, both required:
// globalProperties -> templates across n-link-core reference $devices
// provide -> <script setup> blocks have no `this`, so they inject
app.config.globalProperties.$devices = devices;
app.provide(DEVICES_KEY, devices);
app.mount('#app');