Ctrl K
ComunidadGuías…

scripts/_migrate_schedule_publish.mjs

Rama main · réplica de lectura del repositorio original.

Archivo original ↗Preguntar a KiBot
/**
 * 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();