forked from 1b-agent/opencadstudio-upstream
Ship client-neutral MCP bundles
This commit is contained in:
1 parent
17e5cda3fb
commit
afbf826b0c
30 files changed
+285
-446
No files matched your search
+14
-33
@@ -1,42 +1,23 @@
|
||||
# OpenCADStudio automation
|
||||
# OpenCADStudio MCP control
|
||||
|
||||
`--serve` remains available for isolated headless scripts. `live.py` connects to the real desktop application through a private per-process descriptor under the user's OCS configuration directory. The GUI owns every mutation: transport threads only validate and enqueue requests.
|
||||
Every native OpenCADStudio build contains the same MCP server as the editor. `OpenCADStudio --mcp` starts it over stdio, opens the desktop editor when needed, and exposes the live document without Python, a package manager, a sidecar service, or client-specific code.
|
||||
|
||||
The live protocol requires protocol version 1, stable session/document IDs, an expected edit revision for mutations, and a unique request ID. Commands report `waiting_input` while interactive work remains. Asynchronous file and renderer work remains `running` until its real callback finishes. A bounded operation cache makes retries with the same payload idempotent; after a restart or an expired operation, clients must read state instead of replaying a mutation.
|
||||
The server provides four tools:
|
||||
|
||||
Operations include document state and activation, paged entity queries, layer/header/property inspection, command discovery, start/run/step/cancel, WCS/UCS/relative points, entity and structure picks, selection, property edits, semantic UI actions, undo/redo, protected save, event polling, and current-window PNG capture. The status bar includes a control switch whose green, yellow, and red states mean ready, busy, and off.
|
||||
- `ocs_sessions` finds running editor sessions and opens OpenCADStudio when none exists.
|
||||
- `ocs_read` reads document state, commands, entities, layers, properties, measurements, history, events, and operation status.
|
||||
- `ocs_execute` performs semantic commands and input against the real editor.
|
||||
- `ocs_capture` returns a PNG of the current window for visual verification.
|
||||
|
||||
The Web build exposes `ocs_control_submit(json)` and `ocs_control_take(ticket)`. They enter the same bounded GUI queue and return the same semantic responses; browser code polls the ticket until a response is present.
|
||||
Mutations carry a session ID, document ID, expected revision, selection, and idempotent request ID. Commands report `waiting_input` while more input is required and asynchronous work remains `running` until its real callback finishes. Geometry stays in OpenCADStudio and its geometry kernel.
|
||||
|
||||
`OpenCADStudio --mcp` is the common local entry point for every MCP client. It is built into the application, uses stdio, launches the editor when needed, and has no Python or package-manager dependency. Tool definitions and safety instructions are served by MCP itself, so the drawing behavior is identical in every client.
|
||||
Release builds also produce one standard MCP Bundle containing the native binaries for supported desktop platforms. The release workflow publishes its `server.json` metadata to the official MCP Registry. Compatible AI hosts can therefore discover and install the same server without an OpenCADStudio-specific adapter.
|
||||
|
||||
Run `./docs/automation/install.sh` once for a source build. It installs the release binary in `~/.local/share/ocs-control` and automatically connects installed Codex and Claude Code CLIs. Both registrations point to the same binary. Re-run an individual connection later with:
|
||||
Registry discovery and permission prompts belong to the AI host. Hosts that implement MCP Registry and MCP Bundle support need no OpenCADStudio-specific setup; other hosts cannot be enabled silently by the application.
|
||||
|
||||
The source-tree protocol smoke test uses only the Python standard library:
|
||||
|
||||
```sh
|
||||
~/.local/share/ocs-control/connect.sh codex
|
||||
~/.local/share/ocs-control/connect.sh claude-code
|
||||
```
|
||||
|
||||
Any other local MCP client uses the same command and argument. `connect.sh config` prints the portable configuration object to paste into clients that do not provide a registration CLI:
|
||||
|
||||
```json
|
||||
{"mcpServers":{"opencadstudio":{"command":"/path/to/OpenCADStudio","args":["--mcp"]}}}
|
||||
```
|
||||
|
||||
Client-specific skills and extension manifests may improve discovery, but contain no drawing or protocol implementation. Adding another AI client therefore requires only registering this command; the OpenCADStudio executable and tools do not change.
|
||||
|
||||
The legacy client is unchanged:
|
||||
|
||||
```python
|
||||
from ocs import Ocs
|
||||
with Ocs(binary="OpenCADStudio") as app:
|
||||
app.new()
|
||||
app.run("LINE 0,0 100,0")
|
||||
```
|
||||
|
||||
For direct live diagnostics:
|
||||
|
||||
```sh
|
||||
python3 docs/automation/live.py --launch
|
||||
python3 docs/automation/live.py '{"op":"state"}'
|
||||
cargo build
|
||||
python3 docs/automation/mcp_smoke.py target/debug/OpenCADStudio
|
||||
```
|
||||
@@ -1,65 +0,0 @@
|
||||
#!/bin/sh
|
||||
set -eu
|
||||
|
||||
ROOT=$(CDPATH= cd -- "$(dirname -- "$0")" && pwd)
|
||||
SERVER=${OCS_MCP_COMMAND:-"$ROOT/OpenCADStudio"}
|
||||
NAME=opencadstudio
|
||||
|
||||
require_server() {
|
||||
[ -x "$SERVER" ] || {
|
||||
printf 'OpenCADStudio MCP executable not found: %s\n' "$SERVER" >&2
|
||||
exit 1
|
||||
}
|
||||
}
|
||||
|
||||
connect_codex() {
|
||||
SKILLS=${CODEX_HOME:-"$HOME/.codex"}/skills
|
||||
SOURCE="$ROOT/integrations/codex/opencadstudio-control"
|
||||
if [ -f "$SOURCE/SKILL.md" ]; then
|
||||
mkdir -p "$SKILLS/opencadstudio-control/agents"
|
||||
cp "$SOURCE/SKILL.md" "$SKILLS/opencadstudio-control/SKILL.md"
|
||||
cp "$SOURCE/agents/openai.yaml" "$SKILLS/opencadstudio-control/agents/openai.yaml"
|
||||
fi
|
||||
codex mcp remove "$NAME" >/dev/null 2>&1 || true
|
||||
codex mcp add "$NAME" -- "$SERVER" --mcp
|
||||
printf 'Connected Codex to OpenCADStudio.\n'
|
||||
}
|
||||
|
||||
connect_claude_code() {
|
||||
claude mcp remove "$NAME" >/dev/null 2>&1 || true
|
||||
claude mcp add --transport stdio --scope user "$NAME" -- "$SERVER" --mcp
|
||||
printf 'Connected Claude Code to OpenCADStudio.\n'
|
||||
}
|
||||
|
||||
print_config() {
|
||||
ESCAPED=$(printf '%s' "$SERVER" | sed 's/\\/\\\\/g; s/"/\\"/g')
|
||||
printf '{"mcpServers":{"%s":{"command":"%s","args":["--mcp"]}}}\n' "$NAME" "$ESCAPED"
|
||||
}
|
||||
|
||||
require_server
|
||||
case ${1:-all} in
|
||||
all)
|
||||
FOUND=false
|
||||
if command -v codex >/dev/null 2>&1; then connect_codex; FOUND=true; fi
|
||||
if command -v claude >/dev/null 2>&1; then connect_claude_code; FOUND=true; fi
|
||||
if [ "$FOUND" = false ]; then
|
||||
printf 'No supported AI CLI was found. Use this configuration in any MCP client:\n'
|
||||
print_config
|
||||
fi
|
||||
;;
|
||||
codex)
|
||||
command -v codex >/dev/null 2>&1 || { printf 'Codex CLI is not installed.\n' >&2; exit 1; }
|
||||
connect_codex
|
||||
;;
|
||||
claude-code|claude)
|
||||
command -v claude >/dev/null 2>&1 || { printf 'Claude Code is not installed.\n' >&2; exit 1; }
|
||||
connect_claude_code
|
||||
;;
|
||||
config)
|
||||
print_config
|
||||
;;
|
||||
*)
|
||||
printf 'Usage: %s [all|codex|claude-code|config]\n' "$0" >&2
|
||||
exit 2
|
||||
;;
|
||||
esac
|
||||
@@ -1,19 +0,0 @@
|
||||
#!/bin/sh
|
||||
set -eu
|
||||
ROOT=$(CDPATH= cd -- "$(dirname -- "$0")/../.." && pwd)
|
||||
DEST=${XDG_DATA_HOME:-"$HOME/.local/share"}/ocs-control
|
||||
mkdir -p "$DEST"
|
||||
cargo build --manifest-path "$ROOT/Cargo.toml" --release
|
||||
cp "$ROOT/target/release/OpenCADStudio" "$DEST/OpenCADStudio.new"
|
||||
chmod 755 "$DEST/OpenCADStudio.new"
|
||||
mv -f "$DEST/OpenCADStudio.new" "$DEST/OpenCADStudio"
|
||||
cp "$ROOT/docs/automation/live.py" "$DEST/live.py"
|
||||
cp "$ROOT/docs/automation/connect.sh" "$DEST/connect.sh"
|
||||
chmod 755 "$DEST/connect.sh"
|
||||
mkdir -p "$DEST/integrations/codex/opencadstudio-control/agents"
|
||||
cp "$ROOT/integrations/codex/opencadstudio-control/SKILL.md" "$DEST/integrations/codex/opencadstudio-control/SKILL.md"
|
||||
cp "$ROOT/integrations/codex/opencadstudio-control/agents/openai.yaml" "$DEST/integrations/codex/opencadstudio-control/agents/openai.yaml"
|
||||
rm -f "$DEST/mcp_server.py"
|
||||
rm -rf "$DEST/venv"
|
||||
"$DEST/connect.sh" all
|
||||
printf 'Installed the client-neutral OpenCADStudio MCP runtime.\n'
|
||||
@@ -1,130 +0,0 @@
|
||||
"""Persistent local GUI client; no CAD implementation lives in this adapter."""
|
||||
from __future__ import annotations
|
||||
import json
|
||||
import os
|
||||
from pathlib import Path
|
||||
import socket
|
||||
import subprocess
|
||||
import sys
|
||||
import time
|
||||
import uuid
|
||||
from typing import Any
|
||||
|
||||
READ_OPS = {"state", "hello", "query", "entities", "layers", "header", "properties", "measure", "history", "commands", "events", "operation"}
|
||||
|
||||
|
||||
def discovery_dir() -> Path:
|
||||
if sys.platform == "win32":
|
||||
base = Path(os.environ["APPDATA"])
|
||||
elif sys.platform == "darwin":
|
||||
base = Path.home() / "Library/Application Support"
|
||||
else:
|
||||
base = Path(os.environ.get("XDG_CONFIG_HOME", Path.home() / ".config"))
|
||||
return base / "OpenCADStudio/automation"
|
||||
|
||||
|
||||
def exchange(descriptor: dict, request: dict, timeout: float = 15) -> dict:
|
||||
payload = {**request, "token": descriptor["token"], "session_id": descriptor["session_id"], "protocol": 1}
|
||||
wire = (json.dumps(payload, ensure_ascii=False) + "\n").encode()
|
||||
if len(wire) > 1_048_576:
|
||||
raise ValueError("Request exceeds 1 MiB")
|
||||
with socket.create_connection(("127.0.0.1", descriptor["port"]), timeout=timeout) as sock:
|
||||
sock.sendall(wire)
|
||||
with sock.makefile("rb") as stream:
|
||||
line = stream.readline(16 * 1024 * 1024 + 1)
|
||||
if not line or len(line) > 16 * 1024 * 1024:
|
||||
raise ConnectionError("No valid OCS response; query request_id before retrying a mutation")
|
||||
return json.loads(line)
|
||||
|
||||
|
||||
def sessions() -> list[dict]:
|
||||
found = []
|
||||
for path in sorted(discovery_dir().glob("*.json")):
|
||||
descriptor = None
|
||||
try:
|
||||
if os.name == "posix" and (path.stat().st_uid != os.getuid() or path.stat().st_mode & 0o077):
|
||||
continue
|
||||
descriptor = json.loads(path.read_text())
|
||||
state = exchange(descriptor, {"op": "hello"}, timeout=1)
|
||||
if state.get("ok") and state.get("session_id") == descriptor["session_id"]:
|
||||
found.append({"descriptor": descriptor, "state": state})
|
||||
except (OSError, ValueError, KeyError):
|
||||
# A crashed process cannot remove its descriptor. Only reap a file
|
||||
# whose recorded PID is certainly gone; a busy live session keeps
|
||||
# its discovery record for the next call.
|
||||
try:
|
||||
os.kill(int(descriptor["pid"]), 0)
|
||||
except (ProcessLookupError, TypeError, KeyError):
|
||||
try:
|
||||
path.unlink()
|
||||
except OSError:
|
||||
pass
|
||||
continue
|
||||
return found
|
||||
|
||||
|
||||
class LiveOcs:
|
||||
def __init__(self, session_id: str | None = None):
|
||||
available = sessions()
|
||||
if session_id:
|
||||
available = [s for s in available if s["state"]["session_id"] == session_id]
|
||||
if len(available) != 1:
|
||||
raise ValueError("Choose session_id from sessions; found " + str(len(available)))
|
||||
self.descriptor = available[0]["descriptor"]
|
||||
self.state = available[0]["state"]
|
||||
self.client_id = uuid.uuid4().hex
|
||||
|
||||
def request(self, request: dict, wait_seconds: float = 30) -> dict:
|
||||
req = dict(request)
|
||||
if req.get("op") not in READ_OPS:
|
||||
req.setdefault("request_id", uuid.uuid4().hex)
|
||||
req.setdefault("client_id", self.client_id)
|
||||
req.setdefault("document_id", self.state["document_id"])
|
||||
req.setdefault("revision", self.state["revision"])
|
||||
if req.get("op") in {"input", "property", "run", "action", "save", "undo", "redo"}:
|
||||
req.setdefault("selection", self.state.get("selection", []))
|
||||
response = exchange(self.descriptor, req)
|
||||
deadline = time.monotonic() + min(max(wait_seconds, 0), 60)
|
||||
while response.get("status") in ("accepted", "running") and time.monotonic() < deadline:
|
||||
time.sleep(0.05)
|
||||
response = exchange(self.descriptor, {"op": "operation", "request_id": req["request_id"]})
|
||||
if "state" in response:
|
||||
self.state = response["state"]
|
||||
elif req.get("op") in ("hello", "state") and response.get("ok"):
|
||||
self.state = response
|
||||
return response
|
||||
|
||||
|
||||
def launch(binary: str | None = None) -> list[dict]:
|
||||
existing = sessions()
|
||||
if existing:
|
||||
return existing
|
||||
executable = binary or os.environ.get("OCS_BINARY", str(Path.home() / ".local/share/ocs-control/OpenCADStudio"))
|
||||
log_dir = Path.home() / ".local/share/ocs-control"
|
||||
log_dir.mkdir(parents=True, exist_ok=True)
|
||||
with (log_dir / "gui.log").open("ab") as log:
|
||||
proc = subprocess.Popen([executable, "--new-instance"], stdin=subprocess.DEVNULL, stdout=log, stderr=log, start_new_session=True)
|
||||
deadline = time.monotonic() + 30
|
||||
while time.monotonic() < deadline:
|
||||
if proc.poll() is not None:
|
||||
raise RuntimeError(f"OCS exited ({proc.returncode}); inspect {log_dir / 'gui.log'}")
|
||||
available = sessions()
|
||||
if available:
|
||||
return available
|
||||
time.sleep(0.2)
|
||||
raise TimeoutError("OCS is still starting; call sessions again")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
import argparse
|
||||
parser = argparse.ArgumentParser()
|
||||
parser.add_argument("request", nargs="?", help="JSON request; omit to list sessions")
|
||||
parser.add_argument("--session")
|
||||
parser.add_argument("--launch", action="store_true")
|
||||
args = parser.parse_args()
|
||||
if args.launch:
|
||||
launch()
|
||||
if args.request:
|
||||
print(json.dumps(LiveOcs(args.session).request(json.loads(args.request)), ensure_ascii=False))
|
||||
else:
|
||||
print(json.dumps([s["state"] for s in sessions()], ensure_ascii=False))
|
||||
@@ -1,153 +0,0 @@
|
||||
"""Thin Python client for the Open CAD Studio headless automation server.
|
||||
|
||||
Launches `OpenCADStudio --serve` and talks to it over a line-based JSON protocol
|
||||
(one request object per line on stdin, one response per line on stdout). There
|
||||
is nothing to compile or maintain on the Python side — every method is one JSON
|
||||
message; the real work is Open CAD Studio's own command system.
|
||||
|
||||
from ocs import Ocs
|
||||
|
||||
with Ocs(binary="OpenCADStudio") as ocs:
|
||||
ocs.open("plan.dwg")
|
||||
ocs.run("LAYER Walls")
|
||||
print(ocs.entities()) # {"total": 42, "by_type": {...}}
|
||||
ocs.save("plan_out.dwg")
|
||||
|
||||
Each call returns the parsed response dict and raises `OcsError` on `ok: false`.
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import json
|
||||
import socket
|
||||
import subprocess
|
||||
from typing import Any, Optional
|
||||
|
||||
|
||||
class OcsError(RuntimeError):
|
||||
"""Raised when the server replies with `{"ok": false, ...}`."""
|
||||
|
||||
|
||||
class Ocs:
|
||||
"""Connect by spawning the server (default) or over a TCP socket.
|
||||
|
||||
- `Ocs()` spawns `OpenCADStudio --serve` and talks over stdin/stdout.
|
||||
- `Ocs(port=4242)` connects to a server started with `--serve --port 4242`.
|
||||
"""
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
binary: str = "OpenCADStudio",
|
||||
port: Optional[int] = None,
|
||||
host: str = "127.0.0.1",
|
||||
) -> None:
|
||||
self.proc: Optional[subprocess.Popen] = None
|
||||
self.sock: Optional[socket.socket] = None
|
||||
if port is not None:
|
||||
self.sock = socket.create_connection((host, port))
|
||||
io = self.sock.makefile("rw")
|
||||
self._r, self._w = io, io
|
||||
else:
|
||||
self.proc = subprocess.Popen(
|
||||
[binary, "--serve"],
|
||||
stdin=subprocess.PIPE,
|
||||
stdout=subprocess.PIPE,
|
||||
text=True,
|
||||
bufsize=1,
|
||||
)
|
||||
self._r, self._w = self.proc.stdout, self.proc.stdin
|
||||
self._read() # the {"ready": true} greeting
|
||||
|
||||
# ── protocol ────────────────────────────────────────────────────────────
|
||||
def _read(self) -> dict[str, Any]:
|
||||
line = self._r.readline()
|
||||
if not line:
|
||||
raise OcsError("server closed the connection")
|
||||
return json.loads(line)
|
||||
|
||||
def _send(self, **req: Any) -> dict[str, Any]:
|
||||
self._w.write(json.dumps(req) + "\n")
|
||||
self._w.flush()
|
||||
resp = self._read()
|
||||
if not resp.get("ok", False):
|
||||
raise OcsError(resp.get("error", "unknown error"))
|
||||
return resp
|
||||
|
||||
# ── operations ──────────────────────────────────────────────────────────
|
||||
def new(self) -> dict[str, Any]:
|
||||
"""Start an empty document."""
|
||||
return self._send(op="new")
|
||||
|
||||
def open(self, path: str) -> dict[str, Any]:
|
||||
"""Load a DWG/DXF drawing."""
|
||||
return self._send(op="open", path=path)
|
||||
|
||||
def run(self, cmd: str) -> dict[str, Any]:
|
||||
"""Run a command through Open CAD Studio's command system."""
|
||||
return self._send(op="run", cmd=cmd)
|
||||
|
||||
def entities(self) -> dict[str, Any]:
|
||||
"""Total entity count and a breakdown by type."""
|
||||
return self._send(op="entities")
|
||||
|
||||
def query(
|
||||
self,
|
||||
type: Optional[str] = None,
|
||||
layer: Optional[str] = None,
|
||||
limit: Optional[int] = None,
|
||||
) -> dict[str, Any]:
|
||||
"""List entities (handle, type, layer, geometry), optionally filtered."""
|
||||
return self._send(op="query", type=type, layer=layer, limit=limit)
|
||||
|
||||
def layers(self) -> dict[str, Any]:
|
||||
"""List layers (name, color, on/off, frozen, locked) and the current one."""
|
||||
return self._send(op="layers")
|
||||
|
||||
def header(self) -> dict[str, Any]:
|
||||
"""Read drawing header variables (units, PDMODE/PDSIZE, LTSCALE, …)."""
|
||||
return self._send(op="header")
|
||||
|
||||
def select(
|
||||
self,
|
||||
handles: Optional[list[str]] = None,
|
||||
type: Optional[str] = None,
|
||||
layer: Optional[str] = None,
|
||||
clear: bool = False,
|
||||
) -> dict[str, Any]:
|
||||
"""Set the selection by handle, type, or layer (a following selection
|
||||
command like ``run("ERASE")`` then acts on it). `clear=True` deselects."""
|
||||
return self._send(
|
||||
op="select", handles=handles, type=type, layer=layer, clear=clear
|
||||
)
|
||||
|
||||
def undo(self) -> dict[str, Any]:
|
||||
"""Undo the last change."""
|
||||
return self._send(op="undo")
|
||||
|
||||
def redo(self) -> dict[str, Any]:
|
||||
"""Redo the last undone change."""
|
||||
return self._send(op="redo")
|
||||
|
||||
def save(self, path: Optional[str] = None) -> dict[str, Any]:
|
||||
"""Write the document (defaults to the opened/last-saved path)."""
|
||||
return self._send(op="save", path=path)
|
||||
|
||||
# ── lifecycle ───────────────────────────────────────────────────────────
|
||||
def close(self) -> None:
|
||||
try:
|
||||
self._w.close()
|
||||
except Exception:
|
||||
pass
|
||||
if self.proc is not None:
|
||||
try:
|
||||
self.proc.wait(timeout=5)
|
||||
except subprocess.TimeoutExpired:
|
||||
self.proc.kill()
|
||||
if self.sock is not None:
|
||||
self.sock.close()
|
||||
|
||||
def __enter__(self) -> "Ocs":
|
||||
return self
|
||||
|
||||
def __exit__(self, *_exc: object) -> None:
|
||||
self.close()
|
||||
@@ -149,9 +149,10 @@ trunk serve
|
||||
OpenCADStudio --export input.dwg output.dxf
|
||||
OpenCADStudio --serve
|
||||
OpenCADStudio --serve --port 4242
|
||||
OpenCADStudio --mcp
|
||||
```
|
||||
|
||||
يتبادل الخادم كائن JSON واحداً في كل سطر عبر الإدخال/الإخراج القياسي أو مقبس TCP محلي. راجع [دليل الأتمتة](../automation/README.md) و[عميل Python](../automation/ocs.py) المرفق.
|
||||
يتبادل الخادم كائن JSON واحداً في كل سطر عبر الإدخال/الإخراج القياسي أو مقبس TCP محلي. راجع [دليل الأتمتة](../automation/README.md).
|
||||
|
||||
## الإضافات
|
||||
|
||||
|
||||
@@ -151,9 +151,10 @@ trunk serve
|
||||
OpenCADStudio --export input.dwg output.dxf
|
||||
OpenCADStudio --serve
|
||||
OpenCADStudio --serve --port 4242
|
||||
OpenCADStudio --mcp
|
||||
```
|
||||
|
||||
Сървърът обменя по един JSON обект на ред чрез стандартния вход/изход или локален TCP сокет. Вижте [ръководството за автоматизация](../automation/README.md) и включения [Python клиент](../automation/ocs.py).
|
||||
Сървърът обменя по един JSON обект на ред чрез стандартния вход/изход или локален TCP сокет. Вижте [ръководството за автоматизация](../automation/README.md).
|
||||
|
||||
## Приставки
|
||||
|
||||
|
||||
@@ -149,9 +149,10 @@ Desktopový program podporuje jednorázovou konverzi a trvalý bezobslužný ser
|
||||
OpenCADStudio --export input.dwg output.dxf
|
||||
OpenCADStudio --serve
|
||||
OpenCADStudio --serve --port 4242
|
||||
OpenCADStudio --mcp
|
||||
```
|
||||
|
||||
Server předává jeden objekt JSON na řádek přes standardní vstup/výstup nebo místní TCP socket. Viz [průvodce automatizací](../automation/README.md) a přiložený [klient Python](../automation/ocs.py).
|
||||
Server předává jeden objekt JSON na řádek přes standardní vstup/výstup nebo místní TCP socket. Viz [průvodce automatizací](../automation/README.md).
|
||||
|
||||
## Pluginy
|
||||
|
||||
|
||||
@@ -149,9 +149,10 @@ Die Desktop-Binärdatei unterstützt einmalige Konvertierung und einen dauerhaft
|
||||
OpenCADStudio --export input.dwg output.dxf
|
||||
OpenCADStudio --serve
|
||||
OpenCADStudio --serve --port 4242
|
||||
OpenCADStudio --mcp
|
||||
```
|
||||
|
||||
Der Server tauscht über Standardein-/ausgabe oder einen lokalen TCP-Socket je Zeile ein JSON-Objekt aus. Siehe [Automatisierungsanleitung](../automation/README.md) und den enthaltenen [Python-Client](../automation/ocs.py).
|
||||
Der Server tauscht über Standardein-/ausgabe oder einen lokalen TCP-Socket je Zeile ein JSON-Objekt aus. Siehe [Automatisierungsanleitung](../automation/README.md).
|
||||
|
||||
## Plugins
|
||||
|
||||
|
||||
@@ -149,9 +149,10 @@ El binario de escritorio admite conversión puntual y un servidor persistente si
|
||||
OpenCADStudio --export input.dwg output.dxf
|
||||
OpenCADStudio --serve
|
||||
OpenCADStudio --serve --port 4242
|
||||
OpenCADStudio --mcp
|
||||
```
|
||||
|
||||
El servidor intercambia un objeto JSON por línea mediante entrada/salida estándar o un socket TCP local. Consulta la [guía de automatización](../automation/README.md) y el [cliente Python](../automation/ocs.py) incluido.
|
||||
El servidor intercambia un objeto JSON por línea mediante entrada/salida estándar o un socket TCP local. Consulta la [guía de automatización](../automation/README.md).
|
||||
|
||||
## Complementos
|
||||
|
||||
|
||||
@@ -149,9 +149,10 @@ Työpöytäohjelma tukee kertaluonteista muunnosta ja pysyvää käyttöliittym
|
||||
OpenCADStudio --export input.dwg output.dxf
|
||||
OpenCADStudio --serve
|
||||
OpenCADStudio --serve --port 4242
|
||||
OpenCADStudio --mcp
|
||||
```
|
||||
|
||||
Palvelin vaihtaa yhden JSON-objektin riviä kohti vakiotulon/-lähdön tai paikallisen TCP-pistokkeen kautta. Katso [automaatio-opas](../automation/README.md) ja mukana toimitettu [Python-asiakas](../automation/ocs.py).
|
||||
Palvelin vaihtaa yhden JSON-objektin riviä kohti vakiotulon/-lähdön tai paikallisen TCP-pistokkeen kautta. Katso [automaatio-opas](../automation/README.md).
|
||||
|
||||
## Liitännäiset
|
||||
|
||||
|
||||
@@ -149,9 +149,10 @@ Le binaire de bureau prend en charge la conversion ponctuelle et un serveur pers
|
||||
OpenCADStudio --export input.dwg output.dxf
|
||||
OpenCADStudio --serve
|
||||
OpenCADStudio --serve --port 4242
|
||||
OpenCADStudio --mcp
|
||||
```
|
||||
|
||||
Le serveur échange un objet JSON par ligne via l’entrée/sortie standard ou un socket TCP local. Consultez le [guide d’automatisation](../automation/README.md) et le [client Python](../automation/ocs.py) fourni.
|
||||
Le serveur échange un objet JSON par ligne via l’entrée/sortie standard ou un socket TCP local. Consultez le [guide d’automatisation](../automation/README.md).
|
||||
|
||||
## Plugins
|
||||
|
||||
|
||||
@@ -149,9 +149,10 @@ trunk serve
|
||||
OpenCADStudio --export input.dwg output.dxf
|
||||
OpenCADStudio --serve
|
||||
OpenCADStudio --serve --port 4242
|
||||
OpenCADStudio --mcp
|
||||
```
|
||||
|
||||
सर्वर मानक इनपुट/आउटपुट या स्थानीय TCP सॉकेट के माध्यम से प्रति पंक्ति एक JSON ऑब्जेक्ट का आदान-प्रदान करता है। [स्वचालन मार्गदर्शिका](../automation/README.md) और शामिल [Python क्लाइंट](../automation/ocs.py) देखें।
|
||||
सर्वर मानक इनपुट/आउटपुट या स्थानीय TCP सॉकेट के माध्यम से प्रति पंक्ति एक JSON ऑब्जेक्ट का आदान-प्रदान करता है। [स्वचालन मार्गदर्शिका](../automation/README.md) देखें।
|
||||
|
||||
## प्लगइन
|
||||
|
||||
|
||||
@@ -149,9 +149,10 @@ Az asztali bináris egyszeri konverziót és tartós, felület nélküli kiszolg
|
||||
OpenCADStudio --export input.dwg output.dxf
|
||||
OpenCADStudio --serve
|
||||
OpenCADStudio --serve --port 4242
|
||||
OpenCADStudio --mcp
|
||||
```
|
||||
|
||||
A kiszolgáló soronként egy JSON-objektumot cserél a szabványos bemeneten/kimeneten vagy helyi TCP-foglalaton. Lásd az [automatizálási útmutatót](../automation/README.md) és a mellékelt [Python-klienst](../automation/ocs.py).
|
||||
A kiszolgáló soronként egy JSON-objektumot cserél a szabványos bemeneten/kimeneten vagy helyi TCP-foglalaton. Lásd az [automatizálási útmutatót](../automation/README.md).
|
||||
|
||||
## Bővítmények
|
||||
|
||||
|
||||
@@ -149,9 +149,10 @@ Il binario desktop supporta conversioni singole e un server headless persistente
|
||||
OpenCADStudio --export input.dwg output.dxf
|
||||
OpenCADStudio --serve
|
||||
OpenCADStudio --serve --port 4242
|
||||
OpenCADStudio --mcp
|
||||
```
|
||||
|
||||
Il server scambia un oggetto JSON per riga tramite ingresso/uscita standard o un socket TCP locale. Consulta la [guida all’automazione](../automation/README.md) e il [client Python](../automation/ocs.py) incluso.
|
||||
Il server scambia un oggetto JSON per riga tramite ingresso/uscita standard o un socket TCP locale. Consulta la [guida all’automazione](../automation/README.md).
|
||||
|
||||
## Plugin
|
||||
|
||||
|
||||
@@ -149,9 +149,10 @@ trunk serve
|
||||
OpenCADStudio --export input.dwg output.dxf
|
||||
OpenCADStudio --serve
|
||||
OpenCADStudio --serve --port 4242
|
||||
OpenCADStudio --mcp
|
||||
```
|
||||
|
||||
サーバーは標準入出力またはローカル TCP ソケットを通じ、1 行につき 1 個の JSON オブジェクトを交換します。[自動化ガイド](../automation/README.md) と付属の [Python クライアント](../automation/ocs.py) を参照してください。
|
||||
サーバーは標準入出力またはローカル TCP ソケットを通じ、1 行につき 1 個の JSON オブジェクトを交換します。[自動化ガイド](../automation/README.md) を参照してください。
|
||||
|
||||
## プラグイン
|
||||
|
||||
|
||||
@@ -149,9 +149,10 @@ trunk serve
|
||||
OpenCADStudio --export input.dwg output.dxf
|
||||
OpenCADStudio --serve
|
||||
OpenCADStudio --serve --port 4242
|
||||
OpenCADStudio --mcp
|
||||
```
|
||||
|
||||
서버는 표준 입출력 또는 로컬 TCP 소켓을 통해 한 줄에 하나의 JSON 객체를 교환합니다. [자동화 안내서](../automation/README.md)와 포함된 [Python 클라이언트](../automation/ocs.py)를 참고하세요.
|
||||
서버는 표준 입출력 또는 로컬 TCP 소켓을 통해 한 줄에 하나의 JSON 객체를 교환합니다. [자동화 안내서](../automation/README.md)를 참고하세요.
|
||||
|
||||
## 플러그인
|
||||
|
||||
|
||||
@@ -149,9 +149,10 @@ Het desktopprogramma ondersteunt eenmalige conversie en een permanente headless
|
||||
OpenCADStudio --export input.dwg output.dxf
|
||||
OpenCADStudio --serve
|
||||
OpenCADStudio --serve --port 4242
|
||||
OpenCADStudio --mcp
|
||||
```
|
||||
|
||||
De server wisselt per regel één JSON-object uit via standaardinvoer/-uitvoer of een lokale TCP-socket. Bekijk de [automatiseringshandleiding](../automation/README.md) en de meegeleverde [Python-client](../automation/ocs.py).
|
||||
De server wisselt per regel één JSON-object uit via standaardinvoer/-uitvoer of een lokale TCP-socket. Bekijk de [automatiseringshandleiding](../automation/README.md).
|
||||
|
||||
## Plug-ins
|
||||
|
||||
|
||||
@@ -149,9 +149,10 @@ Program komputerowy obsługuje jednorazową konwersję i trwały serwer bez inte
|
||||
OpenCADStudio --export input.dwg output.dxf
|
||||
OpenCADStudio --serve
|
||||
OpenCADStudio --serve --port 4242
|
||||
OpenCADStudio --mcp
|
||||
```
|
||||
|
||||
Serwer wymienia jeden obiekt JSON na wiersz przez standardowe wejście/wyjście lub lokalne gniazdo TCP. Zobacz [przewodnik automatyzacji](../automation/README.md) i dołączonego [klienta Python](../automation/ocs.py).
|
||||
Serwer wymienia jeden obiekt JSON na wiersz przez standardowe wejście/wyjście lub lokalne gniazdo TCP. Zobacz [przewodnik automatyzacji](../automation/README.md).
|
||||
|
||||
## Wtyczki
|
||||
|
||||
|
||||
@@ -149,9 +149,10 @@ O binário desktop oferece conversão única e um servidor persistente sem inter
|
||||
OpenCADStudio --export input.dwg output.dxf
|
||||
OpenCADStudio --serve
|
||||
OpenCADStudio --serve --port 4242
|
||||
OpenCADStudio --mcp
|
||||
```
|
||||
|
||||
O servidor troca um objeto JSON por linha pela entrada/saída padrão ou por um socket TCP local. Consulte o [guia de automação](../automation/README.md) e o [cliente Python](../automation/ocs.py) incluído.
|
||||
O servidor troca um objeto JSON por linha pela entrada/saída padrão ou por um socket TCP local. Consulte o [guia de automação](../automation/README.md).
|
||||
|
||||
## Plugins
|
||||
|
||||
|
||||
@@ -149,9 +149,10 @@ trunk serve
|
||||
OpenCADStudio --export input.dwg output.dxf
|
||||
OpenCADStudio --serve
|
||||
OpenCADStudio --serve --port 4242
|
||||
OpenCADStudio --mcp
|
||||
```
|
||||
|
||||
Сервер обменивается одним объектом JSON в строке через стандартный ввод/вывод или локальный TCP-сокет. См. [руководство по автоматизации](../automation/README.md) и включённый [клиент Python](../automation/ocs.py).
|
||||
Сервер обменивается одним объектом JSON в строке через стандартный ввод/вывод или локальный TCP-сокет. См. [руководство по автоматизации](../automation/README.md).
|
||||
|
||||
## Плагины
|
||||
|
||||
|
||||
@@ -151,9 +151,10 @@ Masaüstü ikili dosyası tek seferlik dönüştürmeyi ve kalıcı arayüzsüz
|
||||
OpenCADStudio --export input.dwg output.dxf
|
||||
OpenCADStudio --serve
|
||||
OpenCADStudio --serve --port 4242
|
||||
OpenCADStudio --mcp
|
||||
```
|
||||
|
||||
Sunucu standart giriş/çıkış veya yerel TCP soketi üzerinden satır başına bir JSON nesnesi alışverişi yapar. [Otomasyon kılavuzuna](../automation/README.md) ve birlikte verilen [Python istemcisine](../automation/ocs.py) bakın.
|
||||
Sunucu standart giriş/çıkış veya yerel TCP soketi üzerinden satır başına bir JSON nesnesi alışverişi yapar. [Otomasyon kılavuzuna](../automation/README.md) bakın.
|
||||
|
||||
## Eklentiler
|
||||
|
||||
|
||||
@@ -149,9 +149,10 @@ trunk serve
|
||||
OpenCADStudio --export input.dwg output.dxf
|
||||
OpenCADStudio --serve
|
||||
OpenCADStudio --serve --port 4242
|
||||
OpenCADStudio --mcp
|
||||
```
|
||||
|
||||
服务器通过标准输入/输出或本地 TCP 套接字逐行交换 JSON 对象。请参阅[自动化指南](../automation/README.md)和随附的 [Python 客户端](../automation/ocs.py)。
|
||||
服务器通过标准输入/输出或本地 TCP 套接字逐行交换 JSON 对象。请参阅[自动化指南](../automation/README.md)。
|
||||
|
||||
## 插件
|
||||
|
||||
|
||||
@@ -149,9 +149,10 @@ trunk serve
|
||||
OpenCADStudio --export input.dwg output.dxf
|
||||
OpenCADStudio --serve
|
||||
OpenCADStudio --serve --port 4242
|
||||
OpenCADStudio --mcp
|
||||
```
|
||||
|
||||
伺服器透過標準輸入/輸出或本機 TCP 通訊端逐行交換 JSON 物件。請參閱[自動化指南](../automation/README.md)和隨附的 [Python 用戶端](../automation/ocs.py)。
|
||||
伺服器透過標準輸入/輸出或本機 TCP 通訊端逐行交換 JSON 物件。請參閱[自動化指南](../automation/README.md)。
|
||||
|
||||
## 外掛程式
|
||||
|
||||
|
||||
Reference in new issue
Block a user