Commit Graph
163 Commits
Author SHA1 Message Date
Reynaldi ChernandoandClaude Opus 5.5 2b3bc5ebfd fix dynamic worker review findings
- a live app that fails to move stops the address change and removes the new address
- an app lookup that fails is an error, not "no app"
- moving an app writes the new record first and undoes it if Puter refuses
- an app whose record can't be saved is deleted again
- a recreated preview takes the old preview's app and keys
- republish copies keys before switching the live site
- renames of one site run one at a time
- the not-found hint matches the project's kind
- tools carry no Builder-only fields to the AI

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-11-11 10:03:07 +07:00
Reynaldi Chernando 06a315b0fd use dynamic workers 2026-11-11 10:03:07 +07:00
Reynaldi ChernandoandClaude Opus 5.5 5959cafeee improve loading messages (#136)
* improve loading messages

* analytics

* drop the running build on stop, and don't count send now as abandoned

stopActiveTurn clears the build right away, so a Stop or a closed tab while
Send now's message is still being set up no longer reports the replaced build
and its wait time. Send now itself reports nothing: the user is still
building, only something else.

Co-Authored-By: Claude Opus 5.5 <[email protected]>

---------

Co-authored-by: Claude Opus 5.5 <[email protected]>
2026-10-30 07:34:41 +07:00
Reynaldi ChernandoandClaude Opus 5.5 e5c2018fe9 add message queueing (#135)
* add message queueing

* fix message queue review findings

- a stopped turn that fails after the next one started shows no error card
- a message stopped during its upload always comes back to the box
- a clarify reply keeps queued messages in the draft
- a send clears only the files it sent from the tray
- a send takes its picked element when it starts
- test-pwa passes stop_svg

Co-Authored-By: Claude Opus 5.5 <[email protected]>

---------

Co-authored-by: Claude Opus 5.5 <[email protected]>
2026-10-29 20:03:36 +07:00
Reynaldi Chernando bceac05095 optimize pwa prompts (#132)
* optimize pwa prompts

* improve

* fixes
2026-10-29 19:02:31 +07:00
Reynaldi Chernando f245f1feb9 improve compaction analytics (#134) 2026-10-29 18:34:55 +07:00
Reynaldi ChernandoandClaude Opus 5.5 18123f776d various performance improvements (#131)
* various performance improvements

* address review on the performance improvements

- the checkpoint after a turn's last round saves it as finished, so a
  reload before the end-of-turn save lands doesn't offer Resume
- only earlier turns' SuggestNextSteps calls are left out of requests, so a
  call in this turn keeps its error and a resumed turn ends on a result
- the early preview clear starts only when a refresh is pending, not after
  a failed write or publish_site's own refresh
- fix the snapshot comment and the comment merged into CUT_OFF_TOOL_ERROR

Co-Authored-By: Claude Opus 5.5 <[email protected]>

---------

Co-authored-by: Claude Opus 5.5 <[email protected]>
2026-10-28 17:29:22 +07:00
Reynaldi ChernandoandClaude Opus 5.5 bfdf99fecb save the pending upgrade click so Upgrade Completed survives a reload (#130)
* save the pending upgrade click so Upgrade Completed survives a reload

The source of a free user's Upgrade click lived only in memory, so a reload
before the user came back (a phone discarding the tab while they paid, a
closed tab, a restarted app) lost both the Upgrade Completed event and the
"You're subscribed" dialog. The click is now saved per account in
localStorage for 24 hours and checked on page load, on focus and on return
to the tab, under a per-account Web Lock, the same way Upgrade After Limit
works.

Co-Authored-By: Claude Opus 5.5 <[email protected]>

* report how long after the click an upgrade completed

Upgrade Completed now carries since_click, bucketed <10m, 10-60m or 1-24h
like since_limit on Upgrade After Limit, from the time saved with the click.

Co-Authored-By: Claude Opus 5.5 <[email protected]>

* keep the clicking tab's upgrade in memory and wait for startup

Review fixes for the saved Upgrade click:

- The tab where the click happened keeps it in memory again, so it still
  turns paid and shows its success dialog (with Continue building) when
  another tab credited the saved click first. It isn't counted twice.
- When storage doesn't take the click, that copy is counted instead, as
  before this branch.
- Focus checks wait until startup has reopened the project from the link,
  so the success dialog never opens over the loading screen without that
  project's next step.

Co-Authored-By: Claude Opus 5.5 <[email protected]>

---------

Co-authored-by: Claude Opus 5.5 <[email protected]>
2026-10-28 16:12:19 +07:00
Reynaldi Chernando 9342cd2c03 put compaction in feature flag (#127)
* put compaction in feature flag

* review
2026-10-28 15:15:01 +07:00
Reynaldi Chernando 22dda44c5f improve benefits ui (#129) 2026-10-28 15:05:42 +07:00
Reynaldi Chernando 77ab5fb6d3 use puter upgrade url for general upgrade button (#128) 2026-10-28 14:53:24 +07:00
Nariman Jelveh 860a8fc685 look up a backend's worker and app side by side for its sender name
The two lookups ran one after the other for every backend on every
publish, duplicate and delete. They're independent, so they now go out
together, with the same meaning for every failure.
2026-10-27 12:33:49 -07:00
Nariman Jelveh ca8c5983ca don't promise publishing resets a live sender name it never touches
When going back to the default name reached the preview but not the live
backend, the note said publishing again would fix it. Publishing never
carries a default name over, so the live site kept the old name for good.
The note now says to call the tool again.
2026-10-27 12:32:26 -07:00
Nariman Jelveh 7aa5972105 stop telling users line breaks aren't allowed in a sender name
Line breaks are accepted and become spaces. The refusal fires only for @,
quotes, backslashes, angle brackets and other control characters, so it
now says that.
2026-10-27 12:32:06 -07:00
Nariman Jelveh 99f772130e report a too-long sender name's length the way the limit counts it
The refusal counted the raw input, but the check measures the name after
runs of whitespace collapse, so an 81-character name could be reported as
100 characters.
2026-10-27 12:31:51 -07:00
Nariman JelvehandClaude Opus 5.5 02b39144f5 let users set the email sender name from chat
Email a Builder backend sends with puter.email.sendTransactional is labelled
with the title of the worker's sandbox app, which starts out as its internal
name, so recipients saw "sandbox-<worker>" as the sender.

- New set_email_sender_name tool renames the worker's sandbox app (the
  preview's backend, and the live one when the site is published). Names the
  email service would mangle (@, quotes, over 78 chars) are refused.
- Publish copies a chosen name to the live backend; Duplicate copies it to the
  copy's backends; Delete, retiring a live backend, and a discarded duplicate
  put the default back first, since Puter reuses sandbox apps by name.
- A backend on its default name never triggers a rename or a warning, and a
  live name set by hand in the Dev Center is never overwritten.
- Prompt tells the AI to set a sender name whenever a worker sends email and
  to pass replyTo when recipients should be able to reply.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-27 12:07:13 -07:00
Reynaldi Chernando 0bc29c6a75 improve worker editing performance (#124)
* improve worker editing performance

* fixes
2026-10-28 00:07:17 +07:00
Reynaldi ChernandoandClaude Opus 5.5 c345d8f055 add compaction (#125)
* add compaction

* address compaction review

- Send the summary as the first block of the assistant turn after it, the
  shape Puter documents, instead of as a message of its own.
- Use a failed round's summary once anything follows it. It's complete, and
  skipping it paid for a second one. Only an entry with nothing after it is
  left out, so a request never ends on it.
- A Claude summary is plain text in Puter, so a project moved to GPT or Gemini
  gets it as a text message instead of the full history.
- Cut the history before copying it, and never change the stored history.
- Keep two summaries from one stream in order.
- A usage line with no input counts no longer resets the request size.
- Drop the unused turnUsage.lastInput.
- Replace the test for a chunk order Puter never sends (compaction after the
  usage line) with tests for the above.

Co-Authored-By: Claude Opus 5.5 <[email protected]>

---------

Co-authored-by: Claude Opus 5.5 <[email protected]>
2026-10-27 23:44:08 +07:00
Reynaldi Chernando c8a6438d8a improve applying changes performance (#122)
* improve applying changes performance

* suggested changes
2026-10-27 16:55:32 +07:00
Reynaldi Chernando 31a1077b9f add svg rendering (#119)
* add svg rendering

* fixes
2026-10-27 13:47:01 +07:00
Reynaldi ChernandoandClaude 437b4bc3f2 Fix usage-limit test regex for openLimitModal(this.upgradeUrl) (#120)
#118 changed the low-balance override to pass this.upgradeUrl to
openLimitModal, but the source check in test-usage-limit-unblock.mjs
still expected a no-argument call. The failing check made prebuild
(npm test) exit 1, blocking the build.


Claude-Session: https://claude.ai/code/session_01FWCxozU1v7Zb8DhLpKBQcd

Co-authored-by: Claude <[email protected]>
2026-10-27 11:56:53 +07:00
Reynaldi Chernando 1ca50e7a6b github integration (#117)
* github integration

* fixes
2026-10-23 22:24:38 +07:00
Nariman JelvehandClaude Opus 5.5 7f1a636333 Keep the chat composer above the iOS on-screen keyboard
On iOS the keyboard doesn't shrink the layout; Safari pans the visual
viewport to reveal the focused field. The composer sits at the bottom of a
fixed-height column, so it stayed visible only while that pan held, and
scrolling the conversation, the composer growing, or a streaming reply
could drop it behind the keyboard until it was dismissed and reopened.

While a field in the chat column has focus on a touch device at 1x zoom,
size the app to visualViewport.height and undo Safari's pan. Fields
elsewhere (dialogs, sidebar search, the preview iframe), desktop and
pinch-zoom are untouched.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-22 10:31:18 -07:00
Reynaldi ChernandoandClaude Opus 5.5 99ff20b6f6 ai selector feature (#98)
* ai selector feture

* address review on the ai selector

- run a reply's tool calls only once the reply has ended (its usage line or
  the end of the stream), never after a pause: a healthy reply can be silent
  while its next call is written, so running early let a stale call land
  after newer work
- simplify MCP schemas for GPT and Gemini only where a schema holds other
  schemas, so parameters named like keywords (definitions, $id, type) and
  example or default values are kept as they are
- Resume restores the last checklist of a batched reply, like the
  end-of-turn backstop

Co-Authored-By: Claude Opus 5.5 <[email protected]>

---------

Co-authored-by: Claude Opus 5.5 <[email protected]>
2026-10-22 16:31:25 +07:00
Reynaldi ChernandoandClaude Opus 5.5 2a7e0fafdc add code editor (#96)
* add code editor

* address code editor review

- keep text typed while saving before leaving, publishing or restoring
- keep a copied backend's hand-edit note and guard under its renamed file
- ask before leaving with edits to a file deleted elsewhere
- carry the guards of files moved before a move fails
- lift the overwrite guard only after a complete read in a live turn

Co-Authored-By: Claude Opus 5.5 <[email protected]>

* fixes

* remove copy

---------

Co-authored-by: Claude Opus 5.5 <[email protected]>
2026-10-20 18:14:16 +07:00
Nariman Jelveh 280b852934 fix the grid note when no version reached the project
It said "None of them could NOT be saved into the project", which tells the
model the opposite of what happened.
2026-10-19 22:33:10 -07:00
Nariman Jelveh 9dc7d1b8dd don't write a generated file into the project after the turn is stopped
The provider call can't be cancelled, so after Stop (or deleting or leaving
the project) a generation with save_to_project still copied its file into the
project when it arrived: possibly in the middle of a publish, or recreating
the folder of a project that had just been deleted. The file now stays in the
chat's media folder and the result says it was not saved into the project.
2026-10-19 22:32:05 -07:00
Nariman Jelveh 67cc5a1758 recount an image grid when a version fails while it is on screen
removeCard took a failed version's tile down but left the grid's count, so
four options with one failed were announced as "4 generated images" and
laid out differently from the same grid after a reload, and a lone image
left in a grid showed at half width. The grid is now recounted the way a
reopened chat shows it, and a single remaining image gets a full-size card.
2026-10-19 22:29:20 -07:00
Nariman Jelveh 728fcd21eb copy a duplicated chat's media only after its chat file is saved
The media folder was copied before the copy's chat file was written. When
that write failed, the cleanup removed the copied project files, workers and
site but not the media copy, which was left behind for good.
2026-10-19 22:24:38 -07:00
Nariman Jelveh b3bfc6ec9c keep the generated media when copying it into the project fails
A failed copy into the project (save_to_project) threw out of
runGeneration after the file was generated and saved: the card stayed on
"Generating image…" for good, no analytics event was sent, and the image
the user paid for was lost. Now the card shows it, and the note tells the
model the project file does not exist and how to copy it in.
2026-10-19 22:23:16 -07:00
Nariman Jelveh 70b08abb8f add image, video and audio generation
Port GenerateImage, GenerateVideo and GenerateSpeech from ../ai, with
their chat cards (js/media.js): pending card with a timer, image grid for
several versions, full-screen image viewer, Download / Open, and replay
of past generations when a chat is reopened.

- generated files live in a per-chat .media/<chatId> folder beside the
  project, so version snapshots and restores never touch them; deleting
  a chat removes it, duplicating a chat copies it
- save_to_project puts a file into the site (counts as a project change);
  copy and ViewImage can read from the chat's media folder
- system prompt: custom imagery for sites (max 4 images per turn), video
  only on explicit request, speech only (no music or sound effects)
- Plausible events: Image/Video/Audio Generated and ... Generation Failed,
  one per request, with the request's options and a failure reason;
  prompts and file names are never sent
- tests: generated-media (incl. analytics) plus ai's card, lightbox and
  read-URL tests; path-scoping and load-media-urls updated
2026-10-19 20:47:27 -07:00
Reynaldi ChernandoandClaude Opus 5.5 c6620dd891 better limit screen (#91)
* better limit screen

* limit screen: checklist card, builder animation, clearer wording

- steps shows the build's checklist instead of a bare progress bar
- no screenshot shows a looping chat-and-preview animation
- live address sits in an address bar over the screenshot, badge note gone
- "stopped partway" only when the turn did work, otherwise app/new
- every version has Not now and Upgrade

Co-Authored-By: Claude Opus 5.5 <[email protected]>

* limit screen: review fixes

- Upgrade saves the project the dialog opened for, not the one on screen
- Continue building re-checks the project before resuming
- checklist icons say Done / Not done to screen readers
- darker grey for unfinished steps (#666670, 5.3:1)

Co-Authored-By: Claude Opus 5.5 <[email protected]>

---------

Co-authored-by: Claude Opus 5.5 <[email protected]>
2026-10-19 18:18:04 +07:00
Reynaldi Chernando e8c8892966 show badge in preview (#94)
* show badge in preview

* fix
2026-10-17 16:11:59 +07:00
Reynaldi ChernandoandClaude Opus 5.5 593d5cdec1 usage limit analytics (#93)
* usage limit analytics

* Count calls and cost of earlier rounds when a later call fails

Puter sends a call's usage chunk last, after its tool_use, and the stream
runs the tool round (opening the next call) as soon as it reads the
tool_use. When a later call was refused, every earlier stream was still
parked in its tool round with its usage unread. So Usage Limit Hit
reported calls: 0 for every mid-build refusal, and the build's cost never
reached the chat's saved total, which made Project Published's cost_band
read low for projects with a cut-off build.

Each call is now counted at its first tool_use or its usage, and a parked
stream reads its remaining usage before unwinding, under one 1.5s deadline
per turn so a dead connection can't stall the unwind once per round.

Co-Authored-By: Claude Opus 5.5 <[email protected]>

---------

Co-authored-by: Claude Opus 5.5 <[email protected]>
2026-10-17 12:14:57 +07:00
Reynaldi Chernando bfe2019ad4 make badge toggleable (#92)
* make badge toggleable

* suggested changes
2026-10-16 19:49:04 +07:00
Reynaldi Chernando cf0e5a6ac2 improve usage analytics (#90)
* improve usage analytics

* suggested changes
2026-10-16 16:17:34 +07:00
Reynaldi Chernando 7137479a5a templates cleanup (#78) 2026-10-15 19:33:39 +07:00
Reynaldi ChernandoandClaude Opus 5.5 20940c6929 Add cost band to Project Published (#40)
* Add cost band to Project Published and Usage Limit Hit

Adds cost_band (dollar bands, finest under $1 where the free-credit
allowance is decided) and whole-cent cost_cents to Project Published,
and the same pair to Usage Limit Hit, so the spend of users blocked
before publishing can be compared with what a first publish costs.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01KuLWkaCG7cviLYZ1tkb7T8

* Drop cost from Usage Limit Hit; center cost bands on the $3 allowance

At a limit hit the project's cost is roughly the free allowance minus
spend elsewhere, so it adds nothing. Rebalance cost_band to be finest
between $1 and $5, around the current $3 allowance.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01KuLWkaCG7cviLYZ1tkb7T8

---------

Co-authored-by: Claude <[email protected]>
2026-10-14 19:47:43 +07:00
Reynaldi ChernandoandClaude Opus 5.5 4b54c26306 enable removal of puter badge for user with active plan (#39)
* enable removal of puter badge for user with active plan

* Address review: confirm project switch, tighter tag match, fresh plan check, skip card for stopped turns

Co-Authored-By: Claude Opus 5.5 <[email protected]>

---------

Co-authored-by: Claude Opus 5.5 <[email protected]>
2026-10-14 19:41:49 +07:00
Reynaldi ChernandoandClaude Opus 5.5 0167bfac1c Track project context on Usage Limit Hit (#37)
* Track project context on Usage Limit Hit

Adds published, any_published, builds_completed (counted from the chat
history) and projects to the Usage Limit Hit event, so limit hits can be
split by whether the user had a successful build, a published app, or
earlier projects.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01QBPTrbgLwvA1thzXcMauNS

* Widen announce test window for the longer Usage Limit Hit call

Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01QBPTrbgLwvA1thzXcMauNS

* Don't count version-restore notes as completed builds

A restore appends a plain assistant note to the chat; after a failed or
interrupted build it became that build's last reply and inflated
builds_completed. Flag the note (versionNote, stripped before the AI
call) and skip it, matching older unflagged notes by their text.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01QBPTrbgLwvA1thzXcMauNS

---------

Co-authored-by: Claude <[email protected]>
2026-10-14 19:20:38 +07:00
Reynaldi ChernandoandClaude Opus 5.5 05602f4575 Track token usage and first-publish flag on Project Published (#38)
* Track token usage and first-publish flag on Project Published

Adds the project's accumulated AI usage (input/output/cache tokens, a
total, a coarse band for dashboard grouping, and cost in cents) plus an
explicit first_publish boolean to the Project Published event.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01KuLWkaCG7cviLYZ1tkb7T8

* Test the Project Published analytics payload

The other publish tests don't load the usage helpers, so they only ever
exercise the fallback event. Drive the real doPublish with the helpers
loaded and check token totals, band, cost, first/republish flags, the
zero-usage band, the fallback, and tokenBand boundaries.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01KuLWkaCG7cviLYZ1tkb7T8

---------

Co-authored-by: Claude <[email protected]>
2026-10-14 19:20:01 +07:00
Reynaldi ChernandoandClaude Opus 5.5 3822c4ed35 twitter player card template (#23)
* twitter player card template

* fix player card setup chip and FAQ, test template instructions end to end

The setup chip and the FAQ still named a your-site.puter.site placeholder the
page no longer has, and the FAQ promised an address check that was removed.
Add a fork test that follows a template's instructions from template.js into
the new project's system prompt.

Co-Authored-By: Claude Opus 5.5 <[email protected]>

---------

Co-authored-by: Claude Opus 5.5 <[email protected]>
2026-10-10 00:28:49 +07:00
Nariman JelvehandReynaldi Chernando 40b8a0e523 Add official project templates (#12)
* Add official project templates: copy a finished app into your account

Templates are small, complete apps that ship with the builder
(src/templates/<slug>/). "Use this template" copies one into a new
project in the user's own account, where it is theirs to keep building on.

Where they appear:
- A "Start from a template" row under the landing hero (shares the
  community feed's grid and layout), opening a template dialog.
- A static page per template at /templates/<slug>/ and a /templates/ hub,
  rendered by the existing SEO page pipeline (sitemap, llms.txt, OG cards).
  "Use this template" signs the visitor in inside the click, parks the slug
  in the same-origin handoff store, and goes to /?template=<slug>&handoff=…,
  where the app copies it without asking again. A bare /?template= link
  only opens the dialog.

The fork is an ordinary project:
- files are written into a fresh app directory, with its own draft preview;
- each worker a template ships is deployed under a fresh account-unique
  name from <appDir>/workers/<name>.js, so the project owns it (deleting the
  project deletes it); the frontend refers to it only as {{WORKER_URL:name}},
  replaced with the deployed URL;
- the system prompt carries a note that the app already exists (file list,
  preview, backend by path and URL, so Make a copy rewrites it correctly);
- it opens with the template's suggestion chips, a "Started from" note, and
  a version-history restore point.
Any failure removes everything it created, workers first.

The build validates every template (layout, placeholders, the app's own
index validator) and ships /templates.json plus versioned files under
/template-files/<slug>/<version>/. Behind FEATURE_FLAGS.templates.

Ships three templates: Feedback Board (with a serverless backend),
AI Chat Assistant, and Product Landing Page.

* Reject protocol-relative thumbnail paths in the template index

The index validator accepted //host/x.png as a same-origin path, which the
landing card would then load from another host.

* Decode template dev paths only once they are ours

The templates dev middleware decoded every request path before checking its
prefix, so a malformed escape anywhere threw from our code. It now decodes
only its own paths and answers a malformed one with 400.

* Hide the landing sections under the project loading overlay

body.project-loading hides the landing hero so nothing ghosts through the
overlay's fade-in, but not the rows below it, so the templates row (and the
community feed) showed through while a deep-linked project was opening.

* Keep the space after a template chip prompt that ends in a colon

Chips like "...match my brand: " put their prompt in the composer as is,
for the user to finish. The index sanitizer trimmed the trailing space, so
the first word typed ran into the colon.

* Use a div for the templates hub card body

It holds the card's heading and paragraph, which a span may not contain.
Rendering is unchanged (the element was already display: block).

* Make the landing template cards links to their pages

The cards were buttons wrapping block elements (not allowed in a button),
and could not be opened in a new tab or copied. Each is now a link to
/templates/<slug>/: a plain click still opens the template dialog, while
modified and middle clicks keep their usual link behaviour.

* Re-enable Use this template when Back restores the page

Back from the app restores the template page from the back/forward cache
mid hand-over, so both buttons stayed dimmed and ignored every click. The
page now clears its busy state on a persisted pageshow.

* performance improvements

* suggested changes

---------

Co-authored-by: Reynaldi Chernando <[email protected]>
2026-10-08 20:07:54 +07:00
Reynaldi Chernando 02639d0a18 Update analytics (#21)
* Update analytics

* suggested change
2026-10-08 15:04:02 +07:00
jelveh ea3539b2aa Fix Claude strict tool limit for chat requests 2026-10-07 08:03:48 -07:00
Reynaldi Chernando 3914a41db1 add open source landing page (#17)
* add open source landing page

* refine
2026-10-07 18:18:46 +07:00
Nariman JelvehandClaude Fable 5.1 66b37898f2 Keep the Publish button busy when returning to a publishing project
A publish runs for several seconds and its progress note invites the user
to keep building meanwhile, so switching to another project and back
mid-publish is ordinary use. refreshPublishButton bailed outright while a
publish of the open project was running — right while the user stayed put
(setPublishBusy had painted the button), wrong when they came back: the
button kept the label and state painted for the project visited in
between ("Published" on a never-published project), enabled, until the
publish finished. It now paints this project's own state and holds the
button disabled as "Publishing…", and still leaves the popover alone.

Co-Authored-By: Claude Fable 5.1 <[email protected]>
2026-10-05 15:43:31 -07:00
Nariman JelvehandClaude Fable 5.1 96cdeb07e1 Hand an abandoned send's text back even after a history repair
A composer send abandoned before its message reached the conversation
(Stop while the attachments were still uploading) hands the text back to
the composer, since the send had already cleared it and tombstoned its
draft. Whether the message had reached the conversation was judged by the
history having grown past the turn's start — but repairDanglingToolUses
also appends to it, synthesising results for a build that was cut off
mid-tool. In such a project (a common state: refresh mid-build, then type
the next instruction) an abandoned send counted as "in the conversation":
the hand-back was skipped, the text was gone, and Resume re-sent the
repaired old history instead. A flag set where the message is pushed now
decides it.

Co-Authored-By: Claude Fable 5.1 <[email protected]>
2026-10-05 15:42:02 -07:00
Nariman JelvehandClaude Fable 5.1 e80306ea50 Don't read a press inside a Puter dialog as a press outside a panel
puter.ui.alert / prompt, the context menu and the pickers are custom
elements appended to <body>, outside every panel of ours, and the buttons
in their shadow roots don't stop their clicks: a press on OK / Yes / No
bubbles to document with the dialog host as its target. Every "click
outside closes" handler read that as a click outside and closed the
surface the dialog had been raised FROM — a failed publish's alert closed
the publish popover and dropped the typed address it had just promised to
keep (the next open showed a fresh random name); an invalid address in the
Settings dialog collapsed the sidebar under it, so the dialog's focus
return landed on nothing; answering "No" to leaving a running project
closed the project list the user was browsing. The delete flow alone was
guarded against this, with its own flag.

One predicate, isInPuterDialog, now covers every outside-press closer: the
publish, share, device, issues and versions popovers, the projects sidebar,
the account panel and the overflow menu.

Co-Authored-By: Claude Fable 5.1 <[email protected]>
2026-10-05 15:39:32 -07:00
Nariman JelvehandClaude Fable 5.1 e05e3371ab Read a <meta> content value that contains ">" whole
metaContent located the tag with a pattern that stopped at the first ">",
including one inside a quoted attribute value, so a description like
content="a > b" came back empty and the manifest shipped without one.
The tag now runs to the first ">" outside a quoted value.

Co-Authored-By: Claude Fable 5.1 <[email protected]>
2026-10-05 15:34:44 -07:00