@hopper-agent/core 0.1.1

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 (55) hide show
  1. package/LICENSE +179 -0
  2. package/dist/.tsbuildinfo +1 -0
  3. package/dist/src/channel-registry.d.ts +26 -0
  4. package/dist/src/channel-registry.d.ts.map +1 -0
  5. package/dist/src/channel-registry.js +100 -0
  6. package/dist/src/channel-registry.js.map +1 -0
  7. package/dist/src/channel-router.d.ts +28 -0
  8. package/dist/src/channel-router.d.ts.map +1 -0
  9. package/dist/src/channel-router.js +52 -0
  10. package/dist/src/channel-router.js.map +1 -0
  11. package/dist/src/cron-manager.d.ts +70 -0
  12. package/dist/src/cron-manager.d.ts.map +1 -0
  13. package/dist/src/cron-manager.js +301 -0
  14. package/dist/src/cron-manager.js.map +1 -0
  15. package/dist/src/event-bus.d.ts +99 -0
  16. package/dist/src/event-bus.d.ts.map +1 -0
  17. package/dist/src/event-bus.js +56 -0
  18. package/dist/src/event-bus.js.map +1 -0
  19. package/dist/src/heartbeat-delivery.d.ts +27 -0
  20. package/dist/src/heartbeat-delivery.d.ts.map +1 -0
  21. package/dist/src/heartbeat-delivery.js +37 -0
  22. package/dist/src/heartbeat-delivery.js.map +1 -0
  23. package/dist/src/heartbeat-executor.d.ts +35 -0
  24. package/dist/src/heartbeat-executor.d.ts.map +1 -0
  25. package/dist/src/heartbeat-executor.js +174 -0
  26. package/dist/src/heartbeat-executor.js.map +1 -0
  27. package/dist/src/index.d.ts +26 -0
  28. package/dist/src/index.d.ts.map +1 -0
  29. package/dist/src/index.js +15 -0
  30. package/dist/src/index.js.map +1 -0
  31. package/dist/src/permission.d.ts +21 -0
  32. package/dist/src/permission.d.ts.map +1 -0
  33. package/dist/src/permission.js +69 -0
  34. package/dist/src/permission.js.map +1 -0
  35. package/dist/src/reminder-parser.d.ts +12 -0
  36. package/dist/src/reminder-parser.d.ts.map +1 -0
  37. package/dist/src/reminder-parser.js +164 -0
  38. package/dist/src/reminder-parser.js.map +1 -0
  39. package/dist/src/session-store.d.ts +32 -0
  40. package/dist/src/session-store.d.ts.map +1 -0
  41. package/dist/src/session-store.js +112 -0
  42. package/dist/src/session-store.js.map +1 -0
  43. package/dist/src/settings.d.ts +41 -0
  44. package/dist/src/settings.d.ts.map +1 -0
  45. package/dist/src/settings.js +128 -0
  46. package/dist/src/settings.js.map +1 -0
  47. package/dist/src/telegram-gateway.d.ts +35 -0
  48. package/dist/src/telegram-gateway.d.ts.map +1 -0
  49. package/dist/src/telegram-gateway.js +145 -0
  50. package/dist/src/telegram-gateway.js.map +1 -0
  51. package/dist/src/turn-loop.d.ts +106 -0
  52. package/dist/src/turn-loop.d.ts.map +1 -0
  53. package/dist/src/turn-loop.js +288 -0
  54. package/dist/src/turn-loop.js.map +1 -0
  55. package/package.json +33 -0
