rename to tono

This commit is contained in:
2026-03-29 22:51:58 -07:00
parent 961b5d08c8
commit 52da360804
33 changed files with 82 additions and 82 deletions

View File

@@ -1,4 +1,4 @@
# Gwyddion Features Not Yet in argonode # Gwyddion Features Not Yet in tono
Reference for future implementation. Grouped by value to typical SPM workflows. Reference for future implementation. Grouped by value to typical SPM workflows.
@@ -61,11 +61,11 @@ Reference for future implementation. Grouped by value to typical SPM workflows.
--- ---
## Already Implemented in argonode ## Already Implemented in tono
For reference, these Gwyddion equivalents are already covered: For reference, these Gwyddion equivalents are already covered:
| argonode Node | Category | Gwyddion Equivalent | | tono Node | Category | Gwyddion Equivalent |
|--------------|----------|-------------------| |--------------|----------|-------------------|
| Load Image / Load SPM File | io | File import (gwy, sxm, ibw) | | Load Image / Load SPM File | io | File import (gwy, sxm, ibw) |
| Save Image | io | File export | | Save Image | io | File export |

View File

@@ -1,6 +1,6 @@
# argonode # tono
argonode is a node-based image analysis application with: tono is a node-based image analysis application with:
- a Python backend built on `aiohttp` - a Python backend built on `aiohttp`
- a React + Vite frontend - a React + Vite frontend
@@ -11,7 +11,7 @@ The backend serves node definitions, runs workflows, manages file I/O, and strea
## Project Layout ## Project Layout
```text ```text
argonode/ tono/
backend/ Python server, execution engine, nodes backend/ Python server, execution engine, nodes
frontend/ React/Vite app frontend/ React/Vite app
tests/ Python tests tests/ Python tests
@@ -86,7 +86,7 @@ Notes:
- The frontend dev server proxies API and WebSocket requests to the backend. - The frontend dev server proxies API and WebSocket requests to the backend.
- `npm run dev` now clears Vite's local cache and stale Python bytecode first, then starts Vite with `--force`. - `npm run dev` now clears Vite's local cache and stale Python bytecode first, then starts Vite with `--force`.
- If you open the backend directly in a browser instead of the Vite dev server, argonode now refreshes `frontend/dist` automatically when checked-out frontend sources are newer, such as after a `git pull`. - If you open the backend directly in a browser instead of the Vite dev server, tono now refreshes `frontend/dist` automatically when checked-out frontend sources are newer, such as after a `git pull`.
- If you want the frontend accessible from other devices on your LAN, run: - If you want the frontend accessible from other devices on your LAN, run:
```powershell ```powershell
@@ -131,13 +131,13 @@ powershell -ExecutionPolicy Bypass -File scripts\build-desktop.ps1
The packaged app is written to: The packaged app is written to:
```text ```text
desktop-dist/argonode/ desktop-dist/tono/
``` ```
Main executable: Main executable:
```text ```text
desktop-dist/argonode/argonode.exe desktop-dist/tono/tono.exe
``` ```
### One-File Build ### One-File Build
@@ -157,20 +157,20 @@ During normal source-based development, input/output folders live under the repo
In the packaged desktop app, writable data is stored under: In the packaged desktop app, writable data is stored under:
```text ```text
%LOCALAPPDATA%\argonode\ %LOCALAPPDATA%\tono\
``` ```
Specifically: Specifically:
```text ```text
%LOCALAPPDATA%\argonode\input %LOCALAPPDATA%\tono\input
%LOCALAPPDATA%\argonode\output %LOCALAPPDATA%\tono\output
``` ```
You can override the packaged app data directory with: You can override the packaged app data directory with:
```powershell ```powershell
$env:ARGONODE_APPDATA="C:\path\to\custom\data" $env:TONO_APPDATA="C:\path\to\custom\data"
``` ```
## Useful Commands ## Useful Commands

View File

@@ -1,5 +1,5 @@
""" """
Core data types for argonode. Core data types for tono.
DataField mirrors Gwyddion's GwyDataField structure: DataField mirrors Gwyddion's GwyDataField structure:
xres, yres pixel dimensions xres, yres pixel dimensions

View File

