stitchkit 0.78.0 → 0.79.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 (84) hide show
  1. package/dist/agent-runtime-browser.js +53 -581
  2. package/dist/agent-runtime-coding-tools.js +6 -5
  3. package/dist/agent-runtime-harness.js +21 -94
  4. package/dist/agent-runtime-openrouter.js +1 -1
  5. package/dist/agent-runtime.js +68 -64
  6. package/dist/application/kernel.d.ts.map +1 -1
  7. package/dist/application/schemas.d.ts +2 -0
  8. package/dist/application/schemas.d.ts.map +1 -1
  9. package/dist/application/watch-hub.d.ts.map +1 -1
  10. package/dist/application-diagnostic-journal.js +14 -96
  11. package/dist/application-opentelemetry.js +6 -92
  12. package/dist/application-schemas.js +2 -1
  13. package/dist/application.js +158 -1802
  14. package/dist/cli.js +13 -11
  15. package/dist/contract/index.js +7 -4
  16. package/dist/index-2qzskm8h.js +63 -0
  17. package/dist/{index-93xp5tgg.js → index-2rwwmr7v.js} +3 -3
  18. package/dist/{index-kw12fsbc.js → index-3gye9wzb.js} +7 -3
  19. package/dist/{index-1ckavx4h.js → index-3z73fh2c.js} +1 -49
  20. package/dist/index-4fpa9dy2.js +51 -0
  21. package/dist/{index-cwp38wxn.js → index-5mtc969c.js} +2 -2
  22. package/dist/index-5s3zajp8.js +192 -0
  23. package/dist/index-6s7n2v50.js +583 -0
  24. package/dist/{index-qaajjfp6.js → index-758zx2ha.js} +15 -94
  25. package/dist/{index-qyrqwr4c.js → index-77fekveh.js} +4 -1
  26. package/dist/{index-k45qqrdh.js → index-7ag81v2f.js} +13 -166
  27. package/dist/{index-n1g2xm6a.js → index-7gnkny4z.js} +124 -1
  28. package/dist/index-7zbps32p.js +89 -0
  29. package/dist/index-85vfqd7m.js +135 -0
  30. package/dist/{index-4ntp63ps.js → index-9s6z8vgf.js} +18 -142
  31. package/dist/index-a916km3r.js +45 -0
  32. package/dist/index-b9aefrqd.js +20 -0
  33. package/dist/index-dre2ywck.js +48 -0
  34. package/dist/{index-s5tn4kdv.js → index-dwf1f2ap.js} +3 -3
  35. package/dist/{index-wwst0td5.js → index-dx9xehwt.js} +1 -1
  36. package/dist/{index-5r0ak8fr.js → index-dxesg10d.js} +4 -4
  37. package/dist/{index-aczggrty.js → index-dxjjv399.js} +2 -2
  38. package/dist/{index-j6mfaw26.js → index-egaabxkz.js} +3 -3
  39. package/dist/index-evcnmsc3.js +866 -0
  40. package/dist/{index-efm026pw.js → index-fxz0v7vg.js} +86 -86
  41. package/dist/{index-56fm73re.js → index-hb5pf3s4.js} +1 -1
  42. package/dist/{index-n7apa6sy.js → index-k9ay6v6d.js} +24 -275
  43. package/dist/index-kzfs85xp.js +9 -0
  44. package/dist/{index-vbf2p6me.js → index-m9kzax52.js} +91 -89
  45. package/dist/{index-22by16v6.js → index-mgtxfe6b.js} +1 -1
  46. package/dist/index-p7hgdyhb.js +22 -0
  47. package/dist/index-pq95qkbf.js +0 -0
  48. package/dist/index-t0z5p5w6.js +318 -0
  49. package/dist/{index-31k1ns1s.js → index-vwp69871.js} +13 -11
  50. package/dist/index-wc4x00bn.js +103 -0
  51. package/dist/{index-aewy3x5j.js → index-xcetq6j3.js} +10 -8
  52. package/dist/{index-7z69kyrh.js → index-y01f4223.js} +24 -40
  53. package/dist/{index-dmfn9m4x.js → index-ywd0y6m1.js} +20 -341
  54. package/dist/index.js +46 -407
  55. package/dist/live.js +6 -3
  56. package/dist/node.js +17 -14
  57. package/dist/observability/index.js +8 -7
  58. package/dist/primitives.js +4 -2
  59. package/dist/react.js +1 -1
  60. package/dist/remote.js +7 -3
  61. package/dist/server/index.js +32 -45
  62. package/dist/telegram.js +1 -1
  63. package/dist/testing.js +90 -1576
  64. package/dist/tool-invoker.js +11 -9
  65. package/dist/tools/async-operation-contract.d.ts +61 -0
  66. package/dist/tools/async-operation-contract.d.ts.map +1 -0
  67. package/dist/tools/async-operation.d.ts +2 -47
  68. package/dist/tools/async-operation.d.ts.map +1 -1
  69. package/dist/tools/view-file-contract.d.ts +98 -0
  70. package/dist/tools/view-file-contract.d.ts.map +1 -0
  71. package/dist/tools/view-file.d.ts +4 -83
  72. package/dist/tools/view-file.d.ts.map +1 -1
  73. package/dist/tools-contract.d.ts +29 -0
  74. package/dist/tools-contract.d.ts.map +1 -0
  75. package/dist/tools-contract.js +24 -0
  76. package/dist/tools.d.ts +3 -3
  77. package/dist/tools.d.ts.map +1 -1
  78. package/dist/tools.js +61 -140
  79. package/llms-full.txt +38 -3
  80. package/package.json +9 -6
  81. package/dist/index-anyqnqcv.js +0 -79
  82. package/dist/index-ksp6e2ye.js +0 -24
  83. package/dist/index-vj3vvpaa.js +0 -307
  84. package/dist/index-wfq8zerm.js +0 -92
