@adaptic/maestro 1.5.1 → 1.6.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/bin/maestro.mjs CHANGED
@@ -762,26 +762,28 @@ function loadMaestroignore(cwd) {
762
762
  }
763
763
 
764
764
  function patternToRegex(pat) {
765
- // Directory prefix: `scripts/daemon/` matches scripts/daemon/* (recursive)
766
- if (pat.endsWith("/")) {
767
- const prefix = pat.replace(/[.+^${}()|[\]\\]/g, "\\$&");
768
- return new RegExp("^" + prefix);
769
- }
770
- // Glob with * and **.
771
- // Step order matters: ** must be captured before single * to preserve
772
- // recursive semantics. * is intentionally NOT in the regex-escape char
773
- // class so we can rewrite it after escaping the other specials.
774
- if (pat.includes("*")) {
775
- const escaped = pat
776
- .replace(/[.+^${}()|[\]\\]/g, "\\$&")
765
+ // Helper: convert a glob-aware pattern to its regex source.
766
+ // ** must be substituted before single * so we don't double-rewrite it.
767
+ // * is intentionally outside the regex-escape char class so the
768
+ // glob substitution can find unescaped `*` characters afterward.
769
+ const globToRe = (p) =>
770
+ p.replace(/[.+^${}()|[\]\\]/g, "\\$&")
777
771
  .replace(/\*\*/g, "<DBL>")
778
772
  .replace(/\*/g, "[^/]*")
779
773
  .replace(/<DBL>/g, ".*");
780
- return new RegExp("^" + escaped + "$");
774
+
775
+ // Directory prefix: `scripts/daemon/` or `agents/sophie-*/` match
776
+ // anything under that path (recursive).
777
+ if (pat.endsWith("/")) {
778
+ return new RegExp("^" + globToRe(pat));
781
779
  }
782
- // Exact: also match anything underneath (a path like `scripts/daemon`
783
- // without trailing slash should still protect the whole directory if
784
- // it resolves to one gitignore semantics).
780
+ // Single-line glob: must match in full (no trailing slash).
781
+ if (pat.includes("*")) {
782
+ return new RegExp("^" + globToRe(pat) + "$");
783
+ }
784
+ // Exact: also matches anything underneath (gitignore semantics — a
785
+ // pattern without trailing slash still protects a directory if it
786
+ // resolves to one).
785
787
  const escaped = pat.replace(/[.+^${}()|[\]\\]/g, "\\$&");
786
788
  return new RegExp("^" + escaped + "(/|$)");
787
789
  }
@@ -1013,6 +1015,23 @@ Per-file behaviour:
1013
1015
  }
1014
1016
  }
1015
1017
 
1018
+ // Regenerate config/agent.env from config/agent.json so newly-installed
1019
+ // (or already-installed) shell scripts find the agent identity vars.
1020
+ // Soft failure — older agents that haven't migrated to the SOT layout
1021
+ // yet don't have agent.json and that's fine.
1022
+ if (!flags.dryRun && existsSync(join(cwd, "config", "agent.json"))) {
1023
+ try {
1024
+ execFileSync(
1025
+ "node",
1026
+ [join(MAESTRO_ROOT, "scripts/setup/generate-agent-env.mjs")],
1027
+ { cwd, env: { ...process.env, AGENT_DIR: cwd }, stdio: "pipe" }
1028
+ );
1029
+ ok("regenerated config/agent.env");
1030
+ } catch (e) {
1031
+ warn(`could not regenerate config/agent.env: ${e.message}`);
1032
+ }
1033
+ }
1034
+
1016
1035
  // Summary
1017
1036
  console.log();
1018
1037
  console.log(`${C.bold}Upgrade summary${C.reset}${flags.dryRun ? " (dry run, nothing written)" : ""}`);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@adaptic/maestro",
3
- "version": "1.5.1",
3
+ "version": "1.6.0",
4
4
  "description": "Maestro — Autonomous AI agent operating system. Deploy AI employees on dedicated Mac minis.",
5
5
  "type": "module",
