Skip to content

chore(sync): merge upstream Post Workflow v1.1.2, MCP icons & roadmap updates - #32

Merged
JOY (JOY) merged 17 commits into
mainfrom
dev
Sep 5, 2026
Merged

chore(sync): merge upstream Post Workflow v1.1.2, MCP icons & roadmap updates#32
JOY (JOY) merged 17 commits into
mainfrom
dev

Conversation

@JOY

@JOY JOY (JOY) commented Sep 5, 2026

Copy link
Copy Markdown

What kind of change does this PR introduce?

Feature & Ecosystem Sync: Backend, Orchestrator, Frontend. Merges upstream Postiz updates (Post Workflow v1.1.2, MCP Client Icons, Onboarding improvements) and updates Crove Post roadmap.

Why was this change needed?

To bring the latest upstream Postiz stability enhancements (workflow retry resilience on heartbeat timeout and expanded MCP agent support) into main and deploy to the live production environment.

Technical Details & Scope

  • apps/orchestrator: Added post.workflow.v1.1.2.ts to retry publishing activities on heartbeat timeouts with zero heartbeat details.
  • apps/frontend:
    • Added Nanoclaw and other MCP client icon components in mcp.client.icons.tsx.
    • Upgraded onboarding.modal.tsx and public API components.
  • docs:
    • Expanded ROADMAP.md with Crove OS visual modernization and media architecture milestones.
    • Updated CHANGELOG.md.
  • CI/CD: Added guard condition to staging-conflicts.yml so it only runs on upstream gitroomhq/postiz-app.

Verification & Testing

  • Verified NestJS Backend build: pnpm --filter ./apps/backend run build (PASS).
  • Verified Temporal Orchestrator build: pnpm --filter ./apps/orchestrator run build (PASS).
  • Verified SSO Vitest test suite: pnpm --filter @crove/sso test (31/31 passed).
  • Verified Branding Guard validation: pnpm dlx tsx scripts/branding-guard.ts (100% passed).

QA

  1. Log in via SSO DOS ID on post.crove.com/auth
  2. Verify that the dashboard and calendar load without errors
  3. Verify /api/health returns 200 OK
  4. Check that Temporal workflows continue to execute scheduled posts reliably

Checklist:

  • My code follows the project's code style and architectural conventions.
  • Local build passes (pnpm run build).
  • Tests and typecheck have been verified without errors.
  • Documentation has been updated (if applicable).
  • No secrets or sensitive credentials are included in this PR.
  • I have filled in the QA / Verification section above with real steps to verify this change.

Note

Medium Risk
New postWorkflowV112 changes core publish/retry behavior for all queued posts; incorrect retry logic could duplicate or strand posts. The staging-conflicts workflow can push to staging when enabled on the upstream repo.

Overview
Syncs upstream Postiz changes into Crove Post: scheduled publishing now uses Temporal postWorkflowV112 (replacing v1.1.1) with smarter handling of heartbeat timeouts—retries when no heartbeat was ever received, otherwise treats outcomes as unknown to avoid duplicate posts. Developers & onboarding gain a third wizard step (Connect Agents), shared MCP helpers, oauth vs API key auth, more clients (OpenClaw, Hermes, NanoClaw, Grok Bot, etc.), McpClientIcon, and Cursor one-click install.

Settings > Developers MCP UI is aligned with the same client list and auth model. Docs update CHANGELOG.md and expand ROADMAP.md (Crove OS UI, R2, AI). CI adds staging-conflicts.yml: periodic probe of mainstaging merges, Claude-assisted resolution, verification, and push—gated to gitroomhq/postiz-app only so forks do not run it.

Reviewed by Cursor Bugbot for commit d838d21. Configure here.

3c4cc6d removed --max-turns so a multi-file resolution could finish.
9c01436 re-applied the workflow from a pre-3c4cc6d7 buffer and brought
the cap back, so every run with more than a couple of conflicts died on
"Reached maximum number of turns (12)". timeout-minutes: 20 remains the
outer bound.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The workflow file was added independently on main and staging, so the
merge base has no version of the path and git reports add/add. Any edit
to it on main therefore conflicts regardless of staging's content, and
the old guard turned that into a hard failure -- the workflow deadlocked
on every change to itself.

