@bastani/atomic 0.9.39-alpha.2 → 0.9.40-alpha.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (261) hide show
  1. package/CHANGELOG.md +42 -0
  2. package/dist/builtin/intercom/CHANGELOG.md +20 -0
  3. package/dist/builtin/intercom/broker/broker.ts +523 -72
  4. package/dist/builtin/intercom/broker/client.ts +136 -5
  5. package/dist/builtin/intercom/broker/database-wake-up-bus.ts +274 -0
  6. package/dist/builtin/intercom/broker/group-membership.ts +2 -2
  7. package/dist/builtin/intercom/broker/multinode-router.ts +1500 -0
  8. package/dist/builtin/intercom/broker/multinode-state-store.ts +569 -0
  9. package/dist/builtin/intercom/broker/open-broker-state.ts +160 -0
  10. package/dist/builtin/intercom/broker/paths.ts +6 -0
  11. package/dist/builtin/intercom/broker/pending-send-registry.ts +14 -0
  12. package/dist/builtin/intercom/broker/recipient-receipts.ts +93 -0
  13. package/dist/builtin/intercom/broker/restoring-recipients.ts +263 -0
  14. package/dist/builtin/intercom/broker/send-handler.ts +241 -25
  15. package/dist/builtin/intercom/broker/session-id-reclaim.ts +41 -0
  16. package/dist/builtin/intercom/broker/socket-writes.ts +47 -0
  17. package/dist/builtin/intercom/broker/spawn.ts +10 -2
  18. package/dist/builtin/intercom/broker/sql-held-send-store.ts +96 -0
  19. package/dist/builtin/intercom/broker/sql-known-session-store.ts +129 -0
  20. package/dist/builtin/intercom/broker/sql-lease-store.ts +194 -0
  21. package/dist/builtin/intercom/broker/sql-outbox-store.ts +249 -0
  22. package/dist/builtin/intercom/broker/sql-pending-ask-store.ts +105 -0
  23. package/dist/builtin/intercom/broker/sql-restoring-reservation-store.ts +295 -0
  24. package/dist/builtin/intercom/broker/sql-sent-message-authority.ts +126 -0
  25. package/dist/builtin/intercom/broker/supervisor-channel.ts +10 -0
  26. package/dist/builtin/intercom/broker/wake-up-bus.ts +60 -0
  27. package/dist/builtin/intercom/index.bundle.mjs +793 -91
  28. package/dist/builtin/intercom/package.json +1 -1
  29. package/dist/builtin/intercom/retry-policy.ts +4 -0
  30. package/dist/builtin/intercom/session-target.ts +24 -0
  31. package/dist/builtin/intercom/types.ts +57 -3
  32. package/dist/builtin/mcp/package.json +1 -1
  33. package/dist/builtin/subagents/CHANGELOG.md +37 -0
  34. package/dist/builtin/subagents/README.md +18 -12
  35. package/dist/builtin/subagents/package.json +1 -1
  36. package/dist/builtin/subagents/skills/agent-browser/SKILL.md +1 -1
  37. package/dist/builtin/subagents/skills/cua-driver/BROWSER.md +55 -8
  38. package/dist/builtin/subagents/skills/cua-driver/EMBEDDING.md +7 -2
  39. package/dist/builtin/subagents/skills/cua-driver/LINUX.md +7 -1
  40. package/dist/builtin/subagents/skills/cua-driver/MACOS.md +151 -27
  41. package/dist/builtin/subagents/skills/cua-driver/RUNTIME.md +1 -1
  42. package/dist/builtin/subagents/skills/cua-driver/SKILL.md +33 -17
  43. package/dist/builtin/subagents/skills/cua-driver/WINDOWS.md +5 -0
  44. package/dist/builtin/subagents/skills/cua-driver/WORKFLOW.md +46 -8
  45. package/dist/builtin/subagents/skills/subagent/SKILL.md +18 -20
  46. package/dist/builtin/subagents/src/extension/index.bundle.mjs +8032 -6034
  47. package/dist/builtin/web-access/package.json +1 -1
  48. package/dist/builtin/workflows/CHANGELOG.md +32 -0
  49. package/dist/builtin/workflows/README.md +1 -1
  50. package/dist/builtin/workflows/package.json +1 -1
  51. package/dist/builtin/workflows/skills/impeccable/SKILL.md +8 -8
  52. package/dist/builtin/workflows/skills/impeccable/reference/adapt.md +3 -3
  53. package/dist/builtin/workflows/skills/impeccable/reference/adapt.native.md +1 -1
  54. package/dist/builtin/workflows/skills/impeccable/reference/audit.md +4 -2
  55. package/dist/builtin/workflows/skills/impeccable/reference/audit.native.md +2 -2
  56. package/dist/builtin/workflows/skills/impeccable/reference/craft-floor.md +1 -1
  57. package/dist/builtin/workflows/skills/impeccable/reference/critique.md +22 -9
  58. package/dist/builtin/workflows/skills/impeccable/reference/degraded/finish-reviewer.md +2 -2
  59. package/dist/builtin/workflows/skills/impeccable/reference/distill.md +3 -3
  60. package/dist/builtin/workflows/skills/impeccable/reference/extract.md +3 -3
  61. package/dist/builtin/workflows/skills/impeccable/reference/harden.md +2 -4
  62. package/dist/builtin/workflows/skills/impeccable/reference/hooks.md +4 -4
  63. package/dist/builtin/workflows/skills/impeccable/reference/live.md +1 -1
  64. package/dist/builtin/workflows/skills/impeccable/reference/new-work.md +6 -6
  65. package/dist/builtin/workflows/skills/impeccable/reference/onboard.md +3 -3
  66. package/dist/builtin/workflows/skills/impeccable/reference/optimize.md +3 -3
  67. package/dist/builtin/workflows/skills/impeccable/reference/overdrive.md +3 -3
  68. package/dist/builtin/workflows/skills/impeccable/reference/quieter.md +3 -3
  69. package/dist/builtin/workflows/skills/impeccable/reference/typeset.md +10 -0
  70. package/dist/builtin/workflows/skills/impeccable/reference/visualize.md +1 -1
  71. package/dist/builtin/workflows/skills/impeccable/scripts/VERSION +1 -1
  72. package/dist/builtin/workflows/skills/impeccable/scripts/impeccable +6 -0
  73. package/dist/builtin/workflows/skills/impeccable/scripts/impeccable.cmd +47 -22
  74. package/dist/builtin/workflows/skills/impeccable/scripts/live-browser-dom.js +34 -1
  75. package/dist/builtin/workflows/skills/impeccable/scripts/live-browser-session.js +25 -1
  76. package/dist/builtin/workflows/skills/impeccable/scripts/live-browser.js +33 -8
  77. package/dist/builtin/workflows/src/durable/journal/resolution.d.ts +7 -7
  78. package/dist/builtin/workflows/src/extension/index.bundle.mjs +22855 -22308
  79. package/dist/builtin/workflows/src/index.js +106 -35
  80. package/dist/cli/args.d.ts +2 -0
  81. package/dist/cli/args.d.ts.map +1 -1
  82. package/dist/cli/args.js +16 -0
  83. package/dist/cli/args.js.map +1 -1
  84. package/dist/core/agent-session-extension-bindings.d.ts +2 -0
  85. package/dist/core/agent-session-extension-bindings.d.ts.map +1 -1
  86. package/dist/core/agent-session-extension-bindings.js +6 -6
  87. package/dist/core/agent-session-extension-bindings.js.map +1 -1
  88. package/dist/core/agent-session-methods.d.ts +6 -3
  89. package/dist/core/agent-session-methods.d.ts.map +1 -1
  90. package/dist/core/agent-session-methods.js.map +1 -1
  91. package/dist/core/agent-session-persistent-custom-messages.d.ts +7 -2
  92. package/dist/core/agent-session-persistent-custom-messages.d.ts.map +1 -1
  93. package/dist/core/agent-session-persistent-custom-messages.js +29 -12
  94. package/dist/core/agent-session-persistent-custom-messages.js.map +1 -1
  95. package/dist/core/agent-session-recovery.d.ts +14 -0
  96. package/dist/core/agent-session-recovery.d.ts.map +1 -0
  97. package/dist/core/agent-session-recovery.js +83 -0
  98. package/dist/core/agent-session-recovery.js.map +1 -0
  99. package/dist/core/agent-session-tasks.d.ts.map +1 -1
  100. package/dist/core/agent-session-tasks.js +4 -6
  101. package/dist/core/agent-session-tasks.js.map +1 -1
  102. package/dist/core/agent-session-types.d.ts +13 -0
  103. package/dist/core/agent-session-types.d.ts.map +1 -1
  104. package/dist/core/agent-session-types.js.map +1 -1
  105. package/dist/core/agent-session.d.ts +2 -1
  106. package/dist/core/agent-session.d.ts.map +1 -1
  107. package/dist/core/agent-session.js +4 -1
  108. package/dist/core/agent-session.js.map +1 -1
  109. package/dist/core/extensions/api-types.d.ts +6 -2
  110. package/dist/core/extensions/api-types.d.ts.map +1 -1
  111. package/dist/core/extensions/api-types.js.map +1 -1
  112. package/dist/core/extensions/event-results.d.ts +21 -0
  113. package/dist/core/extensions/event-results.d.ts.map +1 -1
  114. package/dist/core/extensions/event-results.js.map +1 -1
  115. package/dist/core/extensions/index.d.ts +1 -1
  116. package/dist/core/extensions/index.d.ts.map +1 -1
  117. package/dist/core/extensions/index.js.map +1 -1
  118. package/dist/core/extensions/loader-api.d.ts.map +1 -1
  119. package/dist/core/extensions/loader-api.js +4 -0
  120. package/dist/core/extensions/loader-api.js.map +1 -1
  121. package/dist/core/extensions/runner-events.d.ts +9 -2
  122. package/dist/core/extensions/runner-events.d.ts.map +1 -1
  123. package/dist/core/extensions/runner-events.js +29 -0
  124. package/dist/core/extensions/runner-events.js.map +1 -1
  125. package/dist/core/extensions/runner.d.ts +5 -3
  126. package/dist/core/extensions/runner.d.ts.map +1 -1
  127. package/dist/core/extensions/runner.js +7 -2
  128. package/dist/core/extensions/runner.js.map +1 -1
  129. package/dist/core/extensions/runtime-types.d.ts +1 -0
  130. package/dist/core/extensions/runtime-types.d.ts.map +1 -1
  131. package/dist/core/extensions/runtime-types.js.map +1 -1
  132. package/dist/core/extensions/session-events.d.ts +30 -2
  133. package/dist/core/extensions/session-events.d.ts.map +1 -1
  134. package/dist/core/extensions/session-events.js.map +1 -1
  135. package/dist/core/sdk-types.d.ts +3 -2
  136. package/dist/core/sdk-types.d.ts.map +1 -1
  137. package/dist/core/sdk-types.js.map +1 -1
  138. package/dist/core/sdk.d.ts.map +1 -1
  139. package/dist/core/sdk.js +3 -0
  140. package/dist/core/sdk.js.map +1 -1
  141. package/dist/core/session-storage.d.ts.map +1 -1
  142. package/dist/core/session-storage.js +15 -9
  143. package/dist/core/session-storage.js.map +1 -1
  144. package/dist/core/storage/process-selection.d.ts +39 -0
  145. package/dist/core/storage/process-selection.d.ts.map +1 -0
  146. package/dist/core/storage/process-selection.js +154 -0
  147. package/dist/core/storage/process-selection.js.map +1 -0
  148. package/dist/core/storage/provider.d.ts +6 -1
  149. package/dist/core/storage/provider.d.ts.map +1 -1
  150. package/dist/core/storage/provider.js +3 -2
  151. package/dist/core/storage/provider.js.map +1 -1
  152. package/dist/core/storage/selection.d.ts +1 -1
  153. package/dist/core/storage/selection.d.ts.map +1 -1
  154. package/dist/core/storage/selection.js.map +1 -1
  155. package/dist/core/storage/session/jsonl-session-store.d.ts +2 -0
  156. package/dist/core/storage/session/jsonl-session-store.d.ts.map +1 -1
  157. package/dist/core/storage/session/jsonl-session-store.js +38 -2
  158. package/dist/core/storage/session/jsonl-session-store.js.map +1 -1
  159. package/dist/core/tasks/completion.d.ts +11 -2
  160. package/dist/core/tasks/completion.d.ts.map +1 -1
  161. package/dist/core/tasks/completion.js +40 -16
  162. package/dist/core/tasks/completion.js.map +1 -1
  163. package/dist/core/tasks/pause.d.ts +4 -1
  164. package/dist/core/tasks/pause.d.ts.map +1 -1
  165. package/dist/core/tasks/pause.js +8 -5
  166. package/dist/core/tasks/pause.js.map +1 -1
  167. package/dist/index-extensions.d.ts +1 -1
  168. package/dist/index-extensions.d.ts.map +1 -1
  169. package/dist/index-extensions.js.map +1 -1
  170. package/dist/index.d.ts +2 -1
  171. package/dist/index.d.ts.map +1 -1
  172. package/dist/index.js +2 -0
  173. package/dist/index.js.map +1 -1
  174. package/dist/main.d.ts.map +1 -1
  175. package/dist/main.js +7 -1
  176. package/dist/main.js.map +1 -1
  177. package/dist/modes/interactive/components/chat-session-host-rendering.d.ts.map +1 -1
  178. package/dist/modes/interactive/components/chat-session-host-rendering.js +11 -1
  179. package/dist/modes/interactive/components/chat-session-host-rendering.js.map +1 -1
  180. package/dist/modes/interactive/components/chat-session-host-state.d.ts +2 -0
  181. package/dist/modes/interactive/components/chat-session-host-state.d.ts.map +1 -1
  182. package/dist/modes/interactive/components/chat-session-host-state.js +2 -0
  183. package/dist/modes/interactive/components/chat-session-host-state.js.map +1 -1
  184. package/dist/modes/interactive/interactive-deferred-startup.d.ts.map +1 -1
  185. package/dist/modes/interactive/interactive-deferred-startup.js +4 -0
  186. package/dist/modes/interactive/interactive-deferred-startup.js.map +1 -1
  187. package/dist/modes/interactive/interactive-mode-surface.d.ts +2 -1
  188. package/dist/modes/interactive/interactive-mode-surface.d.ts.map +1 -1
  189. package/dist/modes/interactive/interactive-mode-surface.js.map +1 -1
  190. package/dist/modes/interactive/interactive-render-chat.js +3 -0
  191. package/dist/modes/interactive/interactive-render-chat.js.map +1 -1
  192. package/dist/modes/interactive/interactive-session-routing.js +2 -0
  193. package/dist/modes/interactive/interactive-session-routing.js.map +1 -1
  194. package/dist/modes/interactive/interactive-session-runtime.d.ts +2 -1
  195. package/dist/modes/interactive/interactive-session-runtime.d.ts.map +1 -1
  196. package/dist/modes/interactive/interactive-session-runtime.js +29 -0
  197. package/dist/modes/interactive/interactive-session-runtime.js.map +1 -1
  198. package/dist/modes/interactive/interactive-startup.d.ts.map +1 -1
  199. package/dist/modes/interactive/interactive-startup.js +4 -1
  200. package/dist/modes/interactive/interactive-startup.js.map +1 -1
  201. package/dist/modes/interactive-engine/engine-args.d.ts.map +1 -1
  202. package/dist/modes/interactive-engine/engine-args.js +4 -0
  203. package/dist/modes/interactive-engine/engine-args.js.map +1 -1
  204. package/dist/modes/interactive-engine/engine-render-service.d.ts.map +1 -1
  205. package/dist/modes/interactive-engine/engine-render-service.js +4 -4
  206. package/dist/modes/interactive-engine/engine-render-service.js.map +1 -1
  207. package/dist/modes/interactive-engine/isolated-runtime.d.ts.map +1 -1
  208. package/dist/modes/interactive-engine/isolated-runtime.js +4 -0
  209. package/dist/modes/interactive-engine/isolated-runtime.js.map +1 -1
  210. package/dist/modes/interactive-engine/remote-renderer.js +1 -1
  211. package/dist/modes/interactive-engine/remote-renderer.js.map +1 -1
  212. package/dist/modes/rpc/rpc-client-api.d.ts +4 -1
  213. package/dist/modes/rpc/rpc-client-api.d.ts.map +1 -1
  214. package/dist/modes/rpc/rpc-client-api.js +4 -0
  215. package/dist/modes/rpc/rpc-client-api.js.map +1 -1
  216. package/dist/modes/rpc/rpc-command-handler.d.ts.map +1 -1
  217. package/dist/modes/rpc/rpc-command-handler.js +3 -0
  218. package/dist/modes/rpc/rpc-command-handler.js.map +1 -1
  219. package/dist/modes/rpc/rpc-command-timeouts.d.ts.map +1 -1
  220. package/dist/modes/rpc/rpc-command-timeouts.js +1 -0
  221. package/dist/modes/rpc/rpc-command-timeouts.js.map +1 -1
  222. package/dist/modes/rpc/rpc-input-scheduler.d.ts.map +1 -1
  223. package/dist/modes/rpc/rpc-input-scheduler.js +6 -1
  224. package/dist/modes/rpc/rpc-input-scheduler.js.map +1 -1
  225. package/dist/modes/rpc/rpc-types.d.ts +12 -1
  226. package/dist/modes/rpc/rpc-types.d.ts.map +1 -1
  227. package/dist/modes/rpc/rpc-types.js.map +1 -1
  228. package/dist/utils/shell.d.ts.map +1 -1
  229. package/dist/utils/shell.js +44 -11
  230. package/dist/utils/shell.js.map +1 -1
  231. package/dist/utils/tools-manager.js +1 -1
  232. package/dist/utils/tools-manager.js.map +1 -1
  233. package/docs/background-tasks.md +5 -3
  234. package/docs/computer-use.md +2 -2
  235. package/docs/environment-variables.md +4 -1
  236. package/docs/extensions/events.md +29 -2
  237. package/docs/getting-started/first-session.md +1 -1
  238. package/docs/guides/intercom.md +1 -1
  239. package/docs/intercom/operations.md +103 -1
  240. package/docs/intercom/reference.md +10 -3
  241. package/docs/intercom.md +8 -6
  242. package/docs/keybindings.md +1 -1
  243. package/docs/models.md +1 -1
  244. package/docs/providers.md +4 -2
  245. package/docs/reference/cli.md +5 -0
  246. package/docs/rpc/protocol.md +19 -0
  247. package/docs/rpc.md +3 -0
  248. package/docs/sdk/web-server.md +1 -1
  249. package/docs/sdk.md +5 -2
  250. package/docs/sessions.md +17 -1
  251. package/docs/settings.md +5 -3
  252. package/docs/skills.md +1 -1
  253. package/docs/storage.md +54 -3
  254. package/docs/subagents.md +49 -9
  255. package/docs/usage.md +1 -1
  256. package/docs/windows.md +14 -4
  257. package/docs/workflows/api-reference.md +1 -1
  258. package/docs/workflows/authoring.md +1 -1
  259. package/docs/workflows/operations.md +10 -6
  260. package/npm-shrinkwrap.json +37 -37
  261. package/package.json +4 -4
@@ -23,7 +23,7 @@ Understand what users need to learn and why:
23
23
  - What's the key action we want them to take? (First project? First invite?)
24
24
  - How do we know onboarding worked? (Completion rate? Time to value?)
25
25
 
26
- **CRITICAL**: Onboarding should get users to value as quickly as possible, not teach everything possible.
26
+ Onboarding should get users to value as quickly as possible, not teach everything possible.
27
27
 
28
28
  ## Onboarding Principles
29
29
 
@@ -208,9 +208,9 @@ localStorage.setItem('onboarding-completed', 'true');
208
208
  localStorage.setItem('feature-tooltip-seen-reports', 'true');
209
209
  ```
210
210
 
211
- **IMPORTANT**: Don't show same onboarding twice (annoying). Track completion and respect dismissals.
211
+ Show onboarding once: track completion and respect dismissals.
212
212
 
213
- **NEVER**:
213
+ **Avoid**:
214
214
  - Force users through long onboarding before they can use product
215
215
  - Patronize users with obvious explanations
216
216
  - Show same tooltip repeatedly (respect dismissals)
@@ -17,7 +17,7 @@ Understand current performance and identify problems:
17
17
  - How bad is it? (Perceivable? Annoying? Blocking?)
18
18
  - Who's affected? (All users? Mobile only? Slow connections?)
19
19
 
20
- **CRITICAL**: Measure before and after. Premature optimization wastes time. Optimize what actually matters.
20
+ Measure before and after. Optimizing without a measurement spends effort on things that do not matter.
21
21
 
22
22
  ## Optimization Strategy
23
23
 
@@ -233,9 +233,9 @@ const observer = new IntersectionObserver((entries) => {
233
233
  - Bundle size
234
234
  - Request count
235
235
 
236
- **IMPORTANT**: Measure on real devices with real network conditions. Desktop Chrome with fast connection isn't representative.
236
+ Measure on real devices with real network conditions. Desktop Chrome on a fast connection isn't representative.
237
237
 
238
- **NEVER**:
238
+ **Avoid**:
239
239
  - Optimize without measuring (premature optimization)
240
240
  - Sacrifice accessibility for performance
241
241
  - Break functionality while optimizing
@@ -7,7 +7,7 @@ Start your response with:
7
7
 
8
8
  Push an interface past conventional limits. This isn't just about visual effects. It's about using the full power of the browser to make any part of an interface feel extraordinary: a table that handles a million rows, a dialog that morphs from its trigger, a form that validates in real-time with streaming feedback, a page transition that feels cinematic.
9
9
 
10
- **EXTRA IMPORTANT FOR THIS COMMAND**: Context determines what "extraordinary" means. A particle system on a creative portfolio is impressive. The same particle system on a settings page is embarrassing. But a settings page with instant optimistic saves and animated state transitions? That's extraordinary too. Understand the project's personality and goals before deciding what's appropriate.
10
+ Context decides what "extraordinary" means. A particle system on a creative portfolio is impressive. The same particle system on a settings page is embarrassing. But a settings page with instant optimistic saves and animated state transitions? That's extraordinary too. Understand the project's personality and goals before deciding what's appropriate.
11
11
 
12
12
  ### Propose Before Building
13
13
 
@@ -19,9 +19,9 @@ This command has the highest potential to misfire. Do NOT jump straight into imp
19
19
 
20
20
  Skipping this step risks building something embarrassing that needs to be thrown away.
21
21
 
22
- ### Iterate with Browser Automation
22
+ ### Verify in the Browser
23
23
 
24
- Technically ambitious effects almost never work on the first try. You MUST actively use browser automation tools to preview your work, visually verify the result, and iterate. Do not assume the effect looks right, check it. Expect multiple rounds of refinement. The gap between "technically works" and "looks extraordinary" is closed through visual iteration, not code alone.
24
+ Ambitious effects rarely work on the first try, so verify them in the browser rather than from code: an effect that technically runs can still stutter, ease wrong, or land on the wrong frame. Aim the checks at timing, easing, and smoothness, batch the fixes between looks, and keep refining until the effect is extraordinary.
25
25
 
26
26
  ---
27
27
 
@@ -30,7 +30,7 @@ Analyze what makes the design feel too intense:
30
30
 
31
31
  If any of these are unclear from the codebase, do not guess. Ask the user directly to clarify what you cannot infer.
32
32
 
33
- **CRITICAL**: "Quieter" doesn't mean boring or generic. It means refined and easier on the eyes. Think luxury, not laziness.
33
+ "Quieter" means refined and easier on the eyes, not generic. Generic quiet looks like gray text on white, one sans at a uniform weight, and a grid of identical cards; restraint still needs a point of view.
34
34
 
35
35
  ## Plan Refinement
36
36
 
@@ -41,7 +41,7 @@ Create a strategy to reduce intensity while maintaining impact:
41
41
  - **Simplification approach**: What can be removed entirely?
42
42
  - **Sophistication approach**: How can we signal quality through restraint?
43
43
 
44
- **IMPORTANT**: Subtlety requires precision. Quiet without intent collapses to generic.
44
+ Subtlety requires precision. Quiet without intent collapses to generic.
45
45
 
46
46
  ## Refine the Design
47
47
 
@@ -80,7 +80,7 @@ Systematically reduce intensity across these dimensions:
80
80
  - **Align to grid**: Bring rogue elements back into systematic alignment
81
81
  - **Even out spacing**: Replace extreme spacing variations with consistent rhythm
82
82
 
83
- **NEVER**:
83
+ **Avoid**:
84
84
  - Make everything the same size/weight (hierarchy still matters)
85
85
  - Remove all color (quiet ≠ grayscale)
86
86
  - Eliminate all personality (maintain character through refinement)
@@ -56,6 +56,16 @@ Use the fewest roles and families that make the hierarchy unmistakable. Combine
56
56
 
57
57
  Do not make type decorative at the expense of comprehension, or introduce a second family without a clear role it alone can perform.
58
58
 
59
+ ## Line breaks
60
+
61
+ After Matthew Butterick's *Practical Typography*, paraphrased; where his numbers differ from these, these stand.
62
+
63
+ - Set `text-wrap: balance` on headings and short centered blocks, and `text-wrap: pretty` on body copy. Both are progressive: a browser that ignores them keeps its default wrap.
64
+ - `pretty` pulls a word down beside a lone last word. It does not fill the last line, and a two-word tail is fine.
65
+ - In a column too narrow for either to help, edit the copy or widen the column.
66
+ - Break a heading by hand only between phrases, and check the break at every width the heading renders at. A hard break that lands mid-line on a phone is worse than the default wrap.
67
+ - An uneven break can carry meaning: a headline that lands on one word for weight, a poster line, a pull quote. Make it deliberate with a hard break or a wrap set on that element, and keep it rare. The detector's `straggler` and `unbalanced-heading` findings are advisory for this reason; say which breaks are intended.
68
+
59
69
  ## Verify
60
70
 
61
71
  - Primary, secondary, body, and metadata roles are recognizable without reading the copy.
@@ -6,7 +6,7 @@ A probe tests composition, narrative, hierarchy, density, focal moment, signatur
6
6
 
7
7
  ## Generate three compositional options
8
8
 
9
- The comp round runs inside the build's phase state: `impeccable build-phase start --direction <seed key>` has already run (with `--decision-comp <path>` when the chosen card has a decision comp) and its `comps` phase is open before the first comp is generated; a comp rendered before that sits outside the state, and a session resumed from that point has no phases to follow. `impeccable generate-image` refuses to write under `.impeccable/mocks/` until start has run; a harness-native image tool is bound by the same order.
9
+ The comp round runs inside the build's phase state: `impeccable build-phase start --direction <seed reference>` has already run (with `--decision-comp <path>` when the chosen card has a decision comp) and its `comps` phase is open before the first comp is generated; a comp rendered before that sits outside the state, and a session resumed from that point has no phases to follow. `impeccable generate-image` refuses to write under `.impeccable/mocks/` until start has run; a harness-native image tool is bound by the same order.
10
10
 
11
11
  Render three distinct high-fidelity north-star comps of the requested surface, saved under `.impeccable/mocks/` so they survive the session. When the chosen card has a decision comp, it is option one: it stays at its path under `.impeccable/mocks/decision/`, where the gate counts it through `--decision-comp`, and is never regenerated; render the other two. Comp at the surface's own viewport: portrait at device size for a native app or mobile-first surface, desktop landscape otherwise; a phone screen comped landscape misstates the composition before anything is built against it. Comps are the build thread's own work, never delegated: the thread that writes the prompts holds the direction's full context and has seen every comp when the build starts. Open every image by its workspace-relative path; sandboxed viewers reject absolute paths, and everything under the project root has a relative one. Base the comps on real content and the surface concepts already developed with the user. On an established world, anchor every comp on the real identity: capture a screenshot of a representative existing page and pass it as a reference image (the harness image tool's input image, or `impeccable generate-image --ref`); the prompt leads with the new surface's structure while the reference carries palette, type, and component character, because DESIGN.md words alone drift where a pixel reference does not. Name what the reference contributes and what it must not: chrome, palette, type, and component character carry over; the reference page's own content does not, and a banner, hero, or card lifted verbatim is the reference leaking, not fidelity. Three is the number: one comp invites rubber-stamping; the spread between three surfaces the composition worth building. The chosen card's decision comp is the first of the three: it already renders this direction at full fidelity under this discipline, so generate two more that vary what the first held fixed, from the direction in words rather than with the first comp as an input image (a reference image anchors the layout, and three comps collapse into one composition). How comps two and three vary from the first is the mode's call, in its COMPS rules. A variant that simplifies the first into a tidier version of itself adds no choice to the round. Send all three to the approval point together. Only a round arriving with no decision comp (a degraded roll, an identity-mode page, a direction pinned without the decision round) renders all three here.
12
12
 
@@ -1 +1 @@
1
- 0.1.14
1
+ 0.1.16
@@ -130,6 +130,12 @@ if [ -n "$version" ] && [ "$os" != unknown ] && [ "$arch" != unknown ]; then
130
130
  [ "$os" = windows ] && asset="$asset.exe"
131
131
  url="$base/engine-v$version/$asset"
132
132
  tmp="$cache_root/bin/$version/.impeccable.part.$$"
133
+ # An interrupted download (Ctrl-C, a hook timeout) would otherwise leave the
134
+ # PID-named staging file behind for good. The handlers must exit explicitly.
135
+ cleanup() { rm -f "$tmp" "$tmp.sha256" 2>/dev/null || :; }
136
+ trap 'cleanup; exit 129' HUP
137
+ trap 'cleanup; exit 130' INT
138
+ trap 'cleanup; exit 143' TERM
133
139
  if ! mkdir -p "$cache_root/bin/$version" 2>/dev/null; then
134
140
  echo "impeccable: engine $version is not installed; cannot create cache directory: $cache_root/bin/$version" >&2
135
141
  setup_help
@@ -78,20 +78,37 @@ if exist "%IMPECCABLE_HOME%\bin\%version%\" goto cache_ready
78
78
  mkdir "%IMPECCABLE_HOME%\bin\%version%" >nul 2>nul
79
79
  if errorlevel 1 goto cache_directory_failed
80
80
  :cache_ready
81
- rem Check the staging file too: an existing directory may be read-only.
81
+ rem Stage the download in a directory only this run owns, as the sh launcher
82
+ rem does with .impeccable.part.$$: concurrent first runs (parallel hooks, two
83
+ rem agents) must never write, hash or move each other's files. mkdir fails
84
+ rem when the name exists, so it claims the name atomically. RANDOM alone is
85
+ rem not enough because cmd seeds it from the clock in whole seconds; the
86
+ rem timestamp and the retry on collision keep same-second runs apart. A cache
87
+ rem directory that refuses every mkdir is reported as unwritable.
88
+ set "attempt=0"
89
+ :claim_staging
90
+ set /a attempt+=1
91
+ if %attempt% GTR 20 goto cache_write_failed
92
+ set "stamp=%TIME: =0%"
93
+ set "stamp=%stamp::=%"
94
+ set "stamp=%stamp:.=%"
95
+ set "stamp=%stamp:,=%"
96
+ set "staging=%IMPECCABLE_HOME%\bin\%version%\.impeccable.part.%stamp%-%RANDOM%%RANDOM%"
97
+ mkdir "%staging%" >nul 2>nul
98
+ if errorlevel 1 goto claim_staging
99
+ set "part=%staging%\impeccable.exe"
100
+ set "sidecar=%staging%\impeccable.sha256"
82
101
  rem Redirection failures do not reliably update ERRORLEVEL in cmd.exe;
83
- rem branch on the command's failure directly. Never treat a directory as a
84
- rem staging file (later del cleanup would prompt to delete its contents).
85
- if exist "%cached%.part\" goto cache_write_failed
86
- (type nul >"%cached%.part") 2>nul || goto cache_write_failed
102
+ rem branch on the command's failure directly.
103
+ (type nul >"%part%") 2>nul || goto staging_write_failed
87
104
  set "asset=impeccable-windows-%arch%.exe"
88
105
  set "url=%IMPECCABLE_DOWNLOAD_BASE%/engine-v%version%/%asset%"
89
- curl.exe -fsSL -o "%cached%.part" "%url%" >nul 2>nul
106
+ curl.exe -fsSL -o "%part%" "%url%" >nul 2>nul
90
107
  if not errorlevel 1 goto verify
91
108
  if not "%arch%"=="arm64" goto download_failed
92
109
  set "asset=impeccable-windows-x64.exe"
93
110
  set "url=%IMPECCABLE_DOWNLOAD_BASE%/engine-v%version%/%asset%"
94
- curl.exe -fsSL -o "%cached%.part" "%url%" >nul 2>nul
111
+ curl.exe -fsSL -o "%part%" "%url%" >nul 2>nul
95
112
  if errorlevel 1 goto download_failed
96
113
 
97
114
  :verify
@@ -101,61 +118,67 @@ rem Mirrors the sh launcher and fails closed: a freshly downloaded binary
101
118
  rem runs only after verifying against its .sha256 sidecar. A sidecar that
102
119
  rem cannot be fetched, or an empty certutil result, refuses the download
103
120
  rem instead of running an unverified binary.
104
- curl.exe -fsSL -o "%cached%.sha256" "%url%.sha256" >nul 2>nul
121
+ curl.exe -fsSL -o "%sidecar%" "%url%.sha256" >nul 2>nul
105
122
  if errorlevel 1 goto verify_refuse
106
123
  set "expected="
107
- set /p expected=<"%cached%.sha256"
124
+ set /p expected=<"%sidecar%"
108
125
  for /f "tokens=1" %%h in ("%expected%") do set "expected=%%h"
109
126
  call :check_download
110
127
  if errorlevel 1 exit /b 127
111
128
  set "actual="
112
129
  rem Reuse the sidecar staging file after reading expected. Check certutil's
113
130
  rem status before parsing: its error text on stdout is not a digest.
114
- certutil -hashfile "%cached%.part" SHA256 >"%cached%.sha256" 2>nul
131
+ certutil -hashfile "%part%" SHA256 >"%sidecar%" 2>nul
115
132
  if errorlevel 1 goto verify_refuse
116
133
  call :check_download
117
134
  if errorlevel 1 exit /b 127
118
- for /f "usebackq skip=1 delims=" %%h in ("%cached%.sha256") do if not defined actual set "actual=%%h"
119
- del "%cached%.sha256" >nul 2>nul
135
+ for /f "usebackq skip=1 delims=" %%h in ("%sidecar%") do if not defined actual set "actual=%%h"
136
+ del "%sidecar%" >nul 2>nul
120
137
  if not defined expected goto verify_refuse
121
138
  if not defined actual goto verify_refuse
122
139
  set "actual=%actual: =%"
123
140
  if /I "%actual%"=="%expected%" goto place
124
- del "%cached%.part" >nul 2>nul
141
+ call :discard_staging
125
142
  echo impeccable: checksum mismatch downloading %url% 1>&2
126
143
  exit /b 127
127
144
 
128
145
  :verify_refuse
129
146
  call :check_download
130
147
  if errorlevel 1 exit /b 127
131
- del "%cached%.part" >nul 2>nul
132
- del "%cached%.sha256" >nul 2>nul
148
+ call :discard_staging
133
149
  echo impeccable: cannot verify %url% against %url%.sha256; refusing the unverified download 1>&2
134
150
  exit /b 127
135
151
 
136
152
  :check_download
137
153
  set "download_file=%~1"
138
- if not defined download_file set "download_file=%cached%.part"
154
+ if not defined download_file set "download_file=%part%"
139
155
  if not exist "%download_file%" goto download_missing
140
156
  for %%f in ("%download_file%") do if %%~zf==0 goto download_empty
141
157
  exit /b 0
142
158
 
143
159
  :download_missing
144
- del "%cached%.sha256" >nul 2>nul
160
+ call :discard_staging
145
161
  echo impeccable: download completed but the file was removed before execution: %url%; check your antivirus quarantine or logs. Refusing to continue; do not disable protection. 1>&2
146
162
  exit /b 127
147
163
 
148
164
  :download_empty
149
165
  del "%download_file%" >nul 2>nul
150
- del "%cached%.sha256" >nul 2>nul
166
+ call :discard_staging
151
167
  echo impeccable: downloaded file is empty: %url%; refusing the unverified download 1>&2
152
168
  exit /b 127
153
169
 
170
+ :discard_staging
171
+ rem Removes this run's staging directory and whatever is left in it. Never
172
+ rem touches another run's staging directory or the cached binary.
173
+ if defined staging rd /s /q "%staging%" >nul 2>nul
174
+ exit /b 0
175
+
154
176
  :place
155
177
  call :check_download
156
178
  if errorlevel 1 exit /b 127
157
- move /y "%cached%.part" "%cached%" >nul 2>nul
179
+ move /y "%part%" "%cached%" >nul 2>nul
158
180
  if errorlevel 1 goto place_failed
181
+ call :discard_staging
159
182
  call :check_download "%cached%"
160
183
  if errorlevel 1 exit /b 127
161
184
  set "run=%cached%"
@@ -164,7 +187,7 @@ goto run
164
187
  :place_failed
165
188
  call :check_download
166
189
  if errorlevel 1 exit /b 127
167
- del "%cached%.part" >nul 2>nul
190
+ call :discard_staging
168
191
  echo impeccable: could not cache the verified download: %url% 1>&2
169
192
  exit /b 127
170
193
 
@@ -193,6 +216,9 @@ exit /b 0
193
216
  echo impeccable: engine %version% is not installed; cannot create cache directory: "%IMPECCABLE_HOME%\bin\%version%" 1>&2
194
217
  goto setup_failed
195
218
 
219
+ :staging_write_failed
220
+ call :discard_staging
221
+
196
222
  :cache_write_failed
197
223
  echo impeccable: engine %version% is not installed; cannot write to cache directory: "%IMPECCABLE_HOME%\bin\%version%" 1>&2
198
224
  goto setup_failed
@@ -202,7 +228,7 @@ echo impeccable: cannot download engine %version%; curl.exe is unavailable. 1>&2
202
228
  goto setup_failed
203
229
 
204
230
  :download_failed
205
- del "%cached%.part" >nul 2>nul
231
+ call :discard_staging
206
232
  echo impeccable: could not download engine %version% from %url%; check network access and the release URL. 1>&2
207
233
 
208
234
  :setup_failed
@@ -212,7 +238,6 @@ echo Alternatively, set IMPECCABLE_HOME to a writable cache location, or IMPECCA
212
238
  exit /b 127
213
239
 
214
240
  :fail
215
- del "%cached%.part" >nul 2>nul
216
241
  echo impeccable: no engine binary found (looked in %bin%, %cached%, PATH). 1>&2
217
242
  echo Download impeccable-windows-%arch%.exe from https://github.com/pbakaus/impeccable/releases (tag engine-v%version%) and save it as %cached%, or set IMPECCABLE_BIN to a preinstalled engine binary. Docs: https://impeccable.style 1>&2
218
243
  exit /b 127
@@ -85,7 +85,10 @@
85
85
  }
86
86
 
87
87
  function id8() {
88
- if (crypto?.randomUUID) return crypto.randomUUID().replace(/-/g, '').slice(0, 8);
88
+ // randomUUID is secure-context only (issue #1055); getRandomValues is not.
89
+ try {
90
+ if (typeof crypto?.randomUUID === 'function') return crypto.randomUUID().replace(/-/g, '').slice(0, 8);
91
+ } catch { /* fall through */ }
89
92
  // Insecure-context fallback (plain-http LAN preview): still draw from the
90
93
  // CSPRNG. Math.random here was flagged by CodeQL (js/insecure-randomness)
91
94
  // because these ids name live-edit sessions.
@@ -200,6 +203,35 @@
200
203
  return el;
201
204
  }
202
205
 
206
+ // Copy text through a selected textarea and execCommand, for origins where
207
+ // navigator.clipboard is missing or refused (plain HTTP, issue #1055).
208
+ // The textarea mounts like any page-level chrome, so while a modal
209
+ // <dialog> is open it sits in that dialog's top-layer host: on <body> it
210
+ // would be inert, and inert text cannot be selected or copied.
211
+ function copyTextViaSelection(text) {
212
+ let ta = null;
213
+ const previous = activeElementDeep();
214
+ try {
215
+ ta = doc.createElement('textarea');
216
+ ta.id = prefix + '-clipboard';
217
+ ta.value = text;
218
+ ta.setAttribute('readonly', '');
219
+ ta.setAttribute('aria-hidden', 'true');
220
+ ta.tabIndex = -1;
221
+ ta.style.cssText = 'position:fixed;top:0;left:0;width:1px;height:1px;opacity:0;pointer-events:none;';
222
+ uiAppendToPage(ta);
223
+ ta.select();
224
+ return doc.execCommand('copy');
225
+ } catch {
226
+ return false;
227
+ } finally {
228
+ ta?.remove();
229
+ if (previous && previous !== activeElementDeep() && typeof previous.focus === 'function') {
230
+ try { previous.focus({ preventScroll: true }); } catch { /* best effort */ }
231
+ }
232
+ }
233
+ }
234
+
203
235
  function uiAppend(el) {
204
236
  const uiRoot = liveUiRoot();
205
237
  if (uiRoot === doc.body) return uiAppendToPage(el);
@@ -267,6 +299,7 @@
267
299
  liveUiRoot,
268
300
  uiAppend,
269
301
  uiAppendToPage,
302
+ copyTextViaSelection,
270
303
  topLayerHost,
271
304
  watchModalDialogs,
272
305
  cloneWithoutChrome,
@@ -8,6 +8,30 @@
8
8
  (function (root) {
9
9
  'use strict';
10
10
 
11
+ // crypto.randomUUID() exists only in secure contexts (HTTPS, localhost), so a
12
+ // dev site on a LAN IP, a Tailscale address, or a custom hostname over plain
13
+ // HTTP has no randomUUID at all (issue #1055). getRandomValues() is available
14
+ // in every context, so the fallback still draws from the CSPRNG: the upstream
15
+ // Math.random last resort is the insecure-randomness class CodeQL flagged in
16
+ // the id8 helper, and these ids name live-edit sessions.
17
+ function randomUUID(cryptoImpl) {
18
+ const c = cryptoImpl === undefined ? root.crypto : cryptoImpl;
19
+ try {
20
+ if (c && typeof c.randomUUID === 'function') return c.randomUUID();
21
+ } catch { /* fall through to getRandomValues */ }
22
+ const bytes = new Uint8Array(16);
23
+ (c || crypto).getRandomValues(bytes);
24
+ bytes[6] = (bytes[6] & 0x0f) | 0x40; // version 4
25
+ bytes[8] = (bytes[8] & 0x3f) | 0x80; // RFC 4122 variant
26
+ const hex = Array.from(bytes, (b) => b.toString(16).padStart(2, '0')).join('');
27
+ return hex.slice(0, 8) + '-' + hex.slice(8, 12) + '-' + hex.slice(12, 16)
28
+ + '-' + hex.slice(16, 20) + '-' + hex.slice(20);
29
+ }
30
+
31
+ function randomId8(cryptoImpl) {
32
+ return randomUUID(cryptoImpl).replace(/-/g, '').slice(0, 8);
33
+ }
34
+
11
35
  function createLiveBrowserSessionState({ prefix, storage, idFactory }) {
12
36
  if (!prefix) throw new Error('prefix required');
13
37
  const store = storage || root.localStorage;
@@ -150,5 +174,5 @@
150
174
  };
151
175
  }
152
176
 
153
- root.__IMPECCABLE_LIVE_SESSION__ = { createLiveBrowserSessionState };
177
+ root.__IMPECCABLE_LIVE_SESSION__ = { createLiveBrowserSessionState, randomUUID, randomId8 };
154
178
  })(typeof window !== 'undefined' ? window : globalThis);
@@ -61,11 +61,19 @@
61
61
  const IMPECCABLE_COMMAND = (window.__IMPECCABLE_COMMAND_PREFIX__ || '/') + 'impeccable';
62
62
  const PICK_CURSOR_STYLE_ID = PREFIX + '-pick-cursor-style';
63
63
  const MANUAL_APPLY_STATE_TTL_MS = 15 * 60 * 1000;
64
- const sessionState = window.__IMPECCABLE_LIVE_SESSION__?.createLiveBrowserSessionState({
65
- prefix: PREFIX,
66
- storage: localStorage,
67
- idFactory: () => crypto.randomUUID().replace(/-/g, '').slice(0, 8),
68
- });
64
+ // No idFactory: the session helper's default works on plain-HTTP origins,
65
+ // where the secure-context-only randomUUID does not exist (issue #1055).
66
+ let sessionState = null;
67
+ try {
68
+ sessionState = window.__IMPECCABLE_LIVE_SESSION__?.createLiveBrowserSessionState({
69
+ prefix: PREFIX,
70
+ storage: localStorage,
71
+ });
72
+ } catch (err) {
73
+ console.error('[impeccable] Live mode could not create its session state.', err);
74
+ window.__IMPECCABLE_LIVE_INIT__ = false; // let a later injection retry
75
+ return;
76
+ }
69
77
  if (!sessionState) {
70
78
  console.error('[impeccable] live-browser-session.js was not loaded. Live mode cannot start safely.');
71
79
  window.__IMPECCABLE_LIVE_INIT__ = false;
@@ -293,6 +301,7 @@
293
301
  liveUiRoot,
294
302
  uiAppend,
295
303
  uiAppendToPage,
304
+ copyTextViaSelection,
296
305
  topLayerHost,
297
306
  watchModalDialogs,
298
307
  cloneWithoutChrome,
@@ -7120,6 +7129,10 @@
7120
7129
  //
7121
7130
 
7122
7131
  function startScrollTracking() {
7132
+ // Idempotent: callers overlap (showBar starts tracking, then the agent
7133
+ // pick path starts it again), and a second loop would never be cancelled
7134
+ // because scrollRaf only remembers the latest one (#1002).
7135
+ stopScrollTracking();
7123
7136
  function tick() {
7124
7137
  if (state === 'CONFIGURING' || state === 'GENERATING' || state === 'CYCLING') {
7125
7138
  if (isInsertGeneratingSession()) ensureInsertPlaceholder();
@@ -13461,12 +13474,24 @@ void main() {
13461
13474
  .replace(/'/g, '&#39;');
13462
13475
  }
13463
13476
 
13477
+ // navigator.clipboard exists only in secure contexts, and writeText can
13478
+ // reject even where it exists (no focus, permission). Fall back
13479
+ // to the DOM helpers' selection copy (execCommand), which plain-HTTP origins
13480
+ // still allow and which stays usable under an open modal dialog.
13464
13481
  function copyToClipboard(text) {
13465
13482
  if (!text) return;
13483
+ const report = (ok) => showToast(ok ? 'Copied: ' + text : 'Could not copy: ' + text);
13484
+ let pending = null;
13466
13485
  try {
13467
- navigator.clipboard.writeText(text);
13468
- showToast('Copied: ' + text);
13469
- } catch { /* ignore */ }
13486
+ if (navigator.clipboard && typeof navigator.clipboard.writeText === 'function') {
13487
+ pending = navigator.clipboard.writeText(text);
13488
+ }
13489
+ } catch { pending = null; }
13490
+ if (pending && typeof pending.then === 'function') {
13491
+ pending.then(() => report(true), () => report(copyTextViaSelection(text)));
13492
+ return;
13493
+ }
13494
+ report(copyTextViaSelection(text));
13470
13495
  }
13471
13496
 
13472
13497
  //
@@ -7,13 +7,13 @@ export interface RunJournalSettings {
7
7
  };
8
8
  storage?: StorageSettingsSelection;
9
9
  }
10
- export declare function selectRunJournal(options?: {
10
+ export interface RunJournalResolutionOptions {
11
11
  journal?: RunJournalOption;
12
12
  settings?: RunJournalSettings;
13
- }): StorageSelection | RunJournal;
14
- export declare function resolveRunJournal(options?: {
15
- journal?: RunJournalOption;
16
- settings?: RunJournalSettings;
17
- }): Promise<RunJournal>;
18
- export declare function openSelectedRunJournal(selection: StorageSelection | RunJournal): Promise<RunJournal>;
13
+ /** The agent directory the owning session resolved its storage against; defaults to `getAgentDir()`. */
14
+ agentDir?: string;
15
+ }
16
+ export declare function selectRunJournal(options?: RunJournalResolutionOptions): StorageSelection | RunJournal;
17
+ export declare function resolveRunJournal(options?: RunJournalResolutionOptions): Promise<RunJournal>;
18
+ export declare function openSelectedRunJournal(selection: StorageSelection | RunJournal, agentDir?: string): Promise<RunJournal>;
19
19
  export declare function withRunJournalConfigSource<T>(selection: StorageSelection | RunJournal, open: () => Promise<T>): Promise<T>;