dabke 0.82.0 → 0.83.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 (83) hide show
  1. package/CHANGELOG.md +23 -0
  2. package/README.md +6 -3
  3. package/dist/cpsat/rules/index.d.ts +3 -0
  4. package/dist/cpsat/rules/index.d.ts.map +1 -1
  5. package/dist/cpsat/rules/index.js +3 -0
  6. package/dist/cpsat/rules/index.js.map +1 -1
  7. package/dist/cpsat/rules/max-days-week.d.ts +44 -0
  8. package/dist/cpsat/rules/max-days-week.d.ts.map +1 -0
  9. package/dist/cpsat/rules/max-days-week.js +95 -0
  10. package/dist/cpsat/rules/max-days-week.js.map +1 -0
  11. package/dist/cpsat/rules/min-days-week.d.ts +34 -0
  12. package/dist/cpsat/rules/min-days-week.d.ts.map +1 -0
  13. package/dist/cpsat/rules/min-days-week.js +84 -0
  14. package/dist/cpsat/rules/min-days-week.js.map +1 -0
  15. package/dist/cpsat/rules/must-assign.d.ts +49 -0
  16. package/dist/cpsat/rules/must-assign.d.ts.map +1 -0
  17. package/dist/cpsat/rules/must-assign.js +86 -0
  18. package/dist/cpsat/rules/must-assign.js.map +1 -0
  19. package/dist/cpsat/rules/registry.d.ts +4 -1
  20. package/dist/cpsat/rules/registry.d.ts.map +1 -1
  21. package/dist/cpsat/rules/registry.js +4 -1
  22. package/dist/cpsat/rules/registry.js.map +1 -1
  23. package/dist/cpsat/rules/rules.types.d.ts +3 -0
  24. package/dist/cpsat/rules/rules.types.d.ts.map +1 -1
  25. package/dist/cpsat/rules/scope.types.d.ts +1 -1
  26. package/dist/index.d.ts +5 -3
  27. package/dist/index.d.ts.map +1 -1
  28. package/dist/index.js +4 -2
  29. package/dist/index.js.map +1 -1
  30. package/dist/schedule/cost.d.ts +204 -0
  31. package/dist/schedule/cost.d.ts.map +1 -0
  32. package/dist/schedule/cost.js +187 -0
  33. package/dist/schedule/cost.js.map +1 -0
  34. package/dist/schedule/coverage.d.ts +85 -0
  35. package/dist/schedule/coverage.d.ts.map +1 -0
  36. package/dist/schedule/coverage.js +33 -0
  37. package/dist/schedule/coverage.js.map +1 -0
  38. package/dist/schedule/definition.d.ts +227 -0
  39. package/dist/schedule/definition.d.ts.map +1 -0
  40. package/dist/{schedule.js → schedule/definition.js} +9 -673
  41. package/dist/schedule/definition.js.map +1 -0
  42. package/dist/schedule/index.d.ts +67 -0
  43. package/dist/schedule/index.d.ts.map +1 -0
  44. package/dist/schedule/index.js +69 -0
  45. package/dist/schedule/index.js.map +1 -0
  46. package/dist/schedule/rules.d.ts +353 -0
  47. package/dist/schedule/rules.d.ts.map +1 -0
  48. package/dist/schedule/rules.js +352 -0
  49. package/dist/schedule/rules.js.map +1 -0
  50. package/dist/schedule/shift-patterns.d.ts +34 -0
  51. package/dist/schedule/shift-patterns.d.ts.map +1 -0
  52. package/dist/schedule/shift-patterns.js +41 -0
  53. package/dist/schedule/shift-patterns.js.map +1 -0
  54. package/dist/schedule/time-periods.d.ts +69 -0
  55. package/dist/schedule/time-periods.d.ts.map +1 -0
  56. package/dist/schedule/time-periods.js +91 -0
  57. package/dist/schedule/time-periods.js.map +1 -0
  58. package/package.json +4 -9
  59. package/src/cpsat/rules/index.ts +3 -0
  60. package/src/cpsat/rules/max-days-week.ts +143 -0
  61. package/src/cpsat/rules/min-days-week.ts +120 -0
  62. package/src/cpsat/rules/must-assign.ts +108 -0
  63. package/src/cpsat/rules/registry.ts +6 -0
  64. package/src/cpsat/rules/rules.types.ts +3 -0
  65. package/src/cpsat/rules/scope.types.ts +1 -1
  66. package/src/index.ts +8 -3
  67. package/src/schedule/cost.ts +242 -0
  68. package/src/schedule/coverage.ts +135 -0
  69. package/src/schedule/definition.ts +958 -0
  70. package/src/schedule/index.ts +112 -0
  71. package/src/schedule/rules.ts +529 -0
  72. package/src/schedule/shift-patterns.ts +46 -0
  73. package/src/schedule/time-periods.ts +110 -0
  74. package/dist/llms.d.ts +0 -2
  75. package/dist/llms.d.ts.map +0 -1
  76. package/dist/llms.js +0 -3
  77. package/dist/llms.js.map +0 -1
  78. package/dist/schedule.d.ts +0 -917
  79. package/dist/schedule.d.ts.map +0 -1
  80. package/dist/schedule.js.map +0 -1
  81. package/llms.txt +0 -758
  82. package/src/llms.ts +0 -3
  83. package/src/schedule.ts +0 -1960