@@ -0,0 +1,583 @@
1
+ import {
2
+ ApplicationIdSchema
3
+ } from "./index-3gye9wzb.js";
4
+ import {
5
+ createBoundedChannel
6
+ } from "./index-7gnkny4z.js";
7
+
8
+ // src/application/latest-sink.ts
9
+ import { z } from "zod";
10
+ var SnapshotRevisionSchema = z.number().int().nonnegative();
11
+ var ApplicationSnapshotSinkStatusSchema = z.object({
12
+ accepting: z.boolean(),
13
+ received: z.number().int().nonnegative(),
14
+ accepted: z.number().int().nonnegative(),
15
+ rejected: z.number().int().nonnegative(),
16
+ delivered: z.number().int().nonnegative(),
17
+ coalesced: z.number().int().nonnegative(),
18
+ failed: z.number().int().nonnegative(),
19
+ inFlight: z.boolean(),
20
+ pending: z.boolean(),
21
+ lastAcceptedRevision: SnapshotRevisionSchema.optional(),
22
+ lastDeliveredRevision: SnapshotRevisionSchema.optional()
23
+ }).strict().readonly();
24
+ function createApplicationSnapshotSink(config) {
25
+ let accepting = true;
26
+ let received = 0;
27
+ let accepted = 0;
28
+ let rejected = 0;
29
+ let delivered = 0;
30
+ let coalesced = 0;
31
+ let failed = 0;
32
+ let lastAcceptedRevision;
33
+ let lastDeliveredRevision;
34
+ let inFlight;
35
+ let closePromise;
36
+ let resolveClose;
37
+ const pending = createBoundedChannel({
38
+ policy: "latest",
39
+ maxItems: 1,
40
+ maxBytes: 1,
41
+ sizeOf: () => 1
42
+ });
43
+ const getStatus = () => ApplicationSnapshotSinkStatusSchema.parse({
44
+ accepting,
45
+ received,
46
+ accepted,
47
+ rejected,
48
+ delivered,
49
+ coalesced,
50
+ failed,
51
+ inFlight: inFlight !== undefined,
52
+ pending: pending.getSnapshot().queuedItems > 0,
53
+ ...lastAcceptedRevision !== undefined && { lastAcceptedRevision },
54
+ ...lastDeliveredRevision !== undefined && { lastDeliveredRevision }
55
+ });
56
+ const reportFailure = (error, snapshot) => {
57
+ if (!config.onSinkError)
58
+ return;
59
+ Promise.resolve().then(() => config.onSinkError?.({ error, snapshot })).catch(() => {
60
+ return;
61
+ });
62
+ };
63
+ const settleCloseIfIdle = () => {
64
+ if (accepting || inFlight || pending.getSnapshot().queuedItems > 0 || !resolveClose)
65
+ return;
66
+ const resolve = resolveClose;
67
+ resolveClose = undefined;
68
+ resolve(getStatus());
69
+ };
70
+ const startWrite = (snapshot) => {
71
+ const write = Promise.resolve().then(() => config.write(snapshot)).then(() => {
72
+ delivered += 1;
73
+ lastDeliveredRevision = snapshot.revision;
74
+ }).catch((error) => {
75
+ failed += 1;
76
+ reportFailure(error, snapshot);
77
+ }).finally(() => {
78
+ if (pending.getSnapshot().queuedItems > 0) {
79
+ pending.next().then((next) => {
80
+ if (next.done) {
81
+ inFlight = undefined;
82
+ settleCloseIfIdle();
83
+ } else {
84
+ startWrite(next.value);
85
+ }
86
+ });
87
+ } else {
88
+ inFlight = undefined;
89
+ settleCloseIfIdle();
90
+ }
91
+ });
92
+ inFlight = write;
93
+ };
94
+ return {
95
+ publish(snapshot) {
96
+ received += 1;
97
+ const revision = SnapshotRevisionSchema.parse(snapshot.revision);
98
+ if (!accepting || lastAcceptedRevision !== undefined && revision <= lastAcceptedRevision) {
99
+ rejected += 1;
100
+ return false;
101
+ }
102
+ accepted += 1;
103
+ lastAcceptedRevision = revision;
104
+ if (!inFlight) {
105
+ startWrite(snapshot);
106
+ } else {
107
+ const offered = pending.offer(snapshot);
108
+ if (offered.outcome === "coalesced")
109
+ coalesced += offered.replaced;
110
+ }
111
+ return true;
112
+ },
113
+ getStatus,
114
+ close() {
115
+ if (closePromise)
116
+ return closePromise;
117
+ accepting = false;
118
+ pending.close({ mode: "drain" });
119
+ closePromise = new Promise((resolve) => {
120
+ resolveClose = resolve;
121
+ settleCloseIfIdle();
122
+ });
123
+ return closePromise;
124
+ }
125
+ };
126
+ }
127
+
128
+ // src/application/activity.ts
129
+ import { z as z2 } from "zod";
130
+ var BoundedOperationalIdSchema = z2.string().min(1).max(64).regex(/^[a-zA-Z0-9][a-zA-Z0-9._:-]*$/);
131
+ var NonNegativeIntegerSchema = z2.number().int().nonnegative();
132
+ var ActivityIdSchema = BoundedOperationalIdSchema;
133
+ var ActivityStageIdSchema = BoundedOperationalIdSchema;
134
+ var ActivityStageSnapshotSchema = z2.object({
135
+ id: ActivityStageIdSchema,
136
+ active: NonNegativeIntegerSchema,
137
+ queued: NonNegativeIntegerSchema,
138
+ completed: NonNegativeIntegerSchema,
139
+ failed: NonNegativeIntegerSchema
140
+ }).strict().readonly();
141
+ var ActivityTotalsSchema = z2.object({
142
+ active: NonNegativeIntegerSchema,
143
+ queued: NonNegativeIntegerSchema,
144
+ completed: NonNegativeIntegerSchema,
145
+ failed: NonNegativeIntegerSchema
146
+ }).strict().readonly();
147
+ var ActivitySnapshotSchema = z2.object({
148
+ id: ActivityIdSchema,
149
+ epoch: z2.string().uuid(),
150
+ revision: NonNegativeIntegerSchema,
151
+ capturedAt: z2.string().datetime({ offset: true }),
152
+ changedAt: z2.string().datetime({ offset: true }),
153
+ stages: z2.array(ActivityStageSnapshotSchema).min(1).max(64).readonly(),
154
+ totals: ActivityTotalsSchema
155
+ }).strict().readonly();
156
+ var ActivityLiveStateSchema = z2.enum(["active", "queued"]);
157
+ var ActivityTokenBrand = Symbol("stitchkit.application.activity");
158
+ function emptyCounters() {
159
+ return { active: 0, queued: 0, completed: 0, failed: 0 };
160
+ }
161
+ function totalsOf(stages) {
162
+ return stages.reduce((totals, stage) => ({
163
+ active: totals.active + stage.active,
164
+ queued: totals.queued + stage.queued,
165
+ completed: totals.completed + stage.completed,
166
+ failed: totals.failed + stage.failed
167
+ }), emptyCounters());
168
+ }
169
+ function createActivityProjection(config) {
170
+ const id = ActivityIdSchema.parse(config.id);
171
+ const declaredStages = z2.array(ActivityStageIdSchema).min(1).max(64).parse(config.stages);
172
+ const uniqueStages = new Set(declaredStages);
173
+ if (uniqueStages.size !== declaredStages.length) {
174
+ throw new Error("[stitchkit] createActivityProjection: stage ids must be unique");
175
+ }
176
+ const epoch = z2.string().uuid().parse(config.epoch ?? crypto.randomUUID());
177
+ const now = config.now ?? (() => new Date);
178
+ const counters = new Map(declaredStages.map((stage) => [stage, emptyCounters()]));
179
+ const activities = new WeakMap;
180
+ const subscribers = new Set;
181
+ let revision = 0;
182
+ let changedAt = now().toISOString();
183
+ const countersFor = (stage) => {
184
+ const value = counters.get(stage);
185
+ if (!value) {
186
+ throw new Error(`[stitchkit] createActivityProjection: undeclared stage "${stage}"`);
187
+ }
188
+ return value;
189
+ };
190
+ const getSnapshot = () => {
191
+ const stages = declaredStages.map((stage) => ({ id: stage, ...countersFor(stage) }));
192
+ return ActivitySnapshotSchema.parse({
193
+ id,
194
+ epoch,
195
+ revision,
196
+ capturedAt: now().toISOString(),
197
+ changedAt,
198
+ stages,
199
+ totals: totalsOf(stages)
200
+ });
201
+ };
202
+ const publishChange = () => {
203
+ revision += 1;
204
+ changedAt = now().toISOString();
205
+ const snapshot = getSnapshot();
206
+ for (const subscriber of subscribers)
207
+ subscriber.publish(snapshot);
208
+ };
209
+ const requireActivity = (token) => {
210
+ const activity = activities.get(token);
211
+ if (!activity) {
212
+ throw new Error("[stitchkit] activity token belongs to another projection");
213
+ }
214
+ return activity;
215
+ };
216
+ const leaveLiveState = (activity) => {
217
+ if (activity.state === "active" || activity.state === "queued") {
218
+ countersFor(activity.stage)[activity.state] -= 1;
219
+ }
220
+ };
221
+ const settle = (token, terminal) => {
222
+ const activity = requireActivity(token);
223
+ if (activity.state === "completed" || activity.state === "failed")
224
+ return false;
225
+ leaveLiveState(activity);
226
+ countersFor(activity.stage)[terminal] += 1;
227
+ activity.state = terminal;
228
+ publishChange();
229
+ return true;
230
+ };
231
+ return {
232
+ open(stage, rawState = "active") {
233
+ const parsedStage = ActivityStageIdSchema.parse(stage);
234
+ const state = ActivityLiveStateSchema.parse(rawState);
235
+ countersFor(parsedStage)[state] += 1;
236
+ const token = Object.freeze({
237
+ get [ActivityTokenBrand]() {
238
+ return true;
239
+ }
240
+ });
241
+ activities.set(token, { stage: parsedStage, state });
242
+ publishChange();
243
+ return token;
244
+ },
245
+ transition(token, input) {
246
+ const activity = requireActivity(token);
247
+ if (activity.state === "completed" || activity.state === "failed") {
248
+ throw new Error("[stitchkit] cannot transition a terminal activity");
249
+ }
250
+ const stage = ActivityStageIdSchema.parse(input.stage);
251
+ const state = ActivityLiveStateSchema.parse(input.state);
252
+ countersFor(stage);
253
+ if (activity.stage === stage && activity.state === state)
254
+ return false;
255
+ leaveLiveState(activity);
256
+ countersFor(stage)[state] += 1;
257
+ activity.stage = stage;
258
+ activity.state = state;
259
+ publishChange();
260
+ return true;
261
+ },
262
+ complete: (token) => settle(token, "completed"),
263
+ fail: (token) => settle(token, "failed"),
264
+ getSnapshot,
265
+ subscribe(listener) {
266
+ const sink = createApplicationSnapshotSink({
267
+ write: listener,
268
+ ...config.onSubscriberError && { onSinkError: config.onSubscriberError }
269
+ });
270
+ subscribers.add(sink);
271
+ sink.publish(getSnapshot());
272
+ return () => {
273
+ subscribers.delete(sink);
274
+ sink.close();
275
+ };
276
+ }
277
+ };
278
+ }
279
+
280
+ // src/application/schedule.ts
281
+ import { z as z3 } from "zod";
282
+ var NonNegativeSafeIntegerSchema = z3.number().int().nonnegative().refine(Number.isSafeInteger, "Expected a safe integer");
283
+ var PositiveSafeIntegerSchema = NonNegativeSafeIntegerSchema.refine((value) => value > 0, "Expected a positive integer");
284
+ var ManagedScheduleOverlapSchema = z3.discriminatedUnion("mode", [
285
+ z3.object({ mode: z3.literal("skip") }).readonly(),
286
+ z3.object({ mode: z3.literal("queue-one") }).readonly(),
287
+ z3.object({
288
+ mode: z3.literal("parallel"),
289
+ maxConcurrent: PositiveSafeIntegerSchema
290
+ }).readonly()
291
+ ]);
292
+ var ManagedScheduleErrorPolicySchema = z3.enum(["continue", "stop-schedule"]);
293
+ var ManagedScheduleDescriptorSchema = z3.object({
294
+ id: ApplicationIdSchema,
295
+ everyMs: PositiveSafeIntegerSchema,
296
+ startAfterMs: NonNegativeSafeIntegerSchema,
297
+ overlap: ManagedScheduleOverlapSchema,
298
+ errorPolicy: ManagedScheduleErrorPolicySchema
299
+ }).readonly();
300
+ var ManagedScheduleStatusSchema = z3.object({
301
+ descriptor: ManagedScheduleDescriptorSchema,
302
+ state: z3.enum(["inactive", "scheduled", "running", "draining", "stopped"]),
303
+ revision: NonNegativeSafeIntegerSchema,
304
+ capturedAt: z3.string().datetime({ offset: true }),
305
+ changedAt: z3.string().datetime({ offset: true }),
306
+ accepting: z3.boolean(),
307
+ active: NonNegativeSafeIntegerSchema,
308
+ queued: z3.boolean(),
309
+ runsStarted: NonNegativeSafeIntegerSchema,
310
+ runsCompleted: NonNegativeSafeIntegerSchema,
311
+ runsFailed: NonNegativeSafeIntegerSchema,
312
+ ticksSkipped: NonNegativeSafeIntegerSchema,
313
+ nextRunAt: z3.string().datetime({ offset: true }).nullable(),
314
+ lastScheduledAt: z3.string().datetime({ offset: true }).nullable(),
315
+ lastStartedAt: z3.string().datetime({ offset: true }).nullable(),
316
+ lastFinishedAt: z3.string().datetime({ offset: true }).nullable()
317
+ }).readonly();
318
+ var systemClock = {
319
+ now: () => performance.now(),
320
+ wallNow: () => new Date,
321
+ schedule(callback, delayMs) {
322
+ const timer = setTimeout(callback, delayMs);
323
+ return { cancel: () => clearTimeout(timer) };
324
+ }
325
+ };
326
+ var DEFAULT_OVERLAP = { mode: "skip" };
327
+ function createManagedSchedule(config) {
328
+ const descriptor = ManagedScheduleDescriptorSchema.parse({
329
+ id: config.id,
330
+ everyMs: config.everyMs,
331
+ startAfterMs: config.startAfterMs ?? config.everyMs,
332
+ overlap: config.overlap ?? DEFAULT_OVERLAP,
333
+ errorPolicy: config.errorPolicy ?? "continue"
334
+ });
335
+ const dependsOn = config.dependsOn?.map((id) => ApplicationIdSchema.parse(id));
336
+ const clock = config.clock ?? systemClock;
337
+ let revision = 0;
338
+ let accepting = false;
339
+ let activated = false;
340
+ let stopped = false;
341
+ let timer = null;
342
+ let activationContext = null;
343
+ let nextRunAt = null;
344
+ let queuedAt = null;
345
+ let runsStarted = 0;
346
+ let runsCompleted = 0;
347
+ let runsFailed = 0;
348
+ let ticksSkipped = 0;
349
+ let lastScheduledAt = null;
350
+ let lastStartedAt = null;
351
+ let lastFinishedAt = null;
352
+ let changedAt = clock.wallNow().toISOString();
353
+ const active = new Set;
354
+ const changed = () => {
355
+ revision += 1;
356
+ changedAt = clock.wallNow().toISOString();
357
+ };
358
+ const cancelFuture = () => {
359
+ timer?.cancel();
360
+ timer = null;
361
+ nextRunAt = null;
362
+ queuedAt = null;
363
+ };
364
+ const stopAdmission = () => {
365
+ if (!accepting && stopped)
366
+ return;
367
+ accepting = false;
368
+ stopped = true;
369
+ cancelFuture();
370
+ changed();
371
+ };
372
+ const reportError = (error, context) => {
373
+ if (!config.onError)
374
+ return;
375
+ Promise.resolve().then(() => config.onError?.(error, context)).catch(() => {});
376
+ };
377
+ const state = () => {
378
+ if (!activated)
379
+ return stopped ? "stopped" : "inactive";
380
+ if (!accepting)
381
+ return active.size > 0 ? "draining" : "stopped";
382
+ return active.size > 0 ? "running" : "scheduled";
383
+ };
384
+ const wallAt = (monotonicAt, anchor) => {
385
+ if (monotonicAt === null)
386
+ return null;
387
+ return new Date(anchor.wallNow + monotonicAt - anchor.monotonicNow).toISOString();
388
+ };
389
+ const status = () => {
390
+ const captured = clock.wallNow();
391
+ const anchor = { monotonicNow: clock.now(), wallNow: captured.getTime() };
392
+ return ManagedScheduleStatusSchema.parse({
393
+ descriptor,
394
+ state: state(),
395
+ revision,
396
+ capturedAt: captured.toISOString(),
397
+ changedAt,
398
+ accepting,
399
+ active: active.size,
400
+ queued: queuedAt !== null,
401
+ runsStarted,
402
+ runsCompleted,
403
+ runsFailed,
404
+ ticksSkipped,
405
+ nextRunAt: wallAt(nextRunAt, anchor),
406
+ lastScheduledAt,
407
+ lastStartedAt,
408
+ lastFinishedAt
409
+ });
410
+ };
411
+ let startExecution = () => {
412
+ return;
413
+ };
414
+ const settleExecution = () => {
415
+ if (!accepting || queuedAt === null || active.size !== 0)
416
+ return;
417
+ const successorAt = queuedAt;
418
+ queuedAt = null;
419
+ changed();
420
+ startExecution(successorAt);
421
+ };
422
+ startExecution = (scheduledAt) => {
423
+ const resourceContext = activationContext;
424
+ if (!accepting || !resourceContext)
425
+ return;
426
+ const startedAt = clock.now();
427
+ const wallStartedAt = clock.wallNow().getTime();
428
+ const runContext = {
429
+ applicationId: resourceContext.applicationId,
430
+ signal: resourceContext.signal,
431
+ scheduledAt,
432
+ startedAt,
433
+ now: () => clock.now()
434
+ };
435
+ runsStarted += 1;
436
+ lastScheduledAt = new Date(wallStartedAt + scheduledAt - startedAt).toISOString();
437
+ lastStartedAt = new Date(wallStartedAt).toISOString();
438
+ changed();
439
+ let tracked;
440
+ tracked = Promise.resolve().then(() => config.run(runContext)).then(() => {
441
+ runsCompleted += 1;
442
+ lastFinishedAt = clock.wallNow().toISOString();
443
+ if (descriptor.errorPolicy === "continue" && accepting) {
444
+ resourceContext.reportHealth("healthy");
445
+ }
446
+ }, (error) => {
447
+ runsFailed += 1;
448
+ lastFinishedAt = clock.wallNow().toISOString();
449
+ reportError(error, runContext);
450
+ if (descriptor.errorPolicy === "stop-schedule") {
451
+ resourceContext.reportHealth("unhealthy");
452
+ stopAdmission();
453
+ } else {
454
+ resourceContext.reportHealth("degraded");
455
+ }
456
+ }).finally(() => {
457
+ active.delete(tracked);
458
+ changed();
459
+ settleExecution();
460
+ });
461
+ active.add(tracked);
462
+ };
463
+ const dispatchTick = (scheduledAt) => {
464
+ if (!accepting)
465
+ return;
466
+ if (descriptor.overlap.mode === "skip") {
467
+ if (active.size > 0) {
468
+ ticksSkipped += 1;
469
+ changed();
470
+ return;
471
+ }
472
+ startExecution(scheduledAt);
473
+ return;
474
+ }
475
+ if (descriptor.overlap.mode === "queue-one") {
476
+ if (active.size > 0) {
477
+ queuedAt = scheduledAt;
478
+ changed();
479
+ return;
480
+ }
481
+ startExecution(scheduledAt);
482
+ return;
483
+ }
484
+ if (active.size >= descriptor.overlap.maxConcurrent) {
485
+ ticksSkipped += 1;
486
+ changed();
487
+ return;
488
+ }
489
+ startExecution(scheduledAt);
490
+ };
491
+ const arm = () => {
492
+ if (!accepting || nextRunAt === null)
493
+ return;
494
+ const delayMs = Math.max(0, nextRunAt - clock.now());
495
+ timer = clock.schedule(() => {
496
+ timer = null;
497
+ if (!accepting || nextRunAt === null)
498
+ return;
499
+ const scheduledAt = nextRunAt;
500
+ const observedAt = clock.now();
501
+ const elapsedIntervals = Math.max(1, Math.floor((observedAt - scheduledAt) / descriptor.everyMs) + 1);
502
+ if (elapsedIntervals > 1) {
503
+ ticksSkipped += elapsedIntervals - 1;
504
+ changed();
505
+ }
506
+ nextRunAt = scheduledAt + elapsedIntervals * descriptor.everyMs;
507
+ arm();
508
+ dispatchTick(scheduledAt);
509
+ }, delayMs);
510
+ };
511
+ const waitForActive = async (context, deadlineAt) => {
512
+ if (active.size === 0 || context.signal.aborted)
513
+ return;
514
+ await new Promise((resolve) => {
515
+ let settled = false;
516
+ let deadlineTimer = null;
517
+ const finish = () => {
518
+ if (settled)
519
+ return;
520
+ settled = true;
521
+ deadlineTimer?.cancel();
522
+ context.signal.removeEventListener("abort", finish);
523
+ resolve();
524
+ };
525
+ context.signal.addEventListener("abort", finish, { once: true });
526
+ if (deadlineAt !== undefined) {
527
+ deadlineTimer = clock.schedule(finish, Math.max(0, deadlineAt - context.now()));
528
+ }
529
+ Promise.allSettled([...active]).then(finish);
530
+ });
531
+ };
532
+ const drain = async (context) => {
533
+ stopAdmission();
534
+ await waitForActive(context, context.deadlineAt);
535
+ };
536
+ return {
537
+ id: descriptor.id,
538
+ ...dependsOn && { dependsOn },
539
+ ...config.required !== undefined && { required: config.required },
540
+ get status() {
541
+ return status();
542
+ },
543
+ start() {
544
+ if (active.size > 0) {
545
+ throw new Error(`[stitchkit] schedule "${descriptor.id}" still has executions from its previous generation`);
546
+ }
547
+ cancelFuture();
548
+ stopped = false;
549
+ accepting = false;
550
+ activated = false;
551
+ activationContext = null;
552
+ queuedAt = null;
553
+ changed();
554
+ },
555
+ activate(context) {
556
+ if (activated || stopped)
557
+ return;
558
+ activated = true;
559
+ accepting = true;
560
+ activationContext = context;
561
+ nextRunAt = clock.now() + descriptor.startAfterMs;
562
+ context.reportHealth("healthy");
563
+ changed();
564
+ arm();
565
+ },
566
+ stopAdmission() {
567
+ stopAdmission();
568
+ },
569
+ drain,
570
+ close() {
571
+ stopAdmission();
572
+ },
573
+ async force(context) {
574
+ stopAdmission();
575
+ await waitForActive(context, context.forceDeadlineAt);
576
+ if (active.size > 0) {
577
+ throw new Error(`[stitchkit] schedule "${descriptor.id}" still has active executions`);
578
+ }
579
+ }
580
+ };
581
+ }
582
+
583
+ export { ApplicationSnapshotSinkStatusSchema, createApplicationSnapshotSink, ActivityIdSchema, ActivityStageIdSchema, ActivityStageSnapshotSchema, ActivitySnapshotSchema, ActivityLiveStateSchema, ActivityTokenBrand, createActivityProjection, ManagedScheduleOverlapSchema, ManagedScheduleErrorPolicySchema, ManagedScheduleDescriptorSchema, ManagedScheduleStatusSchema, createManagedSchedule };
@@ -1,108 +1,29 @@
1
- import {
2
- objectShapeKeys
3
- } from "./index-22by16v6.js";
4
1
  import {
5
2
  getRequestContext,
6
3
  runWithRequestContext
7
- } from "./index-s5tn4kdv.js";
4
+ } from "./index-dwf1f2ap.js";
5
+ import {
6
+ objectShapeKeys
7
+ } from "./index-mgtxfe6b.js";
8
+ import {
9
+ coerceJsonArgs
10
+ } from "./index-7zbps32p.js";
8
11
  import {
9
12
  formatZodError,
10
13
  normalizeError,
11
14
  validateDeclaredOutput
12
- } from "./index-efm026pw.js";
13
- import {
14
- isUnsafeKey,
15
- safeJsonParse
16
- } from "./index-vj3vvpaa.js";
17
- import {
18
- isRecord
19
- } from "./index-qyrqwr4c.js";
15
+ } from "./index-fxz0v7vg.js";
20
16
  import {
21
17
  AppError,
22
18
  STITCH_ERROR_STATUS,
23
19
  isStitchErrorCode
24
20
  } from "./index-0w9abg87.js";
