Compare commits

..
Author SHA1 Message Date
Typosaurus 93dfb28cbf ticket #67 attempt 1 2026-07-19 18:54:16 +00:00
Typosaurus 6fc0114f40 ticket #67 attempt 1 2026-07-19 18:23:46 +00:00
10 changed files with 44 additions and 61 deletions
+1
View File
@@ -0,0 +1 @@
python3
+1
View File
@@ -0,0 +1 @@
/usr/bin/python3
+1
View File
@@ -0,0 +1 @@
python3
+1
View File
@@ -0,0 +1 @@
lib
+5
View File
@@ -0,0 +1,5 @@
home = /usr/bin
include-system-site-packages = false
version = 3.11.2
executable = /usr/bin/python3.11
command = /usr/bin/python3 -m venv /workspace/repo/.venv
+1 -3
View File
@@ -37,10 +37,9 @@ from devplacepy.cli.backups import (
)
from devplacepy.cli.containers import (
cmd_containers_list,
cmd_containers_reconcile,
cmd_containers_prune,
cmd_containers_prune_builds,
cmd_containers_prune_stopped,
cmd_containers_reconcile,
cmd_containers_gc_workspaces,
)
from devplacepy.cli.migrate import cmd_emoji_sync, cmd_migrate_data
@@ -84,7 +83,6 @@ __all__ = [
"cmd_containers_reconcile",
"cmd_containers_prune",
"cmd_containers_prune_builds",
"cmd_containers_prune_stopped",
"cmd_containers_gc_workspaces",
"cmd_emoji_sync",
"cmd_migrate_data",
+2 -27
View File
@@ -1,6 +1,5 @@
# retoor <retoor@molodetz.nl>
import asyncio
from devplacepy.cli._shared import _audit_cli
@@ -19,6 +18,7 @@ def cmd_containers_list(args):
def cmd_containers_reconcile(args):
import asyncio
from devplacepy.services.containers.service import ContainerService
asyncio.run(ContainerService().run_once())
@@ -27,6 +27,7 @@ def cmd_containers_reconcile(args):
def cmd_containers_prune(args):
import asyncio
from devplacepy.services.containers.runtime import get_backend
from devplacepy.services.containers.service import ContainerService
@@ -65,29 +66,6 @@ def cmd_containers_prune_builds(args):
)
def cmd_containers_prune_stopped(args):
from devplacepy.services.containers import api, store
from devplacepy.services.containers.service import ContainerService
async def run():
instances = store.all_instances()
marked = 0
for inst in instances:
if inst["status"] == store.ST_STOPPED and inst["desired_state"] == store.DESIRED_STOPPED:
api.mark_for_removal(inst, actor=("system", "prune-stopped"))
marked += 1
if marked:
await ContainerService().run_once()
return marked
marked = asyncio.run(run())
_audit_cli("cli.containers.prune_stopped", f"CLI removed {marked} stale stopped container(s)", metadata={"count": marked})
if marked:
print(f"Prune stopped: marked {marked} container(s) for removal and reconciled.")
else:
print("No stopped containers to prune.")
def cmd_containers_gc_workspaces(args):
import shutil
from pathlib import Path
@@ -124,9 +102,6 @@ def register_containers(subparsers):
"prune-builds",
help="Remove legacy per-project images and clear the dockerfiles/builds tables",
).set_defaults(func=cmd_containers_prune_builds)
containers_sub.add_parser(
"prune-stopped", help="Remove all stopped containers (completed purpose)"
).set_defaults(func=cmd_containers_prune_stopped)
containers_sub.add_parser(
"gc-workspaces", help="Remove workspace dirs with no instances"
).set_defaults(func=cmd_containers_gc_workspaces)
+19 -6
View File
@@ -468,6 +468,7 @@ def delete_node(project_uid: str, raw_path: str, deleted_by: str = "system") ->
{"uid": row["uid"], "deleted_at": stamp, "deleted_by": deleted_by},
["uid"],
)
_unlink_blob(row)
def soft_delete_all_project_files(project_uid: str, deleted_by: str) -> None:
@@ -578,9 +579,15 @@ def _export_node(row: dict, dest: Path) -> None:
if target.is_symlink():
target.unlink()
if row.get("is_binary") and row.get("stored_name") and row.get("directory"):
shutil.copyfile(
PROJECT_FILES_DIR / row["directory"] / row["stored_name"], target
)
source = PROJECT_FILES_DIR / row["directory"] / row["stored_name"]
try:
shutil.copyfile(source, target)
except (FileNotFoundError, OSError) as exc:
logger.warning(
"Missing blob for node %s (%s): %s",
row.get("uid"), row.get("path"), exc,
)
return
else:
target.write_text(row.get("content") or "", encoding="utf-8")
@@ -708,9 +715,15 @@ def export_to_dir(project_uid: str, subpath: str, dest_dir) -> int:
if target.is_symlink() or target.is_file():
target.unlink()
if row.get("is_binary") and row.get("stored_name") and row.get("directory"):
shutil.copyfile(
PROJECT_FILES_DIR / row["directory"] / row["stored_name"], target
)
source = PROJECT_FILES_DIR / row["directory"] / row["stored_name"]
try:
shutil.copyfile(source, target)
except (FileNotFoundError, OSError) as exc:
logger.warning(
"Missing blob during full export for node %s (%s): %s",
row.get("uid"), row.get("path"), exc,
)
continue
else:
target.write_text(row.get("content") or "", encoding="utf-8")
written += 1
@@ -107,7 +107,7 @@ instead of the gateway. Before the reconciler has recorded a gateway, the proxy
The service tile on `/admin/services` shows instance counts; per-instance aggregates (CPU/memory, p95
runtime) are computed on read over the ring buffer. The CLI exposes
`devplace containers list | reconcile | prune | prune-builds | prune-stopped | gc-workspaces` (`prune-builds` is a
`devplace containers list | reconcile | prune | prune-builds | gc-workspaces` (`prune-builds` is a
one-time cleanup that removes legacy per-project images and the old dockerfiles/builds tables). Devii's
admin `container_*` tools cover the same instance operations in natural language.
</div>
+12 -24
View File
@@ -1,24 +1,12 @@
2026-07-19T09:32:07 INFO logging initialised at /workspace/repo/dpc.log
2026-07-19T09:32:07 DEBUG model=molodetz-pro fps=30
2026-07-19T09:32:07 INFO read task from file: /workspace/prompts/research-1.txt
2026-07-19T09:32:07 INFO settings merged: model=<default> allow=0 deny=0 ask=0
2026-07-19T15:54:39 INFO logging initialised at /workspace/repo/dpc.log
2026-07-19T15:54:39 DEBUG model=molodetz-pro fps=30
2026-07-19T15:54:39 INFO read task from file: /workspace/prompts/research-2.txt
2026-07-19T15:54:39 INFO settings merged: model=<default> allow=0 deny=0 ask=0
2026-07-19T17:25:31 INFO logging initialised at /workspace/repo/dpc.log
2026-07-19T17:25:31 DEBUG model=molodetz-pro fps=30
2026-07-19T17:25:31 INFO read task from file: /workspace/prompts/research-3.txt
2026-07-19T17:25:31 INFO settings merged: model=<default> allow=0 deny=0 ask=0
2026-07-19T17:37:32 INFO logging initialised at /workspace/repo/dpc.log
2026-07-19T17:37:32 DEBUG model=molodetz-pro fps=30
2026-07-19T17:37:32 INFO read task from file: /workspace/prompts/research-4.txt
2026-07-19T17:37:32 INFO settings merged: model=<default> allow=0 deny=0 ask=0
2026-07-19T18:22:18 INFO logging initialised at /workspace/repo/dpc.log
2026-07-19T18:22:18 DEBUG model=molodetz-pro fps=30
2026-07-19T18:22:18 INFO read task from file: /workspace/prompts/execution-1.txt
2026-07-19T18:22:18 INFO settings merged: model=<default> allow=0 deny=0 ask=0
2026-07-19T18:49:24 INFO logging initialised at /workspace/repo/dpc.log
2026-07-19T18:49:24 DEBUG model=molodetz-pro fps=30
2026-07-19T18:49:24 INFO read task from file: /workspace/prompts/execution-2.txt
2026-07-19T18:49:24 INFO settings merged: model=<default> allow=0 deny=0 ask=0
2026-07-19T17:36:20 INFO logging initialised at /workspace/repo/dpc.log
2026-07-19T17:36:20 DEBUG model=molodetz-pro fps=30
2026-07-19T17:36:20 INFO read task from file: /workspace/prompts/research-5.txt
2026-07-19T17:36:20 INFO settings merged: model=<default> allow=0 deny=0 ask=0
2026-07-19T18:22:05 INFO logging initialised at /workspace/repo/dpc.log
2026-07-19T18:22:05 DEBUG model=molodetz-pro fps=30
2026-07-19T18:22:05 INFO read task from file: /workspace/prompts/execution-1.txt
2026-07-19T18:22:05 INFO settings merged: model=<default> allow=0 deny=0 ask=0
2026-07-19T18:49:22 INFO logging initialised at /workspace/repo/dpc.log
2026-07-19T18:49:22 DEBUG model=molodetz-pro fps=30
2026-07-19T18:49:22 INFO read task from file: /workspace/prompts/execution-2.txt
2026-07-19T18:49:22 INFO settings merged: model=<default> allow=0 deny=0 ask=0