@adaptic/maestro 1.8.1 → 1.8.2

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@adaptic/maestro",
3
- "version": "1.8.1",
3
+ "version": "1.8.2",
4
4
  "description": "Maestro — Autonomous AI agent operating system. Deploy AI employees on dedicated Mac minis.",
5
5
  "type": "module",
6
6
  "bin": {
@@ -10,13 +10,14 @@
10
10
  // Install: launchd plist with KeepAlive: true
11
11
  // =============================================================================
12
12
 
13
- // The core daemon implementation lives in sophie-daemon.mjs (filename
14
- // preserved for launchd-plist compatibility; the content is fully
15
- // agent-neutral and reads identity from config/agent.json).
16
- // It uses AGENT_DIR (resolved from this file's location) as the base path.
13
+ // The core daemon implementation is in sophie-daemon.mjs by default, but
14
+ // older agent repos may have a renamed copy at <firstname>-daemon.mjs (a
15
+ // pre-1.7 convention). This entry-point auto-detects the correct file so
16
+ // the launchd plist stays stable regardless of agent identity history.
17
17
 
18
- import { resolve, dirname } from "node:path";
18
+ import { resolve, dirname, join } from "node:path";
19
19
  import { fileURLToPath } from "node:url";
20
+ import { existsSync, readFileSync, readdirSync } from "node:fs";
20
21
 
21
22
  const __dirname = dirname(fileURLToPath(import.meta.url));
22
23
  const AGENT_DIR = process.env.AGENT_DIR || resolve(__dirname, "../..");
@@ -54,5 +55,43 @@ try {
54
55
  // Reactive daemon continues. Doctor / healthcheck will surface this.
55
56
  }
56
57
 
57
- // Import and run the daemon (handles its own .env loading)
58
- await import("./sophie-daemon.mjs");
58
+ // Locate the core daemon module. Try, in order:
59
+ // 1. ./sophie-daemon.mjs — canonical filename (post-Phase-2.5 SOT)
60
+ // 2. ./<firstName>-daemon.mjs — legacy rename from init-maestro Phase 1
61
+ // 3. The first scripts/daemon/*-daemon.mjs that isn't this file
62
+ function resolveCoreDaemon() {
63
+ const localCandidates = [];
64
+ const canonical = resolve(__dirname, "sophie-daemon.mjs");
65
+ localCandidates.push(canonical);
66
+
67
+ try {
68
+ const agentJson = join(AGENT_DIR, "config", "agent.json");
69
+ if (existsSync(agentJson)) {
70
+ const { firstName } = JSON.parse(readFileSync(agentJson, "utf-8"));
71
+ if (firstName && typeof firstName === "string") {
72
+ const lower = firstName.toLowerCase();
73
+ localCandidates.push(resolve(__dirname, `${lower}-daemon.mjs`));
74
+ }
75
+ }
76
+ } catch { /* identity unavailable — fall through */ }
77
+
78
+ for (const p of localCandidates) if (existsSync(p)) return p;
79
+
80
+ // Final fallback: scan the directory for *-daemon.mjs (excluding self).
81
+ try {
82
+ for (const name of readdirSync(__dirname)) {
83
+ if (name === "maestro-daemon.mjs") continue;
84
+ if (name.endsWith("-daemon.mjs")) return resolve(__dirname, name);
85
+ }
86
+ } catch { /* */ }
87
+
88
+ return null;
89
+ }
90
+
91
+ const coreDaemon = resolveCoreDaemon();
92
+ if (!coreDaemon) {
93
+ console.error("[DAEMON] could not locate a core daemon module under scripts/daemon/. Expected sophie-daemon.mjs or <firstName>-daemon.mjs.");
94
+ process.exit(78);
95
+ }
96
+ // Import and run the daemon (handles its own .env loading).
97
+ await import(coreDaemon);
@@ -268,13 +268,27 @@ generate_trigger_plist "meeting-prep" "" "900"
268
268
  # 6. Meeting action capture (every 30 minutes)
269
269
  generate_trigger_plist "meeting-action-capture" "" "1800"
270
270
 
271
- # 7. Midday sweep (daily at 12:00 local)
271
+ # 7a. Daily morning brief (06:30 local)
272
+ generate_trigger_plist "daily-morning-brief" \
273
+ " <key>Hour</key>
274
+ <integer>6</integer>
275
+ <key>Minute</key>
276
+ <integer>30</integer>"
277
+
278
+ # 7b. Midday sweep (daily at 12:00 local)
272
279
  generate_trigger_plist "daily-midday-sweep" \
273
280
  " <key>Hour</key>
274
281
  <integer>12</integer>
275
282
  <key>Minute</key>
276
283
  <integer>0</integer>"
277
284
 
285
+ # 7c. Daily evening wrap (18:00 local)
286
+ generate_trigger_plist "daily-evening-wrap" \
287
+ " <key>Hour</key>
288
+ <integer>18</integer>
289
+ <key>Minute</key>
290
+ <integer>0</integer>"
291
+
278
292
  # 8. Weekly hiring (Monday 09:00)
279
293
  generate_trigger_plist "weekly-hiring" \
280
294
  " <key>Weekday</key>
@@ -95,13 +95,20 @@ function listPlists(agentRoot) {
95
95
  // Tests
96
96
  // ---------------------------------------------------------------------------
97
97
 
98
- test("generator emits 13 plists with the agent's first name", async () => {
98
+ test("generator emits 15 plists with the agent's first name", async () => {
99
+ // Inventory (as of cadence-bus v1):
100
+ // daemon, poll-relay,
101
+ // inbox-processor, backlog-executor, meeting-prep, meeting-action-capture,
102
+ // daily-morning-brief, daily-midday-sweep, daily-evening-wrap,
103
+ // weekly-hiring, weekly-priorities, weekly-execution,
104
+ // weekly-engineering-health, weekly-strategic-memo,
105
+ // quarterly-self-assessment.
99
106
  const root = await makeAgent("alice");
100
107
  try {
101
108
  const r = runGenerator(root);
102
109
  assert.equal(r.status, 0, r.stderr);
103
110
  const plists = listPlists(root);
104
- assert.equal(plists.length, 13);
111
+ assert.equal(plists.length, 15);
105
112
  for (const p of plists) {
106
113
  assert.match(p, /^ai\.adaptic\.alice-/);
107
114
  }