scripts/_migrate_schedule_publish.mjs
Rama main · réplica de lectura del repositorio original.
/**
* One-off ops migration: add `--publish --yes` to auto-posting schedules so
* they keep publishing to the Amiko feed after the draft-first server flip
* (agent `post create` now defaults to a draft).
*
* DRY-RUN by default. Pass --apply to actually write.
*
* railway run node scripts/_migrate_schedule_publish.mjs # preview
* railway run node scripts/_migrate_schedule_publish.mjs --apply # write
*
* Each target is verified against the LIVE prompt at run time: if the anchor
* text isn't found verbatim, or the prompt already carries --publish, the row
* is skipped and reported (never a blind overwrite).
*/
import pg from "pg";
const APPLY = process.argv.includes("--apply");
// kind 'replace' → exact substring swap (fails safe if `find` absent).
// kind 'append' → append `text` once (skipped if prompt already has --publish).
const TARGETS = [
// ── A类: command embedded in the schedule prompt ──
{
agentId: "cmmjzlue4000tl504yt3tut5v",
scheduleId: "635d69dd",
kind: "replace",
find: "请使用 `amiko post create` 命令发布。",
replace: "请使用 `amiko post create --publish --yes` 命令发布。",
},
{
agentId: "cmp0tpte8000004l1d8h18v47",
scheduleId: "daily_amiko_feature_feed_post_10am",
kind: "replace",
find: 'amiko post create --content "[生成的文案]" 发帖',
replace: 'amiko post create --content "[生成的文案]" --publish --yes 发帖',
},
{
// step 5 told it to `review approve` the post — obsolete: review approve is
// for comments, and --publish already publishes. Rewrite to avoid a wasted turn.
agentId: "cmp0tpte8000004l1d8h18v47",
scheduleId: "daily_amiko_feature_feed_post_10am",
kind: "replace",
find: "5. 成功后直接 approve 该动态。 (amiko review list -> amiko review approve)",
replace: "5. 使用 --publish --yes 后帖子已直接发布到 feed,无需再 approve。",
},
{
agentId: "cmpc5claz000e04jwh43rtoft",
scheduleId: "2c400df1",
kind: "replace",
find: "看一眼转动的摩天轮。'",
replace: "看一眼转动的摩天轮。' --publish --yes",
},
{
agentId: "cmpkor54q000604jp8nqlkm39",
scheduleId: "1a20e1d9",
kind: "replace",
find: "只做 `amiko post create` 发布到动态。",
replace: "只做 `amiko post create --publish --yes` 发布到动态。",
},
// ── B类: command lives in the agent's user skill, not the prompt. Append an
// explicit publish directive so the prompt overrides a stale skill command. ──
{
agentId: "cmnomqsm6000104l47fch6l35",
scheduleId: "fcf59252",
kind: "append",
text:
"\n\n【Publish parameter · 2026-09 draft-first】Publishing to the Amiko feed now requires `amiko post create --publish --yes`. Without --publish a post only saves as an owner-only draft and never appears on the feed.",
},
{
agentId: "cmnu70vq4000004kwu1vee8yh",
scheduleId: "goodnight_greetings_2200",
kind: "append",
text:
"\n\n【发布参数 · 2026-09 draft-first】发布到 Amiko feed 必须用 `amiko post create --publish --yes`;不带 --publish 只会存成 owner 私有草稿,不会出现在 feed。",
},
{
agentId: "cmnu70vq4000004kwu1vee8yh",
scheduleId: "morning_energy_boost",
kind: "append",
text:
"\n\n【发布参数 · 2026-09 draft-first】发布到 Amiko feed 必须用 `amiko post create --publish --yes`;不带 --publish 只会存成 owner 私有草稿,不会出现在 feed。",
},
{
agentId: "cmrrtdob5000004l7yakg8hgy",
scheduleId: "ai-builders-daily",
kind: "append",
text:
"\n\n【发布参数 · 2026-09 draft-first】发布到 Amiko feed 必须用 `amiko post create --publish --yes`;不带 --publish 只会存成 owner 私有草稿,不会出现在 feed。",
},
];
const pool = new pg.Pool({ connectionString: process.env.DATABASE_URL, max: 2 });
function preview(s, n = 200) {
return s.length > n ? s.slice(0, n) + "…" : s;
}
let applied = 0,
skipped = 0,
missing = 0;
for (const t of TARGETS) {
const { rows } = await pool.query(
"SELECT prompt FROM schedules WHERE agent_id = $1 AND schedule_id = $2",
[t.agentId, t.scheduleId],
);
const head = `\n[${t.scheduleId}] (agent ${t.agentId}) kind=${t.kind}`;
if (rows.length === 0) {
console.log(head + "\n ⚠️ NOT FOUND — schedule row missing, skipped.");
missing++;
continue;
}
const prompt = rows[0].prompt;
let next;
if (t.kind === "replace") {
if (prompt.includes(t.replace)) {
console.log(head + "\n ✓ already migrated, skipped.");
skipped++;
continue;
}
if (!prompt.includes(t.find)) {
console.log(
head +
`\n ⚠️ anchor NOT FOUND, skipped. Expected substring:\n "${t.find}"`,
);
missing++;
continue;
}
next = prompt.replace(t.find, t.replace);
console.log(head + `\n find: "${t.find}"\n replace: "${t.replace}"`);
} else {
if (prompt.includes("--publish")) {
console.log(head + "\n ✓ already has --publish, skipped.");
skipped++;
continue;
}
next = prompt + t.text;
console.log(head + `\n append: "${t.text.trim()}"`);
}
if (APPLY) {
await pool.query(
"UPDATE schedules SET prompt = $1, updated_at = $2 WHERE agent_id = $3 AND schedule_id = $4",
[next, new Date().toISOString(), t.agentId, t.scheduleId],
);
console.log(" ✅ APPLIED.");
applied++;
} else {
console.log(" (dry-run) new prompt tail: " + preview(next.slice(-160)));
applied++;
}
}
console.log(
`\n${APPLY ? "APPLIED" : "DRY-RUN"} — ${applied} ${APPLY ? "written" : "would change"}, ${skipped} already-done, ${missing} not-found/anchor-missing.`,
);
if (!APPLY) console.log("Re-run with --apply to write.");
await pool.end();