@@ -0,0 +1,174 @@
1
+ import { homedir } from 'node:os';
2
+ import { join } from 'node:path';
3
+ import { readFileSync, existsSync } from 'node:fs';
4
+ import { TurnLoop } from './turn-loop.js';
5
+ /**
6
+ * Wraps TurnLoop with yolo (auto-approve) mode and collects
7
+ * text output, tool call count, and errors via EventBus subscriptions.
8
+ */
9
+ class BatchTurnLoop {
10
+ turnLoop;
11
+ collectedText = '';
12
+ toolCallCount = 0;
13
+ errors = [];
14
+ constructor(config) {
15
+ this.turnLoop = new TurnLoop({
16
+ provider: config.provider,
17
+ model: config.model,
18
+ tools: config.tools,
19
+ cwd: config.cwd,
20
+ settings: config.settings,
21
+ approvalMode: 'yolo',
22
+ effort: config.effort,
23
+ maxTurns: config.maxTurns,
24
+ system: config.system,
25
+ });
26
+ }
27
+ async run(prompt) {
28
+ const unsubs = [
29
+ this.turnLoop.eventBus.subscribe('assistant-delta', (e) => {
30
+ if (e.type === 'assistant-delta')
31
+ this.collectedText += e.text;
32
+ }),
33
+ this.turnLoop.eventBus.subscribe('tool-call', (e) => {
34
+ if (e.type === 'tool-call')
35
+ this.toolCallCount++;
36
+ }),
37
+ this.turnLoop.eventBus.subscribe('error', (e) => {
38
+ if (e.type === 'error')
39
+ this.errors.push(e.message);
40
+ }),
41
+ ];
42
+ const result = await this.turnLoop.run(prompt);
43
+ unsubs.forEach((u) => u());
44
+ return {
45
+ text: this.collectedText,
46
+ toolCalls: this.toolCallCount,
47
+ sessionId: result.sessionId,
48
+ reason: result.reason,
49
+ errors: this.errors,
50
+ };
51
+ }
52
+ }
53
+ /**
54
+ * Default heartbeat protocol — used when ~/.hopper-agent/HEARTBEAT.md
55
+ * does not exist.
56
+ */
57
+ const DEFAULT_HEARTBEAT_PROTOCOL = `# HEARTBEAT.md
58
+ AI AGENT INSTRUCTIONS: This file dictates your periodic proactive routine. Execute the following protocol sequentially.
59
+
60
+ ## Data Ingestion & State Check
61
+ Scan and load the current state of:
62
+ - TODO.md: Parse active tasks
63
+ - Short-Term Memory: Ingest recent daily logs from ~/.hopper-agent/memory/
64
+
65
+ ## Synthesis & Insight Generation
66
+ Cross-reference ingested data to formulate proactive insights (1-3 concise, actionable observations).
67
+
68
+ ## Execution & System Updates
69
+ - Consolidate MEMORY.md: Extract core developments from recent daily logs
70
+ - Stage TODOs: New obligations from daily logs as appropriately prioritized tasks
71
+
72
+ ## User Output (The Heartbeat Brief)
73
+ Generate a strictly formatted status report:
74
+ - Insights: [Brief bullet points]
75
+ - Proposed Actions: [Tasks ready to be added to TODO.md]
76
+ - System Status: [Confirmation of updates]`;
77
+ export class HeartbeatExecutor {
78
+ config;
79
+ heartbeatDir;
80
+ constructor(config) {
81
+ this.config = config;
82
+ this.heartbeatDir = join(homedir(), '.hopper-agent');
83
+ }
84
+ async execute() {
85
+ // 1. Read HEARTBEAT.md instructions
86
+ const heartbeatProtocol = this.readHeartbeatMd();
87
+ // 2. Gather context
88
+ const context = await this.gatherContext();
89
+ // 3. Build prompt with schedule-type header
90
+ const prompt = this.buildPrompt(heartbeatProtocol, context, this.config.scheduleType);
91
+ // 4. Run batch turn loop
92
+ const batchResult = await new BatchTurnLoop({
93
+ provider: this.config.provider,
94
+ model: this.config.model,
95
+ tools: this.config.tools,
96
+ cwd: this.config.cwd,
97
+ settings: this.config.settings,
98
+ effort: this.config.effort,
99
+ maxTurns: this.config.maxTurns ?? 30,
100
+ system: `You are running a Heartbeat cycle. Follow the instructions in the prompt carefully. Use tools to gather data, analyze, and produce the final Heartbeat Brief.`,
101
+ }).run(prompt);
102
+ return {
103
+ sessionId: batchResult.sessionId,
104
+ text: batchResult.text,
105
+ toolCalls: batchResult.toolCalls,
106
+ usage: { inputTokens: 0, outputTokens: 0 },
107
+ errors: batchResult.errors,
108
+ };
109
+ }
110
+ readHeartbeatMd() {
111
+ const path = join(this.heartbeatDir, 'HEARTBEAT.md');
112
+ if (existsSync(path)) {
113
+ return readFileSync(path, 'utf-8');
114
+ }
115
+ return DEFAULT_HEARTBEAT_PROTOCOL;
116
+ }
117
+ async gatherContext() {
118
+ const sections = [];
119
+ // Gather MEMORY.md
120
+ const memoryPath = join(this.heartbeatDir, 'MEMORY.md');
121
+ if (existsSync(memoryPath)) {
122
+ sections.push('=== MEMORY.md ===\n' + readFileSync(memoryPath, 'utf-8'));
123
+ }
124
+ // Gather USER.md
125
+ const userPath = join(this.heartbeatDir, 'USER.md');
126
+ if (existsSync(userPath)) {
127
+ sections.push('=== USER.md ===\n' + readFileSync(userPath, 'utf-8'));
128
+ }
129
+ // Gather AGENTS.md
130
+ const agentsPath = join(this.heartbeatDir, 'AGENTS.md');
131
+ if (existsSync(agentsPath)) {
132
+ sections.push('=== AGENTS.md ===\n' + readFileSync(agentsPath, 'utf-8'));
133
+ }
134
+ // Gather TODO.md from cwd
135
+ const todoPath = join(this.config.cwd, 'TODO.md');
136
+ if (existsSync(todoPath)) {
137
+ sections.push('=== TODO.md ===\n' + readFileSync(todoPath, 'utf-8'));
138
+ }
139
+ // Gather daily memory logs (last 3)
140
+ const memoryDir = join(this.heartbeatDir, 'memory');
141
+ if (existsSync(memoryDir)) {
142
+ sections.push(`=== Memory Directory ===\nDirectory: ${memoryDir} — the agent should glob for recent daily log files`);
143
+ }
144
+ return sections.join('\n\n');
145
+ }
146
+ buildPrompt(protocol, context, scheduleType) {
147
+ const scheduleHint = scheduleType
148
+ ? `Execute the **${scheduleType}** section of the HEARTBEAT protocol.\n`
149
+ : '';
150
+ const now = new Date().toLocaleString('en-US', {
151
+ weekday: 'long',
152
+ year: 'numeric',
153
+ month: 'long',
154
+ day: 'numeric',
155
+ hour: '2-digit',
156
+ minute: '2-digit',
157
+ second: '2-digit',
158
+ hour12: false,
159
+ });
160
+ return [
161
+ '=== HEARTBEAT PROTOCOL ===',
162
+ protocol,
163
+ '',
164
+ '=== GATHERED CONTEXT ===',
165
+ context,
166
+ '',
167
+ '=== CURRENT TIME ===',
168
+ now,
169
+ '',
170
+ `${scheduleHint}Please now execute the Heartbeat protocol using the gathered context. Produce the final Heartbeat Brief as specified in the protocol.`,
171
+ ].join('\n');
172
+ }
173
+ }
174
+ //# sourceMappingURL=heartbeat-executor.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"heartbeat-executor.js","sourceRoot":"","sources":["../../src/heartbeat-executor.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,26 @@
1
+ export { EventBus } from './event-bus.js';
2
+ export type { Event, EventType } from './event-bus.js';
3
+ export { SessionStore, ulid } from './session-store.js';
4
+ export type { SessionInfo, SessionFile } from './session-store.js';
5
+ export { PermissionEngine } from './permission.js';
6
+ export type { ApprovalMode, PermissionRule, PermissionResult, PermissionDecision } from './permission.js';
7
+ export { TurnLoop } from './turn-loop.js';
8
+ export type { TurnLoopConfig, TurnLoopResult, ReasoningEffort } from './turn-loop.js';
9
+ export { SettingsManager } from './settings.js';
10
+ export type { HopperSettings } from './settings.js';
11
+ export { DEFAULT_SETTINGS } from './settings.js';
12
+ export { CronManager } from './cron-manager.js';
13
+ export { parseReminderTime } from './reminder-parser.js';
14
+ export { TelegramGateway } from './telegram-gateway.js';
15
+ export type { TelegramMessageContext } from './telegram-gateway.js';
16
+ export { ChannelRegistry } from './channel-registry.js';
17
+ export type { ChannelEntry, ChannelType } from './channel-registry.js';
18
+ export { ChannelRouter } from './channel-router.js';
19
+ export type { RouteResult } from './channel-router.js';
20
+ export { HeartbeatExecutor } from './heartbeat-executor.js';
21
+ export type { HeartbeatExecutorConfig, HeartbeatResult } from './heartbeat-executor.js';
22
+ export type { ScheduleType, CronTask } from './cron-manager.js';
23
+ export { pickNextSchedule, scheduleLabel } from './cron-manager.js';
24
+ export { HeartbeatDelivery } from './heartbeat-delivery.js';
25
+ export type { HeartbeatDeliveryConfig } from './heartbeat-delivery.js';
26
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAC;AAC1C,YAAY,EAAE,KAAK,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AACvD,OAAO,EAAE,YAAY,EAAE,IAAI,EAAE,MAAM,oBAAoB,CAAC;AACxD,YAAY,EAAE,WAAW,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AACnE,OAAO,EAAE,gBAAgB,EAAE,MAAM,iBAAiB,CAAC;AACnD,YAAY,EAAE,YAAY,EAAE,cAAc,EAAE,gBAAgB,EAAE,kBAAkB,EAAE,MAAM,iBAAiB,CAAC;AAC1G,OAAO,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAC;AAC1C,YAAY,EAAE,cAAc,EAAE,cAAc,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAC;AACtF,OAAO,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC;AAChD,YAAY,EAAE,cAAc,EAAE,MAAM,eAAe,CAAC;AACpD,OAAO,EAAE,gBAAgB,EAAE,MAAM,eAAe,CAAC;AACjD,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAChD,OAAO,EAAE,iBAAiB,EAAE,MAAM,sBAAsB,CAAC;AACzD,OAAO,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AACxD,YAAY,EAAE,sBAAsB,EAAE,MAAM,uBAAuB,CAAC;AACpE,OAAO,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AACxD,YAAY,EAAE,YAAY,EAAE,WAAW,EAAE,MAAM,uBAAuB,CAAC;AACvE,OAAO,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AACpD,YAAY,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC;AACvD,OAAO,EAAE,iBAAiB,EAAE,MAAM,yBAAyB,CAAC;AAC5D,YAAY,EAAE,uBAAuB,EAAE,eAAe,EAAE,MAAM,yBAAyB,CAAC;AACxF,YAAY,EAAE,YAAY,EAAE,QAAQ,EAAE,MAAM,mBAAmB,CAAC;AAChE,OAAO,EAAE,gBAAgB,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAC;AACpE,OAAO,EAAE,iBAAiB,EAAE,MAAM,yBAAyB,CAAC;AAC5D,YAAY,EAAE,uBAAuB,EAAE,MAAM,yBAAyB,CAAC"}
@@ -0,0 +1,15 @@
1
+ export { EventBus } from './event-bus.js';
2
+ export { SessionStore, ulid } from './session-store.js';
3
+ export { PermissionEngine } from './permission.js';
4
+ export { TurnLoop } from './turn-loop.js';
5
+ export { SettingsManager } from './settings.js';
6
+ export { DEFAULT_SETTINGS } from './settings.js';
7
+ export { CronManager } from './cron-manager.js';
8
+ export { parseReminderTime } from './reminder-parser.js';
9
+ export { TelegramGateway } from './telegram-gateway.js';
10
+ export { ChannelRegistry } from './channel-registry.js';
11
+ export { ChannelRouter } from './channel-router.js';
12
+ export { HeartbeatExecutor } from './heartbeat-executor.js';
13
+ export { pickNextSchedule, scheduleLabel } from './cron-manager.js';
14
+ export { HeartbeatDelivery } from './heartbeat-delivery.js';
15
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAC;AAE1C,OAAO,EAAE,YAAY,EAAE,IAAI,EAAE,MAAM,oBAAoB,CAAC;AAExD,OAAO,EAAE,gBAAgB,EAAE,MAAM,iBAAiB,CAAC;AAEnD,OAAO,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAC;AAE1C,OAAO,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC;AAEhD,OAAO,EAAE,gBAAgB,EAAE,MAAM,eAAe,CAAC;AACjD,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAChD,OAAO,EAAE,iBAAiB,EAAE,MAAM,sBAAsB,CAAC;AACzD,OAAO,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AAExD,OAAO,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AAExD,OAAO,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AAEpD,OAAO,EAAE,iBAAiB,EAAE,MAAM,yBAAyB,CAAC;AAG5D,OAAO,EAAE,gBAAgB,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAC;AACpE,OAAO,EAAE,iBAAiB,EAAE,MAAM,yBAAyB,CAAC"}
@@ -0,0 +1,21 @@
1
+ export type ApprovalMode = 'plan' | 'edit' | 'auto' | 'yolo';
2
+ export type PermissionDecision = 'allow' | 'deny' | 'ask';
3
+ export interface PermissionRule {
4
+ allow?: string[];
5
+ ask?: string[];
6
+ deny?: string[];
7
+ }
8
+ export interface PermissionResult {
9
+ decision: PermissionDecision;
10
+ reason: string;
11
+ }
12
+ export declare class PermissionEngine {
13
+ private rules;
14
+ private _mode;
15
+ constructor(rules?: PermissionRule, mode?: ApprovalMode);
16
+ get mode(): ApprovalMode;
17
+ check(toolName: string, input?: Record<string, unknown>): PermissionResult;
18
+ private isPlanFileWrite;
19
+ private buildToolPattern;
20
+ }
21
+ //# sourceMappingURL=permission.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"permission.d.ts","sourceRoot":"","sources":["../../src/permission.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,YAAY,GAAG,MAAM,GAAG,MAAM,GAAG,MAAM,GAAG,MAAM,CAAC;AAI7D,MAAM,MAAM,kBAAkB,GAAG,OAAO,GAAG,MAAM,GAAG,KAAK,CAAC;AAE1D,MAAM,WAAW,cAAc;IAC7B,KAAK,CAAC,EAAE,MAAM,EAAE,CAAC;IACjB,GAAG,CAAC,EAAE,MAAM,EAAE,CAAC;IACf,IAAI,CAAC,EAAE,MAAM,EAAE,CAAC;CACjB;AAED,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,EAAE,kBAAkB,CAAC;IAC7B,MAAM,EAAE,MAAM,CAAC;CAChB;AASD,qBAAa,gBAAgB;IAC3B,OAAO,CAAC,KAAK,CAAiB;IAC9B,OAAO,CAAC,KAAK,CAAe;gBAEhB,KAAK,GAAE,cAAmB,EAAE,IAAI,GAAE,YAAqB;IAKnE,IAAI,IAAI,IAAI,YAAY,CAEvB;IAED,KAAK,CAAC,QAAQ,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,gBAAgB;IAwC1E,OAAO,CAAC,eAAe;IAQvB,OAAO,CAAC,gBAAgB;CAMzB"}
@@ -0,0 +1,69 @@
1
+ // Tools that only inspect state; safe to allow in plan mode.
2
+ const READ_ONLY_TOOLS = new Set(['Read', 'Glob', 'Grep', 'WebFetch', 'WebSearch']);
3
+ function globMatch(pattern, str) {
4
+ const regex = pattern
5
+ .replace(/[.+?^${}()|[\]\\]/g, '\\$&')
6
+ .replace(/\*/g, '.*');
7
+ return new RegExp(`^${regex}$`).test(str);
8
+ }
9
+ export class PermissionEngine {
10
+ rules;
11
+ _mode;
12
+ constructor(rules = {}, mode = 'auto') {
13
+ this.rules = rules;
14
+ this._mode = mode;
15
+ }
16
+ get mode() {
17
+ return this._mode;
18
+ }
19
+ check(toolName, input) {
20
+ const toolPattern = this.buildToolPattern(toolName, input);
21
+ if (this.rules.deny?.some((p) => globMatch(p, toolPattern))) {
22
+ return { decision: 'deny', reason: `Denied by rule: ${this.rules.deny.find((p) => globMatch(p, toolPattern))}` };
23
+ }
24
+ if (this.rules.allow?.some((p) => globMatch(p, toolPattern))) {
25
+ return { decision: 'allow', reason: `Allowed by rule: ${this.rules.allow.find((p) => globMatch(p, toolPattern))}` };
26
+ }
27
+ if (this.rules.ask?.some((p) => globMatch(p, toolPattern))) {
28
+ return { decision: 'ask', reason: `Ask by rule: ${this.rules.ask.find((p) => globMatch(p, toolPattern))}` };
29
+ }
30
+ switch (this.mode) {
31
+ case 'yolo':
32
+ return { decision: 'allow', reason: 'yolo: unsupervised, all tools auto-approved' };
33
+ case 'auto':
34
+ // Every tool call goes through LLM harm-evaluation.
35
+ return { decision: 'ask', reason: 'auto: LLM harm-evaluation required' };
36
+ case 'edit':
37
+ // Every mutating step asks; reads are always free.
38
+ if (READ_ONLY_TOOLS.has(toolName)) {
39
+ return { decision: 'allow', reason: 'edit: read-only tools allowed' };
40
+ }
41
+ return { decision: 'ask', reason: 'edit: every change requires approval' };
42
+ case 'plan':
43
+ if (READ_ONLY_TOOLS.has(toolName)) {
44
+ return { decision: 'allow', reason: 'plan: read-only tools allowed' };
45
+ }
46
+ if (toolName === 'Write' && this.isPlanFileWrite(input)) {
47
+ return { decision: 'allow', reason: 'plan: writing plan file under plans/' };
48
+ }
49
+ return { decision: 'deny', reason: 'plan: mutations blocked — present a plan instead' };
50
+ default:
51
+ return { decision: 'ask', reason: 'unknown mode: defaulting to ask' };
52
+ }
53
+ }
54
+ isPlanFileWrite(input) {
55
+ const p = typeof input?.['file_path'] === 'string' ? input['file_path'] : '';
56
+ if (!p)
57
+ return false;
58
+ // Match any path whose last directory segment is "plans" (or contains /plans/).
59
+ const normalized = p.replace(/\\/g, '/');
60
+ return /(^|\/)plans\//.test(normalized);
61
+ }
62
+ buildToolPattern(name, input) {
63
+ if (name === 'Bash' && input?.command) {
64
+ return `Bash(${String(input.command)})`;
65
+ }
66
+ return name;
67
+ }
68
+ }
69
+ //# sourceMappingURL=permission.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"permission.js","sourceRoot":"","sources":["../../src/permission.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,12 @@
1
+ /**
2
+ * Zero-dependency natural language time parser for reminders.
3
+ * Parses patterns like "in 30 minutes", "tomorrow at 7am", "today at 19:00",
4
+ * "next monday at 9am", etc.
5
+ */
6
+ interface ParsedReminder {
7
+ message: string;
8
+ scheduledAt: number;
9
+ }
10
+ export declare function parseReminderTime(input: string): ParsedReminder | null;
11
+ export {};
12
+ //# sourceMappingURL=reminder-parser.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"reminder-parser.d.ts","sourceRoot":"","sources":["../../src/reminder-parser.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,UAAU,cAAc;IACtB,OAAO,EAAE,MAAM,CAAC;IAChB,WAAW,EAAE,MAAM,CAAC;CACrB;AA+ED,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,MAAM,GAAG,cAAc,GAAG,IAAI,CAoGtE"}
@@ -0,0 +1,164 @@
1
+ /**
2
+ * Zero-dependency natural language time parser for reminders.
3
+ * Parses patterns like "in 30 minutes", "tomorrow at 7am", "today at 19:00",
4
+ * "next monday at 9am", etc.
5
+ */
6
+ const WEEKDAYS = [
7
+ 'sunday', 'monday', 'tuesday', 'wednesday',
8
+ 'thursday', 'friday', 'saturday',
9
+ ];
10
+ /**
11
+ * Parse a time string like "7:00 am", "19:00", "7am", "7:30PM".
12
+ * Returns hours and minutes, or null if unparseable.
13
+ */
14
+ function parseTimeOfDay(timeStr) {
15
+ const match = timeStr.match(/(\d{1,2}):?(\d{2})?\s*([ap]m)?/i);
16
+ if (!match)
17
+ return null;
18
+ let hours = parseInt(match[1] ?? '0', 10);
19
+ const minutes = match[2] ? parseInt(match[2], 10) : 0;
20
+ const ampm = match[3];
21
+ if (ampm) {
22
+ const isPM = ampm.toLowerCase().startsWith('p');
23
+ if (isPM && hours < 12)
24
+ hours += 12;
25
+ if (!isPM && hours === 12)
26
+ hours = 0;
27
+ }
28
+ return { hours, minutes };
29
+ }
30
+ /**
31
+ * Extract a time-of-day from the beginning of a string, returning the time
32
+ * and the remaining message text. e.g. "7:00 am make breakfast" →
33
+ * { time: {hours:7, minutes:0}, message: "make breakfast" }
34
+ */
35
+ function extractTimeAndMessage(str) {
36
+ const match = str.match(/(\d{1,2}):?(\d{2})?\s*([ap]m)?\s*(.*)/i);
37
+ if (!match)
38
+ return null;
39
+ let hours = parseInt(match[1] ?? '0', 10);
40
+ const minutes = match[2] ? parseInt(match[2], 10) : 0;
41
+ const ampm = match[3];
42
+ const message = (match[4] ?? '').trim();
43
+ if (ampm) {
44
+ const isPM = ampm.toLowerCase().startsWith('p');
45
+ if (isPM && hours < 12)
46
+ hours += 12;
47
+ if (!isPM && hours === 12)
48
+ hours = 0;
49
+ }
50
+ return { time: { hours, minutes }, message };
51
+ }
52
+ /**
53
+ * Apply a time-of-day to a base date, returning a new Date.
54
+ */
55
+ function applyTime(date, hours, minutes) {
56
+ const result = new Date(date);
57
+ result.setHours(hours, minutes, 0, 0);
58
+ return result;
59
+ }
60
+ /**
61
+ * Get the next occurrence of a weekday at a given time, or today if
62
+ * the weekday already passed this week (returns next week).
63
+ */
64
+ function nextWeekday(dayName, baseDate, time) {
65
+ const targetDay = WEEKDAYS.indexOf(dayName.toLowerCase());
66
+ if (targetDay === -1)
67
+ return baseDate;
68
+ const today = baseDate.getDay();
69
+ let diff = targetDay - today;
70
+ if (diff <= 0)
71
+ diff += 7; // always go to next occurrence
72
+ const result = new Date(baseDate);
73
+ result.setDate(result.getDate() + diff);
74
+ return applyTime(result, time.hours, time.minutes);
75
+ }
76
+ export function parseReminderTime(input) {
77
+ const trimmed = input.trim();
78
+ if (!trimmed)
79
+ return null;
80
+ const now = new Date();
81
+ let remaining = trimmed;
82
+ let targetTime = null;
83
+ // Pattern 1: "in X minutes"
84
+ const inMinMatch = remaining.match(/^in\s+(\d+)\s+minutes?/i);
85
+ if (inMinMatch) {
86
+ const mins = parseInt(inMinMatch[1], 10);
87
+ const msg = remaining.slice(inMinMatch[0].length).trim();
88
+ targetTime = new Date(Date.now() + mins * 60_000);
89
+ remaining = msg;
90
+ }
91
+ // Pattern 2: "in X hours"
92
+ const inHourMatch = remaining.match(/^in\s+(\d+)\s+hours?/i);
93
+ if (inHourMatch) {
94
+ const hrs = parseInt(inHourMatch[1], 10);
95
+ const msg = remaining.slice(inHourMatch[0].length).trim();
96
+ targetTime = new Date(Date.now() + hrs * 3_600_000);
97
+ remaining = msg;
98
+ }
99
+ // Pattern 3: "in X days"
100
+ const inDayMatch = remaining.match(/^in\s+(\d+)\s+days?/i);
101
+ if (inDayMatch) {
102
+ const days = parseInt(inDayMatch[1], 10);
103
+ const msg = remaining.slice(inDayMatch[0].length).trim();
104
+ const tomorrow = new Date(now);
105
+ tomorrow.setDate(tomorrow.getDate() + days);
106
+ tomorrow.setHours(0, 0, 0, 0);
107
+ targetTime = tomorrow;
108
+ remaining = msg;
109
+ }
110
+ // Pattern 4: "tomorrow at <time>"
111
+ const tomorrowMatch = remaining.match(/^tomorrow(?:\s+at\s+)?(.+)$/i);
112
+ if (tomorrowMatch) {
113
+ const rest = (tomorrowMatch[1] ?? '').trim();
114
+ const parsed = extractTimeAndMessage(rest);
115
+ if (parsed) {
116
+ const tomorrow = new Date(now);
117
+ tomorrow.setDate(tomorrow.getDate() + 1);
118
+ targetTime = applyTime(tomorrow, parsed.time.hours, parsed.time.minutes);
119
+ remaining = parsed.message;
120
+ }
121
+ }
122
+ // Pattern 5: "today at <time>"
123
+ const todayMatch = remaining.match(/^today(?:\s+at\s+)?(.+)$/i);
124
+ if (todayMatch) {
125
+ const rest = (todayMatch[1] ?? '').trim();
126
+ const parsed = extractTimeAndMessage(rest);
127
+ if (parsed) {
128
+ targetTime = applyTime(now, parsed.time.hours, parsed.time.minutes);
129
+ remaining = parsed.message;
130
+ }
131
+ }
132
+ // Pattern 6: "next <weekday> at <time>"
133
+ const nextDayMatch = remaining.match(/^next\s+(monday|tuesday|wednesday|thursday|friday|saturday|sunday)\s+(?:at\s+)?(.+)$/i);
134
+ if (nextDayMatch) {
135
+ const dayName = (nextDayMatch[1] ?? '').trim();
136
+ const rest = (nextDayMatch[2] ?? '').trim();
137
+ const parsed = extractTimeAndMessage(rest);
138
+ if (parsed) {
139
+ targetTime = nextWeekday(dayName, now, parsed.time);
140
+ remaining = parsed.message;
141
+ }
142
+ }
143
+ // Pattern 7: "at <time>" (standalone — defaults to today)
144
+ const atMatch = remaining.match(/^at\s+(.+)$/i);
145
+ if (atMatch) {
146
+ const rest = (atMatch[1] ?? '').trim();
147
+ const parsed = extractTimeAndMessage(rest);
148
+ if (parsed) {
149
+ targetTime = applyTime(now, parsed.time.hours, parsed.time.minutes);
150
+ remaining = parsed.message;
151
+ }
152
+ }
153
+ // If no time was parsed, default to "in 1 hour"
154
+ if (!targetTime) {
155
+ targetTime = new Date(Date.now() + 3_600_000);
156
+ }
157
+ // Extract message: the part after time keywords
158
+ const message = remaining.trim();
159
+ if (!message) {
160
+ return null;
161
+ }
162
+ return { message, scheduledAt: targetTime.getTime() };
163
+ }
164
+ //# sourceMappingURL=reminder-parser.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"reminder-parser.js","sourceRoot":"","sources":["../../src/reminder-parser.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,32 @@
1
+ import { Event } from './event-bus.js';
2
+ export interface SessionInfo {
3
+ id: string;
4
+ cwd: string;
5
+ model: string;
6
+ provider: string;
7
+ createdAt: number;
8
+ updatedAt: number;
9
+ }
10
+ export interface SessionFile {
11
+ path: string;
12
+ events: string;
13
+ metadata: string;
14
+ }
15
+ export declare function ulid(timestamp?: number): string;
16
+ export declare class SessionStore {
17
+ baseDir: string;
18
+ constructor(baseDir?: string);
19
+ sessionPath(id: string): string;
20
+ eventsPath(id: string): string;
21
+ metadataPath(id: string): string;
22
+ getFiles(id: string): SessionFile;
23
+ create(cwd: string, model: string, provider: string): SessionInfo;
24
+ load(id: string): SessionInfo | undefined;
25
+ loadEvents(id: string): Event[];
26
+ appendEvent(id: string, event: Event): void;
27
+ appendEvents(id: string, events: Event[]): void;
28
+ list(): SessionInfo[];
29
+ remove(id: string): void;
30
+ private touch;
31
+ }
32
+ //# sourceMappingURL=session-store.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"session-store.d.ts","sourceRoot":"","sources":["../../src/session-store.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,KAAK,EAAE,MAAM,gBAAgB,CAAC;AAEvC,MAAM,WAAW,WAAW;IAC1B,EAAE,EAAE,MAAM,CAAC;IACX,GAAG,EAAE,MAAM,CAAC;IACZ,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,WAAW;IAC1B,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC;CAClB;AAID,wBAAgB,IAAI,CAAC,SAAS,CAAC,EAAE,MAAM,GAAG,MAAM,CAoB/C;AAED,qBAAa,YAAY;IACJ,OAAO,EAAE,MAAM;gBAAf,OAAO,GAAE,MAA6D;IAEzF,WAAW,CAAC,EAAE,EAAE,MAAM,GAAG,MAAM;IAI/B,UAAU,CAAC,EAAE,EAAE,MAAM,GAAG,MAAM;IAI9B,YAAY,CAAC,EAAE,EAAE,MAAM,GAAG,MAAM;IAIhC,QAAQ,CAAC,EAAE,EAAE,MAAM,GAAG,WAAW;IAQjC,MAAM,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,WAAW;IAajE,IAAI,CAAC,EAAE,EAAE,MAAM,GAAG,WAAW,GAAG,SAAS;IAMzC,UAAU,CAAC,EAAE,EAAE,MAAM,GAAG,KAAK,EAAE;IAW/B,WAAW,CAAC,EAAE,EAAE,MAAM,EAAE,KAAK,EAAE,KAAK,GAAG,IAAI;IAI3C,YAAY,CAAC,EAAE,EAAE,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,GAAG,IAAI;IAO/C,IAAI,IAAI,WAAW,EAAE;IAYrB,MAAM,CAAC,EAAE,EAAE,MAAM,GAAG,IAAI;IAOxB,OAAO,CAAC,KAAK;CAQd"}