contree-cli 0.7.0__tar.gz → 0.7.1__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 (67) hide show
  1. {contree_cli-0.7.0 → contree_cli-0.7.1}/PKG-INFO +1 -1
  2. {contree_cli-0.7.0 → contree_cli-0.7.1}/contree_cli/cli/file.py +22 -24
  3. {contree_cli-0.7.0 → contree_cli-0.7.1}/contree_cli/cli/images.py +13 -15
  4. {contree_cli-0.7.0 → contree_cli-0.7.1}/contree_cli/cli/operation.py +16 -18
  5. {contree_cli-0.7.0 → contree_cli-0.7.1}/contree_cli/client.py +11 -0
  6. {contree_cli-0.7.0 → contree_cli-0.7.1}/pyproject.toml +1 -1
  7. {contree_cli-0.7.0 → contree_cli-0.7.1}/LICENSE +0 -0
  8. {contree_cli-0.7.0 → contree_cli-0.7.1}/README.md +0 -0
  9. {contree_cli-0.7.0 → contree_cli-0.7.1}/contree_cli/__init__.py +0 -0
  10. {contree_cli-0.7.0 → contree_cli-0.7.1}/contree_cli/__main__.py +0 -0
  11. {contree_cli-0.7.0 → contree_cli-0.7.1}/contree_cli/agent.md +0 -0
  12. {contree_cli-0.7.0 → contree_cli-0.7.1}/contree_cli/arguments.py +0 -0
  13. {contree_cli-0.7.0 → contree_cli-0.7.1}/contree_cli/cli/__init__.py +0 -0
  14. {contree_cli-0.7.0 → contree_cli-0.7.1}/contree_cli/cli/agent.py +0 -0
  15. {contree_cli-0.7.0 → contree_cli-0.7.1}/contree_cli/cli/auth.py +0 -0
  16. {contree_cli-0.7.0 → contree_cli-0.7.1}/contree_cli/cli/build.py +0 -0
  17. {contree_cli-0.7.0 → contree_cli-0.7.1}/contree_cli/cli/cat.py +0 -0
  18. {contree_cli-0.7.0 → contree_cli-0.7.1}/contree_cli/cli/cd.py +0 -0
  19. {contree_cli-0.7.0 → contree_cli-0.7.1}/contree_cli/cli/cp.py +0 -0
  20. {contree_cli-0.7.0 → contree_cli-0.7.1}/contree_cli/cli/env.py +0 -0
  21. {contree_cli-0.7.0 → contree_cli-0.7.1}/contree_cli/cli/ls.py +0 -0
  22. {contree_cli-0.7.0 → contree_cli-0.7.1}/contree_cli/cli/run.py +0 -0
  23. {contree_cli-0.7.0 → contree_cli-0.7.1}/contree_cli/cli/session.py +0 -0
  24. {contree_cli-0.7.0 → contree_cli-0.7.1}/contree_cli/cli/show.py +0 -0
  25. {contree_cli-0.7.0 → contree_cli-0.7.1}/contree_cli/cli/skill.py +0 -0
  26. {contree_cli-0.7.0 → contree_cli-0.7.1}/contree_cli/cli/tag.py +0 -0
  27. {contree_cli-0.7.0 → contree_cli-0.7.1}/contree_cli/cli/use.py +0 -0
  28. {contree_cli-0.7.0 → contree_cli-0.7.1}/contree_cli/config.py +0 -0
  29. {contree_cli-0.7.0 → contree_cli-0.7.1}/contree_cli/docker/__init__.py +0 -0
  30. {contree_cli-0.7.0 → contree_cli-0.7.1}/contree_cli/docker/context.py +0 -0
  31. {contree_cli-0.7.0 → contree_cli-0.7.1}/contree_cli/docker/dockerignore.py +0 -0
  32. {contree_cli-0.7.0 → contree_cli-0.7.1}/contree_cli/docker/keyword.py +0 -0
  33. {contree_cli-0.7.0 → contree_cli-0.7.1}/contree_cli/docker/kw_add.py +0 -0
  34. {contree_cli-0.7.0 → contree_cli-0.7.1}/contree_cli/docker/kw_arg.py +0 -0
  35. {contree_cli-0.7.0 → contree_cli-0.7.1}/contree_cli/docker/kw_copy.py +0 -0
  36. {contree_cli-0.7.0 → contree_cli-0.7.1}/contree_cli/docker/kw_env.py +0 -0
  37. {contree_cli-0.7.0 → contree_cli-0.7.1}/contree_cli/docker/kw_from.py +0 -0
  38. {contree_cli-0.7.0 → contree_cli-0.7.1}/contree_cli/docker/kw_run.py +0 -0
  39. {contree_cli-0.7.0 → contree_cli-0.7.1}/contree_cli/docker/kw_skipped.py +0 -0
  40. {contree_cli-0.7.0 → contree_cli-0.7.1}/contree_cli/docker/kw_user.py +0 -0
  41. {contree_cli-0.7.0 → contree_cli-0.7.1}/contree_cli/docker/kw_workdir.py +0 -0
  42. {contree_cli-0.7.0 → contree_cli-0.7.1}/contree_cli/docker/local_context.py +0 -0
  43. {contree_cli-0.7.0 → contree_cli-0.7.1}/contree_cli/docker/parser.py +0 -0
  44. {contree_cli-0.7.0 → contree_cli-0.7.1}/contree_cli/docker/url_fetch.py +0 -0
  45. {contree_cli-0.7.0 → contree_cli-0.7.1}/contree_cli/log.py +0 -0
  46. {contree_cli-0.7.0 → contree_cli-0.7.1}/contree_cli/man.py +0 -0
  47. {contree_cli-0.7.0 → contree_cli-0.7.1}/contree_cli/manual.md +0 -0
  48. {contree_cli-0.7.0 → contree_cli-0.7.1}/contree_cli/mapped_file.py +0 -0
  49. {contree_cli-0.7.0 → contree_cli-0.7.1}/contree_cli/migrations.py +0 -0
  50. {contree_cli-0.7.0 → contree_cli-0.7.1}/contree_cli/output.py +0 -0
  51. {contree_cli-0.7.0 → contree_cli-0.7.1}/contree_cli/py.typed +0 -0
  52. {contree_cli-0.7.0 → contree_cli-0.7.1}/contree_cli/refs.py +0 -0
  53. {contree_cli-0.7.0 → contree_cli-0.7.1}/contree_cli/session.py +0 -0
  54. {contree_cli-0.7.0 → contree_cli-0.7.1}/contree_cli/shell/__init__.py +0 -0
  55. {contree_cli-0.7.0 → contree_cli-0.7.1}/contree_cli/shell/argmap.py +0 -0
  56. {contree_cli-0.7.0 → contree_cli-0.7.1}/contree_cli/shell/argspec.py +0 -0
  57. {contree_cli-0.7.0 → contree_cli-0.7.1}/contree_cli/shell/cache.py +0 -0
  58. {contree_cli-0.7.0 → contree_cli-0.7.1}/contree_cli/shell/completer.py +0 -0
  59. {contree_cli-0.7.0 → contree_cli-0.7.1}/contree_cli/shell/history.py +0 -0
  60. {contree_cli-0.7.0 → contree_cli-0.7.1}/contree_cli/shell/parser.py +0 -0
  61. {contree_cli-0.7.0 → contree_cli-0.7.1}/contree_cli/shell/repl.py +0 -0
  62. {contree_cli-0.7.0 → contree_cli-0.7.1}/contree_cli/shell/sources.py +0 -0
  63. {contree_cli-0.7.0 → contree_cli-0.7.1}/contree_cli/shell/trie.py +0 -0
  64. {contree_cli-0.7.0 → contree_cli-0.7.1}/contree_cli/skill.py +0 -0
  65. {contree_cli-0.7.0 → contree_cli-0.7.1}/contree_cli/skill_body.md +0 -0
  66. {contree_cli-0.7.0 → contree_cli-0.7.1}/contree_cli/types.py +0 -0
  67. {contree_cli-0.7.0 → contree_cli-0.7.1}/contree_cli/update_check.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: contree-cli