@@ -1,5 +1,5 @@
""" """
Graph execution engine for argonode. Graph execution engine for tono.
Prompt format (same as ComfyUI): Prompt format (same as ComfyUI):
{ {

View File

@@ -8,10 +8,10 @@ from typing import Any, Callable
Callback = Callable[[str, Any], None] Callback = Callable[[str, Any], None]
_callbacks_var: ContextVar[dict[str, Callback | None]] = ContextVar( _callbacks_var: ContextVar[dict[str, Callback | None]] = ContextVar(
"argonode_execution_callbacks", "tono_execution_callbacks",
default={}, default={},
) )
_node_id_var: ContextVar[str | None] = ContextVar("argonode_execution_node_id", default=None) _node_id_var: ContextVar[str | None] = ContextVar("tono_execution_node_id", default=None)
_LEGACY_CALLBACK_ATTRS = { _LEGACY_CALLBACK_ATTRS = {
"preview": "_broadcast_fn", "preview": "_broadcast_fn",

View File

@@ -1,11 +1,11 @@
""" """
Entry point for argonode. Entry point for tono.
Run with: Run with:
python -m backend.main python -m backend.main
or simply: or simply:
python backend/main.py python backend/main.py
from the argonode/ directory. from the tono/ directory.
""" """
import asyncio import asyncio
@@ -36,7 +36,7 @@ def main() -> None:
app = create_app(loop) app = create_app(loop)
log.info("=" * 60) log.info("=" * 60)
log.info(" argonode — Node-based image analysis") log.info(" tono — Node-based image analysis")
log.info(" Open your browser at http://%s:%d", HOST, PORT) log.info(" Open your browser at http://%s:%d", HOST, PORT)
log.info("=" * 60) log.info("=" * 60)

View File

@@ -1,5 +1,5 @@
""" """
Node registry for argonode. Node registry for tono.
Nodes are plain Python classes decorated with @register_node. Nodes are plain Python classes decorated with @register_node.
NODE_CLASS_MAPPINGS is the single source of truth consumed by NODE_CLASS_MAPPINGS is the single source of truth consumed by

View File

@@ -1,5 +1,5 @@
""" """
Shared helper functions for argonode nodes. Shared helper functions for tono nodes.
""" """
from __future__ import annotations from __future__ import annotations

View File

@@ -251,7 +251,7 @@ class Save:
length = float(np.linalg.norm(n)) length = float(np.linalg.norm(n))
return n / length if length > 0 else np.array([0.0, 1.0, 0.0], dtype=np.float32) return n / length if length > 0 else np.array([0.0, 1.0, 0.0], dtype=np.float32)
lines = ["solid argonode"] lines = ["solid tono"]
vertices = np.asarray(mesh.vertices, dtype=np.float32) vertices = np.asarray(mesh.vertices, dtype=np.float32)
for face in np.asarray(mesh.faces, dtype=np.int32): for face in np.asarray(mesh.faces, dtype=np.int32):
a, b, c = vertices[int(face[0])], vertices[int(face[1])], vertices[int(face[2])] a, b, c = vertices[int(face[0])], vertices[int(face[1])], vertices[int(face[2])]
@@ -263,7 +263,7 @@ class Save:
lines.append(f" vertex {c[0]} {c[1]} {c[2]}") lines.append(f" vertex {c[0]} {c[1]} {c[2]}")
lines.append(" endloop") lines.append(" endloop")
lines.append(" endfacet") lines.append(" endfacet")
lines.append("endsolid argonode") lines.append("endsolid tono")
path.write_text("\n".join(lines) + "\n", encoding="utf-8") path.write_text("\n".join(lines) + "\n", encoding="utf-8")
def _send_warning(self, message: str): def _send_warning(self, message: str):

View File

@@ -1,5 +1,5 @@
""" """
Plugin loader for argonode. Plugin loader for tono.
Scans a plugins directory for .py files and packages (directories containing Scans a plugins directory for .py files and packages (directories containing
__init__.py), imports each one, and lets their @register_node decorators __init__.py), imports each one, and lets their @register_node decorators
@@ -96,17 +96,17 @@ def _import_plugin(name: str, path: Path) -> None:
""" """
Import a single plugin file (or package ``__init__.py``) via importlib. Import a single plugin file (or package ``__init__.py``) via importlib.
The module is registered under ``argonode_plugins.<name>`` in The module is registered under ``tono_plugins.<name>`` in
``sys.modules``. This namespace: ``sys.modules``. This namespace:
- avoids collisions with any PyPI package of the same name, and - avoids collisions with any PyPI package of the same name, and
- makes package-style plugins (with sub-modules) work correctly, because - makes package-style plugins (with sub-modules) work correctly, because
their relative imports resolve against the ``argonode_plugins.*`` parent. their relative imports resolve against the ``tono_plugins.*`` parent.
If the module was previously imported (e.g. on a hot-reload call after an If the module was previously imported (e.g. on a hot-reload call after an
upload), it is deleted from ``sys.modules`` first so the file is re-executed upload), it is deleted from ``sys.modules`` first so the file is re-executed
and any updated ``@register_node`` decorators take effect. and any updated ``@register_node`` decorators take effect.
""" """
module_name = f"argonode_plugins.{name}" module_name = f"tono_plugins.{name}"
# Remove stale module to support hot-reload after /upload-plugin. # Remove stale module to support hot-reload after /upload-plugin.
if module_name in sys.modules: if module_name in sys.modules:

View File

@@ -4,7 +4,7 @@ import os
import sys import sys
from pathlib import Path from pathlib import Path
APP_NAME = "argonode" APP_NAME = "tono"
def project_root() -> Path: def project_root() -> Path:
@@ -29,7 +29,7 @@ def frontend_dist_dir() -> Path:
def app_data_dir() -> Path: def app_data_dir() -> Path:
override = os.getenv("ARGONODE_APPDATA") override = os.getenv("TONO_APPDATA")
if override: if override:
return Path(override).expanduser().resolve() return Path(override).expanduser().resolve()
@@ -71,11 +71,11 @@ def plugins_enabled(*, native: bool) -> bool:
Return True when the plugin system should be active. Return True when the plugin system should be active.
Default behaviour: enabled on native/desktop builds, disabled for web. Default behaviour: enabled on native/desktop builds, disabled for web.
Override with the ARGONODE_PLUGINS environment variable: Override with the TONO_PLUGINS environment variable:
ARGONODE_PLUGINS=1 force on (useful for testing plugins via main.py) TONO_PLUGINS=1 force on (useful for testing plugins via main.py)
ARGONODE_PLUGINS=0 force off (disable even on native builds) TONO_PLUGINS=0 force off (disable even on native builds)
""" """
env = os.getenv("ARGONODE_PLUGINS", "").strip().lower() env = os.getenv("TONO_PLUGINS", "").strip().lower()
if env in ("1", "true", "yes"): if env in ("1", "true", "yes"):
return True return True
if env in ("0", "false", "no"): if env in ("0", "false", "no"):

View File

@@ -1,5 +1,5 @@
""" """
aiohttp web server for argonode. aiohttp web server for tono.
Routes Routes
------ ------
@@ -355,7 +355,7 @@ def create_app(
plugins, and notify every connected WebSocket client to refresh /nodes. plugins, and notify every connected WebSocket client to refresh /nodes.
Warning: uploading Python files is equivalent to remote code execution. Warning: uploading Python files is equivalent to remote code execution.
This endpoint is intentionally unrestricted because argonode is a This endpoint is intentionally unrestricted because tono is a
local-first application; do not expose it on a public network. local-first application; do not expose it on a public network.
""" """
reader = await request.multipart() reader = await request.multipart()

View File

@@ -15,7 +15,7 @@ from backend.runtime_paths import app_data_dir, ensure_runtime_dirs
from backend.server import create_app from backend.server import create_app
HOST = "127.0.0.1" HOST = "127.0.0.1"
WINDOW_TITLE = "argonode" WINDOW_TITLE = "tono"
class _Api: class _Api:
@@ -141,14 +141,14 @@ def main() -> None:
server_thread = threading.Thread( server_thread = threading.Thread(
target=_run_server, target=_run_server,
args=(HOST, port, ready, state), args=(HOST, port, ready, state),
name="argonode-server", name="tono-server",
daemon=True, daemon=True,
) )
server_thread.start() server_thread.start()
ready.wait(timeout=15.0) ready.wait(timeout=15.0)
if "error" in state: if "error" in state:
raise RuntimeError("argonode server failed to start") from state["error"] raise RuntimeError("tono server failed to start") from state["error"]
_wait_for_server(f"{base_url}/nodes") _wait_for_server(f"{base_url}/nodes")

View File

@@ -705,8 +705,8 @@
<span class="cline-any cline-yes">5x</span> <span class="cline-any cline-yes">5x</span>
<span class="cline-any cline-neutral">&nbsp;</span></td><td class="text"><pre class="prettyprint lang-js">import { sortNodesForParentOrder } from './nodeHierarchy.js'; <span class="cline-any cline-neutral">&nbsp;</span></td><td class="text"><pre class="prettyprint lang-js">import { sortNodesForParentOrder } from './nodeHierarchy.js';
&nbsp; &nbsp;
export const NODE_CLIPBOARD_KIND = 'argonode/node-selection'; export const NODE_CLIPBOARD_KIND = 'tono/node-selection';
export const NODE_CLIPBOARD_MIME = 'application/x-argonode-node-selection'; export const NODE_CLIPBOARD_MIME = 'application/x-tono-node-selection';
&nbsp; &nbsp;
function cloneValue(value) { function cloneValue(value) {
if (value == null) <span class="branch-0 cbranch-no" title="branch not covered" >return value;</span> if (value == null) <span class="branch-0 cbranch-no" title="branch not covered" >return value;</span>

View File

@@ -3,7 +3,7 @@
<head> <head>
<meta charset="UTF-8"> <meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>argonode — Image Analysis</title> <title>tono — Image Analysis</title>
</head> </head>
<body> <body>
<div id="root"></div> <div id="root"></div>

View File

@@ -1,10 +1,10 @@
{ {
"name": "argonode-frontend", "name": "tono-frontend",
"lockfileVersion": 3, "lockfileVersion": 3,
"requires": true, "requires": true,
"packages": { "packages": {
"": { "": {
"name": "argonode-frontend", "name": "tono-frontend",
"dependencies": { "dependencies": {
"@xyflow/react": "^12.0.0", "@xyflow/react": "^12.0.0",
"html-to-image": "^1.11.13", "html-to-image": "^1.11.13",

View File

@@ -1,5 +1,5 @@
{ {
"name": "argonode-frontend", "name": "tono-frontend",
"private": true, "private": true,
"type": "module", "type": "module",
"engines": { "engines": {

View File

@@ -1278,7 +1278,7 @@ function Flow() {
useEffect(() => { useEffect(() => {
api.setMessageHandler((msg) => { api.setMessageHandler((msg) => {
console.log('[argonode] WS:', msg.type, msg.data?.node_id || msg.data?.node || ''); console.log('[tono] WS:', msg.type, msg.data?.node_id || msg.data?.node || '');
switch (msg.type) { switch (msg.type) {
case 'execution_start': case 'execution_start':
setNodes((ns) => ns.map((n) => ({ setNodes((ns) => ns.map((n) => ({
@@ -1295,7 +1295,7 @@ function Flow() {
break; break;
case 'execution_error': case 'execution_error':
setStatus({ text: 'Error: ' + msg.data.message, level: 'error' }); setStatus({ text: 'Error: ' + msg.data.message, level: 'error' });
console.error('[argonode] execution error', msg.data); console.error('[tono] execution error', msg.data);
break; break;
case 'preview': case 'preview':
updateNodeData(msg.data.node_id, { previewImage: msg.data.image }); updateNodeData(msg.data.node_id, { previewImage: msg.data.image });
@@ -2799,7 +2799,7 @@ function Flow() {
<div className="app-container"> <div className="app-container">
{/* Toolbar */} {/* Toolbar */}
<div id="toolbar"> <div id="toolbar">
<span id="app-title">argonode</span> <span id="app-title">tono</span>
<div className="toolbar-group"> <div className="toolbar-group">
<button className="btn btn-primary" onClick={runWorkflow} title="Run workflow (Ctrl+Enter)"> <button className="btn btn-primary" onClick={runWorkflow} title="Run workflow (Ctrl+Enter)">

View File

@@ -224,7 +224,7 @@ class PreviewBoundary extends React.Component {
} }
componentDidCatch(error) { componentDidCatch(error) {
console.error('[argonode] preview render failed', error); console.error('[tono] preview render failed', error);
} }
componentDidUpdate(prevProps) { componentDidUpdate(prevProps) {

View File

@@ -2,7 +2,7 @@ import React, { useRef, useEffect, useCallback, useState } from 'react';
import * as THREE from 'three'; import * as THREE from 'three';
import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls.js'; import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls.js';
const VIEW3D_DIAGNOSTICS_STORAGE_KEY = 'argonode:view3d-diagnostics'; const VIEW3D_DIAGNOSTICS_STORAGE_KEY = 'tono:view3d-diagnostics';
const DEFAULT_CAMERA_STATE = { const DEFAULT_CAMERA_STATE = {
// A diagonal home view avoids edge-on framing when one lateral axis is much smaller. // A diagonal home view avoids edge-on framing when one lateral axis is much smaller.
azimuth: Math.PI / 4, azimuth: Math.PI / 4,
@@ -109,7 +109,7 @@ export default function SurfaceView({ meshData, nodeId, widgetValues, runtimeVal
try { try {
return canvas.toDataURL('image/png'); return canvas.toDataURL('image/png');
} catch (error) { } catch (error) {
console.warn('[argonode] Failed to capture View3D viewport snapshot', error); console.warn('[tono] Failed to capture View3D viewport snapshot', error);
updateDiagnostics({ updateDiagnostics({
status: 'snapshot error', status: 'snapshot error',
error: error?.message || String(error), error: error?.message || String(error),
@@ -454,7 +454,7 @@ export default function SurfaceView({ meshData, nodeId, widgetValues, runtimeVal
} }
scheduleViewportSync(0, false); scheduleViewportSync(0, false);
} catch (error) { } catch (error) {
console.error('[argonode] View3D mesh build failed', error); console.error('[tono] View3D mesh build failed', error);
updateDiagnostics({ updateDiagnostics({
status: 'mesh build error', status: 'mesh build error',
error: error?.message || String(error), error: error?.message || String(error),

View File

@@ -1,11 +1,11 @@
/** /**
* api.js — REST + WebSocket client for argonode backend. * api.js — REST + WebSocket client for tono backend.
* *
* Uses relative URLs so the Vite dev proxy (port 5173 → 8188) * Uses relative URLs so the Vite dev proxy (port 5173 → 8188)
* and production same-origin serving both work transparently. * and production same-origin serving both work transparently.
*/ */
const SESSION_STORAGE_KEY = 'argonode-session-id'; const SESSION_STORAGE_KEY = 'tono-session-id';
let _sessionId = null; let _sessionId = null;
let _ws = null; let _ws = null;
@@ -127,17 +127,17 @@ export function initWS() {
_ws = new WebSocket(`${protocol}//${window.location.host}/ws?session=${session}`); _ws = new WebSocket(`${protocol}//${window.location.host}/ws?session=${session}`);
_ws.onopen = () => { _ws.onopen = () => {
console.log('[argonode] WebSocket connected'); console.log('[tono] WebSocket connected');
}; };
_ws.onclose = () => { _ws.onclose = () => {
console.log('[argonode] WebSocket closed, reconnecting in 3s…'); console.log('[tono] WebSocket closed, reconnecting in 3s…');
clearTimeout(_reconnectTimer); clearTimeout(_reconnectTimer);
_reconnectTimer = setTimeout(() => initWS(), 3000); _reconnectTimer = setTimeout(() => initWS(), 3000);
}; };
_ws.onerror = (e) => { _ws.onerror = (e) => {
console.error('[argonode] WebSocket error', e); console.error('[tono] WebSocket error', e);
}; };
_ws.onmessage = (e) => { _ws.onmessage = (e) => {

View File

@@ -1,7 +1,7 @@
import { sortNodesForParentOrder } from './nodeHierarchy.js'; import { sortNodesForParentOrder } from './nodeHierarchy.js';
export const NODE_CLIPBOARD_KIND = 'argonode/node-selection'; export const NODE_CLIPBOARD_KIND = 'tono/node-selection';
export const NODE_CLIPBOARD_MIME = 'application/x-argonode-node-selection'; export const NODE_CLIPBOARD_MIME = 'application/x-tono-node-selection';
function cloneValue(value) { function cloneValue(value) {
if (value == null) return value; if (value == null) return value;

4
package-lock.json generated
View File

@@ -1,10 +1,10 @@
{ {
"name": "argonode", "name": "tono",
"lockfileVersion": 3, "lockfileVersion": 3,
"requires": true, "requires": true,
"packages": { "packages": {
"": { "": {
"name": "argonode", "name": "tono",
"hasInstallScript": true, "hasInstallScript": true,
"engines": { "engines": {
"node": ">=18.0.0", "node": ">=18.0.0",

View File

@@ -1,5 +1,5 @@
{ {
"name": "argonode", "name": "tono",
"private": true, "private": true,
"engines": { "engines": {
"node": ">=18.0.0", "node": ">=18.0.0",

View File

@@ -1,7 +1,7 @@
""" """
Example argonode plugin: Normalize Z Range Example tono plugin: Normalize Z Range
Drop any .py file into this plugins/ folder and restart argonode (or upload it Drop any .py file into this plugins/ folder and restart tono (or upload it
via POST /upload-plugin) — the node will appear in the Add Node menu immediately. via POST /upload-plugin) — the node will appear in the Add Node menu immediately.
─── What you need to import ───────────────────────────────────────────────── ─── What you need to import ─────────────────────────────────────────────────

View File

@@ -3,7 +3,7 @@ requires = ["setuptools>=68", "wheel"]
build-backend = "setuptools.build_meta" build-backend = "setuptools.build_meta"
[project] [project]
name = "argonode" name = "tono"
version = "0.1.0" version = "0.1.0"
description = "Node-based image analysis app with a Python backend and React frontend." description = "Node-based image analysis app with a Python backend and React frontend."
readme = "GWYDDION_FEATURE_GAP.md" readme = "GWYDDION_FEATURE_GAP.md"

View File

@@ -8,8 +8,8 @@
version="1.1" version="1.1"
id="svg1" id="svg1"
inkscape:version="1.4.3 (0d15f75, 2025-12-25)" inkscape:version="1.4.3 (0d15f75, 2025-12-25)"
sodipodi:docname="argonode.svg" sodipodi:docname="tono.svg"
inkscape:export-filename="argonode.png" inkscape:export-filename="tono.png"
inkscape:export-xdpi="130.05" inkscape:export-xdpi="130.05"
inkscape:export-ydpi="130.05" inkscape:export-ydpi="130.05"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"

Before

Width:  |  Height:  |  Size: 3.3 KiB

After

Width:  |  Height:  |  Size: 3.3 KiB

View File

@@ -41,7 +41,7 @@ $PYTHON -m PyInstaller \
desktop.py \ desktop.py \
--noconfirm \ --noconfirm \
--clean \ --clean \
--name argonode \ --name tono \
--windowed \ --windowed \
$MODE \ $MODE \
--distpath desktop-dist \ --distpath desktop-dist \
@@ -55,9 +55,9 @@ $PYTHON -m PyInstaller \
--collect-all webview --collect-all webview
if $CREATE_TAR; then if $CREATE_TAR; then
TAR_PATH="desktop-dist/argonode-linux.tar.gz" TAR_PATH="desktop-dist/tono-linux.tar.gz"
echo "Creating tarball..." echo "Creating tarball..."
tar -czf "$TAR_PATH" -C desktop-dist argonode tar -czf "$TAR_PATH" -C desktop-dist tono
echo "Tarball created: $TAR_PATH" echo "Tarball created: $TAR_PATH"
fi fi

View File

@@ -41,7 +41,7 @@ $PYTHON -m PyInstaller \
desktop.py \ desktop.py \
--noconfirm \ --noconfirm \
--clean \ --clean \
--name argonode \ --name tono \
--windowed \ --windowed \
$MODE \ $MODE \
--distpath desktop-dist \ --distpath desktop-dist \
@@ -55,12 +55,12 @@ $PYTHON -m PyInstaller \
--collect-all webview \ --collect-all webview \
--icon ../resources/icon.icns --icon ../resources/icon.icns
APP_BUNDLE="desktop-dist/argonode.app" APP_BUNDLE="desktop-dist/tono.app"
if [ ! -d "$APP_BUNDLE" ]; then if [ ! -d "$APP_BUNDLE" ]; then
# --onedir puts it inside a folder # --onedir puts it inside a folder
if [ -d "desktop-dist/argonode/argonode.app" ]; then if [ -d "desktop-dist/tono/tono.app" ]; then
APP_BUNDLE="desktop-dist/argonode/argonode.app" APP_BUNDLE="desktop-dist/tono/tono.app"
else else
echo "Warning: .app bundle not found; skipping DMG creation." echo "Warning: .app bundle not found; skipping DMG creation."
CREATE_DMG=false CREATE_DMG=false
@@ -68,7 +68,7 @@ if [ ! -d "$APP_BUNDLE" ]; then
fi fi
if $CREATE_DMG; then if $CREATE_DMG; then
DMG_PATH="desktop-dist/argonode.dmg" DMG_PATH="desktop-dist/tono.dmg"
echo "Creating DMG installer..." echo "Creating DMG installer..."
rm -f "$DMG_PATH" rm -f "$DMG_PATH"
@@ -80,7 +80,7 @@ if $CREATE_DMG; then
ln -s /Applications "$DMG_STAGING/Applications" ln -s /Applications "$DMG_STAGING/Applications"
hdiutil create \ hdiutil create \
-volname "argonode" \ -volname "tono" \
-srcfolder "$DMG_STAGING" \ -srcfolder "$DMG_STAGING" \
-ov \ -ov \
-format UDZO \ -format UDZO \

View File

@@ -57,7 +57,7 @@ $pyInstallerArgs = @(
"desktop.py", "desktop.py",
"--noconfirm", "--noconfirm",
"--clean", "--clean",
"--name", "argonode", "--name", "tono",
"--windowed", "--windowed",
$mode, $mode,
"--distpath", "desktop-dist", "--distpath", "desktop-dist",
@@ -77,4 +77,4 @@ Write-Host "Packaging desktop app..."
Assert-LastExitCode "PyInstaller packaging" Assert-LastExitCode "PyInstaller packaging"
Write-Host "Desktop build complete." Write-Host "Desktop build complete."
Write-Host "Output folder: $repoRoot\desktop-dist\argonode" Write-Host "Output folder: $repoRoot\desktop-dist\tono"

View File

@@ -122,7 +122,7 @@ def test_save_generic():
node.save(filename="triangle", directory_path=tmpdir, format="STL", value=mesh) node.save(filename="triangle", directory_path=tmpdir, format="STL", value=mesh)
stl_text = Path(tmpdir, "triangle.stl").read_text(encoding="utf-8") stl_text = Path(tmpdir, "triangle.stl").read_text(encoding="utf-8")
assert stl_text.startswith("solid argonode") assert stl_text.startswith("solid tono")
assert "facet normal" in stl_text assert "facet normal" in stl_text
try: try:

View File

@@ -15,7 +15,7 @@ from backend.session_runtime import (
def test_session_paths_round_trip(monkeypatch, tmp_path): def test_session_paths_round_trip(monkeypatch, tmp_path):
monkeypatch.setenv("ARGONODE_APPDATA", str(tmp_path / "appdata")) monkeypatch.setenv("TONO_APPDATA", str(tmp_path / "appdata"))
session_id = "session-test-1234" session_id = "session-test-1234"
input_dir, _ = ensure_session_runtime_dirs(session_id) input_dir, _ = ensure_session_runtime_dirs(session_id)
@@ -31,7 +31,7 @@ def test_session_paths_round_trip(monkeypatch, tmp_path):
def test_browser_sessions_cannot_escape_workspace(monkeypatch, tmp_path): def test_browser_sessions_cannot_escape_workspace(monkeypatch, tmp_path):
monkeypatch.setenv("ARGONODE_APPDATA", str(tmp_path / "appdata")) monkeypatch.setenv("TONO_APPDATA", str(tmp_path / "appdata"))
session_id = "session-test-5678" session_id = "session-test-5678"
ensure_session_runtime_dirs(session_id) ensure_session_runtime_dirs(session_id)

View File

@@ -7,7 +7,7 @@ from backend.server import PNG_SIGNATURE, save_png_bytes
def test_save_png_bytes_writes_exact_png_payload(tmp_path: Path): def test_save_png_bytes_writes_exact_png_payload(tmp_path: Path):
target = tmp_path / "workflow" target = tmp_path / "workflow"
payload = PNG_SIGNATURE + b"argonode-test-payload" payload = PNG_SIGNATURE + b"tono-test-payload"
saved_path = save_png_bytes(str(target), payload) saved_path = save_png_bytes(str(target), payload)