Commit Graph

134 Commits

Author SHA1 Message Date
0c02f0de50 fix(scheduler): suppress channel send when result is HEARTBEAT_OK
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-23 19:59:11 +00:00
b9a5f733c2 chore: auto-commit from dashboard 2026-04-23 09:44:20 +00:00
42797c0bbb chore: auto-commit from dashboard 2026-04-22 20:54:11 +00:00
bfc2283e6f chore: auto-commit from dashboard 2026-04-22 11:05:14 +00:00
51af0918a4 feat(email): send attachments as WhatsApp documents, fix forward sender
- Add /send-document endpoint to WhatsApp bridge (base64 document send)
- save_email_as_note() now saves attachment files to disk alongside note
- email_digest: extract original sender for Fwd: emails so header shows
  the real author, not the forwarder; send attachment files after summary
- email_forward: send attachment files as documents after text parts
- Add extract_original_sender() and save_email_attachment_files() helpers

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-22 07:50:40 +00:00
417de65069 fix(email): use original sender for forwarded emails in digest
Digest was attributing forwarded emails to the person who forwarded
them. Now Claude is instructed to identify the original sender from
the forwarded headers and ignore the forwarder entirely. Also drops
pleasantries/apologies from the summary — facts only.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-22 07:48:11 +00:00
c2455e6245 improve(email): switch digest prompt to factual briefing style
Previous prompt produced narrative, personal-tone summaries. New prompt
enforces third-person, journalistic style: who sent what to whom first,
then concrete facts, dates, and actions — no interpretation or filler.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-22 07:43:58 +00:00
56f6c0df01 feat(email): show attachments in digest and forward commands
Add get_email_attachments() helper that extracts filenames from MIME
parts. Email notes now include an Atașamente section; forwarded emails
show attachment names in the WhatsApp header.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-22 07:41:21 +00:00
eb693a2e71 improve(email): rewrite digest prompt for context-aware summaries
Rigid bullet schema worked for event emails but stripped all
narrative context from argumentative/organizational messages.
New prompt adapts structure to email type and prioritizes
completeness over brevity.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-21 20:33:34 +00:00
30678e6abf fix(email): send WhatsApp notification when no new emails found
Previously digest and forward commands silently exited when inbox
was empty, leaving the user with no feedback after the initial
"processing..." confirmation.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-21 20:29:58 +00:00
2dd5aee9a7 chore: auto-commit from dashboard 2026-04-21 13:56:53 +00:00
a5d054d16f docs(migration): record post-migration state and concrete rollback values
Migration executed 2026-04-21 10:04 UTC. Playbook now carries the actual
SHAs, backup paths, stripped credentials inventory, verification evidence,
and a rollback block with filled-in values for this specific cutover.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-21 10:28:53 +00:00
9bc5c3a3a2 chore: auto-commit from dashboard 2026-04-21 10:23:21 +00:00
d741541e23 test(dashboard): cover constants, git helper, cron endpoint, files sandbox 2026-04-21 07:22:48 +00:00
fa7c0fd1c6 docs(claude): reflect in-repo memory and dashboard layout after openclaw consolidation 2026-04-21 07:19:48 +00:00
bb917e0b33 feat(dashboard): add echo-taskboard.service template (systemd user) 2026-04-21 07:19:23 +00:00
0ac0f3b907 feat(dashboard): consolidate /api/git-commit into /api/eco/git-commit 2026-04-21 07:17:11 +00:00
e0abe5cdfc feat(dashboard): drop /api/agents and /api/activity endpoints 2026-04-21 07:16:20 +00:00
bee21594f5 test(cron): validate jobs.json schema per kind
Loads cron/jobs.json and asserts: unique names, valid cron expressions
(APScheduler parseable), bool enabled field; kind:"shell" entries must
have non-empty channel, non-empty command list of strings, valid
report_on, and timeout within [1, 3600] when present; claude entries
must have non-empty prompt, valid model, list-typed allowed_tools.
Sanity-checks that shell commands reference existing scripts in the
repo and that no imported claude prompt still points at /home/moltbot/clawd/.
2026-04-21 07:15:00 +00:00
dd8f40774f test(migrations): cover import script translation, skip list, and prompt rewrite
18 tests: --dry-run safety, UTC -> Bucharest hour-shift vs. already-tagged
Bucharest passthrough, antfarm/night-execute/YouTube: skip list behavior,
cd ~/clawd and absolute /home/moltbot/clawd/ rewrites, clawd-archive /
clawdbot negative-match guard, duplicate-name preserving existing entry,
--skip-disabled / --skip / --channel flags, non-cron schedule safe-skip,
translate_job enabled/model field preservation.
2026-04-21 07:14:51 +00:00
df8ccc694b docs: add MIGRATION-PLAYBOOK.md for manual cutover steps
Manual sequence Marius runs AFTER the PR merges. Pre-flight (tests,
backups), stop-services, ANAF live-state copy, dashboard migration,
memory inversion (clawd/memory -> echo-core/memory), systemd, crontab,
OpenClaw decommission, verification, and rollback path. Flagged at the
top as human-only -- no AI agent should auto-execute these steps.
2026-04-21 07:14:44 +00:00
84ab27a6b5 feat(scripts): add update_crontab.sh for post-migration crontab fix
Idempotent sed-based rewrite of any crontab line that references
/home/moltbot/clawd/tools/backup_config.sh so it points at the
echo-core copy. Safe to re-run; prints a single status line either way.
2026-04-21 07:14:38 +00:00
55e34afd59 docs(personality): update AGENTS for post-consolidation paths
Grep across personality/ for clawd|openclaw|clawdbot found no hits after
Lane A's earlier sweep. Single remaining operational reference to the
now-decommissioned night-execute cron has been softened to a generic
'add to approved-tasks.md' note.
2026-04-21 07:14:33 +00:00
5678138cc5 feat(config): add echo-work and echo-sprijin channel aliases
Imported claude jobs default channel to echo-work; grup-sprijin-5feb
and grup-sprijin-pregatire route to echo-sprijin. Existing echo-core
channel is preserved.
2026-04-21 07:14:28 +00:00
9fce04f212 feat(cron): import morning/evening/coaching/weekly claude jobs (disabled)
Runs tools/migrations/import_openclaw_jobs_2026-04.py against the real
openclaw jobs.json with --skip daily-morning-checks,archive-tasks,
monica-ion-blog,diagnostic-platou-financiar.

