@poping/yome 0.0.3 → 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.
Files changed (126) hide show
  1. package/README.md +5 -7
  2. package/README.zh-CN.md +5 -7
  3. package/bin/yome-calwatch +0 -0
  4. package/dist/context.js +6 -3
  5. package/dist/context.js.map +1 -1
  6. package/dist/daemon/calendarPermission.d.ts +10 -0
  7. package/dist/daemon/calendarPermission.js +68 -0
  8. package/dist/daemon/calendarPermission.js.map +1 -0
  9. package/dist/daemon/cronCli.d.ts +19 -0
  10. package/dist/daemon/cronCli.js +403 -0
  11. package/dist/daemon/cronCli.js.map +1 -0
  12. package/dist/daemon/envHint.d.ts +5 -0
  13. package/dist/daemon/envHint.js +139 -0
  14. package/dist/daemon/envHint.js.map +1 -0
  15. package/dist/daemon/humanCron.d.ts +1 -0
  16. package/dist/daemon/humanCron.js +72 -0
  17. package/dist/daemon/humanCron.js.map +1 -0
  18. package/dist/daemon/humanOnce.d.ts +1 -0
  19. package/dist/daemon/humanOnce.js +54 -0
  20. package/dist/daemon/humanOnce.js.map +1 -0
  21. package/dist/daemon/index.d.ts +5 -0
  22. package/dist/daemon/index.js +168 -0
  23. package/dist/daemon/index.js.map +1 -0
  24. package/dist/daemon/launchd.d.ts +7 -0
  25. package/dist/daemon/launchd.js +93 -0
  26. package/dist/daemon/launchd.js.map +1 -0
  27. package/dist/daemon/log.d.ts +17 -0
  28. package/dist/daemon/log.js +57 -0
  29. package/dist/daemon/log.js.map +1 -0
  30. package/dist/daemon/paths.d.ts +11 -0
  31. package/dist/daemon/paths.js +27 -0
  32. package/dist/daemon/paths.js.map +1 -0
  33. package/dist/daemon/runTaskEntry.d.ts +1 -0
  34. package/dist/daemon/runTaskEntry.js +67 -0
  35. package/dist/daemon/runTaskEntry.js.map +1 -0
  36. package/dist/daemon/runner.d.ts +21 -0
  37. package/dist/daemon/runner.js +175 -0
  38. package/dist/daemon/runner.js.map +1 -0
  39. package/dist/daemon/scheduler.d.ts +5 -0
  40. package/dist/daemon/scheduler.js +162 -0
  41. package/dist/daemon/scheduler.js.map +1 -0
  42. package/dist/daemon/taskStore.d.ts +62 -0
  43. package/dist/daemon/taskStore.js +88 -0
  44. package/dist/daemon/taskStore.js.map +1 -0
  45. package/dist/daemon/triggers/calendar.d.ts +8 -0
  46. package/dist/daemon/triggers/calendar.js +248 -0
  47. package/dist/daemon/triggers/calendar.js.map +1 -0
  48. package/dist/daemon/triggers/childRunner.d.ts +14 -0
  49. package/dist/daemon/triggers/childRunner.js +111 -0
  50. package/dist/daemon/triggers/childRunner.js.map +1 -0
  51. package/dist/daemon/triggers/cron.d.ts +14 -0
  52. package/dist/daemon/triggers/cron.js +91 -0
  53. package/dist/daemon/triggers/cron.js.map +1 -0
  54. package/dist/daemon/triggers/file.d.ts +7 -0
  55. package/dist/daemon/triggers/file.js +123 -0
  56. package/dist/daemon/triggers/file.js.map +1 -0
  57. package/dist/daemon/triggers/once.d.ts +10 -0
  58. package/dist/daemon/triggers/once.js +80 -0
  59. package/dist/daemon/triggers/once.js.map +1 -0
  60. package/dist/index.js +96 -9
  61. package/dist/index.js.map +1 -1
  62. package/dist/skills/runner/dispatcher.d.ts +74 -3
  63. package/dist/skills/runner/dispatcher.js +258 -48
  64. package/dist/skills/runner/dispatcher.js.map +1 -1
  65. package/dist/skills/runner/dispatcher.test.d.ts +1 -0
  66. package/dist/skills/runner/dispatcher.test.js +141 -0
  67. package/dist/skills/runner/dispatcher.test.js.map +1 -0
  68. package/dist/skills/runner/kernel.js +0 -1
  69. package/dist/skills/runner/kernel.js.map +1 -1
  70. package/dist/skills/runner/nodeBackend.d.ts +32 -0
  71. package/dist/skills/runner/nodeBackend.js +147 -0
  72. package/dist/skills/runner/nodeBackend.js.map +1 -0
  73. package/dist/state/todos.d.ts +12 -0
  74. package/dist/state/todos.js +32 -0
  75. package/dist/state/todos.js.map +1 -0
  76. package/dist/tools/askUser.d.ts +20 -0
  77. package/dist/tools/askUser.js +126 -0
  78. package/dist/tools/askUser.js.map +1 -0
  79. package/dist/tools/bash.js +13 -19
  80. package/dist/tools/bash.js.map +1 -1
  81. package/dist/tools/index.d.ts +2 -0
  82. package/dist/tools/index.js +18 -5
  83. package/dist/tools/index.js.map +1 -1
  84. package/dist/tools/todoWrite.d.ts +2 -0
  85. package/dist/tools/todoWrite.js +141 -0
  86. package/dist/tools/todoWrite.js.map +1 -0
  87. package/dist/tools/yome.d.ts +2 -0
  88. package/dist/tools/yome.js +87 -0
  89. package/dist/tools/yome.js.map +1 -0
  90. package/dist/ui/App.js +52 -3
  91. package/dist/ui/App.js.map +1 -1
  92. package/dist/ui/AskUserPrompt.d.ts +7 -0
  93. package/dist/ui/AskUserPrompt.js +78 -0
  94. package/dist/ui/AskUserPrompt.js.map +1 -0
  95. package/dist/ui/InputBar.js +20 -34
  96. package/dist/ui/InputBar.js.map +1 -1
  97. package/dist/ui/MessageList.d.ts +8 -0
  98. package/dist/ui/MessageList.js +2 -2
  99. package/dist/ui/MessageList.js.map +1 -1
  100. package/dist/ui/MultilineTextInput.d.ts +31 -0
  101. package/dist/ui/MultilineTextInput.js +393 -0
  102. package/dist/ui/MultilineTextInput.js.map +1 -0
  103. package/dist/ui/MultilineTextInput.test.d.ts +1 -0
  104. package/dist/ui/MultilineTextInput.test.js +30 -0
  105. package/dist/ui/MultilineTextInput.test.js.map +1 -0
  106. package/dist/ui/TodoPanel.d.ts +7 -0
  107. package/dist/ui/TodoPanel.js +36 -0
  108. package/dist/ui/TodoPanel.js.map +1 -0
  109. package/dist/yomeSkills/cli.d.ts +8 -0
  110. package/dist/yomeSkills/cli.js +155 -8
  111. package/dist/yomeSkills/cli.js.map +1 -1
  112. package/dist/yomeSkills/deprecate.d.ts +29 -0
  113. package/dist/yomeSkills/deprecate.js +99 -0
  114. package/dist/yomeSkills/deprecate.js.map +1 -0
  115. package/dist/yomeSkills/installFromHubTarball.d.ts +26 -0
  116. package/dist/yomeSkills/installFromHubTarball.js +161 -0
  117. package/dist/yomeSkills/installFromHubTarball.js.map +1 -0
  118. package/dist/yomeSkills/installGithub.d.ts +7 -0
  119. package/dist/yomeSkills/installGithub.js +42 -21
  120. package/dist/yomeSkills/installGithub.js.map +1 -1
  121. package/dist/yomeSkills/invoke.js +50 -18
  122. package/dist/yomeSkills/invoke.js.map +1 -1
  123. package/dist/yomeSkills/publish.d.ts +2 -0
  124. package/dist/yomeSkills/publish.js +6 -1
  125. package/dist/yomeSkills/publish.js.map +1 -1
  126. package/package.json +10 -2
