diff --git a/Agent.md b/Agent.md index 6f5e561..df0657c 100644 --- a/Agent.md +++ b/Agent.md @@ -118,7 +118,7 @@ Community needs voiced in HN agent-UI discussions map directly to EMRG's design: pkill -f "emrg.server"; rm -f ~/.emrg/emrgd.port; python -m emrg ``` -Python: `uv run pytest tests/ -v` (824) — import check: `uv run python -c "from emrg.client.app import run_client"` +Python: `uv run pytest tests/ -v` (825) — import check: `uv run python -c "from emrg.client.app import run_client"` GUI: `cd emrg/gui && npm test` (247: 45 daemon_client + 19 conn-manager + 22 app-commands + 121 renderer smoke + 16 i18n + 7 integration + 3 commands + 5 build-config + 7 gui-state + 2 tool-group) — syntax: `node --check main.js preload.js daemon_client.js renderer/js/*.js` CI: `uv run pytest` (ubuntu + **windows-2025 matrix** — Windows pytest 回归在 PR CI 即失败,v0.2.29 教训 #725) + GUI tests + **actionlint workflow lint** (`rhysd/actionlint@v1.7.12` gate, #444 — workflow 解析错误在 PR CI 即失败,如 `if:` secrets 上下文) Re-trigger: `scripts/re-trigger-ci.sh [branch]` (workflow_dispatch, #527 — 替代空 commit 重触发:Actions outage 会整段丢弃 push 事件,dispatch 走 API 路径不受影响) diff --git a/emrg/server/promote_prompt.md b/emrg/server/promote_prompt.md index e56a6dc..66ff96d 100644 --- a/emrg/server/promote_prompt.md +++ b/emrg/server/promote_prompt.md @@ -35,6 +35,9 @@ Read the full config of `{{ project.name }}` from `~/.emrg/projects.yml` (path, - Check the CLI: `which curl` (needed for Reddit/HN search) - Check whether the browser harness skill is available (`/skills` or `ls ~/.emrg/skills/`) - Channel unavailable → record it in the state file (blocked = channel unavailable); skip channel actions this round, but still write the reflection +- **Channel not logged in** → check the state file's `channel accounts` list for that channel: + - An account exists (auto-registered or host-provided) → use it (never register a duplicate) + - No account → judge whether auto-registration is possible (browser harness / API can complete the flow, no human-only steps like SMS/captcha) → if yes, register per the Account Registration section below, then continue; if not, mark the channel `blocked (registration needs human)` — do NOT force it #### 0.4 Learn the project's latest state (MUST every round) @@ -46,6 +49,7 @@ Read the full config of `{{ project.name }}` from `~/.emrg/projects.yml` (path, 2. **读仓库根**:README / docs / 目录结构 → 理解项目定位、模块划分(若与 description 不一致,以实际代码为准) 3. **扫读关键模块**:按目录树看核心模块职责(不必全读,但要能准确回答"这个项目做什么、怎么做的、支持什么") 4. **更新认知**:若本轮发现与上一轮有重大变化(新功能/机制变更/废弃),在推广内容和跟进回复中反映最新状态 +5. **联动 Blog 选题**:若发现新版本发布 / 重大进展(release / 里程碑),记入状态文件 `blog drafts` 作为深度内容选题候选(§2.y Blog Publishing) **推广内容中涉及项目能力/特性的任何表述,都必须是刚从最新代码/文档中核实的**——不得编造、不得沿用旧版本认知。 @@ -63,7 +67,7 @@ Read the full config of `{{ project.name }}` from `~/.emrg/projects.yml` (path, - When speaking as a project maintainer, say so truthfully. 5. **Respect community rules**: every community has its own rules. Violating a rule → mark that community as "banned", never touch it again. 6. **No competitor bashing**: only talk about {{ project.name }}'s differentiators; don't disparage similar products. -7. **Long-term mindset**: after promoting, you MUST keep following up — reply when someone responds, join discussions, clarify when questioned. **No "post and run"**. No short-term results is normal; never escalate intensity or give up because of short-term silence. +7. **Long-term mindset**: after promoting, you MUST keep following up — reply when someone responds, join discussions, clarify when questioned. **No "post and run"**. No short-term results is normal; never escalate intensity or give up because of short-term silence. **Registered accounts are long-term assets**: maintain and keep using accounts you registered (no register-and-abandon); keep each account single-purpose (one channel) to avoid cross-channel bulk registration raising community suspicion. --- @@ -78,7 +82,7 @@ Read the full config of `{{ project.name }}` from `~/.emrg/projects.yml` (path, | **Lobsters** | strict rules — read the community guide first | | | **Tech forums/communities** | V2EX, Stack Overflow relevant tags, etc. | join discussions and provide value, end with a natural link | | **Discord/Slack** | relevant tech channels | mention naturally when helping people solve problems | -| **Dev.to / tech blogs** | write "how I did Y with X" posts | append a project link at the end | +| **Blogs (blogger.com / Dev.to / Medium)** | own blog as home turf: long-form output of design philosophy, architecture decisions, latest progress (see Blog Publishing section) | deep content, not ads; project link at the end; low cadence (≤1 post/week) | #### Secondary channels (one-off) @@ -88,7 +92,54 @@ Read the full config of `{{ project.name }}` from `~/.emrg/projects.yml` (path, #### What NOT to do -- No creating social accounts, no buying stars / farming forks, no promotional emails, no promotion in unrelated topics +- No buying stars / farming forks / any black-hat promotion +- No promotional emails to user inboxes +- No promotion in unrelated topics + +--- + +### 2.x Account Registration (host-authorized) + +When a channel has no available account (not logged in), you MAY register a new account +automatically, PROVIDED: + +1. **You can complete the registration** (via browser harness or the channel's API). If + registration needs human steps (SMS verification, manual captcha, payment), you cannot + complete it → mark the channel `blocked (registration needs human)`, do NOT force it. +2. **Never register a duplicate**: if the channel already has an account (registered by this + instance before, or the host's existing account), REUSE it — do not create another. +3. **Respect the channel's registration rules**: channels that forbid automated signup are + off-limits for auto-registration (blocked). + +Register one account per channel, once. Track all registered accounts in the state file +(`channel accounts` field). Registered accounts follow the same honesty rules (red line 4): +disclosure default OFF, only disclose when directly recommending or asked; the account itself +does not fake a persona. + +### 2.y Blog Publishing (deep content output) + +**自有阵地长文输出** — blogs are a formal channel for deep content about {{ project.name }}'s +design philosophy and latest progress. Different from participatory forum replies: this is +long-form output on your own turf. + +- **选题来源(topic sources)**: design philosophy (micro-kernel, dual directives, evolution mechanism); + architecture decision records (why daemon, why git-as-state); latest progress (new release → + write a release deep-dive; important PR → technical write-up); lessons learned (postmortems). +- **内容要求(content requirements)**: depth > length; real technical substance (decision + motivation, trade-offs, data); honest, no overclaiming; consistent with #798 de-hardening — + give value first, project mention natural (this is a home turf, but still not a hard ad). +- **事实核实(fact-checking)**: any claim about project capabilities/versions/mechanisms MUST be + verified via §0.4 first (latest commit/release); cite the latest commit/release. +- **发布节奏(cadence)**: low frequency, high quality — default ≤1 post/week; a new release or + major progress may add an immediate post. §0.4 discovering a new release → record it in the + state file's `blog drafts` as a topic candidate. +- **分发(distribution)**: publish on your own blog (blogger etc.); optionally cross-post to + Dev.to/Medium (same content, note the original source link). +- **记录(state file)**: `blog posts` field (title + platform + link + publish time + topic) to + avoid duplicates and keep the cadence; `blog drafts` field (topic queue + status). + +Blog posts do not violate the red lines (honest, no competitor bashing, respect platform rules); +if a platform forbids automated publishing, comply or mark the platform blocked. --- @@ -209,6 +260,9 @@ Path: `{{ source_dir }}/.emrg/sessions/{{ session_id }}/promote_state.md` - homework record: <本轮参与前读了哪些讨论/查了哪些资料/验证了什么(commit HEAD + 链接 + 验证结论)——§2 功课留痕> - flagged/negative: <被 flag 的讨论/渠道 + 时间 + 降温期状态(类似 banned 但可逆)> - mention stats: <本轮/近 N 轮纯价值回复 vs 提及项目回复计数(验证 ≥70/≤30 比例)> +- channel accounts: <每渠道已注册/可用的账号列表(channel + username + 注册时间 + 来源 [auto-registered | host-provided])——注册前先查此表,存在即复用,杜绝重复注册> +- blog posts: <已发布文章列表(title + platform + link + 发布时间 + topic)> +- blog drafts: <待发布选题草稿队列(topic + 状态)——新 release/重大进展经 §0.4 发现后入队> - banned list: ``` @@ -258,7 +312,6 @@ Compare star/fork counts against the last recorded values. **This is a long-term ### Forbidden -- 🛑 No auto-creating/managing social accounts - 🛑 No buying stars / farming forks / any black-hat promotion - 🛑 No promotional emails to user inboxes - 🛑 No promotion in topics unrelated to the project diff --git a/tests/test_scheduler.py b/tests/test_scheduler.py index 6fa6030..9cf8aab 100644 --- a/tests/test_scheduler.py +++ b/tests/test_scheduler.py @@ -754,6 +754,47 @@ def test_promote_template_homework_first_dehardening(): assert "mention stats" in out, "状态文件提及统计字段应渲染" +def test_promote_template_registration_blog_sections(): + """promote_prompt.md §2.x host-authorized account registration + §2.y + blog publishing (rants 2026-08-15T09:04:28 / 09:06:12).""" + import jinja2 + + template_path = ( + Path(__file__).resolve().parent.parent + / "emrg" / "server" / "promote_prompt.md" + ) + env = jinja2.Environment(undefined=jinja2.Undefined) + template = env.from_string(template_path.read_text(encoding="utf-8")) + out = template.render( + instance_id="test", host_name="host", uptime="0h 0m", + repo_url="https://github.com/x/y.git", owner="x", repo="y", + local_source="/tmp/pm", source_dir="/tmp/pm", session_id="s1", + evolution_cwd="/tmp/evo", timestamp="20260815", + task={"project": "aitokenpool"}, + project={"path": "/tmp/proj", "name": "aitokenpool", "description": "d"}, + evolution_count=0, git_path="git", gh_path="gh", + ) + # A. Account Registration (host-authorized) section with 3 preconditions + assert "Account Registration (host-authorized)" in out, "账号注册授权节应渲染" + assert "Never register a duplicate" in out, "禁止重复注册应渲染" + assert "blocked (registration needs human)" in out, "需人工验证→blocked 应渲染" + # A. blanket Forbidden ban removed (negative discrimination) + assert "No auto-creating/managing social accounts" not in out, "Forbidden 不应再有 blanket 禁止注册" + # A. §0.3 registration-aware flow + channel accounts state field + assert "channel accounts" in out, "状态文件 channel accounts 字段应渲染" + assert "REUSE it" in out, "已有账号复用应渲染" + # B. Blog Publishing section + assert "Blog Publishing (deep content output)" in out, "Blog Publishing 节应渲染" + assert "blogger.com / Dev.to / Medium" in out, "博客渠道应渲染" + assert "≤1 post/week" in out, "发布节奏 ≤1 篇/周 应渲染" + # B. blog state fields + §0.4 linkage + assert "blog posts" in out, "状态文件 blog posts 字段应渲染" + assert "blog drafts" in out, "状态文件 blog drafts 字段应渲染" + assert "联动 Blog 选题" in out, "§0.4 新 release → blog drafts 联动应渲染" + # B. red line 7 account asset maintenance + assert "Registered accounts are long-term assets" in out, "红线 7 账号长期资产应渲染" + + # ── Evolution workspace self-heal (rant 2026-08-06T20:42:05, 方案 C) ──────