@flowdot.ai/daemon 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (85) hide show
  1. package/LICENSE +45 -0
  2. package/README.md +51 -0
  3. package/dist/goals/DependencyResolver.d.ts +54 -0
  4. package/dist/goals/DependencyResolver.js +329 -0
  5. package/dist/goals/ErrorRecovery.d.ts +133 -0
  6. package/dist/goals/ErrorRecovery.js +489 -0
  7. package/dist/goals/GoalApiClient.d.ts +81 -0
  8. package/dist/goals/GoalApiClient.js +743 -0
  9. package/dist/goals/GoalCache.d.ts +65 -0
  10. package/dist/goals/GoalCache.js +243 -0
  11. package/dist/goals/GoalCommsHandler.d.ts +150 -0
  12. package/dist/goals/GoalCommsHandler.js +378 -0
  13. package/dist/goals/GoalExporter.d.ts +164 -0
  14. package/dist/goals/GoalExporter.js +318 -0
  15. package/dist/goals/GoalImporter.d.ts +107 -0
  16. package/dist/goals/GoalImporter.js +345 -0
  17. package/dist/goals/GoalManager.d.ts +110 -0
  18. package/dist/goals/GoalManager.js +535 -0
  19. package/dist/goals/GoalReporter.d.ts +105 -0
  20. package/dist/goals/GoalReporter.js +534 -0
  21. package/dist/goals/GoalScheduler.d.ts +102 -0
  22. package/dist/goals/GoalScheduler.js +209 -0
  23. package/dist/goals/GoalValidator.d.ts +72 -0
  24. package/dist/goals/GoalValidator.js +657 -0
  25. package/dist/goals/MetaGoalEnforcer.d.ts +111 -0
  26. package/dist/goals/MetaGoalEnforcer.js +536 -0
  27. package/dist/goals/MilestoneBreaker.d.ts +74 -0
  28. package/dist/goals/MilestoneBreaker.js +348 -0
  29. package/dist/goals/PermissionBridge.d.ts +109 -0
  30. package/dist/goals/PermissionBridge.js +326 -0
  31. package/dist/goals/ProgressTracker.d.ts +113 -0
  32. package/dist/goals/ProgressTracker.js +324 -0
  33. package/dist/goals/ReviewScheduler.d.ts +106 -0
  34. package/dist/goals/ReviewScheduler.js +360 -0
  35. package/dist/goals/TaskExecutor.d.ts +116 -0
  36. package/dist/goals/TaskExecutor.js +370 -0
  37. package/dist/goals/TaskFeedback.d.ts +126 -0
  38. package/dist/goals/TaskFeedback.js +402 -0
  39. package/dist/goals/TaskGenerator.d.ts +75 -0
  40. package/dist/goals/TaskGenerator.js +329 -0
  41. package/dist/goals/TaskQueue.d.ts +84 -0
  42. package/dist/goals/TaskQueue.js +331 -0
  43. package/dist/goals/TaskSanitizer.d.ts +61 -0
  44. package/dist/goals/TaskSanitizer.js +464 -0
  45. package/dist/goals/errors.d.ts +116 -0
  46. package/dist/goals/errors.js +299 -0
  47. package/dist/goals/index.d.ts +24 -0
  48. package/dist/goals/index.js +23 -0
  49. package/dist/goals/types.d.ts +395 -0
  50. package/dist/goals/types.js +230 -0
  51. package/dist/index.d.ts +4 -0
  52. package/dist/index.js +3 -0
  53. package/dist/loop/DaemonIPC.d.ts +67 -0
  54. package/dist/loop/DaemonIPC.js +358 -0
  55. package/dist/loop/IntervalParser.d.ts +39 -0
  56. package/dist/loop/IntervalParser.js +217 -0
  57. package/dist/loop/LoopDaemon.d.ts +123 -0
  58. package/dist/loop/LoopDaemon.js +1821 -0
  59. package/dist/loop/LoopExecutor.d.ts +93 -0
  60. package/dist/loop/LoopExecutor.js +326 -0
  61. package/dist/loop/LoopManager.d.ts +79 -0
  62. package/dist/loop/LoopManager.js +476 -0
  63. package/dist/loop/LoopScheduler.d.ts +69 -0
  64. package/dist/loop/LoopScheduler.js +329 -0
  65. package/dist/loop/LoopStore.d.ts +57 -0
  66. package/dist/loop/LoopStore.js +406 -0
  67. package/dist/loop/LoopValidator.d.ts +55 -0
  68. package/dist/loop/LoopValidator.js +603 -0
  69. package/dist/loop/errors.d.ts +115 -0
  70. package/dist/loop/errors.js +312 -0
  71. package/dist/loop/index.d.ts +11 -0
  72. package/dist/loop/index.js +10 -0
  73. package/dist/loop/notifications/Notifier.d.ts +28 -0
  74. package/dist/loop/notifications/Notifier.js +78 -0
  75. package/dist/loop/notifications/SlackNotifier.d.ts +28 -0
  76. package/dist/loop/notifications/SlackNotifier.js +203 -0
  77. package/dist/loop/notifications/TerminalNotifier.d.ts +18 -0
  78. package/dist/loop/notifications/TerminalNotifier.js +72 -0
  79. package/dist/loop/notifications/WebhookNotifier.d.ts +24 -0
  80. package/dist/loop/notifications/WebhookNotifier.js +123 -0
  81. package/dist/loop/notifications/index.d.ts +24 -0
  82. package/dist/loop/notifications/index.js +109 -0
  83. package/dist/loop/types.d.ts +280 -0
  84. package/dist/loop/types.js +222 -0
  85. package/package.json +92 -0
