@ykurilov/agent-chat-flows 0.0.0-stage → 0.55.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 (151) hide show
  1. package/CHANGELOG.md +252 -0
  2. package/LICENSE +21 -0
  3. package/README.md +124 -2
  4. package/agent-flow.schema.json +1020 -0
  5. package/dist/chunk-3PTJI2XY.js +100 -0
  6. package/dist/chunk-3PTJI2XY.js.map +1 -0
  7. package/dist/chunk-BNMQUNSI.js +9 -0
  8. package/dist/chunk-BNMQUNSI.js.map +1 -0
  9. package/dist/chunk-BOV6FJGU.js +1288 -0
  10. package/dist/chunk-BOV6FJGU.js.map +1 -0
  11. package/dist/chunk-CKY5KG7N.js +165 -0
  12. package/dist/chunk-CKY5KG7N.js.map +1 -0
  13. package/dist/chunk-DCTRMCGV.js +34 -0
  14. package/dist/chunk-DCTRMCGV.js.map +1 -0
  15. package/dist/format.js +147 -0
  16. package/dist/format.js.map +1 -0
  17. package/dist/index.js +3197 -0
  18. package/dist/index.js.map +1 -0
  19. package/dist/postgres.js +387 -0
  20. package/dist/postgres.js.map +1 -0
  21. package/dist/react.js +2650 -0
  22. package/dist/react.js.map +1 -0
  23. package/dist/sqlite.js +319 -0
  24. package/dist/sqlite.js.map +1 -0
  25. package/dist/types/check/app-checks.d.ts +16 -0
  26. package/dist/types/check/check-flow.d.ts +8 -0
  27. package/dist/types/check/index.d.ts +2 -0
  28. package/dist/types/engine/data-conditions.d.ts +10 -0
  29. package/dist/types/engine/day-frame.d.ts +17 -0
  30. package/dist/types/engine/first-messages.d.ts +21 -0
  31. package/dist/types/engine/flow-days.d.ts +39 -0
  32. package/dist/types/engine/flow-graph.d.ts +26 -0
  33. package/dist/types/engine/flow-run.d.ts +130 -0
  34. package/dist/types/engine/index.d.ts +14 -0
  35. package/dist/types/engine/migrate-run.d.ts +11 -0
  36. package/dist/types/engine/next-transition.d.ts +40 -0
  37. package/dist/types/engine/nudges.d.ts +78 -0
  38. package/dist/types/engine/run-updates.d.ts +37 -0
  39. package/dist/types/engine/side-questions.d.ts +26 -0
  40. package/dist/types/engine/side-tasks.d.ts +44 -0
  41. package/dist/types/engine/targets.d.ts +9 -0
  42. package/dist/types/engine/timers.d.ts +61 -0
  43. package/dist/types/engine/zoned-time.d.ts +27 -0
  44. package/dist/types/format/catalog-events.d.ts +5 -0
  45. package/dist/types/format/compact-flow.d.ts +8 -0
  46. package/dist/types/format/flow-format.d.ts +286 -0
  47. package/dist/types/format/flow-json-schema.d.ts +2 -0
  48. package/dist/types/format/flow-schema.d.ts +605 -0
  49. package/dist/types/format/index.d.ts +7 -0
  50. package/dist/types/format/migrate-flow.d.ts +4 -0
  51. package/dist/types/format/parse-flow.d.ts +6 -0
  52. package/dist/types/format.d.ts +3 -0
  53. package/dist/types/index.d.ts +4 -0
  54. package/dist/types/labels/client-card.d.ts +20 -0
  55. package/dist/types/labels/editor.d.ts +261 -0
  56. package/dist/types/labels/index.d.ts +14 -0
  57. package/dist/types/labels/migrate.d.ts +19 -0
  58. package/dist/types/labels/test-chat.d.ts +28 -0
  59. package/dist/types/not-yet.d.ts +2 -0
  60. package/dist/types/postgres.d.ts +10 -0
  61. package/dist/types/prompt/client-card-block.d.ts +16 -0
  62. package/dist/types/prompt/flow-rules.d.ts +9 -0
  63. package/dist/types/prompt/rules/after-end.d.ts +3 -0
  64. package/dist/types/prompt/rules/client-facts.d.ts +2 -0
  65. package/dist/types/prompt/rules/day-frame.d.ts +2 -0
  66. package/dist/types/prompt/rules/link-views.d.ts +4 -0
  67. package/dist/types/prompt/rules/rule-part.d.ts +3 -0
  68. package/dist/types/prompt/rules/side-tasks.d.ts +2 -0
  69. package/dist/types/prompt/rules/time-zone.d.ts +2 -0
  70. package/dist/types/prompt/state-card.d.ts +14 -0
  71. package/dist/types/react/client-card/client-card-panel.d.ts +8 -0
  72. package/dist/types/react/client-card/index.d.ts +2 -0
  73. package/dist/types/react/client-card/use-client-card.d.ts +19 -0
  74. package/dist/types/react/client-card-skin.d.ts +27 -0
  75. package/dist/types/react/editor/board-space.d.ts +51 -0
  76. package/dist/types/react/editor/board-styles.d.ts +1 -0
  77. package/dist/types/react/editor/editor-model.d.ts +60 -0
  78. package/dist/types/react/editor/exit-text.d.ts +11 -0
  79. package/dist/types/react/editor/flow-board.d.ts +11 -0
  80. package/dist/types/react/editor/flow-editor.d.ts +13 -0
  81. package/dist/types/react/editor/flow-simulation.d.ts +44 -0
  82. package/dist/types/react/editor/index.d.ts +6 -0
  83. package/dist/types/react/editor/schedule-model.d.ts +47 -0
  84. package/dist/types/react/editor/side-task-model.d.ts +18 -0
  85. package/dist/types/react/editor/use-flow-editor.d.ts +120 -0
  86. package/dist/types/react/flow-editor-skin.d.ts +453 -0
  87. package/dist/types/react/flow-labels.d.ts +8 -0
  88. package/dist/types/react/index.d.ts +6 -0
  89. package/dist/types/react/test-chat/flow-test-chat.d.ts +22 -0
  90. package/dist/types/react/test-chat/index.d.ts +2 -0
  91. package/dist/types/react/test-chat/use-flow-test-chat.d.ts +50 -0
  92. package/dist/types/react.d.ts +3 -0
  93. package/dist/types/runtime/admit.d.ts +15 -0
  94. package/dist/types/runtime/agent-flow.d.ts +20 -0
  95. package/dist/types/runtime/client-card.d.ts +9 -0
  96. package/dist/types/runtime/client-facts.d.ts +22 -0
  97. package/dist/types/runtime/close-day-tool.d.ts +3 -0
  98. package/dist/types/runtime/decisions-client.d.ts +33 -0
  99. package/dist/types/runtime/extra-tool.d.ts +16 -0
  100. package/dist/types/runtime/first-message-retry.d.ts +4 -0
  101. package/dist/types/runtime/first-message-rules.d.ts +55 -0
  102. package/dist/types/runtime/first-reasons-notice.d.ts +9 -0
  103. package/dist/types/runtime/flow-delivery.d.ts +53 -0
  104. package/dist/types/runtime/flow-events.d.ts +126 -0
  105. package/dist/types/runtime/flow-finish.d.ts +68 -0
  106. package/dist/types/runtime/flow-known-texts.d.ts +11 -0
  107. package/dist/types/runtime/flow-signals.d.ts +12 -0
  108. package/dist/types/runtime/flow-timers.d.ts +55 -0
  109. package/dist/types/runtime/flow-tools.d.ts +23 -0
  110. package/dist/types/runtime/flow-types.d.ts +547 -0
  111. package/dist/types/runtime/held-messages.d.ts +25 -0
  112. package/dist/types/runtime/index.d.ts +11 -0
  113. package/dist/types/runtime/judge-context.d.ts +36 -0
  114. package/dist/types/runtime/judge.d.ts +21 -0
  115. package/dist/types/runtime/migrate-chats.d.ts +20 -0
  116. package/dist/types/runtime/note-tools.d.ts +15 -0
  117. package/dist/types/runtime/pause.d.ts +21 -0
  118. package/dist/types/runtime/prepare-turn.d.ts +12 -0
  119. package/dist/types/runtime/side-task-tool.d.ts +5 -0
  120. package/dist/types/runtime/step-tail.d.ts +11 -0
  121. package/dist/types/runtime/tail/day-line.d.ts +2 -0
  122. package/dist/types/runtime/tail/frame-line.d.ts +2 -0
  123. package/dist/types/runtime/tail/side-tasks-line.d.ts +2 -0
  124. package/dist/types/runtime/tail/tail-part.d.ts +21 -0
  125. package/dist/types/runtime/test-clock.d.ts +26 -0
  126. package/dist/types/runtime/time-zone-tool.d.ts +3 -0
  127. package/dist/types/runtime/turn-gate.d.ts +8 -0
  128. package/dist/types/sqlite.d.ts +9 -0
  129. package/dist/types/store/flow-store-shared.d.ts +20 -0
  130. package/dist/types/store/flow-store.d.ts +240 -0
  131. package/dist/types/store/memory.d.ts +3 -0
  132. package/dist/types/store/migration-settings.d.ts +7 -0
  133. package/dist/types/store/postgres-schema.d.ts +775 -0
  134. package/dist/types/store/postgres.d.ts +15 -0
  135. package/dist/types/store/sqlite-schema.d.ts +824 -0
  136. package/dist/types/store/sqlite.d.ts +9 -0
  137. package/drizzle/postgres/0000_init.sql +45 -0
  138. package/drizzle/postgres/0001_days_pause_side_tasks.sql +21 -0
  139. package/drizzle/postgres/0002_chat_placement.sql +1 -0
  140. package/drizzle/postgres/meta/0000_snapshot.json +317 -0
  141. package/drizzle/postgres/meta/0001_snapshot.json +439 -0
  142. package/drizzle/postgres/meta/0002_snapshot.json +445 -0
  143. package/drizzle/postgres/meta/_journal.json +27 -0
  144. package/drizzle/sqlite/0000_init.sql +44 -0
  145. package/drizzle/sqlite/0001_days_pause_side_tasks.sql +21 -0
  146. package/drizzle/sqlite/0002_chat_placement.sql +1 -0
  147. package/drizzle/sqlite/meta/0000_snapshot.json +297 -0
  148. package/drizzle/sqlite/meta/0001_snapshot.json +427 -0
  149. package/drizzle/sqlite/meta/0002_snapshot.json +434 -0
  150. package/drizzle/sqlite/meta/_journal.json +27 -0
  151. package/package.json +98 -3
