@sellable/mcp 0.1.554 → 0.1.555
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.
- package/dist/index-dev.js +0 -0
- package/dist/index.js +0 -0
- package/dist/refill-contract.d.ts +157 -0
- package/dist/refill-contract.js +487 -0
- package/dist/refill-run-client.d.ts +5 -0
- package/dist/refill-run-client.js +15 -0
- package/dist/refill-run-loop.d.ts +12 -1
- package/dist/refill-run-loop.js +158 -13
- package/dist/tools/campaign-message-preparation.d.ts +62 -0
- package/dist/tools/campaign-message-preparation.js +41 -0
- package/dist/tools/evergreen-refill-plan.d.ts +3 -0
- package/dist/tools/evergreen-refill-plan.js +29 -7
- package/dist/tools/prompts.js +9 -0
- package/dist/tools/refill-executors.d.ts +38 -0
- package/dist/tools/refill-executors.js +222 -3
- package/dist/tools/refill-sends-v2.d.ts +112 -1
- package/dist/tools/refill-sends-v2.js +302 -2
- package/dist/tools/refill-sends.d.ts +678 -32
- package/dist/tools/refill-sends.js +274 -13
- package/dist/tools/refill-target-plan.js +486 -14
- package/dist/tools/registry.d.ts +96 -27
- package/dist/tools/registry.js +1 -3
- package/dist/tools/scheduler-fill-capacity.js +1 -1
- package/dist/tools/scheduler-run.d.ts +71 -0
- package/dist/tools/scheduler-run.js +203 -1
- package/dist/tools/workspaces.d.ts +4 -6
- package/dist/tools/workspaces.js +11 -13
- package/package.json +1 -1
- package/skills/refill-sends/SKILL.md +91 -353
- package/skills/refill-sends-v2/SKILL.md +6 -6
- package/skills/refill-sends-v2-workflow/SKILL.md +5 -5
- package/skills/refill-sends-v2-workflow/core/flow.v1.json +8 -8
- package/skills/refill-sends-workflow/SKILL.md +100 -743
- package/skills/refill-sends-workflow/core/contract.v2.json +543 -0
- package/skills/refill-sends-workflow/core/flow.v1.json +185 -1
- package/dist/refill-date-window.d.ts +0 -34
- package/dist/refill-date-window.js +0 -210
- package/dist/tools/refill-sends-evergreen.d.ts +0 -28
- package/dist/tools/refill-sends-evergreen.js +0 -47
- package/skills/research/config.json +0 -9
|
@@ -30,6 +30,22 @@
|
|
|
30
30
|
"yoloMode"
|
|
31
31
|
]
|
|
32
32
|
}
|
|
33
|
+
},
|
|
34
|
+
{
|
|
35
|
+
"tool": "get_subskill_asset",
|
|
36
|
+
"requiredValues": {
|
|
37
|
+
"subskillName": "refill-sends-workflow",
|
|
38
|
+
"assetPath": "core/contract.v2.json"
|
|
39
|
+
},
|
|
40
|
+
"mustReadUntil": {
|
|
41
|
+
"hasMore": false
|
|
42
|
+
},
|
|
43
|
+
"validation": {
|
|
44
|
+
"supportedMajor": 2,
|
|
45
|
+
"contractVersion": "2.0.0",
|
|
46
|
+
"cacheVersion": "refill-contract-v1",
|
|
47
|
+
"contractHash": "e54ba0f80bc534fd70fd8c10c1caab109fe9a91c205cfc423f5f6735cd53fdc1"
|
|
48
|
+
}
|
|
33
49
|
}
|
|
34
50
|
],
|
|
35
51
|
"gateOrder": [
|
|
@@ -61,6 +77,44 @@
|
|
|
61
77
|
"scheduled",
|
|
62
78
|
"projected"
|
|
63
79
|
],
|
|
80
|
+
"scopeContract": {
|
|
81
|
+
"immutableApprovalEnvelope": [
|
|
82
|
+
"workspaceId",
|
|
83
|
+
"targetDate",
|
|
84
|
+
"senderIds",
|
|
85
|
+
"actionTypes",
|
|
86
|
+
"campaignIds",
|
|
87
|
+
"tableIds",
|
|
88
|
+
"sourceIds",
|
|
89
|
+
"targetShapeRevision",
|
|
90
|
+
"actionKey"
|
|
91
|
+
],
|
|
92
|
+
"mutableProgress": [
|
|
93
|
+
"stateRevision",
|
|
94
|
+
"sent",
|
|
95
|
+
"scheduled",
|
|
96
|
+
"readyToSchedule",
|
|
97
|
+
"remainingProjectedGap"
|
|
98
|
+
],
|
|
99
|
+
"executionRules": [
|
|
100
|
+
"Execute only target.globalActionQueue[0].",
|
|
101
|
+
"Execute one action, then perform a full authoritative reread before selecting any next action.",
|
|
102
|
+
"Mutable progress must not be treated as approval-scope drift while targetShapeRevision remains stable."
|
|
103
|
+
]
|
|
104
|
+
},
|
|
105
|
+
"interruptionRecovery": {
|
|
106
|
+
"rules": [
|
|
107
|
+
"On resume, reread the canonical target plan and reconcile scheduler status or receipt with the matching requestKey and actionKey before retrying.",
|
|
108
|
+
"A matching terminal receipt must replay without a second scheduler execution.",
|
|
109
|
+
"An uncertain_outcome requires reconciliation; do not schedule again with the same or a replacement key until a canonical read resolves it."
|
|
110
|
+
]
|
|
111
|
+
},
|
|
112
|
+
"multiDayOrdering": {
|
|
113
|
+
"rules": [
|
|
114
|
+
"For multiple target dates, finish D1 execution and the full D1 reread before planning D2.",
|
|
115
|
+
"Do not pre-plan or execute a later date from stale earlier-date state."
|
|
116
|
+
]
|
|
117
|
+
},
|
|
64
118
|
"states": [
|
|
65
119
|
{
|
|
66
120
|
"id": "target_plan_read",
|
|
@@ -188,7 +242,7 @@
|
|
|
188
242
|
},
|
|
189
243
|
{
|
|
190
244
|
"id": "scheduler_wait_readback",
|
|
191
|
-
"description": "
|
|
245
|
+
"description": "Exact-date scheduler sweep or read-only polling after rows are ready and paid-credit facts are fresh.",
|
|
192
246
|
"allowedTools": [
|
|
193
247
|
"get_refill_target_plan",
|
|
194
248
|
"get_scheduler_fill_capacity",
|
|
@@ -203,6 +257,9 @@
|
|
|
203
257
|
"rules": [
|
|
204
258
|
"Poll every 60-120 seconds or on the host continuation interval.",
|
|
205
259
|
"Use run_scheduler_sweep with the explicit workspaceId when ready rows need scheduler pickup now; it places cells only inside existing gates and never sends.",
|
|
260
|
+
"A scheduler sweep is a visible workspace-wide scheduling side effect; the packet limits expected target changes but must disclose that unrelated eligible workspace work may also be scheduled.",
|
|
261
|
+
"For an explicit targetDate, execute only the request-scoped run_scheduler_sweep from target.globalActionQueue[0], then perform a full authoritative target-plan reread before any next action.",
|
|
262
|
+
"Reuse the matching requestKey and actionKey only for status or receipt reconciliation; replay a matching terminal receipt and stop on uncertain_outcome rather than scheduling again.",
|
|
206
263
|
"cellsConsidered is allocation-attempt count; inspect campaignScopeSummary before assuming the selected refill campaign/table was included or ready-but-blocked.",
|
|
207
264
|
"Read prefiltered, skipped, and deferred separately: prefiltered ready closed-InMail cells with stale paid-credit facts require refresh_paid_inmail_credits_then_rerun once, then rerun/status.",
|
|
208
265
|
"wait_for_capacity_or_window means report loaded/capped/waiting and do not source or prep more rows; no_ready_cells_continue_refill_prep means return to the refill/prep ladder.",
|
|
@@ -211,6 +268,11 @@
|
|
|
211
268
|
"Do not mark complete or blocked only because awaiting_scheduler_after_ready_buffer persists."
|
|
212
269
|
],
|
|
213
270
|
"transitions": [
|
|
271
|
+
{
|
|
272
|
+
"when": "explicit targetDate and target.globalActionQueue[0] is request-scoped run_scheduler_sweep",
|
|
273
|
+
"action": "execute exactly one request-scoped run_scheduler_sweep, capture its complete receipt, and do not execute a returned next action",
|
|
274
|
+
"to": "target_plan_read"
|
|
275
|
+
},
|
|
214
276
|
{
|
|
215
277
|
"when": "projected coverage fills target",
|
|
216
278
|
"to": "completion_or_blocker"
|
|
@@ -243,6 +305,7 @@
|
|
|
243
305
|
"start_campaign_message_preparation",
|
|
244
306
|
"same_source_copy",
|
|
245
307
|
"bounded_generated_message_approval",
|
|
308
|
+
"run_scheduler_sweep",
|
|
246
309
|
"wait_for_scheduler"
|
|
247
310
|
],
|
|
248
311
|
"neverAutoExecute": [
|
|
@@ -271,16 +334,137 @@
|
|
|
271
334
|
"verification": {
|
|
272
335
|
"requiredProof": [
|
|
273
336
|
"final get_refill_target_plan",
|
|
337
|
+
"get_campaign_refill_state for selected campaign/table facts",
|
|
338
|
+
"get_scheduler_fill_capacity for the exact sender/action/date",
|
|
339
|
+
"run_scheduler_sweep status or receipt for any executed sweep",
|
|
274
340
|
"projected coverage sent + scheduled",
|
|
275
341
|
"scheduler-owned cells with non-null scheduledFor when claiming scheduled",
|
|
276
342
|
"paid-InMail freshness status clean before scheduler wait",
|
|
277
343
|
"refresh receipt for each refreshed sender"
|
|
278
344
|
],
|
|
345
|
+
"forbiddenProof": [
|
|
346
|
+
"individual cell ids",
|
|
347
|
+
"Prisma",
|
|
348
|
+
"SQL",
|
|
349
|
+
"direct database access",
|
|
350
|
+
"production-environment scripts"
|
|
351
|
+
],
|
|
352
|
+
"completionRules": [
|
|
353
|
+
"Report already sent actions separately from future scheduled actions.",
|
|
354
|
+
"Only scheduler-owned future scheduled actions count as scheduled coverage.",
|
|
355
|
+
"Prepared, approved, and ready rows remain intermediate evidence."
|
|
356
|
+
],
|
|
279
357
|
"notCompletionProof": [
|
|
280
358
|
"prepared rows alone",
|
|
281
359
|
"approved rows alone",
|
|
282
360
|
"ready-to-schedule rows alone",
|
|
283
361
|
"awaiting_scheduler_after_ready_buffer"
|
|
284
362
|
]
|
|
363
|
+
},
|
|
364
|
+
"refillContract": {
|
|
365
|
+
"contractVersion": "2.0.0",
|
|
366
|
+
"cacheVersion": "refill-contract-v1",
|
|
367
|
+
"contractHash": "e54ba0f80bc534fd70fd8c10c1caab109fe9a91c205cfc423f5f6735cd53fdc1",
|
|
368
|
+
"semanticIds": {
|
|
369
|
+
"scope": [
|
|
370
|
+
"workspace_id",
|
|
371
|
+
"target_date",
|
|
372
|
+
"sender_selectors",
|
|
373
|
+
"campaign_selectors",
|
|
374
|
+
"approval_mode",
|
|
375
|
+
"contract_identity",
|
|
376
|
+
"installed_identity"
|
|
377
|
+
],
|
|
378
|
+
"gates": [
|
|
379
|
+
"workspace_access",
|
|
380
|
+
"approval_packet",
|
|
381
|
+
"source_family",
|
|
382
|
+
"threshold",
|
|
383
|
+
"scheduler",
|
|
384
|
+
"campaign_lifecycle",
|
|
385
|
+
"send_time",
|
|
386
|
+
"no_direct_send",
|
|
387
|
+
"one_primitive",
|
|
388
|
+
"fresh_reread",
|
|
389
|
+
"normalized_accounting",
|
|
390
|
+
"prep_circuit",
|
|
391
|
+
"terminal_truth"
|
|
392
|
+
],
|
|
393
|
+
"states": [
|
|
394
|
+
"planning",
|
|
395
|
+
"awaiting_approval",
|
|
396
|
+
"executing",
|
|
397
|
+
"settling",
|
|
398
|
+
"replanning",
|
|
399
|
+
"terminal"
|
|
400
|
+
],
|
|
401
|
+
"actions": [
|
|
402
|
+
"prepare_messages",
|
|
403
|
+
"approve_messages",
|
|
404
|
+
"rerun_errored_cells",
|
|
405
|
+
"start_paused_campaign",
|
|
406
|
+
"run_scheduler_sweep",
|
|
407
|
+
"scheduler_first_settle",
|
|
408
|
+
"wait_for_scheduler",
|
|
409
|
+
"wait_for_active_work",
|
|
410
|
+
"wait_for_source_import",
|
|
411
|
+
"copy_selected_source_rows",
|
|
412
|
+
"continue_signal_discovery_source",
|
|
413
|
+
"continue_sales_nav_source",
|
|
414
|
+
"continue_prospeo_source",
|
|
415
|
+
"manual_source_replenishment",
|
|
416
|
+
"refresh_paid_inmail_credits",
|
|
417
|
+
"lower_paid_inmail_threshold",
|
|
418
|
+
"switch_to_connection_lane",
|
|
419
|
+
"create_connection_campaign",
|
|
420
|
+
"next_campaign",
|
|
421
|
+
"done"
|
|
422
|
+
],
|
|
423
|
+
"receipts": [
|
|
424
|
+
"target_plan_receipt",
|
|
425
|
+
"preparation_receipt",
|
|
426
|
+
"scheduler_receipt",
|
|
427
|
+
"run_receipt"
|
|
428
|
+
],
|
|
429
|
+
"sideEffectClasses": [
|
|
430
|
+
"read_only",
|
|
431
|
+
"message_preparation",
|
|
432
|
+
"message_approval",
|
|
433
|
+
"source_replenishment",
|
|
434
|
+
"credit_refresh",
|
|
435
|
+
"campaign_start",
|
|
436
|
+
"scheduler_placement"
|
|
437
|
+
],
|
|
438
|
+
"forbiddenActions": [
|
|
439
|
+
"direct_send",
|
|
440
|
+
"raw_scheduler_write",
|
|
441
|
+
"campaign_create",
|
|
442
|
+
"campaign_archive_delete",
|
|
443
|
+
"threshold_lowering",
|
|
444
|
+
"unselected_source_mutation",
|
|
445
|
+
"unapproved_campaign_start",
|
|
446
|
+
"sender_config_write"
|
|
447
|
+
],
|
|
448
|
+
"terminalReasons": [
|
|
449
|
+
"projected_full",
|
|
450
|
+
"concrete_blocker",
|
|
451
|
+
"deadline_reached",
|
|
452
|
+
"iteration_limit",
|
|
453
|
+
"operator_stopped",
|
|
454
|
+
"capped_by_scheduler",
|
|
455
|
+
"loaded_awaiting_scheduler",
|
|
456
|
+
"lanes_exhausted",
|
|
457
|
+
"not_an_evergreen_workspace",
|
|
458
|
+
"no_refillable_campaigns"
|
|
459
|
+
],
|
|
460
|
+
"transitions": [
|
|
461
|
+
"",
|
|
462
|
+
"",
|
|
463
|
+
"",
|
|
464
|
+
"",
|
|
465
|
+
"",
|
|
466
|
+
""
|
|
467
|
+
]
|
|
468
|
+
}
|
|
285
469
|
}
|
|
286
470
|
}
|
|
@@ -1,34 +0,0 @@
|
|
|
1
|
-
export type RefillDateWindowSource = "default_scheduler_forward" | "horizon_send_days" | "until_date" | "target_date";
|
|
2
|
-
export type NormalizedRefillDateSelector = {
|
|
3
|
-
source: RefillDateWindowSource;
|
|
4
|
-
targetDate: string | null;
|
|
5
|
-
untilDate: string | null;
|
|
6
|
-
horizonSendDays: number | null;
|
|
7
|
-
};
|
|
8
|
-
export type RefillRunDateWindow = NormalizedRefillDateSelector & {
|
|
9
|
-
version: 1;
|
|
10
|
-
selectedDates: string[];
|
|
11
|
-
senderWindows?: Array<{
|
|
12
|
-
senderId: string | null;
|
|
13
|
-
timeZone: string | null;
|
|
14
|
-
selectedDates: string[];
|
|
15
|
-
}>;
|
|
16
|
-
};
|
|
17
|
-
type DateSelectorInput = {
|
|
18
|
-
targetDate?: unknown;
|
|
19
|
-
untilDate?: unknown;
|
|
20
|
-
horizonSendDays?: unknown;
|
|
21
|
-
};
|
|
22
|
-
export declare function normalizeRefillDateSelector(input: DateSelectorInput): NormalizedRefillDateSelector;
|
|
23
|
-
export declare function refillDateSelectorBody(selector: NormalizedRefillDateSelector): {
|
|
24
|
-
targetDate?: string;
|
|
25
|
-
untilDate?: string;
|
|
26
|
-
horizonSendDays?: number;
|
|
27
|
-
};
|
|
28
|
-
export declare function dateWindowFromSelector(selector: NormalizedRefillDateSelector): RefillRunDateWindow;
|
|
29
|
-
export declare function dateWindowFromPlan(plan: Record<string, unknown>, selector: NormalizedRefillDateSelector): RefillRunDateWindow;
|
|
30
|
-
export declare function dateWindowFromRunState(runState: unknown): RefillRunDateWindow | null;
|
|
31
|
-
export declare function selectorFromDateWindow(window: RefillRunDateWindow): NormalizedRefillDateSelector;
|
|
32
|
-
export declare function dateSelectorMatchesWindow(selector: NormalizedRefillDateSelector, window: RefillRunDateWindow): boolean;
|
|
33
|
-
export declare function schedulerSweepTargetDates(window: RefillRunDateWindow): string[];
|
|
34
|
-
export {};
|
|
@@ -1,210 +0,0 @@
|
|
|
1
|
-
function isRecord(value) {
|
|
2
|
-
return Boolean(value) && typeof value === "object" && !Array.isArray(value);
|
|
3
|
-
}
|
|
4
|
-
function stringValue(value) {
|
|
5
|
-
return typeof value === "string" && value.trim() ? value.trim() : null;
|
|
6
|
-
}
|
|
7
|
-
function numberValue(value) {
|
|
8
|
-
return typeof value === "number" && Number.isFinite(value) ? value : null;
|
|
9
|
-
}
|
|
10
|
-
function arrayValue(value) {
|
|
11
|
-
return Array.isArray(value) ? value : [];
|
|
12
|
-
}
|
|
13
|
-
function isValidDateKey(value) {
|
|
14
|
-
if (!/^\d{4}-\d{2}-\d{2}$/.test(value))
|
|
15
|
-
return false;
|
|
16
|
-
const [year, month, day] = value.split("-").map(Number);
|
|
17
|
-
const date = new Date(Date.UTC(year, month - 1, day));
|
|
18
|
-
return (date.getUTCFullYear() === year &&
|
|
19
|
-
date.getUTCMonth() === month - 1 &&
|
|
20
|
-
date.getUTCDate() === day);
|
|
21
|
-
}
|
|
22
|
-
function normalizeDateKey(value, field) {
|
|
23
|
-
if (value === undefined || value === null || value === "")
|
|
24
|
-
return null;
|
|
25
|
-
if (typeof value !== "string") {
|
|
26
|
-
throw new Error(`${field} must be a string in YYYY-MM-DD format.`);
|
|
27
|
-
}
|
|
28
|
-
const trimmed = value.trim();
|
|
29
|
-
if (!isValidDateKey(trimmed)) {
|
|
30
|
-
throw new Error(`${field} must be a valid YYYY-MM-DD calendar date.`);
|
|
31
|
-
}
|
|
32
|
-
return trimmed;
|
|
33
|
-
}
|
|
34
|
-
function normalizeHorizonSendDays(value) {
|
|
35
|
-
if (value === undefined)
|
|
36
|
-
return null;
|
|
37
|
-
if (typeof value !== "number" ||
|
|
38
|
-
!Number.isInteger(value) ||
|
|
39
|
-
value < 1 ||
|
|
40
|
-
value > 7) {
|
|
41
|
-
throw new Error("horizonSendDays must be an integer between 1 and 7.");
|
|
42
|
-
}
|
|
43
|
-
return value;
|
|
44
|
-
}
|
|
45
|
-
export function normalizeRefillDateSelector(input) {
|
|
46
|
-
const targetDate = normalizeDateKey(input.targetDate, "targetDate");
|
|
47
|
-
const untilDate = normalizeDateKey(input.untilDate, "untilDate");
|
|
48
|
-
const horizonSendDays = normalizeHorizonSendDays(input.horizonSendDays);
|
|
49
|
-
if (targetDate) {
|
|
50
|
-
return {
|
|
51
|
-
source: "target_date",
|
|
52
|
-
targetDate,
|
|
53
|
-
untilDate: null,
|
|
54
|
-
horizonSendDays: null,
|
|
55
|
-
};
|
|
56
|
-
}
|
|
57
|
-
if (untilDate) {
|
|
58
|
-
return {
|
|
59
|
-
source: "until_date",
|
|
60
|
-
targetDate: null,
|
|
61
|
-
untilDate,
|
|
62
|
-
horizonSendDays: null,
|
|
63
|
-
};
|
|
64
|
-
}
|
|
65
|
-
if (horizonSendDays !== null) {
|
|
66
|
-
return {
|
|
67
|
-
source: "horizon_send_days",
|
|
68
|
-
targetDate: null,
|
|
69
|
-
untilDate: null,
|
|
70
|
-
horizonSendDays,
|
|
71
|
-
};
|
|
72
|
-
}
|
|
73
|
-
return {
|
|
74
|
-
source: "default_scheduler_forward",
|
|
75
|
-
targetDate: null,
|
|
76
|
-
untilDate: null,
|
|
77
|
-
horizonSendDays: null,
|
|
78
|
-
};
|
|
79
|
-
}
|
|
80
|
-
export function refillDateSelectorBody(selector) {
|
|
81
|
-
if (selector.source === "target_date" && selector.targetDate) {
|
|
82
|
-
return { targetDate: selector.targetDate };
|
|
83
|
-
}
|
|
84
|
-
if (selector.source === "until_date" && selector.untilDate) {
|
|
85
|
-
return { untilDate: selector.untilDate };
|
|
86
|
-
}
|
|
87
|
-
if (selector.source === "horizon_send_days" &&
|
|
88
|
-
selector.horizonSendDays !== null) {
|
|
89
|
-
return { horizonSendDays: selector.horizonSendDays };
|
|
90
|
-
}
|
|
91
|
-
return {};
|
|
92
|
-
}
|
|
93
|
-
export function dateWindowFromSelector(selector) {
|
|
94
|
-
return {
|
|
95
|
-
version: 1,
|
|
96
|
-
...selector,
|
|
97
|
-
selectedDates: selector.targetDate ? [selector.targetDate] : [],
|
|
98
|
-
};
|
|
99
|
-
}
|
|
100
|
-
function selectedDatesFromPlan(plan) {
|
|
101
|
-
const packet = isRecord(plan.packet) ? plan.packet : {};
|
|
102
|
-
const target = isRecord(packet.target) ? packet.target : {};
|
|
103
|
-
const window = isRecord(target.window) ? target.window : {};
|
|
104
|
-
const senderWindows = arrayValue(window.senderWindows).filter(isRecord);
|
|
105
|
-
const fromWindows = senderWindows.flatMap((senderWindow) => arrayValue(senderWindow.selectedDates)
|
|
106
|
-
.map((entry) => stringValue(entry))
|
|
107
|
-
.filter((entry) => Boolean(entry)));
|
|
108
|
-
if (fromWindows.length > 0)
|
|
109
|
-
return Array.from(new Set(fromWindows)).sort();
|
|
110
|
-
const senderRefillPlans = arrayValue(target.senderRefillPlans).filter(isRecord);
|
|
111
|
-
return Array.from(new Set(senderRefillPlans.flatMap((senderPlan) => {
|
|
112
|
-
const horizon = isRecord(senderPlan.horizon) ? senderPlan.horizon : {};
|
|
113
|
-
return arrayValue(horizon.selectedDays)
|
|
114
|
-
.filter(isRecord)
|
|
115
|
-
.map((day) => stringValue(day.date))
|
|
116
|
-
.filter((entry) => Boolean(entry));
|
|
117
|
-
}))).sort();
|
|
118
|
-
}
|
|
119
|
-
function senderWindowsFromPlan(plan) {
|
|
120
|
-
const packet = isRecord(plan.packet) ? plan.packet : {};
|
|
121
|
-
const target = isRecord(packet.target) ? packet.target : {};
|
|
122
|
-
const window = isRecord(target.window) ? target.window : {};
|
|
123
|
-
return arrayValue(window.senderWindows)
|
|
124
|
-
.filter(isRecord)
|
|
125
|
-
.map((senderWindow) => ({
|
|
126
|
-
senderId: stringValue(senderWindow.senderId),
|
|
127
|
-
timeZone: stringValue(senderWindow.timeZone),
|
|
128
|
-
selectedDates: arrayValue(senderWindow.selectedDates)
|
|
129
|
-
.map((entry) => stringValue(entry))
|
|
130
|
-
.filter((entry) => Boolean(entry)),
|
|
131
|
-
}));
|
|
132
|
-
}
|
|
133
|
-
export function dateWindowFromPlan(plan, selector) {
|
|
134
|
-
const packet = isRecord(plan.packet) ? plan.packet : {};
|
|
135
|
-
const request = isRecord(packet.request) ? packet.request : {};
|
|
136
|
-
const targetDate = stringValue(request.targetDate) ?? selector.targetDate ?? null;
|
|
137
|
-
const untilDate = stringValue(request.untilDate) ?? selector.untilDate ?? null;
|
|
138
|
-
const horizonSendDays = numberValue(request.horizonSendDays) ?? selector.horizonSendDays ?? null;
|
|
139
|
-
const source = targetDate
|
|
140
|
-
? "target_date"
|
|
141
|
-
: untilDate
|
|
142
|
-
? "until_date"
|
|
143
|
-
: horizonSendDays !== null
|
|
144
|
-
? "horizon_send_days"
|
|
145
|
-
: selector.source;
|
|
146
|
-
const selectedDates = selectedDatesFromPlan(plan);
|
|
147
|
-
return {
|
|
148
|
-
version: 1,
|
|
149
|
-
source,
|
|
150
|
-
targetDate: source === "target_date" ? targetDate : null,
|
|
151
|
-
untilDate: source === "until_date" ? untilDate : null,
|
|
152
|
-
horizonSendDays: source === "horizon_send_days" ? horizonSendDays : null,
|
|
153
|
-
selectedDates: selectedDates.length > 0
|
|
154
|
-
? selectedDates
|
|
155
|
-
: targetDate
|
|
156
|
-
? [targetDate]
|
|
157
|
-
: [],
|
|
158
|
-
senderWindows: senderWindowsFromPlan(plan),
|
|
159
|
-
};
|
|
160
|
-
}
|
|
161
|
-
export function dateWindowFromRunState(runState) {
|
|
162
|
-
const state = isRecord(runState) ? runState : {};
|
|
163
|
-
const raw = isRecord(state.dateWindow) ? state.dateWindow : null;
|
|
164
|
-
if (!raw || raw.version !== 1)
|
|
165
|
-
return null;
|
|
166
|
-
const source = raw.source === "target_date" ||
|
|
167
|
-
raw.source === "until_date" ||
|
|
168
|
-
raw.source === "horizon_send_days" ||
|
|
169
|
-
raw.source === "default_scheduler_forward"
|
|
170
|
-
? raw.source
|
|
171
|
-
: null;
|
|
172
|
-
if (!source)
|
|
173
|
-
return null;
|
|
174
|
-
return {
|
|
175
|
-
version: 1,
|
|
176
|
-
source,
|
|
177
|
-
targetDate: source === "target_date" ? stringValue(raw.targetDate) : null,
|
|
178
|
-
untilDate: source === "until_date" ? stringValue(raw.untilDate) : null,
|
|
179
|
-
horizonSendDays: source === "horizon_send_days"
|
|
180
|
-
? numberValue(raw.horizonSendDays)
|
|
181
|
-
: null,
|
|
182
|
-
selectedDates: arrayValue(raw.selectedDates)
|
|
183
|
-
.map((entry) => stringValue(entry))
|
|
184
|
-
.filter((entry) => Boolean(entry)),
|
|
185
|
-
};
|
|
186
|
-
}
|
|
187
|
-
export function selectorFromDateWindow(window) {
|
|
188
|
-
return {
|
|
189
|
-
source: window.source,
|
|
190
|
-
targetDate: window.targetDate,
|
|
191
|
-
untilDate: window.untilDate,
|
|
192
|
-
horizonSendDays: window.horizonSendDays,
|
|
193
|
-
};
|
|
194
|
-
}
|
|
195
|
-
export function dateSelectorMatchesWindow(selector, window) {
|
|
196
|
-
return (selector.source === window.source &&
|
|
197
|
-
selector.targetDate === window.targetDate &&
|
|
198
|
-
selector.untilDate === window.untilDate &&
|
|
199
|
-
selector.horizonSendDays === window.horizonSendDays);
|
|
200
|
-
}
|
|
201
|
-
export function schedulerSweepTargetDates(window) {
|
|
202
|
-
if (window.source === "target_date" && window.targetDate) {
|
|
203
|
-
return [window.targetDate];
|
|
204
|
-
}
|
|
205
|
-
if (window.source === "until_date" ||
|
|
206
|
-
window.source === "horizon_send_days") {
|
|
207
|
-
return window.selectedDates;
|
|
208
|
-
}
|
|
209
|
-
return [];
|
|
210
|
-
}
|
|
@@ -1,28 +0,0 @@
|
|
|
1
|
-
type RefillSendsEvergreenInput = {
|
|
2
|
-
workspaceId?: string;
|
|
3
|
-
};
|
|
4
|
-
export declare const refillSendsEvergreenToolDefinitions: {
|
|
5
|
-
name: string;
|
|
6
|
-
description: string;
|
|
7
|
-
inputSchema: {
|
|
8
|
-
type: string;
|
|
9
|
-
properties: {
|
|
10
|
-
workspaceId: {
|
|
11
|
-
type: string;
|
|
12
|
-
description: string;
|
|
13
|
-
};
|
|
14
|
-
};
|
|
15
|
-
required: string[];
|
|
16
|
-
additionalProperties: boolean;
|
|
17
|
-
};
|
|
18
|
-
}[];
|
|
19
|
-
export declare function refillSendsEvergreenCommand(input: RefillSendsEvergreenInput): {
|
|
20
|
-
readOnly: boolean;
|
|
21
|
-
workspaceId: string | null;
|
|
22
|
-
firstOperationalSteps: string[];
|
|
23
|
-
approvalContract: string;
|
|
24
|
-
forbiddenActions: string[];
|
|
25
|
-
fillWindow: string;
|
|
26
|
-
hostExamples: string[];
|
|
27
|
-
};
|
|
28
|
-
export {};
|
|
@@ -1,47 +0,0 @@
|
|
|
1
|
-
export const refillSendsEvergreenToolDefinitions = [
|
|
2
|
-
{
|
|
3
|
-
name: "refill_sends_evergreen",
|
|
4
|
-
description: "Read-only Phase 85 evergreen refill command contract. It performs no mutations and only tells the operator to call get_evergreen_refill_plan for a dry-run packet and journal.",
|
|
5
|
-
inputSchema: {
|
|
6
|
-
type: "object",
|
|
7
|
-
properties: {
|
|
8
|
-
workspaceId: {
|
|
9
|
-
type: "string",
|
|
10
|
-
description: "Explicit request-scoped workspace id.",
|
|
11
|
-
},
|
|
12
|
-
},
|
|
13
|
-
required: ["workspaceId"],
|
|
14
|
-
additionalProperties: false,
|
|
15
|
-
},
|
|
16
|
-
},
|
|
17
|
-
];
|
|
18
|
-
export function refillSendsEvergreenCommand(input) {
|
|
19
|
-
return {
|
|
20
|
-
readOnly: true,
|
|
21
|
-
workspaceId: input.workspaceId ?? null,
|
|
22
|
-
firstOperationalSteps: [
|
|
23
|
-
"Call get_evergreen_refill_plan with the explicit workspaceId.",
|
|
24
|
-
"Read the returned packet, globalActionQueue, per-sender plans, and itinerary before taking any action.",
|
|
25
|
-
"Review the dry-run journal file path returned by get_evergreen_refill_plan.",
|
|
26
|
-
"Phase 85 is PLAN-ONLY; execution arrives in Phase 86.",
|
|
27
|
-
],
|
|
28
|
-
approvalContract: "Nothing is approved or executable in Phase 85. The evergreen command is read-only; Phase 86 introduces execution approval.",
|
|
29
|
-
forbiddenActions: [
|
|
30
|
-
"Do not schedule sends.",
|
|
31
|
-
"Do not send messages.",
|
|
32
|
-
"Do not approve messages.",
|
|
33
|
-
"Do not prepare messages.",
|
|
34
|
-
"Do not start or launch campaigns.",
|
|
35
|
-
"Do not create campaigns.",
|
|
36
|
-
"Do not switch providers or source families.",
|
|
37
|
-
"Do not lower paid InMail thresholds.",
|
|
38
|
-
"Do not refresh paid InMail credits.",
|
|
39
|
-
"Do not write scheduler fields.",
|
|
40
|
-
],
|
|
41
|
-
fillWindow: "Use only the target window and caps returned by get_evergreen_refill_plan.",
|
|
42
|
-
hostExamples: [
|
|
43
|
-
"refill_sends_evergreen({ workspaceId })",
|
|
44
|
-
"get_evergreen_refill_plan({ workspaceId })",
|
|
45
|
-
],
|
|
46
|
-
};
|
|
47
|
-
}
|