Imports 13 claude jobs: morning/evening report + coaching, exercise-snack-1/2/3,
weekly-planning-sun, content-discovery, provocare-reminder, grup-sprijin-5feb,
grup-sprijin-pregatire, heartbeat-2h. All import DISABLED except heartbeat-2h
(preserving its openclaw enabled flag). Cron schedules shifted UTC -> Bucharest.
clawd -> echo-core path rewrites applied.

heartbeat-2h imported with an empty openclaw prompt; filled with a minimal
status-check prompt so scheduler doesn't error on execution.
2026-04-21 07:14:23 +00:00
e964777f69 feat(cron): populate jobs.json with decomposed ANAF + security + archive jobs
Adds 5 kind:"shell" jobs (anaf-monitor, security-audit-daily,
kb-index-refresh, archive-tasks-daily, backup-config) and the new
insights-extract claude job (disabled placeholder). All cron schedules
are Europe/Bucharest local time. Decomposes openclaw's daily-morning-checks
mega-prompt per the Issue 15 eng-review decision.
2026-04-21 07:13:59 +00:00
5f87545b66 feat(migrations): add one-shot import_openclaw_jobs_2026-04 script
Audit-trail tool that translates OpenClaw's nested jobs.json schema
(schedule.expr with optional tz, payload.message, agentId, state) into
echo-core's flat schema. UTC -> Europe/Bucharest cron conversion with
DST-aware offset; Bucharest-tagged source expressions pass through
unchanged. Rewrites `cd ~/clawd` / `/home/moltbot/clawd/` -> echo-core
without matching `clawd-archive` or `clawdbot` substrings.

