openclaw-telegram-manager 2.3.2 → 2.5.0

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 (55) hide show
  1. package/README.md +75 -58
  2. package/dist/commands/autopilot.d.ts +4 -0
  3. package/dist/commands/autopilot.d.ts.map +1 -1
  4. package/dist/commands/autopilot.js +14 -11
  5. package/dist/commands/autopilot.js.map +1 -1
  6. package/dist/commands/daily-report.d.ts +6 -0
  7. package/dist/commands/daily-report.d.ts.map +1 -1
  8. package/dist/commands/daily-report.js +17 -16
  9. package/dist/commands/daily-report.js.map +1 -1
  10. package/dist/commands/doctor-all.d.ts.map +1 -1
  11. package/dist/commands/doctor-all.js +72 -11
  12. package/dist/commands/doctor-all.js.map +1 -1
  13. package/dist/commands/doctor.d.ts.map +1 -1
  14. package/dist/commands/doctor.js +3 -11
  15. package/dist/commands/doctor.js.map +1 -1
  16. package/dist/commands/init.d.ts.map +1 -1
  17. package/dist/commands/init.js +51 -33
  18. package/dist/commands/init.js.map +1 -1
  19. package/dist/commands/rename.d.ts.map +1 -1
  20. package/dist/commands/rename.js +2 -4
  21. package/dist/commands/rename.js.map +1 -1
  22. package/dist/commands/snooze.js +2 -2
  23. package/dist/commands/snooze.js.map +1 -1
  24. package/dist/commands/status.d.ts.map +1 -1
  25. package/dist/commands/status.js +74 -6
  26. package/dist/commands/status.js.map +1 -1
  27. package/dist/commands/sync.js +1 -1
  28. package/dist/commands/sync.js.map +1 -1
  29. package/dist/commands/upgrade.js +2 -2
  30. package/dist/commands/upgrade.js.map +1 -1
  31. package/dist/lib/capsule.js +3 -3
  32. package/dist/lib/capsule.js.map +1 -1
  33. package/dist/lib/doctor-checks.d.ts.map +1 -1
  34. package/dist/lib/doctor-checks.js +26 -59
  35. package/dist/lib/doctor-checks.js.map +1 -1
  36. package/dist/lib/include-generator.d.ts +1 -1
  37. package/dist/lib/include-generator.js +4 -4
  38. package/dist/lib/include-generator.js.map +1 -1
  39. package/dist/lib/registry.d.ts.map +1 -1
  40. package/dist/lib/registry.js +3 -0
  41. package/dist/lib/registry.js.map +1 -1
  42. package/dist/lib/telegram.d.ts +9 -4
  43. package/dist/lib/telegram.d.ts.map +1 -1
  44. package/dist/lib/telegram.js +87 -76
  45. package/dist/lib/telegram.js.map +1 -1
  46. package/dist/lib/types.d.ts +2 -2
  47. package/dist/lib/types.js +1 -1
  48. package/dist/lib/types.js.map +1 -1
  49. package/dist/plugin.js +665 -591
  50. package/dist/setup.js +49 -4
  51. package/dist/setup.js.map +1 -1
  52. package/dist/tool.js +0 -18
  53. package/dist/tool.js.map +1 -1
  54. package/package.json +10 -1
  55. package/skills/tm/SKILL.md +8 -8
package/README.md CHANGED
@@ -1,25 +1,23 @@
1
- # openclaw-telegram-manager [WIP]
2
-
3
- > **This project is a work in progress and is not yet functional.** I'm actively working on it — expect breaking changes, incomplete features, and rough edges. Feel free to watch the repo, but don't use it in production yet.
1
+ # Persistent Memory for OpenClaw Telegram Topics
4
2
 
