morpheus-cli 0.7.1 → 0.7.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/README.md +6 -0
- package/dist/runtime/chronos/parser.js +38 -20
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -312,6 +312,7 @@ neo:
|
|
|
312
312
|
model: gpt-4o-mini
|
|
313
313
|
temperature: 0.2
|
|
314
314
|
context_window: 100
|
|
315
|
+
personality: analytical_engineer
|
|
315
316
|
|
|
316
317
|
apoc:
|
|
317
318
|
provider: openai
|
|
@@ -319,11 +320,13 @@ apoc:
|
|
|
319
320
|
temperature: 0.2
|
|
320
321
|
working_dir: /home/user/projects
|
|
321
322
|
timeout_ms: 30000
|
|
323
|
+
personality: pragmatic_dev
|
|
322
324
|
|
|
323
325
|
trinity:
|
|
324
326
|
provider: openai
|
|
325
327
|
model: gpt-4o-mini
|
|
326
328
|
temperature: 0.2
|
|
329
|
+
personality: data_specialist
|
|
327
330
|
|
|
328
331
|
chronos:
|
|
329
332
|
check_interval_ms: 60000 # polling interval in ms (minimum 60000)
|
|
@@ -400,6 +403,7 @@ Generic Morpheus overrides (selected):
|
|
|
400
403
|
| `MORPHEUS_NEO_CONTEXT_WINDOW` | `neo.context_window` |
|
|
401
404
|
| `MORPHEUS_NEO_API_KEY` | `neo.api_key` |
|
|
402
405
|
| `MORPHEUS_NEO_BASE_URL` | `neo.base_url` |
|
|
406
|
+
| `MORPHEUS_NEO_PERSONALITY` | `neo.personality` |
|
|
403
407
|
| `MORPHEUS_APOC_PROVIDER` | `apoc.provider` |
|
|
404
408
|
| `MORPHEUS_APOC_MODEL` | `apoc.model` |
|
|
405
409
|
| `MORPHEUS_APOC_TEMPERATURE` | `apoc.temperature` |
|
|
@@ -408,10 +412,12 @@ Generic Morpheus overrides (selected):
|
|
|
408
412
|
| `MORPHEUS_APOC_API_KEY` | `apoc.api_key` |
|
|
409
413
|
| `MORPHEUS_APOC_WORKING_DIR` | `apoc.working_dir` |
|
|
410
414
|
| `MORPHEUS_APOC_TIMEOUT_MS` | `apoc.timeout_ms` |
|
|
415
|
+
| `MORPHEUS_APOC_PERSONALITY` | `apoc.personality` |
|
|
411
416
|
| `MORPHEUS_TRINITY_PROVIDER` | `trinity.provider` |
|
|
412
417
|
| `MORPHEUS_TRINITY_MODEL` | `trinity.model` |
|
|
413
418
|
| `MORPHEUS_TRINITY_TEMPERATURE` | `trinity.temperature` |
|
|
414
419
|
| `MORPHEUS_TRINITY_API_KEY` | `trinity.api_key` |
|
|
420
|
+
| `MORPHEUS_TRINITY_PERSONALITY` | `trinity.personality` |
|
|
415
421
|
| `MORPHEUS_AUDIO_PROVIDER` | `audio.provider` |
|
|
416
422
|
| `MORPHEUS_AUDIO_MODEL` | `audio.model` |
|
|
417
423
|
| `MORPHEUS_AUDIO_ENABLED` | `audio.enabled` |
|
|
@@ -77,50 +77,68 @@ function intervalToCron(expression) {
|
|
|
77
77
|
`Supported formats: "every N minutes/hours/days/weeks", "every minute/hour/day/week", ` +
|
|
78
78
|
`"every monday [at 9am]", "every monday and friday at 18:30", "every weekday", "every weekend", "daily", "weekly".`);
|
|
79
79
|
}
|
|
80
|
+
/**
|
|
81
|
+
* Creates a Date in UTC from a local time in a specific timezone.
|
|
82
|
+
* E.g., createDateInTimezone(2026, 2, 26, 23, 0, 'America/Sao_Paulo') returns
|
|
83
|
+
* a Date representing 23:00 BRT = 02:00 UTC (next day).
|
|
84
|
+
*/
|
|
85
|
+
function createDateInTimezone(year, month, day, hour, minute, timezone) {
|
|
86
|
+
// Create a candidate UTC date
|
|
87
|
+
const candidateUtc = Date.UTC(year, month - 1, day, hour, minute, 0, 0);
|
|
88
|
+
// Get the offset at that moment for the timezone
|
|
89
|
+
const offsetMs = ianaToOffsetMinutes(timezone, new Date(candidateUtc)) * 60_000;
|
|
90
|
+
// Subtract offset: if BRT is -180 min (-3h), local 23:00 = UTC 23:00 - (-3h) = UTC 02:00
|
|
91
|
+
return new Date(candidateUtc - offsetMs);
|
|
92
|
+
}
|
|
93
|
+
/**
|
|
94
|
+
* Gets the current date components (year, month, day) in a specific timezone.
|
|
95
|
+
*/
|
|
96
|
+
function getDatePartsInTimezone(date, timezone) {
|
|
97
|
+
const formatter = new Intl.DateTimeFormat('en-CA', { timeZone: timezone, year: 'numeric', month: '2-digit', day: '2-digit' });
|
|
98
|
+
const parts = formatter.formatToParts(date);
|
|
99
|
+
return {
|
|
100
|
+
year: parseInt(parts.find(p => p.type === 'year').value, 10),
|
|
101
|
+
month: parseInt(parts.find(p => p.type === 'month').value, 10),
|
|
102
|
+
day: parseInt(parts.find(p => p.type === 'day').value, 10),
|
|
103
|
+
};
|
|
104
|
+
}
|
|
80
105
|
/**
|
|
81
106
|
* Parses Portuguese time expressions and converts to ISO 8601 format.
|
|
82
107
|
* Handles patterns like "às 15h", "hoje às 15:30", "amanhã às 9h".
|
|
83
108
|
*/
|
|
84
109
|
function parsePortugueseTimeExpression(expression, refDate, timezone) {
|
|
85
110
|
const lower = expression.toLowerCase().trim();
|
|
111
|
+
const { year, month, day } = getDatePartsInTimezone(refDate, timezone);
|
|
86
112
|
// Pattern: "às 15h", "as 15h", "às 15:30", "as 15:30"
|
|
87
113
|
const timeOnlyMatch = lower.match(/^(?:à|a)s?\s+(\d{1,2})(?::(\d{2}))?h?$/);
|
|
88
114
|
if (timeOnlyMatch) {
|
|
89
|
-
|
|
115
|
+
const hour = parseInt(timeOnlyMatch[1], 10);
|
|
90
116
|
const minute = timeOnlyMatch[2] ? parseInt(timeOnlyMatch[2], 10) : 0;
|
|
91
|
-
|
|
92
|
-
// We use Intl.DateTimeFormat to properly handle timezone
|
|
93
|
-
const targetDate = new Date();
|
|
94
|
-
const tzDate = new Date(targetDate.toLocaleString('en-US', { timeZone: timezone }));
|
|
95
|
-
tzDate.setHours(hour, minute, 0, 0);
|
|
117
|
+
let result = createDateInTimezone(year, month, day, hour, minute, timezone);
|
|
96
118
|
// If time is in the past today, schedule for tomorrow
|
|
97
|
-
if (
|
|
98
|
-
|
|
119
|
+
if (result.getTime() <= refDate.getTime()) {
|
|
120
|
+
result = createDateInTimezone(year, month, day + 1, hour, minute, timezone);
|
|
99
121
|
}
|
|
100
|
-
return
|
|
122
|
+
return result;
|
|
101
123
|
}
|
|
102
124
|
// Pattern: "hoje às 15h", "hoje as 15:30"
|
|
103
125
|
const todayMatch = lower.match(/^hoje\s+(?:à|a)s?\s+(\d{1,2})(?::(\d{2}))?h?$/);
|
|
104
126
|
if (todayMatch) {
|
|
105
|
-
|
|
127
|
+
const hour = parseInt(todayMatch[1], 10);
|
|
106
128
|
const minute = todayMatch[2] ? parseInt(todayMatch[2], 10) : 0;
|
|
107
|
-
const
|
|
108
|
-
tzDate.setHours(hour, minute, 0, 0);
|
|
129
|
+
const result = createDateInTimezone(year, month, day, hour, minute, timezone);
|
|
109
130
|
// If already passed, return null (can't schedule in the past)
|
|
110
|
-
if (
|
|
131
|
+
if (result.getTime() <= refDate.getTime()) {
|
|
111
132
|
return null;
|
|
112
133
|
}
|
|
113
|
-
return
|
|
134
|
+
return result;
|
|
114
135
|
}
|
|
115
136
|
// Pattern: "amanhã às 15h", "amanha as 15:30", "amanhã às 15h da tarde"
|
|
116
|
-
const tomorrowMatch = lower.match(/^
|
|
137
|
+
const tomorrowMatch = lower.match(/^amanh[aã]\s+(?:à|a)s?\s+(\d{1,2})(?::(\d{2}))?h?(?:\s+(?:da|do)\s+(?:manh[aã]|tarde|noite))?$/);
|
|
117
138
|
if (tomorrowMatch) {
|
|
118
|
-
|
|
139
|
+
const hour = parseInt(tomorrowMatch[1], 10);
|
|
119
140
|
const minute = tomorrowMatch[2] ? parseInt(tomorrowMatch[2], 10) : 0;
|
|
120
|
-
|
|
121
|
-
tzDate.setDate(tzDate.getDate() + 1);
|
|
122
|
-
tzDate.setHours(hour, minute, 0, 0);
|
|
123
|
-
return tzDate;
|
|
141
|
+
return createDateInTimezone(year, month, day + 1, hour, minute, timezone);
|
|
124
142
|
}
|
|
125
143
|
// Pattern: "daqui a X minutos/horas/dias"
|
|
126
144
|
const relativeMatch = lower.match(/^daqui\s+a\s+(\d+)\s+(minutos?|horas?|dias?|semanas?)$/);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "morpheus-cli",
|
|
3
|
-
"version": "0.7.
|
|
3
|
+
"version": "0.7.2",
|
|
4
4
|
"description": "Morpheus is a local AI agent for developers, running as a CLI daemon that connects to LLMs, local tools, and MCPs, enabling interaction via Terminal, Telegram, and Discord. Inspired by the character Morpheus from *The Matrix*, the project acts as an intelligent orchestrator, bridging the gap between the developer and complex systems.",
|
|
5
5
|
"bin": {
|
|
6
6
|
"morpheus": "./bin/morpheus.js"
|