agent-conveyor 0.1.17 → 0.1.19
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/README.md +5 -0
- package/dist/cli/typescript-runtime.d.ts +9 -0
- package/dist/cli/typescript-runtime.js +155 -6
- package/dist/cli/typescript-runtime.js.map +1 -1
- package/dist/runtime/campaigns.d.ts +19 -0
- package/dist/runtime/campaigns.js +61 -0
- package/dist/runtime/campaigns.js.map +1 -1
- package/package.json +1 -1
- package/skills/manage-codex-workers/SKILL.md +5 -2
package/README.md
CHANGED
|
@@ -327,6 +327,11 @@ tmux attach -t codex-live-test
|
|
|
327
327
|
blockers, approval counts, and the next recommended manager action. This is
|
|
328
328
|
also the supported way to inspect asset receipts and per-slot receipt counts;
|
|
329
329
|
there is no separate `campaign assets` subcommand.
|
|
330
|
+
- `campaign closeout --name C [--failure-mode TEXT] [--json]` —
|
|
331
|
+
Produce a read-only closeout report from the campaign dashboard, including
|
|
332
|
+
verdict, worker thread ids, blockers, receipt counts by assignment, proof
|
|
333
|
+
checks, and the strongest realistic failure mode evidence to carry into a
|
|
334
|
+
manager/operator handoff.
|
|
330
335
|
|
|
331
336
|
Creative Ops Campaign manager loop:
|
|
332
337
|
|
|
@@ -25,6 +25,15 @@ interface SpawnedCodexSessionDiscoveryOptions {
|
|
|
25
25
|
}
|
|
26
26
|
type TypescriptRuntimeOptions = {
|
|
27
27
|
args: readonly string[];
|
|
28
|
+
campaignReadbackBeforeVerify?: (context: {
|
|
29
|
+
databasePath: string;
|
|
30
|
+
readback: {
|
|
31
|
+
assignment?: string;
|
|
32
|
+
campaign: string;
|
|
33
|
+
channel?: string;
|
|
34
|
+
slot?: string;
|
|
35
|
+
};
|
|
36
|
+
}) => void;
|
|
28
37
|
codexCommandResolver?: (name: string) => string | null;
|
|
29
38
|
cwd?: string;
|
|
30
39
|
discoverSpawnedCodexSession?: (options: SpawnedCodexSessionDiscoveryOptions) => SpawnedCodexSessionDiscovery;
|
|
@@ -7,7 +7,7 @@ import { fileURLToPath } from "node:url";
|
|
|
7
7
|
import { taskAuditSync } from "../runtime/audit.js";
|
|
8
8
|
import { appAutopilotPlanSync, appLoopStatusSync, appWakeupDispatchPlanSync, appWakeupPlanSync, directInboxPollCommand, visibleSessionProtocolLines, } from "../runtime/app-autonomy.js";
|
|
9
9
|
import { classifyBusyWait, classifyStartupOutput } from "../runtime/classify.js";
|
|
10
|
-
import { addCampaignWorkerSlotSync, campaignDashboardSync, campaignStatusSync, createCampaignAssignmentSync, createCampaignSync, recordCampaignAssetReceiptSync, updateCampaignWorkerSlotLifecycleSync, upsertCampaignChannelBriefSync, } from "../runtime/campaigns.js";
|
|
10
|
+
import { addCampaignWorkerSlotSync, campaignDashboardSync, campaignSetupReadbackProofSync, campaignStatusSync, createCampaignAssignmentSync, createCampaignSync, recordCampaignAssetReceiptSync, updateCampaignWorkerSlotLifecycleSync, upsertCampaignChannelBriefSync, } from "../runtime/campaigns.js";
|
|
11
11
|
import { exportTaskSync } from "../runtime/export.js";
|
|
12
12
|
import { ingestSessionSync } from "../runtime/ingest.js";
|
|
13
13
|
import { acceptanceCriteriaForTaskSync, loopEvidenceCriterion, recordAdversarialLoopEvidenceSync, recordLoopEvidenceSync, recordVisualDiffLoopEvidenceSync, } from "../runtime/loop-evidence.js";
|
|
@@ -402,6 +402,7 @@ function commandHelpText(program, command) {
|
|
|
402
402
|
` ${program} campaign asset --name launch --slot campaign-slot-id --assignment campaign-assignment-id --asset-type copy --title "Hooks v2" --allow-additional-receipt --json`,
|
|
403
403
|
` ${program} campaign status --name launch --json`,
|
|
404
404
|
` ${program} campaign dashboard --name launch --json`,
|
|
405
|
+
` ${program} campaign closeout --name launch --failure-mode "hidden duplicate receipt" --json`,
|
|
405
406
|
],
|
|
406
407
|
"manager-ack": [
|
|
407
408
|
`usage: ${program} manager-ack <task> --from-stdin ${path}`,
|
|
@@ -476,7 +477,7 @@ function commandHelpText(program, command) {
|
|
|
476
477
|
};
|
|
477
478
|
return linesByCommand[command] ?? [`usage: ${program} ${command} [-h] [options]`];
|
|
478
479
|
}
|
|
479
|
-
const CAMPAIGN_ACTION_NAMES = ["create", "add-slot", "attach-slot", "rotate-slot", "archive-slot", "brief", "assign", "asset", "status", "dashboard"];
|
|
480
|
+
const CAMPAIGN_ACTION_NAMES = ["create", "add-slot", "attach-slot", "rotate-slot", "archive-slot", "brief", "assign", "asset", "status", "dashboard", "closeout"];
|
|
480
481
|
const CAMPAIGN_ACTIONS = new Set(CAMPAIGN_ACTION_NAMES);
|
|
481
482
|
const CAMPAIGN_STRING_FLAGS = {
|
|
482
483
|
"--artifact-path": "artifactPath",
|
|
@@ -485,6 +486,7 @@ const CAMPAIGN_STRING_FLAGS = {
|
|
|
485
486
|
"--brief-json": "briefJson",
|
|
486
487
|
"--channel": "channel",
|
|
487
488
|
"--expected-thread-id": "expectedThreadId",
|
|
489
|
+
"--failure-mode": "failureMode",
|
|
488
490
|
"--instructions": "instructions",
|
|
489
491
|
"--objective": "objective",
|
|
490
492
|
"--prompt-summary": "promptSummary",
|
|
@@ -6094,12 +6096,16 @@ function runCampaignCommand(parsed, options) {
|
|
|
6094
6096
|
name: campaign,
|
|
6095
6097
|
objective,
|
|
6096
6098
|
});
|
|
6099
|
+
const readback = campaignSetupReadbackProofFromConfiguredDatabase(parsed, options, {
|
|
6100
|
+
campaign: campaignId,
|
|
6101
|
+
});
|
|
6097
6102
|
return campaignResult(parsed, {
|
|
6098
6103
|
action,
|
|
6099
6104
|
campaign,
|
|
6100
6105
|
campaign_id: campaignId,
|
|
6101
6106
|
created: true,
|
|
6102
|
-
|
|
6107
|
+
ledger_readback: readback,
|
|
6108
|
+
}, [`campaign ${campaign} created ${campaignId}`, campaignLedgerReadbackText(readback)]);
|
|
6103
6109
|
}
|
|
6104
6110
|
if (action === "add-slot") {
|
|
6105
6111
|
const slotKey = requiredStringFlag(parsed.flags.slotKey, "--slot-key");
|
|
@@ -6117,13 +6123,18 @@ function runCampaignCommand(parsed, options) {
|
|
|
6117
6123
|
slotKey,
|
|
6118
6124
|
...(state ? { state } : {}),
|
|
6119
6125
|
});
|
|
6126
|
+
const readback = campaignSetupReadbackProofFromConfiguredDatabase(parsed, options, {
|
|
6127
|
+
campaign,
|
|
6128
|
+
slot: slotId,
|
|
6129
|
+
});
|
|
6120
6130
|
return campaignResult(parsed, {
|
|
6121
6131
|
action,
|
|
6122
6132
|
campaign,
|
|
6123
6133
|
created: true,
|
|
6134
|
+
ledger_readback: readback,
|
|
6124
6135
|
slot_id: slotId,
|
|
6125
6136
|
slot_key: slotKey,
|
|
6126
|
-
}, [`campaign ${campaign} slot ${slotKey} created ${slotId}
|
|
6137
|
+
}, [`campaign ${campaign} slot ${slotKey} created ${slotId}`, campaignLedgerReadbackText(readback)]);
|
|
6127
6138
|
}
|
|
6128
6139
|
if (action === "attach-slot") {
|
|
6129
6140
|
const slot = requiredStringFlag(parsed.flags.slot, "--slot");
|
|
@@ -6192,13 +6203,18 @@ function runCampaignCommand(parsed, options) {
|
|
|
6192
6203
|
campaign,
|
|
6193
6204
|
channel,
|
|
6194
6205
|
});
|
|
6206
|
+
const readback = campaignSetupReadbackProofFromConfiguredDatabase(parsed, options, {
|
|
6207
|
+
campaign,
|
|
6208
|
+
channel,
|
|
6209
|
+
});
|
|
6195
6210
|
return campaignResult(parsed, {
|
|
6196
6211
|
action,
|
|
6197
6212
|
brief_id: briefId,
|
|
6198
6213
|
campaign,
|
|
6199
6214
|
channel,
|
|
6215
|
+
ledger_readback: readback,
|
|
6200
6216
|
upserted: true,
|
|
6201
|
-
}, [`campaign ${campaign} brief ${channel} upserted ${briefId}
|
|
6217
|
+
}, [`campaign ${campaign} brief ${channel} upserted ${briefId}`, campaignLedgerReadbackText(readback)]);
|
|
6202
6218
|
}
|
|
6203
6219
|
if (action === "assign") {
|
|
6204
6220
|
const slot = requiredStringFlag(parsed.flags.slot, "--slot");
|
|
@@ -6214,13 +6230,19 @@ function runCampaignCommand(parsed, options) {
|
|
|
6214
6230
|
title,
|
|
6215
6231
|
...(status ? { status } : {}),
|
|
6216
6232
|
});
|
|
6233
|
+
const readback = campaignSetupReadbackProofFromConfiguredDatabase(parsed, options, {
|
|
6234
|
+
assignment: assignmentId,
|
|
6235
|
+
campaign,
|
|
6236
|
+
slot,
|
|
6237
|
+
});
|
|
6217
6238
|
return campaignResult(parsed, {
|
|
6218
6239
|
action,
|
|
6219
6240
|
assignment_id: assignmentId,
|
|
6220
6241
|
campaign,
|
|
6221
6242
|
created: true,
|
|
6243
|
+
ledger_readback: readback,
|
|
6222
6244
|
slot_id: slot,
|
|
6223
|
-
}, [`campaign ${campaign} assignment created ${assignmentId}
|
|
6245
|
+
}, [`campaign ${campaign} assignment created ${assignmentId}`, campaignLedgerReadbackText(readback)]);
|
|
6224
6246
|
}
|
|
6225
6247
|
if (action === "asset") {
|
|
6226
6248
|
const slot = requiredStringFlag(parsed.flags.slot, "--slot");
|
|
@@ -6258,6 +6280,13 @@ function runCampaignCommand(parsed, options) {
|
|
|
6258
6280
|
const dashboard = campaignDashboardSync(database, campaign);
|
|
6259
6281
|
return campaignResult(parsed, dashboard, renderCampaignDashboardText(dashboard));
|
|
6260
6282
|
}
|
|
6283
|
+
if (action === "closeout") {
|
|
6284
|
+
const dashboard = campaignDashboardSync(database, campaign);
|
|
6285
|
+
const closeout = campaignCloseoutReport(dashboard, {
|
|
6286
|
+
failureMode: parsed.flags.failureMode,
|
|
6287
|
+
});
|
|
6288
|
+
return campaignResult(parsed, closeout, renderCampaignCloseoutText(closeout));
|
|
6289
|
+
}
|
|
6261
6290
|
return errorResult(unsupportedCampaignActionMessage(action));
|
|
6262
6291
|
}
|
|
6263
6292
|
finally {
|
|
@@ -6267,6 +6296,25 @@ function runCampaignCommand(parsed, options) {
|
|
|
6267
6296
|
function campaignActionsUsage() {
|
|
6268
6297
|
return CAMPAIGN_ACTION_NAMES.join("|");
|
|
6269
6298
|
}
|
|
6299
|
+
function campaignSetupReadbackProofFromConfiguredDatabase(parsed, options, readbackOptions) {
|
|
6300
|
+
const databasePath = runtimeDbPath(parsed, options);
|
|
6301
|
+
options.campaignReadbackBeforeVerify?.({ databasePath, readback: readbackOptions });
|
|
6302
|
+
const database = openDatabaseSync(databasePath);
|
|
6303
|
+
initializeDatabaseSync(database);
|
|
6304
|
+
try {
|
|
6305
|
+
return campaignSetupReadbackProofSync(database, readbackOptions);
|
|
6306
|
+
}
|
|
6307
|
+
catch (error) {
|
|
6308
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
6309
|
+
throw new Error(`campaign ledger readback failed after setup write: ${message}`, { cause: error });
|
|
6310
|
+
}
|
|
6311
|
+
finally {
|
|
6312
|
+
database.close();
|
|
6313
|
+
}
|
|
6314
|
+
}
|
|
6315
|
+
function campaignLedgerReadbackText(proof) {
|
|
6316
|
+
return `ledger_readback ok campaign=${proof.campaign_id} checks=${proof.checks.map((check) => check.entity).join(",")}`;
|
|
6317
|
+
}
|
|
6270
6318
|
function unsupportedCampaignActionMessage(action) {
|
|
6271
6319
|
return `Unsupported campaign action: ${action ?? "<missing>"}; expected one of: ${CAMPAIGN_ACTION_NAMES.join(", ")}. Use \`conveyor campaign dashboard --name <campaign> --json\` to list assets and receipt counts.`;
|
|
6272
6320
|
}
|
|
@@ -6342,6 +6390,107 @@ function renderCampaignDashboardText(dashboard) {
|
|
|
6342
6390
|
}
|
|
6343
6391
|
return lines;
|
|
6344
6392
|
}
|
|
6393
|
+
function campaignCloseoutReport(dashboard, options = {}) {
|
|
6394
|
+
const receiptCountsByAssignment = campaignReceiptCountsByAssignment(dashboard);
|
|
6395
|
+
const activeSlots = dashboard.slots.filter((slot) => slot.state !== "archived");
|
|
6396
|
+
const slotsMissingReceipts = activeSlots.filter((slot) => slot.assignments.length > 0 && slot.asset_receipts === 0);
|
|
6397
|
+
const duplicateAssignmentCounts = receiptCountsByAssignment.filter((item) => item.receipt_count > 1);
|
|
6398
|
+
const failureMode = options.failureMode
|
|
6399
|
+
?? "A hidden duplicate or missing worker receipt could make the campaign look closed while dashboard receipt counts are wrong.";
|
|
6400
|
+
const receiptEvidence = dashboard.slots
|
|
6401
|
+
.map((slot) => `${slot.slot_key}:assignments=${slot.assignments.length},receipts=${slot.asset_receipts}`)
|
|
6402
|
+
.join("; ");
|
|
6403
|
+
return {
|
|
6404
|
+
action: "closeout",
|
|
6405
|
+
approvals: dashboard.approvals,
|
|
6406
|
+
blockers: dashboard.blockers,
|
|
6407
|
+
campaign: dashboard.campaign,
|
|
6408
|
+
failure_mode: {
|
|
6409
|
+
evidence: `dashboard asset_total=${dashboard.summary.asset_total}; assignment_total=${dashboard.summary.assignment_total}; ${receiptEvidence}`,
|
|
6410
|
+
strongest_realistic_failure_mode: failureMode,
|
|
6411
|
+
},
|
|
6412
|
+
next_manager_action: dashboard.next_manager_action,
|
|
6413
|
+
proof_checks: [
|
|
6414
|
+
{
|
|
6415
|
+
check: "dashboard_loaded",
|
|
6416
|
+
evidence: `campaign_id=${dashboard.campaign.id}; updated_at=${dashboard.campaign.updated_at}`,
|
|
6417
|
+
status: "passed",
|
|
6418
|
+
},
|
|
6419
|
+
{
|
|
6420
|
+
check: "blockers_absent",
|
|
6421
|
+
evidence: `blockers=${dashboard.blockers.length}`,
|
|
6422
|
+
status: dashboard.blockers.length === 0 ? "passed" : "failed",
|
|
6423
|
+
},
|
|
6424
|
+
{
|
|
6425
|
+
check: "active_worker_slots_have_receipts",
|
|
6426
|
+
evidence: slotsMissingReceipts.length === 0
|
|
6427
|
+
? "all active slots with assignments have at least one receipt"
|
|
6428
|
+
: `missing_receipt_slots=${slotsMissingReceipts.map((slot) => slot.slot_key).join(",")}`,
|
|
6429
|
+
status: slotsMissingReceipts.length === 0 ? "passed" : "attention",
|
|
6430
|
+
},
|
|
6431
|
+
{
|
|
6432
|
+
check: "assignment_receipt_counts",
|
|
6433
|
+
evidence: duplicateAssignmentCounts.length === 0
|
|
6434
|
+
? "no assignment has more than one receipt"
|
|
6435
|
+
: `additional_receipt_assignments=${duplicateAssignmentCounts.map((item) => `${item.assignment_id}:${item.receipt_count}`).join(",")}`,
|
|
6436
|
+
status: duplicateAssignmentCounts.length === 0 ? "passed" : "attention",
|
|
6437
|
+
},
|
|
6438
|
+
{
|
|
6439
|
+
check: "human_review_gate",
|
|
6440
|
+
evidence: `needs_review=${dashboard.approvals.needs_review}; approved=${dashboard.approvals.approved}; published=${dashboard.approvals.published}`,
|
|
6441
|
+
status: dashboard.approvals.needs_review > 0 && dashboard.approvals.published === 0 ? "passed" : "attention",
|
|
6442
|
+
},
|
|
6443
|
+
],
|
|
6444
|
+
receipt_counts_by_assignment: receiptCountsByAssignment,
|
|
6445
|
+
summary: dashboard.summary,
|
|
6446
|
+
verdict: campaignCloseoutVerdict(dashboard),
|
|
6447
|
+
workers: dashboard.slots.map((slot) => ({
|
|
6448
|
+
active_assignments: slot.active_assignments,
|
|
6449
|
+
asset_receipts: slot.asset_receipts,
|
|
6450
|
+
blockers: slot.blockers,
|
|
6451
|
+
channel: slot.channel,
|
|
6452
|
+
codex_app_thread_id: slot.codex_app_thread_id,
|
|
6453
|
+
codex_app_thread_title: slot.codex_app_thread_title,
|
|
6454
|
+
lifecycle_state: slot.lifecycle.state,
|
|
6455
|
+
receipt_ids: slot.assets.map((asset) => asset.id),
|
|
6456
|
+
slot_key: slot.slot_key,
|
|
6457
|
+
state: slot.state,
|
|
6458
|
+
})),
|
|
6459
|
+
};
|
|
6460
|
+
}
|
|
6461
|
+
function campaignReceiptCountsByAssignment(dashboard) {
|
|
6462
|
+
return dashboard.slots.flatMap((slot) => slot.assignments.map((assignment) => ({
|
|
6463
|
+
assignment_id: assignment.id,
|
|
6464
|
+
receipt_count: slot.assets.filter((asset) => asset.assignment_id === assignment.id).length,
|
|
6465
|
+
slot_key: slot.slot_key,
|
|
6466
|
+
})));
|
|
6467
|
+
}
|
|
6468
|
+
function campaignCloseoutVerdict(dashboard) {
|
|
6469
|
+
if (dashboard.blockers.length > 0 || dashboard.summary.blocked_assignments > 0 || dashboard.summary.blocked_slots > 0 || dashboard.summary.stale_slots > 0) {
|
|
6470
|
+
return "blocked";
|
|
6471
|
+
}
|
|
6472
|
+
if (dashboard.next_manager_action.action === "close_campaign") {
|
|
6473
|
+
return "ready_to_close";
|
|
6474
|
+
}
|
|
6475
|
+
if (dashboard.approvals.needs_review > 0 || dashboard.approvals.rejected > 0) {
|
|
6476
|
+
return "needs_review";
|
|
6477
|
+
}
|
|
6478
|
+
return "needs_work";
|
|
6479
|
+
}
|
|
6480
|
+
function renderCampaignCloseoutText(report) {
|
|
6481
|
+
return [
|
|
6482
|
+
`campaign ${report.campaign.name} ${report.campaign.status}`,
|
|
6483
|
+
`closeout verdict ${report.verdict}`,
|
|
6484
|
+
`next ${report.next_manager_action.action}: ${report.next_manager_action.reason}`,
|
|
6485
|
+
`summary slots=${report.summary.active_slots}/${report.summary.archived_slots} assignments=${report.summary.assignment_total} assets=${report.summary.asset_total} blockers=${report.blockers.length}`,
|
|
6486
|
+
`approvals needs_review=${report.approvals.needs_review} approved=${report.approvals.approved} rejected=${report.approvals.rejected} published=${report.approvals.published}`,
|
|
6487
|
+
`failure_mode ${report.failure_mode.strongest_realistic_failure_mode}`,
|
|
6488
|
+
`failure_mode_evidence ${report.failure_mode.evidence}`,
|
|
6489
|
+
...report.proof_checks.map((check) => `proof ${check.status} ${check.check}: ${check.evidence}`),
|
|
6490
|
+
...report.receipt_counts_by_assignment.map((item) => `assignment_receipts ${item.slot_key} ${item.assignment_id}=${item.receipt_count}`),
|
|
6491
|
+
...report.workers.slice(0, 8).map((worker) => `worker ${worker.slot_key} ${worker.state}/${worker.lifecycle_state} assignments=${worker.active_assignments} receipts=${worker.asset_receipts} thread=${worker.codex_app_thread_id ?? "none"}`),
|
|
6492
|
+
];
|
|
6493
|
+
}
|
|
6345
6494
|
function statusCountsText(counts) {
|
|
6346
6495
|
return Object.entries(counts).map(([status, count]) => `${status}=${count}`).join(" ");
|
|
6347
6496
|
}
|