package/README.md CHANGED
@@ -63,10 +63,9 @@ The agent loop must not live only in the 30 seconds after you press Enter. It sh
63
63
 
64
64
  | Capability | Meaning |
65
65
  |---|---|
66
- | **Daemon** | Long-lived background agent; state persists across sessions, no more "thinking only when a window is open" |
66
+ | **Daemon** | Yome runs as an OS-level daemon, not a chat window. It watches your filesystem, calendar, IM signals, and long-running jobs in the background — and only surfaces when something matters. The agent loop never has to be re-spawned from scratch. |
67
67
  | **Live compaction** | Long sessions auto-compress history; tokens never overflow, memory never lost |
68
- | **Custom missions** | Recurring tasks like *"every Monday morning, draft my weekly report"* become reusable missions |
69
- | **Async agent** | Long jobs run in the background and push notifications when done, instead of blocking your prompt |
68
+ | **Oncall** | The agent is event-driven, not prompt-driven. WeChat / Feishu / Slack / iMessage messages, calendar fires, build finishes, GPU spikes, *@you* mentions Yome reacts to the world and pages you with a one-line summary + a draft response, instead of waiting for you to ask. |
70
69
 
71
70
  **Available today:**
72
71
 
@@ -76,7 +75,7 @@ yome thread share <session-id> --skill=<slug> # build redacted case bundle
76
75
  yome thread submit <bundle-dir> --skill=<slug> # publish as PR (needs gh CLI)