CI definitions belong to main in a main->staging flow, so conflicts under
.github/ are now settled with `git checkout --theirs` before Claude runs.
Verify asserts each .github/ path the merge touched is byte-identical to
main's copy, per-path rather than as a blanket diff, since staging carries
its own non-conflicting CODEOWNERS and build.yml.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
… with no heartbeat details

Replaces the v1.1.1 timing window with the timeout failure's lastHeartbeatDetails.
…ut-retry

feat(orchestrator): post workflow v1.1.2 retries on heartbeat timeout with no heartbeat details
@cursor

cursor Bot commented Sep 5, 2026

Copy link
Copy Markdown

Bugbot couldn't run - usage limit reached

Bugbot is counted against Cursor usage for this user or team, and this run hit a usage or spend limit.

A user or team admin can review and increase usage limits in the Cursor dashboard.

(requestId: serverGenReqId_560d7ab4-db93-4ee9-9119-76e558fb7fd7)

@JOY
JOY (JOY) merged commit 71fe723 into main Sep 5, 2026
15 checks passed

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request introduces onboarding enhancements, including support for third-party MCP client icons, and upgrades the background workflow to version 1.1.2 with automatic retry capabilities on heartbeat timeouts. Key feedback points out a potential runtime TypeError due to unsafe access of the optional integration property on the post object, and an unused poked variable in the workflow. Additionally, there is a potential crash when using btoa with non-ASCII characters, and a UX issue where the local CLI installation section is unnecessarily displayed for remote clients like Claude and ChatGPT.

Comment on lines +185 to +188
if (!post) {
await changeState(postId, 'ERROR', 'No Post');
return;
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

The post object returned from getPostsList has an optional integration property (integration?: Integration). Accessing properties on it directly (e.g., post.integration.token or post.integration.organizationId) or passing it to activities without checking if it is defined can throw a TypeError at runtime. In Temporal, a TypeError inside a workflow will fail the workflow task and block execution. Adding a guard right after retrieving the post ensures robust and defensive execution.

  if (!post) {
    await changeState(postId, 'ERROR', 'No Post');
    return;
  }

  if (!post.integration) {
    await changeState(postId, 'ERROR', 'No Integration');
    return;
  }

Comment on lines +147 to +150
let poked = false;
setHandler(poke, () => {
poked = true;
});

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The poked variable is declared and set to true inside the poke signal handler, but it is never read or used anywhere else in the workflow. If the signal is intended to wake up the workflow from its scheduling sleep, that logic is currently missing (since await sleep(...) is not interrupted by signals unless raced). If it is not needed, the unused variable and handler should be removed to improve maintainability.

Comment on lines +292 to +294
return `cursor://anysphere.cursor-deeplink/mcp/install?name=postiz&config=${btoa(
JSON.stringify(server)
)}`;

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The standard btoa function throws a DOMException if the input string contains any characters outside of the Latin1 range (0x00-0xff). If mcpBase or apiKey contains non-ASCII characters (e.g., in self-hosted IDN domains or custom keys), this will crash the onboarding modal. Safely encoding the string to UTF-8 before calling btoa prevents this issue.

Suggested change
return `cursor://anysphere.cursor-deeplink/mcp/install?name=postiz&config=${btoa(
JSON.stringify(server)
)}`;
return "cursor://anysphere.cursor-deeplink/mcp/install?name=postiz&config=" + btoa(
unescape(encodeURIComponent(JSON.stringify(server)))
);

Comment on lines +614 to +622
) : (
<>
{connectorSection}
<div className="grid grid-cols-2 gap-[16px]">
{mcpSection}
{cliSection}
</div>
</>
)}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The onboarding modal displays the local CLI installation section (cliSection) side-by-side with the MCP configuration for all clients except apiTab and chatOnly clients. This is incorrect and confusing for remote/hosted clients like Claude and ChatGPT, which do not use or require the local CLI. Hiding the CLI section and making the MCP section full-width for these remote clients improves the onboarding UX.

          ) : (
            <>
              {connectorSection}
              <div className={clsx(agent === 'Claude' || agent === 'ChatGPT' ? "flex flex-col" : "grid grid-cols-2", "gap-[16px]")}>
                {mcpSection}
                {agent !== 'Claude' && agent !== 'ChatGPT' && cliSection}
              </div>
            </>
          )

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants