@sellable/mcp 0.1.553 → 0.1.554
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-date-window.d.ts +34 -0
- package/dist/refill-date-window.js +210 -0
- package/dist/tools/refill-executors.d.ts +0 -30
- package/dist/tools/refill-executors.js +0 -126
- package/dist/tools/refill-sends-evergreen.d.ts +28 -0
- package/dist/tools/refill-sends-evergreen.js +47 -0
- package/dist/tools/refill-sends.d.ts +39 -181
- package/dist/tools/refill-sends.js +13 -141
- package/dist/tools/refill-target-plan.js +3 -181
- package/dist/tools/registry.d.ts +0 -8
- package/dist/tools/scheduler-fill-capacity.js +1 -1
- package/dist/tools/scheduler-run.d.ts +0 -10
- package/dist/tools/scheduler-run.js +0 -20
- package/dist/tools/workspaces.d.ts +6 -4
- package/dist/tools/workspaces.js +13 -11
- package/package.json +1 -1
- package/skills/refill-sends/SKILL.md +7 -42
- package/skills/refill-sends-workflow/SKILL.md +6 -44
- package/skills/refill-sends-workflow/core/flow.v1.json +1 -63
- package/skills/research/config.json +9 -0
package/dist/index-dev.js
CHANGED
|
File without changes
|
package/dist/index.js
CHANGED
|
File without changes
|
|
@@ -0,0 +1,34 @@
|
|
|
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 {};
|
|
@@ -0,0 +1,210 @@
|
|
|
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
|
+
}
|
|
@@ -134,36 +134,6 @@ export declare function sleep(ms: number): Promise<unknown>;
|
|
|
134
134
|
export declare function recordValue(value: unknown): Record<string, unknown> | null;
|
|
135
135
|
export declare function stringValue(value: unknown): string | null;
|
|
136
136
|
export declare function numberValue(value: unknown): number | null;
|
|
137
|
-
export type SchedulerChangedCount = {
|
|
138
|
-
campaignId: string;
|
|
139
|
-
tableId: string;
|
|
140
|
-
actionType: string;
|
|
141
|
-
count: number;
|
|
142
|
-
};
|
|
143
|
-
export type SchedulerChangedCounts = {
|
|
144
|
-
complete: true;
|
|
145
|
-
truncated: false;
|
|
146
|
-
total: number;
|
|
147
|
-
byCampaignTableActionType: SchedulerChangedCount[];
|
|
148
|
-
};
|
|
149
|
-
export declare function normalizeSchedulerChangedCounts(value: unknown): SchedulerChangedCounts | null;
|
|
150
|
-
export declare function normalizeSchedulerPrimitiveResult(value: unknown): {
|
|
151
|
-
status: "scheduler_receipt_incomplete";
|
|
152
|
-
schedulerStatus: string;
|
|
153
|
-
receipt: {} | null;
|
|
154
|
-
retryAfterMs: number | null;
|
|
155
|
-
changedCounts: null;
|
|
156
|
-
auditComplete: false;
|
|
157
|
-
blocker: "scheduler_receipt_incomplete";
|
|
158
|
-
} | {
|
|
159
|
-
status: string;
|
|
160
|
-
receipt: {} | null;
|
|
161
|
-
retryAfterMs: number | null;
|
|
162
|
-
changedCounts: SchedulerChangedCounts;
|
|
163
|
-
auditComplete: true;
|
|
164
|
-
schedulerStatus?: undefined;
|
|
165
|
-
blocker?: undefined;
|
|
166
|
-
};
|
|
167
137
|
export declare function stringArray(value: unknown): string[];
|
|
168
138
|
export declare function prepareRowSelectorValue(value: unknown): PrepareRowSelector | undefined;
|
|
169
139
|
export declare function uniqueStrings(values: Array<string | null | undefined>): string[];
|
|
@@ -3,7 +3,6 @@ import { startPrepareCampaignMessages } from "./campaign-message-preparation.js"
|
|
|
3
3
|
import { startCampaign } from "./campaigns.js";
|
|
4
4
|
import { confirmLeadList, importLeads, searchSignals, selectPromisingPosts, } from "./leads.js";
|
|
5
5
|
import { markProviderPromptLoaded } from "./provider-preflight.js";
|
|
6
|
-
import { runSchedulerSweep } from "./scheduler-run.js";
|
|
7
6
|
import { refreshPaidInmailCredits } from "./senders.js";
|
|
8
7
|
import { workspaceRequestOptions } from "./workspace-context.js";
|
|
9
8
|
const PAID_INMAIL_REFRESH_MAX_ATTEMPTS = 3;
|
|
@@ -41,92 +40,6 @@ export function stringValue(value) {
|
|
|
41
40
|
export function numberValue(value) {
|
|
42
41
|
return typeof value === "number" && Number.isFinite(value) ? value : null;
|
|
43
42
|
}
|
|
44
|
-
export function normalizeSchedulerChangedCounts(value) {
|
|
45
|
-
const changedCounts = recordValue(value);
|
|
46
|
-
if (!changedCounts ||
|
|
47
|
-
changedCounts.complete !== true ||
|
|
48
|
-
changedCounts.truncated !== false) {
|
|
49
|
-
return null;
|
|
50
|
-
}
|
|
51
|
-
const total = numberValue(changedCounts.total);
|
|
52
|
-
if (total === null || total < 0 || !Number.isInteger(total))
|
|
53
|
-
return null;
|
|
54
|
-
if (!Array.isArray(changedCounts.byCampaignTableActionType))
|
|
55
|
-
return null;
|
|
56
|
-
const groups = [];
|
|
57
|
-
const seen = new Set();
|
|
58
|
-
for (const rawGroup of changedCounts.byCampaignTableActionType) {
|
|
59
|
-
const group = recordValue(rawGroup);
|
|
60
|
-
const campaignId = stringValue(group?.campaignId);
|
|
61
|
-
const tableId = stringValue(group?.tableId);
|
|
62
|
-
const actionType = stringValue(group?.actionType);
|
|
63
|
-
const count = numberValue(group?.count);
|
|
64
|
-
if (!campaignId ||
|
|
65
|
-
!tableId ||
|
|
66
|
-
!actionType ||
|
|
67
|
-
count === null ||
|
|
68
|
-
count <= 0 ||
|
|
69
|
-
!Number.isInteger(count)) {
|
|
70
|
-
return null;
|
|
71
|
-
}
|
|
72
|
-
const key = `${campaignId}:${tableId}:${actionType}`;
|
|
73
|
-
if (seen.has(key))
|
|
74
|
-
return null;
|
|
75
|
-
seen.add(key);
|
|
76
|
-
groups.push({ campaignId, tableId, actionType, count });
|
|
77
|
-
}
|
|
78
|
-
groups.sort((a, b) => {
|
|
79
|
-
if (a.campaignId !== b.campaignId) {
|
|
80
|
-
return a.campaignId.localeCompare(b.campaignId);
|
|
81
|
-
}
|
|
82
|
-
if (a.tableId !== b.tableId)
|
|
83
|
-
return a.tableId.localeCompare(b.tableId);
|
|
84
|
-
return a.actionType.localeCompare(b.actionType);
|
|
85
|
-
});
|
|
86
|
-
if (groups.reduce((sum, group) => sum + group.count, 0) !== total) {
|
|
87
|
-
return null;
|
|
88
|
-
}
|
|
89
|
-
return {
|
|
90
|
-
complete: true,
|
|
91
|
-
truncated: false,
|
|
92
|
-
total,
|
|
93
|
-
byCampaignTableActionType: groups,
|
|
94
|
-
};
|
|
95
|
-
}
|
|
96
|
-
export function normalizeSchedulerPrimitiveResult(value) {
|
|
97
|
-
const response = recordValue(value);
|
|
98
|
-
const receipt = recordValue(response?.receipt);
|
|
99
|
-
const changedCounts = normalizeSchedulerChangedCounts(receipt?.changedCounts ?? response?.changedCounts);
|
|
100
|
-
const schedulerStatus = stringValue(response?.status) ?? stringValue(receipt?.status) ?? "unknown";
|
|
101
|
-
if (!changedCounts) {
|
|
102
|
-
return {
|
|
103
|
-
status: "scheduler_receipt_incomplete",
|
|
104
|
-
schedulerStatus,
|
|
105
|
-
receipt: response?.receipt ?? null,
|
|
106
|
-
retryAfterMs: numberValue(response?.retryAfterMs),
|
|
107
|
-
changedCounts: null,
|
|
108
|
-
auditComplete: false,
|
|
109
|
-
blocker: "scheduler_receipt_incomplete",
|
|
110
|
-
};
|
|
111
|
-
}
|
|
112
|
-
return {
|
|
113
|
-
status: schedulerStatus,
|
|
114
|
-
receipt: response?.receipt ?? null,
|
|
115
|
-
retryAfterMs: numberValue(response?.retryAfterMs),
|
|
116
|
-
changedCounts,
|
|
117
|
-
auditComplete: true,
|
|
118
|
-
};
|
|
119
|
-
}
|
|
120
|
-
function exactDateValue(value) {
|
|
121
|
-
const targetDate = stringValue(value);
|
|
122
|
-
if (!targetDate || !/^\d{4}-\d{2}-\d{2}$/.test(targetDate))
|
|
123
|
-
return null;
|
|
124
|
-
const parsed = new Date(`${targetDate}T00:00:00.000Z`);
|
|
125
|
-
return !Number.isNaN(parsed.getTime()) &&
|
|
126
|
-
parsed.toISOString().slice(0, 10) === targetDate
|
|
127
|
-
? targetDate
|
|
128
|
-
: null;
|
|
129
|
-
}
|
|
130
43
|
export function stringArray(value) {
|
|
131
44
|
if (!Array.isArray(value))
|
|
132
45
|
return [];
|
|
@@ -857,45 +770,6 @@ export async function executeOneYoloPrimitive(action, workspaceId) {
|
|
|
857
770
|
case "wait_for_active_work":
|
|
858
771
|
case "wait_for_source_import":
|
|
859
772
|
return { status: "read_only_reread", result: waitResultForAction(action) };
|
|
860
|
-
case "run_scheduler_sweep": {
|
|
861
|
-
const toolInput = actionToolInput(action);
|
|
862
|
-
const actionWorkspaceId = stringValue(toolInput.workspaceId);
|
|
863
|
-
const targetDate = exactDateValue(toolInput.targetDate);
|
|
864
|
-
const targetDateKey = exactDateValue(toolInput.targetDateKey);
|
|
865
|
-
const actionKey = stringValue(action.actionKey);
|
|
866
|
-
const requestKey = stringValue(toolInput.requestKey);
|
|
867
|
-
const targetShapeRevision = stringValue(toolInput.targetShapeRevision);
|
|
868
|
-
const receiptRequirements = recordValue(action.receiptRequirements);
|
|
869
|
-
const receiptGroups = stringArray(receiptRequirements?.groupBy);
|
|
870
|
-
if (!workspaceId ||
|
|
871
|
-
!actionWorkspaceId ||
|
|
872
|
-
actionWorkspaceId !== workspaceId ||
|
|
873
|
-
toolInput.action !== "run" ||
|
|
874
|
-
!targetDate ||
|
|
875
|
-
targetDateKey !== targetDate ||
|
|
876
|
-
!actionKey ||
|
|
877
|
-
requestKey !== actionKey ||
|
|
878
|
-
!targetShapeRevision ||
|
|
879
|
-
action.workspaceWide !== true ||
|
|
880
|
-
receiptRequirements?.nonTruncated !== true ||
|
|
881
|
-
receiptGroups.join(":") !== "campaignId:tableId:actionType") {
|
|
882
|
-
return {
|
|
883
|
-
status: "refused",
|
|
884
|
-
refusalReason: "run_scheduler_sweep action is missing exact workspace/date/revision scope or complete receipt requirements",
|
|
885
|
-
};
|
|
886
|
-
}
|
|
887
|
-
const result = await runSchedulerSweep({
|
|
888
|
-
workspaceId,
|
|
889
|
-
action: "run",
|
|
890
|
-
targetDate,
|
|
891
|
-
requestKey,
|
|
892
|
-
targetShapeRevision,
|
|
893
|
-
});
|
|
894
|
-
return {
|
|
895
|
-
status: "executed_and_reread",
|
|
896
|
-
result: normalizeSchedulerPrimitiveResult(result),
|
|
897
|
-
};
|
|
898
|
-
}
|
|
899
773
|
case "prepare_messages": {
|
|
900
774
|
const campaignId = actionCampaignId(action);
|
|
901
775
|
const tableId = actionTableId(action) ?? undefined;
|
|
@@ -0,0 +1,28 @@
|
|
|
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 {};
|
|
@@ -0,0 +1,47 @@
|
|
|
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
|
+
}
|