77
76
  ```
78
77
 
79
- Sessions, history compaction and case bundles ship today. Daemon, custom missions and async agent are next-up on the `next` branch.
78
+ Sessions, history compaction and case bundles ship today. Daemon and Oncall are next-up on the `next` branch.
80
79
 
81
80
  ---
82
81
 
@@ -307,9 +306,8 @@ We do not replace your tools. We **empower** them without interrupting the way y
307
306
  | Capability model (sandbox grants) | **stable** |
308
307
  | Thread history + case bundles | **stable** |
309
308
  | Live history compaction | beta |
310
- | Daemon (always-on agent) | experimental, on `next` branch |
311
- | Custom missions (recurring tasks) | next-up |
312
- | Async agent (background long-running) | next-up |
309
+ | Daemon (OS-level always-on loop) | experimental, on `next` branch |
310
+ | Oncall (event-driven, auto-paging) | next-up |
313
311
 
314
312
  **Daemon roadmap** *(scoped, on `next`)*
315
313
 
package/README.zh-CN.md CHANGED
@@ -63,10 +63,9 @@ Agent loop 不能只活在用户敲下 Enter 的那 30 秒;它应当 always-on,
63
63
 
64
64
  | 能力 | 含义 |
65
65
  |---|---|
66
- | **Daemon · 守护进程** | Agent 长驻后台,跨会话保持状态,不再"开个窗口才会思考" |
66
+ | **Daemon · 守护进程** | Yome 是一个跑在系统层的 daemon,而不是一个聊天窗口。它在后台一直盯着你的文件系统、日历、IM 信号、长任务进程,只有真正值得打断你的时候才出现。Agent loop 永远不需要从零冷启动。 |
67
67
  | **Live compaction · 即时压缩** | 长会话自动压缩历史,token 永远不爆,记忆永远不丢 |
68
- | **Custom missions · 定制任务** | "每周一上午整理周报"这种重复任务沉淀成可复用 mission |
69
- | **Async agent · 异步 agent** | 后台跑长任务,完成后主动 push 通知,而不是阻塞你的 prompt |
68
+ | **Oncall · 主动响应** | Agent 由事件驱动,而不是 prompt 驱动。微信 / 飞书 / Slack / iMessage 来消息,日历到点,build 跑完,GPU 飙高,有人 @你 —— Yome 监听这些信号,主动把"这件事 + 一个候选回复"推给你,而不是等你想起来再问它。 |
70
69
 
71
70
  **当前可用:**
72
71
 
@@ -76,7 +75,7 @@ yome thread share <session-id> --skill=<slug> # 构建脱敏的 case bundle
76
75
  yome thread submit <bundle-dir> --skill=<slug> # 作为 PR 发布 (需要 gh CLI)
77
76
  ```
78
77
 
79
- 会话 / 历史压缩 / case bundle 这三件已落地。Daemon、custom missions、async agent 在 `next` 分支推进。
78
+ 会话 / 历史压缩 / case bundle 这三件已落地。Daemon Oncall 在 `next` 分支推进。
80
79
 
81
80
  ---
82
81
 
@@ -307,9 +306,8 @@ yome --key sk-... --base-url https://… --model …
307
306
  | Capability model (sandbox grants) | **stable** |
308
307
  | Thread 历史 + case bundles | **stable** |
309
308
  | Live history compaction | beta |
310
- | Daemon (always-on agent) | experimental, 在 `next` 分支 |
311
- | Custom missions (recurring tasks) | next-up |
312
- | Async agent (后台长任务) | next-up |
309
+ | Daemon (系统级常驻 loop) | experimental, 在 `next` 分支 |
310
+ | Oncall (事件驱动 / 主动 paging) | next-up |
313
311
 
314
312
  **Daemon roadmap** *(scoped, 在 `next` 分支)*
315
313
 
Binary file
package/dist/context.js CHANGED
@@ -93,11 +93,14 @@ You help with software engineering tasks: reading code, writing code, debugging,
93
93
  - Never expose secrets or API keys.
94
94
 
95
95
  ## Available Tools
96
- You have these tools: Read, Edit, Write, Bash, Glob, Grep, LS.
96
+ You have these tools: Read, Edit, Write, Bash, Yome, AskUser, TodoWrite, Glob, Grep, LS.
97
97
  - Use Read to view file contents.
98
98
  - Use Edit to modify existing files (find & replace with old_string/new_string).
99
99
  - Use Write to create new files.