3
- Version: 0.7.0
3
+ Version: 0.7.1
4
4
  Summary: CLI client for the ConTree sandbox platform
5
5
  Keywords: sandbox,cli,vm,ai-agent,contree
6
6
  Author: Dmitry Orlov
@@ -328,37 +328,35 @@ def cmd_file_ls(args: FileListArgs) -> int | None:
328
328
  if args.until is not None:
329
329
  params["until"] = isoformat_datetime(args.until)
330
330
 
331
- fetcher = PaginatedFetcher(
331
+ emitted = 0
332
+ hit_limit = False
333
+ with PaginatedFetcher(
332
334
  client,
333
335
  "/v1/files",
334
336
  params,
335
337
  lambda body: json.loads(body).get("files", []),
336
338
  limit=args.limit,
337
339
  concurrency=CONTREE_CONCURRENCY,
338
- )
339
-
340
- emitted = 0
341
- hit_limit = False
342
- for page in fetcher:
343
- for entry in page:
344
- if emitted >= args.limit:
345
- hit_limit = True
340
+ ) as fetcher:
341
+ for page in fetcher:
342
+ for entry in page:
343
+ if emitted >= args.limit:
344
+ hit_limit = True
345
+ break
346
+ uuid_str = entry.get("uuid")
347
+ source = sources.get(uuid_str, "") if isinstance(uuid_str, str) else ""
348
+ if args.quiet:
349
+ formatter(
350
+ uuid=uuid_str,
351
+ sha256=entry.get("sha256", ""),
352
+ source=source,
353
+ )
354
+ else:
355
+ formatter(**{**entry, "source": source})
356
+ emitted += 1
357
+ formatter.flush()
358
+ if hit_limit:
346
359
  break
