Compare commits
2
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
1e0f2f9aea | ||
|
|
b560950f82 |
@@ -26,9 +26,42 @@ from resim_context import resimleri_sadelestir
|
||||
import ide_catalog
|
||||
import ozet_kopru
|
||||
|
||||
SURUM = "1"
|
||||
SURUM = "3"
|
||||
HERE = os.path.dirname(os.path.abspath(__file__))
|
||||
|
||||
# Codex sends request bodies zstd-compressed. Python gained zstd in 3.14; for older
|
||||
# interpreters the matching `zstandard` build ships next to this file.
|
||||
_VENDOR = os.path.join(HERE, "vendor", "cp%d%d-win_amd64" % sys.version_info[:2])
|
||||
if os.path.isdir(_VENDOR):
|
||||
sys.path.insert(0, _VENDOR)
|
||||
|
||||
|
||||
def _zstd_decompress(body):
|
||||
try:
|
||||
from compression import zstd as _z
|
||||
return _z.decompress(body)
|
||||
except ImportError:
|
||||
import zstandard
|
||||
return zstandard.ZstdDecompressor().decompressobj().decompress(body)
|
||||
|
||||
|
||||
def _zstd_ready():
|
||||
try:
|
||||
try:
|
||||
from compression import zstd as _z
|
||||
sample = _z.compress(b"aiturk")
|
||||
except ImportError:
|
||||
import zstandard
|
||||
sample = zstandard.ZstdCompressor().compress(b"aiturk")
|
||||
return _zstd_decompress(sample) == b"aiturk"
|
||||
except Exception:
|
||||
return False
|
||||
|
||||
|
||||
# Without zstd every Codex request would fail; the status endpoint then reports
|
||||
# ok=false so that the IDE never points Codex at this bridge.
|
||||
ZSTD_OK = _zstd_ready()
|
||||
|
||||
|
||||
def _arg(name, env):
|
||||
"""--name <value> from the command line, else the environment variable."""
|
||||
@@ -468,10 +501,7 @@ def decompress(body, enc):
|
||||
if enc == "deflate":
|
||||
import zlib; return zlib.decompress(body)
|
||||
if enc == "zstd":
|
||||
try:
|
||||
from compression import zstd as _z; return _z.decompress(body)
|
||||
except ImportError:
|
||||
import zstandard; return zstandard.ZstdDecompressor().decompressobj().decompress(body)
|
||||
return _zstd_decompress(body)
|
||||
if enc == "br":
|
||||
import brotli; return brotli.decompress(body)
|
||||
return body
|
||||
@@ -533,9 +563,18 @@ class H(http.server.BaseHTTPRequestHandler):
|
||||
|
||||
def _control(self, path):
|
||||
"""Local status/stop for AITURK IDE. Loopback only; carries no secrets."""
|
||||
if self.command == "POST" and path.rstrip("/").endswith("/refresh"):
|
||||
# The IDE asks for this after a sign-in or a settings change, so the model
|
||||
# list does not wait for the next periodic refresh.
|
||||
try:
|
||||
load_ide_catalog()
|
||||
except Exception as e:
|
||||
log(f"katalog yenileme hatasi: {e}")
|
||||
path = "/aiturk/codex-baglama/status"
|
||||
self.command = "GET"
|
||||
if self.command == "GET" and path.rstrip("/").endswith("/status"):
|
||||
durum, _, sayi = (IDE_DURUM[0] or "kapali, 0 model").partition(", ")
|
||||
return self._send_json(200, {"ok": True, "surum": SURUM, "ide_durum": durum,
|
||||
return self._send_json(200, {"ok": ZSTD_OK, "surum": SURUM, "zstd": ZSTD_OK, "ide_durum": durum,
|
||||
"ide_model": int((sayi.split() or ["0"])[0]),
|
||||
"ozet": bool((CFG.get("ozet_kopru") or {}).get("enabled", False))})
|
||||
if self.command == "POST" and path.rstrip("/").endswith("/stop"):
|
||||
|
||||
@@ -127,11 +127,22 @@ def sec(data, tanimli, kapsam="ide"):
|
||||
gorunen = ts.get("display_name") or mid
|
||||
kisa = gorunen.split(" · ")[-1].strip()
|
||||
combo = "/" not in kisa # saglayici/model bicimi degil: adlandirilmis combo ya da takma ad
|
||||
# 9Router'dan gelen combolar Codex'te gosterilmez (kullanici karari, 9 Ekim 2026): dogrudan
|
||||
# 9Router kaynagi ve gecidin "9router" saglayicisi uzerinden gelen kopyalari.
|
||||
if combo and (ts.get("source") == "9router" or mid.lower().startswith("9router-")):
|
||||
continue
|
||||
if kapsam != "hepsi" and not combo and kisa.lower() not in tanimli and mid.lower() not in tanimli:
|
||||
continue
|
||||
gorulen.add(mid)
|
||||
secilen.append({"id": mid, "ad": gorunen, "sira": ts.get("order") or 0})
|
||||
secilen.sort(key=lambda s: (s["sira"], s["id"]))
|
||||
# Gecit ayni adin ikinci yoluna "ad (2)" der; birincisi listede yoksa sayac anlamsizdir.
|
||||
adlar = {s["ad"].split(" · ")[-1].strip().lower() for s in secilen}
|
||||
for s in secilen:
|
||||
taban = re.sub(r" \(\d+\)$", "", s["ad"])
|
||||
if taban != s["ad"] and taban.split(" · ")[-1].strip().lower() not in adlar:
|
||||
adlar.add(taban.split(" · ")[-1].strip().lower())
|
||||
s["ad"] = taban
|
||||
return [{"id": s["id"], "ad": s["ad"]} for s in secilen]
|
||||
|
||||
|
||||
|
||||
@@ -2,8 +2,8 @@ import json, os, tempfile, unittest
|
||||
import ide_catalog as c
|
||||
|
||||
|
||||
def girdi(mid, ad, yetenek=("chat",), sira=0):
|
||||
return {"id": mid, "turkservis": {"display_name": ad, "capabilities": list(yetenek), "order": sira}}
|
||||
def girdi(mid, ad, yetenek=("chat",), sira=0, kaynak="omniroute"):
|
||||
return {"id": mid, "turkservis": {"display_name": ad, "capabilities": list(yetenek), "order": sira, "source": kaynak}}
|
||||
|
||||
|
||||
KATALOG = [
|
||||
@@ -53,7 +53,19 @@ class Secim(unittest.TestCase):
|
||||
def test_ide_kapsami(self):
|
||||
s = c.sec(KATALOG, ["cc/claude-opus-5-5"], "ide")
|
||||
# Tanimli model + adlandirilmis combolar; tanimsiz saglayici modeli ve gorsel modeli yok.
|
||||
self.assertEqual([x["id"] for x in s], ["9router-cc-opus", "Ajan-Arac", "9router-Takim-Agir-6e65dba5", "9router-Takim-Agir"])
|
||||
self.assertEqual([x["id"] for x in s], ["9router-cc-opus", "Ajan-Arac"])
|
||||
|
||||
def test_9router_combolari_gosterilmez(self):
|
||||
katalog = [girdi("9router-Takim-Agir-6e65dba5", "Takim-Agir", kaynak="9router", sira=1),
|
||||
girdi("9router-Takim-Agir", "Takim-Agir (2)", sira=2),
|
||||
girdi("Takim-Agir", "Takim-Agir (3)", sira=3),
|
||||
girdi("Ajan-Arac", "Ajan-Arac", sira=4),
|
||||
girdi("9router-nano-x", "nano/x", kaynak="9router", sira=5)]
|
||||
s = c.sec(katalog, ["nano/x"], "ide")
|
||||
# 9Router combosu ve gecidin 9router saglayicisindaki kopyasi yok; OmniRoute'un kendi combosu
|
||||
# sayacsiz adiyla kalir. 9Router'in tekil modeli (combo degil) etkilenmez.
|
||||
self.assertEqual([(x["id"], x["ad"]) for x in s],
|
||||
[("Takim-Agir", "Takim-Agir"), ("Ajan-Arac", "Ajan-Arac"), ("9router-nano-x", "nano/x")])
|
||||
|
||||
def test_gorunen_ad_yalniz_saglayici_ve_model(self):
|
||||
for tam, beklenen in [("OmniRoute · ag/gemini-3.8-flash", "ag/gemini-3.8-flash"),
|
||||
@@ -74,7 +86,7 @@ class Secim(unittest.TestCase):
|
||||
|
||||
def test_hepsi_kapsami_yalniz_sohbet(self):
|
||||
s = c.sec(KATALOG, [], "hepsi")
|
||||
self.assertEqual(len(s), 5)
|
||||
self.assertEqual(len(s), 3) # iki 9Router combosu hicbir kapsamda gosterilmez
|
||||
self.assertNotIn("gorsel", [x["id"] for x in s])
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,35 @@
|
||||
"""Codex compresses request bodies with zstd; the bridge must be able to read them."""
|
||||
import ast
|
||||
import unittest
|
||||
from pathlib import Path
|
||||
|
||||
tree = ast.parse(Path(__file__).with_name("bridge.py").read_text(encoding="utf-8"))
|
||||
wanted = {"_zstd_decompress", "_zstd_ready", "decompress"}
|
||||
env = {}
|
||||
exec(compile(ast.Module(body=[n for n in tree.body if isinstance(n, ast.FunctionDef) and n.name in wanted],
|
||||
type_ignores=[]), "bridge.py", "exec"), env)
|
||||
|
||||
|
||||
class Zstd(unittest.TestCase):
|
||||
def test_self_check_matches_reality(self):
|
||||
try:
|
||||
try:
|
||||
from compression import zstd as z
|
||||
packed = z.compress(b"govde" * 50)
|
||||
except ImportError:
|
||||
import zstandard
|
||||
packed = zstandard.ZstdCompressor().compress(b"govde" * 50)
|
||||
except ImportError:
|
||||
self.assertFalse(env["_zstd_ready"]()) # no zstd here: the bridge must say so
|
||||
return
|
||||
self.assertTrue(env["_zstd_ready"]())
|
||||
self.assertEqual(env["decompress"](packed, "zstd"), b"govde" * 50)
|
||||
|
||||
def test_other_encodings(self):
|
||||
import gzip
|
||||
self.assertEqual(env["decompress"](gzip.compress(b"x"), "gzip"), b"x")
|
||||
self.assertEqual(env["decompress"](b"duz", None), b"duz")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
Vendored
+27
@@ -0,0 +1,27 @@
|
||||
Copyright (c) 2016, Gregory Szorc
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright notice, this
|
||||
list of conditions and the following disclaimer.
|
||||
|
||||
2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation
|
||||
and/or other materials provided with the distribution.
|
||||
|
||||
3. Neither the name of the copyright holder nor the names of its contributors
|
||||
may be used to endorse or promote products derived from this software without
|
||||
specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
|
||||
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
+217
@@ -0,0 +1,217 @@
|
||||
# Copyright (c) 2017-present, Gregory Szorc
|
||||
# All rights reserved.
|
||||
#
|
||||
# This software may be modified and distributed under the terms
|
||||
# of the BSD license. See the LICENSE file for details.
|
||||
|
||||
# ruff: noqa: F403, F405
|
||||
|
||||
"""Python interface to the Zstandard (zstd) compression library."""
|
||||
|
||||
from __future__ import absolute_import, unicode_literals
|
||||
|
||||
# This module serves 2 roles:
|
||||
#
|
||||
# 1) Export the C or CFFI "backend" through a central module.
|
||||
# 2) Implement additional functionality built on top of C or CFFI backend.
|
||||
import builtins
|
||||
import io
|
||||
import os
|
||||
import platform
|
||||
import sys
|
||||
|
||||
if sys.version_info >= (3, 12):
|
||||
from collections.abc import Buffer
|
||||
else:
|
||||
from typing import ByteString as Buffer
|
||||
|
||||
# Some Python implementations don't support C extensions. That's why we have
|
||||
# a CFFI implementation in the first place. The code here import one of our
|
||||
# "backends" then re-exports the symbols from this module. For convenience,
|
||||
# we support falling back to the CFFI backend if the C extension can't be
|
||||
# imported. But for performance reasons, we only do this on unknown Python
|
||||
# implementation. Notably, for CPython we require the C extension by default.
|
||||
# Because someone will inevitably want special behavior, the behavior is
|
||||
# configurable via an environment variable. A potentially better way to handle
|
||||
# this is to import a special ``__importpolicy__`` module or something
|
||||
# defining a variable and `setup.py` could write the file with whatever
|
||||
# policy was specified at build time. Until someone needs it, we go with
|
||||
# the hacky but simple environment variable approach.
|
||||
_module_policy = os.environ.get(
|
||||
"PYTHON_ZSTANDARD_IMPORT_POLICY", "default"
|
||||
).strip()
|
||||
|
||||
if _module_policy == "default":
|
||||
if platform.python_implementation() in ("CPython",):
|
||||
from .backend_c import * # type: ignore
|
||||
|
||||
backend = "cext"
|
||||
elif platform.python_implementation() in ("PyPy",):
|
||||
from .backend_cffi import * # type: ignore
|
||||
|
||||
backend = "cffi"
|
||||
else:
|
||||
try:
|
||||
from .backend_c import *
|
||||
|
||||
backend = "cext"
|
||||
except ImportError:
|
||||
from .backend_cffi import *
|
||||
|
||||
backend = "cffi"
|
||||
elif _module_policy == "cffi_fallback":
|
||||
try:
|
||||
from .backend_c import *
|
||||
|
||||
backend = "cext"
|
||||
except ImportError:
|
||||
from .backend_cffi import *
|
||||
|
||||
backend = "cffi"
|
||||
elif _module_policy == "rust":
|
||||
from .backend_rust import * # type: ignore
|
||||
|
||||
backend = "rust"
|
||||
elif _module_policy == "cext":
|
||||
from .backend_c import *
|
||||
|
||||
backend = "cext"
|
||||
elif _module_policy == "cffi":
|
||||
from .backend_cffi import *
|
||||
|
||||
backend = "cffi"
|
||||
else:
|
||||
raise ImportError(
|
||||
"unknown module import policy: %s; use default, cffi_fallback, "
|
||||
"cext, or cffi" % _module_policy
|
||||
)
|
||||
|
||||
# Keep this in sync with python-zstandard.h, rust-ext/src/lib.rs, and debian/changelog.
|
||||
__version__ = "0.25.0"
|
||||
|
||||
_MODE_CLOSED = 0
|
||||
_MODE_READ = 1
|
||||
_MODE_WRITE = 2
|
||||
|
||||
|
||||
def open(
|
||||
filename,
|
||||
mode="rb",
|
||||
cctx=None,
|
||||
dctx=None,
|
||||
encoding=None,
|
||||
errors=None,
|
||||
newline=None,
|
||||
closefd=None,
|
||||
):
|
||||
"""Create a file object with zstd (de)compression.
|
||||
|
||||
The object returned from this function will be a
|
||||
:py:class:`ZstdDecompressionReader` if opened for reading in binary mode,
|
||||
a :py:class:`ZstdCompressionWriter` if opened for writing in binary mode,
|
||||
or an ``io.TextIOWrapper`` if opened for reading or writing in text mode.
|
||||
|
||||
:param filename:
|
||||
``bytes``, ``str``, or ``os.PathLike`` defining a file to open or a
|
||||
file object (with a ``read()`` or ``write()`` method).
|
||||
:param mode:
|
||||
``str`` File open mode. Accepts any of the open modes recognized by
|
||||
``open()``.
|
||||
:param cctx:
|
||||
``ZstdCompressor`` to use for compression. If not specified and file
|
||||
is opened for writing, the default ``ZstdCompressor`` will be used.
|
||||
:param dctx:
|
||||
``ZstdDecompressor`` to use for decompression. If not specified and file
|
||||
is opened for reading, the default ``ZstdDecompressor`` will be used.
|
||||
:param encoding:
|
||||
``str`` that defines text encoding to use when file is opened in text
|
||||
mode.
|
||||
:param errors:
|
||||
``str`` defining text encoding error handling mode.
|
||||
:param newline:
|
||||
``str`` defining newline to use in text mode.
|
||||
:param closefd:
|
||||
``bool`` whether to close the file when the returned object is closed.
|
||||
Only used if a file object is passed. If a filename is specified, the
|
||||
opened file is always closed when the returned object is closed.
|
||||
"""
|
||||
normalized_mode = mode.replace("t", "")
|
||||
|
||||
if normalized_mode in ("r", "rb"):
|
||||
dctx = dctx or ZstdDecompressor()
|
||||
open_mode = "r"
|
||||
raw_open_mode = "rb"
|
||||
elif normalized_mode in ("w", "wb", "a", "ab", "x", "xb"):
|
||||
cctx = cctx or ZstdCompressor()
|
||||
open_mode = "w"
|
||||
raw_open_mode = normalized_mode
|
||||
if not raw_open_mode.endswith("b"):
|
||||
raw_open_mode = raw_open_mode + "b"
|
||||
else:
|
||||
raise ValueError("Invalid mode: {!r}".format(mode))
|
||||
|
||||
if hasattr(os, "PathLike"):
|
||||
types = (str, bytes, os.PathLike)
|
||||
else:
|
||||
types = (str, bytes)
|
||||
|
||||
if isinstance(filename, types): # type: ignore
|
||||
inner_fh = builtins.open(filename, raw_open_mode)
|
||||
closefd = True
|
||||
elif hasattr(filename, "read") or hasattr(filename, "write"):
|
||||
inner_fh = filename
|
||||
closefd = bool(closefd)
|
||||
else:
|
||||
raise TypeError(
|
||||
"filename must be a str, bytes, file or PathLike object"
|
||||
)
|
||||
|
||||
if open_mode == "r":
|
||||
fh = dctx.stream_reader(inner_fh, closefd=closefd)
|
||||
elif open_mode == "w":
|
||||
fh = cctx.stream_writer(inner_fh, closefd=closefd)
|
||||
else:
|
||||
raise RuntimeError("logic error in zstandard.open() handling open mode")
|
||||
|
||||
if "b" not in normalized_mode:
|
||||
return io.TextIOWrapper(
|
||||
fh, encoding=encoding, errors=errors, newline=newline
|
||||
)
|
||||
else:
|
||||
return fh
|
||||
|
||||
|
||||
def compress(data: Buffer, level: int = 3) -> bytes:
|
||||
"""Compress source data using the zstd compression format.
|
||||
|
||||
This performs one-shot compression using basic/default compression
|
||||
settings.
|
||||
|
||||
This method is provided for convenience and is equivalent to calling
|
||||
``ZstdCompressor(level=level).compress(data)``.
|
||||
|
||||
If you find yourself calling this function in a tight loop,
|
||||
performance will be greater if you construct a single ``ZstdCompressor``
|
||||
and repeatedly call ``compress()`` on it.
|
||||
"""
|
||||
cctx = ZstdCompressor(level=level)
|
||||
|
||||
return cctx.compress(data)
|
||||
|
||||
|
||||
def decompress(data: Buffer, max_output_size: int = 0) -> bytes:
|
||||
"""Decompress a zstd frame into its original data.
|
||||
|
||||
This performs one-shot decompression using basic/default compression
|
||||
settings.
|
||||
|
||||
This method is provided for convenience and is equivalent to calling
|
||||
``ZstdDecompressor().decompress(data, max_output_size=max_output_size)``.
|
||||
|
||||
If you find yourself calling this function in a tight loop, performance
|
||||
will be greater if you construct a single ``ZstdDecompressor`` and
|
||||
repeatedly call ``decompress()`` on it.
|
||||
"""
|
||||
dctx = ZstdDecompressor()
|
||||
|
||||
return dctx.decompress(data, max_output_size=max_output_size)
|
||||
+481
@@ -0,0 +1,481 @@
|
||||
# Copyright (c) 2016-present, Gregory Szorc
|
||||
# All rights reserved.
|
||||
#
|
||||
# This software may be modified and distributed under the terms
|
||||
# of the BSD license. See the LICENSE file for details.
|
||||
|
||||
import os
|
||||
from typing import (
|
||||
IO,
|
||||
BinaryIO,
|
||||
ByteString,
|
||||
Generator,
|
||||
Iterable,
|
||||
List,
|
||||
Optional,
|
||||
Set,
|
||||
Tuple,
|
||||
Union,
|
||||
)
|
||||
|
||||
FLUSH_BLOCK: int
|
||||
FLUSH_FRAME: int
|
||||
|
||||
COMPRESSOBJ_FLUSH_FINISH: int
|
||||
COMPRESSOBJ_FLUSH_BLOCK: int
|
||||
|
||||
CONTENTSIZE_UNKNOWN: int
|
||||
CONTENTSIZE_ERROR: int
|
||||
|
||||
MAX_COMPRESSION_LEVEL: int
|
||||
|
||||
COMPRESSION_RECOMMENDED_INPUT_SIZE: int
|
||||
COMPRESSION_RECOMMENDED_OUTPUT_SIZE: int
|
||||
|
||||
DECOMPRESSION_RECOMMENDED_INPUT_SIZE: int
|
||||
DECOMPRESSION_RECOMMENDED_OUTPUT_SIZE: int
|
||||
|
||||
BLOCKSIZELOG_MAX: int
|
||||
BLOCKSIZE_MAX: int
|
||||
|
||||
WINDOWLOG_MIN: int
|
||||
WINDOWLOG_MAX: int
|
||||
|
||||
CHAINLOG_MIN: int
|
||||
CHAINLOG_MAX: int
|
||||
HASHLOG_MIN: int
|
||||
HASHLOG_MAX: int
|
||||
MINMATCH_MIN: int
|
||||
MINMATCH_MAX: int
|
||||
SEARCHLOG_MIN: int
|
||||
SEARCHLOG_MAX: int
|
||||
SEARCHLENGTH_MIN: int
|
||||
SEARCHLENGTH_MAX: int
|
||||
TARGETLENGTH_MIN: int
|
||||
TARGETLENGTH_MAX: int
|
||||
LDM_MINMATCH_MIN: int
|
||||
LDM_MINMATCH_MAX: int
|
||||
LDM_BUCKETSIZELOG_MAX: int
|
||||
|
||||
STRATEGY_FAST: int
|
||||
STRATEGY_DFAST: int
|
||||
STRATEGY_GREEDY: int
|
||||
STRATEGY_LAZY: int
|
||||
STRATEGY_LAZY2: int
|
||||
STRATEGY_BTLAZY2: int
|
||||
STRATEGY_BTOPT: int
|
||||
STRATEGY_BTULTRA: int
|
||||
STRATEGY_BTULTRA2: int
|
||||
|
||||
DICT_TYPE_AUTO: int
|
||||
DICT_TYPE_RAWCONTENT: int
|
||||
DICT_TYPE_FULLDICT: int
|
||||
|
||||
FORMAT_ZSTD1: int
|
||||
FORMAT_ZSTD1_MAGICLESS: int
|
||||
|
||||
ZSTD_VERSION: Tuple[int, int, int]
|
||||
FRAME_HEADER: bytes
|
||||
MAGIC_NUMBER: int
|
||||
|
||||
backend: str
|
||||
backend_features: Set[str]
|
||||
__version__: str
|
||||
|
||||
class ZstdError(Exception): ...
|
||||
|
||||
class BufferSegment(object):
|
||||
offset: int
|
||||
def __len__(self) -> int: ...
|
||||
def tobytes(self) -> bytes: ...
|
||||
|
||||
class BufferSegments(object):
|
||||
def __len__(self) -> int: ...
|
||||
def __getitem__(self, i: int) -> BufferSegment: ...
|
||||
|
||||
class BufferWithSegments(object):
|
||||
size: int
|
||||
def __init__(self, data: ByteString, segments: ByteString): ...
|
||||
def __len__(self) -> int: ...
|
||||
def __getitem__(self, i: int) -> BufferSegment: ...
|
||||
def segments(self): ...
|
||||
def tobytes(self) -> bytes: ...
|
||||
|
||||
class BufferWithSegmentsCollection(object):
|
||||
def __init__(self, *args): ...
|
||||
def __len__(self) -> int: ...
|
||||
def __getitem__(self, i: int) -> BufferSegment: ...
|
||||
def size(self) -> int: ...
|
||||
|
||||
class ZstdCompressionParameters(object):
|
||||
@staticmethod
|
||||
def from_level(
|
||||
level: int, source_size: int = ..., dict_size: int = ..., **kwargs
|
||||
) -> "ZstdCompressionParameters": ...
|
||||
def __init__(
|
||||
self,
|
||||
format: int = ...,
|
||||
compression_level: int = ...,
|
||||
window_log: int = ...,
|
||||
hash_log: int = ...,
|
||||
chain_log: int = ...,
|
||||
search_log: int = ...,
|
||||
min_match: int = ...,
|
||||
target_length: int = ...,
|
||||
strategy: int = ...,
|
||||
write_content_size: int = ...,
|
||||
write_checksum: int = ...,
|
||||
write_dict_id: int = ...,
|
||||
job_size: int = ...,
|
||||
overlap_log: int = ...,
|
||||
force_max_window: int = ...,
|
||||
enable_ldm: int = ...,
|
||||
ldm_hash_log: int = ...,
|
||||
ldm_min_match: int = ...,
|
||||
ldm_bucket_size_log: int = ...,
|
||||
ldm_hash_rate_log: int = ...,
|
||||
threads: int = ...,
|
||||
): ...
|
||||
@property
|
||||
def format(self) -> int: ...
|
||||
@property
|
||||
def compression_level(self) -> int: ...
|
||||
@property
|
||||
def window_log(self) -> int: ...
|
||||
@property
|
||||
def hash_log(self) -> int: ...
|
||||
@property
|
||||
def chain_log(self) -> int: ...
|
||||
@property
|
||||
def search_log(self) -> int: ...
|
||||
@property
|
||||
def min_match(self) -> int: ...
|
||||
@property
|
||||
def target_length(self) -> int: ...
|
||||
@property
|
||||
def strategy(self) -> int: ...
|
||||
@property
|
||||
def write_content_size(self) -> int: ...
|
||||
@property
|
||||
def write_checksum(self) -> int: ...
|
||||
@property
|
||||
def write_dict_id(self) -> int: ...
|
||||
@property
|
||||
def job_size(self) -> int: ...
|
||||
@property
|
||||
def overlap_log(self) -> int: ...
|
||||
@property
|
||||
def force_max_window(self) -> int: ...
|
||||
@property
|
||||
def enable_ldm(self) -> int: ...
|
||||
@property
|
||||
def ldm_hash_log(self) -> int: ...
|
||||
@property
|
||||
def ldm_min_match(self) -> int: ...
|
||||
@property
|
||||
def ldm_bucket_size_log(self) -> int: ...
|
||||
@property
|
||||
def ldm_hash_rate_log(self) -> int: ...
|
||||
@property
|
||||
def threads(self) -> int: ...
|
||||
def estimated_compression_context_size(self) -> int: ...
|
||||
|
||||
class CompressionParameters(ZstdCompressionParameters): ...
|
||||
|
||||
class ZstdCompressionDict(object):
|
||||
k: int
|
||||
d: int
|
||||
def __init__(
|
||||
self,
|
||||
data: ByteString,
|
||||
dict_type: int = ...,
|
||||
k: int = ...,
|
||||
d: int = ...,
|
||||
): ...
|
||||
def __len__(self) -> int: ...
|
||||
def dict_id(self) -> int: ...
|
||||
def as_bytes(self) -> bytes: ...
|
||||
def precompute_compress(
|
||||
self,
|
||||
level: int = ...,
|
||||
compression_params: ZstdCompressionParameters = ...,
|
||||
): ...
|
||||
|
||||
class ZstdCompressionObj(object):
|
||||
def compress(self, data: ByteString) -> bytes: ...
|
||||
def flush(self, flush_mode: int = ...) -> bytes: ...
|
||||
|
||||
class ZstdCompressionChunker(object):
|
||||
def compress(self, data: ByteString): ...
|
||||
def flush(self): ...
|
||||
def finish(self): ...
|
||||
|
||||
class ZstdCompressionReader(BinaryIO):
|
||||
def __enter__(self) -> "ZstdCompressionReader": ...
|
||||
def __exit__(self, exc_type, exc_value, exc_tb): ...
|
||||
def readable(self) -> bool: ...
|
||||
def writable(self) -> bool: ...
|
||||
def seekable(self) -> bool: ...
|
||||
def readline(self, limit: int = ...) -> bytes: ...
|
||||
def readlines(self, hint: int = ...) -> List[bytes]: ...
|
||||
def write(self, data: ByteString): ...
|
||||
def writelines(self, data: Iterable[bytes]): ...
|
||||
def isatty(self) -> bool: ...
|
||||
def flush(self): ...
|
||||
def close(self): ...
|
||||
@property
|
||||
def closed(self) -> bool: ...
|
||||
def tell(self) -> int: ...
|
||||
def readall(self) -> bytes: ...
|
||||
def __iter__(self): ...
|
||||
def __next__(self): ...
|
||||
def next(self): ...
|
||||
def read(self, size: int = ...) -> bytes: ...
|
||||
def read1(self, size: int = ...) -> bytes: ...
|
||||
def readinto(self, b) -> int: ...
|
||||
def readinto1(self, b) -> int: ...
|
||||
|
||||
class ZstdCompressionWriter(BinaryIO):
|
||||
def __enter__(self) -> "ZstdCompressionWriter": ...
|
||||
def __exit__(self, exc_type, exc_value, exc_tb): ...
|
||||
def memory_size(self) -> int: ...
|
||||
def fileno(self) -> int: ...
|
||||
def close(self): ...
|
||||
@property
|
||||
def closed(self) -> bool: ...
|
||||
def isatty(self) -> bool: ...
|
||||
def readable(self) -> bool: ...
|
||||
def readline(self, size: int = ...) -> bytes: ...
|
||||
def readlines(self, hint: int = ...) -> List[bytes]: ...
|
||||
def seek(self, offset: int, whence: int = ...): ...
|
||||
def seekable(self) -> bool: ...
|
||||
def truncate(self, size: int = ...): ...
|
||||
def writable(self) -> bool: ...
|
||||
def writelines(self, lines: Iterable[bytes]): ...
|
||||
def read(self, size: int = ...) -> bytes: ...
|
||||
def readall(self) -> bytes: ...
|
||||
def readinto(self, b): ...
|
||||
def write(self, data: ByteString) -> int: ...
|
||||
def flush(self, flush_mode: int = ...) -> int: ...
|
||||
def tell(self) -> int: ...
|
||||
|
||||
class ZstdCompressor(object):
|
||||
def __init__(
|
||||
self,
|
||||
level: int = ...,
|
||||
dict_data: Optional[ZstdCompressionDict] = ...,
|
||||
compression_params: Optional[ZstdCompressionParameters] = ...,
|
||||
write_checksum: Optional[bool] = ...,
|
||||
write_content_size: Optional[bool] = ...,
|
||||
write_dict_id: Optional[bool] = ...,
|
||||
threads: int = ...,
|
||||
): ...
|
||||
def memory_size(self) -> int: ...
|
||||
def compress(self, data: ByteString) -> bytes: ...
|
||||
def compressobj(self, size: int = ...) -> ZstdCompressionObj: ...
|
||||
def chunker(
|
||||
self, size: int = ..., chunk_size: int = ...
|
||||
) -> ZstdCompressionChunker: ...
|
||||
def copy_stream(
|
||||
self,
|
||||
ifh: IO[bytes],
|
||||
ofh: IO[bytes],
|
||||
size: int = ...,
|
||||
read_size: int = ...,
|
||||
write_size: int = ...,
|
||||
) -> Tuple[int, int]: ...
|
||||
def stream_reader(
|
||||
self,
|
||||
source: Union[IO[bytes], ByteString],
|
||||
size: int = ...,
|
||||
read_size: int = ...,
|
||||
*,
|
||||
closefd: bool = ...,
|
||||
) -> ZstdCompressionReader: ...
|
||||
def stream_writer(
|
||||
self,
|
||||
writer: IO[bytes],
|
||||
size: int = ...,
|
||||
write_size: int = ...,
|
||||
write_return_read: bool = ...,
|
||||
*,
|
||||
closefd: bool = ...,
|
||||
) -> ZstdCompressionWriter: ...
|
||||
def read_to_iter(
|
||||
self,
|
||||
reader: Union[IO[bytes], ByteString],
|
||||
size: int = ...,
|
||||
read_size: int = ...,
|
||||
write_size: int = ...,
|
||||
) -> Generator[bytes, None, None]: ...
|
||||
def frame_progression(self) -> Tuple[int, int, int]: ...
|
||||
def multi_compress_to_buffer(
|
||||
self,
|
||||
data: Union[
|
||||
BufferWithSegments,
|
||||
BufferWithSegmentsCollection,
|
||||
List[ByteString],
|
||||
],
|
||||
threads: int = ...,
|
||||
) -> BufferWithSegmentsCollection: ...
|
||||
|
||||
class ZstdDecompressionObj(object):
|
||||
def decompress(self, data: ByteString) -> bytes: ...
|
||||
def flush(self, length: int = ...) -> bytes: ...
|
||||
@property
|
||||
def unused_data(self) -> bytes: ...
|
||||
@property
|
||||
def unconsumed_tail(self) -> bytes: ...
|
||||
@property
|
||||
def eof(self) -> bool: ...
|
||||
|
||||
class ZstdDecompressionReader(BinaryIO):
|
||||
def __enter__(self) -> "ZstdDecompressionReader": ...
|
||||
def __exit__(self, exc_type, exc_value, exc_tb): ...
|
||||
def readable(self) -> bool: ...
|
||||
def writable(self) -> bool: ...
|
||||
def seekable(self) -> bool: ...
|
||||
def readline(self, size: int = ...): ...
|
||||
def readlines(self, hint: int = ...): ...
|
||||
def write(self, data: ByteString): ...
|
||||
def writelines(self, lines: Iterable[bytes]): ...
|
||||
def isatty(self) -> bool: ...
|
||||
def flush(self): ...
|
||||
def close(self): ...
|
||||
@property
|
||||
def closed(self) -> bool: ...
|
||||
def tell(self) -> int: ...
|
||||
def readall(self) -> bytes: ...
|
||||
def __iter__(self): ...
|
||||
def __next__(self): ...
|
||||
def next(self): ...
|
||||
def read(self, size: int = ...) -> bytes: ...
|
||||
def readinto(self, b) -> int: ...
|
||||
def read1(self, size: int = ...) -> bytes: ...
|
||||
def readinto1(self, b) -> int: ...
|
||||
def seek(self, pos: int, whence: int = ...) -> int: ...
|
||||
|
||||
class ZstdDecompressionWriter(BinaryIO):
|
||||
def __enter__(self) -> "ZstdDecompressionWriter": ...
|
||||
def __exit__(self, exc_type, exc_value, exc_tb): ...
|
||||
def memory_size(self) -> int: ...
|
||||
def close(self): ...
|
||||
@property
|
||||
def closed(self) -> bool: ...
|
||||
def fileno(self) -> int: ...
|
||||
def flush(self): ...
|
||||
def isatty(self) -> bool: ...
|
||||
def readable(self) -> bool: ...
|
||||
def readline(self, size: int = ...): ...
|
||||
def readlines(self, hint: int = ...): ...
|
||||
def seek(self, offset: int, whence: int = ...): ...
|
||||
def seekable(self) -> bool: ...
|
||||
def tell(self): ...
|
||||
def truncate(self, size: int = ...): ...
|
||||
def writable(self) -> bool: ...
|
||||
def writelines(self, lines: Iterable[bytes]): ...
|
||||
def read(self, size: int = ...): ...
|
||||
def readall(self): ...
|
||||
def readinto(self, b): ...
|
||||
def write(self, data: ByteString) -> int: ...
|
||||
|
||||
class ZstdDecompressor(object):
|
||||
def __init__(
|
||||
self,
|
||||
dict_data: Optional[ZstdCompressionDict] = ...,
|
||||
max_window_size: int = ...,
|
||||
format: int = ...,
|
||||
): ...
|
||||
def memory_size(self) -> int: ...
|
||||
def decompress(
|
||||
self,
|
||||
data: ByteString,
|
||||
max_output_size: int = ...,
|
||||
read_across_frames: bool = ...,
|
||||
allow_extra_data: bool = ...,
|
||||
) -> bytes: ...
|
||||
def stream_reader(
|
||||
self,
|
||||
source: Union[IO[bytes], ByteString],
|
||||
read_size: int = ...,
|
||||
read_across_frames: bool = ...,
|
||||
*,
|
||||
closefd=False,
|
||||
) -> ZstdDecompressionReader: ...
|
||||
def decompressobj(
|
||||
self, write_size: int = ..., read_across_frames: bool = False
|
||||
) -> ZstdDecompressionObj: ...
|
||||
def read_to_iter(
|
||||
self,
|
||||
reader: Union[IO[bytes], ByteString],
|
||||
read_size: int = ...,
|
||||
write_size: int = ...,
|
||||
skip_bytes: int = ...,
|
||||
) -> Generator[bytes, None, None]: ...
|
||||
def stream_writer(
|
||||
self,
|
||||
writer: IO[bytes],
|
||||
write_size: int = ...,
|
||||
write_return_read: bool = ...,
|
||||
*,
|
||||
closefd: bool = ...,
|
||||
) -> ZstdDecompressionWriter: ...
|
||||
def copy_stream(
|
||||
self,
|
||||
ifh: IO[bytes],
|
||||
ofh: IO[bytes],
|
||||
read_size: int = ...,
|
||||
write_size: int = ...,
|
||||
) -> Tuple[int, int]: ...
|
||||
def decompress_content_dict_chain(
|
||||
self, frames: list[ByteString]
|
||||
) -> bytes: ...
|
||||
def multi_decompress_to_buffer(
|
||||
self,
|
||||
frames: Union[
|
||||
BufferWithSegments,
|
||||
BufferWithSegmentsCollection,
|
||||
List[ByteString],
|
||||
],
|
||||
decompressed_sizes: ByteString = ...,
|
||||
threads: int = ...,
|
||||
) -> BufferWithSegmentsCollection: ...
|
||||
|
||||
class FrameParameters(object):
|
||||
content_size: int
|
||||
window_size: int
|
||||
dict_id: int
|
||||
has_checksum: bool
|
||||
|
||||
def estimate_decompression_context_size() -> int: ...
|
||||
def frame_content_size(data: ByteString) -> int: ...
|
||||
def frame_header_size(data: ByteString) -> int: ...
|
||||
def get_frame_parameters(
|
||||
data: ByteString, format: Optional[int] = None
|
||||
) -> FrameParameters: ...
|
||||
def train_dictionary(
|
||||
dict_size: int,
|
||||
samples: list[ByteString],
|
||||
k: int = ...,
|
||||
d: int = ...,
|
||||
f: int = ...,
|
||||
split_point: float = ...,
|
||||
accel: int = ...,
|
||||
notifications: int = ...,
|
||||
dict_id: int = ...,
|
||||
level: int = ...,
|
||||
steps: int = ...,
|
||||
threads: int = ...,
|
||||
) -> ZstdCompressionDict: ...
|
||||
def open(
|
||||
filename: Union[bytes, str, os.PathLike, BinaryIO],
|
||||
mode: str = ...,
|
||||
cctx: Optional[ZstdCompressor] = ...,
|
||||
dctx: Optional[ZstdDecompressor] = ...,
|
||||
encoding: Optional[str] = ...,
|
||||
errors: Optional[str] = ...,
|
||||
newline: Optional[str] = ...,
|
||||
closefd: bool = ...,
|
||||
): ...
|
||||
def compress(data: ByteString, level: int = ...) -> bytes: ...
|
||||
def decompress(data: ByteString, max_output_size: int = ...) -> bytes: ...
|
||||
Vendored
BIN
Binary file not shown.
Vendored
BIN
Binary file not shown.
+4478
File diff suppressed because it is too large
Load Diff
@@ -21,15 +21,15 @@ export const CODEX_LINK_PORT = 8795
|
||||
export const CODEX_LINK_ORIGIN = `http://127.0.0.1:${CODEX_LINK_PORT}`
|
||||
export const CODEX_LINK_STATUS_URL = `${CODEX_LINK_ORIGIN}/aiturk/codex-baglama/status`
|
||||
export const CODEX_LINK_STOP_URL = `${CODEX_LINK_ORIGIN}/aiturk/codex-baglama/stop`
|
||||
export const CODEX_LINK_REFRESH_URL = `${CODEX_LINK_ORIGIN}/aiturk/codex-baglama/refresh`
|
||||
|
||||
/** The trailing comment that marks the line as ours. */
|
||||
export const CODEX_LINK_MARKER = '# AITURK IDE Codex Baglama'
|
||||
// Must equal SURUM in assets/codex-bridge/bridge.py; a running bridge that reports
|
||||
// another version is restarted so an updated IDE never keeps an old bridge alive.
|
||||
export const CODEX_BRIDGE_VERSION = '1'
|
||||
export const CODEX_BRIDGE_VERSION = '3'
|
||||
export const CODEX_LINK_LINE = `openai_base_url = "${CODEX_LINK_ORIGIN}/backend-api/codex" ${CODEX_LINK_MARKER}`
|
||||
|
||||
export const CODEX_LINK_BACKUP_SUFFIX = '.aiturk-yedek'
|
||||
export const CODEX_LINK_RUN_KEY = 'HKCU\\Software\\Microsoft\\Windows\\CurrentVersion\\Run'
|
||||
export const CODEX_LINK_RUN_VALUE = 'AITURK-IDE-Codex-Baglama'
|
||||
export const CODEX_LINK_LAUNCHER_NAME = 'baslat.pyw'
|
||||
|
||||
@@ -3,6 +3,7 @@ import { describe, expect, it } from 'vitest'
|
||||
import { CODEX_BRIDGE_START_BUDGET_MS, type CodexLinkDeps, type CodexLinkPaths, createCodexLink } from './codex-link'
|
||||
import {
|
||||
CODEX_LINK_LINE,
|
||||
CODEX_LINK_REFRESH_URL,
|
||||
CODEX_LINK_STATUS_URL,
|
||||
CODEX_LINK_STOP_URL,
|
||||
codexBridgeArgs,
|
||||
@@ -20,8 +21,7 @@ const PATHS: CodexLinkPaths = {
|
||||
}
|
||||
|
||||
const BRIDGE_JSON = `${PATHS.bridgeHome}\\bridge.json`
|
||||
const BACKUP = `${PATHS.codexConfig}.aiturk-yedek`
|
||||
const STATUS_OK = { ok: true, surum: '1', ide_durum: 'tamam', ide_model: 7, ozet: true }
|
||||
const STATUS_OK = { ok: true, surum: '3', ide_durum: 'tamam', ide_model: 7, ozet: true }
|
||||
const USER_CONFIG = 'model = "gpt-6"\r\n\r\n[features]\r\nweb = true\r\n'
|
||||
|
||||
interface World {
|
||||
@@ -72,12 +72,6 @@ function createWorld(patch: Partial<World> & { files?: Map<string, string> } = {
|
||||
world.events.push(`write ${file}`)
|
||||
world.files.set(file, text)
|
||||
},
|
||||
backupOnce: (source, target) => {
|
||||
if (!world.files.has(target)) {
|
||||
world.events.push(`backup ${target}`)
|
||||
world.files.set(target, world.files.get(source) ?? '')
|
||||
}
|
||||
},
|
||||
spawnBridge: (command, args, env) => {
|
||||
world.events.push(`spawn ${command} ${JSON.stringify(args)} ${JSON.stringify(env)}`)
|
||||
spawned = true
|
||||
@@ -103,6 +97,12 @@ function createWorld(patch: Partial<World> & { files?: Map<string, string> } = {
|
||||
return null
|
||||
}
|
||||
|
||||
if (method === 'POST' && url === CODEX_LINK_REFRESH_URL) {
|
||||
world.events.push('refresh')
|
||||
|
||||
return world.listening ? STATUS_OK : null
|
||||
}
|
||||
|
||||
if (method === 'POST' && url === CODEX_LINK_STOP_URL) {
|
||||
world.events.push('stop')
|
||||
|
||||
@@ -205,19 +205,17 @@ describe('applyCodexLink', () => {
|
||||
hermesHome: PATHS.hermesHome
|
||||
})
|
||||
|
||||
// bridge.json → start → verified answer → config.toml (backed up) → login item
|
||||
// bridge.json → start → verified answer → config.toml → login item
|
||||
expect(world.events).toEqual([
|
||||
`write ${BRIDGE_JSON}`,
|
||||
`spawn ${PATHS.pythonw} ${JSON.stringify(args)} ${JSON.stringify(env)}`,
|
||||
'status ok',
|
||||
`backup ${BACKUP}`,
|
||||
`write ${PATHS.codexConfig}`,
|
||||
'autostart set'
|
||||
])
|
||||
|
||||
expect(JSON.parse(world.files.get(BRIDGE_JSON) ?? '')).toEqual(codexBridgeConfig())
|
||||
expect(world.files.get(PATHS.codexConfig)).toBe(`${CODEX_LINK_LINE}\r\n${USER_CONFIG}`)
|
||||
expect(world.files.get(BACKUP)).toBe(USER_CONFIG)
|
||||
expect(world.autostart).toBe(
|
||||
`"${PATHS.pythonw}" "${PATHS.bridgeScript}" --home "${PATHS.bridgeHome}" --hermes-home "${PATHS.hermesHome}"`
|
||||
)
|
||||
@@ -231,7 +229,6 @@ describe('applyCodexLink', () => {
|
||||
expect(status).toMatchObject({ enabled: true, bridgeRunning: false, lastError: 'bridge-start-failed' })
|
||||
expect(spawns(world)).toHaveLength(1)
|
||||
expect(world.files.get(PATHS.codexConfig)).toBe(USER_CONFIG)
|
||||
expect(world.files.has(BACKUP)).toBe(false)
|
||||
expect(world.autostart).toBeNull()
|
||||
expect(writes(world)).toEqual([`write ${BRIDGE_JSON}`])
|
||||
// The start poll is bounded by its one budget.
|
||||
@@ -273,13 +270,13 @@ describe('applyCodexLink', () => {
|
||||
expect(world.files.get(PATHS.codexConfig)).toBe(`${CODEX_LINK_LINE}\r\n${USER_CONFIG}`)
|
||||
})
|
||||
|
||||
it('never overwrites the first backup', async () => {
|
||||
it('asks a running bridge to re-read the IDE session on every apply', async () => {
|
||||
const { link, world } = createWorld({ listening: true })
|
||||
world.files.set(BACKUP, 'the original original')
|
||||
|
||||
await link.apply()
|
||||
await link.apply({ sync: true })
|
||||
|
||||
expect(world.files.get(BACKUP)).toBe('the original original')
|
||||
expect(world.events).toContain('refresh')
|
||||
expect(spawns(world)).toEqual([])
|
||||
})
|
||||
|
||||
it('falls back to python.exe when pythonw.exe is missing', async () => {
|
||||
|
||||
@@ -23,8 +23,8 @@ import path from 'node:path'
|
||||
import {
|
||||
addCodexLinkLine,
|
||||
CODEX_BRIDGE_VERSION,
|
||||
CODEX_LINK_BACKUP_SUFFIX,
|
||||
CODEX_LINK_LAUNCHER_NAME,
|
||||
CODEX_LINK_REFRESH_URL,
|
||||
CODEX_LINK_RUN_KEY,
|
||||
CODEX_LINK_RUN_VALUE,
|
||||
CODEX_LINK_STATUS_URL,
|
||||
@@ -66,8 +66,6 @@ export interface CodexLinkDeps {
|
||||
readText: (file: string) => null | string
|
||||
/** tmp + rename; creates the parent folder. */
|
||||
writeTextAtomic: (file: string, text: string) => void
|
||||
/** Copy `source` to `target` unless `target` already exists. */
|
||||
backupOnce: (source: string, target: string) => void
|
||||
/** Start the bridge detached and hidden; it must outlive the IDE. */
|
||||
spawnBridge: (command: string, args: string[], env: Record<string, string>) => void
|
||||
/** Parsed JSON body, or null when nothing answered within `budgetMs`. */
|
||||
@@ -306,7 +304,17 @@ export function createCodexLink(deps: CodexLinkDeps): CodexLink {
|
||||
bridge = NOT_RUNNING
|
||||
}
|
||||
|
||||
if (!bridge.running) {
|
||||
if (bridge.running) {
|
||||
// Already up: have it re-read the IDE session and model list now (a sign-in
|
||||
// since its last periodic refresh would otherwise show up minutes later).
|
||||
try {
|
||||
const refreshed = readProbe(await deps.request('POST', CODEX_LINK_REFRESH_URL, CODEX_BRIDGE_START_BUDGET_MS))
|
||||
|
||||
bridge = refreshed.running ? refreshed : bridge
|
||||
} catch {
|
||||
// The status it already gave stays valid.
|
||||
}
|
||||
} else {
|
||||
bridge = await startBridge(python)
|
||||
}
|
||||
|
||||
@@ -323,7 +331,6 @@ export function createCodexLink(deps: CodexLinkDeps): CodexLink {
|
||||
|
||||
if (edit.changed) {
|
||||
try {
|
||||
deps.backupOnce(paths.codexConfig, `${paths.codexConfig}${CODEX_LINK_BACKUP_SUFFIX}`)
|
||||
deps.writeTextAtomic(paths.codexConfig, edit.text)
|
||||
} catch (error) {
|
||||
fail('config-write-failed', error)
|
||||
@@ -461,11 +468,6 @@ export function createNodeCodexLinkDeps(paths: CodexLinkPaths, log: (message: st
|
||||
exists: file => fs.existsSync(file),
|
||||
readText: readTextLossless,
|
||||
writeTextAtomic,
|
||||
backupOnce: (source, target) => {
|
||||
if (!fs.existsSync(target)) {
|
||||
fs.copyFileSync(source, target, fs.constants.COPYFILE_EXCL)
|
||||
}
|
||||
},
|
||||
spawnBridge: (command, args, env) => {
|
||||
fs.mkdirSync(paths.bridgeHome, { recursive: true })
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
"name": "aiturk-ide",
|
||||
"productName": "AITURK IDE",
|
||||
"private": true,
|
||||
"version": "1.0.0-beta.21",
|
||||
"version": "1.0.0-beta.22",
|
||||
"description": "TurkServis resmi yapay zekâ geliştirme ortamı. Hermes Agent tabanlıdır.",
|
||||
"author": "AITURK / TurkServis",
|
||||
"repository": {
|
||||
@@ -304,7 +304,9 @@
|
||||
"from": "assets/codex-bridge",
|
||||
"to": "codex-bridge",
|
||||
"filter": [
|
||||
"*.py",
|
||||
"**/*.py",
|
||||
"**/*.pyd",
|
||||
"**/LICENSE",
|
||||
"!test_*.py"
|
||||
]
|
||||
}
|
||||
|
||||
Generated
+1
-1
@@ -65,7 +65,7 @@
|
||||
},
|
||||
"apps/desktop": {
|
||||
"name": "aiturk-ide",
|
||||
"version": "1.0.0-beta.21",
|
||||
"version": "1.0.0-beta.22",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@assistant-ui/core": "0.2.23",
|
||||
|
||||
Reference in New Issue
Block a user