25
-
26
- // src/tools/coerce.ts
27
- import { z } from "zod";
28
- function needsJsonCoercion(schema) {
29
- if (schema instanceof z.ZodArray || schema instanceof z.ZodObject || schema instanceof z.ZodRecord || schema instanceof z.ZodTuple || schema instanceof z.ZodUnion) {
30
- return true;
31
- }
32
- if (schema instanceof z.ZodOptional || schema instanceof z.ZodNullable || schema instanceof z.ZodDefault) {
33
- return needsJsonCoercion(schema.unwrap());
34
- }
35
- return false;
36
- }
37
- function acceptsRawString(schema) {
38
- const type = schema._zod.def.type;
39
- if (type === "string" || type === "template_literal")
40
- return true;
41
- if (schema instanceof z.ZodLiteral) {
42
- return schema.def.values.some((value) => typeof value === "string");
43
- }
44
- if (schema instanceof z.ZodEnum) {
45
- return schema.options.some((value) => typeof value === "string");
46
- }
47
- if (schema instanceof z.ZodOptional || schema instanceof z.ZodNullable || schema instanceof z.ZodDefault) {
48
- return acceptsRawString(schema.unwrap());
49
- }
50
- if (schema instanceof z.ZodUnion) {
51
- return schema.def.options.some((option) => acceptsRawString(option));
52
- }
53
- return false;
54
- }
55
- function matchingVariant(union, value) {
56
- const disc = union.def.discriminator;
57
- const tag = value[disc];
58
- for (const option of union.def.options) {
59
- if (!(option instanceof z.ZodObject))
60
- continue;
61
- const field = option.shape[disc];
62
- if (field instanceof z.ZodLiteral && field.def.values.some((v) => v === tag))
63
- return option;
64
- if (field instanceof z.ZodEnum && field.options.some((v) => v === tag))
65
- return option;
66
- }
67
- return;
68
- }
69
- function coerceValue(value, schema) {
70
- if (!schema)
71
- return value;
72
- if (schema instanceof z.ZodOptional || schema instanceof z.ZodNullable || schema instanceof z.ZodDefault) {
73
- return coerceValue(value, schema.unwrap());
74
- }
75
- let current = value;
76
- if (typeof current === "string" && needsJsonCoercion(schema)) {
77
- if (acceptsRawString(schema))
78
- return current;
79
- try {
80
- current = safeJsonParse(current);
81
- } catch {
82
- return value;
83
- }
84
- }
85
- if (schema instanceof z.ZodObject && isRecord(current)) {
86
- const shape = schema.shape;
87
- const out = {};
88
- for (const [key, item] of Object.entries(current)) {
89
- out[key] = coerceValue(item, shape[key]);
90
- }
91
- return out;
92
- }
93
- if (schema instanceof z.ZodArray && Array.isArray(current)) {
94
- return current.map((item) => coerceValue(item, schema.element));
95
- }
96
- if (schema instanceof z.ZodDiscriminatedUnion && isRecord(current)) {
97
- const variant = matchingVariant(schema, current);
98
- return variant ? coerceValue(current, variant) : current;
99
- }
100
- return current;
101
- }
102
- function coerceJsonArgs(args, schema) {
103
- const coerced = coerceValue(args, schema);
104
- return isRecord(coerced) ? coerced : args;
105
- }
21
+ import {
22
+ isUnsafeKey
23
+ } from "./index-kzfs85xp.js";
24
+ import {
25
+ isRecord
26
+ } from "./index-77fekveh.js";
106
27
 
107
28
  // src/tools/execute.ts
108
29
  class ToolExecutionControlError extends Error {
@@ -337,4 +258,4 @@ async function runToolMethod(method, toolName, rawArgs, context, hooks, lifecycl
337
258
  }
338
259
  }
339
260
 
340
- export { coerceJsonArgs, ToolExecutionControlError, isToolExecutionControlError, toolResultFromError, toolErrorFromResult, executeToolMethod };
261
+ export { ToolExecutionControlError, isToolExecutionControlError, toolResultFromError, toolErrorFromResult, executeToolMethod };