5
3
  [![CI](https://github.com/jcoulaud/openclaw-telegram-manager/actions/workflows/ci.yml/badge.svg)](https://github.com/jcoulaud/openclaw-telegram-manager/actions/workflows/ci.yml)
6
4
  [![npm version](https://img.shields.io/npm/v/openclaw-telegram-manager)](https://www.npmjs.com/package/openclaw-telegram-manager)
7
5
  [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](LICENSE)
8
6
 
9
- An [OpenClaw](https://openclaw.ai) plugin that gives each Telegram topic its own persistent workspace — status, todos, commands, links, notes — so nothing gets lost when the agent resets or context gets compacted.
7
+ `openclaw-telegram-manager` — an [OpenClaw](https://openclaw.ai) plugin that gives each Telegram topic its own persistent memory, so nothing gets lost when the AI resets or context gets compacted.
10
8
 
11
9
  ## The problem
12
10
 
13
- When OpenClaw manages a Telegram group with topics, each topic is basically a separate project. But after a reset or context compaction, the agent forgets everything: what it was working on, what's left to do, what commands matter.
11
+ When OpenClaw manages a Telegram group with topics, each topic is basically a separate project. But after a reset or context compaction, the AI forgets everything: what it was working on, what's left to do, what commands matter.
14
12
 
15
- This plugin fixes that. Each topic gets a folder of markdown files (a "capsule") that the agent reads on startup. It picks up right where it left off.
13
+ This plugin fixes that. Each topic gets a folder of persistent files that the AI reads automatically on startup. It picks up right where it left off.
16
14
 
17
15
  ## Prerequisites
18
16
 
19
17
  - [OpenClaw](https://openclaw.ai) `>=2026.1.0` installed and running
20
18
  - A Telegram group with [topics enabled](https://telegram.org/blog/tms-in-groups-collectible-usernames#topics-in-groups) and managed by OpenClaw
21
19
 
22
- ## Getting started
20
+ ## Install
23
21
 
24
22
  ```bash
25
23
  npx openclaw-telegram-manager setup
@@ -27,59 +25,78 @@ npx openclaw-telegram-manager setup
27
25
 
28
26
  That's it. The setup script installs the plugin, patches your config, creates the workspace, and restarts the OpenClaw gateway. It's idempotent — running it twice won't break anything.
29
27
 
30
- **Security warnings during install:** OpenClaw's automatic scanner may flag `child_process` and `process.env` usage. These are expected — the setup script calls `openclaw --version`, `openclaw plugins install`, and `openclaw gateway restart`, and reads `process.env` for config directory detection. No data is sent externally.
28
+ <details>
29
+ <summary>Security warnings during install</summary>
30
+
31
+ OpenClaw's automatic scanner may flag `child_process` and `process.env` usage. These are expected — the setup script calls `openclaw --version`, `openclaw plugins install`, and `openclaw gateway restart`, and reads `process.env` for config directory detection. No data is sent externally.
32
+
33
+ </details>
34
+
35
+ ## How it works
36
+
37
+ 1. **One-time setup per topic**
38
+ Open a Telegram topic and type `/tm init`. Pick a type (Coding, Research, Marketing, or Custom). Done.
39
+
40
+ 2. **Everything else is automatic**
41
+ The AI reads and updates the topic's files on its own — tracking progress, TODOs, decisions, and learnings. When context gets compacted or the AI resets, it re-reads these files and continues where it left off.
42
+
43
+ 3. **Health checks and daily reports run in the background**
44
+ Autopilot is enabled by default — the plugin checks all your topics daily and posts a progress report, only when something needs attention.
45
+
46
+ You can also skip the interactive flow: `/tm init my-project coding`
47
+
48
+ ## What gets tracked
31
49
 
32
- Once that's done, head to your Telegram group:
50
+ Each topic gets its own folder with files the AI maintains automatically:
33
51
 
34
- 1. Open any topic
35
- 2. Type `/tm init` in the chat
36
- 3. Pick a topic type (Coding, Research, Marketing, or Custom)
37
- 4. The plugin creates a capsule (a folder of markdown files — see below) and confirms in chat
38
- 5. From now on, the agent reads the capsule on every session start — no context lost
52
+ | File | Purpose |
53
+ |------|---------|
54
+ | `STATUS.md` | Last activity, next actions, upcoming work |
55
+ | `TODO.md` | Task list |
56
+ | `LEARNINGS.md` | Insights, mistakes, workarounds |
57
+ | `COMMANDS.md` | Build/deploy/test commands |
58
+ | `LINKS.md` | URLs and endpoints |
59
+ | `CRON.md` | Scheduled jobs |
60
+ | `NOTES.md` | Anything else worth keeping |
61
+ | `README.md` | What this topic is about |
39
62
 
40
- You can also skip the interactive flow: `/tm init my-project coding` (the first argument is the display name, second is the type)
63
+ Depending on the topic type, extra files are added:
64
+ - **Coding** adds `ARCHITECTURE.md` and `DEPLOY.md`
65
+ - **Research** adds `SOURCES.md` and `FINDINGS.md`
66
+ - **Marketing** adds `CAMPAIGNS.md` and `METRICS.md`
41
67
 
42
- ## Commands
68
+ ## Optional commands
43
69
 
44
- All commands are typed directly in the Telegram group chat:
70
+ You don't need any of these everything runs automatically. They're there if you want to check on things or make changes.
71
+
72
+ **Check on things**
73
+
74
+ | Command | What it does |
75
+ |---------|-------------|
76
+ | `/tm status` | See current progress |
77
+ | `/tm doctor` | Run health checks |
78
+ | `/tm doctor --all` | Health check all topics at once |
79
+ | `/tm daily-report` | Post a daily summary |
80
+ | `/tm list` | List all topics |
81
+
82
+ **Make changes**
45
83
 
46
84
  | Command | What it does |
47
85
  |---------|-------------|
48
- | `/tm init` | Interactive setup — pick a topic type |
49
- | `/tm init [name] [type]` | One-step setup. Types: `coding`, `research`, `marketing`, `custom` |
50
- | `/tm status` | Show the current STATUS.md |
51
- | `/tm list` | List all topics, grouped by status |
52
- | `/tm doctor` | Run health checks on the current topic |
53
- | `/tm doctor --all` | Health check all active topics at once |
54
- | `/tm sync` | Regenerate the include file from the registry |
55
- | `/tm rename <new-name>` | Rename a topic's display name |
56
- | `/tm upgrade` | Upgrade the capsule to the latest template version |
57
- | `/tm snooze <duration>` | Snooze a topic (e.g. `7d`, `30d`) |
86
+ | `/tm rename <new-name>` | Rename a topic |
87
+ | `/tm snooze <duration>` | Pause health checks (e.g. `7d`, `30d`) |
58
88
  | `/tm archive` | Archive a topic |
59
89
  | `/tm unarchive` | Bring back an archived topic |
60
- | `/tm autopilot [enable\|disable\|status]` | Toggle daily health sweeps |
61
- | `/tm daily-report` | Generate a daily status report for the current topic |
62
- | `/tm help` | Show this command list in Telegram |
63
-
64
- ## What's in a capsule
65
-
66
- Each topic gets a folder at `~/.openclaw/workspace/projects/t-<threadId>/` with these files:
67
-
68
- **Always included:**
69
- - `STATUS.md` what's happening, last activity, next actions and upcoming pipeline
70
- - `TODO.md` — task backlog
71
- - `COMMANDS.md` — build/deploy/test commands worth remembering
72
- - `LINKS.md` — URLs and endpoints
73
- - `CRON.md` — scheduled jobs
74
- - `NOTES.md` — anything else worth keeping
75
- - `LEARNINGS.md` — hard-won insights, mistakes, and workarounds
76
- - `README.md` — what this topic is about
77
-
78
- **Extra files by type:**
79
- - `coding` adds `ARCHITECTURE.md` and `DEPLOY.md`
80
- - `research` adds `SOURCES.md` and `FINDINGS.md`
81
- - `marketing` adds `CAMPAIGNS.md` and `METRICS.md`
82
- - `custom` adds nothing — bring your own
90
+ | `/tm upgrade` | Update topic files to the latest version |
91
+ | `/tm sync` | Fix config if something is out of sync |
92
+
93
+ **Autopilot** (enabled by default)
94
+
95
+ | Command | What it does |
96
+ |---------|-------------|
97
+ | `/tm autopilot status` | Check if autopilot is on and when it last ran |
98
+ | `/tm autopilot disable` | Turn off automatic health checks and daily reports |
99
+ | `/tm autopilot enable` | Re-enable if you previously disabled it |
83
100
 
84
101
  ## Permissions
85
102
 
@@ -93,7 +110,7 @@ The first person to run `/tm init` automatically becomes admin.
93
110
 
94
111
  - Path traversal protection (jail checks + symlink rejection)
95
112
  - HMAC-signed inline keyboard callbacks
96
- - HTML escaping on direct Telegram API posts (fan-out doctor reports)
113
+ - HTML escaping on direct Telegram API posts
97
114
  - Schema validation on every registry read (bad entries get quarantined)
98
115
  - File locking to prevent concurrent write corruption
99
116
 
@@ -105,7 +122,7 @@ See [SECURITY.md](SECURITY.md) for reporting vulnerabilities.
105
122
  npx openclaw-telegram-manager uninstall
106
123
  ```
107
124
 
108
- This removes the plugin extension files, the `$include` reference from `openclaw.json`, and the generated include file, then restarts the gateway. You will be asked whether to delete workspace data (registry, topic capsules). To skip the prompt and force deletion, pass `--purge-data`:
125
+ This removes the plugin, the config reference, and the generated include file, then restarts the gateway. You'll be asked whether to delete your topic data. To skip the prompt and delete everything:
109
126
 
110
127
  ```bash
111
128
  npx openclaw-telegram-manager uninstall --purge-data
@@ -119,19 +136,19 @@ See [CONTRIBUTING.md](CONTRIBUTING.md).
119
136
 
120
137
  ```
121
138
  src/
122
- index.ts — plugin entry point (source)
139
+ index.ts — plugin entry point
123
140
  tool.ts — routes /tm sub-commands
124
141
  setup.ts — the setup CLI
125
142
  commands/ — one file per command
126
- lib/ — core logic (registry, capsules, security, auth, etc.)
127
- templates/ — markdown templates for new capsules
143
+ lib/ — core logic (registry, security, auth, etc.)
144
+ templates/ — markdown templates for new topics
128
145
  dist/
129
- plugin.js — bundled plugin (built by esbuild, all deps included)
146
+ plugin.js — bundled plugin (esbuild, all deps included)
130
147
  skills/
131
- tm/SKILL.md — model-only proactive behavior hints (not user-invocable)
148
+ tm/SKILL.md — AI behavior hints (not user-invocable)
132
149
  ```
133
150
 
134
- `npm run build` compiles TypeScript then bundles `src/index.ts` into `dist/plugin.js` with all dependencies. The setup script copies only the bundle — no `node_modules` needed at runtime.
151
+ `npm run build` compiles TypeScript then bundles into `dist/plugin.js`. The setup script copies only the bundle — no `node_modules` needed at runtime.
135
152
 
136
153
  ## License
137
154
 
@@ -1,3 +1,7 @@
1
1
  import type { CommandContext, CommandResult } from './help.js';
2
+ export declare const MARKER_START = "<!-- TM_AUTOPILOT_START -->";
3
+ export declare const MARKER_END = "<!-- TM_AUTOPILOT_END -->";
4
+ export declare const HEARTBEAT_BLOCK = "<!-- TM_AUTOPILOT_START -->\n## Topic Manager \u2014 Balanced Autopilot\n\nExecute these steps IN ORDER. Do not skip steps.\n\n1. CALL `topic_manager` with command \"doctor --all\" to health-check all active topics.\n This runs health checks AND posts daily progress reports for each eligible topic automatically.\n2. For each topic where STATUS.md \"Last done (UTC)\" is >3 days old:\n post a brief nudge in that topic asking the user for a status update.\n3. If no actions were taken in steps 1-2, do nothing (HEARTBEAT_OK).\n<!-- TM_AUTOPILOT_END -->";
5
+ export declare const HEARTBEAT_FILENAME = "HEARTBEAT.md";
2
6
  export declare function handleAutopilot(ctx: CommandContext, args: string): Promise<CommandResult>;
3
7
  //# sourceMappingURL=autopilot.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"autopilot.d.ts","sourceRoot":"","sources":["../../src/commands/autopilot.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,cAAc,EAAE,aAAa,EAAE,MAAM,WAAW,CAAC;AAuB/D,wBAAsB,eAAe,CAAC,GAAG,EAAE,cAAc,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,aAAa,CAAC,CA0B/F"}
1
+ {"version":3,"file":"autopilot.d.ts","sourceRoot":"","sources":["../../src/commands/autopilot.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,cAAc,EAAE,aAAa,EAAE,MAAM,WAAW,CAAC;AAI/D,eAAO,MAAM,YAAY,gCAAgC,CAAC;AAC1D,eAAO,MAAM,UAAU,8BAA8B,CAAC;AAEtD,eAAO,MAAM,eAAe,kjBAUd,CAAC;AAEf,eAAO,MAAM,kBAAkB,iBAAiB,CAAC;AAIjD,wBAAsB,eAAe,CAAC,GAAG,EAAE,cAAc,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,aAAa,CAAC,CA0B/F"}
@@ -2,21 +2,22 @@ import * as fs from 'node:fs';
2
2
  import * as path from 'node:path';
3
3
  import { readRegistry, withRegistry } from '../lib/registry.js';
4
4
  import { checkAuthorization } from '../lib/auth.js';
5
+ import { relativeTime } from '../lib/telegram.js';
5
6
  // ── Marker constants ────────────────────────────────────────────────
6
- const MARKER_START = '<!-- TM_AUTOPILOT_START -->';
7
- const MARKER_END = '<!-- TM_AUTOPILOT_END -->';
8
- const HEARTBEAT_BLOCK = `${MARKER_START}
7
+ export const MARKER_START = '<!-- TM_AUTOPILOT_START -->';
8
+ export const MARKER_END = '<!-- TM_AUTOPILOT_END -->';
9
+ export const HEARTBEAT_BLOCK = `${MARKER_START}
9
10
  ## Topic Manager — Balanced Autopilot
10
11
 
11
12
  Execute these steps IN ORDER. Do not skip steps.
12
13
 
13
14
  1. CALL \`topic_manager\` with command "doctor --all" to health-check all active topics.
14
- This handles stale timestamps, task ID mismatches, and posting errors automatically.
15
+ This runs health checks AND posts daily progress reports for each eligible topic automatically.
15
16
  2. For each topic where STATUS.md "Last done (UTC)" is >3 days old:
16
17
  post a brief nudge in that topic asking the user for a status update.
17
18
  3. If no actions were taken in steps 1-2, do nothing (HEARTBEAT_OK).
18
19
  ${MARKER_END}`;
19
- const HEARTBEAT_FILENAME = 'HEARTBEAT.md';
20
+ export const HEARTBEAT_FILENAME = 'HEARTBEAT.md';
20
21
  // ── Main handler ────────────────────────────────────────────────────
21
22
  export async function handleAutopilot(ctx, args) {
22
23
  const { workspaceDir, userId } = ctx;
@@ -69,7 +70,7 @@ async function handleEnable(ctx) {
69
70
  data.autopilotEnabled = true;
70
71
  });
71
72
  return {
72
- text: '**Autopilot enabled.**\nDaily health sweeps will run via the OpenClaw heartbeat.',
73
+ text: '**Autopilot enabled.**\nHealth checks will run automatically every day.',
73
74
  };
74
75
  }
75
76
  // ── Disable ─────────────────────────────────────────────────────────
@@ -80,14 +81,14 @@ async function handleDisable(ctx) {
80
81
  await withRegistry(workspaceDir, (data) => {
81
82
  data.autopilotEnabled = false;
82
83
  });
83
- return { text: 'Autopilot is not enabled (no HEARTBEAT.md found).' };
84
+ return { text: 'Autopilot is already disabled.' };
84
85
  }
85
86
  let content = fs.readFileSync(heartbeatPath, 'utf-8');
86
87
  if (!content.includes(MARKER_START)) {
87
88
  await withRegistry(workspaceDir, (data) => {
88
89
  data.autopilotEnabled = false;
89
90
  });
90
- return { text: 'Autopilot is not enabled (no marker found in HEARTBEAT.md).' };
91
+ return { text: 'Autopilot is already disabled.' };
91
92
  }
92
93
  // Remove everything between markers (inclusive)
93
94
  const startIdx = content.indexOf(MARKER_START);
@@ -107,7 +108,7 @@ async function handleDisable(ctx) {
107
108
  data.autopilotEnabled = false;
108
109
  });
109
110
  return {
110
- text: '**Autopilot disabled.**\nDaily sweeps will no longer run automatically.',
111
+ text: '**Autopilot disabled.**\nAutomatic health checks are now off.',
111
112
  };
112
113
  }
113
114
  // ── Status ──────────────────────────────────────────────────────────
@@ -115,10 +116,12 @@ async function handleStatus(ctx) {
115
116
  const { workspaceDir } = ctx;
116
117
  const registry = readRegistry(workspaceDir);
117
118
  const enabled = registry.autopilotEnabled;
118
- const lastRun = registry.lastDoctorAllRunAt ?? 'never';
119
+ const lastRun = registry.lastDoctorAllRunAt
120
+ ? relativeTime(registry.lastDoctorAllRunAt)
121
+ : 'never';
119
122
  const lines = [
120
123
  `**Autopilot:** ${enabled ? 'enabled' : 'disabled'}`,
121
- `**Last doctor-all run:** ${lastRun}`,
124
+ `**Last health check run:** ${lastRun}`,
122
125
  ];
123
126
  return {
124
127
  text: lines.join('\n'),
@@ -1 +1 @@
1
- {"version":3,"file":"autopilot.js","sourceRoot":"","sources":["../../src/commands/autopilot.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"autopilot.js","sourceRoot":"","sources":["../../src/commands/autopilot.ts"],"names":[],"mappings":"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"}
@@ -1,4 +1,10 @@
1
1
  import type { CommandContext, CommandResult } from './help.js';
2
2
  export declare function handleDailyReport(ctx: CommandContext): Promise<CommandResult>;
3
+ export declare function readFileOrNull(filePath: string): string | null;
4
+ export declare function extractDoneSection(statusContent: string | null): string;
5
+ export declare function extractTodayLearnings(learningsContent: string | null): string;
6
+ export declare function extractBlockers(todoContent: string | null): string;
7
+ export declare function extractNextActions(statusContent: string | null): string;
8
+ export declare function extractUpcoming(statusContent: string | null): string;
3
9
  export declare function computeHealth(lastMessageAt: string | null, statusContent: string | null, blockers: string): 'fresh' | 'stale' | 'blocked';
4
10
  //# sourceMappingURL=daily-report.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"daily-report.d.ts","sourceRoot":"","sources":["../../src/commands/daily-report.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,cAAc,EAAE,aAAa,EAAE,MAAM,WAAW,CAAC;AAE/D,wBAAsB,iBAAiB,CAAC,GAAG,EAAE,cAAc,GAAG,OAAO,CAAC,aAAa,CAAC,CAoFnF;AAoED,wBAAgB,aAAa,CAC3B,aAAa,EAAE,MAAM,GAAG,IAAI,EAC5B,aAAa,EAAE,MAAM,GAAG,IAAI,EAC5B,QAAQ,EAAE,MAAM,GACf,OAAO,GAAG,OAAO,GAAG,SAAS,CAW/B"}
1
+ {"version":3,"file":"daily-report.d.ts","sourceRoot":"","sources":["../../src/commands/daily-report.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,cAAc,EAAE,aAAa,EAAE,MAAM,WAAW,CAAC;AAE/D,wBAAsB,iBAAiB,CAAC,GAAG,EAAE,cAAc,GAAG,OAAO,CAAC,aAAa,CAAC,CAqFnF;AAID,wBAAgB,cAAc,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAM9D;AAED,wBAAgB,kBAAkB,CAAC,aAAa,EAAE,MAAM,GAAG,IAAI,GAAG,MAAM,CAMvE;AAED,wBAAgB,qBAAqB,CAAC,gBAAgB,EAAE,MAAM,GAAG,IAAI,GAAG,MAAM,CAqB7E;AAED,wBAAgB,eAAe,CAAC,WAAW,EAAE,MAAM,GAAG,IAAI,GAAG,MAAM,CAOlE;AAED,wBAAgB,kBAAkB,CAAC,aAAa,EAAE,MAAM,GAAG,IAAI,GAAG,MAAM,CAMvE;AAED,wBAAgB,eAAe,CAAC,aAAa,EAAE,MAAM,GAAG,IAAI,GAAG,MAAM,CAMpE;AAED,wBAAgB,aAAa,CAC3B,aAAa,EAAE,MAAM,GAAG,IAAI,EAC5B,aAAa,EAAE,MAAM,GAAG,IAAI,EAC5B,QAAQ,EAAE,MAAM,GACf,OAAO,GAAG,OAAO,GAAG,SAAS,CAW/B"}
@@ -15,8 +15,8 @@ export async function handleDailyReport(ctx) {
15
15
  return { text: 'This topic is not registered. Run /tm init first.' };
16
16
  }
17
17
  // Dedup: skip if already reported today
18
- if (entry.lastDoctorReportAt) {
19
- const lastReport = new Date(entry.lastDoctorReportAt);
18
+ if (entry.lastDailyReportAt) {
19
+ const lastReport = new Date(entry.lastDailyReportAt);
20
20
  const now = new Date();
21
21
  if (lastReport.getUTCFullYear() === now.getUTCFullYear() &&
22
22
  lastReport.getUTCMonth() === now.getUTCMonth() &&
@@ -27,7 +27,7 @@ export async function handleDailyReport(ctx) {
27
27
  const projectsBase = path.join(workspaceDir, 'projects');
28
28
  const capsuleDir = path.join(projectsBase, entry.slug);
29
29
  if (!fs.existsSync(capsuleDir)) {
30
- return { text: `Capsule directory not found: projects/${entry.slug}/` };
30
+ return { text: 'Topic files not found. Run /tm init to set up this topic.' };
31
31
  }
32
32
  // Read capsule files
33
33
  const statusContent = readFileOrNull(path.join(capsuleDir, 'STATUS.md'));
@@ -40,7 +40,7 @@ export async function handleDailyReport(ctx) {
40
40
  const nextContent = extractNextActions(statusContent);
41
41
  const upcomingContent = extractUpcoming(statusContent);
42
42
  const health = computeHealth(entry.lastMessageAt, statusContent, blockers);
43
- const reportText = buildDailyReport({
43
+ const reportData = {
44
44
  name: entry.name,
45
45
  doneContent,
46
46
  learningsContent: newLearnings,
@@ -48,15 +48,16 @@ export async function handleDailyReport(ctx) {
48
48
  nextContent,
49
49
  upcomingContent,
50
50
  health,
51
- });
51
+ };
52
52
  // Post to topic if postFn available
53
53
  if (ctx.postFn) {
54
54
  try {
55
- await ctx.postFn(groupId, threadId, reportText);
55
+ const htmlReport = buildDailyReport(reportData, 'html');
56
+ await ctx.postFn(groupId, threadId, htmlReport);
56
57
  await withRegistry(workspaceDir, (data) => {
57
58
  const e = data.topics[key];
58
59
  if (e) {
59
- e.lastDoctorReportAt = new Date().toISOString();
60
+ e.lastDailyReportAt = new Date().toISOString();
60
61
  }
61
62
  });
62
63
  }
@@ -67,18 +68,18 @@ export async function handleDailyReport(ctx) {
67
68
  }
68
69
  }
69
70
  else {
70
- // Update lastDoctorReportAt even without posting
71
+ // Update lastDailyReportAt even without posting
71
72
  await withRegistry(workspaceDir, (data) => {
72
73
  const e = data.topics[key];
73
74
  if (e) {
74
- e.lastDoctorReportAt = new Date().toISOString();
75
+ e.lastDailyReportAt = new Date().toISOString();
75
76
  }
76
77
  });
77
78
  }
78
- return { text: reportText };
79
+ return { text: buildDailyReport(reportData, 'markdown') };
79
80
  }
80
81
  // ── Helpers ────────────────────────────────────────────────────────────
81
- function readFileOrNull(filePath) {
82
+ export function readFileOrNull(filePath) {
82
83
  try {
83
84
  return fs.readFileSync(filePath, 'utf-8');
84
85
  }
@@ -86,7 +87,7 @@ function readFileOrNull(filePath) {
86
87
  return null;
87
88
  }
88
89
  }
89
- function extractDoneSection(statusContent) {
90
+ export function extractDoneSection(statusContent) {
90
91
  if (!statusContent)
91
92
  return '_No STATUS.md found._';
92
93
  const match = statusContent.match(/^##\s*Last done\s*\(UTC\)\s*\n([\s\S]*?)(?=\n##\s|\n*$)/im);
@@ -95,7 +96,7 @@ function extractDoneSection(statusContent) {
95
96
  const text = match[1]?.trim();
96
97
  return text || '_Empty._';
97
98
  }
98
- function extractTodayLearnings(learningsContent) {
99
+ export function extractTodayLearnings(learningsContent) {
99
100
  if (!learningsContent)
100
101
  return '_No LEARNINGS.md found._';
101
102
  const today = new Date().toISOString().slice(0, 10);
@@ -116,14 +117,14 @@ function extractTodayLearnings(learningsContent) {
116
117
  }
117
118
  return todayLines.length > 0 ? todayLines.join('\n') : '_None today._';
118
119
  }
119
- function extractBlockers(todoContent) {
120
+ export function extractBlockers(todoContent) {
120
121
  if (!todoContent)
121
122
  return '_No TODO.md found._';
122
123
  const lines = todoContent.split('\n');
123
124
  const blockerLines = lines.filter((l) => /\[BLOCKED\]/i.test(l) || /\bblocked\b/i.test(l));
124
125
  return blockerLines.length > 0 ? blockerLines.join('\n') : '_None._';
125
126
  }
126
- function extractNextActions(statusContent) {
127
+ export function extractNextActions(statusContent) {
127
128
  if (!statusContent)
128
129
  return '_No STATUS.md found._';
129
130
  const match = statusContent.match(/^##\s*Next (?:3 )?actions(?: \(now\))?\s*\n([\s\S]*?)(?=\n##\s|\n*$)/im);
@@ -132,7 +133,7 @@ function extractNextActions(statusContent) {
132
133
  const text = match[1]?.trim();
133
134
  return text || '_Empty._';
134
135
  }
135
- function extractUpcoming(statusContent) {
136
+ export function extractUpcoming(statusContent) {
136
137
  if (!statusContent)
137
138
  return '_No STATUS.md found._';
138
139
  const match = statusContent.match(/^##\s*Upcoming actions\s*\n([\s\S]*?)(?=\n##\s|\n*$)/im);
@@ -1 +1 @@
1
- {"version":3,"file":"daily-report.js","sourceRoot":"","sources":["../../src/commands/daily-report.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"daily-report.js","sourceRoot":"","sources":["../../src/commands/daily-report.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"doctor-all.d.ts","sourceRoot":"","sources":["../../src/commands/doctor-all.ts"],"names":[],"mappings":"AAeA,OAAO,KAAK,EAAE,cAAc,EAAE,aAAa,EAAE,MAAM,WAAW,CAAC;AAW/D,wBAAsB,eAAe,CAAC,GAAG,EAAE,cAAc,GAAG,OAAO,CAAC,aAAa,CAAC,CA0OjF"}
1
+ {"version":3,"file":"doctor-all.d.ts","sourceRoot":"","sources":["../../src/commands/doctor-all.ts"],"names":[],"mappings":"AAwBA,OAAO,KAAK,EAAE,cAAc,EAAE,aAAa,EAAE,MAAM,WAAW,CAAC;AAW/D,wBAAsB,eAAe,CAAC,GAAG,EAAE,cAAc,GAAG,OAAO,CAAC,aAAa,CAAC,CA6SjF"}
@@ -3,9 +3,10 @@ import * as path from 'node:path';
3
3
  import { readRegistry, withRegistry } from '../lib/registry.js';
4
4
  import { checkAuthorization } from '../lib/auth.js';
5
5
  import { DOCTOR_ALL_COOLDOWN_MS, DOCTOR_PER_TOPIC_CAP_MS, INACTIVE_AFTER_DAYS, MAX_POST_ERROR_LENGTH, SPAM_THRESHOLD, } from '../lib/types.js';
6
- import { buildDoctorReport, buildDoctorButtons, createRateLimitedPoster } from '../lib/telegram.js';
6
+ import { buildDoctorReport, buildDoctorButtons, buildDailyReport, createRateLimitedPoster } from '../lib/telegram.js';
7
7
  import { runAllChecksForTopic, backupCapsuleIfHealthy } from '../lib/doctor-checks.js';
8
8
  import { includePath } from '../lib/include-generator.js';
9
+ import { readFileOrNull, extractDoneSection, extractTodayLearnings, extractBlockers, extractNextActions, extractUpcoming, computeHealth, } from './daily-report.js';
9
10
  export async function handleDoctorAll(ctx) {
10
11
  const { workspaceDir, configDir, userId, logger } = ctx;
11
12
  if (!userId) {
@@ -24,7 +25,7 @@ export async function handleDoctorAll(ctx) {
24
25
  if (elapsed < DOCTOR_ALL_COOLDOWN_MS) {
25
26
  const remainingMin = Math.ceil((DOCTOR_ALL_COOLDOWN_MS - elapsed) / 60_000);
26
27
  return {
27
- text: `Doctor-all was run ${Math.floor(elapsed / 60_000)} minutes ago. Try again in ${remainingMin} minute(s).`,
28
+ text: `Health checks were run ${Math.floor(elapsed / 60_000)} minutes ago. Try again in ${remainingMin} minute(s).`,
28
29
  };
29
30
  }
30
31
  }
@@ -138,7 +139,62 @@ export async function handleDoctorAll(ctx) {
138
139
  }
139
140
  }
140
141
  }
141
- // Update registry: lastDoctorAllRunAt and per-topic timestamps
142
+ // Daily report fan-out: generate and post daily reports for eligible topics
143
+ let dailyReportSuccesses = 0;
144
+ let dailyReportSkipped = 0;
145
+ const dailyReportKeys = new Set();
146
+ if (ctx.postFn && reports.length > 0) {
147
+ const rateLimitedPost = createRateLimitedPoster(ctx.postFn);
148
+ const nowDate = now.toISOString().slice(0, 10);
149
+ for (const report of reports) {
150
+ const key = `${report.groupId}:${report.threadId}`;
151
+ const entry = registry.topics[key];
152
+ if (!entry)
153
+ continue;
154
+ // Dedup: skip if already reported today
155
+ if (entry.lastDailyReportAt) {
156
+ const lastReport = new Date(entry.lastDailyReportAt);
157
+ const lastDate = `${lastReport.getUTCFullYear()}-${String(lastReport.getUTCMonth() + 1).padStart(2, '0')}-${String(lastReport.getUTCDate()).padStart(2, '0')}`;
158
+ if (lastDate === nowDate) {
159
+ dailyReportSkipped++;
160
+ continue;
161
+ }
162
+ }
163
+ // Read capsule files
164
+ const capsuleDir = path.join(projectsBase, entry.slug);
165
+ const statusContent = readFileOrNull(path.join(capsuleDir, 'STATUS.md'));
166
+ const todoContent = readFileOrNull(path.join(capsuleDir, 'TODO.md'));
167
+ const learningsContent = readFileOrNull(path.join(capsuleDir, 'LEARNINGS.md'));
168
+ // Extract sections
169
+ const doneContent = extractDoneSection(statusContent);
170
+ const newLearnings = extractTodayLearnings(learningsContent);
171
+ const blockers = extractBlockers(todoContent);
172
+ const nextContent = extractNextActions(statusContent);
173
+ const upcomingContent = extractUpcoming(statusContent);
174
+ const health = computeHealth(entry.lastMessageAt, statusContent, blockers);
175
+ const reportData = {
176
+ name: entry.name,
177
+ doneContent,
178
+ learningsContent: newLearnings,
179
+ blockersContent: blockers,
180
+ nextContent,
181
+ upcomingContent,
182
+ health,
183
+ };
184
+ try {
185
+ const htmlReport = buildDailyReport(reportData, 'html');
186
+ await rateLimitedPost(report.groupId, report.threadId, htmlReport);
187
+ dailyReportSuccesses++;
188
+ dailyReportKeys.add(key);
189
+ }
190
+ catch (err) {
191
+ const msg = err instanceof Error ? err.message : String(err);
192
+ logger.error(`[doctor-all] Daily report post failed for ${entry.slug}: ${msg}`);
193
+ // Daily report failures don't fail the overall run
194
+ }
195
+ }
196
+ }
197
+ // Update registry: lastDoctorAllRunAt, per-topic timestamps, and daily report timestamps
142
198
  await withRegistry(workspaceDir, (data) => {
143
199
  data.lastDoctorAllRunAt = now.toISOString();
144
200
  for (const [_key, entry] of Object.entries(data.topics)) {
@@ -169,17 +225,25 @@ export async function handleDoctorAll(ctx) {
169
225
  entry.consecutiveSilentDoctors = 0;
170
226
  }
171
227
  }
228
+ // Batch-update lastDailyReportAt for successful daily reports
229
+ for (const key of dailyReportKeys) {
230
+ const entry = data.topics[key];
231
+ if (entry) {
232
+ entry.lastDailyReportAt = now.toISOString();
233
+ }
234
+ }
172
235
  });
173
236
  // Build summary
174
237
  const lines = [
175
- `**Doctor All Summary**`,
238
+ `**Health Check Summary**`,
176
239
  '',
177
- `Processed: ${processed}`,
178
- `Skipped (ineligible): ${skipped}`,
179
- `Total: ${allEntries.length}`,
240
+ `Checked: ${processed}`,
241
+ `Skipped: ${skipped}`,
242
+ `Total topics: ${allEntries.length}`,
180
243
  ];
181
244
  if (ctx.postFn) {
182
245
  lines.push(`Posted: ${postSuccesses}, Post failures: ${postErrors}`);
246
+ lines.push(`Daily reports: ${dailyReportSuccesses} sent, ${dailyReportSkipped} skipped`);
183
247
  }
184
248
  if (errors.length > 0) {
185
249
  lines.push('');
@@ -193,10 +257,7 @@ export async function handleDoctorAll(ctx) {
193
257
  }
194
258
  if (migrationGroups.length > 0) {
195
259
  lines.push('');
196
- lines.push('**Possible group migrations detected:**');
197
- for (const gid of migrationGroups) {
198
- lines.push(`- Group ${gid}: all topics failed. Check for group migration.`);
199
- }
260
+ lines.push(`**Warning:** ${migrationGroups.length} group(s) had all topics fail. The group may have been migrated or deleted.`);
200
261
  }
201
262
  return {
202
263
  text: lines.join('\n'),