6
6
  "bin": {
@@ -0,0 +1,52 @@
1
+ {
2
+ "firstName": "Sophie",
3
+ "lastName": "Nguyen",
4
+ "fullName": "Sophie Nguyen",
5
+ "title": "Chief of Staff",
6
+ "archetype": "executive-operator",
7
+
8
+ "email": "sophie@adaptic.ai",
9
+ "phone": "",
10
+ "slackMemberId": "",
11
+
12
+ "company": "Adaptic.ai",
13
+ "companyDomain": "adaptic.ai",
14
+ "companyDescription": "AI-native institutional asset management group",
15
+
16
+ "principal": {
17
+ "firstName": "Mehran",
18
+ "lastName": "Granfar",
19
+ "fullName": "Mehran Granfar",
20
+ "title": "CEO",
21
+ "email": "mehran@adaptic.ai",
22
+ "slackMemberId": ""
23
+ },
24
+
25
+ "machineName": "sophie-mini",
26
+ "repoSlug": "sophie-ai",
27
+ "launchdLabelPrefix": "ai.adaptic.sophie",
28
+
29
+ "timezone": "UTC",
30
+ "locale": "en-US",
31
+
32
+ "schedule": {
33
+ "morningBrief": "08:00",
34
+ "commsTriage": ["08:00", "12:00", "17:00"],
35
+ "eveningWrap": "18:00",
36
+ "overnightMonitoring": "22:00"
37
+ },
38
+
39
+ "communication": {
40
+ "defaultTone": "warm-professional",
41
+ "externalTone": "formal",
42
+ "voiceModes": [
43
+ { "id": "agent", "label": "Agent's voice", "description": "Default for all operational communications" },
44
+ { "id": "principal", "label": "Principal's voice", "description": "For communications attributed to the principal" },
45
+ { "id": "internal", "label": "Internal notes", "description": "Analysis, risk flags — not sent externally" },
46
+ { "id": "institutional", "label": "Institutional", "description": "Regulatory and legal correspondence" }
47
+ ]
48
+ },
49
+
50
+ "responsibilities": [],
51
+ "operatingPrinciples": []
52
+ }
@@ -1,219 +1,89 @@
1
1
  /**
2
- * Maestro — Agent Configuration
2
+ * Maestro — Agent Configuration (TypeScript wrapper)
3
3
  *
4
- * This is the single source of truth for the agent's identity, contact details,
5
- * organisational context, and operational parameters. Every file in the repo that
6
- * references the agent by name, email, phone, or role should import from here
7
- * instead of hardcoding values.
4
+ * The canonical source of truth is `config/agent.json` every framework
5
+ * file (Python, shell, Node, YAML) reads from that file (or its sibling
6
+ * `config/agent.env` which is auto-generated for shell consumers).
8
7
  *
9
- * When deploying a new Maestro instance, run:
10
- * claude "/init-maestro"
11
- * The wizard will populate this file interactively.
8
+ * This TypeScript wrapper exists ONLY to:
9
+ * - Provide compile-time types for code that imports the config
10
+ * - Expose computed convenience values (REPO_DIR, EMAIL_SIGNATURE, …)
12
11
  *
13
- * To use in scripts:
14
- * import { agent } from '../config/agent.ts';
15
- *
16
- * To use in shell scripts, read the generated JSON:
17
- * jq '.firstName' config/agent.json
12
+ * Do NOT add agent identity values here. Edit `config/agent.json` instead,
13
+ * then run `npx tsx scripts/setup/generate-agent-env.mjs` to regenerate
14
+ * `config/agent.env`.
18
15
  */
19
16
 
20
- // ---------------------------------------------------------------------------
21
- // Agent Identity
22
- // ---------------------------------------------------------------------------
23
-
24
- export const agent = {
25
- /** Agent's first name — used in greetings, signatures, and voice references */
26
- firstName: 'Sophie',
27
-
28
- /** Agent's last name */
29
- lastName: 'Nguyen',
30
-
31
- /** Full display name — appears in email signatures, Slack profile, documents */
32
- fullName: 'Sophie Nguyen',
33
-
34
- /** Job title — used in CLAUDE.md identity section and email signatures */
35
- title: 'Chief of Staff',
36
-
37
- /**
38
- * Role archetype — determines which operating principles, communication rules,
39
- * and workflow templates are most appropriate. Used by /init-maestro to select
40
- * defaults. Common archetypes:
41
- * 'executive-operator' — Chief of Staff, COO-type roles
42
- * 'technical-leader' — CTO, Head of Engineering, Chief Scientist
43
- * 'commercial-leader' — Head of Sales, IR, BD
44
- * 'compliance-officer' — Head of Compliance, Legal, Regulatory
45
- * 'product-leader' — Head of Product, UX
46
- * 'operations-leader' — Head of Ops, Fund Ops, HR
47
- */
48
- archetype: 'executive-operator' as const,
49
-
50
- // ---------------------------------------------------------------------------
51
- // Contact Details
52
- // ---------------------------------------------------------------------------
53
-
54
- /** Agent's primary email address */
55
- email: 'sophie@adaptic.ai',
56
-
57
- /** Agent's phone number (E.164 format) — used for Twilio SMS/voice/WhatsApp */
58
- phone: '+16282656712',
17
+ import agentData from './agent.json' with { type: 'json' };
59
18
 
60
- /** Agent's Slack member ID (e.g. U097N5R0M7U) — used for mentions, DM routing,
61
- * and cross-agent message filtering (see config/known-agents.json) */
62
- slackMemberId: '',
19
+ export interface VoiceMode {
20
+ id: string;
21
+ label: string;
22
+ description: string;
23
+ }
63
24
 
64
- // ---------------------------------------------------------------------------
65
- // Organisation
66
- // ---------------------------------------------------------------------------
25
+ export interface PrincipalConfig {
26
+ firstName: string;
27
+ lastName: string;
28
+ fullName: string;
29
+ title: string;
30
+ email: string;
31
+ slackMemberId: string;
32
+ }
67
33
 
68
- /** Company name — appears in CLAUDE.md, documents, email signatures */
69
- company: 'Adaptic.ai',
34
+ export interface AgentConfig {
35
+ firstName: string;
36
+ lastName: string;
37
+ fullName: string;
38
+ title: string;
39
+ archetype: string;
70
40
 
71
- /** Company domain — used for email addresses, branding */
72
- companyDomain: 'adaptic.ai',
41
+ email: string;
42
+ phone: string;
43
+ slackMemberId: string;
73
44
 
74
- /** Brief company description — used in agent system prompts */
75
- companyDescription: 'AI-native institutional asset management group',
45
+ company: string;
46
+ companyDomain: string;
47
+ companyDescription: string;
76
48
 
77
- // ---------------------------------------------------------------------------
78
- // Reporting Line
79
- // ---------------------------------------------------------------------------
49
+ principal: PrincipalConfig;
80
50
 
81
- /** The agent's primary principal — the person they report to and act on behalf of */
82
- principal: {
83
- firstName: 'Mehran',
84
- lastName: 'Granfar',
85
- fullName: 'Mehran Granfar',
86
- title: 'CEO',
87
- email: 'mehran@adaptic.ai',
88
- slackMemberId: 'U097N5R0M7U',
89
- },
51
+ machineName: string;
52
+ repoSlug: string;
53
+ launchdLabelPrefix: string;
90
54
 
91
- // ---------------------------------------------------------------------------
92
- // Machine & Deployment
93
- // ---------------------------------------------------------------------------
55
+ timezone: string;
56
+ locale: string;
94
57
 
95
- /** Hostname of the dedicated Mac mini this agent runs on */
96
- machineName: 'sophie-mini',
97
-
98
- /** Repository directory name (basename only, not full path) */
99
- repoSlug: 'maestro',
100
-
101
- /**
102
- * LaunchD label prefix for all daemon processes.
103
- * Processes will be named: {labelPrefix}-poller, {labelPrefix}-inbox-processor, etc.
104
- */
105
- launchdLabelPrefix: 'ai.adaptic.sophie',
58
+ schedule: {
59
+ morningBrief: string;
60
+ commsTriage: string[];
61
+ eveningWrap: string;
62
+ overnightMonitoring: string;
63
+ };
106
64
 
107
- // ---------------------------------------------------------------------------
108
- // Operational Parameters
109
- // ---------------------------------------------------------------------------
65
+ communication: {
66
+ defaultTone: string;
67
+ externalTone: string;
68
+ voiceModes: VoiceMode[];
69
+ };
110
70
 
111
- /** IANA timezone — all scheduled triggers use this */
112
- timezone: 'Asia/Dubai',
71
+ responsibilities: string[];
72
+ operatingPrinciples: string[];
73
+ }
113
74
 
114
- /** Locale for date/number formatting */
115
- locale: 'en-US',
75
+ export const agent: AgentConfig = agentData as AgentConfig;
116
76
 
117
- /** Daily schedule (times in HH:MM, agent's timezone) */
118
- schedule: {
119
- morningBrief: '06:00',
120
- commsTriage: ['08:00', '12:00', '17:00'],
121
- eveningWrap: '18:00',
122
- overnightMonitoring: '22:00',
123
- },
77
+ // ── Derived values ──────────────────────────────────────────────────────
124
78
 
125
- // ---------------------------------------------------------------------------
126
- // Communication Style
127
- // ---------------------------------------------------------------------------
128
-
129
- communication: {
130
- /**
131
- * Default tone: 'formal' | 'warm-professional' | 'casual'
132
- * This affects how the agent writes emails, Slack messages, and documents.
133
- */
134
- defaultTone: 'warm-professional' as const,
135
-
136
- /** Tone used for external communications (partners, candidates, vendors) */
137
- externalTone: 'formal' as const,
138
-
139
- /**
140
- * Voice modes available to this agent.
141
- * The first entry is the default voice.
142
- */
143
- voiceModes: [
144
- {
145
- id: 'agent',
146
- label: "Agent's voice",
147
- description: 'Default for all operational communications',
148
- },
149
- {
150
- id: 'principal',
151
- label: "Principal's voice",
152
- description: 'For communications attributed to the principal',
153
- },
154
- {
155
- id: 'internal',
156
- label: 'Internal notes',
157
- description: 'Analysis, risk flags — not sent externally',
158
- },
159
- {
160
- id: 'institutional',
161
- label: 'Institutional',
162
- description: 'Regulatory and legal correspondence',
163
- },
164
- ],
165
- },
166
-
167
- // ---------------------------------------------------------------------------
168
- // Responsibilities
169
- // ---------------------------------------------------------------------------
170
-
171
- /**
172
- * Core responsibilities — used to generate the CLAUDE.md identity section
173
- * and to scope the agent's operating principles. Keep to 3-7 bullet points.
174
- */
175
- responsibilities: [
176
- 'Track every commitment until it closes',
177
- 'Coordinate 30+ specialist agent teams',
178
- 'Manage all inbound/outbound communications',
179
- 'Execute strategic priorities autonomously',
180
- 'Maintain institutional memory across sessions',
181
- ],
182
-
183
- /**
184
- * Operating principles — the behavioural rules that define how the agent works.
185
- * These are injected into CLAUDE.md and guide all decision-making.
186
- */
187
- operatingPrinciples: [
188
- 'Follow-through over brilliance — track every commitment until it closes',
189
- 'Concise over comprehensive — sharp recommendations, not exhaustive reports',
190
- 'Evidence over opinion — cite sources for recommendations',
191
- 'Bias to action — act decisively on operational matters; escalate only strategic commitments',
192
- 'Audit everything — every action is logged',
193
- 'Full autonomy, full accountability — operate independently with complete audit trail',
194
- ],
195
- } as const;
196
-
197
- // ---------------------------------------------------------------------------
198
- // Derived Values (computed from the config above)
199
- // ---------------------------------------------------------------------------
200
-
201
- /** Uppercase first name for shell variable prefixes (e.g. SOPHIE_AI_DIR) */
79
+ /** Uppercase first name for shell variable prefixes */
202
80
  export const AGENT_UPPER = agent.firstName.toUpperCase();
203
81
 
204
- /** Lowercase first name for file/directory naming (e.g. sophie-ai) */
82
+ /** Lowercase first name for file/directory naming */
205
83
  export const AGENT_LOWER = agent.firstName.toLowerCase();
206
84
 
207
- /** The repo directory name in the user's home (e.g. ~/maestro) */
85
+ /** Repo directory in the user's home (e.g. ~/sophie-ai) */
208
86
  export const REPO_DIR = `~/${agent.repoSlug}`;
209
87
 
210
- /** Email signature line */
88
+ /** Email signature one-liner */
211
89
  export const EMAIL_SIGNATURE = `${agent.fullName} | ${agent.title} | ${agent.company}`;
212
-
213
- // ---------------------------------------------------------------------------
214
- // Type Exports
215
- // ---------------------------------------------------------------------------
216
-
217
- export type AgentConfig = typeof agent;
218
- export type VoiceMode = (typeof agent.communication.voiceModes)[number];
219
- export type Archetype = typeof agent.archetype;
@@ -4,14 +4,28 @@
4
4
  # Requires GMAIL_APP_PASSWORD environment variable
5
5
  set -e
6
6
 
7
- export GMAIL_APP_PASSWORD=nqinfcgnhzmjucho
7
+ SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
8
+ AGENT_REPO_DIR="${AGENT_DIR:-$(cd "$SCRIPT_DIR/.." && pwd)}"
9
+
10
+ # Pull AGENT_EMAIL + GMAIL_APP_PASSWORD from agent.env + .env
11
+ [ -f "$AGENT_REPO_DIR/config/agent.env" ] && source "$AGENT_REPO_DIR/config/agent.env"
12
+ [ -f "$AGENT_REPO_DIR/.env" ] && source "$AGENT_REPO_DIR/.env"
13
+
14
+ if [ -z "${GMAIL_APP_PASSWORD:-}" ]; then
15
+ echo "ERROR: GMAIL_APP_PASSWORD not set" >&2
16
+ exit 1
17
+ fi
18
+ export AGENT_EMAIL
19
+ export GMAIL_APP_PASSWORD
8
20
 
9
21
  python3 << 'PYEOF'
10
22
  import imaplib
11
23
  import os
12
24
 
13
- user = "sophie@adaptic.ai"
25
+ user = os.environ.get("AGENT_EMAIL", "")
14
26
  password = os.environ["GMAIL_APP_PASSWORD"]
27
+ if not user:
28
+ raise SystemExit("AGENT_EMAIL not set — check config/agent.env")
15
29
 
16
30
  mail = imaplib.IMAP4_SSL("imap.gmail.com")
17
31
  mail.login(user, password)