diff --git a/SOURCE.txt b/SOURCE.txt deleted file mode 100644 index 9012317..0000000 --- a/SOURCE.txt +++ /dev/null @@ -1,81 +0,0 @@ -PCBJam — self-hosted fork (CMMS embed) -====================================== - -This repository is a self-hosted fork of PCBJam (browser-based KiCad compiled to -WebAssembly), maintained for embedding the editor in the tas-tech.net CMMS -(TT-DB) at /vendor/pcbjam/. - -Upstream --------- - https://github.com/emergence-engineering/pcbjam - tracked here as git remote `upstream`. - - Forked at upstream commit: - 766e2f409fa8b098555226479742ec694709ea48 (branch main, 2026-09-01) - -Branches --------- - main pristine mirror of upstream @ 766e2f4 (no local changes) - build/host-networking docker/docker-compose.yml: host networking on the build - host (its dockerd runs bridge:none + iptables:false for - a VPN killswitch, so the image build + compile container - use the host network namespace). 1 commit (28c545f). - cmms-embed build/host-networking + sub-path mount support so the - standalone editor serves under /vendor/pcbjam/ with no - change to KiCad/wxWidgets or @pcbjam/shared. See the - commit message for the file-by-file breakdown. A pure - no-op when built without `--base` (root deploy). - -Submodules ----------- -Pinned by the superproject gitlinks (nothing in scripts/ overrides them — -`KICAD_COMMIT` in scripts/common/versions.sh is unused/informational): - - kicad 56678639eea1b3c0358f384fa47ef7fab78bd09b - upstream https://github.com/PCBJam/kicad-source-mirror (branch wasm-port) - wxwidgets 4e6cc5a441e46ac07b242caa3adacfd8e7c7ec50 - upstream https://github.com/PCBJam/wxWidgets (branch wasm-port) - web/pcbjam-shared a4984c626d847bd07ce66148d6ec96fde8ee8e42 - upstream https://github.com/PCBJam/pcbjam-shared (branch main) - -.gitmodules still points at PCBJam's GitHub forks — these are NOT mirrored into -Forgejo. A checkout needs `git submodule update --init --recursive` against GitHub. - -Toolchain / dependency pins (scripts/common/versions.sh) -------------------------------------------------------- - Emscripten SDK 6.0.6 (installed from emsdk inside docker/Dockerfile; - base image ubuntu:22.04) - KiCad 8.99 - OpenCASCADE 7.8.0 - wxWidgets 3.3.1 - Boost 1.84.0 - Protobuf 3.21.12 - Python 3.11.5 - ngspice 46 - FreeType 2.13.2 - HarfBuzz 8.3.0 - Cairo 1.18.0 - Pixman 0.42.2 - Zstd 1.5.5 - GLM 0.9.9.8 - (every download in versions.sh also carries a SHA256 pin) - -Build ------ - KiCad WASM: ./docker/build.sh kicad_editor -j 4 --build-deps (debug) - ./docker/build.sh kicad_editor -j 4 --full --release (ship) - Editor UI: cd web && pnpm install --frozen-lockfile - pnpm --filter @pcbjam/standalone exec vite build --base=/vendor/pcbjam/ - (env: web/standalone/.env.production on the cmms-embed branch) - -License -------- -KiCad and wxWidgets are GPLv3. PCBJam's own code carries its upstream licenses -(see LICENSE and the per-package headers; @pcbjam/shared is MIT). This fork is -distributed under the same terms. - -The corresponding source for any deployed WASM build IS this repository at the -commit the build was made from, together with the submodule revisions its -gitlinks pin (listed above). Repository: - - https://repo.tas-tech.net/AI_Assistant/pcbjam diff --git a/web/standalone/.env.production b/web/standalone/.env.production deleted file mode 100644 index cd505e5..0000000 --- a/web/standalone/.env.production +++ /dev/null @@ -1,28 +0,0 @@ -# CMMS embed (cmms-embed branch). Consumed by `vite build` (mode=production). -# Pair with `vite build --base=/vendor/pcbjam/`. All values are public (they ship -# in the bundle) — no secrets here. - -# The PHP adapter. Relative so it resolves against the CMMS origin. The adapter -# handles PATH_INFO, so /api/scopes/... and /api/me land as -# /pcb-project-api.php/api/scopes/... and /pcb-project-api.php/api/me. -VITE_API_BASE_URL=/pcb-project-api.php - -# Projects come from the REST adapter above; file bytes fetched + saves PUT back. -VITE_PROJECT_SOURCE=remote -VITE_DOC_SOURCE=api - -# No library backend for v1 — the editor boots with empty sym/fp-lib-tables. -VITE_LIBS_SOURCE=off - -# Flat WASM layout, served static by Apache under the mount (no per-tool subdir, -# VITE_WASM_MANIFEST intentionally unset). Files: kicad_editor.{js,wasm}, wx.js, -# wx-dom.js, images.tar.gz. -VITE_WASM_ROOT=/vendor/pcbjam/wasm - -# Cross-tab only; no collab server. -VITE_YJS_PROVIDER=broadcastchannel - -# VITE_APP_URL deliberately UNSET — with it set, every non-editor route would -# redirect away from the mount (lib/redirect.ts). -# VITE_USER / VITE_SCOPE deliberately UNSET — identity comes from -# /pcb-project-api.php/api/me, scope from the URL path segment after the mount. diff --git a/web/standalone/src/components/NewFileDialog.tsx b/web/standalone/src/components/NewFileDialog.tsx index 230bf49..651b7ef 100644 --- a/web/standalone/src/components/NewFileDialog.tsx +++ b/web/standalone/src/components/NewFileDialog.tsx @@ -7,7 +7,6 @@ import { } from "@pcbjam/shared"; import { Loader2 } from "lucide-react"; import { uploadFileBytes } from "@/lib/api"; -import { hardNav } from "@/lib/base-path"; import { currentScope } from "@/lib/config"; import { localProjectStore } from "@/lib/project-source"; import { useLocalProjects } from "@/lib/api"; @@ -125,7 +124,7 @@ export function NewFileDialog({ // A home-created project is browser-local (@local scope); an in-project new // file keeps the current scope. The tool is inferred from the file's ext. const scope = homeMode ? LOCAL_SCOPE : currentScope(); - hardNav(projectPath(scope, slug, finalName)); + window.location.assign(projectPath(scope, slug, finalName)); } catch (e) { setBusy(false); setError(e instanceof Error ? e.message : String(e)); diff --git a/web/standalone/src/components/WasmTool.tsx b/web/standalone/src/components/WasmTool.tsx index 643db7a..78b57b8 100644 --- a/web/standalone/src/components/WasmTool.tsx +++ b/web/standalone/src/components/WasmTool.tsx @@ -20,7 +20,6 @@ import { yjsProviderConfig, type DocSource, } from "@/lib/config"; -import { stripBase } from "@/lib/base-path"; import { redirectTargetFor } from "@/lib/redirect"; import { loadSessionIdentity, seedSessionIdentity } from "@/lib/session-identity"; import { useThemeValue } from "@/lib/theme"; @@ -630,10 +629,7 @@ export function WasmTool({ // non-editor surfaces: on a backed deploy (APP_URL set) they belong to the // management app, so quit goes straight there (one hop instead of letting // App.tsx's 0006 redirect bounce it). - // stripBase: segments are relative to the mount, so segments[1] is - // "projects"/"libs" even under /vendor/pcbjam/. exitPath stays app-absolute - // (no mount prefix) — installQuitHook's hardNav() re-adds it. - const segments = stripBase(win.location.pathname).split("/").filter(Boolean); + const segments = win.location.pathname.split("/").filter(Boolean); const exitPath = segments[1] === "libs" ? "/" : projectPath(currentScope(), slug); const removeQuitHook = installQuitHook(win, { diff --git a/web/standalone/src/components/wasm-tool/quit-hook.ts b/web/standalone/src/components/wasm-tool/quit-hook.ts index 8cf77bf..dfd3f78 100644 --- a/web/standalone/src/components/wasm-tool/quit-hook.ts +++ b/web/standalone/src/components/wasm-tool/quit-hook.ts @@ -6,8 +6,6 @@ // the page itself unloads (app.cpp UnloadCallback), so the dispatcher latches // off as soon as any unload/navigation is under way. -import { hardNav } from "@/lib/base-path"; - let activeQuitHook: (() => void) | undefined; let quitHandled = false; @@ -95,9 +93,7 @@ export function installQuitHook( // wasm stack has unwound. setTimeout(() => { opts.log(`[quit] editor closed — going to ${opts.exitUrl}`); - // hardNav: re-add the CMMS mount prefix to the app-absolute exit path - // (a full APP_URL redirect target passes through untouched). - hardNav(opts.exitUrl, win); + win.location.assign(opts.exitUrl); }, 0); }; diff --git a/web/standalone/src/components/wasm-tool/tool-navigation.ts b/web/standalone/src/components/wasm-tool/tool-navigation.ts index 2b9ea4e..77aeb39 100644 --- a/web/standalone/src/components/wasm-tool/tool-navigation.ts +++ b/web/standalone/src/components/wasm-tool/tool-navigation.ts @@ -7,7 +7,6 @@ import { toolSchema, type Tool, } from "@pcbjam/shared"; -import { hardNav } from "@/lib/base-path"; import { currentScope } from "@/lib/config"; import { defaultFileName, newFileTemplate, withExtension } from "@/lib/new-file"; import { memfsProjectDir } from "@/wasm/constants"; @@ -176,7 +175,7 @@ export function installToolNavigationHook( await createFile(relPath, bytes); opts.log(`[nav] created missing ${nextTool} file ${relPath} -> ${url}`); markDeliberateNavigation(); - hardNav(url, win); + win.location.assign(url); } catch (e) { pendingCreate = null; opts.log( @@ -197,7 +196,7 @@ export function installToolNavigationHook( opts.log(`[nav] ${rawToolName} ${rawFileName || "(no file)"} -> ${url}`); markDeliberateNavigation(); - hardNav(url, win); + win.location.assign(url); return true; }; diff --git a/web/standalone/src/lib/base-path.ts b/web/standalone/src/lib/base-path.ts deleted file mode 100644 index bf47041..0000000 --- a/web/standalone/src/lib/base-path.ts +++ /dev/null @@ -1,57 +0,0 @@ -/** - * Sub-path mount support (cmms-embed fork). - * - * The CMMS serves this SPA under `/vendor/pcbjam/`, built with - * `vite build --base=/vendor/pcbjam/` — so `import.meta.env.BASE_URL` is that - * prefix (always a leading + trailing slash; "/" for a root deploy). - * - * `` already makes - * `` / `navigate()` / `useLocation()` mount-relative. This module covers - * the two things the router can't: - * 1. code that reads `window.location.pathname` raw (currentScope, WasmTool's - * quit-path), and - * 2. the hard cross-document `window.location.assign()` navigations — the - * WASM runtime is process-global, so a tool switch / File→Quit / new file - * is a full page load, not a router transition, and the app paths handed - * to it (`@pcbjam/shared` `projectPath()` etc.) are origin-absolute. - * - * Nothing here touches `@pcbjam/shared` — it also compiles for the backend, - * where `import.meta` does not exist. - */ - -/** `import.meta.env.BASE_URL` without its trailing slash ("" for a root deploy). */ -export const BASE_PREFIX = import.meta.env.BASE_URL.replace(/\/$/, ""); - -/** - * `pathname` with the mount prefix removed; the result always starts with "/". - * A pathname outside the mount (or a root deploy) is returned unchanged. - */ -export function stripBase(pathname: string): string { - if ( - BASE_PREFIX && - (pathname === BASE_PREFIX || pathname.startsWith(`${BASE_PREFIX}/`)) - ) { - const rest = pathname.slice(BASE_PREFIX.length); - return rest === "" ? "/" : rest; - } - return pathname; -} - -/** - * `window.location.assign()` to an app-absolute path (e.g. from - * `projectPath()`), re-adding the mount prefix. A full URL (has a scheme or is - * protocol-relative) passes through untouched — so an `APP_URL` redirect target - * is never corrupted. - * - * `win` is injectable for the same reason the tool-navigation / quit hooks take - * a window: test seams and the wx-port's frame window. - */ -export function hardNav( - appPath: string, - win: { location: { assign(url: string): void } } = window, -): void { - const url = /^([a-z][a-z0-9+.-]*:)?\/\//i.test(appPath) - ? appPath - : BASE_PREFIX + appPath; - win.location.assign(url); -} diff --git a/web/standalone/src/lib/config.ts b/web/standalone/src/lib/config.ts index 959f587..0685612 100644 --- a/web/standalone/src/lib/config.ts +++ b/web/standalone/src/lib/config.ts @@ -133,7 +133,6 @@ export const LOCAL_PROJECTS_ENABLED = import.meta.env.VITE_LOCAL_PROJECTS === "idb"; import { colorForUser, type PresenceUser } from "@pcbjam/shared"; -import { stripBase } from "@/lib/base-path"; import { sessionIdentity } from "@/lib/session-identity"; import type { ProviderConfig, ProviderKind } from "@/wasm/collab"; import { cdnLibsSource } from "@/wasm/libs/cdn-source"; @@ -283,11 +282,7 @@ export const PRESENCE_TUNER_ENABLED = import.meta.env.VITE_PRESENCE_TUNER === "1 */ export function currentScope(): string { if (typeof window !== "undefined") { - // stripBase: under the CMMS sub-path mount the scope is the first segment - // AFTER /vendor/pcbjam/, not "vendor". No-op for a root deploy. - const seg = stripBase(window.location.pathname) - .split("/") - .filter(Boolean)[0]; + const seg = window.location.pathname.split("/").filter(Boolean)[0]; if (seg && seg !== "projects" && seg !== "libs") { return decodeURIComponent(seg); } diff --git a/web/standalone/src/main.tsx b/web/standalone/src/main.tsx index ba35ef6..bb194f1 100644 --- a/web/standalone/src/main.tsx +++ b/web/standalone/src/main.tsx @@ -38,10 +38,7 @@ const queryClient = new QueryClient({ // instantiate exactly once per navigation. ReactDOM.createRoot(document.getElementById("root")!).render( - {/* basename = the vite `base` (import.meta.env.BASE_URL) so the CMMS - sub-path mount (/vendor/pcbjam/) is transparent to /navigate(); - the hard location.assign() navs use hardNav() (lib/base-path.ts). */} - + , diff --git a/web/standalone/src/pages/ProjectView.tsx b/web/standalone/src/pages/ProjectView.tsx index 00fbbb3..a79c2ab 100644 --- a/web/standalone/src/pages/ProjectView.tsx +++ b/web/standalone/src/pages/ProjectView.tsx @@ -17,7 +17,6 @@ import { Trash2, } from "lucide-react"; import { fetchFileBytes, useProject, useSourceDescriptor } from "@/lib/api"; -import { hardNav } from "@/lib/base-path"; import { downloadBytes } from "@/lib/download"; import { localProjectStore } from "@/lib/project-source"; import { zipFiles } from "@/lib/zip"; @@ -109,7 +108,7 @@ export function ProjectView() { // scoped with a full reload; document tools create a templated file first. const launchTool = (tool: Tool) => { if (FILELESS_TOOLS.has(tool)) { - hardNav(projectToolPath(scope, slug, tool)); + window.location.assign(projectToolPath(scope, slug, tool)); } else { setNewFileTool(tool); }