@@ -0,0 +1,1288 @@
1
+ // src/format/flow-format.ts
2
+ var AGENT_FLOW_FORMAT = "agent-flow";
3
+ var AGENT_FLOW_FORMAT_VERSION = 2;
4
+ var RETURN_TARGET = "@return";
5
+ var ANY_STATE_LAYOUT_KEY = "@any";
6
+ var FLOW_FIELD_TYPES = ["text", "number", "choice", "boolean"];
7
+ var FLOW_DATA_OPS = ["filled", "eq", "ne", "gt", "lt", "contains"];
8
+ var FLOW_OPS_BY_FIELD_TYPE = {
9
+ text: ["filled", "contains"],
10
+ number: ["filled", "eq", "gt", "lt"],
11
+ choice: ["filled", "eq"],
12
+ boolean: ["filled", "eq", "ne"]
13
+ };
14
+ var FLOW_EVENT_TYPES = ["message", "button", "tool", "app"];
15
+ var FLOW_TIMER_UNITS = ["min", "h", "d"];
16
+ var FLOW_TIMER_SPANS = ["in_state", "silence", "since_start"];
17
+ var DEFAULT_LATE_START_HOURS = 3;
18
+ var DEFAULT_SIDE_TASK_MAX_ATTEMPTS = 2;
19
+ var FLOW_AFTER_END_MODES = ["reply", "silent"];
20
+
21
+ // src/format/flow-schema.ts
22
+ import { z } from "zod";
23
+ var id = z.string().min(1);
24
+ var names = z.array(z.string()).default([]);
25
+ var clock = z.string().regex(/^([01]\d|2[0-3]):[0-5]\d$/, "\u0412\u0440\u0435\u043C\u044F \u0441\u0443\u0442\u043E\u043A \u043F\u0438\u0448\u0435\u0442\u0441\u044F \u043A\u0430\u043A \xAB\u0427\u0427:\u041C\u041C\xBB, \u043D\u0430\u043F\u0440\u0438\u043C\u0435\u0440 \xAB10:00\xBB.");
26
+ var fieldShape = {
27
+ id,
28
+ name: z.string(),
29
+ about: z.string().default(""),
30
+ type: z.enum(FLOW_FIELD_TYPES).default("text"),
31
+ options: names
32
+ };
33
+ var flowField = z.strictObject(fieldShape);
34
+ var clientCardField = z.strictObject({
35
+ ...fieldShape,
36
+ refreshAfterMonths: z.int().positive().nullable().default(null)
37
+ });
38
+ var judgeCondition = z.strictObject({ type: z.literal("judge"), text: z.string() });
39
+ var dataCondition = z.strictObject({
40
+ type: z.literal("data"),
41
+ field: id,
42
+ op: z.enum(FLOW_DATA_OPS).default("filled"),
43
+ value: z.union([z.string(), z.number(), z.boolean()]).optional()
44
+ }).superRefine((condition, context) => {
45
+ if (condition.op !== "filled" && condition.value === void 0) {
46
+ context.addIssue({ code: "custom", path: ["value"], message: "\u0414\u043B\u044F \u0441\u0440\u0430\u0432\u043D\u0435\u043D\u0438\u044F \u043D\u0443\u0436\u043D\u043E \u0437\u043D\u0430\u0447\u0435\u043D\u0438\u0435 `value`." });
47
+ }
48
+ });
49
+ var eventCondition = z.strictObject({
50
+ type: z.literal("event"),
51
+ event: z.enum(FLOW_EVENT_TYPES),
52
+ name: z.string().optional()
53
+ });
54
+ var timerCondition = z.discriminatedUnion("from", [
55
+ z.strictObject({
56
+ type: z.literal("timer"),
57
+ from: z.enum(FLOW_TIMER_SPANS),
58
+ amount: z.number().positive(),
59
+ unit: z.enum(FLOW_TIMER_UNITS)
60
+ }),
61
+ z.strictObject({ type: z.literal("timer"), from: z.literal("time_of_day"), at: clock }),
62
+ // `days` < 1 — не ошибка формы: недописанный сценарий сохраняется, находку показывает `checkFlow`.
63
+ z.strictObject({ type: z.literal("timer"), from: z.literal("state_days"), days: z.int() }),
64
+ // Дробный и меньше 1 — тоже находка `checkFlow`.
65
+ z.strictObject({ type: z.literal("timer"), from: z.literal("program_day"), day: z.number() })
66
+ ]);
67
+ var duration = z.strictObject({ amount: z.number().positive(), unit: z.enum(FLOW_TIMER_UNITS) });
68
+ var nudges = z.strictObject({
69
+ afterSilence: z.array(duration),
70
+ dailyAt: z.array(clock).optional(),
71
+ giveUpAfter: duration.optional()
72
+ });
73
+ var schedule = z.strictObject({
74
+ dayStart: clock,
75
+ nightFrom: clock.optional(),
76
+ lateStartHours: z.number().min(0).max(24).default(DEFAULT_LATE_START_HOURS),
77
+ lengthDays: z.int().min(1).max(60).optional(),
78
+ deadlineState: z.string().optional(),
79
+ farewellOnDeadline: z.boolean().default(false),
80
+ farewellText: z.string().optional(),
81
+ firstMessages: z.strictObject({
82
+ maxPerDay: z.int().min(0).optional(),
83
+ morning: z.boolean().optional(),
84
+ skipMorningIfHumanWithinMin: z.int().min(0).optional()
85
+ }).optional(),
86
+ nudges: nudges.optional(),
87
+ dayFrame: z.strictObject({ softFrom: z.int().positive().optional(), hardAt: z.int().positive().optional(), hardText: z.string().optional() }).optional()
88
+ });
89
+ var sideTask = z.strictObject({
90
+ id,
91
+ text: z.string(),
92
+ when: z.string().optional(),
93
+ field: z.string().optional(),
94
+ maxAttempts: z.int().positive().default(DEFAULT_SIDE_TASK_MAX_ATTEMPTS),
95
+ perConversation: z.boolean().default(false)
96
+ });
97
+ var flowCondition = z.discriminatedUnion("type", [judgeCondition, dataCondition, eventCondition, timerCondition]);
98
+ var flowExit = z.strictObject({ id, when: flowCondition, to: z.string().nullable().default(null) });
99
+ var exits = z.array(flowExit).default([]);
100
+ var flowState = z.strictObject({
101
+ id,
102
+ kind: z.literal("state").default("state"),
103
+ title: z.string().default(""),
104
+ instructions: z.string().default(""),
105
+ firstMessage: z.string().nullable().default(null),
106
+ learn: names,
107
+ noSideQuestions: z.boolean().default(false),
108
+ tools: names,
109
+ tags: names,
110
+ exits,
111
+ nudges: z.union([nudges.extend({ days: z.number().optional() }), z.literal("off")]).optional()
112
+ });
113
+ var DEFAULT_SIDE_QUESTION_EVERY_MESSAGES = 5;
114
+ var agentFlowSchema = z.strictObject({
115
+ $schema: z.string().optional(),
116
+ format: z.literal(AGENT_FLOW_FORMAT),
117
+ version: z.literal(AGENT_FLOW_FORMAT_VERSION),
118
+ id,
119
+ name: z.string(),
120
+ start: z.string().nullable().default(null),
121
+ common: z.string().default(""),
122
+ pace: z.strictObject({ sideQuestionEveryMessages: z.int().positive().default(DEFAULT_SIDE_QUESTION_EVERY_MESSAGES) }).default({ sideQuestionEveryMessages: DEFAULT_SIDE_QUESTION_EVERY_MESSAGES }),
123
+ clientCard: z.array(clientCardField).default([]),
124
+ chatNotes: z.array(flowField).default([]),
125
+ tools: names,
126
+ anyState: z.strictObject({ except: names, exits }).default({ except: [], exits: [] }),
127
+ states: z.array(flowState),
128
+ layout: z.record(z.string(), z.strictObject({ x: z.number(), y: z.number() })).default({}),
129
+ schedule: schedule.optional(),
130
+ nudges: nudges.optional(),
131
+ sideTasks: z.array(sideTask).optional(),
132
+ afterEnd: z.enum(FLOW_AFTER_END_MODES).optional()
133
+ }).transform(({ $schema: _schema, ...flow }) => flow);
134
+
135
+ // src/format/migrate-flow.ts
136
+ var FORMAT_STEPS = {
137
+ // 1 → 2: новые поля («Дни и время», касания, «нода длится», «да/нет», попутные задачи) необязательные,
138
+ // без них сценарий ведёт себя как в версии 1. Меняется только номер версии.
139
+ 1: (flow) => flow
140
+ };
141
+ function migrateFlow(flow, from) {
142
+ let current = flow;
143
+ for (let version = from; version < AGENT_FLOW_FORMAT_VERSION; version += 1) {
144
+ const step = FORMAT_STEPS[version];
145
+ if (!step) throw new Error(`\u041D\u0435\u0442 \u0448\u0430\u0433\u0430 \u043F\u0435\u0440\u0435\u0432\u043E\u0434\u0430 \u0444\u043E\u0440\u043C\u0430\u0442\u0430 \u0441\u0446\u0435\u043D\u0430\u0440\u0438\u044F \u0441 \u0432\u0435\u0440\u0441\u0438\u0438 ${version}.`);
146
+ current = { ...step(current), version: version + 1 };
147
+ }
148
+ return current;
149
+ }
150
+
151
+ // src/format/parse-flow.ts
152
+ import { z as z2 } from "zod";
153
+ var russianMessages = z2.locales.ru().localeError;
154
+ var OTHERWISE_REMOVED = "\u0423\u0441\u043B\u043E\u0432\u0438\u044F \xAB\u0438\u043D\u0430\u0447\u0435\xBB \u0431\u043E\u043B\u044C\u0448\u0435 \u043D\u0435\u0442 (\u043F\u043E\u043B\u0435 `otherwise`): \u0435\u0441\u043B\u0438 \u043D\u0438 \u043E\u0434\u043D\u043E \u0443\u0441\u043B\u043E\u0432\u0438\u0435 \u043D\u0435 \u0441\u0440\u0430\u0431\u043E\u0442\u0430\u043B\u043E, \u0430\u0433\u0435\u043D\u0442 \u043E\u0441\u0442\u0430\u0451\u0442\u0441\u044F \u0432 \u0441\u043E\u0441\u0442\u043E\u044F\u043D\u0438\u0438. \u041E\u0431\u0449\u0435\u0435 \u0434\u043B\u044F \u0432\u0441\u0435\u0445 \u0441\u043E\u0441\u0442\u043E\u044F\u043D\u0438\u0439 \u2014 \u0446\u0435\u043D\u044B, \u0443\u0441\u043B\u043E\u0432\u0438\u044F, \u0442\u043E\u043D \u2014 \u043F\u0438\u0448\u0435\u0442\u0441\u044F \u0432 `common`.";
155
+ function parseFlow(input) {
156
+ let json = input;
157
+ if (typeof input === "string") {
158
+ try {
159
+ json = JSON.parse(input);
160
+ } catch (error) {
161
+ return failure("", `\u042D\u0442\u043E \u043D\u0435 JSON: ${error.message}`);
162
+ }
163
+ }
164
+ if (typeof json !== "object" || json === null || Array.isArray(json)) {
165
+ return failure("", "\u0421\u0446\u0435\u043D\u0430\u0440\u0438\u0439 \u2014 \u044D\u0442\u043E \u043E\u0431\u044A\u0435\u043A\u0442 JSON.");
166
+ }
167
+ const raw = json;
168
+ if (raw.format !== AGENT_FLOW_FORMAT) {
169
+ return failure("format", `\u042D\u0442\u043E \u043D\u0435 \u0441\u0446\u0435\u043D\u0430\u0440\u0438\u0439 agent-flow: \u0443 \u0441\u0446\u0435\u043D\u0430\u0440\u0438\u044F \u0434\u043E\u043B\u0436\u043D\u043E \u0431\u044B\u0442\u044C \u043F\u043E\u043B\u0435 "format": "${AGENT_FLOW_FORMAT}".`);
170
+ }
171
+ const version = raw.version;
172
+ if (typeof version !== "number" || !Number.isInteger(version) || version < 1) {
173
+ return failure("version", "\u041D\u043E\u043C\u0435\u0440 \u0432\u0435\u0440\u0441\u0438\u0438 \u0444\u043E\u0440\u043C\u0430\u0442\u0430 (`version`) \u2014 \u0446\u0435\u043B\u043E\u0435 \u0447\u0438\u0441\u043B\u043E \u043E\u0442 1.");
174
+ }
175
+ if (version > AGENT_FLOW_FORMAT_VERSION) {
176
+ return failure(
177
+ "version",
178
+ `\u0421\u0446\u0435\u043D\u0430\u0440\u0438\u0439 \u0437\u0430\u043F\u0438\u0441\u0430\u043D \u0432 \u0432\u0435\u0440\u0441\u0438\u0438 \u0444\u043E\u0440\u043C\u0430\u0442\u0430 ${version}, \u0430 \u044D\u0442\u043E\u0442 SDK \u0437\u043D\u0430\u0435\u0442 \u0432\u0435\u0440\u0441\u0438\u0438 \u0434\u043E ${AGENT_FLOW_FORMAT_VERSION}: \u043E\u0431\u043D\u043E\u0432\u0438\u0442\u0435 SDK.`
179
+ );
180
+ }
181
+ const parsed = agentFlowSchema.safeParse(migrateFlow(raw, version), { error: russianMessages });
182
+ if (parsed.success) return { ok: true, flow: parsed.data };
183
+ return { ok: false, errors: parsed.error.issues.flatMap(formatIssue) };
184
+ }
185
+ function formatIssue(issue) {
186
+ if (issue.code === "unrecognized_keys") {
187
+ return issue.keys.map((key) => ({
188
+ path: formatPath([...issue.path, key]),
189
+ message: key === "otherwise" ? OTHERWISE_REMOVED : `\u041D\u0435\u0438\u0437\u0432\u0435\u0441\u0442\u043D\u043E\u0435 \u043F\u043E\u043B\u0435 \xAB${key}\xBB.`
190
+ }));
191
+ }
192
+ if (issue.code === "invalid_union" && issue.discriminator) {
193
+ const options = issue.options ?? [];
194
+ const known = options.map((option) => `\xAB${String(option)}\xBB`).join(", ");
195
+ return [{ path: formatPath(issue.path), message: `\u041D\u0435\u0438\u0437\u0432\u0435\u0441\u0442\u043D\u043E\u0435 \u0437\u043D\u0430\u0447\u0435\u043D\u0438\u0435 \u043F\u043E\u043B\u044F \xAB${issue.discriminator}\xBB. \u041C\u043E\u0436\u043D\u043E: ${known}.` }];
196
+ }
197
+ return [{ path: formatPath(issue.path), message: issue.message }];
198
+ }
199
+ function formatPath(path) {
200
+ return path.reduce((text, key) => {
201
+ if (typeof key === "number") return `${text}[${key}]`;
202
+ return text ? `${text}.${String(key)}` : String(key);
203
+ }, "");
204
+ }
205
+ function failure(path, message) {
206
+ return { ok: false, errors: [{ path, message }] };
207
+ }
208
+
209
+ // src/format/catalog-events.ts
210
+ function catalogEventNames(catalog) {
211
+ return catalog.events.map((event) => typeof event === "string" ? event : event.name);
212
+ }
213
+ function catalogEventLabel(catalog, name) {
214
+ const found = catalog?.events.find((event) => typeof event !== "string" && event.name === name);
215
+ return typeof found === "object" ? found.label?.trim() || void 0 : void 0;
216
+ }
217
+
218
+ // src/format/compact-flow.ts
219
+ function compactFlow(flow) {
220
+ return withoutEmpty({
221
+ format: flow.format,
222
+ version: flow.version,
223
+ id: flow.id,
224
+ name: flow.name,
225
+ start: flow.start,
226
+ common: flow.common,
227
+ pace: flow.pace.sideQuestionEveryMessages === DEFAULT_SIDE_QUESTION_EVERY_MESSAGES ? void 0 : { sideQuestionEveryMessages: flow.pace.sideQuestionEveryMessages },
228
+ clientCard: flow.clientCard.map(compactField),
229
+ chatNotes: flow.chatNotes.map(compactField),
230
+ tools: flow.tools,
231
+ anyState: flow.anyState.except.length || flow.anyState.exits.length ? withoutEmpty({ except: flow.anyState.except, exits: flow.anyState.exits.map(compactExit) }) : void 0,
232
+ states: flow.states.map(compactState),
233
+ layout: Object.keys(flow.layout).length ? flow.layout : void 0,
234
+ schedule: flow.schedule && compactSchedule(flow.schedule),
235
+ nudges: flow.nudges,
236
+ sideTasks: flow.sideTasks?.map(compactSideTask),
237
+ afterEnd: flow.afterEnd
238
+ }, ["states"]);
239
+ }
240
+ function compactSchedule(schedule2) {
241
+ return withoutEmpty({
242
+ ...schedule2,
243
+ lateStartHours: schedule2.lateStartHours === DEFAULT_LATE_START_HOURS ? void 0 : schedule2.lateStartHours,
244
+ farewellOnDeadline: schedule2.farewellOnDeadline || void 0
245
+ });
246
+ }
247
+ function compactSideTask(task) {
248
+ return withoutEmpty({
249
+ ...task,
250
+ maxAttempts: task.maxAttempts === DEFAULT_SIDE_TASK_MAX_ATTEMPTS ? void 0 : task.maxAttempts,
251
+ perConversation: task.perConversation || void 0
252
+ });
253
+ }
254
+ function compactField(field) {
255
+ return withoutEmpty({ ...field, type: field.type === "text" ? void 0 : field.type });
256
+ }
257
+ function compactState(state) {
258
+ return withoutEmpty({
259
+ ...state,
260
+ kind: state.kind === "state" ? void 0 : state.kind,
261
+ noSideQuestions: state.noSideQuestions || void 0,
262
+ exits: state.exits.map(compactExit)
263
+ });
264
+ }
265
+ function compactExit(exit) {
266
+ const when = exit.when.type === "data" && exit.when.op === "filled" ? { ...exit.when, op: void 0 } : exit.when;
267
+ return withoutEmpty({ id: exit.id, when: withoutEmpty(when), to: exit.to });
268
+ }
269
+ function withoutEmpty(object, keep = []) {
270
+ return Object.fromEntries(
271
+ Object.entries(object).filter(([key, value]) => {
272
+ if (keep.includes(key)) return true;
273
+ if (value === void 0 || value === null || value === "") return false;
274
+ return !(Array.isArray(value) && value.length === 0);
275
+ })
276
+ );
277
+ }
278
+
279
+ // src/engine/flow-run.ts
280
+ var FLOW_STATE_KEY = "flow";
281
+ var FLOW_PATH_LIMIT = 50;
282
+ var FLOW_CHAIN_LIMIT = 5;
283
+ var DEFAULT_FIRST_MESSAGES = {
284
+ quietHours: { from: "21:00", to: "09:00" },
285
+ maxPerDay: 3
286
+ };
287
+
288
+ // src/engine/flow-graph.ts
289
+ function stateById(flow, id2) {
290
+ return id2 === null ? void 0 : flow.states.find((state) => state.id === id2);
291
+ }
292
+ function isFinal(state) {
293
+ return state.exits.length === 0;
294
+ }
295
+ function isTouch(state) {
296
+ return state.exits.some((exit) => exit.to === RETURN_TARGET);
297
+ }
298
+ function commonApplies(flow, state) {
299
+ return !isFinal(state) && !flow.anyState.except.includes(state.id);
300
+ }
301
+ function activeExits(flow, state) {
302
+ const own = state.exits.map((exit) => ({ exit, own: true }));
303
+ if (!commonApplies(flow, state)) return own;
304
+ const common = flow.anyState.exits.filter((exit) => exit.to !== state.id).map((exit) => ({ exit, own: false }));
305
+ return [...own, ...common];
306
+ }
307
+ function fieldById(flow, id2) {
308
+ const card = flow.clientCard.find((field) => field.id === id2);
309
+ if (card) return { field: card, place: "card" };
310
+ const note = flow.chatNotes.find((field) => field.id === id2);
311
+ return note ? { field: note, place: "notes" } : void 0;
312
+ }
313
+ function sameText(left, right) {
314
+ return left.trim().toLocaleLowerCase() === right.trim().toLocaleLowerCase();
315
+ }
316
+
317
+ // src/engine/data-conditions.ts
318
+ function fitsType(type, value) {
319
+ if (type === "number") return typeof value === "number" && Number.isFinite(value);
320
+ if (type === "boolean") return typeof value === "boolean";
321
+ return typeof value === "string" && value.trim() !== "";
322
+ }
323
+ var YES_WORDS = /* @__PURE__ */ new Set(["\u0434\u0430", "yes", "true"]);
324
+ var NO_WORDS = /* @__PURE__ */ new Set(["\u043D\u0435\u0442", "no", "false"]);
325
+ function parseBooleanAnswer(raw) {
326
+ if (typeof raw === "boolean") return raw;
327
+ if (typeof raw !== "string") return void 0;
328
+ const word = raw.trim().toLocaleLowerCase().replace(/[.!\s]+$/u, "");
329
+ if (YES_WORDS.has(word)) return true;
330
+ return NO_WORDS.has(word) ? false : void 0;
331
+ }
332
+ function fieldValueFits(field, value) {
333
+ if (!fitsType(field.type, value)) return false;
334
+ if (field.type !== "choice" || field.options.length === 0) return true;
335
+ return field.options.some((option) => sameText(option, value));
336
+ }
337
+ function dataConditionHolds(condition, fieldType, value) {
338
+ if (!FLOW_OPS_BY_FIELD_TYPE[fieldType].includes(condition.op)) return false;
339
+ if (!fitsType(fieldType, value)) return false;
340
+ const expected = condition.value;
341
+ switch (condition.op) {
342
+ case "filled":
343
+ return true;
344
+ case "eq":
345
+ if (fieldType === "number" || fieldType === "boolean") return value === expected;
346
+ return typeof expected === "string" && sameText(value, expected);
347
+ case "ne":
348
+ return typeof expected === "boolean" && value !== expected;
349
+ case "gt":
350
+ return typeof expected === "number" && value > expected;
351
+ case "lt":
352
+ return typeof expected === "number" && value < expected;
353
+ case "contains":
354
+ return typeof expected === "string" && expected.trim() !== "" && value.toLocaleLowerCase().includes(expected.trim().toLocaleLowerCase());
355
+ }
356
+ }
357
+
358
+ // src/engine/targets.ts
359
+ function returnTarget(flow, run) {
360
+ for (let index = run.path.length - 1; index >= 0; index -= 1) {
361
+ const id2 = run.path[index].state;
362
+ if (id2 === run.state) continue;
363
+ const state = stateById(flow, id2);
364
+ if (state && !isTouch(state)) return state;
365
+ }
366
+ return stateById(flow, flow.start);
367
+ }
368
+ function exitTarget(flow, run, to) {
369
+ if (to === null) return void 0;
370
+ if (to !== RETURN_TARGET) {
371
+ const state2 = stateById(flow, to);
372
+ return state2 ? { state: state2, returned: false } : void 0;
373
+ }
374
+ const state = returnTarget(flow, run);
375
+ return state && state.id !== run.state ? { state, returned: true } : void 0;
376
+ }
377
+
378
+ // src/engine/zoned-time.ts
379
+ var formatters = /* @__PURE__ */ new Map();
380
+ function formatterFor(timeZone) {
381
+ let formatter = formatters.get(timeZone);
382
+ if (!formatter) {
383
+ const options = {
384
+ year: "numeric",
385
+ month: "numeric",
386
+ day: "numeric",
387
+ hour: "numeric",
388
+ minute: "numeric",
389
+ second: "numeric",
390
+ hourCycle: "h23"
391
+ };
392
+ try {
393
+ formatter = new Intl.DateTimeFormat("en-US", { ...options, timeZone });
394
+ } catch {
395
+ formatter = new Intl.DateTimeFormat("en-US", { ...options, timeZone: "UTC" });
396
+ }
397
+ formatters.set(timeZone, formatter);
398
+ }
399
+ return formatter;
400
+ }
401
+ function zonedParts(at, timeZone) {
402
+ const parts = {};
403
+ for (const part of formatterFor(timeZone).formatToParts(at)) {
404
+ if (part.type !== "literal") parts[part.type] = Number(part.value);
405
+ }
406
+ return {
407
+ year: parts.year,
408
+ month: parts.month,
409
+ day: parts.day,
410
+ hour: parts.hour % 24,
411
+ minute: parts.minute,
412
+ second: parts.second
413
+ };
414
+ }
415
+ function offsetAt(at, timeZone) {
416
+ const parts = zonedParts(at, timeZone);
417
+ const wall = Date.UTC(parts.year, parts.month - 1, parts.day, parts.hour, parts.minute, parts.second);
418
+ return wall - Math.floor(at / 1e3) * 1e3;
419
+ }
420
+ function zonedTime(date, minutes, timeZone) {
421
+ const wall = Date.UTC(date.year, date.month - 1, date.day, 0, minutes);
422
+ const first = wall - offsetAt(wall, timeZone);
423
+ const second = wall - offsetAt(first, timeZone);
424
+ return second;
425
+ }
426
+ function nextDate(date, days = 1) {
427
+ const moved = new Date(Date.UTC(date.year, date.month - 1, date.day + days));
428
+ return { year: moved.getUTCFullYear(), month: moved.getUTCMonth() + 1, day: moved.getUTCDate() };
429
+ }
430
+ function parseClock(clock2) {
431
+ const match = /^([01]\d|2[0-3]):([0-5]\d)$/.exec(clock2);
432
+ return match ? Number(match[1]) * 60 + Number(match[2]) : null;
433
+ }
434
+ function clockMinutes(at, timeZone) {
435
+ const parts = zonedParts(at, timeZone);
436
+ return parts.hour * 60 + parts.minute;
437
+ }
438
+ function nextClockTime(after, minutes, timeZone) {
439
+ let date = zonedParts(after, timeZone);
440
+ for (let attempt = 0; attempt < 3; attempt += 1) {
441
+ const candidate = zonedTime(date, minutes, timeZone);
442
+ if (candidate > after) return candidate;
443
+ date = nextDate(date);
444
+ }
445
+ return zonedTime(date, minutes, timeZone);
446
+ }
447
+ function startOfNextDay(at, timeZone) {
448
+ return zonedTime(nextDate(zonedParts(at, timeZone)), 0, timeZone);
449
+ }
450
+ function localDay(at, timeZone) {
451
+ const { year, month, day } = zonedParts(at, timeZone);
452
+ return `${year}-${String(month).padStart(2, "0")}-${String(day).padStart(2, "0")}`;
453
+ }
454
+
455
+ // src/engine/flow-days.ts
456
+ var DAY_MINUTES = 24 * 60;
457
+ var DAY_MS = 864e5;
458
+ var dayStartMinutes = (schedule2) => parseClock(schedule2.dayStart) ?? 0;
459
+ var nightMinutes = (schedule2) => parseClock(schedule2.nightFrom ?? DEFAULT_FIRST_MESSAGES.quietHours.from) ?? 0;
460
+ var dateKey = ({ year, month, day }) => `${year}-${String(month).padStart(2, "0")}-${String(day).padStart(2, "0")}`;
461
+ var dateOf = (key) => {
462
+ const [year, month, day] = key.split("-").map(Number);
463
+ return { year, month, day };
464
+ };
465
+ var shiftDate = (key, days) => dateKey(nextDate(dateOf(key), days));
466
+ var daysBetween = (from, to) => {
467
+ const [a, b] = [dateOf(from), dateOf(to)];
468
+ return Math.round((Date.UTC(b.year, b.month - 1, b.day) - Date.UTC(a.year, a.month - 1, a.day)) / DAY_MS);
469
+ };
470
+ var later = (a, b) => a > b ? a : b;
471
+ var eveningNight = (schedule2) => nightMinutes(schedule2) > dayStartMinutes(schedule2);
472
+ function dayOf(at, timeZone, schedule2) {
473
+ const today = localDay(at, timeZone);
474
+ return eveningNight(schedule2) && clockMinutes(at, timeZone) >= nightMinutes(schedule2) ? shiftDate(today, 1) : today;
475
+ }
476
+ function dayInProgress(at, timeZone, schedule2) {
477
+ const today = localDay(at, timeZone);
478
+ return clockMinutes(at, timeZone) < dayStartMinutes(schedule2) ? shiftDate(today, -1) : today;
479
+ }
480
+ function dayStartAt(localDate, timeZone, schedule2) {
481
+ return zonedTime(dateOf(localDate), dayStartMinutes(schedule2), timeZone);
482
+ }
483
+ function nextDayStartAfter(at, timeZone, schedule2) {
484
+ return dayStartAt(shiftDate(dayInProgress(at, timeZone, schedule2), 1), timeZone, schedule2);
485
+ }
486
+ function firstDayOf(startedAt, timeZone, schedule2) {
487
+ const first = dayOf(startedAt, timeZone, schedule2);
488
+ const threshold = (schedule2.lateStartHours ?? DEFAULT_LATE_START_HOURS) * 60;
489
+ const clock2 = clockMinutes(startedAt, timeZone);
490
+ if (threshold <= 0 || clock2 < dayStartMinutes(schedule2) || first !== localDay(startedAt, timeZone)) return first;
491
+ const untilNight = (nightMinutes(schedule2) - clock2 + DAY_MINUTES) % DAY_MINUTES;
492
+ return untilNight < threshold ? shiftDate(first, 1) : first;
493
+ }
494
+ var lastActivity = (run) => Math.max(run.startedAt, run.enteredAt, run.lastHumanAt ?? 0, run.lastAgentAt ?? 0);
495
+ function dayAnchor(run, timeZone, schedule2) {
496
+ const fresh = () => dayStartAt(firstDayOf(run.startedAt, timeZone, schedule2), timeZone, schedule2);
497
+ const stored = run.dayAnchorAt;
498
+ if (stored === void 0) return fresh();
499
+ if (clockMinutes(stored, timeZone) === dayStartMinutes(schedule2)) return stored;
500
+ const around = localDay(stored, timeZone);
501
+ const moved = [-1, 0, 1].map((shift) => dayStartAt(shiftDate(around, shift), timeZone, schedule2)).reduce((best, candidate) => Math.abs(candidate - stored) < Math.abs(best - stored) ? candidate : best);
502
+ const dayNow = daysBetween(localDay(moved, timeZone), dayInProgress(lastActivity(run), timeZone, schedule2)) + 1;
503
+ return dayNow <= 1 ? fresh() : moved;
504
+ }
505
+ var anchorDate = (run, timeZone, schedule2) => localDay(dayAnchor(run, timeZone, schedule2), timeZone);
506
+ function stateDaysDue(run, days, timeZone, schedule2) {
507
+ const entered = later(dayOf(run.enteredAt, timeZone, schedule2), anchorDate(run, timeZone, schedule2));
508
+ return dayStartAt(shiftDate(entered, days), timeZone, schedule2);
509
+ }
510
+ function programDayDue(run, day, timeZone, schedule2) {
511
+ return dayStartAt(shiftDate(anchorDate(run, timeZone, schedule2), day - 1), timeZone, schedule2);
512
+ }
513
+ function flowDay(run, now, timeZone, schedule2) {
514
+ const first = anchorDate(run, timeZone, schedule2);
515
+ const current = later(dayInProgress(now, timeZone, schedule2), shiftDate(first, -1));
516
+ const day = Math.max(0, daysBetween(first, current) + 1);
517
+ const today = day === 0 ? shiftDate(first, -1) : current;
518
+ return {
519
+ day,
520
+ ...schedule2.lengthDays !== void 0 && { totalDays: schedule2.lengthDays },
521
+ isLastDay: schedule2.lengthDays !== void 0 && day === schedule2.lengthDays,
522
+ dayStartedAt: dayStartAt(today, timeZone, schedule2),
523
+ nextDayStartAt: dayStartAt(shiftDate(today, 1), timeZone, schedule2)
524
+ };
525
+ }
526
+ function deadlineAt(run, timeZone, schedule2) {
527
+ if (schedule2.lengthDays === void 0) return null;
528
+ return dayStartAt(shiftDate(anchorDate(run, timeZone, schedule2), schedule2.lengthDays), timeZone, schedule2);
529
+ }
530
+ function beforeFirstNight(run, now, timeZone, schedule2) {
531
+ const first = anchorDate(run, timeZone, schedule2);
532
+ const nightDate = eveningNight(schedule2) ? first : shiftDate(first, 1);
533
+ return now < zonedTime(dateOf(nightDate), nightMinutes(schedule2), timeZone);
534
+ }
535
+ function withDayAnchor(run, timeZone, schedule2) {
536
+ if (!schedule2) return run;
537
+ const dayAnchorAt = dayAnchor(run, timeZone, schedule2);
538
+ return run.dayAnchorAt === dayAnchorAt ? run : { ...run, dayAnchorAt };
539
+ }
540
+ function clockText(at, timeZone) {
541
+ const { hour, minute } = zonedParts(at, timeZone);
542
+ return `${String(hour).padStart(2, "0")}:${String(minute).padStart(2, "0")}`;
543
+ }
544
+
545
+ // src/engine/nudges.ts
546
+ function stateNudges(flow, stateId) {
547
+ const own = stateById(flow, stateId)?.nudges;
548
+ if (own === "off") return null;
549
+ return own ?? flow.schedule?.nudges ?? flow.nudges ?? null;
550
+ }
551
+ var CALENDAR_DAYS = { dayStart: "00:00", lateStartHours: 0, farewellOnDeadline: false };
552
+ function nudgeRings(flow, run, timeZone) {
553
+ const own = stateById(flow, run.state)?.nudges;
554
+ if (own === "off") return null;
555
+ const common = flow.schedule?.nudges ?? flow.nudges ?? null;
556
+ if (!own) return common && { ring: common };
557
+ if (own.days === void 0) return { ring: own };
558
+ const schedule2 = flow.schedule ?? CALENDAR_DAYS;
559
+ const entryDay = flowDay(run, run.enteredAt, timeZone, schedule2).day;
560
+ return { ring: own, until: programDayDue(run, entryDay + own.days, timeZone, schedule2), after: common };
561
+ }
562
+ var UNIT_MS = { min: 6e4, h: 36e5, d: 864e5 };
563
+ var durationMs = (duration2) => duration2.amount * UNIT_MS[duration2.unit];
564
+ var DEFAULT_SKIP_MORNING_MIN = 180;
565
+ function nextNudge(flow, run, now, timeZone, context = {}) {
566
+ const rings = nudgesRunning(flow, run, timeZone, context);
567
+ if (!rings || run.lastAgentAt === null) return null;
568
+ const base = Math.max(run.lastAgentAt, context.pausedUntil ?? 0, context.undeliveredAt ?? 0);
569
+ const step = run.nudgeStep ?? 0;
570
+ let nudge = null;
571
+ if (rings.until === void 0) nudge = ringNudge(rings.ring, base, step, timeZone);
572
+ else {
573
+ const own = base < rings.until ? ringNudge(rings.ring, base, step, timeZone) : null;
574
+ if (own && own.at < rings.until) nudge = { ...own, own: true };
575
+ else if (rings.after) nudge = ringNudge(rings.after, Math.max(base, rings.until), run.nudgeStepOwn || base < rings.until ? 0 : step, timeZone);
576
+ }
577
+ const giveUp = giveUpAt(flow, run, timeZone, context);
578
+ if (giveUp !== null && (!nudge || giveUp <= nudge.at || giveUp <= now)) return { at: giveUp, reason: { kind: "give_up" } };
579
+ return nudge;
580
+ }
581
+ function ringNudge(ring, base, step, timeZone) {
582
+ const silence = ring.afterSilence[step];
583
+ if (silence) return { at: base + durationMs(silence), reason: { kind: "silence", step: step + 1 } };
584
+ let nudge = null;
585
+ for (const clock2 of ring.dailyAt ?? []) {
586
+ const minutes = parseClock(clock2);
587
+ if (minutes === null) continue;
588
+ const at = nextClockTime(base, minutes, timeZone);
589
+ if (!nudge || at < nudge.at) nudge = { at, reason: { kind: "daily", at: clock2 } };
590
+ }
591
+ return nudge;
592
+ }
593
+ function nudgesRunning(flow, run, timeZone, context) {
594
+ const rings = nudgeRings(flow, run, timeZone);
595
+ if (!rings || run.endedAt !== void 0 || run.lastAgentAt === null) return null;
596
+ if (run.lastHumanAt !== null && run.lastHumanAt > run.lastAgentAt || (context.unanswered ?? 0) > 0) return null;
597
+ return rings;
598
+ }
599
+ function giveUpAt(flow, run, timeZone, context = {}) {
600
+ const rings = nudgesRunning(flow, run, timeZone, context);
601
+ const giveUpAfter = rings && (rings.ring.giveUpAfter ?? (rings.until !== void 0 ? rings.after?.giveUpAfter : void 0));
602
+ return giveUpAfter ? Math.max(run.lastHumanAt ?? run.startedAt, context.pausedUntil ?? 0) + durationMs(giveUpAfter) : null;
603
+ }
604
+ var morningOn = (schedule2) => schedule2.firstMessages?.morning ?? schedule2.lengthDays !== void 0;
605
+ function nextMorning(flow, run, timeZone, context = {}) {
606
+ const schedule2 = flow.schedule;
607
+ if (!schedule2 || !morningOn(schedule2) || run.endedAt !== void 0) return null;
608
+ const skipMs = (schedule2.firstMessages?.skipMorningIfHumanWithinMin ?? DEFAULT_SKIP_MORNING_MIN) * 6e4;
609
+ const since = Math.max(run.lastAgentAt ?? run.startedAt, context.undeliveredAt ?? 0);
610
+ let morning = flowDay(run, since, timeZone, schedule2).nextDayStartAt;
611
+ for (let day = 0; day < 3; day += 1) {
612
+ const humanJustWrote = run.lastHumanAt !== null && run.lastHumanAt < morning && morning - run.lastHumanAt < skipMs;
613
+ const paused = (context.pausedUntil ?? 0) > morning;
614
+ if (!humanJustWrote && !paused) return morning;
615
+ morning = flowDay(run, morning, timeZone, schedule2).nextDayStartAt;
616
+ }
617
+ return morning;
618
+ }
619
+ var HELD_AT_DAY_START = /* @__PURE__ */ new Set(["morning", "silence", "daily"]);
620
+ function dayStartHoldUntil(flow, run, now, timeZone, reasons) {
621
+ const schedule2 = flow.schedule;
622
+ if (!schedule2 || run.lastHumanAt === null || !reasons.every((reason) => HELD_AT_DAY_START.has(reason.kind))) return null;
623
+ const until = run.lastHumanAt + (schedule2.firstMessages?.skipMorningIfHumanWithinMin ?? DEFAULT_SKIP_MORNING_MIN) * 6e4;
624
+ if (until <= now) return null;
625
+ return run.lastHumanAt < flowDay(run, now, timeZone, schedule2).dayStartedAt ? until : null;
626
+ }
627
+ function nextNightReply(flow, run, timeZone, context = {}) {
628
+ if (!(context.unanswered ?? 0) || run.endedAt !== void 0) return null;
629
+ const last = Math.max(run.lastAgentAt ?? 0, run.lastHumanAt ?? 0, run.startedAt, context.undeliveredAt ?? 0);
630
+ return flow.schedule ? flowDay(run, last, timeZone, flow.schedule).nextDayStartAt : last;
631
+ }
632
+
633
+ // src/engine/timers.ts
634
+ var FLOW_DEADLINE_EXIT = "@deadline";
635
+ var UNIT_MS2 = { min: 6e4, h: 36e5, d: 864e5 };
636
+ function actualEntry(run) {
637
+ const last = run.path.at(-1);
638
+ return last && last.state === run.state ? last.at : run.enteredAt;
639
+ }
640
+ function timerDueAt(condition, run, timeZone, schedule2) {
641
+ switch (condition.from) {
642
+ case "in_state":
643
+ return run.enteredAt + condition.amount * UNIT_MS2[condition.unit];
644
+ case "since_start":
645
+ return run.startedAt + condition.amount * UNIT_MS2[condition.unit];
646
+ case "silence":
647
+ if (run.lastAgentAt === null) return null;
648
+ if (run.lastHumanAt !== null && run.lastHumanAt > run.lastAgentAt) return null;
649
+ return run.lastAgentAt + condition.amount * UNIT_MS2[condition.unit];
650
+ case "time_of_day": {
651
+ const minutes = parseClock(condition.at);
652
+ return minutes === null ? null : nextClockTime(actualEntry(run), minutes, timeZone);
653
+ }
654
+ case "state_days":
655
+ return schedule2 ? stateDaysDue(run, condition.days, timeZone, schedule2) : null;
656
+ case "program_day":
657
+ return schedule2 ? programDayDue(run, condition.day, timeZone, schedule2) : null;
658
+ }
659
+ }
660
+ var ENTRY_FREE_TIMERS = /* @__PURE__ */ new Set(["since_start", "program_day"]);
661
+ function overdueOnEntry(flow, run, now, timeZone) {
662
+ const state = stateById(flow, run.state);
663
+ if (!state) return null;
664
+ let best = null;
665
+ for (const { exit } of activeExits(flow, state)) {
666
+ if (exit.when.type !== "timer" || !ENTRY_FREE_TIMERS.has(exit.when.from) || !exitTarget(flow, run, exit.to)) continue;
667
+ const at = timerDueAt(exit.when, run, timeZone, flow.schedule);
668
+ if (at !== null && at <= now && (best === null || at < best.at)) best = { at, exitId: exit.id };
669
+ }
670
+ return best?.exitId ?? null;
671
+ }
672
+ function nextDue(flow, run, _now, timeZone) {
673
+ if (run.endedAt !== void 0) return null;
674
+ const state = stateById(flow, run.state);
675
+ if (!state) return null;
676
+ let best = null;
677
+ for (const { exit } of activeExits(flow, state)) {
678
+ if (exit.when.type !== "timer" || !exitTarget(flow, run, exit.to)) continue;
679
+ const at = timerDueAt(exit.when, run, timeZone, flow.schedule);
680
+ if (at !== null && (best === null || at < best.at)) best = { at, exitId: exit.id };
681
+ }
682
+ const deadline = flow.schedule ? deadlineAt(run, timeZone, flow.schedule) : null;
683
+ if (deadline !== null && (best === null || deadline <= best.at)) best = { at: deadline, exitId: FLOW_DEADLINE_EXIT };
684
+ return best;
685
+ }
686
+ var FLOW_FIRST_EXIT = "@first";
687
+ var FLOW_GIVE_UP_EXIT = "@give_up";
688
+ function firstMessageDues(flow, run, now, timeZone, context) {
689
+ const nudge = nextNudge(flow, run, now, timeZone, context);
690
+ const morning = nextMorning(flow, run, timeZone, context);
691
+ const night = nextNightReply(flow, run, timeZone, context);
692
+ const dues = [];
693
+ if (morning !== null) dues.push({ at: morning, reason: { kind: "morning" } });
694
+ if (night !== null) dues.push({ at: night, reason: { kind: "night_messages", count: context.unanswered ?? 0 } });
695
+ if (nudge && nudge.reason.kind !== "give_up") dues.push({ at: nudge.at, reason: nudge.reason });
696
+ return { dues, giveUp: nudge?.reason.kind === "give_up" ? nudge.at : null, ownNudge: nudge?.own === true };
697
+ }
698
+ function nextWake(flow, run, now, timeZone, context = {}) {
699
+ if (run.endedAt !== void 0) return null;
700
+ let best = nextDue(flow, run, now, timeZone);
701
+ const { dues, giveUp } = firstMessageDues(flow, run, now, timeZone, context);
702
+ const deadlineFirst = best?.exitId === FLOW_DEADLINE_EXIT;
703
+ if (giveUp !== null && (best === null || giveUp < best.at || giveUp === best.at && !deadlineFirst)) best = { at: giveUp, exitId: FLOW_GIVE_UP_EXIT };
704
+ for (const due of dues) if (best === null || due.at < best.at) best = { at: due.at, exitId: FLOW_FIRST_EXIT };
705
+ return best;
706
+ }
707
+ function dueReasons(flow, run, now, timeZone, context = {}) {
708
+ const none = { deadline: false, giveUp: false, exitId: null, reasons: [] };
709
+ if (run.endedAt !== void 0) return none;
710
+ const exit = nextDue(flow, run, now, timeZone);
711
+ const deadline = flow.schedule ? deadlineAt(run, timeZone, flow.schedule) : null;
712
+ if (deadline !== null && deadline <= now) return { ...none, deadline: true };
713
+ const { dues, giveUp, ownNudge } = firstMessageDues(flow, run, now, timeZone, context);
714
+ if (giveUp !== null && giveUp <= now) return { ...none, giveUp: true };
715
+ const exitId = exit && exit.at <= now ? exit.exitId : null;
716
+ const morning = dues.some((due) => due.at <= now && due.reason.kind === "morning");
717
+ const reasons = dues.filter((due) => due.at <= now && !((exitId || morning) && (due.reason.kind === "silence" || due.reason.kind === "daily"))).map((due) => due.reason);
718
+ const nudged = reasons.some((reason) => reason.kind === "silence" || reason.kind === "daily");
719
+ return { ...none, exitId, reasons, ...ownNudge && nudged && { ownNudge: true } };
720
+ }
721
+ function nextFirstMessageAfter(flow, run, now, timeZone, context = {}) {
722
+ if (run.endedAt !== void 0) return null;
723
+ const ahead = firstMessageDues(flow, run, now, timeZone, context).dues.filter((due) => due.at > now);
724
+ return ahead.length === 0 ? null : Math.min(...ahead.map((due) => due.at));
725
+ }
726
+ function endingWake(flow, run, now, timeZone, context) {
727
+ if (run.endedAt !== void 0) return null;
728
+ const deadline = flow.schedule ? deadlineAt(run, timeZone, flow.schedule) : null;
729
+ const giveUp = giveUpAt(flow, run, timeZone, context);
730
+ const candidates = [
731
+ ...deadline !== null && deadline > now ? [{ at: deadline, exitId: FLOW_DEADLINE_EXIT }] : [],
732
+ ...giveUp !== null && giveUp > now ? [{ at: giveUp, exitId: FLOW_GIVE_UP_EXIT }] : []
733
+ ];
734
+ return earliest(candidates);
735
+ }
736
+ var earliest = (dues) => dues.reduce((best, due) => best === null || due.at < best.at ? due : best, null);
737
+ function deferredWake(flow, run, now, timeZone, context, retry) {
738
+ if (run.endedAt !== void 0) return null;
739
+ const exit = nextDue(flow, run, now, timeZone);
740
+ const ending = endingWake(flow, run, now, timeZone, context);
741
+ return earliest([
742
+ ...exit && exit.at > now && exit.exitId !== FLOW_DEADLINE_EXIT ? [exit] : [],
743
+ ...ending ? [ending] : [],
744
+ ...retry.at !== null ? [{ at: Math.max(retry.at, now), exitId: retry.exitId }] : []
745
+ ]);
746
+ }
747
+
748
+ // src/engine/next-transition.ts
749
+ function matches(flow, run, exitId, when, event, now) {
750
+ switch (event.type) {
751
+ case "event":
752
+ if (when.type !== "event" || when.event !== event.event) return false;
753
+ return when.event === "message" || when.name === void 0 || when.name === event.name;
754
+ case "data": {
755
+ if (when.type !== "data" || event.field !== void 0 && when.field !== event.field) return false;
756
+ const found = fieldById(flow, when.field);
757
+ if (!found) return false;
758
+ const value = found.place === "notes" ? run.notes[when.field] : event.card?.[when.field];
759
+ return dataConditionHolds(when, found.field.type, value);
760
+ }
761
+ case "verdict":
762
+ return exitId === event.exitId && when.type === "judge";
763
+ case "timer": {
764
+ if (exitId !== event.exitId || when.type !== "timer") return false;
765
+ const due = timerDueAt(when, run, event.timeZone, flow.schedule);
766
+ return due !== null && due <= now;
767
+ }
768
+ }
769
+ }
770
+ var UNITS = { min: "\u043C\u0438\u043D", h: "\u0447", d: "\u0434" };
771
+ var DATA_SIGNS = { eq: "=", ne: "\u2260", gt: ">", lt: "<", contains: "\u0441\u043E\u0434\u0435\u0440\u0436\u0438\u0442" };
772
+ function daysText(days) {
773
+ const last = days % 10;
774
+ const tens = days % 100;
775
+ const word = last === 1 && tens !== 11 ? "\u0434\u0435\u043D\u044C" : last >= 2 && last <= 4 && (tens < 12 || tens > 14) ? "\u0434\u043D\u044F" : "\u0434\u043D\u0435\u0439";
776
+ return `${days} ${word}`;
777
+ }
778
+ var valueText = (value) => value === true ? "\u0434\u0430" : value === false ? "\u043D\u0435\u0442" : String(value);
779
+ function describeCondition(flow, when, catalog) {
780
+ switch (when.type) {
781
+ case "judge":
782
+ return when.text;
783
+ case "data": {
784
+ const field = flow.clientCard.find((item) => item.id === when.field) ?? flow.chatNotes.find((item) => item.id === when.field);
785
+ const name = `\xAB${field?.name ?? when.field}\xBB`;
786
+ return when.op === "filled" ? `\u0443\u0437\u043D\u0430\u043B\u0438 ${name}` : `${name} ${DATA_SIGNS[when.op]} ${valueText(when.value)}`;
787
+ }
788
+ case "event": {
789
+ if (when.event === "message") return "\u0447\u0435\u043B\u043E\u0432\u0435\u043A \u043D\u0430\u043F\u0438\u0441\u0430\u043B";
790
+ if (when.event === "tool") return `\u0432\u044B\u0437\u0432\u0430\u043D \u0438\u043D\u0441\u0442\u0440\u0443\u043C\u0435\u043D\u0442 \xAB${when.name ?? ""}\xBB`;
791
+ const name = (when.name && catalogEventLabel(catalog, when.name)) ?? when.name ?? "";
792
+ return when.event === "button" ? `\u043D\u0430\u0436\u0430\u0442\u0430 \u043A\u043D\u043E\u043F\u043A\u0430 \xAB${name}\xBB` : `\u0441\u043E\u0431\u044B\u0442\u0438\u0435 \xAB${name}\xBB`;
793
+ }
794
+ case "timer":
795
+ if (when.from === "time_of_day") return `\u043D\u0430\u0441\u0442\u0443\u043F\u0438\u043B\u043E ${when.at}`;
796
+ if (when.from === "state_days") return `\u043D\u043E\u0434\u0430 \u0434\u043B\u0438\u0442\u0441\u044F ${daysText(when.days)}`;
797
+ if (when.from === "program_day") return `\u043D\u0430\u0441\u0442\u0443\u043F\u0438\u043B \u0434\u0435\u043D\u044C ${when.day}`;
798
+ if (when.from === "silence") return `\u0442\u0438\u0448\u0438\u043D\u0430 ${when.amount} ${UNITS[when.unit]}`;
799
+ if (when.from === "in_state") return `\u0432 \u0441\u043E\u0441\u0442\u043E\u044F\u043D\u0438\u0438 ${when.amount} ${UNITS[when.unit]}`;
800
+ return `\u0441 \u043D\u0430\u0447\u0430\u043B\u0430 \u0440\u0430\u0437\u0433\u043E\u0432\u043E\u0440\u0430 ${when.amount} ${UNITS[when.unit]}`;
801
+ }
802
+ }
803
+ function reasonOf(flow, event, when) {
804
+ const claimed = event.type === "verdict" ? event.why?.trim() : void 0;
805
+ return { kind: deciderOf(event), text: claimed || describeCondition(flow, when) };
806
+ }
807
+ var deciderOf = (event) => event.type === "verdict" ? event.decidedBy : event.type;
808
+ function nextTransition(flow, run, event, now) {
809
+ if (run.chain >= FLOW_CHAIN_LIMIT) return null;
810
+ const state = stateById(flow, run.state);
811
+ if (!state) return null;
812
+ for (const { exit } of activeExits(flow, state)) {
813
+ if (!matches(flow, run, exit.id, exit.when, event, now)) continue;
814
+ const target = exitTarget(flow, run, exit.to);
815
+ if (!target) continue;
816
+ return {
817
+ from: run.state,
818
+ to: target.state.id,
819
+ exitId: exit.id,
820
+ decidedBy: deciderOf(event),
821
+ ...event.type === "verdict" ? { probability: event.probability } : {},
822
+ tags: target.state.tags,
823
+ at: now,
824
+ ...target.returned ? { returned: true } : {},
825
+ reason: reasonOf(flow, event, exit.when)
826
+ };
827
+ }
828
+ return null;
829
+ }
830
+
831
+ // src/engine/run-updates.ts
832
+ function startRun(flow, now) {
833
+ const start = stateById(flow, flow.start);
834
+ if (!start) throw new Error(`\u0421\u0446\u0435\u043D\u0430\u0440\u0438\u0439 \xAB${flow.id}\xBB \u0431\u0435\u0437 \u0441\u0442\u0430\u0440\u0442\u0430: \u0441\u0442\u0430\u0440\u0442\u043E\u0432\u043E\u0435 \u0441\u043E\u0441\u0442\u043E\u044F\u043D\u0438\u0435 \u043D\u0435 \u0432\u044B\u0431\u0440\u0430\u043D\u043E \u0438\u043B\u0438 \u0435\u0433\u043E \u043D\u0435\u0442.`);
835
+ return {
836
+ state: start.id,
837
+ enteredAt: now,
838
+ startedAt: now,
839
+ path: [{ state: start.id, at: now, tags: start.tags, from: null, exitId: null, decidedBy: "start" }],
840
+ pausedClocks: {},
841
+ notes: {},
842
+ humanMessages: 0,
843
+ agentAnswers: 0,
844
+ sideQuestionAt: null,
845
+ lastRejected: null,
846
+ lastAgentAt: null,
847
+ lastHumanAt: null,
848
+ chain: 0
849
+ };
850
+ }
851
+ function appendPath(path, entry) {
852
+ return [...path, entry].slice(-FLOW_PATH_LIMIT);
853
+ }
854
+ function applyTransition(flow, run, transition) {
855
+ const from = stateById(flow, transition.from);
856
+ const to = stateById(flow, transition.to);
857
+ let enteredAt = transition.at;
858
+ let pausedClocks = {};
859
+ if (transition.returned) {
860
+ enteredAt = transition.at - (run.pausedClocks[transition.to] ?? 0);
861
+ } else if (to && isTouch(to)) {
862
+ pausedClocks = from && !isTouch(from) ? { [from.id]: transition.at - run.enteredAt } : run.pausedClocks;
863
+ }
864
+ return {
865
+ ...run,
866
+ state: transition.to,
867
+ enteredAt,
868
+ pausedClocks,
869
+ path: appendPath(run.path, {
870
+ state: transition.to,
871
+ at: transition.at,
872
+ tags: transition.tags,
873
+ from: transition.from,
874
+ exitId: transition.exitId,
875
+ decidedBy: transition.decidedBy,
876
+ ...transition.probability === void 0 ? {} : { probability: transition.probability },
877
+ ...transition.reason === void 0 ? {} : { reason: transition.reason }
878
+ }),
879
+ chain: run.chain + 1,
880
+ lastRejected: null
881
+ };
882
+ }
883
+ function noteHumanMessage(run, now, dayKey, count = 1) {
884
+ return {
885
+ ...run,
886
+ humanMessages: run.humanMessages + count,
887
+ lastHumanAt: now,
888
+ chain: 0,
889
+ ...run.nudgeStep === void 0 ? {} : { nudgeStep: 0 },
890
+ ...run.serverTurns === void 0 ? {} : { serverTurns: 0 },
891
+ ...dayKey === void 0 ? {} : { dayCounts: { [dayKey]: (run.dayCounts?.[dayKey] ?? 0) + count } }
892
+ };
893
+ }
894
+ function noteAgentAnswer(run, now) {
895
+ return { ...run, agentAnswers: run.agentAnswers + 1, lastAgentAt: now, chain: 0 };
896
+ }
897
+ function withoutUndeliveredTouch(run, undelivered) {
898
+ const touch = run.touch;
899
+ if (!touch || !undelivered.has(touch.answerId)) return { run, undeliveredAt: null };
900
+ const { touch: _touch, ...rest } = run;
901
+ return {
902
+ run: { ...withoutOwnStep(rest), lastAgentAt: touch.lastAgentAt, nudgeStep: touch.nudgeStep, ...touch.nudgeStepOwn && { nudgeStepOwn: true }, agentAnswers: touch.agentAnswers },
903
+ undeliveredAt: touch.at
904
+ };
905
+ }
906
+ function noteRejectedClaim(run, exitId) {
907
+ return { ...run, lastRejected: { exitId, atHumanMessages: run.humanMessages } };
908
+ }
909
+ function claimAllowed(run, exitId) {
910
+ return !(run.lastRejected?.exitId === exitId && run.lastRejected.atHumanMessages === run.humanMessages);
911
+ }
912
+ function noteSideQuestion(run) {
913
+ return { ...run, sideQuestionAt: run.humanMessages };
914
+ }
915
+ function withoutOwnStep(run) {
916
+ const { nudgeStepOwn: _own, ...rest } = run;
917
+ return rest;
918
+ }
919
+ function withNudgeStep(run, step, own) {
920
+ return { ...withoutOwnStep(run), nudgeStep: step, ...own && { nudgeStepOwn: true } };
921
+ }
922
+
923
+ // src/engine/side-questions.ts
924
+ function isFieldStale(field, updatedAt, now) {
925
+ if (field.refreshAfterMonths === null) return false;
926
+ const due = new Date(updatedAt);
927
+ due.setUTCMonth(due.getUTCMonth() + field.refreshAfterMonths);
928
+ return due.getTime() <= now;
929
+ }
930
+ function sideQuestion(flow, run, input) {
931
+ const state = stateById(flow, run.state);
932
+ if (!state || isFinal(state)) return null;
933
+ const known = (id2) => {
934
+ const found = fieldById(flow, id2);
935
+ if (!found) return true;
936
+ const value = found.place === "notes" ? run.notes[id2] : input.card[id2]?.value;
937
+ return fieldValueFits(found.field, value);
938
+ };
939
+ const learn = state.learn.find((id2) => !known(id2));
940
+ if (learn) return { fieldId: learn, reason: "learn" };
941
+ if (state.noSideQuestions) return null;
942
+ if (run.sideQuestionAt !== null && run.humanMessages - run.sideQuestionAt < flow.pace.sideQuestionEveryMessages) return null;
943
+ const stale = flow.clientCard.find((field) => {
944
+ const entry = input.card[field.id];
945
+ return entry !== void 0 && known(field.id) && isFieldStale(field, entry.updatedAt, input.now);
946
+ });
947
+ if (stale) return { fieldId: stale.id, reason: "stale" };
948
+ const unknown = flow.clientCard.find((field) => !known(field.id));
949
+ return unknown ? { fieldId: unknown.id, reason: "unknown" } : null;
950
+ }
951
+
952
+ // src/check/app-checks.ts
953
+ function pick(items, key) {
954
+ if (!items || key === void 0) return void 0;
955
+ return /^\d+$/.test(key) ? items[Number(key)] : items.find((item) => item.id === key);
956
+ }
957
+ function placeOfPath(flow, path) {
958
+ const state = /^states\[([^\]]+)\](?:\.exits\[([^\]]+)\])?/.exec(path);
959
+ if (state) {
960
+ const found = pick(flow.states, state[1]);
961
+ if (!found) return {};
962
+ const exit = pick(found.exits, state[2]);
963
+ return exit ? { stateId: found.id, exitId: exit.id } : { stateId: found.id };
964
+ }
965
+ const any = /^anyState\.exits\[([^\]]+)\]/.exec(path);
966
+ if (any) {
967
+ const exit = pick(flow.anyState.exits, any[1]);
968
+ return exit ? { exitId: exit.id } : {};
969
+ }
970
+ const field = /^(clientCard|chatNotes)\[([^\]]+)\]/.exec(path);
971
+ if (field) {
972
+ const found = pick(flow[field[1]], field[2]);
973
+ return found ? { fieldId: found.id } : {};
974
+ }
975
+ const task = /^sideTasks\[([^\]]+)\]/.exec(path);
976
+ if (task) {
977
+ const found = pick(flow.sideTasks, task[1]);
978
+ return found ? { sideTaskId: found.id } : {};
979
+ }
980
+ return {};
981
+ }
982
+ function appIssues(flow, found) {
983
+ return found.map((issue) => ({
984
+ level: issue.level ?? "error",
985
+ code: issue.code ?? "app_check",
986
+ message: issue.message,
987
+ place: issue.place ?? (issue.path === void 0 ? {} : placeOfPath(flow, issue.path))
988
+ }));
989
+ }
990
+
991
+ // src/check/check-flow.ts
992
+ var Issues = class {
993
+ list = [];
994
+ error(code, message, place = {}) {
995
+ this.list.push({ level: "error", code, message, place });
996
+ }
997
+ warning(code, message, place = {}) {
998
+ this.list.push({ level: "warning", code, message, place });
999
+ }
1000
+ };
1001
+ var quote = (text) => `\xAB${text}\xBB`;
1002
+ var stateName = (state) => quote(state.title.trim() || state.id);
1003
+ function checkDuplicates(flow, issues) {
1004
+ const states = /* @__PURE__ */ new Set();
1005
+ for (const state of flow.states) {
1006
+ if (states.has(state.id)) issues.error("duplicate_state", `\u0414\u0432\u0430 \u0441\u043E\u0441\u0442\u043E\u044F\u043D\u0438\u044F \u0441 id ${quote(state.id)}`, { stateId: state.id });
1007
+ states.add(state.id);
1008
+ }
1009
+ const exits2 = /* @__PURE__ */ new Set();
1010
+ const exitsOf = [
1011
+ ...flow.states.map((state) => ({ stateId: state.id, exits: state.exits })),
1012
+ { exits: flow.anyState.exits }
1013
+ ];
1014
+ for (const { stateId, exits: list } of exitsOf) {
1015
+ for (const exit of list) {
1016
+ if (exits2.has(exit.id)) {
1017
+ issues.error("duplicate_exit", `\u0414\u0432\u0430 \u0443\u0441\u043B\u043E\u0432\u0438\u044F \u0441 id ${quote(exit.id)}: \u0438\u0441\u0442\u043E\u0440\u0438\u044F \u043F\u0435\u0440\u0435\u0445\u043E\u0434\u043E\u0432 \u0438\u0445 \u043D\u0435 \u0440\u0430\u0437\u043B\u0438\u0447\u0438\u0442`, {
1018
+ ...stateId === void 0 ? {} : { stateId },
1019
+ exitId: exit.id
1020
+ });
1021
+ }
1022
+ exits2.add(exit.id);
1023
+ }
1024
+ }
1025
+ const fields = /* @__PURE__ */ new Set();
1026
+ for (const field of [...flow.clientCard, ...flow.chatNotes]) {
1027
+ if (fields.has(field.id)) issues.error("duplicate_field", `\u0414\u0432\u0430 \u043F\u043E\u043B\u044F \u0441 id ${quote(field.id)} \u0432 \u043A\u0430\u0440\u0442\u043E\u0447\u043A\u0435 \u0438 \u0437\u0430\u043C\u0435\u0442\u043A\u0430\u0445`, { fieldId: field.id });
1028
+ fields.add(field.id);
1029
+ }
1030
+ }
1031
+ function eventKnown(exit, catalog) {
1032
+ if (exit.when.type !== "event" || exit.when.name === void 0) return true;
1033
+ const { event, name } = exit.when;
1034
+ if (event === "tool") return catalog.tools.includes(name);
1035
+ if (event === "button") return catalog.widgets.includes(name) || catalogEventNames(catalog).includes(name);
1036
+ if (event === "app") return catalogEventNames(catalog).includes(name);
1037
+ return true;
1038
+ }
1039
+ function checkExit(flow, catalog, issues, exit, index, state) {
1040
+ const where = state ? stateName(state) : "\u041E\u0431\u0449\u0438\u0435 \u043F\u0435\u0440\u0435\u0445\u043E\u0434\u044B";
1041
+ const what = `${where}: \u0443\u0441\u043B\u043E\u0432\u0438\u0435 \u2116${index + 1}`;
1042
+ const place = state ? { stateId: state.id, exitId: exit.id } : { exitId: exit.id };
1043
+ if (exit.to === null) issues.error("exit_without_target", `${what} \u043D\u0438\u043A\u0443\u0434\u0430 \u043D\u0435 \u0432\u0435\u0434\u0451\u0442`, place);
1044
+ else if (exit.to === RETURN_TARGET) {
1045
+ if (!state) issues.error("return_from_any_state", `${what}: \xAB\u043D\u0430\u0437\u0430\u0434\xBB \u0438\u0437 \u043E\u0431\u0449\u0438\u0445 \u043F\u0435\u0440\u0435\u0445\u043E\u0434\u043E\u0432 \u2014 \u043D\u0435\u043F\u043E\u043D\u044F\u0442\u043D\u043E, \u043A\u0443\u0434\u0430 \u0432\u043E\u0437\u0432\u0440\u0430\u0449\u0430\u0442\u044C\u0441\u044F`, place);
1046
+ } else if (!stateById(flow, exit.to)) issues.error("unknown_target", `${what} \u0432\u0435\u0434\u0451\u0442 \u0432 \u0441\u043E\u0441\u0442\u043E\u044F\u043D\u0438\u0435 ${quote(exit.to)}, \u043A\u043E\u0442\u043E\u0440\u043E\u0433\u043E \u043D\u0435\u0442`, place);
1047
+ const when = exit.when;
1048
+ if (when.type === "judge" && when.text.trim() === "") {
1049
+ issues.error("empty_judge", `${what} \u043D\u0435 \u043D\u0430\u043F\u0438\u0441\u0430\u043D\u043E: \u0430\u0433\u0435\u043D\u0442\u0443 \u0438 \u0441\u0443\u0434\u044C\u0435 \u043D\u0435\u0447\u0435\u0433\u043E \u043F\u0440\u043E\u0432\u0435\u0440\u044F\u0442\u044C`, place);
1050
+ }
1051
+ if (when.type === "data") {
1052
+ const found = fieldById(flow, when.field);
1053
+ const fieldPlace = { ...place, fieldId: when.field };
1054
+ if (!found) {
1055
+ issues.error("unknown_field", `${what}: \u043F\u043E\u043B\u044F ${quote(when.field)} \u043D\u0435\u0442 \u043D\u0438 \u0432 \u043A\u0430\u0440\u0442\u043E\u0447\u043A\u0435 \u043A\u043B\u0438\u0435\u043D\u0442\u0430, \u043D\u0438 \u0432 \u0437\u0430\u043C\u0435\u0442\u043A\u0430\u0445 \u0447\u0430\u0442\u0430`, fieldPlace);
1056
+ } else if (!FLOW_OPS_BY_FIELD_TYPE[found.field.type].includes(when.op)) {
1057
+ issues.error("op_not_for_type", `${what}: \u043F\u043E\u043B\u0435 ${quote(found.field.name)} \u0442\u0430\u043A \u043D\u0435 \u0441\u0440\u0430\u0432\u043D\u0438\u0432\u0430\u0435\u0442\u0441\u044F`, fieldPlace);
1058
+ } else if (found.field.type === "number" && when.op !== "filled" && typeof when.value !== "number") {
1059
+ issues.error("value_not_number", `${what}: \u043F\u043E\u043B\u0435 ${quote(found.field.name)} \u2014 \u0447\u0438\u0441\u043B\u043E, \u0441\u0440\u0430\u0432\u043D\u0438\u0432\u0430\u0442\u044C \u0435\u0433\u043E \u043D\u0443\u0436\u043D\u043E \u0441 \u0447\u0438\u0441\u043B\u043E\u043C`, fieldPlace);
1060
+ } else if (found.field.type === "boolean" && when.op !== "filled" && typeof when.value !== "boolean") {
1061
+ issues.error("value_not_boolean", `${what}: \u043F\u043E\u043B\u0435 ${quote(found.field.name)} \u2014 \xAB\u0434\u0430/\u043D\u0435\u0442\xBB, \u0441\u0440\u0430\u0432\u043D\u0438\u0432\u0430\u0442\u044C \u0435\u0433\u043E \u043D\u0443\u0436\u043D\u043E \u0441 \xAB\u0434\u0430\xBB \u0438\u043B\u0438 \xAB\u043D\u0435\u0442\xBB`, fieldPlace);
1062
+ } else if (found.field.type === "choice" && when.op === "eq" && found.field.options.length > 0 && !found.field.options.some((option) => sameText(option, String(when.value)))) {
1063
+ issues.error("value_not_in_options", `${what}: \u0443 \u043F\u043E\u043B\u044F ${quote(found.field.name)} \u043D\u0435\u0442 \u0432\u0430\u0440\u0438\u0430\u043D\u0442\u0430 ${quote(String(when.value))}`, fieldPlace);
1064
+ }
1065
+ }
1066
+ if (when.type === "timer" && when.from === "state_days") {
1067
+ if (!flow.schedule) {
1068
+ issues.error("state_days_without_day_start", `${what}: \xAB\u0434\u043B\u0438\u0442\u0441\u044F ${when.days} \u0434\u043D.\xBB \u2014 \u0443 \u0441\u0446\u0435\u043D\u0430\u0440\u0438\u044F \u043D\u0435 \u0437\u0430\u0434\u0430\u043D\u043E \u043D\u0430\u0447\u0430\u043B\u043E \u0434\u043D\u044F (\xAB\u0414\u043D\u0438 \u0438 \u0432\u0440\u0435\u043C\u044F\xBB)`, place);
1069
+ }
1070
+ if (when.days < 1) issues.error("state_days_below_one", `${what}: \u043D\u043E\u0434\u0430 \u0434\u043E\u043B\u0436\u043D\u0430 \u0434\u043B\u0438\u0442\u044C\u0441\u044F \u0445\u043E\u0442\u044F \u0431\u044B \u043E\u0434\u0438\u043D \u0434\u0435\u043D\u044C`, place);
1071
+ }
1072
+ if (when.type === "timer" && when.from === "program_day") {
1073
+ if (!Number.isInteger(when.day) || when.day < 1) {
1074
+ issues.error("program_day_invalid", `${what}: \u0434\u0435\u043D\u044C \u043F\u0440\u043E\u0433\u0440\u0430\u043C\u043C\u044B \u2014 \u0446\u0435\u043B\u043E\u0435 \u0447\u0438\u0441\u043B\u043E \u0441 1`, place);
1075
+ } else if (flow.schedule?.lengthDays !== void 0 && when.day > flow.schedule.lengthDays) {
1076
+ issues.error("program_day_after_end", `${what}: \u0434\u043D\u044F ${when.day} \u043D\u0435\u0442 \u2014 \u043F\u0440\u043E\u0433\u0440\u0430\u043C\u043C\u0430 \u0434\u043B\u0438\u0442\u0441\u044F ${flow.schedule.lengthDays} \u0434\u043D.`, place);
1077
+ }
1078
+ if (!flow.schedule) issues.warning("program_day_without_schedule", `${what}: \xAB\u0441 \u0434\u043D\u044F ${when.day}\xBB \u043D\u0435 \u0441\u0440\u0430\u0431\u043E\u0442\u0430\u0435\u0442 \u2014 \u0443 \u0441\u0446\u0435\u043D\u0430\u0440\u0438\u044F \u043D\u0435\u0442 \xAB\u0414\u043D\u0435\u0439 \u0438 \u0432\u0440\u0435\u043C\u0435\u043D\u0438\xBB`, place);
1079
+ }
1080
+ if (when.type === "event" && when.event !== "message") {
1081
+ if (when.name === void 0 || when.name.trim() === "") {
1082
+ issues.error("event_without_name", `${what}: \u043D\u0435 \u0432\u044B\u0431\u0440\u0430\u043D\u043E, \u043A\u0430\u043A\u043E\u0435 \u0441\u043E\u0431\u044B\u0442\u0438\u0435 \u0436\u0434\u0430\u0442\u044C`, place);
1083
+ } else if (!eventKnown(exit, catalog)) {
1084
+ issues.error("unknown_event", `${what}: \u043F\u0440\u0438\u043B\u043E\u0436\u0435\u043D\u0438\u0435 \u043D\u0435 \u043E\u0431\u044A\u044F\u0432\u0438\u043B\u043E ${quote(when.name)}`, place);
1085
+ }
1086
+ }
1087
+ }
1088
+ function checkState(flow, catalog, issues, state) {
1089
+ for (const tool of state.tools) {
1090
+ if (!flow.tools.includes(tool)) {
1091
+ issues.error("tool_not_in_flow", `${stateName(state)}: \u0438\u043D\u0441\u0442\u0440\u0443\u043C\u0435\u043D\u0442\u0430 ${quote(tool)} \u043D\u0435\u0442 \u0432 \u0441\u043F\u0438\u0441\u043A\u0435 \u0438\u043D\u0441\u0442\u0440\u0443\u043C\u0435\u043D\u0442\u043E\u0432 \u0441\u0446\u0435\u043D\u0430\u0440\u0438\u044F`, { stateId: state.id });
1092
+ } else if (!catalog.tools.includes(tool)) {
1093
+ issues.error("unknown_tool", `${stateName(state)}: \u0438\u043D\u0441\u0442\u0440\u0443\u043C\u0435\u043D\u0442\u0430 ${quote(tool)} \u043D\u0435\u0442 \u0443 \u043F\u0440\u0438\u043B\u043E\u0436\u0435\u043D\u0438\u044F`, { stateId: state.id });
1094
+ }
1095
+ }
1096
+ for (const fieldId of state.learn) {
1097
+ if (!fieldById(flow, fieldId)) {
1098
+ issues.error("unknown_learn_field", `${stateName(state)}: \xAB\u0443\u0437\u043D\u0430\u0442\u044C \u0437\u0434\u0435\u0441\u044C\xBB \u2014 \u043F\u043E\u043B\u044F ${quote(fieldId)} \u043D\u0435\u0442`, { stateId: state.id, fieldId });
1099
+ }
1100
+ }
1101
+ state.exits.forEach((exit, index) => checkExit(flow, catalog, issues, exit, index, state));
1102
+ if (state.nudges && state.nudges !== "off" && nudgesEmpty(state.nudges)) {
1103
+ issues.warning("empty_nudges", `${stateName(state)}: \u0432 \u043A\u0430\u0441\u0430\u043D\u0438\u044F\u0445 \u043D\u0435\u0442 \u043D\u0438 \u043E\u0434\u043D\u043E\u0433\u043E \u0441\u0440\u043E\u043A\u0430 \u2014 \u0430\u0433\u0435\u043D\u0442 \u043D\u0435 \u043D\u0430\u043F\u0438\u0448\u0435\u0442 \u043F\u0435\u0440\u0432\u044B\u043C`, { stateId: state.id });
1104
+ }
1105
+ const days = state.nudges && state.nudges !== "off" ? state.nudges.days : void 0;
1106
+ if (days !== void 0 && (!Number.isInteger(days) || days < 1)) {
1107
+ issues.error("nudges_days_invalid", `${stateName(state)}: \u0441\u0432\u043E\u0438 \u043A\u0430\u0441\u0430\u043D\u0438\u044F \u0434\u0435\u0439\u0441\u0442\u0432\u0443\u044E\u0442 \u0446\u0435\u043B\u043E\u0435 \u0447\u0438\u0441\u043B\u043E \u0434\u043D\u0435\u0439, \u0441 1`, { stateId: state.id });
1108
+ }
1109
+ }
1110
+ var nudgesEmpty = (nudges2) => nudges2.afterSilence.length === 0 && !nudges2.dailyAt?.length;
1111
+ function checkSchedule(flow, issues) {
1112
+ const schedule2 = flow.schedule;
1113
+ if (!schedule2) return;
1114
+ const dayStart = parseClock(schedule2.dayStart);
1115
+ const nightFrom = schedule2.nightFrom === void 0 ? null : parseClock(schedule2.nightFrom);
1116
+ if (dayStart !== null && nightFrom !== null && nightFrom <= dayStart) {
1117
+ issues.error("night_before_day_start", `\xAB\u0414\u043D\u0438 \u0438 \u0432\u0440\u0435\u043C\u044F\xBB: \u043D\u043E\u0447\u044C (${schedule2.nightFrom}) \u043D\u0430\u0447\u0438\u043D\u0430\u0435\u0442\u0441\u044F \u043D\u0435 \u043F\u043E\u0437\u0436\u0435 \u043D\u0430\u0447\u0430\u043B\u0430 \u0434\u043D\u044F (${schedule2.dayStart})`);
1118
+ }
1119
+ if (schedule2.deadlineState !== void 0 && !stateById(flow, schedule2.deadlineState)) {
1120
+ issues.error("unknown_deadline_state", `\xAB\u0414\u043D\u0438 \u0438 \u0432\u0440\u0435\u043C\u044F\xBB: \u043F\u0440\u0438 \xAB\u0441\u0440\u043E\u043A \u0432\u044B\u0448\u0435\u043B\xBB \u043F\u0435\u0440\u0435\u0445\u043E\u0434 \u0432 \u0441\u043E\u0441\u0442\u043E\u044F\u043D\u0438\u0435 ${quote(schedule2.deadlineState)}, \u043A\u043E\u0442\u043E\u0440\u043E\u0433\u043E \u043D\u0435\u0442`, {
1121
+ stateId: schedule2.deadlineState
1122
+ });
1123
+ }
1124
+ const frame = schedule2.dayFrame;
1125
+ if (frame?.softFrom !== void 0 && frame.hardAt !== void 0 && frame.softFrom >= frame.hardAt) {
1126
+ issues.error("day_frame_soft_after_hard", `\xAB\u0414\u043D\u0438 \u0438 \u0432\u0440\u0435\u043C\u044F\xBB: \u043C\u044F\u0433\u043A\u0430\u044F \u0440\u0430\u043C\u043A\u0430 (${frame.softFrom}) \u0434\u043E\u043B\u0436\u043D\u0430 \u0431\u044B\u0442\u044C \u0440\u0430\u043D\u044C\u0448\u0435 \u0436\u0451\u0441\u0442\u043A\u043E\u0439 (${frame.hardAt})`);
1127
+ }
1128
+ if (schedule2.nudges && nudgesEmpty(schedule2.nudges)) {
1129
+ issues.warning("empty_nudges", "\xAB\u0414\u043D\u0438 \u0438 \u0432\u0440\u0435\u043C\u044F\xBB: \u0432 \u043A\u0430\u0441\u0430\u043D\u0438\u044F\u0445 \u043D\u0435\u0442 \u043D\u0438 \u043E\u0434\u043D\u043E\u0433\u043E \u0441\u0440\u043E\u043A\u0430 \u2014 \u0430\u0433\u0435\u043D\u0442 \u043D\u0435 \u043D\u0430\u043F\u0438\u0448\u0435\u0442 \u043F\u0435\u0440\u0432\u044B\u043C");
1130
+ }
1131
+ if (schedule2.nudges && flow.nudges) {
1132
+ issues.warning("nudges_shadowed", "\u041A\u0430\u0441\u0430\u043D\u0438\u044F \u0437\u0430\u0434\u0430\u043D\u044B \u0438 \u0443 \u0441\u0446\u0435\u043D\u0430\u0440\u0438\u044F, \u0438 \u0432 \xAB\u0414\u043D\u044F\u0445 \u0438 \u0432\u0440\u0435\u043C\u0435\u043D\u0438\xBB: \u0434\u0435\u0439\u0441\u0442\u0432\u0443\u044E\u0442 \u043A\u0430\u0441\u0430\u043D\u0438\u044F \xAB\u0414\u043D\u0435\u0439 \u0438 \u0432\u0440\u0435\u043C\u0435\u043D\u0438\xBB");
1133
+ }
1134
+ }
1135
+ function checkFlowNudges(flow, issues) {
1136
+ if (flow.nudges && nudgesEmpty(flow.nudges)) {
1137
+ issues.warning("empty_nudges", "\u041A\u0430\u0441\u0430\u043D\u0438\u044F \u0441\u0446\u0435\u043D\u0430\u0440\u0438\u044F: \u043D\u0435\u0442 \u043D\u0438 \u043E\u0434\u043D\u043E\u0433\u043E \u0441\u0440\u043E\u043A\u0430 \u2014 \u0430\u0433\u0435\u043D\u0442 \u043D\u0435 \u043D\u0430\u043F\u0438\u0448\u0435\u0442 \u043F\u0435\u0440\u0432\u044B\u043C");
1138
+ }
1139
+ }
1140
+ function checkSideTasks(flow, issues) {
1141
+ const seen = /* @__PURE__ */ new Set();
1142
+ for (const task of flow.sideTasks ?? []) {
1143
+ if (seen.has(task.id)) issues.error("duplicate_side_task", `\u0414\u0432\u0435 \u043F\u043E\u043F\u0443\u0442\u043D\u044B\u0435 \u0437\u0430\u0434\u0430\u0447\u0438 \u0441 id ${quote(task.id)}`, { sideTaskId: task.id });
1144
+ seen.add(task.id);
1145
+ if (task.field !== void 0 && !fieldById(flow, task.field)) {
1146
+ issues.error("side_task_unknown_field", `\u041F\u043E\u043F\u0443\u0442\u043D\u0430\u044F \u0437\u0430\u0434\u0430\u0447\u0430 ${quote(task.id)}: \u043F\u043E\u043B\u044F ${quote(task.field)} \u043D\u0435\u0442 \u043D\u0438 \u0432 \u043A\u0430\u0440\u0442\u043E\u0447\u043A\u0435, \u043D\u0438 \u0432 \u0437\u0430\u043C\u0435\u0442\u043A\u0430\u0445`, {
1147
+ sideTaskId: task.id,
1148
+ fieldId: task.field
1149
+ });
1150
+ }
1151
+ }
1152
+ }
1153
+ function reachableFrom(flow, start) {
1154
+ const seen = /* @__PURE__ */ new Set();
1155
+ const queue = [start];
1156
+ const deadline = flow.schedule?.deadlineState === void 0 ? void 0 : stateById(flow, flow.schedule.deadlineState);
1157
+ if (deadline) queue.push(deadline);
1158
+ while (queue.length > 0) {
1159
+ const state = queue.shift();
1160
+ if (seen.has(state.id)) continue;
1161
+ seen.add(state.id);
1162
+ const exits2 = commonApplies(flow, state) ? [...state.exits, ...flow.anyState.exits] : state.exits;
1163
+ for (const exit of exits2) {
1164
+ const next = stateById(flow, exit.to);
1165
+ if (next && !seen.has(next.id)) queue.push(next);
1166
+ }
1167
+ }
1168
+ return seen;
1169
+ }
1170
+ function checkFlow(flow, catalog, options = {}) {
1171
+ const issues = new Issues();
1172
+ checkDuplicates(flow, issues);
1173
+ const start = stateById(flow, flow.start);
1174
+ if (flow.start === null) issues.error("no_start", "\u041D\u0435\u0442 \u0441\u0442\u0430\u0440\u0442\u043E\u0432\u043E\u0433\u043E \u0441\u043E\u0441\u0442\u043E\u044F\u043D\u0438\u044F: \u043E\u0442\u043C\u0435\u0442\u044C\u0442\u0435, \u0433\u0434\u0435 \u043D\u0430\u0447\u0438\u043D\u0430\u0435\u0442\u0441\u044F \u0441\u0446\u0435\u043D\u0430\u0440\u0438\u0439");
1175
+ else if (!start) issues.error("unknown_start", `\u0421\u0442\u0430\u0440\u0442\u043E\u0432\u043E\u0435 \u0441\u043E\u0441\u0442\u043E\u044F\u043D\u0438\u0435 ${quote(flow.start)} \u043D\u0435 \u043D\u0430\u0439\u0434\u0435\u043D\u043E`);
1176
+ for (const tool of flow.tools) {
1177
+ if (!catalog.tools.includes(tool)) issues.error("unknown_tool", `\u0418\u043D\u0441\u0442\u0440\u0443\u043C\u0435\u043D\u0442\u0430 ${quote(tool)} \u043D\u0435\u0442 \u0443 \u043F\u0440\u0438\u043B\u043E\u0436\u0435\u043D\u0438\u044F`);
1178
+ }
1179
+ for (const state of flow.states) checkState(flow, catalog, issues, state);
1180
+ for (const stateId of flow.anyState.except) {
1181
+ if (!stateById(flow, stateId)) {
1182
+ issues.warning("unknown_except_state", `\u041E\u0431\u0449\u0438\u0435 \u043F\u0435\u0440\u0435\u0445\u043E\u0434\u044B: \u0438\u0441\u043A\u043B\u044E\u0447\u0435\u043D\u043E \u0441\u043E\u0441\u0442\u043E\u044F\u043D\u0438\u0435 ${quote(stateId)}, \u043A\u043E\u0442\u043E\u0440\u043E\u0433\u043E \u043D\u0435\u0442`, { stateId });
1183
+ }
1184
+ }
1185
+ flow.anyState.exits.forEach((exit, index) => checkExit(flow, catalog, issues, exit, index));
1186
+ checkSchedule(flow, issues);
1187
+ checkFlowNudges(flow, issues);
1188
+ checkSideTasks(flow, issues);
1189
+ if (start) {
1190
+ const reachable = reachableFrom(flow, start);
1191
+ const reported = /* @__PURE__ */ new Set();
1192
+ for (const state of flow.states) {
1193
+ if (reachable.has(state.id) || reported.has(state.id)) continue;
1194
+ reported.add(state.id);
1195
+ issues.error("unreachable_state", `${stateName(state)}: \u043D\u0435\u0434\u043E\u0441\u0442\u0438\u0436\u0438\u043C\u043E \u2014 \u0441\u044E\u0434\u0430 \u043D\u0435 \u0432\u0435\u0434\u0451\u0442 \u043D\u0438 \u043E\u0434\u0438\u043D \u043F\u0435\u0440\u0435\u0445\u043E\u0434 \u043E\u0442 \u0441\u0442\u0430\u0440\u0442\u0430`, { stateId: state.id });
1196
+ }
1197
+ if (!flow.states.some((state) => reachable.has(state.id) && isFinal(state))) {
1198
+ issues.warning("no_reachable_end", "\u041D\u0435\u0442 \u0434\u043E\u0441\u0442\u0438\u0436\u0438\u043C\u043E\u0433\u043E \u043A\u043E\u043D\u0435\u0447\u043D\u043E\u0433\u043E \u0441\u043E\u0441\u0442\u043E\u044F\u043D\u0438\u044F: \u0441\u0446\u0435\u043D\u0430\u0440\u0438\u0439 \u043D\u0438\u043A\u043E\u0433\u0434\u0430 \u043D\u0435 \u0437\u0430\u043A\u043E\u043D\u0447\u0438\u0442\u0441\u044F \u0441\u0430\u043C");
1199
+ }
1200
+ }
1201
+ return [...issues.list, ...options.checks ? appIssues(flow, options.checks(flow)) : []];
1202
+ }
1203
+
1204
+ export {
1205
+ AGENT_FLOW_FORMAT,
1206
+ AGENT_FLOW_FORMAT_VERSION,
1207
+ RETURN_TARGET,
1208
+ ANY_STATE_LAYOUT_KEY,
1209
+ FLOW_FIELD_TYPES,
1210
+ FLOW_DATA_OPS,
1211
+ FLOW_OPS_BY_FIELD_TYPE,
1212
+ FLOW_EVENT_TYPES,
1213
+ FLOW_TIMER_UNITS,
1214
+ FLOW_TIMER_SPANS,
1215
+ DEFAULT_LATE_START_HOURS,
1216
+ DEFAULT_SIDE_TASK_MAX_ATTEMPTS,
1217
+ FLOW_AFTER_END_MODES,
1218
+ DEFAULT_SIDE_QUESTION_EVERY_MESSAGES,
1219
+ agentFlowSchema,
1220
+ migrateFlow,
1221
+ parseFlow,
1222
+ catalogEventNames,
1223
+ catalogEventLabel,
1224
+ compactFlow,
1225
+ FLOW_STATE_KEY,
1226
+ FLOW_PATH_LIMIT,
1227
+ FLOW_CHAIN_LIMIT,
1228
+ DEFAULT_FIRST_MESSAGES,
1229
+ stateById,
1230
+ isFinal,
1231
+ isTouch,
1232
+ commonApplies,
1233
+ activeExits,
1234
+ fieldById,
1235
+ sameText,
1236
+ parseBooleanAnswer,
1237
+ fieldValueFits,
1238
+ dataConditionHolds,
1239
+ returnTarget,
1240
+ parseClock,
1241
+ clockMinutes,
1242
+ nextClockTime,
1243
+ startOfNextDay,
1244
+ localDay,
1245
+ dayOf,
1246
+ dayInProgress,
1247
+ dayStartAt,
1248
+ nextDayStartAfter,
1249
+ dayAnchor,
1250
+ stateDaysDue,
1251
+ flowDay,
1252
+ deadlineAt,
1253
+ beforeFirstNight,
1254
+ withDayAnchor,
1255
+ clockText,
1256
+ stateNudges,
1257
+ nextNudge,
1258
+ dayStartHoldUntil,
1259
+ FLOW_DEADLINE_EXIT,
1260
+ timerDueAt,
1261
+ overdueOnEntry,
1262
+ nextDue,
1263
+ FLOW_FIRST_EXIT,
1264
+ FLOW_GIVE_UP_EXIT,
1265
+ nextWake,
1266
+ dueReasons,
1267
+ nextFirstMessageAfter,
1268
+ endingWake,
1269
+ deferredWake,
1270
+ describeCondition,
1271
+ nextTransition,
1272
+ startRun,
1273
+ appendPath,
1274
+ applyTransition,
1275
+ noteHumanMessage,
1276
+ noteAgentAnswer,
1277
+ withoutUndeliveredTouch,
1278
+ noteRejectedClaim,
1279
+ claimAllowed,
1280
+ noteSideQuestion,
1281
+ withNudgeStep,
1282
+ isFieldStale,
1283
+ sideQuestion,
1284
+ placeOfPath,
1285
+ appIssues,
1286
+ checkFlow
1287
+ };
1288
+ //# sourceMappingURL=chunk-BOV6FJGU.js.map