100
- - Use Bash to run shell commands.
100
+ - Use Bash for /bin/sh commands ONLY (ls, cat, git, mkdir, build/test runners, pipes…). It does NOT route to hub skills.
101
+ - Use Yome to invoke installed hub-skill commands (xl, ppt, cal, fs, rem, …) — pass the command line exactly as a human would type it (e.g. \`xl books\`, \`ppt new ~/Desktop/x.pptx\`).
102
+ - Use AskUser when requirements are ambiguous or you need the user to choose between trade-offs BEFORE doing irreversible work. Send 1–4 multiple-choice questions; do NOT include "Other" (the UI provides a custom-answer entry). Blocks until the user responds.
103
+ - Use TodoWrite proactively whenever you start a task with 3+ meaningful steps. Always send the FULL list. Keep exactly ONE item in_progress at a time. Flip status the moment you start / finish a step — don't batch updates. Each item needs \`content\` (imperative) + \`activeForm\` (present continuous) + \`status\`.
101
104
  - Use Glob to find files by pattern.
102
105
  - Use Grep to search file contents.
103
106
  - Use LS to list directory contents.
@@ -162,7 +165,7 @@ function buildSkillsSection(skills) {
162
165
  * the trigger / effects / entry triad.
163
166
  */
164
167
  function buildHubSkillsSection(entries) {
165
- let section = `\n## Installed Hub Skills\nUse the Bash tool: \`<domain> <action> [args]\` (no \`yome\` prefix, no SkillCall).\n\n`;
168
+ let section = `\n## Installed Hub Skills\nUse the **Yome** tool: \`<domain> <action> [args]\` (no \`yome\` prefix, no SkillCall, NOT the Bash tool).\nThe Bash tool is for /bin/sh ops only and will NOT route to skills.\n\n`;
166
169
  for (const e of entries) {
167
170
  const manifest = readManifest(e.installedAt);
168
171
  section += renderL1Block(e.domain, manifest, e.description) + '\n';
@@ -1 +1 @@
1
- {"version":3,"file":"context.js","sourceRoot":"","sources":["../src/context.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"context.js","sourceRoot":"","sources":["../src/context.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,10 @@
1
+ export interface CalendarAccessResult {
2
+ ok: boolean;
3
+ status: 'granted' | 'denied' | 'restricted' | 'not-determined' | 'unknown' | 'no-helper';
4
+ message: string;
5
+ /** Hint surfaced from the Swift helper (e.g. "open System Settings → ..."). */
6
+ fix?: string;
7
+ }
8
+ /** Best-effort path to bin/yome-calwatch. */
9
+ export declare function resolveCalwatchPath(): string;
10
+ export declare function checkCalendarAccess(): CalendarAccessResult;
@@ -0,0 +1,68 @@
1
+ // Pre-flight EventKit permission probe for `yome cron add --on calendar:*`.
2
+ //
3
+ // We invoke the same Swift helper the daemon uses (`yome-calwatch
4
+ // --check-access`) — it's the only reliable way to learn the current
5
+ // state because TCC is per-binary, not per-user.
6
+ //
7
+ // Exit codes (mirrors the helper):
8
+ // 0 granted
9
+ // 2 denied / restricted (with a JSON line describing the fix)
10
+ // 3 unknown
11
+ // non-existent binary → returns { ok: false, message: '...' }
12
+ import { spawnSync } from 'child_process';
13
+ import { existsSync } from 'fs';
14
+ import { dirname, resolve } from 'path';
15
+ import { fileURLToPath } from 'url';
16
+ /** Best-effort path to bin/yome-calwatch. */
17
+ export function resolveCalwatchPath() {
18
+ const here = dirname(fileURLToPath(import.meta.url));
19
+ // dist/daemon/calendarPermission.js → ../../bin/yome-calwatch
20
+ // src/daemon/calendarPermission.ts → ../../bin/yome-calwatch
21
+ return resolve(here, '..', '..', 'bin', 'yome-calwatch');
22
+ }
23
+ export function checkCalendarAccess() {
24
+ const bin = resolveCalwatchPath();
25
+ if (!existsSync(bin)) {
26
+ return {
27
+ ok: false,
28
+ status: 'no-helper',
29
+ message: 'native helper yome-calwatch is missing. ' +
30
+ 'On macOS: cd cli && npm run build:native. ' +
31
+ 'On Linux/Windows: calendar triggers are macOS-only.',
32
+ };
33
+ }
34
+ const r = spawnSync(bin, ['--check-access'], { encoding: 'utf-8', timeout: 30_000 });
35
+ // Helper writes one JSON line to stdout regardless of exit code.
36
+ const last = (r.stdout ?? '').split('\n').reverse().find((l) => l.trim().startsWith('{'));
37
+ let parsed = {};
38
+ if (last) {
39
+ try {
40
+ parsed = JSON.parse(last);
41
+ }
42
+ catch { /* noop */ }
43
+ }
44
+ const status = String(parsed.status ?? '');
45
+ const fix = typeof parsed.fix === 'string' ? parsed.fix : undefined;
46
+ if (r.status === 0 && status === 'granted') {
47
+ return { ok: true, status: 'granted', message: 'calendar access granted' };
48
+ }
49
+ if (status === 'denied' || status === 'restricted') {
50
+ return {
51
+ ok: false,
52
+ status: status,
53
+ message: `calendar access ${status}`,
54
+ fix,
55
+ };
56
+ }
57
+ if (status === 'not-determined') {
58
+ return { ok: false, status: 'not-determined', message: 'calendar access not yet determined', fix };
59
+ }
60
+ return {
61
+ ok: false,
62
+ status: 'unknown',
63
+ message: `unable to determine calendar access (helper exit=${r.status}). ` +
64
+ `stdout=${(r.stdout ?? '').slice(0, 200)} stderr=${(r.stderr ?? '').slice(0, 200)}`,
65
+ fix,
66
+ };
67
+ }
68
+ //# sourceMappingURL=calendarPermission.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"calendarPermission.js","sourceRoot":"","sources":["../../src/daemon/calendarPermission.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,19 @@
1
+ export interface CronCliFlags {
2
+ at?: string;
3
+ human?: string;
4
+ once?: string;
5
+ on?: string;
6
+ path?: string;
7
+ within?: string;
8
+ titleRegex?: string;
9
+ calendar?: string;
10
+ tz?: string;
11
+ cwd?: string;
12
+ allow?: string | string[];
13
+ deny?: string | string[];
14
+ maxMs?: string;
15
+ env?: string | string[];
16
+ follow?: boolean;
17
+ json?: boolean;
18
+ }
19
+ export declare function runCronSubcommand(args: string[], flags: CronCliFlags): Promise<number>;
@@ -0,0 +1,403 @@
1
+ // `yome cron <subcommand>` — task management UI on top of taskStore.
2
+ //
3
+ // add create a new task
4
+ // list list tasks
5
+ // rm delete a task
6
+ // enable / disable
7
+ // run manually fire a task right now (out-of-process, like the scheduler does)
8
+ // logs show audit logs for a task
9
+ //
10
+ // All of these are pure CLI side-effects. The actual scheduling lives in
11
+ // the daemon process; tasks.json is the shared state and the daemon
12
+ // watches it for changes (see scheduler.ts).
13
+ import cron from 'node-cron';
14
+ import { addTask, listTasks, removeTask, getTask, setEnabled } from './taskStore.js';
15
+ import { humanToCron } from './humanCron.js';
16
+ import { humanToOnceMs } from './humanOnce.js';
17
+ import { fireTask, resolveYomeBinPath } from './triggers/cron.js';
18
+ import { listRunsForTask, readRunLog } from './log.js';
19
+ import { readPidIfRunning } from './scheduler.js';
20
+ import { execSync } from 'child_process';
21
+ import { checkCalendarAccess } from './calendarPermission.js';
22
+ export async function runCronSubcommand(args, flags) {
23
+ const sub = args[0];
24
+ switch (sub) {
25
+ case 'add': return doAdd(args.slice(1), flags);
26
+ case 'list':
27
+ case 'ls': return doList(flags);
28
+ case 'rm':
29
+ case 'remove': return doRm(args.slice(1));
30
+ case 'enable': return doToggle(args.slice(1), true);
31
+ case 'disable': return doToggle(args.slice(1), false);
32
+ case 'run': return doRun(args.slice(1));
33
+ case 'logs': return doLogs(args.slice(1), flags);
34
+ case undefined:
35
+ case 'help':
36
+ case '--help':
37
+ printHelp();
38
+ return 0;
39
+ default:
40
+ console.error(`Unknown subcommand: yome cron ${sub}`);
41
+ printHelp();
42
+ return 2;
43
+ }
44
+ }
45
+ function printHelp() {
46
+ console.log(`Usage: yome cron <subcommand>
47
+
48
+ add "<prompt>" Add a task. Pick exactly one trigger:
49
+ --at "<crontab>" cron schedule, e.g. "0 18 * * *"
50
+ --human "<phrase>" friendly: "9:00", "every 5 min", "mon 9:00"
51
+ --once "<time>" one-shot: "in 5 minutes",
52
+ "tomorrow 9:00", "2026-04-30 18:00", ISO 8601
53
+ --on file:<event> --path "<glob>"
54
+ fire on file events. <event> ∈
55
+ change (add+change, default),
56
+ any (add+change+unlink),
57
+ add, unlink
58
+ Glob: "~/Desktop/test/**/*.xlsx"
59
+ --on calendar:<event> fire on macOS Calendar events. <event> ∈
60
+ event-start (default), event-end, event-added
61
+ Filters (calendar only):
62
+ --within "10m" lead time before start
63
+ --title-regex "^Standup" case-insensitive title match
64
+ --calendar "Work" calendar display name (substring)
65
+ Optional:
66
+ --tz <iana> timezone (default: system local; cron only)
67
+ --cwd <dir> working dir for the task
68
+ --allow <rules> comma-separated allowlist, e.g. "Read,Write,Yome(@yome/fs:*)"
69
+ --deny <rules> comma-separated denylist
70
+ --max-ms <ms> wall-time cap (default 300000)
71
+ list / ls List tasks
72
+ rm <id> Remove a task
73
+ enable <id> Re-enable a paused task
74
+ disable <id> Pause a task without deleting it
75
+ run <id> Fire a task immediately (out-of-process)
76
+ logs <id> [-f] Show audit logs for a task
77
+ -f / --follow follow the latest run
78
+
79
+ Tip: edits to tasks.json take effect immediately — the daemon watches
80
+ the file. You don't need to restart the daemon after add/rm/enable.`);
81
+ }
82
+ function doAdd(args, flags) {
83
+ const prompt = args[0];
84
+ if (!prompt) {
85
+ console.error('Usage: yome cron add "<prompt>" <--at|--human|--once|--on ...>');
86
+ return 2;
87
+ }
88
+ // Exactly one trigger type must be specified.
89
+ const triggerSpecified = [flags.at, flags.human, flags.once, flags.on].filter(Boolean).length;
90
+ if (triggerSpecified === 0) {
91
+ console.error('Must specify a trigger: --at, --human, --once, or --on');
92
+ return 2;
93
+ }
94
+ if (triggerSpecified > 1) {
95
+ console.error('Specify exactly ONE trigger (--at / --human / --once / --on)');
96
+ return 2;
97
+ }
98
+ let trigger;
99
+ let summary;
100
+ try {
101
+ if (flags.at || flags.human) {
102
+ let schedule;
103
+ if (flags.at) {
104
+ if (!cron.validate(flags.at))
105
+ throw new Error(`Invalid crontab: '${flags.at}'`);
106
+ schedule = flags.at;
107
+ }
108
+ else {
109
+ schedule = humanToCron(flags.human);
110
+ }
111
+ trigger = { kind: 'cron', schedule, ...(flags.tz ? { tz: flags.tz } : {}) };
112
+ summary = `cron "${schedule}"${flags.tz ? ` tz=${flags.tz}` : ''}`;
113
+ }
114
+ else if (flags.once) {
115
+ const atMs = humanToOnceMs(flags.once);
116
+ trigger = { kind: 'once', atMs };
117
+ summary = `once @ ${new Date(atMs).toISOString()}`;
118
+ }
119
+ else if (flags.on) {
120
+ // file:change → add+change (any mutation that creates/updates content)
121
+ // file:any → add+change+unlink
122
+ // file:add → just creates
123
+ // file:unlink → just deletions
124
+ // calendar:event-start | event-end | event-added (each via Swift helper)
125
+ const [domain, event] = flags.on.split(':');
126
+ if (domain === 'file') {
127
+ if (!flags.path)
128
+ throw new Error('--on file:* requires --path "<glob>"');
129
+ const events = mapFileEvent(event ?? 'change');
130
+ trigger = { kind: 'file', path: flags.path, events };
131
+ summary = `file ${event ?? 'change'} on ${flags.path}`;
132
+ }
133
+ else if (domain === 'calendar') {
134
+ const ev = (event ?? 'event-start');
135
+ if (ev !== 'event-start' && ev !== 'event-end' && ev !== 'event-added') {
136
+ throw new Error(`unknown calendar event: ${ev} (use event-start | event-end | event-added)`);
137
+ }
138
+ // Pre-flight permission probe so the user gets immediate feedback
139
+ // instead of "task added but never fires". Mirrors option C in the
140
+ // PR4 plan (helper also re-checks at watcher startup).
141
+ const access = checkCalendarAccess();
142
+ if (!access.ok) {
143
+ let msg = `cannot add calendar trigger: ${access.message}`;
144
+ if (access.fix)
145
+ msg += `\n → ${access.fix}`;
146
+ throw new Error(msg);
147
+ }
148
+ const leadMs = flags.within ? parseDurationMs(flags.within) : 0;
149
+ trigger = {
150
+ kind: 'calendar',
151
+ events: [ev],
152
+ ...(leadMs ? { leadMs } : {}),
153
+ ...(flags.titleRegex ? { titleRegex: flags.titleRegex } : {}),
154
+ ...(flags.calendar ? { calendar: flags.calendar } : {}),
155
+ };
156
+ const filterDesc = [
157
+ flags.titleRegex ? `title=/${flags.titleRegex}/i` : '',
158
+ flags.calendar ? `cal="${flags.calendar}"` : '',
159
+ leadMs ? `lead=${flags.within}` : '',
160
+ ].filter(Boolean).join(' ');
161
+ summary = `calendar ${ev}${filterDesc ? ` ${filterDesc}` : ''}`;
162
+ }
163
+ else {
164
+ throw new Error(`unknown --on event: ${flags.on}`);
165
+ }
166
+ }
167
+ else {
168
+ throw new Error('unreachable');
169
+ }
170
+ }
171
+ catch (e) {
172
+ console.error(`✗ ${e?.message ?? e}`);
173
+ return 2;
174
+ }
175
+ const t = addTask({
176
+ trigger,
177
+ prompt,
178
+ cwd: flags.cwd,
179
+ autoAllow: parseRuleList(flags.allow),
180
+ autoDeny: parseRuleList(flags.deny),
181
+ maxDurationMs: flags.maxMs ? Number.parseInt(flags.maxMs, 10) : undefined,
182
+ env: parseEnvList(flags.env),
183
+ });
184
+ console.log(`✓ added ${t.id}`);
185
+ console.log(` trigger: ${summary}`);
186
+ console.log(` prompt: ${prompt.length > 80 ? prompt.slice(0, 80) + '…' : prompt}`);
187
+ if (t.autoAllow?.length)
188
+ console.log(` autoAllow: ${t.autoAllow.join(', ')}`);
189
+ if (t.autoDeny?.length)
190
+ console.log(` autoDeny: ${t.autoDeny.join(', ')}`);
191
+ if (!readPidIfRunning()) {
192
+ console.log('');
193
+ console.log('⚠️ Daemon is not running. Start it with: yome daemon start');
194
+ }
195
+ return 0;
196
+ }
197
+ function parseRuleList(s) {
198
+ if (!s)
199
+ return undefined;
200
+ // meow with isMultiple gives us an array; the manual case (single
201
+ // --allow "a,b,c") gives us a string. Normalise both into a flat
202
+ // array of comma-trimmed rule names.
203
+ const parts = Array.isArray(s) ? s : [s];
204
+ const out = parts.flatMap((p) => p.split(',').map((x) => x.trim()).filter(Boolean));
205
+ return out.length === 0 ? undefined : out;
206
+ }
207
+ /**
208
+ * Parse repeated --env KEY=VAL flags (or a single comma-separated string)
209
+ * into a flat { KEY: VAL } record. Quoted values aren't unescaped — pass
210
+ * them via shell quoting at the call site.
211
+ */
212
+ function parseEnvList(s) {
213
+ if (!s)
214
+ return undefined;
215
+ const parts = Array.isArray(s) ? s : [s];
216
+ const out = {};
217
+ for (const p of parts) {
218
+ for (const kv of p.split(',')) {
219
+ const eq = kv.indexOf('=');
220
+ if (eq <= 0)
221
+ continue;
222
+ const k = kv.slice(0, eq).trim();
223
+ const v = kv.slice(eq + 1).trim();
224
+ if (k)
225
+ out[k] = v;
226
+ }
227
+ }
228
+ return Object.keys(out).length === 0 ? undefined : out;
229
+ }
230
+ /**
231
+ * Parse a friendly duration string into milliseconds.
232
+ * "30s" → 30000 "10m" → 600000 "2h" → 7200000 "500ms" → 500
233
+ * bare number → milliseconds.
234
+ */
235
+ function parseDurationMs(s) {
236
+ const m = /^(\d+(?:\.\d+)?)\s*(ms|s|m|h)?$/i.exec(s.trim());
237
+ if (!m)
238
+ throw new Error(`invalid duration: ${JSON.stringify(s)} (use e.g. "30s", "10m", "2h")`);
239
+ const n = Number(m[1]);
240
+ const unit = (m[2] ?? 'ms').toLowerCase();
241
+ switch (unit) {
242
+ case 'ms': return Math.round(n);
243
+ case 's': return Math.round(n * 1000);
244
+ case 'm': return Math.round(n * 60_000);
245
+ case 'h': return Math.round(n * 3_600_000);
246
+ default: return Math.round(n);
247
+ }
248
+ }
249
+ /**
250
+ * Map a user-friendly file event token into chokidar event names.
251
+ *
252
+ * Most users typing `--on file:change` mean "any time these files are
253
+ * created, edited, or deleted" rather than chokidar's strict "change =
254
+ * existing file content modified, distinct from add/unlink". We pick a
255
+ * sensible default and let power users be explicit.
256
+ */
257
+ function mapFileEvent(token) {
258
+ switch (token.toLowerCase()) {
259
+ case 'change': return ['add', 'change'];
260
+ case 'any':
261
+ case '*': return ['add', 'change', 'unlink'];
262
+ case 'add': return ['add'];
263
+ case 'unlink':
264
+ case 'delete': return ['unlink'];
265
+ default:
266
+ throw new Error(`unknown file event: '${token}' (try change | add | unlink | any)`);
267
+ }
268
+ }
269
+ function doList(flags) {
270
+ const tasks = listTasks();
271
+ if (flags.json) {
272
+ process.stdout.write(JSON.stringify(tasks, null, 2) + '\n');
273
+ return 0;
274
+ }
275
+ if (tasks.length === 0) {
276
+ console.log('(no tasks defined — use `yome cron add ...`)');
277
+ return 0;
278
+ }
279
+ const idW = Math.max(2, ...tasks.map((t) => t.id.length));
280
+ const schedW = Math.max(8, ...tasks.map((t) => trigSummary(t.trigger).length));
281
+ const pad = (s, w) => s + ' '.repeat(Math.max(0, w - s.length));
282
+ console.log(` ${pad('ID', idW)} ${pad('SCHEDULE', schedW)} STATE LAST-RUN PROMPT`);
283
+ for (const t of tasks) {
284
+ const state = t.enabled ? 'on ' : 'off';
285
+ const last = t.lastRun
286
+ ? new Date(t.lastRun.ts).toISOString().replace('T', ' ').slice(0, 19) + (t.lastRun.ok ? ' ok' : ' err')
287
+ : '—';
288
+ const prompt = t.prompt.length > 60 ? t.prompt.slice(0, 60) + '…' : t.prompt;
289
+ console.log(` ${pad(t.id, idW)} ${pad(trigSummary(t.trigger), schedW)} ${state} ${pad(last, 22)} ${prompt}`);
290
+ }
291
+ if (!readPidIfRunning() && tasks.some((t) => t.enabled)) {
292
+ console.log('');
293
+ console.log('⚠️ Daemon is not running — enabled tasks will not fire. Start with: yome daemon start');
294
+ }
295
+ return 0;
296
+ }
297
+ function trigSummary(trig) {
298
+ if (trig?.kind === 'cron')
299
+ return trig.schedule;
300
+ if (trig?.kind === 'once')
301
+ return `once @ ${new Date(trig.atMs).toISOString().slice(0, 16)}`;
302
+ if (trig?.kind === 'file')
303
+ return `file:${trig.path}`;
304
+ if (trig?.kind === 'calendar') {
305
+ const ev = (trig.events ?? ['event-start']).join(',');
306
+ const bits = [`cal:${ev}`];
307
+ if (trig.leadMs)
308
+ bits.push(`-${Math.round(trig.leadMs / 1000)}s`);
309
+ if (trig.titleRegex)
310
+ bits.push(`/${trig.titleRegex}/`);
311
+ if (trig.calendar)
312
+ bits.push(`@${trig.calendar}`);
313
+ return bits.join(' ');
314
+ }
315
+ return '?';
316
+ }
317
+ function doRm(args) {
318
+ const id = args[0];
319
+ if (!id) {
320
+ console.error('Usage: yome cron rm <id>');
321
+ return 2;
322
+ }
323
+ if (!removeTask(id)) {
324
+ console.error(`✗ no such task: ${id}`);
325
+ return 1;
326
+ }
327
+ console.log(`✓ removed ${id}`);
328
+ return 0;
329
+ }
330
+ function doToggle(args, enabled) {
331
+ const id = args[0];
332
+ if (!id) {
333
+ console.error(`Usage: yome cron ${enabled ? 'enable' : 'disable'} <id>`);
334
+ return 2;
335
+ }
336
+ if (!setEnabled(id, enabled)) {
337
+ console.error(`✗ no such task: ${id}`);
338
+ return 1;
339
+ }
340
+ console.log(`✓ ${enabled ? 'enabled' : 'disabled'} ${id}`);
341
+ return 0;
342
+ }
343
+ function doRun(args) {
344
+ const id = args[0];
345
+ if (!id) {
346
+ console.error('Usage: yome cron run <id>');
347
+ return 2;
348
+ }
349
+ const t = getTask(id);
350
+ if (!t) {
351
+ console.error(`✗ no such task: ${id}`);
352
+ return 1;
353
+ }
354
+ // Spawn out-of-process via the same path the scheduler uses, so behaviour
355
+ // (stdout capture, kill timer, jsonl logging) matches a scheduled fire.
356
+ console.log(`→ firing ${id} now (out-of-process)…`);
357
+ fireTask(id, resolveYomeBinPath(), t);
358
+ console.log(`✓ task spawned. Watch logs with: yome cron logs ${id} -f`);
359
+ return 0;
360
+ }
361
+ function doLogs(args, flags) {
362
+ const id = args[0];
363
+ if (!id) {
364
+ console.error('Usage: yome cron logs <id> [-f]');
365
+ return 2;
366
+ }
367
+ const runs = listRunsForTask(id);
368
+ if (runs.length === 0) {
369
+ console.log(`(no runs recorded for ${id} yet)`);
370
+ return 0;
371
+ }
372
+ const latest = runs[0];
373
+ if (flags.follow) {
374
+ try {
375
+ execSync(`tail -F "${latest.file}"`, { stdio: 'inherit' });
376
+ }
377
+ catch { /* user terminated tail */ }
378
+ return 0;
379
+ }
380
+ console.log(`── latest run: ${new Date(latest.runTs).toISOString()} (${latest.file}) ──`);
381
+ for (const e of readRunLog(latest.file)) {
382
+ const t = new Date(e.ts).toISOString().slice(11, 19);
383
+ if (e.type === 'tool_use') {
384
+ console.log(`[${t}] tool ${e.name} ${JSON.stringify(e.input).slice(0, 120)}`);
385
+ }
386
+ else if (e.type === 'tool_result') {
387
+ const r = String(e.result ?? '').replace(/\n/g, ' ').slice(0, 120);
388
+ console.log(`[${t}] └─ ${r}`);
389
+ }
390
+ else if (e.type === 'run_start' || e.type === 'run_end') {
391
+ console.log(`[${t}] ${e.type} ${JSON.stringify({ ok: e.ok, durationMs: e.durationMs, error: e.error }).slice(0, 200)}`);
392
+ }
393
+ else {
394
+ console.log(`[${t}] ${e.type} ${JSON.stringify(e).slice(0, 200)}`);
395
+ }
396
+ }
397
+ if (runs.length > 1) {
398
+ console.log('');
399
+ console.log(`(${runs.length - 1} earlier run(s) in ${latest.file.replace(/\/[^/]+$/, '')})`);
400
+ }
401
+ return 0;
402
+ }
403
+ //# sourceMappingURL=cronCli.js.map