@sellable/mcp 0.1.559 → 0.1.560
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/refill-run-loop.js
CHANGED
|
@@ -1027,6 +1027,23 @@ async function gatePlan(input, deps, ctx) {
|
|
|
1027
1027
|
fallbackSummary: line.fallbackSummary,
|
|
1028
1028
|
}));
|
|
1029
1029
|
const fingerprint = fingerprintFromPlan(plan);
|
|
1030
|
+
const approvedTargetShapeRevision = stringValue(input.approval?.targetShapeRevision);
|
|
1031
|
+
if (approvedTargetShapeRevision &&
|
|
1032
|
+
approvedTargetShapeRevision !== fingerprint.targetShapeRevision) {
|
|
1033
|
+
return {
|
|
1034
|
+
status: "blocked",
|
|
1035
|
+
blocker: "scope_drift",
|
|
1036
|
+
runId: ctx.runId,
|
|
1037
|
+
fence: ctx.fence,
|
|
1038
|
+
gate: ctx.gate,
|
|
1039
|
+
guidance: "The canonical refill target shape changed after approval; render a new packet before another primitive.",
|
|
1040
|
+
report: {
|
|
1041
|
+
approvedTargetShapeRevision,
|
|
1042
|
+
freshTargetShapeRevision: fingerprint.targetShapeRevision,
|
|
1043
|
+
},
|
|
1044
|
+
journalPath: ctx.journalPath,
|
|
1045
|
+
};
|
|
1046
|
+
}
|
|
1030
1047
|
const persistedCircuit = recordValue(runStateProgress(ctx).prepCircuit);
|
|
1031
1048
|
if (stringValue(action.type) === "prepare_messages" &&
|
|
1032
1049
|
openCircuitWaits(persistedCircuit, deps.now?.() ?? new Date())) {
|
|
@@ -167,6 +167,17 @@ export declare function prepareRefillSendsV2Approval(input: RefillV2ApprovalPrep
|
|
|
167
167
|
response?: undefined;
|
|
168
168
|
}>;
|
|
169
169
|
export declare function refillSendsV2Command(input: RefillSendsV2Input): Promise<{
|
|
170
|
+
status: "blocked";
|
|
171
|
+
blocker: "approval_expired" | "approval_fingerprint_mismatch";
|
|
172
|
+
guidance: string;
|
|
173
|
+
report: {
|
|
174
|
+
fresh?: {} | null | undefined;
|
|
175
|
+
changed: string[];
|
|
176
|
+
};
|
|
177
|
+
readOnly: boolean;
|
|
178
|
+
forbiddenActions: string[];
|
|
179
|
+
boundedAuthority: string;
|
|
180
|
+
} | {
|
|
170
181
|
readOnly: boolean;
|
|
171
182
|
mode: string;
|
|
172
183
|
forbiddenActions: string[];
|
|
@@ -325,7 +325,11 @@ function validateApprovalEcho(envelope, echo, now = new Date()) {
|
|
|
325
325
|
];
|
|
326
326
|
const changed = fields.filter((field) => echo[field] !== envelope.approval[field]);
|
|
327
327
|
if (Date.parse(envelope.approval.approvalExpiresAt) <= now.getTime()) {
|
|
328
|
-
return {
|
|
328
|
+
return {
|
|
329
|
+
ok: false,
|
|
330
|
+
blocker: "approval_expired",
|
|
331
|
+
changed,
|
|
332
|
+
};
|
|
329
333
|
}
|
|
330
334
|
return changed.length === 0
|
|
331
335
|
? { ok: true }
|
|
@@ -335,6 +339,85 @@ function validateApprovalEcho(envelope, echo, now = new Date()) {
|
|
|
335
339
|
changed,
|
|
336
340
|
};
|
|
337
341
|
}
|
|
342
|
+
function blockedApprovalResult(params) {
|
|
343
|
+
return {
|
|
344
|
+
status: "blocked",
|
|
345
|
+
blocker: params.blocker,
|
|
346
|
+
guidance: "The durable refill approval no longer matches its persisted scope; render and approve a new packet before mutation.",
|
|
347
|
+
report: {
|
|
348
|
+
changed: params.changed,
|
|
349
|
+
...(params.fresh === undefined ? {} : { fresh: params.fresh }),
|
|
350
|
+
},
|
|
351
|
+
readOnly: false,
|
|
352
|
+
forbiddenActions: FORBIDDEN_ACTIONS,
|
|
353
|
+
boundedAuthority: BOUNDED_AUTHORITY,
|
|
354
|
+
};
|
|
355
|
+
}
|
|
356
|
+
function storedApprovalFromStatus(value) {
|
|
357
|
+
const status = record(value) ?? {};
|
|
358
|
+
const config = record(status.config);
|
|
359
|
+
const scope = record(config?.scope);
|
|
360
|
+
const approval = record(config?.approval);
|
|
361
|
+
const scopeHash = text(config?.scopeHash);
|
|
362
|
+
if (!config || !scope || !approval || !scopeHash)
|
|
363
|
+
return null;
|
|
364
|
+
return {
|
|
365
|
+
config,
|
|
366
|
+
scope,
|
|
367
|
+
scopeHash,
|
|
368
|
+
approval,
|
|
369
|
+
hasDispatched: status.hasDispatched === true,
|
|
370
|
+
};
|
|
371
|
+
}
|
|
372
|
+
function validateStoredApprovalEcho(params) {
|
|
373
|
+
const fields = [
|
|
374
|
+
"scopeHash",
|
|
375
|
+
"targetShapeRevision",
|
|
376
|
+
"actionFingerprint",
|
|
377
|
+
"expectedTargetsHash",
|
|
378
|
+
"approvalExpiresAt",
|
|
379
|
+
"approvalFingerprint",
|
|
380
|
+
];
|
|
381
|
+
const changed = fields.filter((field) => text(params.approval[field]) !== params.echo[field]);
|
|
382
|
+
const expiresAt = text(params.approval.approvalExpiresAt);
|
|
383
|
+
if (!params.allowExpired &&
|
|
384
|
+
(!expiresAt ||
|
|
385
|
+
Date.parse(expiresAt) <= (params.now ?? new Date()).getTime())) {
|
|
386
|
+
return {
|
|
387
|
+
ok: false,
|
|
388
|
+
blocker: "approval_expired",
|
|
389
|
+
changed,
|
|
390
|
+
};
|
|
391
|
+
}
|
|
392
|
+
return changed.length === 0
|
|
393
|
+
? { ok: true }
|
|
394
|
+
: {
|
|
395
|
+
ok: false,
|
|
396
|
+
blocker: "approval_fingerprint_mismatch",
|
|
397
|
+
changed,
|
|
398
|
+
};
|
|
399
|
+
}
|
|
400
|
+
function executionScopeFromStored(scope, fallback) {
|
|
401
|
+
const dateSelector = record(scope.dateSelector) ?? {};
|
|
402
|
+
const kind = text(dateSelector.kind);
|
|
403
|
+
const senderIds = list(scope.senderIds)
|
|
404
|
+
.map((value) => text(value))
|
|
405
|
+
.filter((value) => value != null);
|
|
406
|
+
const approvalMode = scope.approvalMode === "mark_ready" ? "mark_ready" : "approve";
|
|
407
|
+
return {
|
|
408
|
+
intent: text(scope.intent) ?? fallback.intent,
|
|
409
|
+
senderIds,
|
|
410
|
+
approvalMode,
|
|
411
|
+
...(kind === "target_date" && text(dateSelector.targetDate)
|
|
412
|
+
? { targetDate: text(dateSelector.targetDate) }
|
|
413
|
+
: kind === "until_date" && text(dateSelector.untilDate)
|
|
414
|
+
? { untilDate: text(dateSelector.untilDate) }
|
|
415
|
+
: kind === "horizon_send_days" &&
|
|
416
|
+
typeof dateSelector.horizonSendDays === "number"
|
|
417
|
+
? { horizonSendDays: dateSelector.horizonSendDays }
|
|
418
|
+
: {}),
|
|
419
|
+
};
|
|
420
|
+
}
|
|
338
421
|
async function maybeAddLostFenceGuidance(result, input) {
|
|
339
422
|
if (result.status !== "blocked" ||
|
|
340
423
|
result.blocker !== "lease_lost" ||
|
|
@@ -365,7 +448,53 @@ export async function refillSendsV2Command(input) {
|
|
|
365
448
|
let resolvedScope = input.scope;
|
|
366
449
|
let resolvedScopeHash = input.scopeHash;
|
|
367
450
|
let resolvedApproval = input.approval;
|
|
368
|
-
if (input.
|
|
451
|
+
if (input.runId && input.approvalEcho) {
|
|
452
|
+
const status = await refillRunStatus({ workspaceId, runId: input.runId });
|
|
453
|
+
const stored = storedApprovalFromStatus(status);
|
|
454
|
+
if (!stored) {
|
|
455
|
+
return {
|
|
456
|
+
status: "blocked",
|
|
457
|
+
blocker: "approval_run_unavailable",
|
|
458
|
+
guidance: "The durable refill run no longer exposes a valid persisted approval packet.",
|
|
459
|
+
report: { status },
|
|
460
|
+
readOnly: false,
|
|
461
|
+
forbiddenActions: FORBIDDEN_ACTIONS,
|
|
462
|
+
boundedAuthority: BOUNDED_AUTHORITY,
|
|
463
|
+
};
|
|
464
|
+
}
|
|
465
|
+
const validation = validateStoredApprovalEcho({
|
|
466
|
+
approval: stored.approval,
|
|
467
|
+
echo: input.approvalEcho,
|
|
468
|
+
allowExpired: stored.hasDispatched,
|
|
469
|
+
});
|
|
470
|
+
if (!validation.ok) {
|
|
471
|
+
return blockedApprovalResult({
|
|
472
|
+
blocker: validation.blocker,
|
|
473
|
+
changed: validation.changed,
|
|
474
|
+
fresh: stored.approval,
|
|
475
|
+
});
|
|
476
|
+
}
|
|
477
|
+
const freshTargetShapeRevision = input.targetPlan
|
|
478
|
+
? (text(input.targetPlan.targetShapeRevision) ??
|
|
479
|
+
text(record(input.targetPlan.target)?.targetShapeRevision))
|
|
480
|
+
: null;
|
|
481
|
+
const storedTargetShapeRevision = text(stored.approval.targetShapeRevision);
|
|
482
|
+
if (freshTargetShapeRevision &&
|
|
483
|
+
freshTargetShapeRevision !== storedTargetShapeRevision) {
|
|
484
|
+
return blockedApprovalResult({
|
|
485
|
+
blocker: "approval_fingerprint_mismatch",
|
|
486
|
+
changed: ["targetShapeRevision"],
|
|
487
|
+
fresh: {
|
|
488
|
+
storedTargetShapeRevision,
|
|
489
|
+
freshTargetShapeRevision,
|
|
490
|
+
},
|
|
491
|
+
});
|
|
492
|
+
}
|
|
493
|
+
resolvedScope = stored.scope;
|
|
494
|
+
resolvedScopeHash = stored.scopeHash;
|
|
495
|
+
resolvedApproval = stored.approval;
|
|
496
|
+
}
|
|
497
|
+
else if (input.targetPlan && input.approvalEcho) {
|
|
369
498
|
const envelope = buildApprovalEnvelope({
|
|
370
499
|
workspaceId,
|
|
371
500
|
intent: input.intent,
|
|
@@ -379,15 +508,11 @@ export async function refillSendsV2Command(input) {
|
|
|
379
508
|
});
|
|
380
509
|
const validation = validateApprovalEcho(envelope, input.approvalEcho);
|
|
381
510
|
if (!validation.ok) {
|
|
382
|
-
return {
|
|
383
|
-
status: "blocked",
|
|
511
|
+
return blockedApprovalResult({
|
|
384
512
|
blocker: validation.blocker,
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
forbiddenActions: FORBIDDEN_ACTIONS,
|
|
389
|
-
boundedAuthority: BOUNDED_AUTHORITY,
|
|
390
|
-
};
|
|
513
|
+
changed: validation.changed,
|
|
514
|
+
fresh: envelope.approval,
|
|
515
|
+
});
|
|
391
516
|
}
|
|
392
517
|
resolvedScope = envelope.scope;
|
|
393
518
|
resolvedScopeHash = envelope.scopeHash;
|
|
@@ -409,13 +534,18 @@ export async function refillSendsV2Command(input) {
|
|
|
409
534
|
boundedAuthority: BOUNDED_AUTHORITY,
|
|
410
535
|
};
|
|
411
536
|
}
|
|
537
|
+
const executionScope = resolvedScope
|
|
538
|
+
? executionScopeFromStored(resolvedScope, input)
|
|
539
|
+
: {
|
|
540
|
+
intent: input.intent,
|
|
541
|
+
senderIds: input.senderIds,
|
|
542
|
+
approvalMode: input.approvalMode ?? "approve",
|
|
543
|
+
...date,
|
|
544
|
+
};
|
|
412
545
|
const result = await runRefillV2Loop({
|
|
413
546
|
workspaceId,
|
|
414
|
-
|
|
415
|
-
senderIds: input.senderIds,
|
|
416
|
-
approvalMode: input.approvalMode ?? "approve",
|
|
547
|
+
...executionScope,
|
|
417
548
|
resume: resumeHandle(input),
|
|
418
|
-
...date,
|
|
419
549
|
scope: resolvedScope,
|
|
420
550
|
scopeHash: resolvedScopeHash,
|
|
421
551
|
approval: resolvedApproval,
|
|
@@ -725,6 +725,23 @@ export declare function executeRefillSendsCommand(input?: RefillSendsCommandInpu
|
|
|
725
725
|
intent: RefillSendsIntent;
|
|
726
726
|
} | {
|
|
727
727
|
yoloExecution: {
|
|
728
|
+
selectedAction: Record<string, unknown> | null;
|
|
729
|
+
targetPlanReread: boolean;
|
|
730
|
+
status: "blocked";
|
|
731
|
+
blocker: "approval_expired" | "approval_fingerprint_mismatch";
|
|
732
|
+
guidance: string;
|
|
733
|
+
report: {
|
|
734
|
+
fresh?: {} | null | undefined;
|
|
735
|
+
changed: string[];
|
|
736
|
+
};
|
|
737
|
+
readOnly: boolean;
|
|
738
|
+
forbiddenActions: string[];
|
|
739
|
+
boundedAuthority: string;
|
|
740
|
+
enabled: boolean;
|
|
741
|
+
result?: undefined;
|
|
742
|
+
refusalReason?: undefined;
|
|
743
|
+
postActionFirstAction?: undefined;
|
|
744
|
+
} | {
|
|
728
745
|
selectedAction: Record<string, unknown> | null;
|
|
729
746
|
targetPlanReread: boolean;
|
|
730
747
|
readOnly: boolean;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
+
import { REFILL_CONTRACT_CACHE_VERSION, REFILL_CONTRACT_HASH, REFILL_CONTRACT_VERSION, renderRefillBootstrapGuidance, renderRefillSafetyGuidance, renderRefillTerminalGuidance, } from "../refill-contract.js";
|
|
1
2
|
import { actionIds, classifyPaidInmailRefreshReceipt, collectPaidInmailRefreshActions, executeOneYoloPrimitive, firstGlobalAction, normalizeStrings, numberValue, recordValue, refreshPaidInmailCreditsWithRetry, stringValue, } from "./refill-executors.js";
|
|
2
3
|
import { prepareRefillSendsV2Approval, refillSendsV2Command, } from "./refill-sends-v2.js";
|
|
3
|
-
import { REFILL_CONTRACT_CACHE_VERSION, REFILL_CONTRACT_HASH, REFILL_CONTRACT_VERSION, renderRefillBootstrapGuidance, renderRefillSafetyGuidance, renderRefillTerminalGuidance, } from "../refill-contract.js";
|
|
4
4
|
import { getRefillTargetPlan } from "./refill-target-plan.js";
|
|
5
5
|
import { createWorkspaceContext, normalizeExplicitWorkspaceId, } from "./workspace-context.js";
|
|
6
6
|
const REFILL_SEND_ACTION_TYPES = ["send_invite", "send_inmail_closed"];
|
|
@@ -563,8 +563,13 @@ export async function executeRefillSendsCommand(input = {}) {
|
|
|
563
563
|
}
|
|
564
564
|
const targetPlanInput = targetPlanInputFor(scopedInput);
|
|
565
565
|
const targetPlanBeforePaidRefresh = await getRefillTargetPlan(targetPlanInput);
|
|
566
|
+
const durableResumeRequested = Boolean(yolo &&
|
|
567
|
+
workspaceId &&
|
|
568
|
+
scopedInput.runId &&
|
|
569
|
+
typeof scopedInput.fence === "number" &&
|
|
570
|
+
scopedInput.approvalFingerprint);
|
|
566
571
|
const approvedPacket = approvedPacketComparison(scopedInput, targetPlanBeforePaidRefresh);
|
|
567
|
-
if (approvedPacket.changed) {
|
|
572
|
+
if (!durableResumeRequested && approvedPacket.changed) {
|
|
568
573
|
return {
|
|
569
574
|
...command,
|
|
570
575
|
ok: false,
|
|
@@ -595,7 +600,8 @@ export async function executeRefillSendsCommand(input = {}) {
|
|
|
595
600
|
}
|
|
596
601
|
if (yolo &&
|
|
597
602
|
workspaceId &&
|
|
598
|
-
|
|
603
|
+
(durableResumeRequested ||
|
|
604
|
+
durableV2PlanEligible(targetPlanBeforePaidRefresh))) {
|
|
599
605
|
const base = durableYoloBaseResult({
|
|
600
606
|
command,
|
|
601
607
|
targetPlan: targetPlanBeforePaidRefresh,
|