deepagents-code 0.2.0__py3-none-any.whl → 0.2.1__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.
@@ -1,3 +1,3 @@
1
1
  """Generated at build time. Do not edit or commit."""
2
2
 
3
- BUILD_COMMIT = "981a87a"
3
+ BUILD_COMMIT = "8f48aab"
@@ -0,0 +1,184 @@
1
+ """Presence lock telling a launch whether other dcode sessions share its install.
2
+
3
+ A Python migration rebuilds the uv tool environment, which breaks every dcode
4
+ process — and every server it spawned — still running from the old one. Startup
5
+ auto-update may only migrate when no other session uses the installation, and
6
+ it cannot tell that from a process listing: shims, renamed symlinks, and the
7
+ server bootstrap all run under different names.
8
+
9
+ Instead, each dcode process of a non-editable install (editable installs never
10
+ auto-update) holds a shared `flock` on `SESSION_LOCK_FILE` for its lifetime,
11
+ and hands the descriptor to the servers it spawns so they hold
12
+ the same lock. A process asking "am I alone?" tries to take the lock
13
+ exclusively; that succeeds only when no other session's open file holds it.
14
+ The kernel drops a lock when its last descriptor closes, so a crashed session
15
+ can never leave a stale claim behind.
16
+
17
+ The answer is a snapshot. It cannot see sessions of versions from before this
18
+ lock existed, and nothing stops a session that launches while the migration
19
+ runs; both are accepted as rare and recoverable by a relaunch.
20
+
21
+ POSIX only. On Windows, or whenever the lock cannot be taken, a process is
22
+ never reported as alone, so the migration stays deferred to `dcode update`.
23
+ """
24
+
25
+ from __future__ import annotations
26
+
27
+ import logging
28
+ import os
29
+ import sys
30
+ from typing import TYPE_CHECKING
31
+
32
+ from deepagents_code._paths import PATHS
33
+
34
+ if sys.platform != "win32":
35
+ import fcntl
36
+
37
+ if TYPE_CHECKING:
38
+ from pathlib import Path
39
+
40
+ logger = logging.getLogger(__name__)
41
+
42
+ SESSION_LOCK_FILE: Path = PATHS.installation.locks_dir / "sessions.lock"
43
+ """Advisory lock held shared by every registered dcode process of one installation.
44
+
45
+ Lives beside `update.lock`, outside the tool environment, so a migration that
46
+ rebuilds the environment keeps the same file. Carries no data.
47
+
48
+ Installation-scoped only, with no per-profile fallback: a profile-scoped lock
49
+ would hide sessions of other profiles, and over-reporting "alone" is the one
50
+ failure this lock must not have.
51
+ """
52
+
53
+ _held_fd: int | None = None
54
+ """Descriptor holding this process's shared lock, or `None` when not held."""
55
+
56
+
57
+ def hold_session_lock() -> None:
58
+ """Register this process as a running session for its lifetime.
59
+
60
+ Idempotent and fail-soft: when the lock cannot be taken, the process runs
61
+ unregistered and `is_sole_session` reports `False`. The descriptor is
62
+ non-inheritable, so the re-exec after an update drops it and the new
63
+ process registers itself again.
64
+ """
65
+ global _held_fd # noqa: PLW0603 # one registration per process
66
+ if _held_fd is not None or sys.platform == "win32":
67
+ return
68
+ try:
69
+ SESSION_LOCK_FILE.parent.mkdir(mode=0o700, parents=True, exist_ok=True)
70
+ fd = os.open(SESSION_LOCK_FILE, os.O_RDWR | os.O_CREAT, 0o600)
71
+ except OSError:
72
+ logger.warning(
73
+ "Could not open session lock %s", SESSION_LOCK_FILE, exc_info=True
74
+ )
75
+ return
76
+ try:
77
+ # Blocks only while another process is inside `is_sole_session`, the
78
+ # one place the lock is ever held exclusively, and only for an instant.
79
+ # Failing fast instead would leave this session invisible to that check.
80
+ fcntl.flock(fd, fcntl.LOCK_SH)
81
+ except OSError:
82
+ logger.warning(
83
+ "Could not take session lock %s", SESSION_LOCK_FILE, exc_info=True
84
+ )
85
+ os.close(fd)
86
+ return
87
+ _held_fd = fd
88
+
89
+
90
+ def session_lock_fds() -> tuple[int, ...]:
91
+ """Return descriptors a spawned server must inherit to count as this session.
92
+
93
+ `flock` locks belong to the open file description, so a child given the
94
+ descriptor holds the same lock: the server keeps the install marked in use
95
+ if it outlives its client, and does not count as a second session.
96
+ """
97
+ return () if _held_fd is None else (_held_fd,)
98
+
99
+
100
+ def session_lock_unavailable() -> bool:
101
+ """Return whether this POSIX process failed to register as a session.
102
+
103
+ Lets callers tell "other sessions are running" apart from "presence cannot
104
+ be known", which quitting other sessions would never fix.
105
+ """
106
+ return sys.platform != "win32" and _held_fd is None
107
+
108
+
109
+ def is_sole_session() -> bool:
110
+ """Return whether no other dcode session holds this installation.
111
+
112
+ Converting a `flock` is not atomic: the shared lock is released before the
113
+ exclusive one is tried, so two processes checking at once could each see
114
+ the other as absent. An exclusive lock on `sessions.check.lock` beside
115
+ `SESSION_LOCK_FILE` admits one checker at a time; a process that finds it
116
+ taken is not alone.
117
+
118
+ Returns:
119
+ `True` only when this process holds the session lock and could take
120
+ it exclusively. `False` when another session holds it, or when the
121
+ lock is unavailable and presence cannot be known.
122
+ """
123
+ if _held_fd is None:
124
+ return False
125
+ check_file = SESSION_LOCK_FILE.with_name("sessions.check.lock")
126
+ try:
127
+ guard = os.open(check_file, os.O_RDWR | os.O_CREAT, 0o600)
128
+ except OSError:
129
+ logger.warning("Could not open %s", check_file, exc_info=True)
130
+ return False
131
+ try:
132
+ fcntl.flock(guard, fcntl.LOCK_EX | fcntl.LOCK_NB)
133
+ except OSError:
134
+ return False
135
+ else:
136
+ return _probe_exclusive(_held_fd)
137
+ finally:
138
+ os.close(guard)
139
+
140
+
141
+ def _probe_exclusive(fd: int) -> bool:
142
+ """Try to take the session lock exclusively, then hold it shared again.
143
+
144
+ Returns:
145
+ Whether the exclusive attempt succeeded and the shared lock is back.
146
+ """
147
+ try:
148
+ fcntl.flock(fd, fcntl.LOCK_EX | fcntl.LOCK_NB)
149
+ except BlockingIOError:
150
+ sole = False
151
+ except OSError:
152
+ logger.warning(
153
+ "Could not check session lock %s", SESSION_LOCK_FILE, exc_info=True
154
+ )
155
+ sole = False
156
+ else:
157
+ sole = True
158
+ # Re-take it on both branches: on Linux a failed upgrade attempt has already
159
+ # released the shared lock.
160
+ return _restore_shared(fd) and sole
161
+
162
+
163
+ def _restore_shared(fd: int) -> bool:
164
+ """Hold the session lock shared again, or unregister on failure.
165
+
166
+ Returns:
167
+ Whether this process is still registered.
168
+ """
169
+ global _held_fd # noqa: PLW0603 # unregister a lock this process lost
170
+ try:
171
+ # Blocking is safe: the check lock is held, so no other process holds
172
+ # this lock exclusively.
173
+ fcntl.flock(fd, fcntl.LOCK_SH)
174
+ except OSError:
175
+ logger.warning(
176
+ "Could not restore the shared session lock %s; other dcode sessions "
177
+ "will not see this one",
178
+ SESSION_LOCK_FILE,
179
+ exc_info=True,
180
+ )
181
+ _held_fd = None
182
+ os.close(fd)
183
+ return False
184
+ return True
@@ -2,7 +2,7 @@
2
2
 
