rename to tono
This commit is contained in:
@@ -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 |
|
||||||
|
|||||||
20
README.md
20
README.md
@@ -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
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
"""
|
"""
|
||||||
Graph execution engine for argonode.
|
Graph execution engine for tono.
|
||||||
|
|
||||||
Prompt format (same as ComfyUI):
|
Prompt format (same as ComfyUI):
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -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",
|
||||||
|
|||||||
@@ -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)
|
||||||
|
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
"""
|
"""
|
||||||
Shared helper functions for argonode nodes.
|
Shared helper functions for tono nodes.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|||||||
@@ -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):
|
||||||
|
|||||||
@@ -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:
|
||||||
|
|||||||
@@ -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"):
|
||||||
|
|||||||
@@ -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()
|
||||||
|
|||||||
@@ -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")
|
||||||
|
|
||||||
|
|||||||
@@ -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"> </span></td><td class="text"><pre class="prettyprint lang-js">import { sortNodesForParentOrder } from './nodeHierarchy.js';
|
<span class="cline-any cline-neutral"> </span></td><td class="text"><pre class="prettyprint lang-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) <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>
|
||||||
|
|||||||
@@ -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>
|
||||||
|
|||||||
4
frontend/package-lock.json
generated
4
frontend/package-lock.json
generated
@@ -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",
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
{
|
{
|
||||||
"name": "argonode-frontend",
|
"name": "tono-frontend",
|
||||||
"private": true,
|
"private": true,
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"engines": {
|
"engines": {
|
||||||
|
|||||||
@@ -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)">
|
||||||
|
|||||||
@@ -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) {
|
||||||
|
|||||||
@@ -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),
|
||||||
|
|||||||
@@ -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) => {
|
||||||
|
|||||||
@@ -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
4
package-lock.json
generated
@@ -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",
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
{
|
{
|
||||||
"name": "argonode",
|
"name": "tono",
|
||||||
"private": true,
|
"private": true,
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=18.0.0",
|
"node": ">=18.0.0",
|
||||||
|
|||||||
@@ -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 ─────────────────────────────────────────────────
|
||||||
|
|||||||
@@ -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"
|
||||||
|
|||||||
@@ -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 |
@@ -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
|
||||||
|
|
||||||
|
|||||||
@@ -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 \
|
||||||
|
|||||||
@@ -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"
|
||||||
|
|||||||
@@ -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:
|
||||||
|
|||||||
@@ -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)
|
||||||
|
|||||||
@@ -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)
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user