Commit graph

1683 commits

Author SHA1 Message Date
open-design-bot
9d0efa944a chore(contributors): @xiaobinHub opened issue #3017 2026-05-26 14:23:59 +00:00
open-design-bot
6eab748995 chore(card): generated card 2026-05-26 14:22:37 +00:00
open-design-bot
8060f2ffb6 chore(events): append issue_opened_accepted 2026-05-26 14:22:35 +00:00
open-design-bot
dd6080c2bf chore(contributors): @xxiaoxiong opened issue #3016 2026-05-26 14:22:33 +00:00
open-design-bot
ec1f46d827 chore(events): append pr_merged 2026-05-26 14:09:48 +00:00
open-design-bot
034f8e5e65 chore(contributors): +12pts for @lefarcen (PR #2994) 2026-05-26 14:09:46 +00:00
lefarcen
7312c64580
ci(landing): split landing deploy into staging gate + manual production (#2994)
* ci(landing): split landing deploy into staging gate + manual production

A merge to `main` previously published the landing page straight to
production (open-design.ai) via `landing-page-deploy`. There was no
buffer to review the rendered site, so a bad merge was live instantly.

Split deploys across two Cloudflare Pages projects so production is only
ever reached by an explicit human action:

- `landing-page-staging` (push to main) -> staging project
  `open-design-landing-staging` -> staging.open-design.ai.
- `landing-page-production` (manual workflow_dispatch only) -> production
  project `open-design-landing` -> open-design.ai. Only this workflow
  names the production project; gate it with required reviewers on the
  `production` GitHub environment.
- `landing-page-ci` now also deploys a per-PR preview into the staging
  project (`--branch=pr-<n>`) for same-repo branches and comments the URL.
  Fork PRs (no secrets / read-only token) skip the deploy and keep just
  the build validation. Path filters already scope this to landing edits.

Decouple search-engine indexing from staging:

- `blog-indexing-on-deploy` now triggers on `landing-page-production`
  (not every main push), so the test environment is never submitted to
  Google/IndexNow.
- It diffs from a new `blog-indexed-prod` tag (the last indexed prod
  commit) instead of `HEAD^`, and force-advances the tag after a
  successful run, so a manual promotion bundling several merged posts
  indexes all of them rather than only the last commit.

Staging and PR-preview builds drop `PUBLIC_GA_MEASUREMENT_ID` so test
traffic does not pollute the production GA property.

* ci(landing): keep staging + PR previews out of the search index

staging.open-design.ai mirrors production and is exposed via cert
transparency logs, so search engines can discover it. Indexing the
mirror competes with open-design.ai for the same content.

Emit `<meta name="robots" content="noindex, nofollow">` whenever
OD_LANDING_NOINDEX=1, and set that flag on the staging and PR-preview
builds (production leaves it unset and stays indexable). noindex is
used rather than a robots.txt Disallow so crawlers can still fetch the
page and read both the tag and the canonical, which already points at
the production origin.

* fix(landing): make staging noindex actually take effect

The previous commit read `process.env.OD_LANDING_NOINDEX` directly in
`seo-head.astro`, but `.astro` frontmatter is transformed by Vite and
does not see process.env, so the meta never rendered. Two fixes:

- Inject the flag as the compile-time constant `__OD_LANDING_NOINDEX__`
  via `vite.define` in astro.config.ts (config runs in Node and can read
  process.env); SeoHead consumes that constant.
- The homepage (`index.astro`) and `og.astro` build their own <head> and
  never use SeoHead, so a per-component meta can miss pages. Add an
  `astro:build:done` integration that appends a catch-all
  `/*  X-Robots-Tag: noindex, nofollow` to the Cloudflare Pages `_headers`
  on staging/preview builds, covering every response (homepage, assets,
  any custom-head page) at the HTTP layer. Production builds leave
  `_headers` untouched.

Verified: build with OD_LANDING_NOINDEX=1 emits the _headers block and
the SeoHead <meta>; build without the flag emits neither; astro check
clean.

* fix(landing): address review — pin prod checkout to main, defer index pointer

Two blockers from review:

- landing-page-production: workflow_dispatch can be launched from any ref
  via the Actions "Use workflow from" dropdown, so an operator could ship
  an arbitrary branch to open-design.ai. Pin the checkout to `ref: main`
  so the deployed artifact always equals reviewed main.

- blog-indexing-on-deploy: the `blog-indexed-prod` pointer was advanced
  right after sitemap submission, before Inspect / Search Analytics /
  Render status / Open status PR. A failure in any of those still moved
  the pointer, so the next production run skipped those posts. Move the
  advance to the very end, gated on `success()`, so a failure leaves the
  tag in place and the range is re-processed next run (submissions are
  idempotent).

* fix(landing): gate production promotion to the main ref only

Follow-up to the production-path review note: pinning checkout to main
fixed the deployed content, but the workflow was still dispatchable from
any ref, which records a non-main production run and would dodge
blog-indexing's `workflow_run` `branches: [main]` filter. Gate the whole
job on `github.ref == 'refs/heads/main'` so a dispatch from any other
branch/tag is skipped outright.
2026-05-26 14:05:04 +00:00
open-design-bot
6618780812 chore(card): generated card 2026-05-26 14:01:21 +00:00
open-design-bot
a7bafe78f7 chore(events): append pr_merged 2026-05-26 14:01:19 +00:00
open-design-bot
22d7830943 chore(contributors): +30pts for @jinmeihong0201-gif (PR #3012) 2026-05-26 14:01:17 +00:00
ashleytheash
f27fbfb3f1 chore(test): restore contributor data after email pipeline verification 2026-05-26 21:10:10 +08:00
open-design-bot
2e45a49a8d chore(card): generated card 2026-05-26 13:05:40 +00:00
open-design-bot
5ebced04f8 chore(events): append issue_opened_accepted 2026-05-26 13:05:38 +00:00
open-design-bot
c6c98d11a5 chore(contributors): @ashleytheash opened issue #3008 2026-05-26 13:05:37 +00:00
ashleytheash
9d5343a7de chore(test): reset for end-to-end resend send verification 2026-05-26 21:05:30 +08:00
open-design-bot
997a07e57d chore(card): generated card 2026-05-26 13:04:30 +00:00
open-design-bot
1bb91282b2 chore(events): append pr_merged 2026-05-26 13:04:28 +00:00
open-design-bot
51c46201fb chore(contributors): +30pts for @lefarcen (PR #2993) 2026-05-26 13:04:27 +00:00
lefarcen
a0ea9bdaf3
ci: make agent PR exploration manual only (#2993)
* Make agent PR explore manual dispatch only

* chore: retrigger PR checks

* chore: retrigger CI after Actions recovery
2026-05-26 12:59:58 +00:00
open-design-bot
faa77a940d chore(card): generated card 2026-05-26 12:59:04 +00:00
open-design-bot
371cf483e3 chore(events): append issue_opened_accepted 2026-05-26 12:59:03 +00:00
open-design-bot
c97d817ad8 chore(contributors): @ashleytheash opened issue #3007 2026-05-26 12:59:01 +00:00
ashleyashli
a922d077bf chore(test): reset contributors before resend-key end-to-end test 2026-05-26 20:58:01 +08:00
open-design-bot
2c968dd528 chore(card): generated card 2026-05-26 12:54:38 +00:00
open-design-bot
80149127e2 chore(events): append issue_opened_accepted 2026-05-26 12:54:37 +00:00
open-design-bot
7f2abf6b67 chore(contributors): @ashleytheash opened issue #3006 2026-05-26 12:54:35 +00:00
ashleyashli
31ac82b4e7 chore(test): reset contributors to test spark welcome flow end-to-end 2026-05-26 20:53:07 +08:00
open-design-bot
05ecfc335f chore(events): append issue_opened_accepted 2026-05-26 12:49:33 +00:00
open-design-bot
248f0e320a chore(contributors): @ashleytheash opened issue #3005 2026-05-26 12:49:32 +00:00
open-design-bot
687814a5ba chore(card): generated card 2026-05-26 12:48:56 +00:00
open-design-bot
b2da15bcca chore(events): append issue_opened_accepted 2026-05-26 12:48:54 +00:00
open-design-bot
5f72423261 chore(contributors): @ashleyashli opened issue #3004 2026-05-26 12:48:53 +00:00
ashleyashli
0bad8c8591 chore(test): temporarily remove ashleyashli to re-trigger spark welcome flow 2026-05-26 20:48:38 +08:00
open-design-bot
6d3786024f chore(card): generated card 2026-05-26 12:44:52 +00:00
open-design-bot
b1d518a39d chore(events): append issue_opened_accepted 2026-05-26 12:44:50 +00:00
open-design-bot
23f1b6b1ec chore(contributors): @ashleyashli opened issue #3003 2026-05-26 12:44:49 +00:00
open-design-bot
243dcab605 chore(card): generated card 2026-05-26 12:41:52 +00:00
open-design-bot
89d55b64d7 chore(events): append issue_opened_accepted 2026-05-26 12:41:50 +00:00
open-design-bot
9cc7460b9f chore(contributors): @ashleytheash opened issue #3002 2026-05-26 12:41:49 +00:00
chaoxiaoche
fce444bcab
Consolidate chat comments preview on main (#2906)
* feat(web): queue chat sends

* feat(web): render code comment directives

* feat(web): add preview comments and manual edits

* fix(web): polish shared chrome controls

* fix(web): align queued send loading state

* feat(web): open primary project artifacts

* fix(web): keep queued sends and tests aligned

* fix(web): restore docked comment tools layout

* fix(web): align preview comment toolbar

* fix(web): place local cli beside handoff

* fix(web): move agent menu beside handoff

* fix(web): make project instructions a direct header action

* fix(web): compact handoff and toolbar labels

* fix(web): clarify handoff menu and annotation label

* fix(web): restore compact cursor handoff trigger

* fix(web): align agent menu trigger with handoff

* fix(web): add draw toolbar close action

* fix(web): move inspect editing into edit mode

* fix(web): avoid reserving comment sidebar in annotation mode

* fix(web): float preview comments panel

* fix(web): keep edit canvas full width

* fix(web): polish preview annotation tools

* fix(web): highlight active preview comments

* fix(web): open comments panel after annotation save

* fix(web): polish comment handoff controls

* fix(web): remove palette preview tool

* fix(web): simplify draw annotation toolbar

* fix(web): restore queued tasks into composer

* fix(web): restore queued send strip styling

* fix(web): hide internal comment target ids

* fix(web): align manual edit panel header

* test(web): cover visual interaction contracts

* fix(web): address PR feedback regressions

* fix(web): preserve artifact chrome state

* fix(daemon): restore project raw file routes

---------

Co-authored-by: chaoxiaoche <chaoxiaoche@chaoxiaochedeMacBook-Pro.local>
Co-authored-by: mrcfps <mrc@powerformer.com>
2026-05-26 10:31:19 +00:00
lefarcen
b5bf28060b
Add sandboxed agent PR exploration (#2604) 2026-05-26 07:52:42 +00:00
Jane
ceb636aa1b
feat(landing-page): plugin detail page interactive preview + share dialog (#2958)
* feat(landing-page): plugin detail page interactive preview + share dialog

The new `/plugins/<manifest-id>/` detail page that shipped in #2926
landed without the two affordances PR #2679 added to the legacy
`/skills/<slug>/` and `/templates/<slug>/` pages: a click-to-expand
iframe of the live artifact, and a share dialog with brand-keyword
copy plus four-channel jump buttons (X / LinkedIn / Reddit /
Facebook). This restores both, sourced from the bundled-plugin
manifest under `plugins/_official/<bucket>/<slug>/open-design.json`.

## Interactive preview

Three preview-type behaviours, gated on `od.preview.type`:

  - `video` (Cloudflare Stream URLs already in the manifest) —
    inline `<video controls poster=...>` with the playable MP4 as
    `<source>`. Detail-page row is unchanged from #2926; controls
    double as the open-full affordance.
  - `html` (a local `example.html` referenced by `od.preview.entry`,
    only the `examples/` bucket today) — `<details>` toggle wraps the
    poster image as the summary; clicking opens a sandboxed
    `<iframe>` that loads the entry HTML lazily, with an
    "Open in new tab ↗" pill in the frame's top-right corner so the
    artifact can be inspected at full screen.
  - `image` or no entry — static `<img>` (existing behaviour).

`copy-example-html.ts` is extended to mirror the local entry and any
`./assets/...` siblings to `out/plugins/<manifest-id>/<entry>` so the
iframe URL resolves on Cloudflare Pages instead of SPA-falling-back to
the homepage. The four examples carrying sibling-asset references
(flowai-live-dashboard-template, trading-analysis-dashboard-template,
open-design-landing, open-design-landing-deck) all render in-place.

## Share dialog

Same `<dialog data-share-dialog>` markup the legacy detail pages use,
so the global click handlers in `header-enhancer.astro`
(`data-share-open` / `data-share-copy` / `data-copy-link`) wire up
the open / copy actions automatically — no extra client bundle. Four
platform jumps (X / LinkedIn / Reddit / Facebook) plus a Copy-text /
Copy-link pair, with a single English template for now (the new
`/plugins/...` routes only generate English pages; localisation can
land alongside the i18n catch-all follow-up).

## Bundled in

- The `copy-example-html.ts` sibling-assets fix from open PR #2880.
  Without it the existing `/skills/<slug>/` iframe still 404s on
  Cloudflare Pages for after-hours-editorial-template and the four
  others; bundling it here means the same script handles both
  sources in one pass and sidesteps two PRs touching identical
  helper code.

* fix(plugins): remove dangling preview.entry from example-hyperframes

The hyperframes example folder ships a SKILL.md (it's an instruction
manual for using the HyperFrames HTML format) but no runnable
`example.html`. The manifest still claimed `preview.type: html` /
`preview.entry: ./example.html`, which made the marketing site try
to iframe a non-existent file and forced the preview pipeline into
its `Path 3` fallback card — leaving the catalog row visually
inconsistent with the eleven sibling `video-template-hyperframes-*`
plugins that have real Cloudflare-Stream poster URLs.

Drop the preview block entirely so the manifest stops promising a
demo it can't deliver. The landing-page detail row continues to
render the typographic fallback card (sourced from title /
description / mode), which is now the honest representation:
"this is an instruction skill, not a renderable template".

* fix(landing-page): address PR #2958 review feedback on plugin preview pipeline

Two blocking issues called out in code review:

1) `bundled-plugins.ts` exposed `previewEntryUrl` for every manifest
   that declared `preview.type: "html"`, even when the entry file
   wasn't shipped. Several first-party manifests fall in this state
   (example-design-brief's `./brief-preview.html`, example-x-research,
   example-pptx-html-fidelity-audit, example-hatch-pet,
   example-last30days, example-guizang-ppt, example-replit-deck,
   example-live-artifact, example-html-ppt, example-dcf-valuation).
   The detail page then rendered a click-to-expand iframe and popout
   link to a file that copy-example-html.ts had skipped, so the
   iframe URL SPA-fell-back to the homepage on Cloudflare Pages.

   `entryRelativeUrl()` now `existsSync()`-checks the resolved local
   path before returning a URL. When the file's missing the detail
   page falls through to the static thumbnail branch, exactly like
   plugins that ship no preview entry at all.

2) `copy-example-html.ts` recognised only `(src|href|poster)="./assets/..."`
   and then bulk-copied the entry's sibling `assets/` folder, so it
   missed two real ref shapes: bare-relative (`href="assets/styles.css"`,
   `src="assets/deck-stage.js"` under example-html-ppt-zhangzara-pin-and-paper)
   and cross-folder (`src="../open-design-landing/assets/hero.png"`
   under example-open-design-landing-deck).

   Replaced the heuristic with a generic walker that:
   - Parses every relative ref in the entry HTML
     (`(src|href|poster|srcset|data-src)=` plus `url(...)`), splitting
     srcset on whitespace/commas so multi-URL attrs are honoured.
   - Resolves each ref against `dirname(entrypointSrc)` for the source
     and against `dirname(iframeAbsPath)` for the destination —
     identical to how a browser resolves the same ref against the
     iframe URL. Files outside the source root or the iframe root
     are dropped.
   - Recurses into copied HTML / CSS / JS / SVG so multi-step chains
     (entry → assets/template.html → assets/fonts/foo.woff) don't
     strand intermediate files.
   - Tracks visited *destinations* rather than sources, so a single
     source that legitimately needs to land at two different out-paths
     (same-folder copy at /plugins/example-X/assets/foo.png AND a
     cross-folder copy at /plugins/open-design-landing/assets/foo.png
     for sibling decks that use `../open-design-landing/assets/foo.png`)
     gets both copies.

Verified manually:
- /plugins/example-html-ppt-zhangzara-pin-and-paper/assets/styles.css
  and assets/deck-stage.js → 200 (bare-relative)
- /plugins/open-design-landing/assets/hero.png and assets/about.png
  → 200 (cross-folder destination, no manifest-id prefix because
  iframe URL `..` collapses the prefix)
- /plugins/example-design-brief/ renders the static thumbnail only,
  no click-to-expand iframe (broken entry guard)
- /plugins/example-flowai-live-dashboard-template/assets/template.html
  → 200 (existing same-folder behaviour preserved)

Build now reports `copied 266 entry files + 65 referenced files`,
where the 65 includes both the same-folder `./assets/...` payloads
the previous heuristic captured and the bare-relative + cross-folder
shapes it didn't.

---------

Co-authored-by: Joey-nexu <joeylee12629@gmail.com>
2026-05-26 07:43:46 +00:00
Yuhao Chen
3655230571
fix(web): align draw note enter action (#2971) 2026-05-26 07:36:34 +00:00
Marc Chan
d5659d82d4
chore(nix): streamline pnpm deps hash maintenance (#2919)
* chore(nix): streamline pnpm deps hash maintenance

Generated-By: looper 0.9.0 (runner=worker, agent=opencode)

* fix(ci): satisfy actionlint in nix hash autofix

Generated-By: looper 0.9.0 (runner=fixer, agent=opencode)

* fix(ci): allow nix hash autofix on fork PRs

Generated-By: looper 0.9.0 (runner=fixer, agent=opencode)

* fix(ci): follow up nix hash review

Generated-By: looper 0.9.0 (runner=fixer, agent=opencode)

* fix(ci): tolerate nix hash bot token failures

Generated-By: looper 0.9.0 (runner=fixer, agent=opencode)
2026-05-26 07:35:38 +00:00
Yuhao Chen
fb1e0c819f
fix(plugins): reject symlinked plugin assets (#2036)
* fix(plugins): reject symlinked plugin assets

* test(plugins): cover asset directory symlink escapes

* fix(plugins): reject symlinked asset path segments
2026-05-26 07:03:22 +00:00
kami
9e8d01ee22
fix(daemon): fail disallowed connector tool selections (#2006)
* fix(daemon): fail disallowed connector tool selections

* fix(daemon): harden connector tool error parsing
2026-05-26 07:03:10 +00:00
蓝宙
b5b975769a
fix Windows folder import from project modal (#2863)
Co-authored-by: Lanzhou3 <217479610+Lanzhou3@users.noreply.github.com>
2026-05-26 06:52:07 +00:00
Yuhao Chen
1770789fa0
fix(web): hide recent project pagination chrome (#2966) 2026-05-26 06:47:48 +00:00
ashleytheash
dbdf3b9637
feat(landing): add /share-out redirect to track X share button clicks (#2969)
* feat(landing): add /share-out redirect for X share button click tracking

Adds a Cloudflare Pages Function at /share-out/:eventId that records each
click of the "Share on X" button surfaced in the contributor card comments
on GitHub, then 302-redirects to the original twitter.com / x.com intent
URL (passed via ?to=, host-allowlisted).

Together with the existing /share/:eventId function this gives us both
sides of the X funnel without an X API key:

  - /share-out/:eventId  -> GitHub user clicked the X button   (funnel step 1)
  - /share/:eventId      -> someone on X clicked the posted tweet (funnel step 2)

Per-event KV storage is optional (SHARE_OUT_CLICK_EVENTS). When no KV is
bound the function falls back to console.log; aggregate counts are visible
in Cloudflare Pages analytics with no extra setup.

Co-authored-by: Cursor <cursoragent@cursor.com>

* chore: retrigger CI

Co-authored-by: Cursor <cursoragent@cursor.com>

---------

Co-authored-by: ashley li <ashleyli@ashleydeMacBook-Air-2.local>
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-26 15:13:59 +08:00
nettee
6c6ee44e07
docs(media): clarify custom providers and ComfyUI status (#479) (#2942)
Closes #479

Generated-By: looper 0.9.0 (runner=worker, agent=opencode)
2026-05-26 06:22:02 +00:00