@@ -0,0 +1,280 @@
1
+ export type ModelTier = 'simple' | 'capable' | 'complex';
2
+ export declare function isModelTier(value: unknown): value is ModelTier;
3
+ export type LoopId = string;
4
+ export type LoopRunId = string;
5
+ export type LoopStatus = 'running' | 'paused' | 'stopped' | 'expired' | 'error';
6
+ export type LoopRunStatus = 'running' | 'success' | 'error';
7
+ export type NotifyMethod = 'none' | 'terminal' | 'webhook' | 'slack';
8
+ export type OnErrorAction = 'continue' | 'pause' | 'stop';
9
+ export type IntervalType = 'duration' | 'cron';
10
+ export interface LoopInterval {
11
+ readonly type: IntervalType;
12
+ readonly raw: string;
13
+ readonly milliseconds: number;
14
+ readonly cronExpression: string | null;
15
+ nextRunAt: Date;
16
+ }
17
+ export interface LoopOptions {
18
+ readonly model: ModelTier;
19
+ readonly maxRuns: number | null;
20
+ readonly onError: OnErrorAction;
21
+ readonly notify: NotifyMethod;
22
+ readonly webhookUrl: string | null;
23
+ readonly slackWebhookUrl: string | null;
24
+ readonly quiet: boolean;
25
+ }
26
+ export declare const DEFAULT_LOOP_OPTIONS: LoopOptions;
27
+ export interface LoopStats {
28
+ totalRuns: number;
29
+ successfulRuns: number;
30
+ failedRuns: number;
31
+ consecutiveFailures: number;
32
+ lastRunAt: Date | null;
33
+ lastRunStatus: 'success' | 'error' | null;
34
+ lastRunDuration: number | null;
35
+ lastError: string | null;
36
+ }
37
+ export declare const INITIAL_LOOP_STATS: LoopStats;
38
+ export interface Loop {
39
+ readonly id: LoopId;
40
+ readonly name: string | null;
41
+ readonly prompt: string;
42
+ readonly interval: LoopInterval;
43
+ status: LoopStatus;
44
+ readonly createdAt: Date;
45
+ readonly expiresAt: Date | null;
46
+ readonly options: LoopOptions;
47
+ stats: LoopStats;
48
+ readonly cwd: string;
49
+ }
50
+ export interface LoopRunError {
51
+ readonly code: string;
52
+ readonly message: string;
53
+ readonly stack: string | null;
54
+ }
55
+ export interface LoopRun {
56
+ readonly id: LoopRunId;
57
+ readonly loopId: LoopId;
58
+ readonly startedAt: Date;
59
+ completedAt: Date | null;
60
+ status: LoopRunStatus;
61
+ duration: number | null;
62
+ output: string | null;
63
+ error: LoopRunError | null;
64
+ }
65
+ export interface LoopRegistryEntry {
66
+ readonly id: LoopId;
67
+ readonly name: string | null;
68
+ status: LoopStatus;
69
+ readonly createdAt: string;
70
+ lastRunAt: string | null;
71
+ }
72
+ export interface LoopRegistry {
73
+ readonly version: number;
74
+ updatedAt: string;
75
+ loops: Record<LoopId, LoopRegistryEntry>;
76
+ }
77
+ export declare const LOOP_REGISTRY_VERSION = 1;
78
+ export interface LoopDaemonConfig {
79
+ readonly port: number;
80
+ readonly logLevel: 'debug' | 'info' | 'warn' | 'error';
81
+ readonly healthCheckInterval: number;
82
+ }
83
+ export interface LoopWebhookConfig {
84
+ readonly defaultUrl: string | null;
85
+ readonly timeout: number;
86
+ readonly retries: number;
87
+ }
88
+ export interface LoopConfig {
89
+ readonly defaultExpiration: string;
90
+ readonly defaultOnError: OnErrorAction;
91
+ readonly defaultNotify: NotifyMethod;
92
+ readonly maxConcurrentLoops: number;
93
+ readonly minInterval: string;
94
+ readonly maxRunDuration: string;
95
+ readonly errorThreshold: number;
96
+ readonly daemon: LoopDaemonConfig;
97
+ readonly webhooks: LoopWebhookConfig;
98
+ }
99
+ export declare const DEFAULT_LOOP_CONFIG: LoopConfig;
100
+ export interface CreateLoopInput {
101
+ readonly interval: string;
102
+ readonly prompt: string;
103
+ readonly name?: string;
104
+ readonly maxRuns?: number;
105
+ readonly expires?: string;
106
+ readonly model?: ModelTier;
107
+ readonly onError?: OnErrorAction;
108
+ readonly notify?: NotifyMethod;
109
+ readonly webhookUrl?: string;
110
+ readonly slackWebhookUrl?: string;
111
+ readonly quiet?: boolean;
112
+ readonly dryRun?: boolean;
113
+ readonly cwd?: string;
114
+ }
115
+ export interface UpdateLoopInput {
116
+ readonly identifier: string;
117
+ readonly name?: string;
118
+ readonly interval?: string;
119
+ readonly model?: ModelTier;
120
+ readonly onError?: OnErrorAction;
121
+ readonly notify?: NotifyMethod;
122
+ }
123
+ export type IPCMessageType = 'ping' | 'pong' | 'request' | 'create_loop' | 'pause_loop' | 'resume_loop' | 'stop_loop' | 'run_loop' | 'get_loop' | 'list_loops' | 'get_history' | 'get_stats' | 'shutdown' | 'response' | 'error' | 'event';
124
+ export interface IPCMessage {
125
+ readonly type: IPCMessageType;
126
+ readonly id: string;
127
+ readonly payload?: unknown;
128
+ readonly timestamp: string;
129
+ }
130
+ export interface IPCRequest extends IPCMessage {
131
+ readonly type: Exclude<IPCMessageType, 'response' | 'error' | 'pong' | 'event'>;
132
+ }
133
+ export interface IPCResponse extends IPCMessage {
134
+ readonly type: 'response' | 'error';
135
+ readonly requestId: string;
136
+ readonly success: boolean;
137
+ readonly errorMessage?: string;
138
+ readonly errorCode?: string;
139
+ }
140
+ export interface IPCEvent extends IPCMessage {
141
+ readonly type: 'event';
142
+ readonly event: string;
143
+ readonly data: unknown;
144
+ }
145
+ export interface DaemonStatus {
146
+ readonly running: boolean;
147
+ readonly pid: number | null;
148
+ readonly startedAt: Date | null;
149
+ readonly activeLoops: number;
150
+ readonly uptime: number | null;
151
+ }
152
+ export interface ManagerStats {
153
+ totalLoops: number;
154
+ activeLoops: number;
155
+ pausedLoops: number;
156
+ stoppedLoops: number;
157
+ errorLoops: number;
158
+ totalRuns: number;
159
+ successfulRuns: number;
160
+ failedRuns: number;
161
+ }
162
+ export interface NotificationPayload {
163
+ readonly title: string;
164
+ readonly message: string;
165
+ readonly loopId: LoopId;
166
+ readonly loopName: string | null;
167
+ readonly runId?: LoopRunId;
168
+ readonly status?: LoopRunStatus;
169
+ readonly error?: string;
170
+ readonly timestamp: Date;
171
+ }
172
+ export interface Notifier {
173
+ readonly type: NotifyMethod;
174
+ send(payload: NotificationPayload): Promise<void>;
175
+ }
176
+ export declare function isLoopStatus(value: unknown): value is LoopStatus;
177
+ export declare function isLoopRunStatus(value: unknown): value is LoopRunStatus;
178
+ export declare function isNotifyMethod(value: unknown): value is NotifyMethod;
179
+ export declare function isOnErrorAction(value: unknown): value is OnErrorAction;
180
+ export declare function isIntervalType(value: unknown): value is IntervalType;
181
+ export interface SerializedLoop {
182
+ id: string;
183
+ name: string | null;
184
+ prompt: string;
185
+ interval: {
186
+ type: IntervalType;
187
+ raw: string;
188
+ milliseconds: number;
189
+ cronExpression: string | null;
190
+ nextRunAt: string;
191
+ };
192
+ status: LoopStatus;
193
+ createdAt: string;
194
+ expiresAt: string | null;
195
+ options: LoopOptions;
196
+ stats: {
197
+ totalRuns: number;
198
+ successfulRuns: number;
199
+ failedRuns: number;
200
+ consecutiveFailures: number;
201
+ lastRunAt: string | null;
202
+ lastRunStatus: 'success' | 'error' | null;
203
+ lastRunDuration: number | null;
204
+ lastError: string | null;
205
+ };
206
+ cwd: string;
207
+ }
208
+ export interface SerializedLoopRun {
209
+ id: string;
210
+ loopId: string;
211
+ startedAt: string;
212
+ completedAt: string | null;
213
+ status: LoopRunStatus;
214
+ duration: number | null;
215
+ output: string | null;
216
+ error: LoopRunError | null;
217
+ }
218
+ export declare function serializeLoop(loop: Loop): SerializedLoop;
219
+ export declare function deserializeLoop(data: SerializedLoop): Loop;
220
+ export declare function serializeLoopRun(run: LoopRun): SerializedLoopRun;
221
+ export declare function deserializeLoopRun(data: SerializedLoopRun): LoopRun;
222
+ export interface SerializedRegistry {
223
+ version: number;
224
+ updatedAt: string;
225
+ loops: Record<string, SerializedLoop>;
226
+ byName: Record<string, string>;
227
+ }
228
+ export interface ExtendedLoopRegistry {
229
+ loops: Record<LoopId, Loop>;
230
+ byName: Record<string, LoopId>;
231
+ lastUpdated: Date;
232
+ }
233
+ export declare function serializeRegistry(registry: ExtendedLoopRegistry): SerializedRegistry;
234
+ export declare function deserializeRegistry(data: SerializedRegistry): ExtendedLoopRegistry;
235
+ export declare function createDefaultLoopOptions(overrides?: Partial<LoopOptions>): LoopOptions;
236
+ export declare function createDefaultLoopStats(): LoopStats;
237
+ export declare function createLoop(params: {
238
+ prompt: string;
239
+ interval: LoopInterval;
240
+ name?: string | null;
241
+ options?: Partial<LoopOptions>;
242
+ cwd?: string;
243
+ expiresAt?: Date | null;
244
+ }): Loop;
245
+ export declare function createLoopRun(loopId: LoopId): LoopRun;
246
+ export declare function isActiveStatus(status: LoopStatus): boolean;
247
+ export declare function isTerminalStatus(status: LoopStatus): boolean;
248
+ export declare function canTransitionTo(from: LoopStatus, to: LoopStatus): boolean;
249
+ export declare function generateLoopId(): LoopId;
250
+ export declare function generateLoopRunId(): LoopRunId;
251
+ export declare function isValidLoopId(value: unknown): value is LoopId;
252
+ export declare function isValidLoopRunId(value: unknown): value is LoopRunId;
253
+ export interface Logger {
254
+ debug(category: string, message: string, data?: Record<string, unknown>): void;
255
+ info(category: string, message: string, data?: Record<string, unknown>): void;
256
+ warn(category: string, message: string, data?: Record<string, unknown>): void;
257
+ error(category: string, message: string, data?: Record<string, unknown>): void;
258
+ }
259
+ export type AgenticResponseCallback = (chunk: string) => void;
260
+ export type AgenticResponseFunction = (prompt: string, options: {
261
+ model?: ModelTier;
262
+ cwd?: string;
263
+ timeout?: number;
264
+ onOutput?: AgenticResponseCallback;
265
+ abortSignal?: AbortSignal;
266
+ }) => Promise<{
267
+ success: boolean;
268
+ output: string;
269
+ error?: string;
270
+ }>;
271
+ export type ExecuteActionFunction = (action: string, options?: {
272
+ cwd?: string;
273
+ timeout?: number;
274
+ abortSignal?: AbortSignal;
275
+ }) => Promise<{
276
+ success: boolean;
277
+ output: string;
278
+ error?: string;
279
+ }>;
280
+ export type LoopCreateInput = CreateLoopInput;
@@ -0,0 +1,222 @@
1
+ export function isModelTier(value) {
2
+ return (typeof value === 'string' &&
3
+ ['simple', 'capable', 'complex'].includes(value));
4
+ }
5
+ export const DEFAULT_LOOP_OPTIONS = {
6
+ model: 'capable',
7
+ maxRuns: null,
8
+ onError: 'continue',
9
+ notify: 'none',
10
+ webhookUrl: null,
11
+ slackWebhookUrl: null,
12
+ quiet: false,
13
+ };
14
+ export const INITIAL_LOOP_STATS = {
15
+ totalRuns: 0,
16
+ successfulRuns: 0,
17
+ failedRuns: 0,
18
+ consecutiveFailures: 0,
19
+ lastRunAt: null,
20
+ lastRunStatus: null,
21
+ lastRunDuration: null,
22
+ lastError: null,
23
+ };
24
+ export const LOOP_REGISTRY_VERSION = 1;
25
+ export const DEFAULT_LOOP_CONFIG = {
26
+ defaultExpiration: '3d',
27
+ defaultOnError: 'continue',
28
+ defaultNotify: 'none',
29
+ maxConcurrentLoops: 10,
30
+ minInterval: '1m',
31
+ maxRunDuration: '30m',
32
+ errorThreshold: 5,
33
+ daemon: {
34
+ port: 47691,
35
+ logLevel: 'info',
36
+ healthCheckInterval: 30000,
37
+ },
38
+ webhooks: {
39
+ defaultUrl: null,
40
+ timeout: 30000,
41
+ retries: 3,
42
+ },
43
+ };
44
+ export function isLoopStatus(value) {
45
+ return (typeof value === 'string' &&
46
+ ['running', 'paused', 'stopped', 'expired', 'error'].includes(value));
47
+ }
48
+ export function isLoopRunStatus(value) {
49
+ return (typeof value === 'string' &&
50
+ ['running', 'success', 'error'].includes(value));
51
+ }
52
+ export function isNotifyMethod(value) {
53
+ return (typeof value === 'string' &&
54
+ ['none', 'terminal', 'webhook', 'slack'].includes(value));
55
+ }
56
+ export function isOnErrorAction(value) {
57
+ return (typeof value === 'string' &&
58
+ ['continue', 'pause', 'stop'].includes(value));
59
+ }
60
+ export function isIntervalType(value) {
61
+ return (typeof value === 'string' &&
62
+ ['duration', 'cron'].includes(value));
63
+ }
64
+ export function serializeLoop(loop) {
65
+ return {
66
+ id: loop.id,
67
+ name: loop.name,
68
+ prompt: loop.prompt,
69
+ interval: {
70
+ type: loop.interval.type,
71
+ raw: loop.interval.raw,
72
+ milliseconds: loop.interval.milliseconds,
73
+ cronExpression: loop.interval.cronExpression,
74
+ nextRunAt: loop.interval.nextRunAt.toISOString(),
75
+ },
76
+ status: loop.status,
77
+ createdAt: loop.createdAt.toISOString(),
78
+ expiresAt: loop.expiresAt?.toISOString() ?? null,
79
+ options: loop.options,
80
+ stats: {
81
+ ...loop.stats,
82
+ lastRunAt: loop.stats.lastRunAt?.toISOString() ?? null,
83
+ },
84
+ cwd: loop.cwd,
85
+ };
86
+ }
87
+ export function deserializeLoop(data) {
88
+ return {
89
+ id: data.id,
90
+ name: data.name,
91
+ prompt: data.prompt,
92
+ interval: {
93
+ type: data.interval.type,
94
+ raw: data.interval.raw,
95
+ milliseconds: data.interval.milliseconds,
96
+ cronExpression: data.interval.cronExpression,
97
+ nextRunAt: new Date(data.interval.nextRunAt),
98
+ },
99
+ status: data.status,
100
+ createdAt: new Date(data.createdAt),
101
+ expiresAt: data.expiresAt ? new Date(data.expiresAt) : null,
102
+ options: data.options,
103
+ stats: {
104
+ ...data.stats,
105
+ lastRunAt: data.stats.lastRunAt ? new Date(data.stats.lastRunAt) : null,
106
+ },
107
+ cwd: data.cwd,
108
+ };
109
+ }
110
+ export function serializeLoopRun(run) {
111
+ return {
112
+ id: run.id,
113
+ loopId: run.loopId,
114
+ startedAt: run.startedAt.toISOString(),
115
+ completedAt: run.completedAt?.toISOString() ?? null,
116
+ status: run.status,
117
+ duration: run.duration,
118
+ output: run.output,
119
+ error: run.error,
120
+ };
121
+ }
122
+ export function deserializeLoopRun(data) {
123
+ return {
124
+ id: data.id,
125
+ loopId: data.loopId,
126
+ startedAt: new Date(data.startedAt),
127
+ completedAt: data.completedAt ? new Date(data.completedAt) : null,
128
+ status: data.status,
129
+ duration: data.duration,
130
+ output: data.output,
131
+ error: data.error,
132
+ };
133
+ }
134
+ export function serializeRegistry(registry) {
135
+ const serializedLoops = {};
136
+ for (const [id, loop] of Object.entries(registry.loops)) {
137
+ serializedLoops[id] = serializeLoop(loop);
138
+ }
139
+ return {
140
+ version: LOOP_REGISTRY_VERSION,
141
+ updatedAt: registry.lastUpdated.toISOString(),
142
+ loops: serializedLoops,
143
+ byName: registry.byName,
144
+ };
145
+ }
146
+ export function deserializeRegistry(data) {
147
+ const loops = {};
148
+ for (const [id, serializedLoop] of Object.entries(data.loops)) {
149
+ loops[id] = deserializeLoop(serializedLoop);
150
+ }
151
+ return {
152
+ loops,
153
+ byName: data.byName,
154
+ lastUpdated: new Date(data.updatedAt),
155
+ };
156
+ }
157
+ export function createDefaultLoopOptions(overrides) {
158
+ return {
159
+ ...DEFAULT_LOOP_OPTIONS,
160
+ ...overrides,
161
+ };
162
+ }
163
+ export function createDefaultLoopStats() {
164
+ return { ...INITIAL_LOOP_STATS };
165
+ }
166
+ export function createLoop(params) {
167
+ return {
168
+ id: generateLoopId(),
169
+ name: params.name ?? null,
170
+ prompt: params.prompt,
171
+ interval: params.interval,
172
+ status: 'paused',
173
+ createdAt: new Date(),
174
+ expiresAt: params.expiresAt ?? null,
175
+ options: createDefaultLoopOptions(params.options),
176
+ stats: createDefaultLoopStats(),
177
+ cwd: params.cwd ?? process.cwd(),
178
+ };
179
+ }
180
+ export function createLoopRun(loopId) {
181
+ return {
182
+ id: generateLoopRunId(),
183
+ loopId,
184
+ startedAt: new Date(),
185
+ completedAt: null,
186
+ status: 'running',
187
+ duration: null,
188
+ output: null,
189
+ error: null,
190
+ };
191
+ }
192
+ export function isActiveStatus(status) {
193
+ return status === 'running';
194
+ }
195
+ export function isTerminalStatus(status) {
196
+ return status === 'stopped' || status === 'expired';
197
+ }
198
+ const STATUS_TRANSITIONS = {
199
+ running: ['paused', 'stopped', 'error', 'expired'],
200
+ paused: ['running', 'stopped'],
201
+ stopped: [],
202
+ expired: [],
203
+ error: ['paused', 'stopped', 'running'],
204
+ };
205
+ export function canTransitionTo(from, to) {
206
+ return STATUS_TRANSITIONS[from].includes(to);
207
+ }
208
+ export function generateLoopId() {
209
+ return `loop-${generateRandomId()}`;
210
+ }
211
+ export function generateLoopRunId() {
212
+ return `run-${generateRandomId()}`;
213
+ }
214
+ function generateRandomId() {
215
+ return Math.random().toString(36).substring(2, 10);
216
+ }
217
+ export function isValidLoopId(value) {
218
+ return typeof value === 'string' && value.startsWith('loop-') && value.length > 5;
219
+ }
220
+ export function isValidLoopRunId(value) {
221
+ return typeof value === 'string' && value.startsWith('run-') && value.length > 4;
222
+ }
package/package.json ADDED
@@ -0,0 +1,92 @@
1
+ {
2
+ "name": "@flowdot.ai/daemon",
3
+ "version": "1.0.0",
4
+ "description": "Shared FlowDot daemon and loop/goal management for CLI and native app",
5
+ "main": "dist/index.js",
6
+ "types": "dist/index.d.ts",
7
+ "type": "module",
8
+ "exports": {
9
+ ".": {
10
+ "types": "./dist/index.d.ts",
11
+ "import": "./dist/index.js"
12
+ },
13
+ "./loop": {
14
+ "types": "./dist/loop/index.d.ts",
15
+ "import": "./dist/loop/index.js"
16
+ }
17
+ },
18
+ "scripts": {
19
+ "clean": "rimraf dist coverage",
20
+ "build": "tsc",
21
+ "dev": "tsc --watch",
22
+ "lint": "eslint .",
23
+ "lint:fix": "eslint . --fix",
24
+ "test": "vitest run",
25
+ "test:watch": "vitest",
26
+ "test:coverage": "vitest run --coverage",
27
+ "verify-pack": "node scripts/verify-pack.mjs",
28
+ "prepublishOnly": "npm run clean && npm run lint && npm test && npm run build && npm run verify-pack",
29
+ "prepare": "husky || true"
30
+ },
31
+ "keywords": [
32
+ "flowdot",
33
+ "daemon",
34
+ "loop",
35
+ "scheduler"
36
+ ],
37
+ "author": "FlowDot",
38
+ "license": "SEE LICENSE IN LICENSE",
39
+ "repository": {
40
+ "type": "git",
41
+ "url": "https://github.com/ElliotTheGreek/flowdot-daemon.git"
42
+ },
43
+ "homepage": "https://flowdot.ai/docs/daemon",
44
+ "dependencies": {
45
+ "cron-parser": "^4.9.0",
46
+ "ms": "^2.1.3",
47
+ "uuid": "^9.0.0"
48
+ },
49
+ "devDependencies": {
50
+ "@eslint/js": "^9.15.0",
51
+ "@types/ms": "^2.1.0",
52
+ "@types/node": "^20.0.0",
53
+ "@types/node-notifier": "^8.0.5",
54
+ "@types/uuid": "^9.0.0",
55
+ "@vitest/coverage-v8": "^3.2.4",
56
+ "eslint": "^9.15.0",
57
+ "globals": "^15.12.0",
58
+ "husky": "^9.1.7",
59
+ "lint-staged": "^15.2.10",
60
+ "rimraf": "^6.0.1",
61
+ "typescript": "^5.0.0",
62
+ "typescript-eslint": "^8.15.0",
63
+ "vitest": "^3.2.4"
64
+ },
65
+ "peerDependencies": {
66
+ "@flowdot.ai/api": "^1.0.0"
67
+ },
68
+ "peerDependenciesMeta": {
69
+ "@flowdot.ai/api": {
70
+ "optional": true
71
+ }
72
+ },
73
+ "files": [
74
+ "dist",
75
+ "LICENSE",
76
+ "README.md"
77
+ ],
78
+ "engines": {
79
+ "node": ">=20.0.0"
80
+ },
81
+ "publishConfig": {
82
+ "access": "public"
83
+ },
84
+ "optionalDependencies": {
85
+ "node-notifier": "^10.0.1"
86
+ },
87
+ "lint-staged": {
88
+ "*.ts": [
89
+ "eslint --fix"
90
+ ]
91
+ }
92
+ }