347
- uuid_str = entry.get("uuid")
348
- source = sources.get(uuid_str, "") if isinstance(uuid_str, str) else ""
349
- if args.quiet:
350
- formatter(
351
- uuid=uuid_str,
352
- sha256=entry.get("sha256", ""),
353
- source=source,
354
- )
355
- else:
356
- formatter(**{**entry, "source": source})
357
- emitted += 1
358
- formatter.flush()
359
- if hit_limit:
360
- fetcher.stop()
361
- break
362
360
 
363
361
  if hit_limit:
364
362
  logger.warning(
@@ -272,28 +272,26 @@ def cmd_images(args: ImagesArgs) -> None:
272
272
  if args.until is not None:
273
273
  base_params["until"] = isoformat_datetime(args.until)
274
274
 
275
- fetcher = PaginatedFetcher(
275
+ emitted = 0
276
+ hit_limit = False
277
+ with PaginatedFetcher(
276
278
  client,
277
279
  "/v1/images",
278
280
  base_params,
279
281
  lambda body: json.loads(body)["images"],
280
282
  limit=args.limit,
281
283
  concurrency=CONTREE_CONCURRENCY,
282
- )
283
-
284
- emitted = 0
285
- hit_limit = False
286
- for page in fetcher:
287
- for image in page:
288
- if emitted >= args.limit:
289
- hit_limit = True
284
+ ) as fetcher:
285
+ for page in fetcher:
286
+ for image in page:
287
+ if emitted >= args.limit:
288
+ hit_limit = True
289
+ break
290
+ formatter(**image)
291
+ emitted += 1
292
+ formatter.flush()
293
+ if hit_limit:
290
294
  break
291
- formatter(**image)
292
- emitted += 1
293
- formatter.flush()
294
- if hit_limit:
295
- fetcher.stop()
296
- break
297
295
 
298
296
  if hit_limit:
299
297
  logger.warning(
@@ -393,31 +393,29 @@ def cmd_list(args: ListArgs) -> None:
393
393
  base_params["until"] = isoformat_datetime(args.until)
394
394
 
395
395
  limit = args.show_max
396
- fetcher = PaginatedFetcher(
396
+ emitted = 0
397
+ hit_limit = False
398
+ with PaginatedFetcher(
397
399
  client,
398
400
  "/v1/operations",
399
401
  base_params,
400
402
  json.loads,
401
403
  limit=limit,
402
404
  concurrency=CONTREE_CONCURRENCY,
403
- )
404
-
405
- emitted = 0
406
- hit_limit = False
407
- for page in fetcher:
408
- for op in page:
409
- if limit is not None and emitted >= limit:
410
- hit_limit = True
405
+ ) as fetcher:
406
+ for page in fetcher:
407
+ for op in page:
408
+ if limit is not None and emitted >= limit:
409
+ hit_limit = True
410
+ break
411
+ if args.quiet:
412
+ print(op["uuid"])
413
+ else:
414
+ formatter(**op)
415
+ emitted += 1
416
+ formatter.flush()
417
+ if hit_limit:
411
418
  break
412
- if args.quiet:
413
- print(op["uuid"])
414
- else:
415
- formatter(**op)
416
- emitted += 1
417
- formatter.flush()
418
- if hit_limit:
419
- fetcher.stop()
420
- break
421
419
 
422
420
  if hit_limit:
423
421
  logger.warning(
@@ -619,6 +619,17 @@ class PaginatedFetcher:
619
619
  """Signal that the caller has seen enough; skip pending fetches."""
620
620
  self._stop.set()
621
621
 
622
+ def __enter__(self) -> PaginatedFetcher:
623
+ return self
624
+
625
+ def __exit__(self, *_: object) -> None:
626
+ # Setting the stop event short-circuits any worker that hasn't
627
+ # started yet and prevents the iterator's refill from enqueueing
628
+ # more fetches. Callers wrap iteration in `with PaginatedFetcher(...)`
629
+ # so they don't have to remember an explicit `stop()` after
630
+ # breaking out of a paged loop.
631
+ self.stop()
632
+
622
633
  def _fetch(self, offset: int) -> list[dict[str, Any]]:
623
634
  if self._stop.is_set():
624
635
  return []
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "contree-cli"
3
- version = "0.7.0"
3
+ version = "0.7.1"
4
4
  description = "CLI client for the ConTree sandbox platform"
5
5
  readme = "README.md"
6
6
  requires-python = ">=3.10"
File without changes
File without changes