delos-cli 2.1.0__tar.gz → 5.9.15__tar.gz

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.
Files changed (82) hide show
  1. {delos_cli-2.1.0 → delos_cli-5.9.15}/.gitignore +32 -10
  2. {delos_cli-2.1.0 → delos_cli-5.9.15}/PKG-INFO +5 -3
  3. delos_cli-5.9.15/delos_cli/__main__.py +10 -0
  4. delos_cli-5.9.15/delos_cli/_build.json +5 -0
  5. {delos_cli-2.1.0 → delos_cli-5.9.15}/delos_cli/auth/config.py +35 -7
  6. {delos_cli-2.1.0 → delos_cli-5.9.15}/delos_cli/commands/prompts.py +2 -2
  7. {delos_cli-2.1.0 → delos_cli-5.9.15}/delos_cli/public_key.py +1 -1
  8. {delos_cli-2.1.0 → delos_cli-5.9.15}/delos_cli/serve/confirm.py +3 -0
  9. {delos_cli-2.1.0 → delos_cli-5.9.15}/delos_cli/serve/rpc.py +42 -15
  10. {delos_cli-2.1.0 → delos_cli-5.9.15}/delos_cli/telemetry.py +4 -0
  11. {delos_cli-2.1.0 → delos_cli-5.9.15}/delos_cli/tools/glob_tool.py +3 -12
  12. {delos_cli-2.1.0 → delos_cli-5.9.15}/delos_cli/tools/grep.py +1 -1
  13. delos_cli-5.9.15/delos_cli/transport/models.py +50 -0
  14. {delos_cli-2.1.0 → delos_cli-5.9.15}/pyproject.toml +12 -4
  15. delos_cli-2.1.0/.claude/settings.local.json +0 -8
  16. delos_cli-2.1.0/delos_cli/_build.json +0 -1
  17. delos_cli-2.1.0/delos_cli/transport/models.py +0 -19
  18. {delos_cli-2.1.0 → delos_cli-5.9.15}/README.md +0 -0
  19. {delos_cli-2.1.0 → delos_cli-5.9.15}/delos_cli/__init__.py +0 -0
  20. {delos_cli-2.1.0 → delos_cli-5.9.15}/delos_cli/agent/__init__.py +0 -0
  21. {delos_cli-2.1.0 → delos_cli-5.9.15}/delos_cli/agent/session.py +0 -0
  22. {delos_cli-2.1.0 → delos_cli-5.9.15}/delos_cli/agent/tools.py +0 -0
  23. {delos_cli-2.1.0 → delos_cli-5.9.15}/delos_cli/agent/transport.py +0 -0
  24. {delos_cli-2.1.0 → delos_cli-5.9.15}/delos_cli/agent/turn.py +0 -0
  25. {delos_cli-2.1.0 → delos_cli-5.9.15}/delos_cli/apps/__init__.py +0 -0
  26. {delos_cli-2.1.0 → delos_cli-5.9.15}/delos_cli/apps/base.py +0 -0
  27. {delos_cli-2.1.0 → delos_cli-5.9.15}/delos_cli/apps/chat/__init__.py +0 -0
  28. {delos_cli-2.1.0 → delos_cli-5.9.15}/delos_cli/apps/chat/app.py +0 -0
  29. {delos_cli-2.1.0 → delos_cli-5.9.15}/delos_cli/apps/chat/commands.py +0 -0
  30. {delos_cli-2.1.0 → delos_cli-5.9.15}/delos_cli/apps/chat/render.py +0 -0
  31. {delos_cli-2.1.0 → delos_cli-5.9.15}/delos_cli/apps/replay.py +0 -0
  32. {delos_cli-2.1.0 → delos_cli-5.9.15}/delos_cli/apps/scribe/__init__.py +0 -0
  33. {delos_cli-2.1.0 → delos_cli-5.9.15}/delos_cli/apps/scribe/app.py +0 -0
  34. {delos_cli-2.1.0 → delos_cli-5.9.15}/delos_cli/apps/scribe/commands.py +0 -0
  35. {delos_cli-2.1.0 → delos_cli-5.9.15}/delos_cli/apps/scribe/tools.py +0 -0
  36. {delos_cli-2.1.0 → delos_cli-5.9.15}/delos_cli/auth/__init__.py +0 -0
  37. {delos_cli-2.1.0 → delos_cli-5.9.15}/delos_cli/auth/mfa.py +0 -0
  38. {delos_cli-2.1.0 → delos_cli-5.9.15}/delos_cli/auth/oauth.py +0 -0
  39. {delos_cli-2.1.0 → delos_cli-5.9.15}/delos_cli/auth/token_manager.py +0 -0
  40. {delos_cli-2.1.0 → delos_cli-5.9.15}/delos_cli/commands/__init__.py +0 -0
  41. {delos_cli-2.1.0 → delos_cli-5.9.15}/delos_cli/commands/base.py +0 -0
  42. {delos_cli-2.1.0 → delos_cli-5.9.15}/delos_cli/commands/builtin.py +0 -0
  43. {delos_cli-2.1.0 → delos_cli-5.9.15}/delos_cli/context_report.py +0 -0
  44. {delos_cli-2.1.0 → delos_cli-5.9.15}/delos_cli/ctx.py +0 -0
  45. {delos_cli-2.1.0 → delos_cli-5.9.15}/delos_cli/git_context.py +0 -0
  46. {delos_cli-2.1.0 → delos_cli-5.9.15}/delos_cli/loop.py +0 -0
  47. {delos_cli-2.1.0 → delos_cli-5.9.15}/delos_cli/main.py +0 -0
  48. {delos_cli-2.1.0 → delos_cli-5.9.15}/delos_cli/project_context.py +0 -0
  49. {delos_cli-2.1.0 → delos_cli-5.9.15}/delos_cli/sentry_identity.py +0 -0
  50. {delos_cli-2.1.0 → delos_cli-5.9.15}/delos_cli/serve/__init__.py +0 -0
  51. {delos_cli-2.1.0 → delos_cli-5.9.15}/delos_cli/serve/app.py +0 -0
  52. {delos_cli-2.1.0 → delos_cli-5.9.15}/delos_cli/serve/protocol.py +0 -0
  53. {delos_cli-2.1.0 → delos_cli-5.9.15}/delos_cli/serve/server.py +0 -0
  54. {delos_cli-2.1.0 → delos_cli-5.9.15}/delos_cli/state.py +0 -0
  55. {delos_cli-2.1.0 → delos_cli-5.9.15}/delos_cli/tools/__init__.py +0 -0
  56. {delos_cli-2.1.0 → delos_cli-5.9.15}/delos_cli/tools/ask_user_input.py +0 -0
  57. {delos_cli-2.1.0 → delos_cli-5.9.15}/delos_cli/tools/edit_content.py +0 -0
  58. {delos_cli-2.1.0 → delos_cli-5.9.15}/delos_cli/tools/explore.py +0 -0
  59. {delos_cli-2.1.0 → delos_cli-5.9.15}/delos_cli/tools/read.py +0 -0
  60. {delos_cli-2.1.0 → delos_cli-5.9.15}/delos_cli/tools/run_shell.py +0 -0
  61. {delos_cli-2.1.0 → delos_cli-5.9.15}/delos_cli/tools/task.py +0 -0
  62. {delos_cli-2.1.0 → delos_cli-5.9.15}/delos_cli/tools/todo_write.py +0 -0
  63. {delos_cli-2.1.0 → delos_cli-5.9.15}/delos_cli/tools/verify.py +0 -0
  64. {delos_cli-2.1.0 → delos_cli-5.9.15}/delos_cli/tools/write_content.py +0 -0
  65. {delos_cli-2.1.0 → delos_cli-5.9.15}/delos_cli/transport/__init__.py +0 -0
  66. {delos_cli-2.1.0 → delos_cli-5.9.15}/delos_cli/transport/chats.py +0 -0
  67. {delos_cli-2.1.0 → delos_cli-5.9.15}/delos_cli/transport/client.py +0 -0
  68. {delos_cli-2.1.0 → delos_cli-5.9.15}/delos_cli/transport/documents.py +0 -0
  69. {delos_cli-2.1.0 → delos_cli-5.9.15}/delos_cli/transport/integrations.py +0 -0
  70. {delos_cli-2.1.0 → delos_cli-5.9.15}/delos_cli/ui/__init__.py +0 -0
  71. {delos_cli-2.1.0 → delos_cli-5.9.15}/delos_cli/ui/banner.py +0 -0
  72. {delos_cli-2.1.0 → delos_cli-5.9.15}/delos_cli/ui/chat_picker.py +0 -0
  73. {delos_cli-2.1.0 → delos_cli-5.9.15}/delos_cli/ui/collapse.py +0 -0
  74. {delos_cli-2.1.0 → delos_cli-5.9.15}/delos_cli/ui/completer.py +0 -0
  75. {delos_cli-2.1.0 → delos_cli-5.9.15}/delos_cli/ui/document_picker.py +0 -0
  76. {delos_cli-2.1.0 → delos_cli-5.9.15}/delos_cli/ui/integrations_picker.py +0 -0
  77. {delos_cli-2.1.0 → delos_cli-5.9.15}/delos_cli/ui/lexer.py +0 -0
  78. {delos_cli-2.1.0 → delos_cli-5.9.15}/delos_cli/ui/model_picker.py +0 -0
  79. {delos_cli-2.1.0 → delos_cli-5.9.15}/delos_cli/ui/output.py +0 -0
  80. {delos_cli-2.1.0 → delos_cli-5.9.15}/delos_cli/ui/repl.py +0 -0
  81. {delos_cli-2.1.0 → delos_cli-5.9.15}/delos_cli/ui/style.py +0 -0
  82. {delos_cli-2.1.0 → delos_cli-5.9.15}/delos_cli/usage_report.py +0 -0
