chore: add retoor header to all devplacepy source files and update style agent header rule

The diff adds the mandatory `retoor <retoor@molodetz.nl>` header comment to every `.py` file under `devplacepy/` (including `__init__.py` and `routers/__init__.py`), and updates the `StyleAgent` in `agents/style.py` to instruct agents to only add the header on created or already-edited files rather than sweeping the entire repo. The `agents/base.py` operating protocol is also revised to reorder and clarify tool discipline rules.
This commit is contained in:
2026-06-11 23:58:46 +00:00
parent fd64a6f1a7
commit 7fc9b0f715
127 changed files with 267 additions and 25 deletions
+2
View File
@@ -0,0 +1,2 @@
# retoor <retoor@molodetz.nl>
+2
View File
@@ -1,3 +1,5 @@
# retoor <retoor@molodetz.nl>
import asyncio
import ipaddress
import logging
+2
View File
@@ -1,3 +1,5 @@
# retoor <retoor@molodetz.nl>
import logging
logger = logging.getLogger(__name__)
+2
View File
@@ -1,3 +1,5 @@
# retoor <retoor@molodetz.nl>
import time
from collections import OrderedDict
+2
View File
@@ -1,3 +1,5 @@
# retoor <retoor@molodetz.nl>
import argparse
import sys
from devplacepy.database import get_table
+2
View File
@@ -1,3 +1,5 @@
# retoor <retoor@molodetz.nl>
from pathlib import Path
from dotenv import load_dotenv
from os import environ
+2
View File
@@ -1,3 +1,5 @@
# retoor <retoor@molodetz.nl>
TOPICS = ["devlog", "showcase", "question", "rant", "fun", "random", "signals"]
REACTION_EMOJI = [
+2
View File
@@ -1,3 +1,5 @@
# retoor <retoor@molodetz.nl>
import dataset
import logging
from collections import defaultdict
+2
View File
@@ -1,3 +1,5 @@
# retoor <retoor@molodetz.nl>
from devplacepy import schemas
from devplacepy.constants import TOPICS, REACTION_EMOJI
from devplacepy.docs_examples import schema_example, action_example
+2
View File
@@ -1,3 +1,5 @@
# retoor <retoor@molodetz.nl>
from typing import Any, Union, get_args, get_origin
from pydantic import BaseModel
+2
View File
@@ -1,3 +1,5 @@
# retoor <retoor@molodetz.nl>
import base64
import json
import re
+2
View File
@@ -1,3 +1,5 @@
# retoor <retoor@molodetz.nl>
from devplacepy.database import (
db,
get_table,
+2
View File
@@ -1,3 +1,5 @@
# retoor <retoor@molodetz.nl>
import html
import math
import re
+2
View File
@@ -1,3 +1,5 @@
# retoor <retoor@molodetz.nl>
import fcntl
import logging
import os
+2
View File
@@ -1,3 +1,5 @@
# retoor <retoor@molodetz.nl>
from datetime import datetime
from typing import Literal, Optional
from pydantic import BaseModel, Field, field_validator, model_validator
+2
View File
@@ -1,3 +1,5 @@
# retoor <retoor@molodetz.nl>
import logging
from fastapi import Request
+2
View File
@@ -0,0 +1,2 @@
# retoor <retoor@molodetz.nl>
+2
View File
@@ -1,3 +1,5 @@
# retoor <retoor@molodetz.nl>
import json
import logging
from typing import Annotated
+2
View File
@@ -1,3 +1,5 @@
# retoor <retoor@molodetz.nl>
import hashlib
import secrets
import logging
+2
View File
@@ -1,3 +1,5 @@
# retoor <retoor@molodetz.nl>
import hashlib
import logging
from fastapi import APIRouter, Request
+2
View File
@@ -1,3 +1,5 @@
# retoor <retoor@molodetz.nl>
import logging
from typing import Annotated
from datetime import datetime, timezone
+2
View File
@@ -1,3 +1,5 @@
# retoor <retoor@molodetz.nl>
import logging
from typing import Annotated
from datetime import datetime, timezone
+2
View File
@@ -1,3 +1,5 @@
# retoor <retoor@molodetz.nl>
import logging
from fastapi import APIRouter, Request
from fastapi.responses import HTMLResponse, RedirectResponse, Response
+2
View File
@@ -1,3 +1,5 @@
# retoor <retoor@molodetz.nl>
import logging
from fastapi import APIRouter, Request
from fastapi.responses import HTMLResponse
+2
View File
@@ -1,3 +1,5 @@
# retoor <retoor@molodetz.nl>
import logging
from datetime import datetime, timezone
from fastapi import APIRouter, Request
+2
View File
@@ -1,3 +1,5 @@
# retoor <retoor@molodetz.nl>
import logging
from typing import Annotated
from fastapi import APIRouter, Request, Form
+2
View File
@@ -1,3 +1,5 @@
# retoor <retoor@molodetz.nl>
import logging
from fastapi import APIRouter, Request
from fastapi.responses import HTMLResponse
+2
View File
@@ -1,3 +1,5 @@
# retoor <retoor@molodetz.nl>
import logging
from fastapi import APIRouter, Request
from devplacepy.database import get_table
+2
View File
@@ -1,3 +1,5 @@
# retoor <retoor@molodetz.nl>
import logging
from typing import Annotated
from datetime import datetime, timezone
+2
View File
@@ -1,3 +1,5 @@
# retoor <retoor@molodetz.nl>
import logging
from datetime import datetime, timedelta, timezone
from fastapi import APIRouter, Request
+2
View File
@@ -1,3 +1,5 @@
# retoor <retoor@molodetz.nl>
import logging
from datetime import datetime, timedelta, timezone
from fastapi import APIRouter, Request
+2
View File
@@ -1,3 +1,5 @@
# retoor <retoor@molodetz.nl>
import logging
from fastapi import APIRouter, Request, HTTPException
from devplacepy.services.manager import service_manager
+2
View File
@@ -1,3 +1,5 @@
# retoor <retoor@molodetz.nl>
import logging
from typing import Annotated
from datetime import datetime, timezone
+2
View File
@@ -1,3 +1,5 @@
# retoor <retoor@molodetz.nl>
import logging
from typing import Annotated
from fastapi import APIRouter, Request, Form
+2
View File
@@ -1,3 +1,5 @@
# retoor <retoor@molodetz.nl>
import logging
from typing import Annotated
from sqlalchemy import or_
+2
View File
@@ -1,3 +1,5 @@
# retoor <retoor@molodetz.nl>
import logging
from fastapi import APIRouter, Request
from fastapi.responses import PlainTextResponse, Response
+2
View File
@@ -1,3 +1,5 @@
# retoor <retoor@molodetz.nl>
import logging
from fastapi import APIRouter, Request
from fastapi.responses import HTMLResponse, JSONResponse
+2
View File
@@ -1,3 +1,5 @@
# retoor <retoor@molodetz.nl>
import logging
from pathlib import Path
from typing import Annotated
+2
View File
@@ -1,3 +1,5 @@
# retoor <retoor@molodetz.nl>
import logging
from typing import Annotated
from datetime import datetime, timezone
+1 -7
View File
@@ -1,10 +1,4 @@
"""Pydantic response models for JSON content negotiation.
Every model uses ``extra="ignore"`` so it can be validated directly against the
dict context a template already receives, dropping internal keys (request, SEO)
and - importantly - sensitive user fields (email, api_key, password_hash) that
are never part of ``UserOut``.
"""
# retoor <retoor@molodetz.nl>
from __future__ import annotations
+2
View File
@@ -1,3 +1,5 @@
# retoor <retoor@molodetz.nl>
import json
import logging
import os
+2
View File
@@ -1,3 +1,5 @@
# retoor <retoor@molodetz.nl>
from devplacepy.services.base import BaseService
from devplacepy.services.manager import service_manager
+2
View File
@@ -1,3 +1,5 @@
# retoor <retoor@molodetz.nl>
import asyncio
import json
import logging
+2
View File
@@ -1,3 +1,5 @@
# retoor <retoor@molodetz.nl>
from devplacepy.services.bot.service import BotsService
__all__ = ["BotsService"]
+2
View File
@@ -1,3 +1,5 @@
# retoor <retoor@molodetz.nl>
import asyncio
import hashlib
import logging
+2
View File
@@ -1,3 +1,5 @@
# retoor <retoor@molodetz.nl>
import asyncio
import logging
import random
+2
View File
@@ -1,3 +1,5 @@
# retoor <retoor@molodetz.nl>
import random
from pathlib import Path
+2
View File
@@ -1,3 +1,5 @@
# retoor <retoor@molodetz.nl>
import json
import logging
import random
+2
View File
@@ -1,3 +1,5 @@
# retoor <retoor@molodetz.nl>
import json
import logging
import time
+3 -1
View File
@@ -1,3 +1,5 @@
# retoor <retoor@molodetz.nl>
import fcntl
import json
import logging
@@ -44,7 +46,7 @@ class ArticleRegistry:
fd = os.open(str(self.path), os.O_RDWR | os.O_CREAT)
fcntl.flock(fd, fcntl.LOCK_EX)
data = {}
if os.path.getsize(str(self.path)) > 0:
if self.path.stat().st_size > 0:
chunks = []
while True:
chunk = os.read(fd, 65536)
+2
View File
@@ -1,3 +1,5 @@
# retoor <retoor@molodetz.nl>
from dataclasses import dataclass
from pathlib import Path
+2
View File
@@ -1,3 +1,5 @@
# retoor <retoor@molodetz.nl>
import asyncio
import importlib
import logging
+2
View File
@@ -1,3 +1,5 @@
# retoor <retoor@molodetz.nl>
import json
import logging
import os
-2
View File
@@ -123,8 +123,6 @@ async def _bootstrap_auth(client: PlatformClient, settings: Settings) -> str:
def _resolve_owner(settings: Settings) -> tuple[str, str]:
"""Resolve the local DevPlace user behind the CLI's credentials so the CLI shares the
same per-user memory, tasks, and admin analytics as the web session for that account."""
try:
from devplacepy.database import db, get_table
@@ -56,8 +56,6 @@ NAT64_PREFIXES = (
def _effective_address(address: Any) -> Any:
"""Resolve NAT64 / IPv4-mapped IPv6 to the embedded IPv4 so DNS64 networks
don't make public sites look like reserved addresses."""
if isinstance(address, ipaddress.IPv6Address):
if address.ipv4_mapped is not None:
return address.ipv4_mapped
+13 -7
View File
@@ -6,27 +6,33 @@ import shutil
import sys
import zipfile
import zlib
from pathlib import Path
FIXED_DATE = (1980, 1, 1, 0, 0, 0)
CHUNK_SIZE = 1024 * 1024
def _build(source_dir: str, output_path: str) -> dict:
bytes_in = 0
file_count = 0
dir_count = 0
source_path = Path(source_dir)
output_path_obj = Path(output_path)
with zipfile.ZipFile(output_path, "w", zipfile.ZIP_DEFLATED) as archive:
for root, dirs, files in os.walk(source_dir):
dirs.sort()
root_path = Path(root)
for name in dirs:
dir_count += 1
arcname = os.path.relpath(os.path.join(root, name), source_dir) + "/"
arcname = str(Path(root_path / name).relative_to(source_path)) + "/"
info = zipfile.ZipInfo(arcname, date_time=FIXED_DATE)
info.external_attr = (0o040755 << 16) | 0x10
archive.writestr(info, b"")
for name in sorted(files):
full = os.path.join(root, name)
arcname = os.path.relpath(full, source_dir)
bytes_in += os.path.getsize(full)
full = str(root_path / name)
arcname = str(Path(full).relative_to(source_path))
bytes_in += Path(full).stat().st_size
info = zipfile.ZipInfo(arcname, date_time=FIXED_DATE)
info.compress_type = zipfile.ZIP_DEFLATED
info.external_attr = 0o644 << 16
@@ -36,12 +42,12 @@ def _build(source_dir: str, output_path: str) -> dict:
crc = 0
with open(output_path, "rb") as handle:
for chunk in iter(lambda: handle.read(1024 * 1024), b""):
for chunk in iter(lambda: handle.read(CHUNK_SIZE), b""):
crc = zlib.crc32(chunk, crc)
return {
"bytes_in": bytes_in,
"bytes_out": os.path.getsize(output_path),
"bytes_out": output_path_obj.stat().st_size,
"file_count": file_count,
"dir_count": dir_count,
"crc32": crc & 0xFFFFFFFF,
@@ -53,7 +59,7 @@ def main(argv: list) -> int:
sys.stderr.write("usage: zip_worker <source_dir> <output_zip>\n")
return 2
source_dir, output_path = argv[1], argv[2]
if not os.path.isdir(source_dir):
if not Path(source_dir).is_dir():
sys.stderr.write(f"source directory not found: {source_dir}\n")
return 3
stats = _build(source_dir, output_path)
+2
View File
@@ -1,3 +1,5 @@
# retoor <retoor@molodetz.nl>
import asyncio
import logging
+2
View File
@@ -1,3 +1,5 @@
# retoor <retoor@molodetz.nl>
import logging
import os
import re
@@ -1,3 +1,5 @@
# retoor <retoor@molodetz.nl>
from devplacepy.services.openai_gateway.service import GatewayService
__all__ = ["GatewayService"]
@@ -1,3 +1,5 @@
# retoor <retoor@molodetz.nl>
UPSTREAM_URL_DEFAULT = "https://api.deepseek.com/chat/completions"
MODEL_DEFAULT = "deepseek-v4-flash"
TIMEOUT_DEFAULT = 300
@@ -1,3 +1,5 @@
# retoor <retoor@molodetz.nl>
import asyncio
import json
import logging
@@ -1,3 +1,5 @@
# retoor <retoor@molodetz.nl>
import json
import logging
import os
@@ -1,3 +1,5 @@
# retoor <retoor@molodetz.nl>
import asyncio
import hashlib
import logging
+2
View File
@@ -1,3 +1,5 @@
/* retoor <retoor@molodetz.nl> */
.admin-layout {
display: grid;
grid-template-columns: var(--sidebar-width) 1fr;
+2
View File
@@ -1,3 +1,5 @@
/* retoor <retoor@molodetz.nl> */
.attachment-gallery {
display: flex;
flex-wrap: wrap;
+2
View File
@@ -1,3 +1,5 @@
/* retoor <retoor@molodetz.nl> */
.auth-page {
min-height: 100vh;
display: flex;
+2
View File
@@ -1,3 +1,5 @@
/* retoor <retoor@molodetz.nl> */
.error-page {
text-align: center;
padding: 4rem 1rem;
+2
View File
@@ -1,3 +1,5 @@
/* retoor <retoor@molodetz.nl> */
.bugs-layout {
max-width: 720px;
margin: 0 auto;
+2
View File
@@ -1,3 +1,5 @@
/* retoor <retoor@molodetz.nl> */
.dialog-overlay {
display: none;
position: fixed;
+2
View File
@@ -1,3 +1,5 @@
/* retoor <retoor@molodetz.nl> */
.docs-layout {
display: grid;
grid-template-columns: var(--sidebar-width, 240px) 1fr;
+2
View File
@@ -1,3 +1,5 @@
/* retoor <retoor@molodetz.nl> */
.reaction-bar {
display: inline-flex;
align-items: center;
+2
View File
@@ -1,3 +1,5 @@
/* retoor <retoor@molodetz.nl> */
.feed-layout {
display: grid;
grid-template-columns: var(--sidebar-width) 1fr 280px;
+2
View File
@@ -1,3 +1,5 @@
/* retoor <retoor@molodetz.nl> */
.gist-length-error {
margin-top: 0.5rem;
padding: 0.75rem;
+2
View File
@@ -1,3 +1,5 @@
/* retoor <retoor@molodetz.nl> */
.landing {
min-height: 100vh;
background: var(--bg-gradient);
+2
View File
@@ -1,3 +1,5 @@
/* retoor <retoor@molodetz.nl> */
img[data-lightbox] {
cursor: zoom-in;
}
+2
View File
@@ -1,3 +1,5 @@
/* retoor <retoor@molodetz.nl> */
.rendered-content {
line-height: 1.65;
word-break: break-word;
+2
View File
@@ -1,3 +1,5 @@
/* retoor <retoor@molodetz.nl> */
.media-grid {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(160px, 1fr));
+2
View File
@@ -1,3 +1,5 @@
/* retoor <retoor@molodetz.nl> */
.mention-wrapper {
position: relative;
width: 100%;
+2
View File
@@ -1,3 +1,5 @@
/* retoor <retoor@molodetz.nl> */
.messages-layout {
display: grid;
grid-template-columns: minmax(0, 320px) 1fr;
+2
View File
@@ -1,3 +1,5 @@
/* retoor <retoor@molodetz.nl> */
.news-page {
max-width: 960px;
margin: 0 auto;
+2
View File
@@ -1,3 +1,5 @@
/* retoor <retoor@molodetz.nl> */
.notifications-page {
max-width: 640px;
margin: 0 auto;
+2
View File
@@ -1,3 +1,5 @@
/* retoor <retoor@molodetz.nl> */
.post-page {
max-width: 720px;
margin: 0 auto;
+2
View File
@@ -1,3 +1,5 @@
/* retoor <retoor@molodetz.nl> */
.profile-layout {
display: grid;
grid-template-columns: 280px 1fr;
+2
View File
@@ -1,3 +1,5 @@
/* retoor <retoor@molodetz.nl> */
.pf-page {
display: flex;
flex-direction: column;
+2
View File
@@ -1,3 +1,5 @@
/* retoor <retoor@molodetz.nl> */
.projects-layout {
display: grid;
grid-template-columns: var(--sidebar-width) 1fr;
+2
View File
@@ -1,3 +1,5 @@
/* retoor <retoor@molodetz.nl> */
.services-page {
max-width: 900px;
margin: 0 auto;
+2
View File
@@ -1,3 +1,5 @@
/* retoor <retoor@molodetz.nl> */
.sidebar-card {
position: sticky;
top: calc(var(--nav-height) + 1rem);
+2
View File
@@ -1,3 +1,5 @@
/* retoor <retoor@molodetz.nl> */
:root {
--bg-primary: #0f0a1a;
--bg-secondary: #1a1028;
+2
View File
@@ -1,3 +1,5 @@
// retoor <retoor@molodetz.nl>
import { ApiTester } from "./ApiTester.js";
import { CodeCopy } from "./CodeCopy.js";
+2
View File
@@ -1,3 +1,5 @@
// retoor <retoor@molodetz.nl>
import { Http } from "./Http.js";
import { Toast } from "./Toast.js";
+2
View File
@@ -1,3 +1,5 @@
// retoor <retoor@molodetz.nl>
import { contentRenderer } from "./ContentRenderer.js";
import { CodeBlock } from "./CodeBlock.js";
+2
View File
@@ -1,3 +1,5 @@
// retoor <retoor@molodetz.nl>
import "./components/index.js";
import { ModalManager } from "./ModalManager.js";
import { FormManager } from "./FormManager.js";
+2
View File
@@ -1,3 +1,5 @@
// retoor <retoor@molodetz.nl>
export class Avatar {
static imgElement(username, size = 24) {
const img = document.createElement("img");
+2
View File
@@ -1,3 +1,5 @@
// retoor <retoor@molodetz.nl>
import { OptimisticAction } from "./OptimisticAction.js";
export class BookmarkManager extends OptimisticAction {
+2
View File
@@ -1,3 +1,5 @@
// retoor <retoor@molodetz.nl>
export const CodeBlock = {
highlight(code) {
if (typeof hljs === "undefined" || !code) return;
+2
View File
@@ -1,3 +1,5 @@
// retoor <retoor@molodetz.nl>
import { CodeBlock } from "./CodeBlock.js";
export class CodeCopy {
+2
View File
@@ -1,3 +1,5 @@
// retoor <retoor@molodetz.nl>
import { Http } from "./Http.js";
export class CommentManager {
+2
View File
@@ -1,3 +1,5 @@
// retoor <retoor@molodetz.nl>
import { contentRenderer } from "./ContentRenderer.js";
import { MentionInput } from "./MentionInput.js";
import { EmojiPicker } from "./EmojiPicker.js";
+2
View File
@@ -1,3 +1,5 @@
// retoor <retoor@molodetz.nl>
export class ContentRenderer {
constructor() {
this.emojiMap = this.buildEmojiMap();
+2
View File
@@ -1,3 +1,5 @@
// retoor <retoor@molodetz.nl>
import { Http } from "./Http.js";
import { Poller } from "./Poller.js";

Some files were not shown because too many files have changed in this diff Show More