@@ -1,917 +0,0 @@
1
- /**
2
- * High-level schedule definition API.
3
- *
4
- * Small, composable factory functions that produce a complete scheduling
5
- * configuration. Designed for LLM code generation: each concept is a single
6
- * function call with per-call type safety.
7
- *
8
- * @example
9
- * ```typescript
10
- * import {
11
- * schedule, t, time, cover, shift,
12
- * maxHoursPerDay, maxHoursPerWeek, minRestBetweenShifts,
13
- * weekdays, weekend,
14
- * } from "dabke";
15
- *
16
- * const venue = schedule({
17
- * roleIds: ["cashier", "floor_lead", "stocker"],
18
- * skillIds: ["keyholder"],
19
- *
20
- * times: {
21
- * opening: time({ startTime: t(8), endTime: t(10) }),
22
- * peak_hours: time(
23
- * { startTime: t(11), endTime: t(14) },
24
- * { startTime: t(10), endTime: t(15), dayOfWeek: weekend },
25
- * ),
26
- * closing: time({ startTime: t(20), endTime: t(22) }),
27
- * },
28
- *
29
- * coverage: [
30
- * cover("opening", "keyholder", 1),
31
- * cover("peak_hours", "cashier", 3, { dayOfWeek: weekdays }),
32
- * cover("peak_hours", "cashier", 5, { dayOfWeek: weekend }),
33
- * cover("closing", "floor_lead", 1),
34
- * ],
35
- *
36
- * shiftPatterns: [
37
- * shift("morning", t(8), t(14)),
38
- * shift("afternoon", t(14), t(22)),
39
- * ],
40
- *
41
- * rules: [
42
- * maxHoursPerDay(10),
43
- * maxHoursPerWeek(48),
44
- * minRestBetweenShifts(10),
45
- * ],
46
- * });
47
- *
48
- * const result = await venue
49
- * .with([
50
- * { id: "alice", roleIds: ["cashier"], skillIds: ["keyholder"] },
51
- * ])
52
- * .solve(client, { dateRange: { start: "2025-03-03", end: "2025-03-09" } });
53
- * ```
54
- *
55
- * @module
56
- */
57
- import type { DayOfWeek, TimeOfDay } from "./types.js";
58
- import type { SemanticTimeVariant, SemanticTimeEntry, CoverageVariant } from "./cpsat/semantic-time.js";
59
- export type { CoverageVariant } from "./cpsat/semantic-time.js";
60
- import type { CompilationResult } from "./cpsat/model-builder.js";
61
- import { ModelBuilder } from "./cpsat/model-builder.js";
62
- import type { SchedulingMember, ShiftPattern, Priority } from "./cpsat/types.js";
63
- import type { CreateCpsatRuleFunction } from "./cpsat/rules/rules.types.js";
64
- import type { RecurringPeriod } from "./cpsat/rules/scope.types.js";
65
- import type { OvertimeTier } from "./cpsat/rules/overtime-tiered-multiplier.js";
66
- import type { SolverClient } from "./client.types.js";
67
- import type { ShiftAssignment } from "./cpsat/response.js";
68
- import type { ScheduleValidation } from "./cpsat/validation.types.js";
69
- import type { CostBreakdown } from "./cpsat/cost.js";
70
- /**
71
- * Creates a {@link TimeOfDay} value.
72
- *
73
- * @param hours - Hour component (0-23)
74
- * @param minutes - Minute component (0-59)
75
- *
76
- * @example Hours only
77
- * ```ts
78
- * t(9) // { hours: 9, minutes: 0 }
79
- * ```
80
- *
81
- * @example Hours and minutes
82
- * ```ts
83
- * t(17, 30) // { hours: 17, minutes: 30 }
84
- * ```
85
- *
86
- * @category Time Periods
87
- */
88
- export declare function t(hours: number, minutes?: number): TimeOfDay;
89
- /**
90
- * Monday through Friday.
91
- *
92
- * @category Time Periods
93
- */
94
- export declare const weekdays: readonly ["monday", "tuesday", "wednesday", "thursday", "friday"];
95
- /**
96
- * Saturday and Sunday.
97
- *
98
- * @category Time Periods
99
- */
100
- export declare const weekend: readonly ["saturday", "sunday"];
101
- /**
102
- * Define a named semantic time period.
103
- *
104
- * @remarks
105
- * Each entry has `startTime`/`endTime` and optional `dayOfWeek` or `dates`
106
- * scoping. Entries without scoping are the default.
107
- *
108
- * @example
109
- * ```typescript
110
- * times: {
111
- * // Simple: same times every day
112
- * lunch: time({ startTime: t(12), endTime: t(15) }),
113
- *
114
- * // Variants: different times on weekends
115
- * dinner: time(
116
- * { startTime: t(17), endTime: t(21) },
117
- * { startTime: t(18), endTime: t(22), dayOfWeek: weekend },
118
- * ),
119
- *
120
- * // Point-in-time window (keyholder at opening)
121
- * opening: time({ startTime: t(8, 30), endTime: t(9) }),
122
- * }
123
- * ```
124
- *
125
- * @privateRemarks
126
- * Resolution precedence: `dates` > `dayOfWeek` > default.
127
- *
128
- * @category Time Periods
129
- */
130
- export declare function time(...entries: [SemanticTimeVariant, ...SemanticTimeVariant[]]): SemanticTimeEntry;
131
- /**
132
- * Options for a {@link cover} call.
133
- *
134
- * @remarks
135
- * Day/date scoping controls which days this coverage entry applies to.
136
- * An entry without `dayOfWeek` or `dates` applies every day in the
137
- * scheduling period.
138
- *
139
- * @category Coverage
140
- */
141
- export interface CoverageOptions {
142
- /** Additional skill ID filter (AND logic with the target role). */
143
- skillIds?: [string, ...string[]];
144
- /** Restrict to specific days of the week. */
145
- dayOfWeek?: readonly [DayOfWeek, ...DayOfWeek[]];
146
- /** Restrict to specific dates (YYYY-MM-DD). */
147
- dates?: string[];
148
- /** Defaults to `"MANDATORY"`. */
149
- priority?: Priority;
150
- }
151
- /**
152
- * A coverage entry returned by {@link cover}.
153
- *
154
- * @remarks
155
- * Carries the semantic time name and target type information for
156
- * compile-time validation by {@link schedule}. This is an opaque
157
- * token; pass it directly into the `coverage` array.
158
- */
159
- export interface CoverageEntry<T extends string = string, R extends string = string> {
160
- /** @internal */ readonly _type: "coverage";
161
- /** @internal */ readonly timeName: T;
162
- /** @internal */ readonly target: R | R[];
163
- /** @internal */ readonly count: number;
164
- /** @internal */ readonly options: CoverageOptions;
165
- /** @internal When present, this entry uses variant-based resolution. */
166
- readonly variants?: readonly CoverageVariant[];
167
- }
168
- /**
169
- * Defines a staffing requirement for a semantic time period.
170
- *
171
- * @remarks
172
- * Entries for the same time and role **stack additively**.
173
- * For weekday vs weekend staffing, use mutually exclusive `dayOfWeek`
174
- * on both entries.
175
- *
176
- * @param timeName - Name of a declared semantic time
177
- * @param target - Role name (string), array of role names (OR logic), or skill name
178
- * @param count - Number of people needed
179
- * @param opts - Options: `skillIds` (AND filter), `dayOfWeek`, `dates`, `priority`
180
- *
181
- * @example
182
- * ```typescript
183
- * coverage: [
184
- * // 2 waiters during lunch
185
- * cover("lunch", "waiter", 2),
186
- *
187
- * // 1 manager OR supervisor during dinner
188
- * cover("dinner", ["manager", "supervisor"], 1),
189
- *
190
- * // 1 person with keyholder skill at opening
191
- * cover("opening", "keyholder", 1),
192
- *
193
- * // 1 senior waiter (role + skill AND)
194
- * cover("lunch", "waiter", 1, { skillIds: ["senior"] }),
195
- *
196
- * // Different counts by day (mutually exclusive dayOfWeek!)
197
- * cover("lunch", "waiter", 2, { dayOfWeek: weekdays }),
198
- * cover("lunch", "waiter", 3, { dayOfWeek: weekend }),
199
- * ]
200
- * ```
201
- *
202
- * @category Coverage
203
- */
204
- export declare function cover<T extends string, R extends string>(timeName: T, target: R | [R, ...R[]], count: number, opts?: CoverageOptions): CoverageEntry<T, R>;
205
- export declare function cover<T extends string, R extends string>(timeName: T, target: R | [R, ...R[]], ...variants: [CoverageVariant, ...CoverageVariant[]]): CoverageEntry<T, R>;
206
- /**
207
- * Define a shift pattern: a time slot available for employee assignment.
208
- *
209
- * @remarks
210
- * Each pattern repeats daily unless filtered by `dayOfWeek`.
211
- *
212
- * @example
213
- * ```typescript
214
- * shiftPatterns: [
215
- * shift("morning", t(11, 30), t(15)),
216
- * shift("evening", t(17), t(22)),
217
- *
218
- * // Role-restricted shift
219
- * shift("kitchen", t(6), t(14), { roleIds: ["chef", "prep_cook"] }),
220
- *
221
- * // Day-restricted shift
222
- * shift("saturday_short", t(9), t(14), { dayOfWeek: ["saturday"] }),
223
- *
224
- * // Location-specific shift
225
- * shift("terrace_lunch", t(12), t(16), { locationId: "terrace" }),
226
- * ]
227
- * ```
228
- *
229
- * @category Shift Patterns
230
- */
231
- export declare function shift(id: string, startTime: TimeOfDay, endTime: TimeOfDay, opts?: Pick<ShiftPattern, "roleIds" | "dayOfWeek" | "locationId">): ShiftPattern;
232
- /**
233
- * Scoping options shared by most rule functions.
234
- *
235
- * @remarks
236
- * Default priority is `MANDATORY`. Use `appliesTo` to scope to a
237
- * role, skill, or member ID. Use time scoping options (`dayOfWeek`,
238
- * `dateRange`, `dates`) to limit when the rule applies.
239
- * Not all rules support all scoping options. Entity-only rules
240
- * (e.g., {@link maxConsecutiveDays}) ignore time scoping.
241
- *
242
- * @category Rules
243
- */
244
- export interface RuleOptions {
245
- /** Who this rule applies to (role name, skill name, or member ID). */
246
- appliesTo?: string | string[];
247
- /** Restrict to specific days of the week. */
248
- dayOfWeek?: readonly [DayOfWeek, ...DayOfWeek[]];
249
- /** Restrict to a date range. */
250
- dateRange?: {
251
- start: string;
252
- end: string;
253
- };
254
- /** Restrict to specific dates (YYYY-MM-DD). */
255
- dates?: string[];
256
- /** Restrict to recurring calendar periods. */
257
- recurringPeriods?: [RecurringPeriod, ...RecurringPeriod[]];
258
- /** Defaults to `"MANDATORY"`. */
259
- priority?: Priority;
260
- }
261
- /**
262
- * Options for rules that support entity scoping only (no time scoping).
263
- *
264
- * @remarks
265
- * Used by rules whose semantics are inherently per-day or per-week
266
- * (e.g., {@link minHoursPerDay}, {@link maxConsecutiveDays}) and cannot
267
- * be meaningfully restricted to a date range or day of week.
268
- *
269
- * @category Rules
270
- */
271
- export interface EntityOnlyRuleOptions {
272
- /** Who this rule applies to (role name, skill name, or member ID). */
273
- appliesTo?: string | string[];
274
- /** Defaults to `"MANDATORY"`. */
275
- priority?: Priority;
276
- }
277
- /**
278
- * Options for {@link timeOff}.
279
- *
280
- * @remarks
281
- * At least one time scoping field is required (`dayOfWeek`, `dateRange`,
282
- * `dates`, or `recurringPeriods`). Use `from`/`until` to block only part
283
- * of a day.
284
- *
285
- * @category Rules
286
- */
287
- export interface TimeOffOptions {
288
- /** Who this rule applies to (role name, skill name, or member ID). */
289
- appliesTo?: string | string[];
290
- /** Off from this time until end of day. */
291
- from?: TimeOfDay;
292
- /** Off from start of day until this time. */
293
- until?: TimeOfDay;
294
- /** Restrict to specific days of the week. */
295
- dayOfWeek?: readonly [DayOfWeek, ...DayOfWeek[]];
296
- /** Restrict to a date range. */
297
- dateRange?: {
298
- start: string;
299
- end: string;
300
- };
301
- /** Restrict to specific dates (YYYY-MM-DD). */
302
- dates?: string[];
303
- /** Restrict to recurring calendar periods. */
304
- recurringPeriods?: [RecurringPeriod, ...RecurringPeriod[]];
305
- /** Defaults to `"MANDATORY"`. */
306
- priority?: Priority;
307
- }
308
- /**
309
- * Options for {@link assignTogether}.
310
- *
311
- * @category Rules
312
- */
313
- export interface AssignTogetherOptions {
314
- /** Defaults to `"MANDATORY"`. */
315
- priority?: Priority;
316
- }
317
- /**
318
- * Options for cost rules.
319
- *
320
- * Cost rules are objective terms, not constraints. The `priority` field from
321
- * {@link RuleOptions} does not apply.
322
- *
323
- * @category Cost Optimization
324
- */
325
- export interface CostRuleOptions {
326
- /** Who this rule applies to (role name, skill name, or member ID). */
327
- appliesTo?: string | string[];
328
- /** Restrict to specific days of the week. */
329
- dayOfWeek?: readonly [DayOfWeek, ...DayOfWeek[]];
330
- /** Restrict to a date range. */
331
- dateRange?: {
332
- start: string;
333
- end: string;
334
- };
335
- /** Restrict to specific dates (YYYY-MM-DD). */
336
- dates?: string[];
337
- /** Restrict to recurring calendar periods. */
338
- recurringPeriods?: [RecurringPeriod, ...RecurringPeriod[]];
339
- }
340
- /**
341
- * Context passed to a rule's resolve function during compilation.
342
- *
343
- * Contains the declared roles, skills, and member IDs so the resolver
344
- * can translate user-facing fields (like `appliesTo`) into internal
345
- * scoping fields.
346
- *
347
- * @category Rules
348
- */
349
- export interface RuleResolveContext {
350
- readonly roles: ReadonlySet<string>;
351
- readonly skills: ReadonlySet<string>;
352
- readonly memberIds: ReadonlySet<string>;
353
- }
354
- interface RuleEntryBase {
355
- readonly _type: "rule";
356
- readonly _rule: string;
357
- /**
358
- * Optional custom resolver. When present, `resolveRules()` calls this
359
- * instead of the default translation path. Built-in rules that need
360
- * special field mapping (e.g., `timeOff`, `assignTogether`) attach one;
361
- * all other rules use the default resolver.
362
- */
363
- readonly _resolve?: (ctx: RuleResolveContext) => Record<string, unknown> & {
364
- name: string;
365
- };
366
- }
367
- /**
368
- * An opaque rule entry returned by rule functions.
369
- *
370
- * @remarks
371
- * Pass these directly into the `rules` array of {@link ScheduleConfig}.
372
- * The internal fields are resolved during compilation.
373
- */
374
- export type RuleEntry = RuleEntryBase & Record<string, unknown>;
375
- /**
376
- * Creates a rule entry for use in {@link ScheduleConfig.rules}.
377
- *
378
- * Built-in rules use the helpers (`maxHoursPerDay`, `timeOff`, etc.).
379
- * Custom rules can use `defineRule` to create entries that plug into the
380
- * same resolution and compilation pipeline.
381
- *
382
- * @param name - Rule name. Must match a key in the rule factory registry.
383
- * @param fields - Rule-specific configuration fields.
384
- * @param resolve - Optional custom resolver. When omitted, the default
385
- * resolution applies: `appliesTo` is mapped to `roleIds`/`skillIds`/`memberIds`,
386
- * `dates` is renamed to `specificDates`, and all other fields pass through.
387
- *
388
- * @category Rules
389
- */
390
- export declare function defineRule(name: string, fields: Record<string, unknown>, resolve?: (ctx: RuleResolveContext) => Record<string, unknown> & {
391
- name: string;
392
- }): RuleEntry;
393
- /**
394
- * Limits hours per day.
395
- *
396
- * @example
397
- * ```typescript
398
- * maxHoursPerDay(10)
399
- * maxHoursPerDay(4, { appliesTo: "student", dayOfWeek: weekdays })
400
- * ```
401
- *
402
- * @category Rules
403
- */
404
- export declare function maxHoursPerDay(hours: number, opts?: RuleOptions): RuleEntry;
405
- /**
406
- * Limits hours per scheduling week.
407
- *
408
- * @example
409
- * ```typescript
410
- * maxHoursPerWeek(48)
411
- * maxHoursPerWeek(20, { appliesTo: "student" })
412
- * ```
413
- *
414
- * @category Rules
415
- */
416
- export declare function maxHoursPerWeek(hours: number, opts?: RuleOptions): RuleEntry;
417
- /**
418
- * Minimum hours when assigned on a day.
419
- *
420
- * @example
421
- * ```typescript
422
- * minHoursPerDay(4)
423
- * ```
424
- *
425
- * @category Rules
426
- */
427
- export declare function minHoursPerDay(hours: number, opts?: EntityOnlyRuleOptions): RuleEntry;
428
- /**
429
- * Minimum hours per scheduling week.
430
- *
431
- * @example
432
- * ```typescript
433
- * minHoursPerWeek(20, { priority: "HIGH" })
434
- * ```
435
- *
436
- * @category Rules
437
- */
438
- export declare function minHoursPerWeek(hours: number, opts?: EntityOnlyRuleOptions): RuleEntry;
439
- /**
440
- * Maximum distinct shifts per day.
441
- *
442
- * @example
443
- * ```typescript
444
- * maxShiftsPerDay(1)
445
- * maxShiftsPerDay(2, { appliesTo: "student", dayOfWeek: weekend })
446
- * ```
447
- *
448
- * @category Rules
449
- */
450
- export declare function maxShiftsPerDay(shifts: number, opts?: RuleOptions): RuleEntry;
451
- /**
452
- * Maximum consecutive working days.
453
- *
454
- * @example
455
- * ```typescript
456
- * maxConsecutiveDays(5)
457
- * ```
458
- *
459
- * @category Rules
460
- */
461
- export declare function maxConsecutiveDays(days: number, opts?: EntityOnlyRuleOptions): RuleEntry;
462
- /**
463
- * Once working, continue for at least this many consecutive days.
464
- *
465
- * @example
466
- * ```typescript
467
- * minConsecutiveDays(2, { priority: "HIGH" })
468
- * ```
469
- *
470
- * @category Rules
471
- */
472
- export declare function minConsecutiveDays(days: number, opts?: EntityOnlyRuleOptions): RuleEntry;
473
- /**
474
- * Minimum rest hours between shifts.
475
- *
476
- * @example
477
- * ```typescript
478
- * minRestBetweenShifts(10)
479
- * ```
480
- *
481
- * @category Rules
482
- */
483
- export declare function minRestBetweenShifts(hours: number, opts?: EntityOnlyRuleOptions): RuleEntry;
484
- /**
485
- * Prefer (`"high"`) or avoid (`"low"`) assigning. Requires `appliesTo`.
486
- *
487
- * @example
488
- * ```typescript
489
- * preference("high", { appliesTo: "waiter" })
490
- * preference("low", { appliesTo: "student", dayOfWeek: weekdays })
491
- * ```
492
- *
493
- * @category Rules
494
- */
495
- export declare function preference(level: "high" | "low", opts?: Omit<RuleOptions, "priority">): RuleEntry;
496
- /**
497
- * Prefer assigning to shifts at a specific location. Requires `appliesTo`.
498
- *
499
- * @example
500
- * ```typescript
501
- * preferLocation("terrace", { appliesTo: "alice" })
502
- * ```
503
- *
504
- * @category Rules
505
- */
506
- export declare function preferLocation(locationId: string, opts?: EntityOnlyRuleOptions): RuleEntry;
507
- /**
508
- * Tells the solver to minimize total labor cost.
509
- *
510
- * @remarks
511
- * Without this rule, cost modifiers only affect post-solve calculation.
512
- * When present, the solver actively prefers cheaper assignments.
513
- *
514
- * For hourly members, penalizes each assignment proportionally to cost.
515
- * For salaried members, adds a fixed weekly salary cost when they have
516
- * any assignment that week (zero marginal cost up to contracted hours).
517
- *
518
- * Cost modifiers adjust the calculation:
519
- * - `dayMultiplier(factor, opts?)` - multiply base rate on specific days
520
- * - `daySurcharge(amount, opts?)` - flat extra per hour on specific days
521
- * - `timeSurcharge(amount, window, opts?)` - flat extra per hour during a time window
522
- * - `overtimeMultiplier({ after, factor }, opts?)` - weekly overtime multiplier
523
- * - `overtimeSurcharge({ after, amount }, opts?)` - weekly overtime surcharge
524
- * - `dailyOvertimeMultiplier({ after, factor }, opts?)` - daily overtime multiplier
525
- * - `dailyOvertimeSurcharge({ after, amount }, opts?)` - daily overtime surcharge
526
- * - `tieredOvertimeMultiplier(tiers, opts?)` - multiple overtime thresholds
527
- *
528
- * @example
529
- * ```ts
530
- * minimizeCost()
531
- * ```
532
- *
533
- * @category Cost Optimization
534
- */
535
- export declare function minimizeCost(opts?: CostRuleOptions): RuleEntry;
536
- /**
537
- * Multiplies the base rate for assignments on specified days.
538
- *
539
- * @remarks
540
- * The base cost (1x) is already counted by {@link minimizeCost};
541
- * this rule adds only the extra portion above 1x.
542
- *
543
- * @category Cost Optimization
544
- *
545
- * @example Weekend multiplier
546
- * ```typescript
547
- * dayMultiplier(1.5, { dayOfWeek: weekend })
548
- * ```
549
- */
550
- export declare function dayMultiplier(factor: number, opts?: CostRuleOptions): RuleEntry;
551
- /**
552
- * Adds a flat extra amount per hour for assignments on specified days.
553
- *
554
- * @remarks
555
- * The surcharge is independent of the member's base rate.
556
- *
557
- * @category Cost Optimization
558
- *
559
- * @example Weekend surcharge
560
- * ```typescript
561
- * daySurcharge(500, { dayOfWeek: weekend })
562
- * ```
563
- */
564
- export declare function daySurcharge(amountPerHour: number, opts?: CostRuleOptions): RuleEntry;
565
- /**
566
- * Adds a flat surcharge per hour for the portion of a shift that overlaps a time-of-day window.
567
- *
568
- * @remarks
569
- * The window supports overnight spans (e.g., 22:00-06:00). The surcharge
570
- * is independent of the member's base rate.
571
- *
572
- * @param amountPerHour - Flat surcharge per hour in smallest currency unit
573
- * @param window - Time-of-day window
574
- * @param opts - Entity and time scoping
575
- *
576
- * @category Cost Optimization
577
- *
578
- * @example Night differential
579
- * ```typescript
580
- * timeSurcharge(200, { from: t(22), until: t(6) })
581
- * ```
582
- */
583
- export declare function timeSurcharge(amountPerHour: number, window: {
584
- from: TimeOfDay;
585
- until: TimeOfDay;
586
- }, opts?: CostRuleOptions): RuleEntry;
587
- /**
588
- * Applies a multiplier to hours beyond a weekly threshold.
589
- *
590
- * @remarks
591
- * Only the extra portion above 1x is added (the base cost is already
592
- * counted by {@link minimizeCost}).
593
- *
594
- * @category Cost Optimization
595
- *
596
- * @example
597
- * ```typescript
598
- * overtimeMultiplier({ after: 40, factor: 1.5 })
599
- * ```
600
- */
601
- export declare function overtimeMultiplier(opts: {
602
- after: number;
603
- factor: number;
604
- } & CostRuleOptions): RuleEntry;
605
- /**
606
- * Adds a flat surcharge per hour beyond a weekly threshold.
607
- *
608
- * @remarks
609
- * The surcharge is independent of the member's base rate.
610
- *
611
- * @category Cost Optimization
612
- *
613
- * @example
614
- * ```typescript
615
- * overtimeSurcharge({ after: 40, amount: 1000 })
616
- * ```
617
- */
618
- export declare function overtimeSurcharge(opts: {
619
- after: number;
620
- amount: number;
621
- } & CostRuleOptions): RuleEntry;
622
- /**
623
- * Applies a multiplier to hours beyond a daily threshold.
624
- *
625
- * @remarks
626
- * Only the extra portion above 1x is added (the base cost is already
627
- * counted by {@link minimizeCost}).
628
- *
629
- * @category Cost Optimization
630
- *
631
- * @example
632
- * ```typescript
633
- * dailyOvertimeMultiplier({ after: 8, factor: 1.5 })
634
- * ```
635
- */
636
- export declare function dailyOvertimeMultiplier(opts: {
637
- after: number;
638
- factor: number;
639
- } & CostRuleOptions): RuleEntry;
640
- /**
641
- * Adds a flat surcharge per hour beyond a daily threshold.
642
- *
643
- * @remarks
644
- * The surcharge is independent of the member's base rate.
645
- *
646
- * @category Cost Optimization
647
- *
648
- * @example
649
- * ```typescript
650
- * dailyOvertimeSurcharge({ after: 8, amount: 500 })
651
- * ```
652
- */
653
- export declare function dailyOvertimeSurcharge(opts: {
654
- after: number;
655
- amount: number;
656
- } & CostRuleOptions): RuleEntry;
657
- /**
658
- * Applies multiple overtime thresholds with increasing multipliers.
659
- *
660
- * @remarks
661
- * Each tier applies only to the hours between its threshold and the next.
662
- * Tiers must be sorted by threshold ascending.
663
- *
664
- * @category Cost Optimization
665
- *
666
- * @example
667
- * ```typescript
668
- * // Hours 0-40: base rate
669
- * // Hours 40-48: 1.5x
670
- * // Hours 48+: 2.0x
671
- * tieredOvertimeMultiplier([
672
- * { after: 40, factor: 1.5 },
673
- * { after: 48, factor: 2.0 },
674
- * ])
675
- * ```
676
- */
677
- export declare function tieredOvertimeMultiplier(tiers: [OvertimeTier, ...OvertimeTier[]], opts?: CostRuleOptions): RuleEntry;
678
- /**
679
- * Block assignments during specified periods.
680
- * Requires at least one time scope (`dayOfWeek`, `dateRange`, `dates`, or `from`/`until`).
681
- *
682
- * @example
683
- * ```typescript
684
- * // Full days off
685
- * timeOff({ appliesTo: "alice", dateRange: { start: "2024-02-01", end: "2024-02-05" } })
686
- *
687
- * // Every weekend off
688
- * timeOff({ appliesTo: "mauro", dayOfWeek: weekend })
689
- *
690
- * // Wednesday afternoons off
691
- * timeOff({ appliesTo: "student", dayOfWeek: ["wednesday"], from: t(14) })
692
- * ```
693
- *
694
- * @category Rules
695
- */
696
- export declare function timeOff(opts: TimeOffOptions): RuleEntry;
697
- /**
698
- * Members work the same shifts on days they are both assigned.
699
- *
700
- * @example
701
- * ```typescript
702
- * assignTogether(["alice", "bob"])
703
- * assignTogether(["alice", "bob", "charlie"], { priority: "HIGH" })
704
- * ```
705
- *
706
- * @category Rules
707
- */
708
- export declare function assignTogether(memberIds: [string, string, ...string[]], opts?: AssignTogetherOptions): RuleEntry;
709
- /** A value that can be passed to {@link Schedule.with}. */
710
- type WithArg = Schedule | SchedulingMember[];
711
- /** Status of a solve attempt, using idiomatic lowercase TypeScript literals. */
712
- export type SolveStatus = "optimal" | "feasible" | "infeasible" | "no_solution";
713
- /**
714
- * Result of {@link Schedule.solve}.
715
- *
716
- * @category Schedule Definition
717
- */
718
- export interface SolveResult {
719
- /** Outcome of the solve attempt. */
720
- status: SolveStatus;
721
- /** Shift assignments (empty when infeasible or no solution). */
722
- assignments: ShiftAssignment[];
723
- /** Validation diagnostics from compilation. */
724
- validation: ScheduleValidation;
725
- /** Cost breakdown (present when cost rules are used and a solution is found). */
726
- cost?: CostBreakdown;
727
- }
728
- /**
729
- * Options for {@link Schedule.solve} and {@link Schedule.compile}.
730
- *
731
- * @category Schedule Definition
732
- */
733
- export interface SolveOptions {
734
- /** The date range to schedule. */
735
- dateRange: {
736
- start: string;
737
- end: string;
738
- };
739
- /**
740
- * Fixed assignments from a prior solve (e.g., rolling schedule).
741
- * These are injected as fixed variables in the solver.
742
- *
743
- * Not yet implemented. Providing pinned assignments throws an error.
744
- */
745
- pinned?: ShiftAssignment[];
746
- }
747
- /**
748
- * Configuration for {@link schedule}.
749
- *
750
- * @remarks
751
- * Coverage entries for the same semantic time and target stack additively.
752
- * An unscoped entry applies every day; adding a weekend-only entry on top
753
- * doubles the count on those days. Use mutually exclusive `dayOfWeek` on
754
- * both entries to avoid stacking. See {@link cover} for details.
755
- *
756
- * `roleIds`, `times`, `coverage`, and `shiftPatterns` are required.
757
- * These four fields form the minimum solvable schedule.
758
- *
759
- * @category Schedule Definition
760
- */
761
- export interface ScheduleConfig<R extends readonly string[] = readonly string[], S extends readonly string[] = readonly string[], T extends Record<string, SemanticTimeEntry> = Record<string, SemanticTimeEntry>> {
762
- /** Declared role IDs. */
763
- roleIds: R;
764
- /** Declared skill IDs. */
765
- skillIds?: S;
766
- /** Named semantic time periods. */
767
- times: T;
768
- /** Staffing requirements per time period (entries stack additively). */
769
- coverage: CoverageEntry<keyof T & string, R[number] | NonNullable<S>[number]>[];
770
- /** Available shift patterns. */
771
- shiftPatterns: ShiftPattern[];
772
- /** Scheduling rules and constraints. */
773
- rules?: RuleEntry[];
774
- /**
775
- * Custom rule factories. Keys are rule names, values are functions
776
- * that take a config object and return a {@link CompilationRule}.
777
- * Built-in rule names cannot be overridden.
778
- */
779
- ruleFactories?: Record<string, CreateCpsatRuleFunction>;
780
- /** Team members (typically added via `.with()` at runtime). */
781
- members?: SchedulingMember[];
782
- /** Days of the week the business operates (inclusion filter). */
783
- dayOfWeek?: readonly [DayOfWeek, ...DayOfWeek[]];
784
- /** Which day starts the week for weekly rules. Defaults to `"monday"`. */
785
- weekStartsOn?: DayOfWeek;
786
- }
787
- /** Internal representation of a fully merged schedule. */
788
- interface MergedScheduleConfig {
789
- roleIds: string[];
790
- skillIds: string[];
791
- times: Record<string, SemanticTimeEntry>;
792
- coverage: CoverageEntry[];
793
- shiftPatterns: ShiftPattern[];
794
- rules: RuleEntry[];
795
- ruleFactories: Record<string, CreateCpsatRuleFunction>;
796
- members: SchedulingMember[];
797
- dayOfWeek?: readonly [DayOfWeek, ...DayOfWeek[]];
798
- weekStartsOn?: DayOfWeek;
799
- }
800
- /**
801
- * An immutable schedule definition.
802
- *
803
- * Created by {@link schedule}, composed via {@link Schedule.with},
804
- * and solved via {@link Schedule.solve}.
805
- *
806
- * @category Schedule Definition
807
- */
808
- export declare class Schedule {
809
- #private;
810
- /** @internal */
811
- constructor(config: MergedScheduleConfig);
812
- /** @internal Returns a defensive copy of the config for merging. */
813
- _getConfig(): MergedScheduleConfig;
814
- /** Declared role IDs. */
815
- get roleIds(): readonly string[];
816
- /** Declared skill IDs. */
817
- get skillIds(): readonly string[];
818
- /** Names of declared semantic times. */
819
- get timeNames(): readonly string[];
820
- /** Shift pattern IDs. */
821
- get shiftPatternIds(): readonly string[];
822
- /** Internal rule identifiers in kebab-case. */
823
- get ruleNames(): readonly string[];
824
- /**
825
- * Merges schedules or members onto this schedule, returning a new
826
- * immutable `Schedule`. The original is untouched.
827
- *
828
- * Accepts any mix of `Schedule` instances and `SchedulingMember[]` arrays.
829
- *
830
- * Merge semantics (when merging schedules):
831
- * - Roles: union (additive)
832
- * - Skills: union (additive)
833
- * - Times: additive; error on name collision
834
- * - Coverage: additive
835
- * - Shift patterns: additive; error on ID collision
836
- * - Rules: additive
837
- * - Members: additive; error on duplicate ID
838
- *
839
- * Validation runs eagerly: role/skill disjointness, coverage targets
840
- * referencing declared roles/skills, member role references, etc.
841
- */
842
- with(...args: WithArg[]): Schedule;
843
- /**
844
- * Compiles, validates, solves, and parses in one call.
845
- *
846
- * @param client - Solver client (e.g., `new HttpSolverClient(fetch, url)`)
847
- * @param options - Date range and optional pinned assignments
848
- */
849
- solve(client: SolverClient, options: SolveOptions): Promise<SolveResult>;
850
- /**
851
- * Diagnostic escape hatch. Compiles the schedule without solving.
852
- *
853
- * @param options - Date range and optional pinned assignments
854
- */
855
- compile(options: SolveOptions): CompilationResult & {
856
- builder: ModelBuilder;
857
- };
858
- }
859
- /**
860
- * Create a schedule definition.
861
- *
862
- * Returns an immutable {@link Schedule} that can be composed via `.with()`
863
- * and solved via `.solve()`.
864
- *
865
- * @example
866
- * ```typescript
867
- * const venue = schedule({
868
- * roleIds: ["waiter", "runner", "manager"],
869
- * skillIds: ["senior"],
870
- * times: {
871
- * lunch: time({ startTime: t(12), endTime: t(15) }),
872
- * dinner: time(
873
- * { startTime: t(17), endTime: t(21) },
874
- * { startTime: t(18), endTime: t(22), dayOfWeek: weekend },
875
- * ),
876
- * },
877
- * coverage: [
878
- * cover("lunch", "waiter", 2),
879
- * cover("dinner", "waiter", 4, { dayOfWeek: weekdays }),
880
- * cover("dinner", "waiter", 5, { dayOfWeek: weekend }),
881
- * cover("dinner", "manager", 1),
882
- * ],
883
- * shiftPatterns: [
884
- * shift("lunch_shift", t(11, 30), t(15)),
885
- * shift("evening", t(17), t(22)),
886
- * ],
887
- * rules: [
888
- * maxHoursPerDay(10),
889
- * maxHoursPerWeek(48),
890
- * minRestBetweenShifts(11),
891
- * ],
892
- * });
893
- * ```
894
- *
895
- * @category Schedule Definition
896
- */
897
- export declare function schedule<const R extends readonly string[], const S extends readonly string[], const T extends Record<string, SemanticTimeEntry>>(config: ScheduleConfig<R, S, T>): Schedule;
898
- /**
899
- * Create a partial schedule for composition via `.with()`.
900
- *
901
- * Unlike {@link schedule}, all fields are optional. Use this for
902
- * schedules that layer rules, coverage, or other config onto a
903
- * complete base schedule.
904
- *
905
- * @example
906
- * ```typescript
907
- * const companyPolicy = partialSchedule({
908
- * rules: [maxHoursPerWeek(40), minRestBetweenShifts(11)],
909
- * });
910
- *
911
- * const ready = venue.with(companyPolicy, teamMembers);
912
- * ```
913
- *
914
- * @category Schedule Definition
915
- */
916
- export declare function partialSchedule(config: Partial<ScheduleConfig>): Schedule;
917
- //# sourceMappingURL=schedule.d.ts.map