@@ -2,6 +2,8 @@ knip.txt
2
2
  pentest-*
3
3
  backend/.vscode
4
4
  backend/cosmos_env
5
+ # convert_scribes_to_docx.py run log (projects/1015_scribe_decoupling)
6
+ backend/scribe_conversion.jsonl
5
7
  # Allow backend/.env (has safe localhost defaults), but ignore all other .env files
6
8
  apps/**/.env
7
9
  collab/.env
@@ -21,26 +23,33 @@ infrastructure/supabase/**/.env
21
23
  backend/.python-version
22
24
  /scripts/
23
25
  */scripts/
26
+ !packages/cms/shared/scripts/
24
27
  !tooling/scripts/
25
28
  # Re-include the tools-catalog export script (CI drift test imports it)
26
29
  !backend/scripts/
27
30
  backend/scripts/*
28
31
  !backend/scripts/__init__.py
29
32
  !backend/scripts/export_tools_catalog.py
33
+ !backend/scripts/export_module_catalog.py
34
+ !backend/scripts/export_microsoft_capabilities.py
30
35
  !backend/scripts/check_supabase_models.py
31
36
  !backend/scripts/dump_openapi.py
32
37
  !backend/scripts/backfill_agent_issues.py
33
38
  !backend/scripts/backfill_directive_recurrence.py
34
39
  !backend/scripts/analyze_prompt_dumps.py
35
40
  !backend/scripts/check_route_response_types.py
41
+ !backend/scripts/check_usage_export.py
36
42
  !backend/scripts/fly_source_recovery.py
37
43
  !backend/scripts/audit_sprite_regions.py
38
44
  !backend/scripts/migrate_vibe_sprites.py
45
+ !backend/scripts/requeue_mail_file_processing.py
46
+ !backend/scripts/dedupe_outlook_mail.py
39
47
 
40
48
  .claude/worktrees
41
49
 
42
50
  data/documents2
43
51
  data/logs
52
+ .data/database-service
44
53
  **/**0
