mycode-cli 0.4.2__py3-none-any.whl → 0.5.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- mycode_cli/config.py +17 -9
- mycode_cli/main.py +3 -7
- mycode_cli/runtime.py +19 -17
- mycode_cli/server/deps.py +2 -1
- mycode_cli/server/routers/chat.py +29 -31
- mycode_cli/server/routers/sessions.py +3 -10
- mycode_cli/server/schemas.py +2 -7
- mycode_cli/server/static/assets/{EditDiff-BCA9aTUr.js → EditDiff-WSvfoXLm.js} +1 -1
- mycode_cli/server/static/assets/{index-C8gu4B-1.js → index-CzU-UeUh.js} +71 -73
- mycode_cli/server/static/index.html +1 -1
- mycode_cli/system_prompt.py +1 -2
- mycode_cli/tui/chat.py +9 -15
- mycode_cli/tui/render.py +33 -33
- {mycode_cli-0.4.2.dist-info → mycode_cli-0.5.0.dist-info}/METADATA +44 -35
- {mycode_cli-0.4.2.dist-info → mycode_cli-0.5.0.dist-info}/RECORD +18 -18
- {mycode_cli-0.4.2.dist-info → mycode_cli-0.5.0.dist-info}/WHEEL +0 -0
- {mycode_cli-0.4.2.dist-info → mycode_cli-0.5.0.dist-info}/entry_points.txt +0 -0
- {mycode_cli-0.4.2.dist-info → mycode_cli-0.5.0.dist-info}/licenses/LICENSE +0 -0
mycode_cli/config.py
CHANGED
|
@@ -1,11 +1,4 @@
|
|
|
1
|
-
"""
|
|
2
|
-
|
|
3
|
-
This module keeps runtime config loading intentionally simple:
|
|
4
|
-
|
|
5
|
-
- read the global config, then the workspace config
|
|
6
|
-
- merge provider entries by name
|
|
7
|
-
- resolve one runnable provider from explicit args, config defaults, or env
|
|
8
|
-
"""
|
|
1
|
+
"""Config loading, provider resolution, and CLI-owned filesystem paths."""
|
|
9
2
|
|
|
10
3
|
from __future__ import annotations
|
|
11
4
|
|
|
@@ -27,9 +20,24 @@ from mycode.providers import (
|
|
|
27
20
|
provider_default_models,
|
|
28
21
|
provider_env_api_key_names,
|
|
29
22
|
)
|
|
30
|
-
from mycode.session import resolve_mycode_home
|
|
31
23
|
from mycode.utils import as_bool, as_int
|
|
32
24
|
|
|
25
|
+
_DEFAULT_MYCODE_HOME = "~/.mycode"
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
def resolve_mycode_home() -> Path:
|
|
29
|
+
"""Resolve the mycode home directory (``$MYCODE_HOME`` or ``~/.mycode``)."""
|
|
30
|
+
|
|
31
|
+
raw = os.environ.get("MYCODE_HOME", _DEFAULT_MYCODE_HOME)
|
|
32
|
+
return Path(raw).expanduser().resolve(strict=False)
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
def resolve_sessions_dir() -> Path:
|
|
36
|
+
"""Resolve the directory used for persisted sessions."""
|
|
37
|
+
|
|
38
|
+
return resolve_mycode_home() / "sessions"
|
|
39
|
+
|
|
40
|
+
|
|
33
41
|
_API_KEY_ENV_REF_RE = re.compile(r"^\$\{([A-Za-z_][A-Za-z0-9_]*)\}$")
|
|
34
42
|
# Full set of user-facing choices. "auto" means "do not send an explicit effort
|
|
35
43
|
# to the provider" and is represented internally as `None` after normalization.
|
mycode_cli/main.py
CHANGED
|
@@ -13,7 +13,7 @@ import typer
|
|
|
13
13
|
from mycode.agent import Agent
|
|
14
14
|
from mycode.messages import ConversationMessage
|
|
15
15
|
from mycode.session import SessionStore
|
|
16
|
-
from mycode_cli.config import ResolvedProvider, Settings, get_settings, resolve_provider
|
|
16
|
+
from mycode_cli.config import ResolvedProvider, Settings, get_settings, resolve_provider, resolve_sessions_dir
|
|
17
17
|
|
|
18
18
|
from .runtime import ResolvedSession, build_agent, resolve_session
|
|
19
19
|
from .tui.chat import TerminalChat
|
|
@@ -82,7 +82,7 @@ def _bootstrap(
|
|
|
82
82
|
raise typer.BadParameter("--session and --continue are mutually exclusive")
|
|
83
83
|
|
|
84
84
|
cwd = os.path.abspath(os.getcwd())
|
|
85
|
-
store = SessionStore()
|
|
85
|
+
store = SessionStore(data_dir=resolve_sessions_dir())
|
|
86
86
|
view = TerminalView()
|
|
87
87
|
settings = get_settings(cwd)
|
|
88
88
|
|
|
@@ -91,10 +91,7 @@ def _bootstrap(
|
|
|
91
91
|
resolved_session = asyncio.run(
|
|
92
92
|
resolve_session(
|
|
93
93
|
store=store,
|
|
94
|
-
provider=resolved_provider.provider,
|
|
95
94
|
cwd=cwd,
|
|
96
|
-
model=resolved_provider.model,
|
|
97
|
-
api_base=resolved_provider.api_base,
|
|
98
95
|
requested_session_id=session,
|
|
99
96
|
continue_last=continue_last,
|
|
100
97
|
)
|
|
@@ -109,7 +106,6 @@ def _bootstrap(
|
|
|
109
106
|
settings=settings,
|
|
110
107
|
resolved_provider=resolved_provider,
|
|
111
108
|
session_id=resolved_session.session_id,
|
|
112
|
-
messages=resolved_session.messages,
|
|
113
109
|
max_turns=max_turns,
|
|
114
110
|
)
|
|
115
111
|
|
|
@@ -222,7 +218,7 @@ def session_list(
|
|
|
222
218
|
"""List saved sessions."""
|
|
223
219
|
|
|
224
220
|
cwd = os.path.abspath(os.getcwd())
|
|
225
|
-
store = SessionStore()
|
|
221
|
+
store = SessionStore(data_dir=resolve_sessions_dir())
|
|
226
222
|
view = TerminalView()
|
|
227
223
|
|
|
228
224
|
sessions = asyncio.run(store.list_sessions(cwd=None if all_workspaces else cwd))
|
mycode_cli/runtime.py
CHANGED
|
@@ -4,6 +4,7 @@ from __future__ import annotations
|
|
|
4
4
|
|
|
5
5
|
from dataclasses import dataclass
|
|
6
6
|
from typing import Any
|
|
7
|
+
from uuid import uuid4
|
|
7
8
|
|
|
8
9
|
from mycode.agent import Agent
|
|
9
10
|
from mycode.providers import (
|
|
@@ -48,22 +49,24 @@ def build_agent(
|
|
|
48
49
|
settings: Settings,
|
|
49
50
|
resolved_provider: ResolvedProvider,
|
|
50
51
|
session_id: str,
|
|
51
|
-
messages: list[dict[str, Any]] | None = None,
|
|
52
52
|
max_turns: int | None = None,
|
|
53
53
|
reasoning_effort: str | None = None,
|
|
54
54
|
) -> Agent:
|
|
55
|
-
"""Build an agent from the resolved provider, honoring model config overrides.
|
|
55
|
+
"""Build an agent from the resolved provider, honoring model config overrides.
|
|
56
56
|
|
|
57
|
-
|
|
57
|
+
History is auto-loaded from disk when ``session_id`` already exists under
|
|
58
|
+
the store; callers never pass messages explicitly.
|
|
59
|
+
"""
|
|
60
|
+
|
|
61
|
+
model_config = model_config_for(settings, resolved_provider)
|
|
58
62
|
return Agent(
|
|
59
63
|
model=resolved_provider.model,
|
|
60
64
|
provider=resolved_provider.provider,
|
|
61
65
|
cwd=cwd,
|
|
62
|
-
session_dir=store.
|
|
66
|
+
session_dir=store.data_dir,
|
|
63
67
|
session_id=session_id,
|
|
64
68
|
api_key=resolved_provider.api_key,
|
|
65
69
|
api_base=resolved_provider.api_base,
|
|
66
|
-
messages=messages,
|
|
67
70
|
reasoning_effort=reasoning_effort if reasoning_effort is not None else resolved_provider.reasoning_effort,
|
|
68
71
|
max_tokens=model_config.max_output_tokens if model_config else None,
|
|
69
72
|
context_window=model_config.context_window if model_config else None,
|
|
@@ -77,7 +80,7 @@ def build_agent(
|
|
|
77
80
|
)
|
|
78
81
|
|
|
79
82
|
|
|
80
|
-
def
|
|
83
|
+
def model_config_for(settings: Settings, resolved: ResolvedProvider) -> ModelConfig | None:
|
|
81
84
|
"""Return the user-configured overrides for the resolved provider+model, if any."""
|
|
82
85
|
|
|
83
86
|
provider_config = settings.providers.get(resolved.provider_name or "")
|
|
@@ -86,18 +89,20 @@ def _model_config_for(settings: Settings, resolved: ResolvedProvider) -> ModelCo
|
|
|
86
89
|
return provider_config.models.get(resolved.model)
|
|
87
90
|
|
|
88
91
|
|
|
89
|
-
def clone_agent(agent: Agent, *, store: SessionStore, session_id: str
|
|
90
|
-
"""Keep the current runtime config while swapping session state.
|
|
92
|
+
def clone_agent(agent: Agent, *, store: SessionStore, session_id: str) -> Agent:
|
|
93
|
+
"""Keep the current runtime config while swapping session state.
|
|
94
|
+
|
|
95
|
+
History auto-loads from disk when ``session_id`` exists under the store.
|
|
96
|
+
"""
|
|
91
97
|
|
|
92
98
|
return Agent(
|
|
93
99
|
model=agent.model,
|
|
94
100
|
provider=agent.provider,
|
|
95
101
|
cwd=agent.cwd,
|
|
96
|
-
session_dir=store.
|
|
102
|
+
session_dir=store.data_dir,
|
|
97
103
|
session_id=session_id,
|
|
98
104
|
api_key=agent.api_key,
|
|
99
105
|
api_base=agent.api_base,
|
|
100
|
-
messages=messages,
|
|
101
106
|
max_turns=agent.max_turns,
|
|
102
107
|
max_tokens=agent.max_tokens,
|
|
103
108
|
context_window=agent.context_window,
|
|
@@ -171,10 +176,7 @@ def supports_reasoning_effort(agent: Agent) -> bool:
|
|
|
171
176
|
async def resolve_session(
|
|
172
177
|
*,
|
|
173
178
|
store: SessionStore,
|
|
174
|
-
provider: str,
|
|
175
179
|
cwd: str,
|
|
176
|
-
model: str,
|
|
177
|
-
api_base: str | None,
|
|
178
180
|
requested_session_id: str | None,
|
|
179
181
|
continue_last: bool,
|
|
180
182
|
) -> ResolvedSession:
|
|
@@ -205,9 +207,9 @@ async def resolve_session(
|
|
|
205
207
|
"resumed",
|
|
206
208
|
)
|
|
207
209
|
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
return ResolvedSession(
|
|
210
|
+
# New sessions: the id is allocated here; the on-disk session is created
|
|
211
|
+
# lazily by Agent.achat on the first persist.
|
|
212
|
+
return ResolvedSession(uuid4().hex, {}, [], "new")
|
|
211
213
|
|
|
212
214
|
|
|
213
215
|
def apply_resolved_provider(agent: Agent, resolved: ResolvedProvider, settings: Settings) -> bool:
|
|
@@ -233,7 +235,7 @@ def apply_resolved_provider(agent: Agent, resolved: ResolvedProvider, settings:
|
|
|
233
235
|
agent.reasoning_effort = resolved.reasoning_effort
|
|
234
236
|
|
|
235
237
|
if runtime_changed:
|
|
236
|
-
model_config =
|
|
238
|
+
model_config = model_config_for(settings, resolved)
|
|
237
239
|
agent.refresh_capabilities(
|
|
238
240
|
max_tokens=model_config.max_output_tokens if model_config else None,
|
|
239
241
|
context_window=model_config.context_window if model_config else None,
|
mycode_cli/server/deps.py
CHANGED
|
@@ -8,6 +8,7 @@ from typing import Annotated
|
|
|
8
8
|
from fastapi import Depends
|
|
9
9
|
|
|
10
10
|
from mycode.session import SessionStore
|
|
11
|
+
from mycode_cli.config import resolve_sessions_dir
|
|
11
12
|
from mycode_cli.server.run_manager import RunManager
|
|
12
13
|
|
|
13
14
|
|
|
@@ -15,7 +16,7 @@ from mycode_cli.server.run_manager import RunManager
|
|
|
15
16
|
def get_store() -> SessionStore:
|
|
16
17
|
"""Return the shared session store for server requests."""
|
|
17
18
|
|
|
18
|
-
return SessionStore()
|
|
19
|
+
return SessionStore(data_dir=resolve_sessions_dir())
|
|
19
20
|
|
|
20
21
|
|
|
21
22
|
@lru_cache
|
|
@@ -17,7 +17,6 @@ from fastapi.responses import StreamingResponse
|
|
|
17
17
|
from mycode.messages import (
|
|
18
18
|
build_message,
|
|
19
19
|
document_block,
|
|
20
|
-
flatten_message_text,
|
|
21
20
|
image_block,
|
|
22
21
|
text_block,
|
|
23
22
|
)
|
|
@@ -31,7 +30,7 @@ from mycode_cli.config import (
|
|
|
31
30
|
resolve_provider,
|
|
32
31
|
resolve_provider_choices,
|
|
33
32
|
)
|
|
34
|
-
from mycode_cli.runtime import build_agent
|
|
33
|
+
from mycode_cli.runtime import build_agent, model_config_for
|
|
35
34
|
from mycode_cli.server.deps import RunManagerDep, StoreDep
|
|
36
35
|
from mycode_cli.server.run_manager import ActiveRunError, RunState
|
|
37
36
|
from mycode_cli.server.schemas import ChatRequest, StreamEvent
|
|
@@ -165,19 +164,19 @@ async def chat(chat: ChatRequest, store: StoreDep, runs: RunManagerDep):
|
|
|
165
164
|
|
|
166
165
|
data = await store.load_session(session_id)
|
|
167
166
|
session = (data or {}).get("session")
|
|
168
|
-
|
|
167
|
+
existing_messages = (data or {}).get("messages") or []
|
|
169
168
|
|
|
170
169
|
if not session and chat.rewind_to is not None:
|
|
171
170
|
raise HTTPException(status_code=400, detail="rewind_to requires an existing session")
|
|
172
171
|
|
|
173
172
|
if chat.rewind_to is not None:
|
|
174
|
-
if not (0 <= chat.rewind_to < len(
|
|
173
|
+
if not (0 <= chat.rewind_to < len(existing_messages)):
|
|
175
174
|
raise HTTPException(
|
|
176
175
|
status_code=400,
|
|
177
|
-
detail=f"rewind_to must reference a visible message index between 0 and {len(
|
|
176
|
+
detail=f"rewind_to must reference a visible message index between 0 and {len(existing_messages) - 1}",
|
|
178
177
|
)
|
|
179
178
|
|
|
180
|
-
target =
|
|
179
|
+
target = existing_messages[chat.rewind_to]
|
|
181
180
|
raw_blocks = target.get("content")
|
|
182
181
|
blocks = raw_blocks if isinstance(raw_blocks, list) else []
|
|
183
182
|
has_user_content = any(
|
|
@@ -194,7 +193,29 @@ async def chat(chat: ChatRequest, store: StoreDep, runs: RunManagerDep):
|
|
|
194
193
|
detail="rewind_to must reference a real user message",
|
|
195
194
|
)
|
|
196
195
|
|
|
197
|
-
|
|
196
|
+
# Capability check before any disk mutation — a failed check must not
|
|
197
|
+
# leave an empty session on disk or land a premature rewind marker.
|
|
198
|
+
model_config = model_config_for(settings, resolved)
|
|
199
|
+
caps = resolve_model_metadata(
|
|
200
|
+
provider=resolved.provider,
|
|
201
|
+
model=resolved.model,
|
|
202
|
+
supports_image_input=model_config.supports_image_input if model_config else None,
|
|
203
|
+
supports_pdf_input=model_config.supports_pdf_input if model_config else None,
|
|
204
|
+
)
|
|
205
|
+
content_types = {b.get("type") for b in (user_message.get("content") or []) if isinstance(b, dict)}
|
|
206
|
+
if "image" in content_types and not caps.supports_image_input:
|
|
207
|
+
raise HTTPException(status_code=400, detail="current model does not support image input")
|
|
208
|
+
if "document" in content_types and not caps.supports_pdf_input:
|
|
209
|
+
raise HTTPException(status_code=400, detail="current model does not support PDF input")
|
|
210
|
+
|
|
211
|
+
# All validation passed. Land the rewind marker (if any) and create the
|
|
212
|
+
# session so the response payload has a meta dict and the agent's
|
|
213
|
+
# auto-resume sees the correct on-disk state.
|
|
214
|
+
if chat.rewind_to is not None:
|
|
215
|
+
await store.append_rewind(session_id, chat.rewind_to)
|
|
216
|
+
if not session:
|
|
217
|
+
created = await store.create_session(session_id, cwd=cwd)
|
|
218
|
+
session = created["session"]
|
|
198
219
|
|
|
199
220
|
agent = build_agent(
|
|
200
221
|
store=store,
|
|
@@ -202,37 +223,14 @@ async def chat(chat: ChatRequest, store: StoreDep, runs: RunManagerDep):
|
|
|
202
223
|
settings=settings,
|
|
203
224
|
resolved_provider=resolved,
|
|
204
225
|
session_id=session_id,
|
|
205
|
-
messages=messages,
|
|
206
226
|
reasoning_effort=reasoning_effort,
|
|
207
227
|
)
|
|
208
228
|
|
|
209
|
-
content_types = {b.get("type") for b in (user_message.get("content") or []) if isinstance(b, dict)}
|
|
210
|
-
if "image" in content_types and not agent.supports_image_input:
|
|
211
|
-
raise HTTPException(status_code=400, detail="current model does not support image input")
|
|
212
|
-
if "document" in content_types and not agent.supports_pdf_input:
|
|
213
|
-
raise HTTPException(status_code=400, detail="current model does not support PDF input")
|
|
214
|
-
|
|
215
|
-
if not session:
|
|
216
|
-
title = flatten_message_text(user_message).replace("\n", " ").strip()[:48] or "New chat"
|
|
217
|
-
created = await store.create_session(
|
|
218
|
-
title,
|
|
219
|
-
session_id=session_id,
|
|
220
|
-
provider=resolved.provider,
|
|
221
|
-
model=resolved.model,
|
|
222
|
-
cwd=cwd,
|
|
223
|
-
api_base=resolved.api_base,
|
|
224
|
-
)
|
|
225
|
-
session = created["session"]
|
|
226
|
-
|
|
227
|
-
if chat.rewind_to is not None:
|
|
228
|
-
# Land the rewind marker before the agent appends the next user turn.
|
|
229
|
-
await store.append_rewind(session_id, chat.rewind_to)
|
|
230
|
-
|
|
231
229
|
try:
|
|
232
230
|
run = await runs.start_run(
|
|
233
231
|
session_id=session_id,
|
|
234
232
|
user_message=user_message,
|
|
235
|
-
base_messages=messages,
|
|
233
|
+
base_messages=agent.messages,
|
|
236
234
|
agent=agent,
|
|
237
235
|
)
|
|
238
236
|
except ActiveRunError as exc:
|
|
@@ -3,10 +3,10 @@
|
|
|
3
3
|
from __future__ import annotations
|
|
4
4
|
|
|
5
5
|
import os
|
|
6
|
+
from uuid import uuid4
|
|
6
7
|
|
|
7
8
|
from fastapi import APIRouter, HTTPException
|
|
8
9
|
|
|
9
|
-
from mycode_cli.config import get_settings, resolve_provider
|
|
10
10
|
from mycode_cli.server.deps import RunManagerDep, StoreDep
|
|
11
11
|
from mycode_cli.server.schemas import SessionCreateRequest
|
|
12
12
|
|
|
@@ -16,15 +16,8 @@ router = APIRouter(prefix="/sessions", tags=["sessions"])
|
|
|
16
16
|
@router.post("")
|
|
17
17
|
async def create_session(req: SessionCreateRequest, store: StoreDep):
|
|
18
18
|
cwd = os.path.abspath(req.cwd or os.getcwd())
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
return await store.create_session(
|
|
22
|
-
req.title,
|
|
23
|
-
provider=resolved.provider,
|
|
24
|
-
model=resolved.model,
|
|
25
|
-
cwd=cwd,
|
|
26
|
-
api_base=resolved.api_base,
|
|
27
|
-
)
|
|
19
|
+
session_id = uuid4().hex
|
|
20
|
+
return await store.create_session(session_id, cwd=cwd)
|
|
28
21
|
|
|
29
22
|
|
|
30
23
|
@router.get("")
|
mycode_cli/server/schemas.py
CHANGED
|
@@ -37,11 +37,7 @@ class ChatRequest(BaseModel):
|
|
|
37
37
|
class SessionCreateRequest(BaseModel):
|
|
38
38
|
"""Request body for /sessions."""
|
|
39
39
|
|
|
40
|
-
title: str | None = None
|
|
41
|
-
provider: str | None = None
|
|
42
|
-
model: str | None = None
|
|
43
40
|
cwd: str | None = None
|
|
44
|
-
api_base: str | None = None
|
|
45
41
|
|
|
46
42
|
|
|
47
43
|
class ToolCallPayload(BaseModel):
|
|
@@ -60,8 +56,7 @@ class StreamEvent(BaseModel):
|
|
|
60
56
|
delta: str | None = None # text/reasoning
|
|
61
57
|
tool_call: ToolCallPayload | None = None # tool_start
|
|
62
58
|
tool_use_id: str | None = None
|
|
63
|
-
output: str | None = None # tool_output
|
|
64
|
-
|
|
65
|
-
display_text: str | None = None # tool_done
|
|
59
|
+
output: str | None = None # tool_output + tool_done
|
|
60
|
+
metadata: dict[str, Any] | None = None # tool_done
|
|
66
61
|
is_error: bool | None = None # tool_done
|
|
67
62
|
message: str | None = None # error
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import{r as N,h as D,a as _,l as O,j as y,c as q,S as A}from"./index-
|
|
1
|
+
import{r as N,h as D,a as _,l as O,j as y,c as q,S as A}from"./index-CzU-UeUh.js";class R{diff(e,n,t={}){let l;typeof t=="function"?(l=t,t={}):"callback"in t&&(l=t.callback);const o=this.castInput(e,t),i=this.castInput(n,t),a=this.removeEmpty(this.tokenize(o,t)),s=this.removeEmpty(this.tokenize(i,t));return this.diffWithOptionsObj(a,s,t,l)}diffWithOptionsObj(e,n,t,l){var o;const i=m=>{if(m=this.postProcess(m,t),l){setTimeout(function(){l(m)},0);return}else return m},a=n.length,s=e.length;let r=1,d=a+s;t.maxEditLength!=null&&(d=Math.min(d,t.maxEditLength));const h=(o=t.timeout)!==null&&o!==void 0?o:1/0,x=Date.now()+h,f=[{oldPos:-1,lastComponent:void 0}];let p=this.extractCommon(f[0],n,e,0,t);if(f[0].oldPos+1>=s&&p+1>=a)return i(this.buildValues(f[0].lastComponent,n,e));let g=-1/0,P=1/0;const T=()=>{for(let m=Math.max(g,-r);m<=Math.min(P,r);m+=2){let v;const L=f[m-1],j=f[m+1];L&&(f[m-1]=void 0);let u=!1;if(j){const k=j.oldPos-m;u=j&&0<=k&&k<a}const w=L&&L.oldPos+1<s;if(!u&&!w){f[m]=void 0;continue}if(!w||u&&L.oldPos<j.oldPos?v=this.addToPath(j,!0,!1,0,t):v=this.addToPath(L,!1,!0,1,t),p=this.extractCommon(v,n,e,m,t),v.oldPos+1>=s&&p+1>=a)return i(this.buildValues(v.lastComponent,n,e))||!0;f[m]=v,v.oldPos+1>=s&&(P=Math.min(P,m-1)),p+1>=a&&(g=Math.max(g,m+1))}r++};if(l)(function m(){setTimeout(function(){if(r>d||Date.now()>x)return l(void 0);T()||m()},0)})();else for(;r<=d&&Date.now()<=x;){const m=T();if(m)return m}}addToPath(e,n,t,l,o){const i=e.lastComponent;return i&&!o.oneChangePerToken&&i.added===n&&i.removed===t?{oldPos:e.oldPos+l,lastComponent:{count:i.count+1,added:n,removed:t,previousComponent:i.previousComponent}}:{oldPos:e.oldPos+l,lastComponent:{count:1,added:n,removed:t,previousComponent:i}}}extractCommon(e,n,t,l,o){const i=n.length,a=t.length;let s=e.oldPos,r=s-l,d=0;for(;r+1<i&&s+1<a&&this.equals(t[s+1],n[r+1],o);)r++,s++,d++,o.oneChangePerToken&&(e.lastComponent={count:1,previousComponent:e.lastComponent,added:!1,removed:!1});return d&&!o.oneChangePerToken&&(e.lastComponent={count:d,previousComponent:e.lastComponent,added:!1,removed:!1}),e.oldPos=s,r}equals(e,n,t){return t.comparator?t.comparator(e,n):e===n||!!t.ignoreCase&&e.toLowerCase()===n.toLowerCase()}removeEmpty(e){const n=[];for(let t=0;t<e.length;t++)e[t]&&n.push(e[t]);return n}castInput(e,n){return e}tokenize(e,n){return Array.from(e)}join(e){return e.join("")}postProcess(e,n){return e}get useLongestToken(){return!1}buildValues(e,n,t){const l=[];let o;for(;e;)l.push(e),o=e.previousComponent,delete e.previousComponent,e=o;l.reverse();const i=l.length;let a=0,s=0,r=0;for(;a<i;a++){const d=l[a];if(d.removed)d.value=this.join(t.slice(r,r+d.count)),r+=d.count;else{if(!d.added&&this.useLongestToken){let h=n.slice(s,s+d.count);h=h.map(function(x,f){const p=t[r+f];return p.length>x.length?p:x}),d.value=this.join(h)}else d.value=this.join(n.slice(s,s+d.count));s+=d.count,d.added||(r+=d.count)}}return l}}class z extends R{constructor(){super(...arguments),this.tokenize=V}equals(e,n,t){return t.ignoreWhitespace?((!t.newlineIsToken||!e.includes(`
|
|
2
2
|
`))&&(e=e.trim()),(!t.newlineIsToken||!n.includes(`
|
|
3
3
|
`))&&(n=n.trim())):t.ignoreNewlineAtEof&&!t.newlineIsToken&&(e.endsWith(`
|
|
4
4
|
`)&&(e=e.slice(0,-1)),n.endsWith(`
|