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.
- {delos_cli-2.1.0 → delos_cli-5.9.15}/.gitignore +32 -10
- {delos_cli-2.1.0 → delos_cli-5.9.15}/PKG-INFO +5 -3
- delos_cli-5.9.15/delos_cli/__main__.py +10 -0
- delos_cli-5.9.15/delos_cli/_build.json +5 -0
- {delos_cli-2.1.0 → delos_cli-5.9.15}/delos_cli/auth/config.py +35 -7
- {delos_cli-2.1.0 → delos_cli-5.9.15}/delos_cli/commands/prompts.py +2 -2
- {delos_cli-2.1.0 → delos_cli-5.9.15}/delos_cli/public_key.py +1 -1
- {delos_cli-2.1.0 → delos_cli-5.9.15}/delos_cli/serve/confirm.py +3 -0
- {delos_cli-2.1.0 → delos_cli-5.9.15}/delos_cli/serve/rpc.py +42 -15
- {delos_cli-2.1.0 → delos_cli-5.9.15}/delos_cli/telemetry.py +4 -0
- {delos_cli-2.1.0 → delos_cli-5.9.15}/delos_cli/tools/glob_tool.py +3 -12
- {delos_cli-2.1.0 → delos_cli-5.9.15}/delos_cli/tools/grep.py +1 -1
- delos_cli-5.9.15/delos_cli/transport/models.py +50 -0
- {delos_cli-2.1.0 → delos_cli-5.9.15}/pyproject.toml +12 -4
- delos_cli-2.1.0/.claude/settings.local.json +0 -8
- delos_cli-2.1.0/delos_cli/_build.json +0 -1
- delos_cli-2.1.0/delos_cli/transport/models.py +0 -19
- {delos_cli-2.1.0 → delos_cli-5.9.15}/README.md +0 -0
- {delos_cli-2.1.0 → delos_cli-5.9.15}/delos_cli/__init__.py +0 -0
- {delos_cli-2.1.0 → delos_cli-5.9.15}/delos_cli/agent/__init__.py +0 -0
- {delos_cli-2.1.0 → delos_cli-5.9.15}/delos_cli/agent/session.py +0 -0
- {delos_cli-2.1.0 → delos_cli-5.9.15}/delos_cli/agent/tools.py +0 -0
- {delos_cli-2.1.0 → delos_cli-5.9.15}/delos_cli/agent/transport.py +0 -0
- {delos_cli-2.1.0 → delos_cli-5.9.15}/delos_cli/agent/turn.py +0 -0
- {delos_cli-2.1.0 → delos_cli-5.9.15}/delos_cli/apps/__init__.py +0 -0
- {delos_cli-2.1.0 → delos_cli-5.9.15}/delos_cli/apps/base.py +0 -0
- {delos_cli-2.1.0 → delos_cli-5.9.15}/delos_cli/apps/chat/__init__.py +0 -0
- {delos_cli-2.1.0 → delos_cli-5.9.15}/delos_cli/apps/chat/app.py +0 -0
- {delos_cli-2.1.0 → delos_cli-5.9.15}/delos_cli/apps/chat/commands.py +0 -0
- {delos_cli-2.1.0 → delos_cli-5.9.15}/delos_cli/apps/chat/render.py +0 -0
- {delos_cli-2.1.0 → delos_cli-5.9.15}/delos_cli/apps/replay.py +0 -0
- {delos_cli-2.1.0 → delos_cli-5.9.15}/delos_cli/apps/scribe/__init__.py +0 -0
- {delos_cli-2.1.0 → delos_cli-5.9.15}/delos_cli/apps/scribe/app.py +0 -0
- {delos_cli-2.1.0 → delos_cli-5.9.15}/delos_cli/apps/scribe/commands.py +0 -0
- {delos_cli-2.1.0 → delos_cli-5.9.15}/delos_cli/apps/scribe/tools.py +0 -0
- {delos_cli-2.1.0 → delos_cli-5.9.15}/delos_cli/auth/__init__.py +0 -0
- {delos_cli-2.1.0 → delos_cli-5.9.15}/delos_cli/auth/mfa.py +0 -0
- {delos_cli-2.1.0 → delos_cli-5.9.15}/delos_cli/auth/oauth.py +0 -0
- {delos_cli-2.1.0 → delos_cli-5.9.15}/delos_cli/auth/token_manager.py +0 -0
- {delos_cli-2.1.0 → delos_cli-5.9.15}/delos_cli/commands/__init__.py +0 -0
- {delos_cli-2.1.0 → delos_cli-5.9.15}/delos_cli/commands/base.py +0 -0
- {delos_cli-2.1.0 → delos_cli-5.9.15}/delos_cli/commands/builtin.py +0 -0
- {delos_cli-2.1.0 → delos_cli-5.9.15}/delos_cli/context_report.py +0 -0
- {delos_cli-2.1.0 → delos_cli-5.9.15}/delos_cli/ctx.py +0 -0
- {delos_cli-2.1.0 → delos_cli-5.9.15}/delos_cli/git_context.py +0 -0
- {delos_cli-2.1.0 → delos_cli-5.9.15}/delos_cli/loop.py +0 -0
- {delos_cli-2.1.0 → delos_cli-5.9.15}/delos_cli/main.py +0 -0
- {delos_cli-2.1.0 → delos_cli-5.9.15}/delos_cli/project_context.py +0 -0
- {delos_cli-2.1.0 → delos_cli-5.9.15}/delos_cli/sentry_identity.py +0 -0
- {delos_cli-2.1.0 → delos_cli-5.9.15}/delos_cli/serve/__init__.py +0 -0
- {delos_cli-2.1.0 → delos_cli-5.9.15}/delos_cli/serve/app.py +0 -0
- {delos_cli-2.1.0 → delos_cli-5.9.15}/delos_cli/serve/protocol.py +0 -0
- {delos_cli-2.1.0 → delos_cli-5.9.15}/delos_cli/serve/server.py +0 -0
- {delos_cli-2.1.0 → delos_cli-5.9.15}/delos_cli/state.py +0 -0
- {delos_cli-2.1.0 → delos_cli-5.9.15}/delos_cli/tools/__init__.py +0 -0
- {delos_cli-2.1.0 → delos_cli-5.9.15}/delos_cli/tools/ask_user_input.py +0 -0
- {delos_cli-2.1.0 → delos_cli-5.9.15}/delos_cli/tools/edit_content.py +0 -0
- {delos_cli-2.1.0 → delos_cli-5.9.15}/delos_cli/tools/explore.py +0 -0
- {delos_cli-2.1.0 → delos_cli-5.9.15}/delos_cli/tools/read.py +0 -0
- {delos_cli-2.1.0 → delos_cli-5.9.15}/delos_cli/tools/run_shell.py +0 -0
- {delos_cli-2.1.0 → delos_cli-5.9.15}/delos_cli/tools/task.py +0 -0
- {delos_cli-2.1.0 → delos_cli-5.9.15}/delos_cli/tools/todo_write.py +0 -0
- {delos_cli-2.1.0 → delos_cli-5.9.15}/delos_cli/tools/verify.py +0 -0
- {delos_cli-2.1.0 → delos_cli-5.9.15}/delos_cli/tools/write_content.py +0 -0
- {delos_cli-2.1.0 → delos_cli-5.9.15}/delos_cli/transport/__init__.py +0 -0
- {delos_cli-2.1.0 → delos_cli-5.9.15}/delos_cli/transport/chats.py +0 -0
- {delos_cli-2.1.0 → delos_cli-5.9.15}/delos_cli/transport/client.py +0 -0
- {delos_cli-2.1.0 → delos_cli-5.9.15}/delos_cli/transport/documents.py +0 -0
- {delos_cli-2.1.0 → delos_cli-5.9.15}/delos_cli/transport/integrations.py +0 -0
- {delos_cli-2.1.0 → delos_cli-5.9.15}/delos_cli/ui/__init__.py +0 -0
- {delos_cli-2.1.0 → delos_cli-5.9.15}/delos_cli/ui/banner.py +0 -0
- {delos_cli-2.1.0 → delos_cli-5.9.15}/delos_cli/ui/chat_picker.py +0 -0
- {delos_cli-2.1.0 → delos_cli-5.9.15}/delos_cli/ui/collapse.py +0 -0
- {delos_cli-2.1.0 → delos_cli-5.9.15}/delos_cli/ui/completer.py +0 -0
- {delos_cli-2.1.0 → delos_cli-5.9.15}/delos_cli/ui/document_picker.py +0 -0
- {delos_cli-2.1.0 → delos_cli-5.9.15}/delos_cli/ui/integrations_picker.py +0 -0
- {delos_cli-2.1.0 → delos_cli-5.9.15}/delos_cli/ui/lexer.py +0 -0
- {delos_cli-2.1.0 → delos_cli-5.9.15}/delos_cli/ui/model_picker.py +0 -0
- {delos_cli-2.1.0 → delos_cli-5.9.15}/delos_cli/ui/output.py +0 -0
- {delos_cli-2.1.0 → delos_cli-5.9.15}/delos_cli/ui/repl.py +0 -0
- {delos_cli-2.1.0 → delos_cli-5.9.15}/delos_cli/ui/style.py +0 -0
- {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
|
-
|
|
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
|
|
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:
|
|
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'
|
|
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()
|
|
@@ -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 = "
|
|
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 = "
|
|
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
|
-
|
|
356
|
-
left in place; only the lock state
|
|
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
|
-
|
|
389
|
+
_lock(f)
|
|
362
390
|
yield
|
|
363
391
|
finally:
|
|
364
392
|
with contextlib.suppress(OSError):
|
|
365
|
-
|
|
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
|
|
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
|
-
"""
|
|
95
|
+
"""File + folder lookup, Cmd+P style: ``rg --files`` + ranked matching.
|
|
96
96
|
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
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
|
-
|
|
108
|
-
|
|
109
|
-
|
|
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
|
-
|
|
112
|
-
if
|
|
113
|
-
|
|
114
|
-
|
|
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
|
-
"""
|
|
153
|
-
|
|
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 = "
|
|
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
|
-
|
|
39
|
-
|
|
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 +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
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|