macroclaw 0.46.0 → 0.47.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.
- package/README.md +46 -13
- package/package.json +1 -1
- package/src/app.test.ts +388 -5
- package/src/app.ts +216 -45
- package/src/authorized-chats.test.ts +196 -0
- package/src/authorized-chats.ts +122 -0
- package/src/cli.test.ts +7 -7
- package/src/cli.ts +3 -3
- package/src/index.ts +1 -1
- package/src/orchestrator.test.ts +25 -25
- package/src/orchestrator.ts +10 -6
- package/src/prompt-builder.test.ts +28 -3
- package/src/prompt-builder.ts +20 -11
- package/src/scheduler.test.ts +36 -10
- package/src/scheduler.ts +7 -6
- package/src/sessions.test.ts +85 -19
- package/src/sessions.ts +33 -5
- package/src/settings.test.ts +40 -16
- package/src/settings.ts +29 -5
- package/src/setup.test.ts +12 -6
- package/src/setup.ts +8 -7
- package/workspace-template/.claude/skills/schedule-event/SKILL.md +28 -7
- package/workspace-template/data/schedule.json +2 -0
package/src/setup.ts
CHANGED
|
@@ -63,12 +63,13 @@ export class SetupWizard {
|
|
|
63
63
|
this.#io.write(" 3. Copy the token it gives you (looks like 123456:ABC-DEF...)\n\n");
|
|
64
64
|
const { botToken, bot } = await this.#askBotToken();
|
|
65
65
|
|
|
66
|
-
//
|
|
67
|
-
this.#io.write("Next, we need
|
|
68
|
-
this.#io.write("
|
|
69
|
-
|
|
70
|
-
const
|
|
71
|
-
const
|
|
66
|
+
// Admin chat ID
|
|
67
|
+
this.#io.write("Next, we need the admin chat ID. This is the bootstrap chat with full\n");
|
|
68
|
+
this.#io.write("control — send /chatid to the bot in Telegram to get yours. Additional\n");
|
|
69
|
+
this.#io.write("chats can be authorized at runtime via /chatsadd from the admin chat.\n\n");
|
|
70
|
+
const defaultAdminChatId = this.#default("adminChatId");
|
|
71
|
+
const adminChatIdPrompt = defaultAdminChatId ? `Admin chat ID [${defaultAdminChatId}]: ` : "Admin chat ID: ";
|
|
72
|
+
const adminChatId = await this.#askValidated("adminChatId", adminChatIdPrompt, defaultAdminChatId);
|
|
72
73
|
|
|
73
74
|
// Stop setup bot after chat ID is collected
|
|
74
75
|
await bot.stop();
|
|
@@ -103,7 +104,7 @@ export class SetupWizard {
|
|
|
103
104
|
|
|
104
105
|
const settings: Settings = settingsSchema.parse({
|
|
105
106
|
botToken,
|
|
106
|
-
|
|
107
|
+
adminChatId,
|
|
107
108
|
model,
|
|
108
109
|
workspace,
|
|
109
110
|
timeZone,
|
|
@@ -21,10 +21,21 @@ Schedule a new event by adding it to `data/schedule.json`.
|
|
|
21
21
|
3. Determine job type:
|
|
22
22
|
- **Recurring** → convert to a cron expression in local time. See reference below.
|
|
23
23
|
- **One-time** → compute an ISO 8601 timestamp with the user's timezone offset for `fireAt`
|
|
24
|
-
4. **
|
|
25
|
-
5.
|
|
26
|
-
6.
|
|
27
|
-
7.
|
|
24
|
+
4. **Route the job to a chat via the `chat` field** — see [Chat routing](#chat-routing) below. When scheduling from a conversation, target the chat the user is talking to you in (read the `<event chat="...">` attribute on the incoming event).
|
|
25
|
+
5. **Be proactive about timing**: if the user says "next week" or "tomorrow" without a specific time, pick the best time based on what you know (their routine, calendar, context)
|
|
26
|
+
6. Append the new job to the `jobs` array
|
|
27
|
+
7. Write the updated file
|
|
28
|
+
8. Confirm: what was scheduled, when it will fire, and offer to adjust
|
|
29
|
+
|
|
30
|
+
## Chat routing
|
|
31
|
+
|
|
32
|
+
Every incoming `<event>` has a `chat="<name>"` attribute identifying which chat it came from (e.g. `admin`, `family`). When a scheduled job fires, the bridge delivers the response to the chat named in the job's `chat` field.
|
|
33
|
+
|
|
34
|
+
- **Default (no `chat` field)** — response goes to the admin chat.
|
|
35
|
+
- **Explicit chat name** — e.g. `"chat": "family"`. Response goes to that chat.
|
|
36
|
+
- **Broadcast** — `"chat": "*"`. The same prompt runs once per authorized chat, and each response is delivered to that chat. Use sparingly — only for genuinely universal reminders.
|
|
37
|
+
|
|
38
|
+
When the user asks you to schedule something, set `chat` to the chat name from the incoming event's `chat` attribute so the reminder comes back to the same chat. Don't omit `chat` unless you know the job should reach the admin chat specifically.
|
|
28
39
|
|
|
29
40
|
## Natural language → job format
|
|
30
41
|
|
|
@@ -52,18 +63,27 @@ Two job types, discriminated by field:
|
|
|
52
63
|
{
|
|
53
64
|
"name": "morning-summary",
|
|
54
65
|
"cron": "0 7 * * 1-5",
|
|
55
|
-
"prompt": "Give me a morning summary of my tasks"
|
|
66
|
+
"prompt": "Give me a morning summary of my tasks",
|
|
67
|
+
"chat": "admin"
|
|
68
|
+
},
|
|
69
|
+
{
|
|
70
|
+
"name": "family-dinner-poll",
|
|
71
|
+
"cron": "0 17 * * 5",
|
|
72
|
+
"prompt": "Ask what everyone wants for dinner",
|
|
73
|
+
"chat": "family"
|
|
56
74
|
},
|
|
57
75
|
{
|
|
58
76
|
"name": "email-check",
|
|
59
77
|
"cron": "*/30 * * * *",
|
|
60
78
|
"prompt": "Check if any important emails arrived",
|
|
61
|
-
"model": "haiku"
|
|
79
|
+
"model": "haiku",
|
|
80
|
+
"chat": "admin"
|
|
62
81
|
},
|
|
63
82
|
{
|
|
64
83
|
"name": "dentist-reminder",
|
|
65
84
|
"fireAt": "2026-03-15T08:00:00",
|
|
66
|
-
"prompt": "Reminder: call the dentist to reschedule your appointment"
|
|
85
|
+
"prompt": "Reminder: call the dentist to reschedule your appointment",
|
|
86
|
+
"chat": "admin"
|
|
67
87
|
}
|
|
68
88
|
]
|
|
69
89
|
}
|
|
@@ -77,6 +97,7 @@ Two job types, discriminated by field:
|
|
|
77
97
|
| `cron` | for recurring | Standard cron expression (local time). See reference below. |
|
|
78
98
|
| `fireAt` | for one-time | ISO 8601 timestamp (e.g. `2026-03-15T08:00:00`). Can include a timezone offset (e.g. `2026-03-15T08:00:00+01:00`); without one, the time is interpreted in the configured timezone. |
|
|
79
99
|
| `prompt` | yes | The message sent to the agent when the event fires. Write it as a natural instruction. |
|
|
100
|
+
| `chat` | no | Name of the chat to deliver the response to (e.g. `admin`, `family`). Defaults to `admin`. Use `"*"` to broadcast the prompt to every authorized chat. Match the `chat` attribute from the incoming `<event>` when scheduling from a conversation. |
|
|
80
101
|
| `model` | no | Override the model. Use `haiku` for cheap checks, `opus` for complex reasoning. Omit for default. |
|
|
81
102
|
|
|
82
103
|
Each job must have exactly one of `cron` or `fireAt` (not both).
|
|
@@ -4,12 +4,14 @@
|
|
|
4
4
|
"name": "memory-capture",
|
|
5
5
|
"cron": "0 */4 * * *",
|
|
6
6
|
"model": "haiku",
|
|
7
|
+
"chat": "*",
|
|
7
8
|
"prompt": "Append today's noteworthy events to memory/YYYY-MM-DD.md (create the file and directory if needed). Add a ## HH:MM heading with bullet points underneath. Capture: decisions made, facts learned, user preferences expressed, tasks completed or started, problems solved. Be factual and concise — one line per item. If the file already exists, APPEND only — never overwrite. If nothing meaningful happened since the last entry, respond silently."
|
|
8
9
|
},
|
|
9
10
|
{
|
|
10
11
|
"name": "memory-consolidate",
|
|
11
12
|
"cron": "0 3 * * *",
|
|
12
13
|
"model": "opus",
|
|
14
|
+
"chat": "admin",
|
|
13
15
|
"prompt": "Read daily logs in memory/ from the past 3 days. Distill durable knowledge into MEMORY.md: confirmed facts, recurring patterns, stable preferences, key decisions, and important context. Remove entries from MEMORY.md that are outdated or contradicted by recent logs. Keep MEMORY.md concise and organized by topic (not chronologically). Do not duplicate entries. If daily logs contain new personal facts about the user (preferences, routines, family, work, interests), update USER.md accordingly. Respond silently."
|
|
14
16
|
}
|
|
15
17
|
]
|