45
54
  _local
46
55
  .env.old
@@ -86,12 +95,9 @@ dist/
86
95
  *.pem
87
96
 
88
97
  # pnpm is the only package manager here, including the standalone services.
89
- # One recorded exception: cvn/whatsapp-bridge is an npm-managed runtime sidecar
90
- # (baileys needs the git-only `libsignal`, which blockExoticSubdeps rejects and
91
- # pnpm has no scoped exception for — pnpm/pnpm#11799); its lockfile is tracked
92
- # so the git ref stays pinned.
93
98
  package-lock.json
94
- !cvn/whatsapp-bridge/package-lock.json
99
+ # Pinned Node libraries copied into the document authoring Docker images.
100
+ !backend/cosmos/modules/office/pptx/node/package-lock.json
95
101
  yarn.lock
96
102
  npm-shrinkwrap.json
97
103
 
@@ -157,7 +163,8 @@ logs/
157
163
  # serena
158
164
  .serena/
159
165
 
160
- # Mobile App (Expo/React Native)
166
+ # Mobile app (Expo/React Native) — root-level so prettier/oxlint invoked from
167
+ # the repo root skip the generated native folders (they read only this .gitignore)
161
168
  apps/mobile/.expo/
162
169
  apps/mobile/dist/
163
170
  apps/mobile/web-build/