3
3
  # Keep the `x-release-please-version` annotation — release-please uses it to
4
4
  # bump `__version__` in sync with `pyproject.toml` on every release PR.
5
- __version__ = "0.2.0" # x-release-please-version
5
+ __version__ = "0.2.1" # x-release-please-version
6
6
 
7
7
  DOCS_URL = "https://docs.langchain.com/oss/python/deepagents/code"
8
8
  """URL for `deepagents-code` documentation."""
deepagents_code/agent.py CHANGED
@@ -2772,6 +2772,28 @@ def create_cli_agent(
2772
2772
  ):
2773
2773
  extension_registry = None
2774
2774
  mcp_tools = tuple(mcp_tools or ())
2775
+ skill_tools = tuple(
2776
+ item
2777
+ for item in mcp_tools
2778
+ if (item.metadata or {}).get("_deepagents_code_skill_only") is True
2779
+ )
2780
+ skill_tool_ids = {id(item) for item in skill_tools}
2781
+ tools = [item for item in tools if id(item) not in skill_tool_ids]
2782
+ if skill_tools and mcp_server_info:
2783
+ skill_tool_names = {item.name for item in skill_tools}
2784
+ mcp_server_info = [
2785
+ replace(
2786
+ server,
2787
+ tools=tuple(
2788
+ item for item in server.tools if item.name not in skill_tool_names
2789
+ ),
2790
+ )
2791
+ for server in mcp_server_info
2792
+ ]
2793
+ if skill_tools and not enable_skills:
2794
+ logger.warning(
2795
+ "Skill-only MCP tools are unavailable because skills are disabled"
2796
+ )
2775
2797
  if auto_mode_enabled and sandbox is not None:
2776
2798
  logger.warning(
2777
2799
  "Classifier-backed Auto is unavailable with a sandbox; using Manual HITL"
@@ -2792,6 +2814,12 @@ def create_cli_agent(
2792
2814
  # Base instructions are loaded fresh from get_system_prompt()
2793
2815
  agent_md.touch()
2794
2816
 
2817
+ skill_sources = (
2818
+ get_skill_sources(assistant_id=assistant_id, project_context=project_context)
2819
+ if enable_skills
2820
+ else []
2821
+ )
2822
+
2795
2823
  # Load custom subagents from filesystem
2796
2824
  custom_subagents: list[SubAgent | CompiledSubAgent] = []
2797
2825
  resolved_shell_allow_list = _resolve_shell_allow_list()
@@ -2892,6 +2920,16 @@ def create_cli_agent(
2892
2920
  middleware.append(
2893
2921
  ManagedMemoryGuardMiddleware([get_user_agent_md_path(assistant_id)])
2894
2922
  )
2923
+ if enable_skills and skill_tools:
2924
+ middleware.insert(
2925
+ 0,
2926
+ PluginSkillsMiddleware(
2927
+ backend=FilesystemBackend(virtual_mode=False),
2928
+ sources=skill_sources,
2929
+ path_base=effective_cwd,
2930
+ tools=skill_tools,
2931
+ ),
2932
+ )
2895
2933
  return middleware
2896
2934
 
2897
2935
  from deepagents_code._cli_context import INHERIT_CLASSIFIER_MODEL
@@ -3097,14 +3135,11 @@ def create_cli_agent(
3097
3135
 
3098
3136
  # Add skills middleware
3099
3137
  if enable_skills:
3100
- sources = get_skill_sources(
3101
- assistant_id=assistant_id,
3102
- project_context=project_context,
3103
- )
3104
3138
  skills_middleware = PluginSkillsMiddleware(
3105
3139
  backend=FilesystemBackend(virtual_mode=False),
3106
- sources=sources,
3140
+ sources=skill_sources,
3107
3141
  path_base=effective_cwd,
3142
+ tools=skill_tools,
3108
3143
  )
3109
3144
  agent_middleware.append(skills_middleware)
3110
3145
  instruction_middleware.append(skills_middleware)
deepagents_code/app.py CHANGED
@@ -243,7 +243,7 @@ _DEFERRED_START_NOTICE = (
243
243
 
244
244
  _AUTO_CLASSIFIER_RECOMMENDED_MODELS = {
245
245
  "anthropic:claude-haiku-5-5": "Claude Haiku 5.5",
246
- "anthropic:claude-sonnet-5": "Claude Sonnet 5",
246
+ "anthropic:claude-sonnet-5-5": "Claude Sonnet 5.5",
247
247
  "google_genai:gemini-3.8-flash": "Gemini 3.8 Flash",
248
248
  "openai:gpt-6-luna": "GPT-6 Luna",
249
249
  }
@@ -2864,8 +2864,7 @@ class AutoModeHITLMiddleware(HumanInTheLoopMiddleware[AutoModeState, Any, Any]):
2864
2864
  selected,
2865
2865
  # Classifier history never replays thinking blocks,
2866
2866
  # so the Anthropic preserved-thinking binding would only
2867
- # cost it the forced tool call `with_structured_output`
2868
- # relies on.
2867
+ # add latency and cost to every review.
2869
2868
  bind_preserved_thinking=False,
2870
2869
  **retry_kwargs,
2871
2870
  )
@@ -3089,12 +3088,18 @@ class AutoModeHITLMiddleware(HumanInTheLoopMiddleware[AutoModeState, Any, Any]):
3089
3088
  timeout_cm = asyncio.timeout(self._classifier_timeout_seconds)
3090
3089
  try:
3091
3090
  async with timeout_cm:
3092
- thinking = getattr(model, "thinking", None)
3091
+ # Anthropic's native structured output constrains decoding to
3092
+ # the schema. Forced tool calling only suggests it, and Claude
3093
+ # intermittently wraps a valid verdict list in a JSON string or
3094
+ # a placeholder key, which strict validation rejects and the
3095
+ # fail-closed path turns into a denied batch. Models without
3096
+ # native support (Claude 4.1 and earlier) reject the request
3097
+ # outright, so they keep forced tool calling.
3098
+ profile = getattr(model, "profile", None)
3093
3099
  if (
3094
- spec is None
3095
- and getattr(model, "_llm_type", None) == "anthropic-chat"
3096
- and isinstance(thinking, dict)
3097
- and thinking.get("type") in {"adaptive", "enabled"}
3100
+ getattr(model, "_llm_type", None) == "anthropic-chat"
3101
+ and isinstance(profile, dict)
3102
+ and profile.get("structured_output") is True
3098
3103
  ):
3099
3104
  structured = model.with_structured_output(
3100
3105
  _ClassifierBatch, method="json_schema"
@@ -76,7 +76,12 @@ class _ParentGuard:
76
76
 
77
77
 
78
78
  def _main() -> None:
79
- guard = _ParentGuard(int(sys.argv[1]), float(sys.argv[2]))
79
+ reader, *held = (int(fd) for fd in sys.argv[1].split(","))
80
+ for fd in held:
81
+ # Keep the session lock in this process only, so a long-lived
82
+ # grandchild cannot hold the install in use after the server exits.
83
+ os.set_inheritable(fd, False)
84
+ guard = _ParentGuard(reader, float(sys.argv[2]))
80
85
  guard.start()
81
86
  if not guard.begin_dispatch():
82
87
  return
@@ -1039,17 +1039,22 @@ class ServerProcess:
1039
1039
  creationflags=_WINDOWS_CREATE_NEW_PROCESS_GROUP,
1040
1040
  )
1041
1041
 
1042
+ from deepagents_code._session_lock import session_lock_fds
1043
+
1042
1044
  reader, writer = os.pipe() # Both ends are non-inheritable by default.
1043
1045
  self._parent_pipe_writer = writer
1044
1046
  # Abandoning the manager must not leak its writer. Explicit teardown
1045
1047
  # invokes this same finalizer so a reused descriptor is never closed twice.
1046
1048
  self._parent_pipe_finalizer = weakref.finalize(self, os.close, writer)
1049
+ # The session lock keeps the install marked in use while the server
1050
+ # runs, so a migration does not rebuild it underneath.
1051
+ inherited = (reader, *session_lock_fds())
1047
1052
  try:
1048
1053
  return subprocess.Popen( # noqa: S603 # argv is built internally
1049
1054
  [
1050
1055
  *cmd[:2],
1051
1056
  "deepagents_code.client.launch._server_bootstrap",
1052
- str(reader),
1057
+ ",".join(map(str, inherited)),
1053
1058
  str(_SHUTDOWN_TIMEOUT),
1054
1059
  *cmd[3:],
1055
1060
  ],
@@ -1059,7 +1064,7 @@ class ServerProcess:
1059
1064
  stderr=subprocess.STDOUT,
1060
1065
  start_new_session=True,
1061
1066
  creationflags=0,
1062
- pass_fds=(reader,),
1067
+ pass_fds=inherited,
1063
1068
  )
1064
1069
  finally:
1065
1070
  os.close(reader)
deepagents_code/config.py CHANGED
@@ -4685,7 +4685,7 @@ def resolve_auto_classifier_model_with_problem() -> tuple[str | None, str | None
4685
4685
 
4686
4686
 
4687
4687
  _DEFAULT_AUTO_CLASSIFIER_MODELS = {
4688
- "anthropic": "anthropic:claude-sonnet-5",
4688
+ "anthropic": "anthropic:claude-sonnet-5-5",
4689
4689
  "google_genai": "google_genai:gemini-3.8-flash",
4690
4690
  "google_vertexai": "google_vertexai:gemini-3.8-flash",
4691
4691
  "openai": "openai:gpt-5.6-luna",
deepagents_code/main.py CHANGED
@@ -52,6 +52,11 @@ _UNPERSISTED_AUTO_UPDATE_FAILURE_NOTE = (
52
52
  "\n[yellow]Note:[/yellow] this failure could not be recorded, so dcode will "
53
53
  "retry this update on the next launch until the state directory becomes writable."
54
54
  )
55
+ _UNPERSISTED_AUTO_UPDATE_DEFERRAL_NOTE = (
56
+ "\n[yellow]Note:[/yellow] this deferral could not be recorded, so dcode will "
57
+ "announce this update again on the next launch until the state directory "
58
+ "becomes writable."
59
+ )
55
60
 
56
61
 
57
62
  class _TrustAction(Enum):
@@ -457,6 +462,27 @@ def _confirm_update_after_restart(console: Console, version: str) -> None:
457
462
  console.print(f"[green]Updated to v{version}.[/green]", highlight=False)
458
463
 
459
464
 
465
+ def _session_lock_unavailable_note() -> str:
466
+ """Explain a migration deferral that quitting other sessions cannot fix.
467
+
468
+ Returns:
469
+ A line ending in a newline, or an empty string when the session lock
470
+ works and the deferral notice alone is accurate.
471
+ """
472
+ from deepagents_code._session_lock import (
473
+ SESSION_LOCK_FILE,
474
+ session_lock_unavailable,
475
+ )
476
+
477
+ if not session_lock_unavailable():
478
+ return ""
479
+ return (
480
+ f"dcode could not lock {SESSION_LOCK_FILE}, so it cannot tell whether "
481
+ "other sessions are running and will not migrate on its own. Run "
482
+ "`dcode update` instead.\n"
483
+ )
484
+
485
+
460
486
  def _mark_startup_auto_update_failed_safe(version: str) -> None:
461
487
  """Record the auto-update cooldown for *version*, never raising.
462
488
 
@@ -622,10 +648,12 @@ def _run_startup_auto_update(console: Console) -> None:
622
648
  is_update_check_enabled,
623
649
  mark_auto_update_default_acknowledged,
624
650
  mark_startup_auto_update_failed,
651
+ migration_deferral_message,
625
652
  perform_upgrade,
626
653
  release_requires_prereleases,
627
654
  should_announce_auto_update_default,
628
655
  should_skip_startup_auto_update_after_failure,
656
+ startup_auto_update_was_deferred,
629
657
  update_install_lock,
630
658
  upgrade_command,
631
659
  )
@@ -687,12 +715,15 @@ def _run_startup_auto_update(console: Console) -> None:
687
715
  highlight=False,
688
716
  )
689
717
  return
718
+ # A deferred migration is retried as soon as no other session is
719
+ # running; the install lock section decides between migrating and
720
+ # repeating the deferral.
721
+ retrying_deferral = startup_auto_update_was_deferred(latest)
690
722
  if should_skip_startup_auto_update_after_failure(latest):
691
- # A same-version upgrade failed or was deferred recently; retrying
692
- # it here would very likely fail again and re-stall every launch
693
- # (this runs before the TUI). Skip for the cooldown window and
694
- # point at `dcode update`: unlike a bare uv command, it also
695
- # handles a Python migration that startup deferred.
723
+ # A same-version upgrade failed recently; retrying it here would
724
+ # very likely fail again and re-stall every launch (this runs
725
+ # before the TUI). Skip for the cooldown window and point at
726
+ # `dcode update`.
696
727
  from deepagents_code._invocation import invoked_name
697
728
 
698
729
  console.print(
@@ -751,6 +782,23 @@ def _run_startup_auto_update(console: Console) -> None:
751
782
  highlight=False,
752
783
  )
753
784
  return
785
+ # A migration rebuilds the shared tool environment, which would
786
+ # break dcode sessions running in other terminals, so it only runs
787
+ # here when no other session was found at this check.
788
+ from deepagents_code._session_lock import is_sole_session
789
+
790
+ sole_session = is_sole_session()
791
+ if retrying_deferral and not sole_session:
792
+ # Repeat the deferral without re-fetching the release's Python
793
+ # requirement or announcing an update that will not happen.
794
+ console.print(
795
+ f"{migration_deferral_message(latest)}\n"
796
+ f"{_session_lock_unavailable_note()}"
797
+ f"Continuing with v{cli_version}.",
798
+ markup=False,
799
+ highlight=False,
800
+ )
801
+ return
754
802
  release_age = format_release_age_parenthetical(latest)
755
803
  console.print(
756
804
  f"Updating dcode from v{cli_version} to v{latest}{release_age}..."
@@ -775,15 +823,12 @@ def _run_startup_auto_update(console: Console) -> None:
775
823
  notices.append(message)
776
824
  console.print(message, markup=False, highlight=False)
777
825
 
778
- # A Python migration rebuilds the shared tool environment, which
779
- # would break dcode sessions running in other terminals. Defer it
780
- # to an explicit `dcode update`.
781
826
  success, output, _installed = asyncio.run(
782
827
  perform_upgrade(
783
828
  on_notice=show_notice,
784
829
  log_path=log_path,
785
830
  target_version=latest,
786
- allow_python_migration=False,
831
+ allow_python_migration=sole_session,
787
832
  on_migration_deferred=lambda: deferred.append(True),
788
833
  on_unverified_install=lambda: unverified.append(True),
789
834
  )
@@ -841,12 +886,13 @@ def _run_startup_auto_update(console: Console) -> None:
841
886
  _mark_startup_auto_update_failed_safe(latest)
842
887
  _exit_after_unrestartable_update(console, latest)
843
888
  return
844
- persisted = mark_startup_auto_update_failed(latest)
889
+ persisted = mark_startup_auto_update_failed(latest, deferred=bool(deferred))
845
890
  if unverified:
846
891
  _exit_after_unverified_update(console, persisted=persisted)
847
892
  if deferred:
848
893
  # Nothing failed: the notice above explains how to migrate.
849
- message = f"Continuing with v{cli_version}."
894
+ note = escape(_session_lock_unavailable_note())
895
+ message = f"{note}Continuing with v{cli_version}."
850
896
  elif notices:
851
897
  # The notice above carries its own recovery steps; a generic
852
898
  # command here would contradict them.
@@ -867,14 +913,16 @@ def _run_startup_auto_update(console: Console) -> None:
867
913
  f"Run manually: [cyan]{cmd}[/cyan]\n"
868
914
  f"Continuing with v{cli_version}."
869
915
  )
870
- if not persisted and not deferred:
871
- # The cooldown marker could not be saved (e.g. a read-only state
872
- # dir), so this same failing upgrade would otherwise be retried on
873
- # every launch. Surface it rather than silently re-stalling, the
874
- # way the consent-announce path surfaces its un-persisted state.
875
- # After a deferral nothing failed: a lost marker only repeats the
876
- # deferral notice, which installs nothing.
877
- message += _UNPERSISTED_AUTO_UPDATE_FAILURE_NOTE
916
+ if not persisted:
917
+ # The marker could not be saved (e.g. a read-only state dir), so
918
+ # this same upgrade would otherwise be retried on every launch.
919
+ # Surface it rather than silently re-stalling, the way the
920
+ # consent-announce path surfaces its un-persisted state.
921
+ message += (
922
+ _UNPERSISTED_AUTO_UPDATE_DEFERRAL_NOTE
923
+ if deferred
924
+ else _UNPERSISTED_AUTO_UPDATE_FAILURE_NOTE
925
+ )
878
926
  console.print(message, markup=True, highlight=False)
879
927
  except SystemExit:
880
928
  # Process replacement (and test doubles that simulate it), plus the
@@ -2630,7 +2678,7 @@ def parse_args() -> argparse.Namespace:
2630
2678
  dest="auto_classifier_model",
2631
2679
  metavar="MODEL",
2632
2680
  help="Model the Auto approval classifier reviews actions with "
2633
- "(e.g. anthropic:claude-sonnet-5). Local TUI or ACP only. Defaults to "
2681
+ "(e.g. anthropic:claude-sonnet-5-5). Local TUI or ACP only. Defaults to "
2634
2682
  "DEEPAGENTS_CODE_AUTO_CLASSIFIER_MODEL, then [models].auto_classifier, "
2635
2683
  "then a provider-specific model or the main agent model. A weaker model "
2636
2684
  "weakens Auto's review.",
@@ -5520,10 +5568,23 @@ def cli_main() -> None:
5520
5568
  # accessor triggers `_ensure_bootstrap()` (dotenv loading), and
5521
5569
  # commands dispatched below — notably `auth status` — resolve
5522
5570
  # credentials from the environment expecting `.env` to be loaded.
5523
- from deepagents_code.config import _get_credentials, console
5571
+ from deepagents_code.config import (
5572
+ _get_credentials,
5573
+ _is_editable_install,
5574
+ console,
5575
+ )
5524
5576
 
5525
5577
  _get_credentials()
5526
5578
 
5579
+ # Mark this install as in use before anything can migrate it, so a
5580
+ # concurrent launch's auto-update does not rebuild the environment out
5581
+ # from under this process. Editable installs never auto-update, so
5582
+ # nothing reads their registration.
5583
+ if not _is_editable_install():
5584
+ from deepagents_code._session_lock import hold_session_lock
5585
+
5586
+ hold_session_lock()
5587
+
5527
5588
  if command is None:
5528
5589
  # The health gate already ran above, for every command, so the
5529
5590
  # violation check inside cannot fire. Kept as defense in depth: it
@@ -438,6 +438,12 @@ def _validate_server_config(server_name: str, server_config: dict[str, Any]) ->
438
438
  error_msg = f"Server '{server_name}' config must be a dictionary"
439
439
  raise TypeError(error_msg)
440
440
 
441
+ if "skillOnly" in server_config and not isinstance(
442
+ server_config["skillOnly"], bool
443
+ ):
444
+ error_msg = f"Server '{server_name}' 'skillOnly' must be a boolean"
445
+ raise TypeError(error_msg)
446
+
441
447
  server_type = _resolve_server_type(server_config)
442
448
 
443
449
  if server_type in _SUPPORTED_REMOTE_TYPES:
@@ -2295,6 +2301,11 @@ async def _load_tools_from_config(
2295
2301
  for tool in server_tools:
2296
2302
  original_name = (tool.metadata or {})[_MCP_ORIGINAL_TOOL_NAME_KEY]
2297
2303
  tool.name = tool_names[server_name, original_name]
2304
+ if server_config.get("skillOnly"):
2305
+ tool.metadata = {
2306
+ **(tool.metadata or {}),
2307
+ "_deepagents_code_skill_only": True,
2308
+ }
2298
2309
  server_tools = _apply_tool_filter(server_tools, server_name, server_config)
2299
2310
 
2300
2311
  # Pair each schema by the server-side name retained in the adapted
@@ -42,6 +42,7 @@ if TYPE_CHECKING:
42
42
 
43
43
  from deepagents.backends.protocol import BackendProtocol
44
44
  from langchain_core.runnables import RunnableConfig
45
+ from langchain_core.tools import BaseTool
45
46
  from langgraph.runtime import Runtime
46
47
 
47
48
  logger = logging.getLogger(__name__)
@@ -440,6 +441,7 @@ class PluginSkillsMiddleware(SkillsMiddleware):
440
441
  sources: Sequence[CodeSkillSource],
441
442
  system_prompt: str | None = sdk_skills.SKILLS_SYSTEM_PROMPT,
442
443
  path_base: Path | None = None,
444
+ tools: Sequence[BaseTool] = (),
443
445
  ) -> None:
444
446
  """Initialize the middleware with Code-local plugin source tuples.
445
447
 
@@ -451,6 +453,7 @@ class PluginSkillsMiddleware(SkillsMiddleware):
451
453
  path_base: Directory that relative `skills.extra_allowed_dirs`
452
454
  entries resolve against. If `None`, the process working
453
455
  directory is used.
456
+ tools: Tools disclosed only after their skill is read or pinned.
454
457
  """
455
458
  self._allowed_roots = tuple(Path(source[0]).resolve() for source in sources)
456
459
  self._path_base = path_base
@@ -459,6 +462,7 @@ class PluginSkillsMiddleware(SkillsMiddleware):
459
462
  backend=backend,
460
463
  sources=sdk_sources,
461
464
  system_prompt=system_prompt,
465
+ tools=tools,
462
466
  )
463
467
  self._namespaces = tuple(
464
468
  source[2] if len(source) == _PLUGIN_SKILL_SOURCE_LENGTH else None
@@ -277,9 +277,11 @@ RESUME_AUTO_UPDATE_GRACE_PERIOD = 7 * 24 * 60 * 60
277
277
 
278
278
  _STARTUP_AUTO_UPDATE_FAILED_VERSION_KEY = "startup_auto_update_failed_version"
279
279
  _STARTUP_AUTO_UPDATE_FAILED_AT_KEY = "startup_auto_update_failed_at"
280
+ _STARTUP_AUTO_UPDATE_DEFERRED_KEY = "startup_auto_update_deferred"
280
281
  _STARTUP_AUTO_UPDATE_FAILURE_KEYS: tuple[str, ...] = (
281
282
  _STARTUP_AUTO_UPDATE_FAILED_VERSION_KEY,
282
283
  _STARTUP_AUTO_UPDATE_FAILED_AT_KEY,
284
+ _STARTUP_AUTO_UPDATE_DEFERRED_KEY,
283
285
  )
284
286
  _RESUME_AUTO_UPDATE_DEFERRED_AT_KEY = "resume_auto_update_deferred_at"
285
287
 
@@ -1323,19 +1325,32 @@ def clear_resume_auto_update_deferral() -> None:
1323
1325
 
1324
1326
 
1325
1327
  def should_skip_startup_auto_update_after_failure(version: str) -> bool:
1326
- """Return whether startup auto-update should skip a recently failed version."""
1328
+ """Return whether startup auto-update should skip a recently failed version.
1329
+
1330
+ A deferred migration is not a failure, so it never starts the cooldown.
1331
+ """
1327
1332
  data = _read_update_state()
1328
1333
  failed_version = data.get(_STARTUP_AUTO_UPDATE_FAILED_VERSION_KEY)
1329
1334
  failed_at = data.get(_STARTUP_AUTO_UPDATE_FAILED_AT_KEY)
1330
1335
  return bool(
1331
1336
  failed_version == version
1337
+ and data.get(_STARTUP_AUTO_UPDATE_DEFERRED_KEY) is not True
1332
1338
  and isinstance(failed_at, (int, float))
1333
1339
  and time.time() - failed_at < STARTUP_AUTO_UPDATE_FAILURE_COOLDOWN
1334
1340
  )
1335
1341
 
1336
1342
 
1337
- def mark_startup_auto_update_failed(version: str) -> bool:
1338
- """Persist a same-version startup auto-update retry cooldown marker.
1343
+ def mark_startup_auto_update_failed(version: str, *, deferred: bool = False) -> bool:
1344
+ """Persist a same-version marker for a failed or deferred startup auto-update.
1345
+
1346
+ Only a failure starts a retry cooldown; a deferral is retried on the next
1347
+ launch that finds no other session running.
1348
+
1349
+ Args:
1350
+ version: Target version the attempt did not install.
1351
+ deferred: Whether the attempt deliberately deferred a Python migration
1352
+ rather than failing, so the next launch can say so and retry once
1353
+ no other session is running.
1339
1354
 
1340
1355
  Returns:
1341
1356
  `True` if the marker was written, `False` otherwise.
@@ -1344,10 +1359,20 @@ def mark_startup_auto_update_failed(version: str) -> bool:
1344
1359
  {
1345
1360
  _STARTUP_AUTO_UPDATE_FAILED_VERSION_KEY: version,
1346
1361
  _STARTUP_AUTO_UPDATE_FAILED_AT_KEY: time.time(),
1362
+ _STARTUP_AUTO_UPDATE_DEFERRED_KEY: deferred,
1347
1363
  }
1348
1364
  )
1349
1365
 
1350
1366
 
1367
+ def startup_auto_update_was_deferred(version: str) -> bool:
1368
+ """Return whether the last startup attempt at `version` deferred a migration."""
1369
+ data = _read_update_state()
1370
+ return (
1371
+ data.get(_STARTUP_AUTO_UPDATE_FAILED_VERSION_KEY) == version
1372
+ and data.get(_STARTUP_AUTO_UPDATE_DEFERRED_KEY) is True
1373
+ )
1374
+
1375
+
1351
1376
  def clear_startup_auto_update_failure(version: str) -> None:
1352
1377
  """Clear a startup auto-update failure marker for `version` if present."""
1353
1378
  data = _read_update_state()
@@ -2761,7 +2786,7 @@ def _migration_notice(target_version: str) -> str:
2761
2786
  )
2762
2787
 
2763
2788
 
2764
- def _migration_deferral_message(target_version: str) -> str:
2789
+ def migration_deferral_message(target_version: str) -> str:
2765
2790
  """Return the guidance for a migration that this caller may not run.
2766
2791
 
2767
2792
  Returns:
@@ -3043,7 +3068,7 @@ async def perform_upgrade(
3043
3068
  and (not allow_python_migration or _is_windows())
3044
3069
  ):
3045
3070
  logger.info("Deferred the Python 3.14 migration for v%s", target_version)
3046
- guidance = _migration_deferral_message(target_version)
3071
+ guidance = migration_deferral_message(target_version)
3047
3072
  # Flag first: if showing the notice raises, the caller must still
3048
3073
  # report a deferral rather than a failure.
3049
3074
  if on_migration_deferred is not None:
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: deepagents-code
3
- Version: 0.2.0
3
+ Version: 0.2.1
4
4
  Summary: Terminal coding agent built on the Deep Agents SDK - works with any model, with persistent memory, customizable skills, subagents, and approval controls.
5
5
  Project-URL: Homepage, https://www.langchain.com/dcode
6
6
  Project-URL: Documentation, https://docs.langchain.com/oss/deepagents/code/overview
@@ -28,7 +28,7 @@ Requires-Python: <3.15,>=3.14
28
28
  Requires-Dist: aiosqlite>=0.22.1
29
29
  Requires-Dist: anyio>=4.14.2
30
30
  Requires-Dist: deepagents-acp<1.0.0,>=0.0.10
31
- Requires-Dist: deepagents==0.7.30
31
+ Requires-Dist: deepagents==0.7.31
32
32
  Requires-Dist: fastmcp>=4.0.0b4
33
33
  Requires-Dist: filelock<3.30,>=3.29.7
34
34
  Requires-Dist: genai-prices<0.2.0,>=0.1.13
@@ -40,7 +40,7 @@ Requires-Dist: langchain-quickjs<0.4.0,>=0.3.4
40
40
  Requires-Dist: langchain<2.0.0,>=1.4.7
41
41
  Requires-Dist: langgraph-checkpoint-sqlite<4.0.0,>=3.1.2
42
42
  Requires-Dist: langgraph-cli[inmem]<1.0.0,>=0.4.37
43
- Requires-Dist: langgraph-runtime-inmem<1.0.0,>=0.36.4
43
+ Requires-Dist: langgraph-runtime-inmem<1.0.0,>=0.36.5
44
44
  Requires-Dist: langgraph-sdk<1.0.0,>=0.4.8
45
45
  Requires-Dist: langsmith[sandbox]>=0.14.12
46
46
  Requires-Dist: markdownify>=1.2.3
@@ -2,7 +2,7 @@ deepagents_code/__init__.py,sha256=73a8obvgWKoHOkvV-npfpuJwVQTq4fy56ITb8ZkuTVo,2
2
2
  deepagents_code/__main__.py,sha256=5ew3bdnHNft6Pbx9Svfs8jkvPwVOmRBsY5hubL2OicY,142
3
3
  deepagents_code/_ask_user_types.py,sha256=YqyBfBlW1J7LpHqsN3seOnMX0MqdM11lGoFRXkxwHuw,30794
4
4
  deepagents_code/_async.py,sha256=oONFzkt5GsIAYIyU2-OHRBOuxifWcZKuBqO4INxP1uE,711
5
- deepagents_code/_build_info.py,sha256=jtZTijHLu6AerW-5vL_271KLG7G9dv18sBc4K_OrDsA,80
5
+ deepagents_code/_build_info.py,sha256=jjY6ObKm0gq6ot69nPy7NN3Kjxxa9sTM_ieu3rGwMS4,80
6
6
  deepagents_code/_cli_context.py,sha256=BsjGF9ytVLsVexLLKnHeLXDsSUgK2clpAUlW4eNJMC8,10345
7
7
  deepagents_code/_constants.py,sha256=ho8IHzookJPAgUPkAbtttKADbEu2BoyUYAcLMBp8wME,4976
8
8
  deepagents_code/_content_blocks.py,sha256=RhKMm25MId1bvPrhGV8bKGPLIhVcuG0DRX4gh_HJ-xU,1116
@@ -21,6 +21,7 @@ deepagents_code/_paths.py,sha256=nOWdjxHzadfJiyKZO2Fj8hIzD_Vzl6RHsmm-U4af8Ck,364
21
21
  deepagents_code/_repository_bounds.py,sha256=dTeooOMgNyXHloVrqdFFNbJ8PJfmWdNHHY_OzP21s2w,18917
22
22
  deepagents_code/_reserved_names.py,sha256=tNWxxKryYMaiepjhM3Fmoy8bMxa3C0trSYpQxsL8QBA,5373
23
23
  deepagents_code/_server_config.py,sha256=4WOeZA1nRPmRs0rk4c7dMUSI1mDDS8HbYJHhrpO0oU0,46412
24
+ deepagents_code/_session_lock.py,sha256=W0hz4204unsrYVmLZNU7-Pp3ZBK9uFtBtdVUVNrIIz0,6783
24
25
  deepagents_code/_session_stats.py,sha256=fr6tZkpnxXkRIk2QuvsykobXWUpeLWKWis6pcY96h9s,62210
25
26
  deepagents_code/_startup_error.py,sha256=ckxykiVyVpK3lWBJjWxut4xIhfvc44qkypZXJaMBlzI,5059
26
27
  deepagents_code/_terminal_stderr.py,sha256=MzdL-tbEDzM9IGWVrWhihpySMALN6tfHtBtU5JTOVMI,6889
@@ -29,16 +30,16 @@ deepagents_code/_textual_patches.py,sha256=ff7_2yMS1wWYMv5luvjRcKAxwHRRp_4Ly6bu4
29
30
  deepagents_code/_tool_free.py,sha256=i2-Ycq3gp7zT3UyagDSd4-5O9kigprR137ptO70hpfE,2252
30
31
  deepagents_code/_tool_stream.py,sha256=lXVM-0gObwmkik8ElEoPwaZI3PPq_ATar1fvPraW5Vk,39111
31
32
  deepagents_code/_tracing.py,sha256=-Zucmritu9TreUHFcpwjiwPxkqmeJleL4dTDxKqPzLk,2530
32
- deepagents_code/_version.py,sha256=qy1dO1KRbdh4Y6JJ60Nh0FMyqGufkD5KkdCSxEn-Nzw,975
33
+ deepagents_code/_version.py,sha256=0Z5h2XVHXBcadlAd1dK5BLP0HfSWrQyfu_YqeHiselw,975
33
34
  deepagents_code/acp.py,sha256=WCJcpmvUU_lX8yutv3CESV6TG5xPY6AflK0hFwSbuy8,4525
34
- deepagents_code/agent.py,sha256=B8qNUk-anYi09aiZjLGDPWtiofhLbukhF1eeD35S5L4,153404
35
- deepagents_code/app.py,sha256=hj8x6_LIdTK3Uv_lxqB__zeimfIX6uKXRuJLGacxWtI,1407115
35
+ deepagents_code/agent.py,sha256=Q6uusd_NSxf6oszW3c9F1MoHCulpu1ThK-ESAxJO7KQ,154634
36
+ deepagents_code/app.py,sha256=KKiyXHqvRUsgErw0W6_K8s_6qKwBzU8GnZlb392iR6U,1407119
36
37
  deepagents_code/app.tcss,sha256=5-LyCr0t0Bwl9o2ydzTduYqTqsnayIrU3iH63qSlmjA,10711
37
38
  deepagents_code/approval_mode.py,sha256=CTBUNNuXalzj5NxYeT0m3xH2d675JE5uT9fxZ0YhJZ4,19336
38
39
  deepagents_code/ask_user.py,sha256=ice3x1SsOyXGoxpzM60MfuVxlVJGapOa782mxw7GVVo,24499
39
40
  deepagents_code/auth_display.py,sha256=0j_S1f6-csuknYxfc3HtnkSQb18ozv2zi3cpjaCE4aY,6573
40
41
  deepagents_code/auth_store.py,sha256=mTFneywYi4eaOL7Hpv6ORASXfOzIC-kIDgNgTvkrqiM,21145
41
- deepagents_code/auto_mode.py,sha256=MmVEJxW4ENDg6ZJLHo34GLa4mnLInG73a4jol9tkWB0,178148
42
+ deepagents_code/auto_mode.py,sha256=Msx1LOA-InZCOpV7I6glTOy6NAQC-zbrTa64u0gkly8,178578
42
43
  deepagents_code/btw.py,sha256=uckPQrEE2jWbnFem4Eh9puzpxIpW1eldxB_u_yLZNHQ,22756
43
44
  deepagents_code/btw_api.py,sha256=O-hngehTKXg2135r9EdBNvEPLzPh9kTZaSqt45GQ9ws,9282
44
45
  deepagents_code/btw_cost.py,sha256=aYg5R3qy75o7Wg5jbCqSh7OLBExscdwExk41wpRMC3U,8202
@@ -47,7 +48,7 @@ deepagents_code/bundled_prices.json,sha256=4QrFzlEKLOmOC9vAf2fxPTJqNhSr3tY02vMQI
47
48
  deepagents_code/clipboard.py,sha256=aTwllmEigtxFMbD8w8fewtxRV_4YuSO5UfncMNcA3Vc,7498
48
49
  deepagents_code/cold_cache.py,sha256=KK1GAvjW7YtrJzB8K-nQTqu0Pr5uA5llZMD59IqGvYc,50482
49
50
  deepagents_code/command_registry.py,sha256=I8VWy3QTKUHL5aSyj5RQ52VIZHvFmUHDPTtABZFpEw8,21101
50
- deepagents_code/config.py,sha256=pNsDPFEyyPZlvKVCuNI8k2dRL-Uo55lXxkntecItuZo,291496
51
+ deepagents_code/config.py,sha256=U4HWRDEbR-I1pApBwZak3OeH0y7ohNXuIoSe4ItlopM,291498
51
52
  deepagents_code/config_manifest.py,sha256=mHXVkBjv73SIB708Y6HsCSPTiv_QsONMJX8KlfBRE18,133205
52
53
  deepagents_code/configurable_model.py,sha256=ulrM0mQWB8RVLQVPt-_LLndGHnaIIKKNdfSYcRQr8ss,44643
53
54
  deepagents_code/context_doctor.py,sha256=Rp0Am6Gdfnievs5NslNxtzRM9ClfL-FMkYPA4ivsu44,9584
@@ -68,7 +69,7 @@ deepagents_code/input.py,sha256=WwrD0UMJ3x-Y6bgfVVJYBsj7e9noHyu9b6BE-i42hnM,3859
68
69
  deepagents_code/iterm_cursor_guide.py,sha256=l2lcBb9N84ucTEsdI-SHBQ2h6grddNaXNMdLCLWewY8,5989
69
70
  deepagents_code/json_types.py,sha256=lwkG1m0-flVumX4an4zaK4nLpkbAAl3tqJqUaOBy7SY,616
70
71
  deepagents_code/local_context.py,sha256=nK3-5mdjONUhKeuyXKsZ4x-R7dZTEA38UIgZy6Bb448,36239
71
- deepagents_code/main.py,sha256=Vkl6yeJ4Pau6a0A2rfcHkgzH5xzu2vsZBo1kdoIAVMQ,277345
72
+ deepagents_code/main.py,sha256=VKNuCJZkOEEMkc6kCSzw3kxEaEAldYEhlr8PAr_qxvg,279665
72
73
  deepagents_code/managed_tools.py,sha256=_UdVnot-sf7hbDzgPirHZXgp3l3G5DFuhuVL43vJfIQ,32993
73
74
  deepagents_code/mcp_auth.py,sha256=wccHG5-G8Rw1MzWvJAZ_L0dcpTpf0aLWuGSYNLMkzPY,94209
74
75
  deepagents_code/mcp_config.py,sha256=3gcdbs13V3O5GizojB3rlgUbcbUDrFv9t2t_52yAkFU,7951
@@ -77,7 +78,7 @@ deepagents_code/mcp_login_service.py,sha256=wJWX_b8uxE_iXiHdkvEjcnWKxjwxmVZswaii
77
78
  deepagents_code/mcp_middleware.py,sha256=Oy6QvDpuKUOPqO-TEa3KoFsl3gT8RNLws_QlKWkySDY,6992
78
79
  deepagents_code/mcp_oauth_ui.py,sha256=ylP11W8Aod219Xir_CYMBibnPH1rSC7s0hzyksjJo8A,8552
79
80
  deepagents_code/mcp_proxy.py,sha256=qyMJmDvDjO8wD7GsPCuoKv_txdjYT7xdZ9WQ5cHnYkA,5675
80
- deepagents_code/mcp_tools.py,sha256=NfTFGIheR4bP_Gf2sCtzwBIsAXWQmr6MguWuxC-VFVI,113925
81
+ deepagents_code/mcp_tools.py,sha256=kTppibNQUDJRucBYJT8dlH0FtV5bDqHcqy_E40qDM54,114362
81
82
  deepagents_code/media_utils.py,sha256=xLecgZ5eczNa9QdSYfGYqBEKXVb4El8HN8ir8Rj99_Q,21682
82
83
  deepagents_code/memory_guard.py,sha256=p5nRFgcziaCwqjR8Gg6Qu5t9x1rp2QbwRtlCpRpJ2JE,19735
83
84
  deepagents_code/model_api.py,sha256=nXA1YU0S-jrJQBNh9frY9TqOskgPC-Du3vb-F0KH9qs,8484
@@ -114,7 +115,7 @@ deepagents_code/tool_display.py,sha256=0TCgsG-K5-zEdE6MAf14K_i6X0c0JlILWLlgeYhPv
114
115
  deepagents_code/tools.py,sha256=LDRNbQvbH1in4o0Vgs8hHmTmaMoYNihsDmnreiEErak,21518
115
116
  deepagents_code/ui.py,sha256=2ap3mU6WYXGv8MbI1EehiDicbUb6Wp9nc9ZwhfOjpxE,41149
116
117
  deepagents_code/unicode_security.py,sha256=1j5lZPnsdQiKwMH9uCa_nfSaL6eCWvpM-nb2ECZbSFk,18563
117
- deepagents_code/update_check.py,sha256=3iTFa2FUw9BetwJXmimBx-gHno0PjhpCuL1VIef6ep8,205101
118
+ deepagents_code/update_check.py,sha256=GFA9AKIB1WtJe-92oWC7jVBUaUxw2VTchedsQgbeTU8,206177
118
119
  deepagents_code/workspace.py,sha256=khy70RiXA4jfvaiULJUaUPNm3fi8eK6cpS-Xu0p2hg0,32422
119
120
  deepagents_code/workspace_diagnostics.py,sha256=ZpW4i2_y2q7DOFD351hPabYBB-PR_MjgsgbKoRr8j8g,15882
120
121
  deepagents_code/built_in_skills/__init__.py,sha256=eBIGmXIRC-wrHxfYaY6C536YQ-VlTXHkZ6JgRL5J7jc,190
@@ -137,8 +138,8 @@ deepagents_code/client/commands/extras.py,sha256=hAd8CD5t93Cw_RBhKqO5rMxEw8THi0S
137
138
  deepagents_code/client/commands/mcp.py,sha256=skQyORq7w2E2fLiA5g-sNAt4LRHMcT81YMQHiCdembk,16899
138
139
  deepagents_code/client/commands/tools.py,sha256=y5NaeiJL4TYjyJfxukKfkj3jSa4h-m71j-HOSQ1oqWA,15858
139
140
  deepagents_code/client/launch/__init__.py,sha256=yMGWZVpgZYkij5Jq8tTqhcigpppuTVazMmIYCNImiwk,74
140
- deepagents_code/client/launch/_server_bootstrap.py,sha256=W4ImjLRCxcrlZtj_zG3iJaOA1bmKEM7-Fh9z8tccogk,2964
141
- deepagents_code/client/launch/server.py,sha256=lcvMKwhO4mGgLyN1lmSxUCo0qPaBmW2ytGaJorBPykU,52107
141
+ deepagents_code/client/launch/_server_bootstrap.py,sha256=1shrnMvuILAsSXGsU5xh5D-Ds2BdfrkEyTIK8s2muuI,3221
142
+ deepagents_code/client/launch/server.py,sha256=nJl6wb41-jAvpRAtzbCp92-EUOGAog4AKFg0RcONW24,52382
142
143
  deepagents_code/client/launch/server_manager.py,sha256=rx_mUDrxprVPzppypFD9DyWVyYCxg8smpm1icWXIEGs,25849
143
144
  deepagents_code/configuration/__init__.py,sha256=N3X7ng0ngwGaLdUmXrexUDeN00oaiCDuhXSPZtrjE6E,1147
144
145
  deepagents_code/configuration/interpreter.py,sha256=NqyF3o9Gv9DdssV9Z3S0i0YwLaqyGLLkJRaRSN_k0Sw,3575
@@ -214,7 +215,7 @@ deepagents_code/plugins/adapters/__init__.py,sha256=ZB8FkoIuMIXI_EBtDrwbTUg9FryL
214
215
  deepagents_code/plugins/adapters/hooks.py,sha256=tkk1WBe4GqX6zzslMjflr9R1lDhOThyE1Gds0-OuYaQ,5617
215
216
  deepagents_code/plugins/adapters/mcp.py,sha256=7Xf3W4XwuwmxT2AjoyyUNanEIX3SK5IAdnrl1oFgmvY,8885
216
217
  deepagents_code/plugins/adapters/skills.py,sha256=Fv6TRoyZ4jbob4WcoIhfFtrEbi5PLe1S7X_D6BxIfWs,4348
217
- deepagents_code/plugins/adapters/skills_middleware.py,sha256=gEn-smZwdGDjuBEl3_VvIFBgoX0nNtDv4OtxNf7mieI,27085
218
+ deepagents_code/plugins/adapters/skills_middleware.py,sha256=F7IBOj7IQHTLZVsxUwu3v9QtfG8eqlolee44qug9PUI,27273
218
219
  deepagents_code/skills/__init__.py,sha256=jUERq___q_hZT8SFqGHrgnSbYg4X_qAq1pmx_uYNLRM,440
219
220
  deepagents_code/skills/commands.py,sha256=9YKY3aa2lN8JBpNz8poGhxz4SCeZucJ7NCFgaYZLqJ4,44378
220
221
  deepagents_code/skills/invocation.py,sha256=yEGadCEEWi4ywbrHh0gV7HiTtXoVw-Iao7ZR5QpoyhM,8296
@@ -300,9 +301,9 @@ deepagents_code/tui/widgets/update_confirm.py,sha256=OUH1s5hTJpXJE63SpukBFgKvR2k
300
301
  deepagents_code/tui/widgets/update_progress.py,sha256=wkTgN7YlvJYrwDzhh4gxbA4ac15RpMAmyWd9CTiZlJw,10672
301
302
  deepagents_code/tui/widgets/welcome.py,sha256=8oFyMjfqy1pLTdfbZeoCjr20YjKVqFOb5l0hfO-e-8A,23196
302
303
  deepagents_code/tui/widgets/yolo_mode_notice.py,sha256=_Qt2Z5Of3EyY27_K28gUkaKyUZo0zH8nZljEB768JEg,6497
303
- deepagents_code-0.2.0.data/data/deepagents_code/default_agent_prompt.md,sha256=4I23oEsscs0X-VqXJ6JiC_Tl3FV0f-Na4iIbs5tqVbQ,336
304
- deepagents_code-0.2.0.dist-info/METADATA,sha256=fqDJzZCSRfkHVjx61tr_8taIrPbE1uVs0G0x8KZDw5M,11568
305
- deepagents_code-0.2.0.dist-info/WHEEL,sha256=W3fkpkm7-wf9vBI5Z-7s0eWkeM-spu78I8Neb98DeEg,87
306
- deepagents_code-0.2.0.dist-info/entry_points.txt,sha256=_6mmNRQU3vBqMDX-REOesqVwwqijvs-WASYDEvasGzQ,94
307
- deepagents_code-0.2.0.dist-info/licenses/LICENSE,sha256=TsZ-TKbmch26hJssqCJhWXyGph7iFLvyFBYAa3stBHg,1067
308
- deepagents_code-0.2.0.dist-info/RECORD,,
304
+ deepagents_code-0.2.1.data/data/deepagents_code/default_agent_prompt.md,sha256=4I23oEsscs0X-VqXJ6JiC_Tl3FV0f-Na4iIbs5tqVbQ,336
305
+ deepagents_code-0.2.1.dist-info/METADATA,sha256=DlRMxDJ-FzQJTqmnQi7YWzel9_f48meKuw6rjE3YR40,11568
306
+ deepagents_code-0.2.1.dist-info/WHEEL,sha256=W3fkpkm7-wf9vBI5Z-7s0eWkeM-spu78I8Neb98DeEg,87
307
+ deepagents_code-0.2.1.dist-info/entry_points.txt,sha256=_6mmNRQU3vBqMDX-REOesqVwwqijvs-WASYDEvasGzQ,94
308
+ deepagents_code-0.2.1.dist-info/licenses/LICENSE,sha256=TsZ-TKbmch26hJssqCJhWXyGph7iFLvyFBYAa3stBHg,1067
309
+ deepagents_code-0.2.1.dist-info/RECORD,,