Built-in skip list covers night-execute and antfarm/feature-dev/*; YouTube:
prefix is auto-skipped. --dry-run, --skip-disabled, --skip, --channel,
--source, --target flags. Duplicate job names in target are skipped with
a warning; existing entries are preserved.
2026-04-21 07:13:50 +00:00
67d10c4c9a feat(dashboard): rewrite /api/cron for echo-core flat schema 2026-04-21 07:12:09 +00:00
b00d9d6fbd refactor(dashboard): split api.py into handler modules 2026-04-21 07:11:41 +00:00
af444d7066 test(anaf): assert monitor_v2 emits GSTACK-CRON marker as last stdout line
Four checks:
- The script file exists at the expected path.
- The source contains the marker print statement (fast regression guard).
- Running the script against an empty config produces a matching marker
  (^GSTACK-CRON: changes=\d+$) with changes=0.
- The marker is the last non-empty line of stdout so tailers can parse it.

The runtime test copies the script into a tmp cwd so that the script's
SCRIPT_DIR-relative state files (hashes.json, versions.json, snapshots/,
monitor.log) don't pollute the repo.
2026-04-21 07:05:46 +00:00
c82dbc5654 feat(anaf): emit GSTACK-CRON marker and exit 0 on successful run
The Echo-Core scheduler's report_on='changes' contract parses
^GSTACK-CRON: changes=\d+$ from stdout to decide whether to forward
the run's output to a channel. monitor_v2.py now prints that marker
as its final stdout line with num_changes from the current run.

Also switches the success return value from len(all_changes) to 0.
Previously, any run that detected changes (N>0) exited with a non-zero
status, which the scheduler treats as an error (always forwarded,
ignoring report_on). Exit code now signals only fatal errors; the
marker carries the change count.
2026-04-21 07:05:37 +00:00
b3ed653bb3 test(scheduler): cover shell-kind validation, execution, timezone, backward-compat
Adds four new test groups to tests/test_scheduler.py:

- TestTimezone: asserts AsyncIOScheduler is constructed with Europe/Bucharest.
- TestShellKind: 16 cases covering add_shell_job validation (duplicate name
  across claude/shell, invalid cron, empty/non-list/non-string command,
  bad report_on, bad timeout bounds/type, empty channel, custom report_on
  and timeout pass-through).
- TestShellExecute: 14 cases covering the report_on contract:
  - exit 0 + marker N>0 → forwards stdout
  - exit 0 + marker N==0 → silent
  - exit 0 + no marker   → silent + warning
  - report_on=always and =never variants
  - non-zero exit reports stderr even when report_on='never'
  - TimeoutExpired and launch exceptions report '[cron:X] Error: ...'
  - per-job timeout passed to subprocess.run; default 300 when None
  - subprocess.run receives the job's command list verbatim
  - stdout trimmed to 1500 ch; stderr trimmed to 500 ch
- TestBackwardCompat: a jobs.json entry without a 'kind' field dispatches
  to _execute_claude_job (never to _execute_shell_job); the existing Claude
  add_job/run_job round-trip still works with the old CLI invocation.
- TestMarkerRegex: parametrised positive/negative cases for _MARKER_RE.
2026-04-21 07:05:29 +00:00
e747491b85 feat(scheduler): add kind:"shell" jobs with Bucharest tz and GSTACK-CRON marker
- AsyncIOScheduler now runs in Europe/Bucharest so cron strings in jobs.json
  match local wall-clock time.
- New add_shell_job() validates name, cron, command list, channel, report_on
  (always|changes|never), and optional timeout (1..3600s). Existing add_job()
  stays untouched for the Claude path.
- _execute_job dispatches on job['kind'] (default 'claude'); legacy jobs
  without the field still route to the Claude executor. Refactored the
  Claude path into _execute_claude_job; new _execute_shell_job runs
  subprocess with _safe_env + PROJECT_ROOT cwd.
- Shell semantics: non-zero exit always forwards stderr (trimmed to 500 ch)
  as '[cron:NAME] exit CODE: STDERR' regardless of report_on. On exit 0,
  'always' forwards stdout (trimmed to 1500 ch), 'never' stays silent, and
  'changes' parses the GSTACK-CRON marker (^GSTACK-CRON: changes=\d+$) and
  forwards stdout only when N>0; missing/malformed marker logs a warning
  and stays silent.
- Timeout honoured per-job (falls back to JOB_TIMEOUT=300s).
2026-04-21 07:05:19 +00:00
ca9167d129 refactor(dashboard): normalize paths with constants block for echo-core 2026-04-21 07:02:56 +00:00
cd07e43533 feat(dashboard): copy from clawd 2026-04-21 07:01:30 +00:00
4e78ef7219 claude gstack 2026-04-21 05:47:37 +00:00
929d2e9c81 docs(tools): include Tailscale link to saved YouTube notes
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-21 05:45:15 +00:00
000b406c8d feat(newsletter): scan forward for multiple issues and re-enable cron
Loop through consecutive newsletter numbers until one is missing, so
backlog gets delivered in a single run. Use httpx for 404 check and
point to absolute claude binary path for cron. Enable job in config.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-21 05:45:10 +00:00
9314d63aa0 feat(email): add digest and forward commands to WhatsApp
Digest summarizes unread emails via Claude CLI; forward sends raw
content (split to 4096 chars). Wired as /email digest and
/email forward slash commands, plus instant per-guild sync on ready.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-21 05:45:02 +00:00
9d447b9ff1 fix(newsletter): use follow_redirects=False to avoid false positive on 404 redirect
Beehiiv redirects non-existent newsletters to /?404=... with HTTP 302.
With follow_redirects=True, the final 200 was misread as "newsletter exists".
Fix: disable redirect following so only a direct HTTP 200 = newsletter real.
Also reset state back to last_sent=13 (real).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-03 17:06:00 +00:00
5fafc29dc1 chore: auto-commit from dashboard 2026-04-02 19:43:01 +00:00
d9450ce70d chore: auto-commit from dashboard 2026-04-02 17:43:13 +00:00
006123a63b chore: auto-commit from dashboard 2026-03-03 20:17:07 +00:00
19e253ec43 feat(heartbeat): save emails to KB + fix memory symlink access
- heartbeat saves unread whitelisted emails via email_process --save --json
- fix: add --add-dir so Claude CLI subprocess can access memory/ symlink
- email_check/process: use BODY.PEEK[] to avoid marking emails as read
- email_process: simplify credential loading via credential_store only
- config: heartbeat interval 30→120min, quiet hours end 08→07

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-02-25 12:10:53 +00:00
08c330a371 corectii 2026-02-19 14:09:12 +00:00
95bd651377 openrouter 2026-02-17 09:30:35 +00:00
MoltBot Service
e8492c3fa9 chore: auto-commit from dashboard 2026-02-16 10:02:52 +00:00
MoltBot Service
fd9d962ad2 chore: auto-commit from dashboard 2026-02-15 23:23:29 +00:00
MoltBot Service
8ce7ea3bd6 refactor(heartbeat): move kb/embeddings reindex messages to log only
KB and embeddings reindex status messages were being sent to Discord
as heartbeat results. These are internal housekeeping — now logged
instead of surfaced to the user.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-15 22:52:28 +00:00
MoltBot Service
207b39f957 chore: update allowed_tools syntax + gitignore memory.bak
- Switch Bash permission patterns from space to colon separator
- Add memory.bak/ to .gitignore

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-15 21:14:53 +00:00