@@ -170,13 +177,13 @@ apps/mobile/*.mobileprovision
170
177
  apps/mobile/*.p12
171
178
  apps/mobile/*.key
172
179
  apps/mobile/.metro-health-check*
180
+ apps/mobile/.*
173
181
 
174
- # Desktop App (Electron) — build output (node_modules/build already ignored above)
175
- apps/desktop/dist/
176
- apps/desktop/release/
177
182
 
183
+ # Desktop App (Electron) — build output (node_modules/build already ignored above)
184
+ apps/ping-desktop/dist/
185
+ apps/ping-desktop/release/
178
186
 
179
- .gitnexus
180
187
 
181
188
  # Python cache
182
189
  __pycache__/
@@ -200,3 +207,18 @@ apps/workers-mobile/eas-asc-key.p8
200
207
 
201
208
  # backfill_fts.py keyset cursor (local run state)
202
209
  projects/0904_drivesearch/.fts-cursor.json
210
+
211
+ # Totem: the Pi's config, pushed by totem/scripts/deploy.sh; the Pi-side lock is local.
212
+ # Its scripts/ are the deploy path itself, not build spill: re-included past `*/scripts/`.
213
+ totem/.env.pi
214
+ totem/uv.lock
215
+ !totem/scripts/
216
+
217
+ # pnpm addin:check report page
218
+ .addin-check/
219
+
220
+ # Corporate templates the PowerPoint evals run on — the customers' own files, kept off git
221
+ backend/evals/data/powerpoint/private/
222
+
223
+ # Delos Code worktrees — full repo copies; tools that walk the tree (ty, ruff, oxlint) must skip them
224
+ .delos/
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: delos-cli
3
- Version: 2.1.0
3
+ Version: 5.9.15
4
4
  Summary: Terminal REPL for the Delos agent — the Claude-Code-style CLI for Delos.
5
5
  Project-URL: Homepage, https://delos.so
6
6
  Project-URL: Repository, https://github.com/Delos-Intelligence/cosmos-saas
@@ -24,9 +24,11 @@ Requires-Dist: httpx>=0.27.0
24
24
  Requires-Dist: prompt-toolkit>=3.0.47
25
25
  Requires-Dist: questionary>=2.0.1
26
26
  Requires-Dist: rich>=13.8.0
27
- Requires-Dist: ripgrep<15,>=14; sys_platform == 'darwin' and platform_machine == 'arm64'
28
- Requires-Dist: ripgrep<15,>=14; sys_platform == 'linux' and platform_machine == 'x86_64'
27
+ Requires-Dist: ripgrep<15,>=14; sys_platform == 'darwin'
28
+ Requires-Dist: ripgrep<15,>=14; sys_platform == 'linux' and (platform_machine == 'x86_64' or platform_machine == 'aarch64')
29
+ Requires-Dist: ripgrep<15,>=14; sys_platform == 'win32' and (platform_machine == 'AMD64' or platform_machine == 'x86_64')
29
30
  Requires-Dist: sentry-sdk<3,>=2.44.0
31
+ Requires-Dist: truststore>=0.10.0
30
32
  Requires-Dist: typer>=0.12.5
31
33
  Description-Content-Type: text/markdown
32
34
 
@@ -0,0 +1,10 @@
1
+ """``python -m delos_cli`` — how the VS Code extension runs its bundled copy.
2
+
3
+ The extension ships its own interpreter with the CLI installed into it and
4
+ launches it through this module rather than the ``delos`` console script,
5
+ whose launcher is tied to the machine that built it.
6
+ """
7
+
8
+ from delos_cli.telemetry import main
9
+
10
+ main()
@@ -0,0 +1,5 @@
1
+ {
2
+ "release": "v5.9.15",
3
+ "sha": "d90e1f13f19f4dd81ac163706bab5fe35e75761e",
4
+ "version": "5.9.15"
5
+ }
@@ -15,9 +15,9 @@ monorepo so each developer's local ngrok tunnel is picked up automatically.
15
15
  from __future__ import annotations
16
16
 
17
17
  import contextlib
18
- import fcntl # POSIX only; Windows support skipped for v1
19
18
  import json
20
19
  import os
20
+ import sys
21
21
  import tempfile
22
22
  from contextlib import contextmanager
23
23
  from dataclasses import asdict, dataclass, field
@@ -49,10 +49,10 @@ class RegionUrls(TypedDict):
49
49
 
50
50
  # Supabase anon keys are public; same values live in apps/web/.env.production.*
51
51
  # and are embedded in the web/extension bundles. Safe to ship here.
52
- _EU_ANON = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.ewogICJyb2xlIjogImFub24iLAogICJpc3MiOiAic3VwYWJhc2UiLAogICJpYXQiOiAxNzEyNTI3MjAwLAogICJleHAiOiAxODcwMjkzNjAwCn0.gO1qyjuG2g4yAZ3u820P9q5CUTQmDiDrHSurZjIePbA"
52
+ _EU_ANON = "sb_publishable_k0h1VrcR5Wlo7uHypgzp6EPXBM6AmCJYaty1HdlwHkc"
53
53
  _US_ANON = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJyb2xlIjoiYW5vbiIsImlzcyI6InN1cGFiYXNlIiwiaWF0IjoxNzU5MjY5NjAwLCJleHAiOjE5MTcwMzYwMDB9.VYuiRrB3q9GaR3qsZauOm1oIH_bZ3iuOzmNQfDcqo40"
54
54
  _AE_ANON = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJyb2xlIjoiYW5vbiIsImlzcyI6InN1cGFiYXNlIiwiaWF0IjoxNzY1MTQ4NDAwLCJleHAiOjE5MjI5MTQ4MDB9.TlD6gF-Q5K1drdnh-XPQgXGs410h5NcHJBRgV6aNXrY"
55
- _STAGING_ANON = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.ewogICJyb2xlIjogImFub24iLAogICJpc3MiOiAic3VwYWJhc2UiLAogICJpYXQiOiAxNzEyNTI3MjAwLAogICJleHAiOiAxODcwMjkzNjAwCn0.GDHgmBuu4XivLHq18P3A-sHblw99If9uqW-HChepSb8"
55
+ _STAGING_ANON = "sb_publishable_FXOYjigrAP8eOtVoJsxJs-X6X6oEL0UfEIi3n-3r_4o"
56
56
  _DEV_ANON = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZS1kZW1vIiwicm9sZSI6ImFub24iLCJleHAiOjE5ODM4MTI5OTZ9.CRXP1A7WOeoJeXxjNni43kdQwgnWNReilDMblYTn_I0"
57
57
 
58
58
 
@@ -343,6 +343,33 @@ def save_tokens(cfg: Config) -> Path:
343
343
  return save(disk)
344
344
 
345
345
 
346
+ if sys.platform == "win32":
347
+ import msvcrt
348
+
349
+ def _lock(f: IO[str]) -> None:
350
+ # LK_LOCK gives up after ~10 s of retries; loop for flock's blocking semantics.
351
+ f.seek(0)
352
+ while True:
353
+ try:
354
+ msvcrt.locking(f.fileno(), msvcrt.LK_LOCK, 1)
355
+ except OSError:
356
+ continue
357
+ return
358
+
359
+ def _unlock(f: IO[str]) -> None:
360
+ f.seek(0)
361
+ msvcrt.locking(f.fileno(), msvcrt.LK_UNLCK, 1)
362
+
363
+ else:
364
+ import fcntl
365
+
366
+ def _lock(f: IO[str]) -> None:
367
+ fcntl.flock(f.fileno(), fcntl.LOCK_EX)
368
+
369
+ def _unlock(f: IO[str]) -> None:
370
+ fcntl.flock(f.fileno(), fcntl.LOCK_UN)
371
+
372
+
346
373
  @contextmanager
347
374
  def config_file_lock() -> Iterator[None]:
348
375
  """Advisory cross-process exclusive lock on ``~/.config/delos/.config.lock``.
@@ -352,17 +379,18 @@ def config_file_lock() -> Iterator[None]:
352
379
  against the same stale refresh_token (whichever loses the race would
353
380
  otherwise be kicked out with ``invalid_grant``).
354
381
 
355
- POSIX only (uses :mod:`fcntl`). The lockfile is created on first use and
356
- left in place; only the lock state matters.
382
+ ``fcntl.flock`` on POSIX, ``msvcrt.locking`` on byte 0 on Windows. The
383
+ lockfile is created on first use and left in place; only the lock state
384
+ matters.
357
385
  """
358
386
  CONFIG_DIR.mkdir(parents=True, exist_ok=True)
359
387
  f: IO[str] = LOCK_PATH.open("a+")
360
388
  try:
361
- fcntl.flock(f.fileno(), fcntl.LOCK_EX)
389
+ _lock(f)
362
390
  yield
363
391
  finally:
364
392
  with contextlib.suppress(OSError):
365
- fcntl.flock(f.fileno(), fcntl.LOCK_UN)
393
+ _unlock(f)
366
394
  f.close()
367
395
 
368
396
 
@@ -73,7 +73,7 @@ def expand_slash_command(
73
73
  Returns ``(content, mode)`` — unchanged when the message isn't a known
74
74
  command (unknown ``/xyz`` passes through as plain text; the agent can
75
75
  answer helpfully). ``/execute`` forces build mode: executing a plan is
76
- pointless with read-only tools.
76
+ pointless with read-only tools (``auto`` is kept: it already executes).
77
77
  """
78
78
  head, _, rest = content.strip().partition(" ")
79
79
  rest = rest.strip()
@@ -86,5 +86,5 @@ def expand_slash_command(
86
86
  prompt = EXECUTE_PROMPT
87
87
  if rest:
88
88
  prompt += f"\n\nAdditional user instructions: {rest}"
89
- return prompt, "build"
89
+ return prompt, "auto" if mode == "auto" else "build"
90
90
  return content, mode
@@ -1,4 +1,4 @@
1
- """Public key discovery; keep in sync with cvn/backend/cvn/public_key.py.
1
+ """Public key discovery; keep in sync with desktop/backend/cvn/public_key.py.
2
2
 
3
3
  Only public API keys are cached. Database URLs, user JWTs and refresh tokens
4
4
  are never changed. A process uses one snapshot until it restarts.
@@ -8,6 +8,7 @@ a later ``permission_reply`` resolves.
8
8
  Policy (mirrors the extension's previous ``needsPermission`` gate plus the
9
9
  REPL's permission modes):
10
10
 
11
+ * ``auto`` mode (any tool, incl. ``run_shell``) → accept silently
11
12
  * tool previously approved with "always" → accept silently
12
13
  * ``build`` mode + edit/write tool → accept silently
13
14
  * ``plan`` mode + edit/write tool → deny with an explanatory reason
@@ -53,6 +54,8 @@ def make_confirm(server: StdioServer, turn: TurnState) -> ConfirmFn:
53
54
 
54
55
  async def _confirm(body: str, tool: str | None = None) -> ConfirmOutcome:
55
56
  name = tool or ""
57
+ if turn.mode == "auto":
58
+ return ConfirmOutcome(accepted=True)
56
59
  if name in server.always_allowed:
57
60
  return ConfirmOutcome(accepted=True)
58
61
  if name in EDIT_TOOLS:
@@ -22,7 +22,7 @@ from delos_cli.transport.integrations import (
22
22
  fetch_manage_url,
23
23
  set_integration_active,
24
24
  )
25
- from delos_cli.transport.models import fetch_models
25
+ from delos_cli.transport.models import fetch_model_infos, fetch_models
26
26
 
27
27
  if TYPE_CHECKING:
28
28
  from .server import StdioServer
@@ -92,11 +92,13 @@ async def fork_chat(server: StdioServer, params: dict[str, Any]) -> dict[str, An
92
92
 
93
93
 
94
94
  async def find_files(server: StdioServer, params: dict[str, Any]) -> list[str]:
95
- """Fuzzy-ish file lookup: ``rg --files`` + case-insensitive substring filter.
95
+ """File + folder lookup, Cmd+P style: ``rg --files`` + ranked matching.
96
96
 
97
- Replaces the ripgrep spawn the extension used to own; same semantics
98
- (workspace-relative paths, .git/node_modules excluded by rg defaults
99
- plus explicit globs). Falls back to an os.walk scan when rg is absent.
97
+ Workspace-relative paths, .git/node_modules excluded. Folders are
98
+ derived from the file paths and returned with a trailing ``/``.
99
+ Ranking: folders containing the query, folders matching it as a
100
+ subsequence (a, then r, then e), then files likewise. Falls back to an
101
+ os.walk scan when rg is absent.
100
102
  """
101
103
  query = str(params.get("query") or "").strip().lower()
102
104
  max_results = int(params.get("maxResults") or _FIND_FILES_DEFAULT_MAX)
@@ -104,14 +106,37 @@ async def find_files(server: StdioServer, params: dict[str, Any]) -> list[str]:
104
106
  paths = await _rg_files(server.workspace)
105
107
  except FileNotFoundError:
106
108
  paths = await asyncio.to_thread(_walk_files, server.workspace)
107
- matches: list[str] = []
108
- for path in paths:
109
- if query and query not in path.lower():
109
+ return _rank_paths(paths, query, max_results)
110
+
111
+
112
+ def _is_subsequence(query: str, text: str) -> bool:
113
+ it = iter(text)
114
+ return all(ch in it for ch in query)
115
+
116
+
117
+ def _rank_paths(paths: list[str], query: str, max_results: int) -> list[str]:
118
+ folders = sorted({parent.as_posix() for p in paths for parent in Path(p).parents if parent.as_posix() != "."})
119
+ entries = [(f + "/", True) for f in folders] + [(p, False) for p in paths]
120
+
121
+ if not query:
122
+ ordered = [e for e in entries if e[1]] + [e for e in entries if not e[1]]
123
+ return [path for path, _ in ordered[:max_results]]
124
+
125
+ ranked: list[tuple[tuple[int, int, int, int], str]] = []
126
+ for path, is_dir in entries:
127
+ full = path.rstrip("/").lower()
128
+ base = full.rsplit("/", 1)[-1]
129
+ if query in full:
130
+ tier = 0
131
+ elif _is_subsequence(query, full):
132
+ tier = 1
133
+ else:
110
134
  continue
111
- matches.append(path)
112
- if len(matches) >= max_results:
113
- break
114
- return matches
135
+ # Within a tier: basename hits beat directory-part hits, then shorter paths.
136
+ base_hit = 0 if (query in base if tier == 0 else _is_subsequence(query, base)) else 1
137
+ ranked.append(((0 if is_dir else 1, tier, base_hit, len(full)), path))
138
+ ranked.sort()
139
+ return [path for _, path in ranked[:max_results]]
115
140
 
116
141
 
117
142
  async def _rg_files(workspace: Path) -> list[str]:
@@ -148,9 +173,11 @@ def _walk_files(workspace: Path) -> list[str]:
148
173
  return found
149
174
 
150
175
 
151
- async def list_models(server: StdioServer, params: dict[str, Any]) -> list[str]:
152
- """Model ids available to the signed-in user/org (mirrors the REPL picker)."""
153
- _ = params
176
+ async def list_models(server: StdioServer, params: dict[str, Any]) -> list[str] | list[dict[str, Any]]:
177
+ """Models available to the signed-in user/org: ids, or with Gate's copy when ``locale`` is given."""
178
+ locale = params.get("locale")
179
+ if isinstance(locale, str) and locale:
180
+ return await fetch_model_infos(server.require_http(), locale)
154
181
  return await fetch_models(server.require_http())
155
182
 
156
183
 
@@ -8,6 +8,7 @@ from pathlib import Path
8
8
  from typing import TYPE_CHECKING
9
9
 
10
10
  import sentry_sdk
11
+ import truststore
11
12
 
12
13
  from delos_cli import __version__, _editable_source_dir
13
14
  from delos_cli.public_key import public_key_tags
@@ -41,6 +42,9 @@ def applied_config(cfg: Config) -> None:
41
42
  def main() -> None:
42
43
  """Keep CLI exit codes and exceptions intact; never collect CLI arguments."""
43
44
  global _cli_client # noqa: PLW0603 -- identify our client in a shared process
45
+ # Before any SSLContext exists: every httpx client (and Sentry) then trusts
46
+ # the OS store, so a TLS-inspection proxy's corporate CA is accepted.
47
+ truststore.inject_into_ssl()
44
48
  build = build_identity()
45
49
  editable = _editable_source_dir() is not None
46
50
  disabled = editable or os.environ.get("DELOS_TELEMETRY_DISABLED") == "1"
@@ -63,15 +63,9 @@ async def handle_glob(tool_input: dict[str, Any], ctx: Ctx) -> str: # noqa: RUF
63
63
 
64
64
  # ``Path.glob`` handles ``**`` recursive segments natively.
65
65
  try:
66
- matches = (
67
- base.glob(pattern, recurse_symlinks=True)
68
- if include_ignored
69
- else base.glob(pattern)
70
- )
66
+ matches = base.glob(pattern, recurse_symlinks=True) if include_ignored else base.glob(pattern)
71
67
  candidates = [
72
- p
73
- for p in matches
74
- if (include_ignored or not _IGNORED_DIR_SEGMENTS.intersection(p.parts)) and p.is_file()
68
+ p for p in matches if (include_ignored or not _IGNORED_DIR_SEGMENTS.intersection(p.parts)) and p.is_file()
75
69
  ]
76
70
  except (OSError, ValueError) as e:
77
71
  return f"Error walking {base} with pattern {pattern!r}: {e}"
@@ -80,10 +74,7 @@ async def handle_glob(tool_input: dict[str, Any], ctx: Ctx) -> str: # noqa: RUF
80
74
  suffix = (
81
75
  ""
82
76
  if include_ignored
83
- else (
84
- " (dependency/build trees like node_modules are excluded — "
85
- "pass include_ignored=true to search them)"
86
- )
77
+ else (" (dependency/build trees like node_modules are excluded — pass include_ignored=true to search them)")
87
78
  )
88
79
  return f"No files matching {pattern!r} in {base}{suffix}."
89
80
 
@@ -69,7 +69,7 @@ def _find_rg() -> str | None:
69
69
  that's the most reliable location — PATH is whatever the spawning app
70
70
  (VSCode, launchd) happened to have.
71
71
  """
72
- bundled = Path(sys.executable).parent / "rg"
72
+ bundled = Path(sys.executable).parent / ("rg.exe" if sys.platform == "win32" else "rg")
73
73
  if os.access(bundled, os.X_OK):
74
74
  return str(bundled)
75
75
  found = shutil.which("rg")
@@ -0,0 +1,50 @@
1
+ """Thin wrapper around ``GET /client/picker/{org_uuid}`` — the plan's ``cli`` picker, in admin order."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from typing import TYPE_CHECKING, Any
6
+ from urllib.parse import quote
7
+
8
+ from .client import TransportError
9
+
10
+ if TYPE_CHECKING:
11
+ from .client import AuthedClient
12
+
13
+
14
+ async def fetch_models(client: AuthedClient) -> list[str]:
15
+ """Return model ids available to the signed-in user/org."""
16
+ path = f"/client/picker/{client.cfg.org_uuid}?app=cli"
17
+ payload = await client.json_get(path)
18
+ return [m["id"] for m in payload.get("models", [])]
19
+
20
+
21
+ async def fetch_model_infos(client: AuthedClient, locale: str) -> list[dict[str, Any]]:
22
+ """Return the same models with Gate's title and description in ``locale``, and the provider's logo."""
23
+ path = f"/client/picker/{client.cfg.org_uuid}?app=cli&locale={quote(locale)}"
24
+ payload = await client.json_get(path)
25
+ logos = await _fetch_provider_logos(client)
26
+ return [
27
+ {
28
+ "id": m["id"],
29
+ "title": m.get("title"),
30
+ "description": m.get("description"),
31
+ "icon": logos.get((m.get("provider") or "").lower()),
32
+ }
33
+ for m in payload.get("models", [])
34
+ ]
35
+
36
+
37
+ async def _fetch_provider_logos(client: AuthedClient) -> dict[str, str]:
38
+ """Gate developer id → logo as an image URL; empty when Gate is unreachable (the picker then shows no marks)."""
39
+ try:
40
+ payload = await client.json_get("/client/developers")
41
+ except TransportError:
42
+ return {}
43
+ logos: dict[str, str] = {}
44
+ for developer in payload.get("developers", []):
45
+ logo = (developer.get("logo") or "").strip()
46
+ if not logo:
47
+ continue
48
+ # Gate stores either an inline SVG or a data URI (same rule as the add-ins' `providerIcon`).
49
+ logos[developer["id"].lower()] = f"data:image/svg+xml,{quote(logo)}" if logo.startswith("<") else logo
50
+ return logos
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "delos-cli"
3
- version = "2.1.0"
3
+ version = "5.9.15"
4
4
  description = "Terminal REPL for the Delos agent — the Claude-Code-style CLI for Delos."
5
5
  readme = "README.md"
6
6
  license = { text = "MIT" }
@@ -26,6 +26,10 @@ dependencies = [
26
26
  "rich>=13.8.0",
27
27
  "prompt_toolkit>=3.0.47",
28
28
  "httpx>=0.27.0",
29
+ # Verify TLS against the OS trust store (Windows store, macOS Keychain)
30
+ # instead of certifi alone, so corporate TLS-inspection proxies whose root
31
+ # CA is installed system-wide (Zscaler & co.) do not fail every request.
32
+ "truststore>=0.10.0",
29
33
  "questionary>=2.0.1",
30
34
  # Real ripgrep binary shipped as a wheel — the grep/glob tools use it for
31
35
  # fast, .gitignore-aware search. Markers limit it to the platforms that
@@ -34,9 +38,13 @@ dependencies = [
34
38
  # manylinux_2_39 (glibc >= 2.39), so on older distros (Ubuntu 22.04,
35
39
  # Debian 12, ...) resolvers fall back to the sdist, which fails to build
36
40
  # because its Cargo.toml needs the edition2024 feature. 14.x still ships
37
- # a manylinux2014 (glibc >= 2.17) wheel that works everywhere.
38
- "ripgrep>=14,<15 ; sys_platform == 'darwin' and platform_machine == 'arm64'",
39
- "ripgrep>=14,<15 ; sys_platform == 'linux' and platform_machine == 'x86_64'",
41
+ # a manylinux2014 (glibc >= 2.17) wheel that works everywhere. Windows has
42
+ # no POSIX grep to fall back on, so its wheel (x64 only) is what makes the
43
+ # tools work there at all. Windows x64 reports AMD64; uv's cross-platform
44
+ # resolution (the extension's bundled runtime) reports x86_64.
45
+ "ripgrep>=14,<15 ; sys_platform == 'darwin'",
46
+ "ripgrep>=14,<15 ; sys_platform == 'linux' and (platform_machine == 'x86_64' or platform_machine == 'aarch64')",
47
+ "ripgrep>=14,<15 ; sys_platform == 'win32' and (platform_machine == 'AMD64' or platform_machine == 'x86_64')",
40
48
  ]
41
49
 
42
50
  [project.scripts]
@@ -1,8 +0,0 @@
1
- {
2
- "disabledMcpjsonServers": [
3
- "sentry",
4
- "agent-analysis-localhost",
5
- "agent-analysis-staging",
6
- "agent-analysis-prod"
7
- ]
8
- }
@@ -1 +0,0 @@
1
- {}
@@ -1,19 +0,0 @@
1
- """Thin wrapper around ``GET /client/models/{org_uuid}``.
2
-
3
- Mirrors the data the web frontend uses for its chat model picker —
4
- filtered server-side by sigma flag, deployment plan, and config fallbacks.
5
- """
6
-
7
- from __future__ import annotations
8
-
9
- from typing import TYPE_CHECKING
10
-
11
- if TYPE_CHECKING:
12
- from .client import AuthedClient
13
-
14
-
15
- async def fetch_models(client: AuthedClient) -> list[str]:
16
- """Return model ids available to the signed-in user/org."""
17
- path = f"/client/models/{client.cfg.org_uuid}?capability=cli"
18
- payload = await client.json_get(path)
19
- return [m["id"] for m in payload.get("models", [])]
File without changes
File without changes
File without changes
File without changes
File without changes