@poping/yome 0.0.2 → 0.0.4
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/LICENSE +202 -0
- package/NOTICE +11 -0
- package/README.md +306 -27
- package/README.zh-CN.md +333 -0
- package/bin/yome-calwatch +0 -0
- package/dist/agent.d.ts +24 -2
- package/dist/agent.js +34 -2
- package/dist/agent.js.map +1 -1
- package/dist/context.d.ts +2 -0
- package/dist/context.js +121 -13
- package/dist/context.js.map +1 -1
- package/dist/daemon/calendarPermission.d.ts +10 -0
- package/dist/daemon/calendarPermission.js +68 -0
- package/dist/daemon/calendarPermission.js.map +1 -0
- package/dist/daemon/cronCli.d.ts +19 -0
- package/dist/daemon/cronCli.js +403 -0
- package/dist/daemon/cronCli.js.map +1 -0
- package/dist/daemon/envHint.d.ts +5 -0
- package/dist/daemon/envHint.js +139 -0
- package/dist/daemon/envHint.js.map +1 -0
- package/dist/daemon/humanCron.d.ts +1 -0
- package/dist/daemon/humanCron.js +72 -0
- package/dist/daemon/humanCron.js.map +1 -0
- package/dist/daemon/humanOnce.d.ts +1 -0
- package/dist/daemon/humanOnce.js +54 -0
- package/dist/daemon/humanOnce.js.map +1 -0
- package/dist/daemon/index.d.ts +5 -0
- package/dist/daemon/index.js +168 -0
- package/dist/daemon/index.js.map +1 -0
- package/dist/daemon/launchd.d.ts +7 -0
- package/dist/daemon/launchd.js +93 -0
- package/dist/daemon/launchd.js.map +1 -0
- package/dist/daemon/log.d.ts +17 -0
- package/dist/daemon/log.js +57 -0
- package/dist/daemon/log.js.map +1 -0
- package/dist/daemon/paths.d.ts +11 -0
- package/dist/daemon/paths.js +27 -0
- package/dist/daemon/paths.js.map +1 -0
- package/dist/daemon/runTaskEntry.d.ts +1 -0
- package/dist/daemon/runTaskEntry.js +67 -0
- package/dist/daemon/runTaskEntry.js.map +1 -0
- package/dist/daemon/runner.d.ts +21 -0
- package/dist/daemon/runner.js +175 -0
- package/dist/daemon/runner.js.map +1 -0
- package/dist/daemon/scheduler.d.ts +5 -0
- package/dist/daemon/scheduler.js +162 -0
- package/dist/daemon/scheduler.js.map +1 -0
- package/dist/daemon/taskStore.d.ts +62 -0
- package/dist/daemon/taskStore.js +88 -0
- package/dist/daemon/taskStore.js.map +1 -0
- package/dist/daemon/triggers/calendar.d.ts +8 -0
- package/dist/daemon/triggers/calendar.js +248 -0
- package/dist/daemon/triggers/calendar.js.map +1 -0
- package/dist/daemon/triggers/childRunner.d.ts +14 -0
- package/dist/daemon/triggers/childRunner.js +111 -0
- package/dist/daemon/triggers/childRunner.js.map +1 -0
- package/dist/daemon/triggers/cron.d.ts +14 -0
- package/dist/daemon/triggers/cron.js +91 -0
- package/dist/daemon/triggers/cron.js.map +1 -0
- package/dist/daemon/triggers/file.d.ts +7 -0
- package/dist/daemon/triggers/file.js +123 -0
- package/dist/daemon/triggers/file.js.map +1 -0
- package/dist/daemon/triggers/once.d.ts +10 -0
- package/dist/daemon/triggers/once.js +80 -0
- package/dist/daemon/triggers/once.js.map +1 -0
- package/dist/index.js +240 -15
- package/dist/index.js.map +1 -1
- package/dist/llm.js +45 -2
- package/dist/llm.js.map +1 -1
- package/dist/loops/chain.js +8 -0
- package/dist/loops/chain.js.map +1 -1
- package/dist/loops/evaluator.js +8 -0
- package/dist/loops/evaluator.js.map +1 -1
- package/dist/loops/orchestrator.js +8 -0
- package/dist/loops/orchestrator.js.map +1 -1
- package/dist/loops/parallel.js.map +1 -1
- package/dist/loops/route.js +8 -0
- package/dist/loops/route.js.map +1 -1
- package/dist/loops/simple.js +15 -0
- package/dist/loops/simple.js.map +1 -1
- package/dist/permissions/index.d.ts +1 -1
- package/dist/permissions/index.js +1 -1
- package/dist/permissions/index.js.map +1 -1
- package/dist/permissions/loader.d.ts +20 -1
- package/dist/permissions/loader.js +51 -0
- package/dist/permissions/loader.js.map +1 -1
- package/dist/redact.d.ts +56 -0
- package/dist/redact.js +191 -0
- package/dist/redact.js.map +1 -0
- package/dist/skills/runner/applescript.d.ts +49 -0
- package/dist/skills/runner/applescript.js +100 -0
- package/dist/skills/runner/applescript.js.map +1 -0
- package/dist/skills/runner/dispatcher.d.ts +128 -0
- package/dist/skills/runner/dispatcher.js +617 -0
- package/dist/skills/runner/dispatcher.js.map +1 -0
- package/dist/skills/runner/dispatcher.test.d.ts +1 -0
- package/dist/skills/runner/dispatcher.test.js +141 -0
- package/dist/skills/runner/dispatcher.test.js.map +1 -0
- package/dist/skills/runner/kernel.d.ts +8 -0
- package/dist/skills/runner/kernel.js +731 -0
- package/dist/skills/runner/kernel.js.map +1 -0
- package/dist/skills/runner/nodeBackend.d.ts +32 -0
- package/dist/skills/runner/nodeBackend.js +147 -0
- package/dist/skills/runner/nodeBackend.js.map +1 -0
- package/dist/skills/runner/tokenizer.d.ts +36 -0
- package/dist/skills/runner/tokenizer.js +177 -0
- package/dist/skills/runner/tokenizer.js.map +1 -0
- package/dist/state/todos.d.ts +12 -0
- package/dist/state/todos.js +32 -0
- package/dist/state/todos.js.map +1 -0
- package/dist/threadCli.d.ts +11 -0
- package/dist/threadCli.js +177 -0
- package/dist/threadCli.js.map +1 -0
- package/dist/threadShare.d.ts +21 -0
- package/dist/threadShare.js +121 -0
- package/dist/threadShare.js.map +1 -0
- package/dist/threadSubmit.d.ts +32 -0
- package/dist/threadSubmit.js +199 -0
- package/dist/threadSubmit.js.map +1 -0
- package/dist/tools/askUser.d.ts +20 -0
- package/dist/tools/askUser.js +126 -0
- package/dist/tools/askUser.js.map +1 -0
- package/dist/tools/bash.js +63 -14
- package/dist/tools/bash.js.map +1 -1
- package/dist/tools/index.d.ts +24 -2
- package/dist/tools/index.js +54 -5
- package/dist/tools/index.js.map +1 -1
- package/dist/tools/skillCall.d.ts +2 -0
- package/dist/tools/skillCall.js +77 -0
- package/dist/tools/skillCall.js.map +1 -0
- package/dist/tools/todoWrite.d.ts +2 -0
- package/dist/tools/todoWrite.js +141 -0
- package/dist/tools/todoWrite.js.map +1 -0
- package/dist/tools/yome.d.ts +2 -0
- package/dist/tools/yome.js +87 -0
- package/dist/tools/yome.js.map +1 -0
- package/dist/ui/AgentPicker.js +3 -3
- package/dist/ui/AgentPicker.js.map +1 -1
- package/dist/ui/App.js +263 -61
- package/dist/ui/App.js.map +1 -1
- package/dist/ui/AskUserPrompt.d.ts +7 -0
- package/dist/ui/AskUserPrompt.js +78 -0
- package/dist/ui/AskUserPrompt.js.map +1 -0
- package/dist/ui/Banner.d.ts +2 -1
- package/dist/ui/Banner.js +23 -4
- package/dist/ui/Banner.js.map +1 -1
- package/dist/ui/InputBar.js +25 -36
- package/dist/ui/InputBar.js.map +1 -1
- package/dist/ui/Markdown.d.ts +2 -2
- package/dist/ui/Markdown.js +22 -7
- package/dist/ui/Markdown.js.map +1 -1
- package/dist/ui/MarketplacePicker.d.ts +7 -0
- package/dist/ui/MarketplacePicker.js +122 -0
- package/dist/ui/MarketplacePicker.js.map +1 -0
- package/dist/ui/MessageList.d.ts +12 -1
- package/dist/ui/MessageList.js +72 -7
- package/dist/ui/MessageList.js.map +1 -1
- package/dist/ui/ModelPicker.js +4 -4
- package/dist/ui/ModelPicker.js.map +1 -1
- package/dist/ui/MultilineTextInput.d.ts +31 -0
- package/dist/ui/MultilineTextInput.js +393 -0
- package/dist/ui/MultilineTextInput.js.map +1 -0
- package/dist/ui/MultilineTextInput.test.d.ts +1 -0
- package/dist/ui/MultilineTextInput.test.js +30 -0
- package/dist/ui/MultilineTextInput.test.js.map +1 -0
- package/dist/ui/PermissionPrompt.d.ts +16 -4
- package/dist/ui/PermissionPrompt.js +60 -15
- package/dist/ui/PermissionPrompt.js.map +1 -1
- package/dist/ui/SessionPicker.js +2 -2
- package/dist/ui/SessionPicker.js.map +1 -1
- package/dist/ui/ShimmerText.d.ts +8 -0
- package/dist/ui/ShimmerText.js +40 -0
- package/dist/ui/ShimmerText.js.map +1 -0
- package/dist/ui/Spinner.js +3 -9
- package/dist/ui/Spinner.js.map +1 -1
- package/dist/ui/TodoPanel.d.ts +7 -0
- package/dist/ui/TodoPanel.js +36 -0
- package/dist/ui/TodoPanel.js.map +1 -0
- package/dist/ui/TogglePicker.js +4 -4
- package/dist/ui/TogglePicker.js.map +1 -1
- package/dist/ui/ToolResult.js +6 -0
- package/dist/ui/ToolResult.js.map +1 -1
- package/dist/ui/UnifiedSkillsPicker.d.ts +10 -0
- package/dist/ui/UnifiedSkillsPicker.js +63 -0
- package/dist/ui/UnifiedSkillsPicker.js.map +1 -0
- package/dist/ui/animation.d.ts +3 -0
- package/dist/ui/animation.js +48 -0
- package/dist/ui/animation.js.map +1 -0
- package/dist/ui/useThrottledStream.d.ts +7 -0
- package/dist/ui/useThrottledStream.js +63 -0
- package/dist/ui/useThrottledStream.js.map +1 -0
- package/dist/yomeSkills/auth.d.ts +20 -0
- package/dist/yomeSkills/auth.js +70 -0
- package/dist/yomeSkills/auth.js.map +1 -0
- package/dist/yomeSkills/blacklist.d.ts +33 -0
- package/dist/yomeSkills/blacklist.js +101 -0
- package/dist/yomeSkills/blacklist.js.map +1 -0
- package/dist/yomeSkills/capabilities.d.ts +54 -0
- package/dist/yomeSkills/capabilities.js +175 -0
- package/dist/yomeSkills/capabilities.js.map +1 -0
- package/dist/yomeSkills/capabilityGuard.d.ts +31 -0
- package/dist/yomeSkills/capabilityGuard.js +113 -0
- package/dist/yomeSkills/capabilityGuard.js.map +1 -0
- package/dist/yomeSkills/cli.d.ts +25 -0
- package/dist/yomeSkills/cli.js +624 -0
- package/dist/yomeSkills/cli.js.map +1 -0
- package/dist/yomeSkills/deprecate.d.ts +29 -0
- package/dist/yomeSkills/deprecate.js +99 -0
- package/dist/yomeSkills/deprecate.js.map +1 -0
- package/dist/yomeSkills/devLink.d.ts +17 -0
- package/dist/yomeSkills/devLink.js +91 -0
- package/dist/yomeSkills/devLink.js.map +1 -0
- package/dist/yomeSkills/doctor.d.ts +13 -0
- package/dist/yomeSkills/doctor.js +152 -0
- package/dist/yomeSkills/doctor.js.map +1 -0
- package/dist/yomeSkills/enable.d.ts +8 -0
- package/dist/yomeSkills/enable.js +67 -0
- package/dist/yomeSkills/enable.js.map +1 -0
- package/dist/yomeSkills/hubPing.d.ts +1 -0
- package/dist/yomeSkills/hubPing.js +41 -0
- package/dist/yomeSkills/hubPing.js.map +1 -0
- package/dist/yomeSkills/install.d.ts +18 -0
- package/dist/yomeSkills/install.js +143 -0
- package/dist/yomeSkills/install.js.map +1 -0
- package/dist/yomeSkills/installFromHubTarball.d.ts +26 -0
- package/dist/yomeSkills/installFromHubTarball.js +161 -0
- package/dist/yomeSkills/installFromHubTarball.js.map +1 -0
- package/dist/yomeSkills/installGithub.d.ts +33 -0
- package/dist/yomeSkills/installGithub.js +213 -0
- package/dist/yomeSkills/installGithub.js.map +1 -0
- package/dist/yomeSkills/installMeta.d.ts +8 -0
- package/dist/yomeSkills/installMeta.js +76 -0
- package/dist/yomeSkills/installMeta.js.map +1 -0
- package/dist/yomeSkills/integrity.d.ts +26 -0
- package/dist/yomeSkills/integrity.js +107 -0
- package/dist/yomeSkills/integrity.js.map +1 -0
- package/dist/yomeSkills/invoke.d.ts +29 -0
- package/dist/yomeSkills/invoke.js +135 -0
- package/dist/yomeSkills/invoke.js.map +1 -0
- package/dist/yomeSkills/list.d.ts +11 -0
- package/dist/yomeSkills/list.js +55 -0
- package/dist/yomeSkills/list.js.map +1 -0
- package/dist/yomeSkills/login.d.ts +41 -0
- package/dist/yomeSkills/login.js +221 -0
- package/dist/yomeSkills/login.js.map +1 -0
- package/dist/yomeSkills/manifest.d.ts +60 -0
- package/dist/yomeSkills/manifest.js +47 -0
- package/dist/yomeSkills/manifest.js.map +1 -0
- package/dist/yomeSkills/paths.d.ts +13 -0
- package/dist/yomeSkills/paths.js +33 -0
- package/dist/yomeSkills/paths.js.map +1 -0
- package/dist/yomeSkills/publish.d.ts +18 -0
- package/dist/yomeSkills/publish.js +114 -0
- package/dist/yomeSkills/publish.js.map +1 -0
- package/dist/yomeSkills/rollback.d.ts +10 -0
- package/dist/yomeSkills/rollback.js +83 -0
- package/dist/yomeSkills/rollback.js.map +1 -0
- package/dist/yomeSkills/search.d.ts +21 -0
- package/dist/yomeSkills/search.js +31 -0
- package/dist/yomeSkills/search.js.map +1 -0
- package/dist/yomeSkills/skillsIndex.d.ts +36 -0
- package/dist/yomeSkills/skillsIndex.js +111 -0
- package/dist/yomeSkills/skillsIndex.js.map +1 -0
- package/dist/yomeSkills/unified.d.ts +53 -0
- package/dist/yomeSkills/unified.js +187 -0
- package/dist/yomeSkills/unified.js.map +1 -0
- package/dist/yomeSkills/uninstall.d.ts +7 -0
- package/dist/yomeSkills/uninstall.js +22 -0
- package/dist/yomeSkills/uninstall.js.map +1 -0
- package/dist/yomeSkills/update.d.ts +18 -0
- package/dist/yomeSkills/update.js +75 -0
- package/dist/yomeSkills/update.js.map +1 -0
- package/dist/yomeSkills/validate.d.ts +11 -0
- package/dist/yomeSkills/validate.js +99 -0
- package/dist/yomeSkills/validate.js.map +1 -0
- package/package.json +23 -6
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
// Human-friendly cron parser.
|
|
2
|
+
//
|
|
3
|
+
// Accepts a small set of natural-ish phrases and converts them into a
|
|
4
|
+
// standard 5-field crontab string (compatible with node-cron):
|
|
5
|
+
//
|
|
6
|
+
// "9:00" → "0 9 * * *" (every day at 9am)
|
|
7
|
+
// "9:00 daily" → "0 9 * * *"
|
|
8
|
+
// "18:00" → "0 18 * * *"
|
|
9
|
+
// "every 5 minutes" → "* /5 * * * *" (note: 5-field cron — minute slot)
|
|
10
|
+
// "every minute" → "* * * * *"
|
|
11
|
+
// "every hour" → "0 * * * *"
|
|
12
|
+
// "hourly" → "0 * * * *"
|
|
13
|
+
// "daily 9:00" → "0 9 * * *"
|
|
14
|
+
// "weekly mon 9:00" → "0 9 * * 1"
|
|
15
|
+
//
|
|
16
|
+
// Anything we don't recognise → throws. The caller (cli.ts) catches and
|
|
17
|
+
// suggests the user pass a real crontab via --at instead.
|
|
18
|
+
const DAY_NAMES = {
|
|
19
|
+
sun: 0, sunday: 0,
|
|
20
|
+
mon: 1, monday: 1,
|
|
21
|
+
tue: 2, tuesday: 2,
|
|
22
|
+
wed: 3, wednesday: 3,
|
|
23
|
+
thu: 4, thursday: 4,
|
|
24
|
+
fri: 5, friday: 5,
|
|
25
|
+
sat: 6, saturday: 6,
|
|
26
|
+
};
|
|
27
|
+
export function humanToCron(input) {
|
|
28
|
+
const s = input.trim().toLowerCase();
|
|
29
|
+
if (!s)
|
|
30
|
+
throw new Error('empty schedule');
|
|
31
|
+
if (s === 'every minute' || s === 'minutely')
|
|
32
|
+
return '* * * * *';
|
|
33
|
+
if (s === 'every hour' || s === 'hourly')
|
|
34
|
+
return '0 * * * *';
|
|
35
|
+
if (s === 'daily' || s === 'every day')
|
|
36
|
+
return '0 9 * * *';
|
|
37
|
+
// every N minutes / hours
|
|
38
|
+
const everyN = s.match(/^every\s+(\d+)\s+(minute|minutes|min|hour|hours)$/);
|
|
39
|
+
if (everyN) {
|
|
40
|
+
const n = Number.parseInt(everyN[1], 10);
|
|
41
|
+
const unit = everyN[2];
|
|
42
|
+
if (n < 1 || n > 59)
|
|
43
|
+
throw new Error(`interval out of range: ${n}`);
|
|
44
|
+
if (unit.startsWith('hour'))
|
|
45
|
+
return `0 */${n} * * *`;
|
|
46
|
+
return `*/${n} * * * *`;
|
|
47
|
+
}
|
|
48
|
+
// HH:MM with optional 'daily' / weekday
|
|
49
|
+
// Examples: "9:00", "9:00 daily", "9:00 mon", "weekly mon 9:00"
|
|
50
|
+
const timeRe = /(\d{1,2}):(\d{2})/;
|
|
51
|
+
const time = s.match(timeRe);
|
|
52
|
+
if (time) {
|
|
53
|
+
const hour = Number.parseInt(time[1], 10);
|
|
54
|
+
const minute = Number.parseInt(time[2], 10);
|
|
55
|
+
if (hour < 0 || hour > 23 || minute < 0 || minute > 59) {
|
|
56
|
+
throw new Error(`invalid time: ${time[0]}`);
|
|
57
|
+
}
|
|
58
|
+
// Look for an explicit weekday token
|
|
59
|
+
const tokens = s.split(/\s+/).filter(Boolean);
|
|
60
|
+
let dow = '*';
|
|
61
|
+
for (const t of tokens) {
|
|
62
|
+
if (t in DAY_NAMES) {
|
|
63
|
+
dow = String(DAY_NAMES[t]);
|
|
64
|
+
break;
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
return `${minute} ${hour} * * ${dow}`;
|
|
68
|
+
}
|
|
69
|
+
throw new Error(`unrecognised schedule: '${input}'. ` +
|
|
70
|
+
`Try '9:00', 'every 5 minutes', 'every hour', 'mon 9:00', or pass a crontab via --at "0 9 * * *".`);
|
|
71
|
+
}
|
|
72
|
+
//# sourceMappingURL=humanCron.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"humanCron.js","sourceRoot":"","sources":["../../src/daemon/humanCron.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function humanToOnceMs(input: string, now?: () => number): number;
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
// Parse a human-friendly one-shot time spec into a wall-clock epoch ms.
|
|
2
|
+
//
|
|
3
|
+
// Accepted shapes:
|
|
4
|
+
// "in 5 minutes" / "in 1 hour" / "in 30s"
|
|
5
|
+
// "tomorrow 9:00" / "tomorrow 09:00"
|
|
6
|
+
// "today 18:00"
|
|
7
|
+
// "2026-04-30 18:00"
|
|
8
|
+
// "2026-04-30T18:00:00+08:00"
|
|
9
|
+
// "1777340834798" (raw epoch ms)
|
|
10
|
+
//
|
|
11
|
+
// Anything else → throws. Returns ms since epoch (UTC).
|
|
12
|
+
export function humanToOnceMs(input, now = Date.now) {
|
|
13
|
+
const s = input.trim();
|
|
14
|
+
if (!s)
|
|
15
|
+
throw new Error('empty time spec');
|
|
16
|
+
// Raw epoch ms (>= 13 digits).
|
|
17
|
+
if (/^\d{13,}$/.test(s)) {
|
|
18
|
+
return Number.parseInt(s, 10);
|
|
19
|
+
}
|
|
20
|
+
// ISO 8601 / Date-parseable. Try this first for unambiguous inputs
|
|
21
|
+
// like "2026-04-30T18:00:00+08:00".
|
|
22
|
+
const isoTry = Date.parse(s);
|
|
23
|
+
if (!Number.isNaN(isoTry) && /\d{4}-\d{2}-\d{2}/.test(s)) {
|
|
24
|
+
return isoTry;
|
|
25
|
+
}
|
|
26
|
+
const lower = s.toLowerCase();
|
|
27
|
+
// "in N <unit>"
|
|
28
|
+
const inMatch = lower.match(/^in\s+(\d+)\s*(s|sec|secs|second|seconds|m|min|mins|minute|minutes|h|hr|hour|hours|d|day|days)$/);
|
|
29
|
+
if (inMatch) {
|
|
30
|
+
const n = Number.parseInt(inMatch[1], 10);
|
|
31
|
+
const unit = inMatch[2];
|
|
32
|
+
const mult = unit.startsWith('s') ? 1_000 :
|
|
33
|
+
unit.startsWith('m') ? 60_000 :
|
|
34
|
+
unit.startsWith('h') ? 3_600_000 :
|
|
35
|
+
86_400_000;
|
|
36
|
+
return now() + n * mult;
|
|
37
|
+
}
|
|
38
|
+
// "today HH:MM" / "tomorrow HH:MM"
|
|
39
|
+
const dayMatch = lower.match(/^(today|tomorrow)\s+(\d{1,2}):(\d{2})$/);
|
|
40
|
+
if (dayMatch) {
|
|
41
|
+
const offset = dayMatch[1] === 'tomorrow' ? 1 : 0;
|
|
42
|
+
const hour = Number.parseInt(dayMatch[2], 10);
|
|
43
|
+
const minute = Number.parseInt(dayMatch[3], 10);
|
|
44
|
+
if (hour > 23 || minute > 59)
|
|
45
|
+
throw new Error(`invalid time: ${dayMatch[2]}:${dayMatch[3]}`);
|
|
46
|
+
const d = new Date(now());
|
|
47
|
+
d.setDate(d.getDate() + offset);
|
|
48
|
+
d.setHours(hour, minute, 0, 0);
|
|
49
|
+
return d.getTime();
|
|
50
|
+
}
|
|
51
|
+
throw new Error(`unrecognised once-time: '${input}'. ` +
|
|
52
|
+
`Try 'in 5 minutes', 'tomorrow 9:00', '2026-04-30 18:00', or an ISO 8601 string.`);
|
|
53
|
+
}
|
|
54
|
+
//# sourceMappingURL=humanOnce.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"humanOnce.js","sourceRoot":"","sources":["../../src/daemon/humanOnce.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,168 @@
|
|
|
1
|
+
// Top-level CLI entry for `yome daemon ...`.
|
|
2
|
+
//
|
|
3
|
+
// Subcommands:
|
|
4
|
+
// install write LaunchAgent plist + launchctl load
|
|
5
|
+
// uninstall launchctl unload + delete plist
|
|
6
|
+
// start run the scheduler in the foreground (--foreground) or
|
|
7
|
+
// background (& and detach)
|
|
8
|
+
// stop send SIGTERM to the running daemon
|
|
9
|
+
// status print pid + active task count
|
|
10
|
+
// logs [-f] tail the daemon's stdout/stderr log
|
|
11
|
+
import { execSync } from 'child_process';
|
|
12
|
+
import { readFileSync, existsSync, openSync } from 'fs';
|
|
13
|
+
import { spawn } from 'child_process';
|
|
14
|
+
import { startDaemon, readPidIfRunning } from './scheduler.js';
|
|
15
|
+
import { installLaunchAgent, uninstallLaunchAgent } from './launchd.js';
|
|
16
|
+
import { listTasks } from './taskStore.js';
|
|
17
|
+
import { resolveYomeBinPath } from './triggers/cron.js';
|
|
18
|
+
import { PID_FILE, STDOUT_LOG, STDERR_LOG, ensureDirs } from './paths.js';
|
|
19
|
+
export async function runDaemonSubcommand(args, flags) {
|
|
20
|
+
const sub = args[0];
|
|
21
|
+
switch (sub) {
|
|
22
|
+
case 'install': return doInstall();
|
|
23
|
+
case 'uninstall': return doUninstall();
|
|
24
|
+
case 'start': return doStart(flags);
|
|
25
|
+
case 'stop': return doStop();
|
|
26
|
+
case 'status': return doStatus();
|
|
27
|
+
case 'logs': return doLogs(flags);
|
|
28
|
+
case undefined:
|
|
29
|
+
case 'help':
|
|
30
|
+
case '--help':
|
|
31
|
+
printHelp();
|
|
32
|
+
return 0;
|
|
33
|
+
default:
|
|
34
|
+
console.error(`Unknown subcommand: yome daemon ${sub}`);
|
|
35
|
+
printHelp();
|
|
36
|
+
return 2;
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
function printHelp() {
|
|
40
|
+
console.log(`Usage: yome daemon <subcommand>
|
|
41
|
+
|
|
42
|
+
install Install the macOS LaunchAgent (auto-starts on login)
|
|
43
|
+
uninstall Remove the LaunchAgent
|
|
44
|
+
start Start the daemon in the foreground (use --foreground via launchd)
|
|
45
|
+
stop Stop the running daemon (SIGTERM)
|
|
46
|
+
status Show daemon pid + active task summary
|
|
47
|
+
logs [-f] Print daemon stdout/stderr (use -f / --follow to tail)
|
|
48
|
+
|
|
49
|
+
Daemon files:
|
|
50
|
+
~/.yome/daemon/daemon.pid pid of the running daemon
|
|
51
|
+
~/.yome/daemon/stdout.log scheduler stdout
|
|
52
|
+
~/.yome/daemon/stderr.log scheduler stderr
|
|
53
|
+
~/.yome/cron/tasks.json task definitions
|
|
54
|
+
~/.yome/cron/logs/<id>/... per-run audit logs (jsonl)
|
|
55
|
+
|
|
56
|
+
See also: yome cron --help`);
|
|
57
|
+
}
|
|
58
|
+
function doInstall() {
|
|
59
|
+
const r = installLaunchAgent(resolveYomeBinPath());
|
|
60
|
+
if (r.ok) {
|
|
61
|
+
console.log(`✓ ${r.message}`);
|
|
62
|
+
return 0;
|
|
63
|
+
}
|
|
64
|
+
console.error(`✗ ${r.message}`);
|
|
65
|
+
return 1;
|
|
66
|
+
}
|
|
67
|
+
function doUninstall() {
|
|
68
|
+
const r = uninstallLaunchAgent();
|
|
69
|
+
if (r.ok) {
|
|
70
|
+
console.log(`✓ ${r.message}`);
|
|
71
|
+
return 0;
|
|
72
|
+
}
|
|
73
|
+
console.error(`✗ ${r.message}`);
|
|
74
|
+
return 1;
|
|
75
|
+
}
|
|
76
|
+
function doStart(flags) {
|
|
77
|
+
const existing = readPidIfRunning();
|
|
78
|
+
if (existing) {
|
|
79
|
+
console.error(`✗ daemon already running (pid=${existing})`);
|
|
80
|
+
return 1;
|
|
81
|
+
}
|
|
82
|
+
ensureDirs();
|
|
83
|
+
if (flags.foreground) {
|
|
84
|
+
// Block here; this is the path launchd uses.
|
|
85
|
+
startDaemon();
|
|
86
|
+
// startDaemon installs signal handlers and the cron jobs keep the
|
|
87
|
+
// event loop alive — we just await forever.
|
|
88
|
+
return new Promise(() => { });
|
|
89
|
+
}
|
|
90
|
+
// Non-foreground: spawn ourselves as a detached background process so
|
|
91
|
+
// the user gets their shell back. Redirect stdio to the log files
|
|
92
|
+
// shown by `daemon status` and `daemon logs -f` so debug output (e.g.
|
|
93
|
+
// helper child stderr) is recoverable instead of being silently dropped.
|
|
94
|
+
ensureDirs();
|
|
95
|
+
const out = openSync(STDOUT_LOG, 'a');
|
|
96
|
+
const err = openSync(STDERR_LOG, 'a');
|
|
97
|
+
const child = spawn(process.execPath, [resolveYomeBinPath(), 'daemon', 'start', '--foreground'], {
|
|
98
|
+
detached: true,
|
|
99
|
+
stdio: ['ignore', out, err],
|
|
100
|
+
});
|
|
101
|
+
child.unref();
|
|
102
|
+
console.log(`✓ daemon launched in background (pid will be written to ${PID_FILE})`);
|
|
103
|
+
console.log(` logs: ${STDOUT_LOG}`);
|
|
104
|
+
return 0;
|
|
105
|
+
}
|
|
106
|
+
function doStop() {
|
|
107
|
+
const pid = readPidIfRunning();
|
|
108
|
+
if (!pid) {
|
|
109
|
+
console.log('(daemon was not running)');
|
|
110
|
+
return 0;
|
|
111
|
+
}
|
|
112
|
+
try {
|
|
113
|
+
process.kill(pid, 'SIGTERM');
|
|
114
|
+
console.log(`✓ sent SIGTERM to pid=${pid}`);
|
|
115
|
+
return 0;
|
|
116
|
+
}
|
|
117
|
+
catch (e) {
|
|
118
|
+
console.error(`✗ failed to stop daemon: ${e?.message ?? e}`);
|
|
119
|
+
return 1;
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
function doStatus() {
|
|
123
|
+
const pid = readPidIfRunning();
|
|
124
|
+
const tasks = listTasks();
|
|
125
|
+
const enabled = tasks.filter((t) => t.enabled).length;
|
|
126
|
+
if (!pid) {
|
|
127
|
+
console.log('Status: not running');
|
|
128
|
+
console.log(`Tasks: ${tasks.length} total, ${enabled} enabled (daemon must be running to fire them)`);
|
|
129
|
+
console.log(`PID file: ${PID_FILE}`);
|
|
130
|
+
return 0;
|
|
131
|
+
}
|
|
132
|
+
console.log(`Status: running (pid=${pid})`);
|
|
133
|
+
console.log(`Tasks: ${tasks.length} total, ${enabled} enabled`);
|
|
134
|
+
console.log(`PID file: ${PID_FILE}`);
|
|
135
|
+
console.log(`Logs: ${STDOUT_LOG}`);
|
|
136
|
+
return 0;
|
|
137
|
+
}
|
|
138
|
+
function doLogs(flags) {
|
|
139
|
+
if (!existsSync(STDOUT_LOG) && !existsSync(STDERR_LOG)) {
|
|
140
|
+
console.log('(no daemon logs yet — start the daemon first)');
|
|
141
|
+
return 0;
|
|
142
|
+
}
|
|
143
|
+
if (flags.follow) {
|
|
144
|
+
// Use tail -F so log rotation / atomic-replace is handled for free.
|
|
145
|
+
try {
|
|
146
|
+
execSync(`tail -F "${STDOUT_LOG}" "${STDERR_LOG}"`, { stdio: 'inherit' });
|
|
147
|
+
}
|
|
148
|
+
catch { /* tail terminated by user */ }
|
|
149
|
+
return 0;
|
|
150
|
+
}
|
|
151
|
+
// One-shot: print the last 100 lines of each.
|
|
152
|
+
const tail = (file) => {
|
|
153
|
+
if (!existsSync(file))
|
|
154
|
+
return;
|
|
155
|
+
try {
|
|
156
|
+
const buf = readFileSync(file, 'utf-8');
|
|
157
|
+
const lines = buf.split('\n');
|
|
158
|
+
const last = lines.slice(-100).join('\n');
|
|
159
|
+
console.log(`── ${file} ──`);
|
|
160
|
+
console.log(last);
|
|
161
|
+
}
|
|
162
|
+
catch { /* noop */ }
|
|
163
|
+
};
|
|
164
|
+
tail(STDOUT_LOG);
|
|
165
|
+
tail(STDERR_LOG);
|
|
166
|
+
return 0;
|
|
167
|
+
}
|
|
168
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/daemon/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
// launchd integration — `yome daemon install` writes a plist to
|
|
2
|
+
// ~/Library/LaunchAgents/work.yome.daemon.plist and loads it via
|
|
3
|
+
// launchctl, so the daemon survives reboots / logouts.
|
|
4
|
+
//
|
|
5
|
+
// We deliberately use a USER LaunchAgent (not a system LaunchDaemon) so
|
|
6
|
+
// no sudo is required and the daemon inherits the user's environment
|
|
7
|
+
// (Keychain access, ~/.yome/, etc.).
|
|
8
|
+
import { writeFileSync, existsSync, unlinkSync, mkdirSync } from 'fs';
|
|
9
|
+
import { join } from 'path';
|
|
10
|
+
import { homedir } from 'os';
|
|
11
|
+
import { execSync } from 'child_process';
|
|
12
|
+
import { PLIST_LABEL, STDOUT_LOG, STDERR_LOG, DAEMON_ROOT } from './paths.js';
|
|
13
|
+
const LAUNCH_AGENTS_DIR = join(homedir(), 'Library', 'LaunchAgents');
|
|
14
|
+
const PLIST_PATH = join(LAUNCH_AGENTS_DIR, `${PLIST_LABEL}.plist`);
|
|
15
|
+
function buildPlist(yomeBinPath) {
|
|
16
|
+
// ProgramArguments uses absolute paths because launchd doesn't honour
|
|
17
|
+
// the user's interactive PATH. We prepend a wide PATH for the agent's
|
|
18
|
+
// own subprocess spawns (Bash tool / skill OTA backends).
|
|
19
|
+
const homebrewBin = '/opt/homebrew/bin';
|
|
20
|
+
const localBin = '/usr/local/bin';
|
|
21
|
+
return `<?xml version="1.0" encoding="UTF-8"?>
|
|
22
|
+
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
|
23
|
+
<plist version="1.0">
|
|
24
|
+
<dict>
|
|
25
|
+
<key>Label</key><string>${PLIST_LABEL}</string>
|
|
26
|
+
<key>ProgramArguments</key>
|
|
27
|
+
<array>
|
|
28
|
+
<string>${process.execPath}</string>
|
|
29
|
+
<string>${yomeBinPath}</string>
|
|
30
|
+
<string>daemon</string>
|
|
31
|
+
<string>start</string>
|
|
32
|
+
<string>--foreground</string>
|
|
33
|
+
</array>
|
|
34
|
+
<key>RunAtLoad</key><true/>
|
|
35
|
+
<key>KeepAlive</key>
|
|
36
|
+
<dict>
|
|
37
|
+
<key>SuccessfulExit</key><false/>
|
|
38
|
+
<key>Crashed</key><true/>
|
|
39
|
+
</dict>
|
|
40
|
+
<key>StandardOutPath</key><string>${STDOUT_LOG}</string>
|
|
41
|
+
<key>StandardErrorPath</key><string>${STDERR_LOG}</string>
|
|
42
|
+
<key>WorkingDirectory</key><string>${homedir()}</string>
|
|
43
|
+
<key>EnvironmentVariables</key>
|
|
44
|
+
<dict>
|
|
45
|
+
<key>PATH</key><string>${homebrewBin}:${localBin}:/usr/bin:/bin:/usr/sbin:/sbin</string>
|
|
46
|
+
<key>HOME</key><string>${homedir()}</string>
|
|
47
|
+
</dict>
|
|
48
|
+
<key>ProcessType</key><string>Background</string>
|
|
49
|
+
</dict>
|
|
50
|
+
</plist>
|
|
51
|
+
`;
|
|
52
|
+
}
|
|
53
|
+
export function installLaunchAgent(yomeBinPath) {
|
|
54
|
+
if (process.platform !== 'darwin') {
|
|
55
|
+
return { ok: false, plistPath: PLIST_PATH, message: 'launchd is macOS-only' };
|
|
56
|
+
}
|
|
57
|
+
try {
|
|
58
|
+
mkdirSync(LAUNCH_AGENTS_DIR, { recursive: true });
|
|
59
|
+
mkdirSync(DAEMON_ROOT, { recursive: true });
|
|
60
|
+
const plist = buildPlist(yomeBinPath);
|
|
61
|
+
writeFileSync(PLIST_PATH, plist, 'utf-8');
|
|
62
|
+
// unload first (ignore errors — likely just "not loaded")
|
|
63
|
+
try {
|
|
64
|
+
execSync(`launchctl unload "${PLIST_PATH}"`, { stdio: 'ignore' });
|
|
65
|
+
}
|
|
66
|
+
catch { /* noop */ }
|
|
67
|
+
execSync(`launchctl load "${PLIST_PATH}"`, { stdio: 'ignore' });
|
|
68
|
+
return { ok: true, plistPath: PLIST_PATH, message: `installed and loaded ${PLIST_PATH}` };
|
|
69
|
+
}
|
|
70
|
+
catch (e) {
|
|
71
|
+
return { ok: false, plistPath: PLIST_PATH, message: `install failed: ${e?.message ?? e}` };
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
export function uninstallLaunchAgent() {
|
|
75
|
+
if (process.platform !== 'darwin') {
|
|
76
|
+
return { ok: false, plistPath: PLIST_PATH, message: 'launchd is macOS-only' };
|
|
77
|
+
}
|
|
78
|
+
try {
|
|
79
|
+
if (existsSync(PLIST_PATH)) {
|
|
80
|
+
try {
|
|
81
|
+
execSync(`launchctl unload "${PLIST_PATH}"`, { stdio: 'ignore' });
|
|
82
|
+
}
|
|
83
|
+
catch { /* noop */ }
|
|
84
|
+
unlinkSync(PLIST_PATH);
|
|
85
|
+
return { ok: true, plistPath: PLIST_PATH, message: `unloaded and removed ${PLIST_PATH}` };
|
|
86
|
+
}
|
|
87
|
+
return { ok: true, plistPath: PLIST_PATH, message: '(was not installed)' };
|
|
88
|
+
}
|
|
89
|
+
catch (e) {
|
|
90
|
+
return { ok: false, plistPath: PLIST_PATH, message: `uninstall failed: ${e?.message ?? e}` };
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
//# sourceMappingURL=launchd.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"launchd.js","sourceRoot":"","sources":["../../src/daemon/launchd.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
export type LogEntryType = 'run_start' | 'run_end' | 'tool_use' | 'tool_result' | 'text_delta' | 'permission_denied_auto' | 'timeout' | 'error';
|
|
2
|
+
export interface LogEntry {
|
|
3
|
+
ts: number;
|
|
4
|
+
type: LogEntryType;
|
|
5
|
+
[k: string]: unknown;
|
|
6
|
+
}
|
|
7
|
+
export declare function openTaskLog(taskId: string, runTs: number): string;
|
|
8
|
+
export declare function appendLog(file: string, entry: Omit<LogEntry, 'ts'> & {
|
|
9
|
+
ts?: number;
|
|
10
|
+
}): void;
|
|
11
|
+
/** List run-log files for a task, newest first. */
|
|
12
|
+
export declare function listRunsForTask(taskId: string): {
|
|
13
|
+
runTs: number;
|
|
14
|
+
file: string;
|
|
15
|
+
sizeBytes: number;
|
|
16
|
+
}[];
|
|
17
|
+
export declare function readRunLog(file: string): LogEntry[];
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
// JSONL audit log for daemon-run tasks.
|
|
2
|
+
// One file per (taskId, runStartTs). Append-only, line-delimited JSON so
|
|
3
|
+
// `yome cron logs <id>` can tail / parse it without touching live writers.
|
|
4
|
+
import { appendFileSync, readFileSync, readdirSync, existsSync, statSync } from 'fs';
|
|
5
|
+
import { join } from 'path';
|
|
6
|
+
import { logFileForTask, logDirForTask } from './paths.js';
|
|
7
|
+
export function openTaskLog(taskId, runTs) {
|
|
8
|
+
return logFileForTask(taskId, runTs);
|
|
9
|
+
}
|
|
10
|
+
export function appendLog(file, entry) {
|
|
11
|
+
const full = { ts: entry.ts ?? Date.now(), ...entry };
|
|
12
|
+
try {
|
|
13
|
+
appendFileSync(file, JSON.stringify(full) + '\n', 'utf-8');
|
|
14
|
+
}
|
|
15
|
+
catch {
|
|
16
|
+
// Best-effort: if the log dir vanished mid-run we don't want to crash
|
|
17
|
+
// the agent. The runner already keeps an in-memory error counter.
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
/** List run-log files for a task, newest first. */
|
|
21
|
+
export function listRunsForTask(taskId) {
|
|
22
|
+
const dir = logDirForTask(taskId);
|
|
23
|
+
if (!existsSync(dir))
|
|
24
|
+
return [];
|
|
25
|
+
const files = readdirSync(dir).filter((f) => f.endsWith('.jsonl'));
|
|
26
|
+
const out = files.map((f) => {
|
|
27
|
+
const full = join(dir, f);
|
|
28
|
+
const runTs = Number.parseInt(f.replace('.jsonl', ''), 10) || 0;
|
|
29
|
+
let sizeBytes = 0;
|
|
30
|
+
try {
|
|
31
|
+
sizeBytes = statSync(full).size;
|
|
32
|
+
}
|
|
33
|
+
catch { /* race */ }
|
|
34
|
+
return { runTs, file: full, sizeBytes };
|
|
35
|
+
});
|
|
36
|
+
out.sort((a, b) => b.runTs - a.runTs);
|
|
37
|
+
return out;
|
|
38
|
+
}
|
|
39
|
+
export function readRunLog(file) {
|
|
40
|
+
try {
|
|
41
|
+
const raw = readFileSync(file, 'utf-8').trim();
|
|
42
|
+
if (!raw)
|
|
43
|
+
return [];
|
|
44
|
+
const out = [];
|
|
45
|
+
for (const line of raw.split('\n')) {
|
|
46
|
+
try {
|
|
47
|
+
out.push(JSON.parse(line));
|
|
48
|
+
}
|
|
49
|
+
catch { /* skip malformed */ }
|
|
50
|
+
}
|
|
51
|
+
return out;
|
|
52
|
+
}
|
|
53
|
+
catch {
|
|
54
|
+
return [];
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
//# sourceMappingURL=log.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"log.js","sourceRoot":"","sources":["../../src/daemon/log.ts"],"names":[],"mappings":"AAAA,wCAAwC;AACxC,yEAAyE;AACzE,2EAA2E;AAE3E,OAAO,EAAE,cAAc,EAAE,YAAY,EAAE,WAAW,EAAE,UAAU,EAAE,QAAQ,EAAE,MAAM,IAAI,CAAC;AACrF,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;AAC5B,OAAO,EAAE,cAAc,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAkB3D,MAAM,UAAU,WAAW,CAAC,MAAc,EAAE,KAAa;IACvD,OAAO,cAAc,CAAC,MAAM,EAAE,KAAK,CAAC,CAAC;AACvC,CAAC;AAED,MAAM,UAAU,SAAS,CAAC,IAAY,EAAE,KAA6C;IACnF,MAAM,IAAI,GAAa,EAAE,EAAE,EAAE,KAAK,CAAC,EAAE,IAAI,IAAI,CAAC,GAAG,EAAE,EAAE,GAAG,KAAK,EAAc,CAAC;IAC5E,IAAI,CAAC;QACH,cAAc,CAAC,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,GAAG,IAAI,EAAE,OAAO,CAAC,CAAC;IAC7D,CAAC;IAAC,MAAM,CAAC;QACP,sEAAsE;QACtE,kEAAkE;IACpE,CAAC;AACH,CAAC;AAED,mDAAmD;AACnD,MAAM,UAAU,eAAe,CAAC,MAAc;IAC5C,MAAM,GAAG,GAAG,aAAa,CAAC,MAAM,CAAC,CAAC;IAClC,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC;QAAE,OAAO,EAAE,CAAC;IAChC,MAAM,KAAK,GAAG,WAAW,CAAC,GAAG,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC,CAAC;IACnE,MAAM,GAAG,GAAG,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE;QAC1B,MAAM,IAAI,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC;QAC1B,MAAM,KAAK,GAAG,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAC,OAAO,CAAC,QAAQ,EAAE,EAAE,CAAC,EAAE,EAAE,CAAC,IAAI,CAAC,CAAC;QAChE,IAAI,SAAS,GAAG,CAAC,CAAC;QAClB,IAAI,CAAC;YAAC,SAAS,GAAG,QAAQ,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC;QAAC,CAAC;QAAC,MAAM,CAAC,CAAC,UAAU,CAAC,CAAC;QAC7D,OAAO,EAAE,KAAK,EAAE,IAAI,EAAE,IAAI,EAAE,SAAS,EAAE,CAAC;IAC1C,CAAC,CAAC,CAAC;IACH,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,KAAK,GAAG,CAAC,CAAC,KAAK,CAAC,CAAC;IACtC,OAAO,GAAG,CAAC;AACb,CAAC;AAED,MAAM,UAAU,UAAU,CAAC,IAAY;IACrC,IAAI,CAAC;QACH,MAAM,GAAG,GAAG,YAAY,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC,IAAI,EAAE,CAAC;QAC/C,IAAI,CAAC,GAAG;YAAE,OAAO,EAAE,CAAC;QACpB,MAAM,GAAG,GAAe,EAAE,CAAC;QAC3B,KAAK,MAAM,IAAI,IAAI,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC;YACnC,IAAI,CAAC;gBAAC,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC;YAAC,CAAC;YAAC,MAAM,CAAC,CAAC,oBAAoB,CAAC,CAAC;QACpE,CAAC;QACD,OAAO,GAAG,CAAC;IACb,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,EAAE,CAAC;IACZ,CAAC;AACH,CAAC"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
export declare const DAEMON_ROOT: string;
|
|
2
|
+
export declare const CRON_ROOT: string;
|
|
3
|
+
export declare const TASKS_FILE: string;
|
|
4
|
+
export declare const LOGS_ROOT: string;
|
|
5
|
+
export declare const PID_FILE: string;
|
|
6
|
+
export declare const STDOUT_LOG: string;
|
|
7
|
+
export declare const STDERR_LOG: string;
|
|
8
|
+
export declare const PLIST_LABEL = "work.yome.daemon";
|
|
9
|
+
export declare function ensureDirs(): void;
|
|
10
|
+
export declare function logFileForTask(taskId: string, runTs: number): string;
|
|
11
|
+
export declare function logDirForTask(taskId: string): string;
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
// Daemon-wide path constants. Centralised so the runner, scheduler, log
|
|
2
|
+
// reader and launchd plist generator all agree on where things live.
|
|
3
|
+
import { join } from 'path';
|
|
4
|
+
import { homedir } from 'os';
|
|
5
|
+
import { mkdirSync } from 'fs';
|
|
6
|
+
export const DAEMON_ROOT = join(homedir(), '.yome', 'daemon');
|
|
7
|
+
export const CRON_ROOT = join(homedir(), '.yome', 'cron');
|
|
8
|
+
export const TASKS_FILE = join(CRON_ROOT, 'tasks.json');
|
|
9
|
+
export const LOGS_ROOT = join(CRON_ROOT, 'logs');
|
|
10
|
+
export const PID_FILE = join(DAEMON_ROOT, 'daemon.pid');
|
|
11
|
+
export const STDOUT_LOG = join(DAEMON_ROOT, 'stdout.log');
|
|
12
|
+
export const STDERR_LOG = join(DAEMON_ROOT, 'stderr.log');
|
|
13
|
+
export const PLIST_LABEL = 'work.yome.daemon';
|
|
14
|
+
export function ensureDirs() {
|
|
15
|
+
mkdirSync(DAEMON_ROOT, { recursive: true });
|
|
16
|
+
mkdirSync(CRON_ROOT, { recursive: true });
|
|
17
|
+
mkdirSync(LOGS_ROOT, { recursive: true });
|
|
18
|
+
}
|
|
19
|
+
export function logFileForTask(taskId, runTs) {
|
|
20
|
+
const dir = join(LOGS_ROOT, taskId);
|
|
21
|
+
mkdirSync(dir, { recursive: true });
|
|
22
|
+
return join(dir, `${runTs}.jsonl`);
|
|
23
|
+
}
|
|
24
|
+
export function logDirForTask(taskId) {
|
|
25
|
+
return join(LOGS_ROOT, taskId);
|
|
26
|
+
}
|
|
27
|
+
//# sourceMappingURL=paths.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"paths.js","sourceRoot":"","sources":["../../src/daemon/paths.ts"],"names":[],"mappings":"AAAA,wEAAwE;AACxE,qEAAqE;AAErE,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;AAC5B,OAAO,EAAE,OAAO,EAAE,MAAM,IAAI,CAAC;AAC7B,OAAO,EAAE,SAAS,EAAE,MAAM,IAAI,CAAC;AAE/B,MAAM,CAAC,MAAM,WAAW,GAAG,IAAI,CAAC,OAAO,EAAE,EAAE,OAAO,EAAE,QAAQ,CAAC,CAAC;AAC9D,MAAM,CAAC,MAAM,SAAS,GAAG,IAAI,CAAC,OAAO,EAAE,EAAE,OAAO,EAAE,MAAM,CAAC,CAAC;AAC1D,MAAM,CAAC,MAAM,UAAU,GAAG,IAAI,CAAC,SAAS,EAAE,YAAY,CAAC,CAAC;AACxD,MAAM,CAAC,MAAM,SAAS,GAAG,IAAI,CAAC,SAAS,EAAE,MAAM,CAAC,CAAC;AACjD,MAAM,CAAC,MAAM,QAAQ,GAAG,IAAI,CAAC,WAAW,EAAE,YAAY,CAAC,CAAC;AACxD,MAAM,CAAC,MAAM,UAAU,GAAG,IAAI,CAAC,WAAW,EAAE,YAAY,CAAC,CAAC;AAC1D,MAAM,CAAC,MAAM,UAAU,GAAG,IAAI,CAAC,WAAW,EAAE,YAAY,CAAC,CAAC;AAC1D,MAAM,CAAC,MAAM,WAAW,GAAG,kBAAkB,CAAC;AAE9C,MAAM,UAAU,UAAU;IACxB,SAAS,CAAC,WAAW,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IAC5C,SAAS,CAAC,SAAS,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IAC1C,SAAS,CAAC,SAAS,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;AAC5C,CAAC;AAED,MAAM,UAAU,cAAc,CAAC,MAAc,EAAE,KAAa;IAC1D,MAAM,GAAG,GAAG,IAAI,CAAC,SAAS,EAAE,MAAM,CAAC,CAAC;IACpC,SAAS,CAAC,GAAG,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IACpC,OAAO,IAAI,CAAC,GAAG,EAAE,GAAG,KAAK,QAAQ,CAAC,CAAC;AACrC,CAAC;AAED,MAAM,UAAU,aAAa,CAAC,MAAc;IAC1C,OAAO,IAAI,CAAC,SAAS,EAAE,MAAM,CAAC,CAAC;AACjC,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function runTaskById(taskId: string): Promise<number>;
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
// Entry point for `yome __run-task <id>`.
|
|
2
|
+
//
|
|
3
|
+
// The cron trigger spawns a child process per fire, with this command.
|
|
4
|
+
// We load the task from tasks.json, build a config (same as interactive
|
|
5
|
+
// `yome`), call runDaemonTask, then exit with 0/1 based on success.
|
|
6
|
+
//
|
|
7
|
+
// This file is intentionally tiny — all business logic lives in
|
|
8
|
+
// runner.ts. Keeping the entry small means the cold-start cost per fire
|
|
9
|
+
// is just "load Node + parse tasks.json + bootstrap Agent".
|
|
10
|
+
import { resolveConfig, loadModelEntries, modelEntryToConfig } from '../config.js';
|
|
11
|
+
import { getTask } from './taskStore.js';
|
|
12
|
+
import { runDaemonTask } from './runner.js';
|
|
13
|
+
import { buildEnvHint } from './envHint.js';
|
|
14
|
+
export async function runTaskById(taskId) {
|
|
15
|
+
const t = getTask(taskId);
|
|
16
|
+
if (!t) {
|
|
17
|
+
console.error(`__run-task: no such task: ${taskId}`);
|
|
18
|
+
return 1;
|
|
19
|
+
}
|
|
20
|
+
// Resolve the LLM config. Same precedence as interactive `yome`:
|
|
21
|
+
// stored config → first customModels entry → bail.
|
|
22
|
+
let config = resolveConfig({});
|
|
23
|
+
if (!config.apiKey) {
|
|
24
|
+
const entries = loadModelEntries();
|
|
25
|
+
if (entries.length > 0)
|
|
26
|
+
config = modelEntryToConfig(entries[0]);
|
|
27
|
+
}
|
|
28
|
+
if (!config.apiKey) {
|
|
29
|
+
console.error('__run-task: no API key — set one via `yome --key sk-...` first');
|
|
30
|
+
return 1;
|
|
31
|
+
}
|
|
32
|
+
// Compose the final user prompt by stacking three layers, in order:
|
|
33
|
+
// 1. envHint — auto-detected local tools + per-OS gotchas, only in daemon mode.
|
|
34
|
+
// 2. extra — runtime context injected by file/calendar triggers via env var.
|
|
35
|
+
// 3. t.prompt — what the user originally wrote in `yome cron add "..."`.
|
|
36
|
+
// Each layer is independent: if the env hint detects nothing, it returns
|
|
37
|
+
// '' and is filtered out so we don't waste tokens on an empty header.
|
|
38
|
+
const envHint = buildEnvHint();
|
|
39
|
+
const extra = process.env.YOME_TASK_EXTRA_CONTEXT;
|
|
40
|
+
const promptWithContext = [envHint, extra?.trim(), t.prompt]
|
|
41
|
+
.filter((s) => !!s && s.length > 0)
|
|
42
|
+
.join('\n\n');
|
|
43
|
+
const result = await runDaemonTask(config, {
|
|
44
|
+
taskId: t.id,
|
|
45
|
+
prompt: promptWithContext,
|
|
46
|
+
cwd: t.cwd,
|
|
47
|
+
autoAllow: t.autoAllow,
|
|
48
|
+
autoDeny: t.autoDeny,
|
|
49
|
+
});
|
|
50
|
+
// Brief stdout summary — the audit jsonl in ~/.yome/cron/logs/<id>/
|
|
51
|
+
// has the full transcript. The parent process (scheduler) captures
|
|
52
|
+
// stdout and stuffs the tail into the run_end log entry, so this
|
|
53
|
+
// doubles as a coarse status line.
|
|
54
|
+
console.log(JSON.stringify({
|
|
55
|
+
taskId: t.id,
|
|
56
|
+
ok: result.ok,
|
|
57
|
+
toolCalls: result.toolCalls,
|
|
58
|
+
durationMs: result.durationMs,
|
|
59
|
+
inputTokens: result.inputTokens,
|
|
60
|
+
outputTokens: result.outputTokens,
|
|
61
|
+
error: result.error,
|
|
62
|
+
finalTextHead: result.finalText.slice(0, 200),
|
|
63
|
+
logFile: result.logFile,
|
|
64
|
+
}));
|
|
65
|
+
return result.ok ? 0 : 1;
|
|
66
|
+
}
|
|
67
|
+
//# sourceMappingURL=runTaskEntry.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"runTaskEntry.js","sourceRoot":"","sources":["../../src/daemon/runTaskEntry.ts"],"names":[],"mappings":"AAAA,0CAA0C;AAC1C,EAAE;AACF,uEAAuE;AACvE,wEAAwE;AACxE,oEAAoE;AACpE,EAAE;AACF,gEAAgE;AAChE,wEAAwE;AACxE,4DAA4D;AAE5D,OAAO,EAAE,aAAa,EAAE,gBAAgB,EAAE,kBAAkB,EAAE,MAAM,cAAc,CAAC;AACnF,OAAO,EAAE,OAAO,EAAE,MAAM,gBAAgB,CAAC;AACzC,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAC5C,OAAO,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AAE5C,MAAM,CAAC,KAAK,UAAU,WAAW,CAAC,MAAc;IAC9C,MAAM,CAAC,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;IAC1B,IAAI,CAAC,CAAC,EAAE,CAAC;QACP,OAAO,CAAC,KAAK,CAAC,6BAA6B,MAAM,EAAE,CAAC,CAAC;QACrD,OAAO,CAAC,CAAC;IACX,CAAC;IAED,iEAAiE;IACjE,qDAAqD;IACrD,IAAI,MAAM,GAAG,aAAa,CAAC,EAAE,CAAC,CAAC;IAC/B,IAAI,CAAC,MAAM,CAAC,MAAM,EAAE,CAAC;QACnB,MAAM,OAAO,GAAG,gBAAgB,EAAE,CAAC;QACnC,IAAI,OAAO,CAAC,MAAM,GAAG,CAAC;YAAE,MAAM,GAAG,kBAAkB,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC;IAClE,CAAC;IACD,IAAI,CAAC,MAAM,CAAC,MAAM,EAAE,CAAC;QACnB,OAAO,CAAC,KAAK,CAAC,gEAAgE,CAAC,CAAC;QAChF,OAAO,CAAC,CAAC;IACX,CAAC;IAED,oEAAoE;IACpE,sFAAsF;IACtF,qFAAqF;IACrF,8EAA8E;IAC9E,yEAAyE;IACzE,sEAAsE;IACtE,MAAM,OAAO,GAAG,YAAY,EAAE,CAAC;IAC/B,MAAM,KAAK,GAAG,OAAO,CAAC,GAAG,CAAC,uBAAuB,CAAC;IAClD,MAAM,iBAAiB,GAAG,CAAC,OAAO,EAAE,KAAK,EAAE,IAAI,EAAE,EAAE,CAAC,CAAC,MAAM,CAAC;SACzD,MAAM,CAAC,CAAC,CAAC,EAAe,EAAE,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,MAAM,GAAG,CAAC,CAAC;SAC/C,IAAI,CAAC,MAAM,CAAC,CAAC;IAEhB,MAAM,MAAM,GAAG,MAAM,aAAa,CAAC,MAAM,EAAE;QACzC,MAAM,EAAE,CAAC,CAAC,EAAE;QACZ,MAAM,EAAE,iBAAiB;QACzB,GAAG,EAAE,CAAC,CAAC,GAAG;QACV,SAAS,EAAE,CAAC,CAAC,SAAS;QACtB,QAAQ,EAAE,CAAC,CAAC,QAAQ;KACrB,CAAC,CAAC;IAEH,oEAAoE;IACpE,mEAAmE;IACnE,iEAAiE;IACjE,mCAAmC;IACnC,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC;QACzB,MAAM,EAAE,CAAC,CAAC,EAAE;QACZ,EAAE,EAAE,MAAM,CAAC,EAAE;QACb,SAAS,EAAE,MAAM,CAAC,SAAS;QAC3B,UAAU,EAAE,MAAM,CAAC,UAAU;QAC7B,WAAW,EAAE,MAAM,CAAC,WAAW;QAC/B,YAAY,EAAE,MAAM,CAAC,YAAY;QACjC,KAAK,EAAE,MAAM,CAAC,KAAK;QACnB,aAAa,EAAE,MAAM,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC;QAC7C,OAAO,EAAE,MAAM,CAAC,OAAO;KACxB,CAAC,CAAC,CAAC;IAEJ,OAAO,MAAM,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AAC3B,CAAC"}
|