quiver-cli 0.8.0 → 1.1.0

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 (200) hide show
  1. package/README.md +127 -45
  2. package/bin/quiver-cli.mjs +3 -1
  3. package/dist/cli.js +666 -436
  4. package/package.json +2 -2
  5. package/template/.agents/AGENTS.md +4 -3
  6. package/template/.agents/config.json +7 -0
  7. package/template/.agents/plugins/opencode/rtk.ts +34 -0
  8. package/template/.agents/skills/agent-browser/SKILL.md +1 -0
  9. package/template/.agents/skills/apps/skybridge/SKILL.md +4 -0
  10. package/template/.agents/skills/design/impeccable/SKILL.md +36 -118
  11. package/template/.agents/skills/design/impeccable/reference/adapt.md +1 -0
  12. package/template/.agents/skills/design/impeccable/reference/adapt.native.md +58 -0
  13. package/template/.agents/skills/design/impeccable/reference/android.md +40 -0
  14. package/template/.agents/skills/design/impeccable/reference/animate.md +73 -188
  15. package/template/.agents/skills/design/impeccable/reference/audit.md +12 -9
  16. package/template/.agents/skills/design/impeccable/reference/audit.native.md +139 -0
  17. package/template/.agents/skills/design/impeccable/reference/bolder.md +19 -101
  18. package/template/.agents/skills/design/impeccable/reference/clarify.md +59 -253
  19. package/template/.agents/skills/design/impeccable/reference/colorize.md +51 -222
  20. package/template/.agents/skills/design/impeccable/reference/craft-floor.md +42 -0
  21. package/template/.agents/skills/design/impeccable/reference/craft.md +3 -121
  22. package/template/.agents/skills/design/impeccable/reference/critique.md +44 -23
  23. package/template/.agents/skills/design/impeccable/reference/degraded/asset-producer.md +90 -0
  24. package/template/.agents/skills/design/impeccable/reference/degraded/documenter.md +24 -0
  25. package/template/.agents/skills/design/impeccable/reference/degraded/finish-reviewer.md +37 -0
  26. package/template/.agents/skills/design/impeccable/reference/degraded/manual-edit-applier.md +92 -0
  27. package/template/.agents/skills/design/impeccable/reference/delight.md +47 -279
  28. package/template/.agents/skills/design/impeccable/reference/distill.md +2 -2
  29. package/template/.agents/skills/design/impeccable/reference/doctor.md +53 -0
  30. package/template/.agents/skills/design/impeccable/reference/document.md +60 -73
  31. package/template/.agents/skills/design/impeccable/reference/harden.md +1 -12
  32. package/template/.agents/skills/design/impeccable/reference/hooks.md +20 -5
  33. package/template/.agents/skills/design/impeccable/reference/init.md +72 -119
  34. package/template/.agents/skills/design/impeccable/reference/ios.md +45 -0
  35. package/template/.agents/skills/design/impeccable/reference/layout.md +54 -131
  36. package/template/.agents/skills/design/impeccable/reference/live-setup.md +102 -0
  37. package/template/.agents/skills/design/impeccable/reference/live.md +116 -511
  38. package/template/.agents/skills/design/impeccable/reference/new-work.md +105 -0
  39. package/template/.agents/skills/design/impeccable/reference/{product.md → operate.md} +6 -5
  40. package/template/.agents/skills/design/impeccable/reference/optimize.md +4 -4
  41. package/template/.agents/skills/design/impeccable/reference/overdrive.md +1 -4
  42. package/template/.agents/skills/design/impeccable/reference/polish.md +68 -212
  43. package/template/.agents/skills/design/impeccable/reference/quieter.md +3 -3
  44. package/template/.agents/skills/design/impeccable/reference/routing.md +18 -0
  45. package/template/.agents/skills/design/impeccable/reference/shape.md +38 -144
  46. package/template/.agents/skills/design/impeccable/reference/typeset.md +51 -250
  47. package/template/.agents/skills/design/impeccable/reference/visualize.md +47 -0
  48. package/template/.agents/skills/design/impeccable/scripts/command-metadata.json +1 -1
  49. package/template/.agents/skills/design/impeccable/scripts/concept-seed.mjs +558 -0
  50. package/template/.agents/skills/design/impeccable/scripts/context-signals.mjs +119 -10
  51. package/template/.agents/skills/design/impeccable/scripts/context.mjs +534 -45
  52. package/template/.agents/skills/design/impeccable/scripts/critique-storage.mjs +18 -47
  53. package/template/.agents/skills/design/impeccable/scripts/detector/browser/injected/index.mjs +96 -10
  54. package/template/.agents/skills/design/impeccable/scripts/detector/cli/main.mjs +174 -26
  55. package/template/.agents/skills/design/impeccable/scripts/detector/design-system.mjs +233 -0
  56. package/template/.agents/skills/design/impeccable/scripts/detector/detect-antipatterns-browser.js +3348 -203
  57. package/template/.agents/skills/design/impeccable/scripts/detector/engines/browser/detect-url.mjs +102 -7
  58. package/template/.agents/skills/design/impeccable/scripts/detector/engines/regex/detect-text.mjs +297 -97
  59. package/template/.agents/skills/design/impeccable/scripts/detector/engines/static-html/css-cascade.mjs +187 -16
  60. package/template/.agents/skills/design/impeccable/scripts/detector/engines/static-html/detect-html.mjs +41 -11
  61. package/template/.agents/skills/design/impeccable/scripts/detector/findings.mjs +7 -1
  62. package/template/.agents/skills/design/impeccable/scripts/detector/node/file-system.mjs +16 -2
  63. package/template/.agents/skills/design/impeccable/scripts/detector/registry/antipatterns.mjs +207 -38
  64. package/template/.agents/skills/design/impeccable/scripts/detector/rules/checks.mjs +3082 -173
  65. package/template/.agents/skills/design/impeccable/scripts/detector/shared/constants.mjs +11 -0
  66. package/template/.agents/skills/design/impeccable/scripts/detector/shared/fonts.mjs +30 -0
  67. package/template/.agents/skills/design/impeccable/scripts/doctor.mjs +336 -0
  68. package/template/.agents/skills/design/impeccable/scripts/embed-prompt.mjs +133 -0
  69. package/template/.agents/skills/design/impeccable/scripts/generate-image.mjs +240 -0
  70. package/template/.agents/skills/design/impeccable/scripts/hook-admin.mjs +98 -18
  71. package/template/.agents/skills/design/impeccable/scripts/hook-before-edit.mjs +46 -6
  72. package/template/.agents/skills/design/impeccable/scripts/hook-lib.mjs +518 -50
  73. package/template/.agents/skills/design/impeccable/scripts/hook.mjs +25 -8
  74. package/template/.agents/skills/design/impeccable/scripts/lib/artifact-schema.mjs +93 -0
  75. package/template/.agents/skills/design/impeccable/scripts/lib/composition-catalog.mjs +200 -0
  76. package/template/.agents/skills/design/impeccable/scripts/lib/concept-catalog.mjs +357 -0
  77. package/template/.agents/skills/design/impeccable/scripts/lib/impeccable-config.mjs +27 -7
  78. package/template/.agents/skills/design/impeccable/scripts/lib/impeccable-paths.mjs +17 -8
  79. package/template/.agents/skills/design/impeccable/scripts/lib/provider.mjs +5 -0
  80. package/template/.agents/skills/design/impeccable/scripts/lib/roll-selection.mjs +362 -0
  81. package/template/.agents/skills/design/impeccable/scripts/lib/staleness-deep.mjs +457 -0
  82. package/template/.agents/skills/design/impeccable/scripts/lib/staleness-notice.mjs +169 -0
  83. package/template/.agents/skills/design/impeccable/scripts/lib/staleness.mjs +457 -0
  84. package/template/.agents/skills/design/impeccable/scripts/lib/surface-briefs.mjs +151 -0
  85. package/template/.agents/skills/design/impeccable/scripts/lib/target-slug.mjs +33 -0
  86. package/template/.agents/skills/design/impeccable/scripts/lib/template-extensions.mjs +146 -0
  87. package/template/.agents/skills/design/impeccable/scripts/live/accept-css.mjs +617 -0
  88. package/template/.agents/skills/design/impeccable/scripts/live/accept-verify.mjs +60 -0
  89. package/template/.agents/skills/design/impeccable/scripts/live/browser-script-parts.mjs +7 -1
  90. package/template/.agents/skills/design/impeccable/scripts/live/completion.mjs +10 -1
  91. package/template/.agents/skills/design/impeccable/scripts/live/event-validation.mjs +67 -5
  92. package/template/.agents/skills/design/impeccable/scripts/live/frameworks/astro.mjs +47 -0
  93. package/template/.agents/skills/design/impeccable/scripts/live/frameworks/detect-utils.mjs +73 -0
  94. package/template/.agents/skills/design/impeccable/scripts/live/frameworks/index.mjs +143 -0
  95. package/template/.agents/skills/design/impeccable/scripts/live/frameworks/journal.mjs +197 -0
  96. package/template/.agents/skills/design/impeccable/scripts/live/frameworks/nextjs.mjs +49 -0
  97. package/template/.agents/skills/design/impeccable/scripts/live/frameworks/nuxt.mjs +161 -0
  98. package/template/.agents/skills/design/impeccable/scripts/live/frameworks/script-src.mjs +17 -0
  99. package/template/.agents/skills/design/impeccable/scripts/live/frameworks/static-html.mjs +26 -0
  100. package/template/.agents/skills/design/impeccable/scripts/live/frameworks/sveltekit.mjs +71 -0
  101. package/template/.agents/skills/design/impeccable/scripts/live/frameworks/tag-strategy.mjs +247 -0
  102. package/template/.agents/skills/design/impeccable/scripts/live/frameworks/tanstack-start.mjs +70 -0
  103. package/template/.agents/skills/design/impeccable/scripts/live/frameworks/vite-generic.mjs +42 -0
  104. package/template/.agents/skills/design/impeccable/scripts/live/generation-preflight.mjs +149 -0
  105. package/template/.agents/skills/design/impeccable/scripts/live/instructions.mjs +142 -0
  106. package/template/.agents/skills/design/impeccable/scripts/live/poll-lanes.mjs +14 -0
  107. package/template/.agents/skills/design/impeccable/scripts/live/roots.mjs +508 -0
  108. package/template/.agents/skills/design/impeccable/scripts/live/session-store.mjs +324 -50
  109. package/template/.agents/skills/design/impeccable/scripts/live/source-lock.mjs +105 -0
  110. package/template/.agents/skills/design/impeccable/scripts/live/source-search.mjs +105 -0
  111. package/template/.agents/skills/design/impeccable/scripts/live/svelte-ast.mjs +961 -0
  112. package/template/.agents/skills/design/impeccable/scripts/live/svelte-component.mjs +588 -72
  113. package/template/.agents/skills/design/impeccable/scripts/live/sveltekit-adapter.mjs +59 -17
  114. package/template/.agents/skills/design/impeccable/scripts/live/tanstack-adapter.mjs +280 -0
  115. package/template/.agents/skills/design/impeccable/scripts/live/vocabulary.mjs +135 -0
  116. package/template/.agents/skills/design/impeccable/scripts/live-accept.mjs +210 -68
  117. package/template/.agents/skills/design/impeccable/scripts/live-browser.js +1562 -223
  118. package/template/.agents/skills/design/impeccable/scripts/live-commit-manual-edits.mjs +3 -0
  119. package/template/.agents/skills/design/impeccable/scripts/live-complete.mjs +33 -1
  120. package/template/.agents/skills/design/impeccable/scripts/live-inject.mjs +175 -255
  121. package/template/.agents/skills/design/impeccable/scripts/live-insert.mjs +26 -6
  122. package/template/.agents/skills/design/impeccable/scripts/live-manual-edit-evidence.mjs +6 -1
  123. package/template/.agents/skills/design/impeccable/scripts/live-poll.mjs +61 -16
  124. package/template/.agents/skills/design/impeccable/scripts/live-resume.mjs +39 -10
  125. package/template/.agents/skills/design/impeccable/scripts/live-server.mjs +573 -47
  126. package/template/.agents/skills/design/impeccable/scripts/live-status.mjs +17 -7
  127. package/template/.agents/skills/design/impeccable/scripts/live-wrap.mjs +124 -91
  128. package/template/.agents/skills/design/impeccable/scripts/live.mjs +88 -26
  129. package/template/.agents/skills/design/impeccable/scripts/palette.mjs +76 -81
  130. package/template/.agents/skills/design/impeccable/scripts/pin.mjs +18 -11
  131. package/template/.agents/skills/design/impeccable/scripts/serve-question.mjs +932 -0
  132. package/template/.agents/skills/design/impeccable/scripts/surface-brief.mjs +74 -0
  133. package/template/.agents/skills/design/shadcn/SKILL.md +46 -11
  134. package/template/.agents/skills/design/shadcn/cli.md +49 -16
  135. package/template/.agents/skills/design/shadcn/customization.md +14 -7
  136. package/template/.agents/skills/design/shadcn/evals/evals.json +30 -0
  137. package/template/.agents/skills/design/shadcn/mcp.md +27 -16
  138. package/template/.agents/skills/design/shadcn/registry.md +277 -0
  139. package/template/.agents/skills/design/shadcn/rules/chat.md +224 -0
  140. package/template/.agents/skills/design/shadcn/rules/composition.md +20 -2
  141. package/template/.agents/skills/design/shadcn/rules/styling.md +23 -0
  142. package/template/.agents/skills/find-skills/SKILL.md +2 -3
  143. package/template/.agents/skills/hono/SKILL.md +579 -0
  144. package/template/.agents/skills/integrations/langfuse/SKILL.md +10 -6
  145. package/template/.agents/skills/integrations/langfuse/references/ci-cd.md +41 -0
  146. package/template/.agents/skills/integrations/langfuse/references/cli.md +8 -0
  147. package/template/.agents/skills/integrations/langfuse/references/error-analysis.md +15 -27
  148. package/template/.agents/skills/integrations/langfuse/references/instrumentation.md +39 -52
  149. package/template/.agents/skills/integrations/langfuse/references/judge-calibration.md +5 -2
  150. package/template/.agents/skills/integrations/langfuse/references/prompt-engineering.md +35 -0
  151. package/template/.agents/skills/integrations/langfuse/references/prompt-migration.md +41 -196
  152. package/template/.agents/skills/integrations/langfuse/references/skill-feedback.md +3 -0
  153. package/template/.agents/skills/integrations/langfuse/references/trace-evaluator-upgrade.md +76 -0
  154. package/template/.agents/skills/integrations/langfuse/references/user-feedback.md +4 -0
  155. package/template/.agents/skills/integrations/langfuse/references/v4-project-migration.md +73 -0
  156. package/template/.agents/skills/supabase/CHANGELOG.md +71 -0
  157. package/template/.agents/skills/supabase/SKILL.md +145 -0
  158. package/template/.agents/skills/supabase/assets/feedback-issue-template.md +17 -0
  159. package/template/.agents/skills/supabase/references/skill-feedback.md +17 -0
  160. package/template/.agents/skills/supabase-postgres-best-practices/CHANGELOG.md +73 -0
  161. package/template/.agents/skills/supabase-postgres-best-practices/SKILL.md +64 -0
  162. package/template/.agents/skills/supabase-postgres-best-practices/references/_contributing.md +170 -0
  163. package/template/.agents/skills/supabase-postgres-best-practices/references/_sections.md +39 -0
  164. package/template/.agents/skills/supabase-postgres-best-practices/references/_template.md +34 -0
  165. package/template/.agents/skills/supabase-postgres-best-practices/references/advanced-full-text-search.md +55 -0
  166. package/template/.agents/skills/supabase-postgres-best-practices/references/advanced-jsonb-indexing.md +49 -0
  167. package/template/.agents/skills/supabase-postgres-best-practices/references/conn-idle-timeout.md +46 -0
  168. package/template/.agents/skills/supabase-postgres-best-practices/references/conn-limits.md +44 -0
  169. package/template/.agents/skills/supabase-postgres-best-practices/references/conn-pooling.md +41 -0
  170. package/template/.agents/skills/supabase-postgres-best-practices/references/conn-prepared-statements.md +46 -0
  171. package/template/.agents/skills/supabase-postgres-best-practices/references/data-batch-inserts.md +54 -0
  172. package/template/.agents/skills/supabase-postgres-best-practices/references/data-n-plus-one.md +53 -0
  173. package/template/.agents/skills/supabase-postgres-best-practices/references/data-pagination.md +50 -0
  174. package/template/.agents/skills/supabase-postgres-best-practices/references/data-upsert.md +50 -0
  175. package/template/.agents/skills/supabase-postgres-best-practices/references/lock-advisory.md +56 -0
  176. package/template/.agents/skills/supabase-postgres-best-practices/references/lock-deadlock-prevention.md +68 -0
  177. package/template/.agents/skills/supabase-postgres-best-practices/references/lock-short-transactions.md +50 -0
  178. package/template/.agents/skills/supabase-postgres-best-practices/references/lock-skip-locked.md +54 -0
  179. package/template/.agents/skills/supabase-postgres-best-practices/references/monitor-explain-analyze.md +45 -0
  180. package/template/.agents/skills/supabase-postgres-best-practices/references/monitor-pg-stat-statements.md +55 -0
  181. package/template/.agents/skills/supabase-postgres-best-practices/references/monitor-vacuum-analyze.md +55 -0
  182. package/template/.agents/skills/supabase-postgres-best-practices/references/query-composite-indexes.md +44 -0
  183. package/template/.agents/skills/supabase-postgres-best-practices/references/query-covering-indexes.md +40 -0
  184. package/template/.agents/skills/supabase-postgres-best-practices/references/query-index-types.md +48 -0
  185. package/template/.agents/skills/supabase-postgres-best-practices/references/query-missing-indexes.md +43 -0
  186. package/template/.agents/skills/supabase-postgres-best-practices/references/query-partial-indexes.md +45 -0
  187. package/template/.agents/skills/supabase-postgres-best-practices/references/schema-constraints.md +80 -0
  188. package/template/.agents/skills/supabase-postgres-best-practices/references/schema-data-types.md +46 -0
  189. package/template/.agents/skills/supabase-postgres-best-practices/references/schema-foreign-key-indexes.md +59 -0
  190. package/template/.agents/skills/supabase-postgres-best-practices/references/schema-lowercase-identifiers.md +55 -0
  191. package/template/.agents/skills/supabase-postgres-best-practices/references/schema-partitioning.md +55 -0
  192. package/template/.agents/skills/supabase-postgres-best-practices/references/schema-primary-keys.md +61 -0
  193. package/template/.agents/skills/supabase-postgres-best-practices/references/security-privileges.md +54 -0
  194. package/template/.agents/skills/supabase-postgres-best-practices/references/security-rls-basics.md +50 -0
  195. package/template/.agents/skills/supabase-postgres-best-practices/references/security-rls-performance.md +63 -0
  196. package/template/.agents/upstreams.json +34 -12
  197. package/template/.agents/skills/design/impeccable/reference/brand.md +0 -108
  198. package/template/.agents/skills/design/impeccable/reference/codex.md +0 -105
  199. package/template/.agents/skills/design/impeccable/reference/interaction-design.md +0 -189
  200. package/template/.agents/skills/integrations/langfuse/references/sdk-upgrade.md +0 -175
@@ -0,0 +1,149 @@
1
+ import { execFile } from 'node:child_process';
2
+ import path from 'node:path';
3
+ import { promisify } from 'node:util';
4
+
5
+ const execFileAsync = promisify(execFile);
6
+ const PREFLIGHT_TIMEOUT_MS = 15_000;
7
+
8
+ // Per-target cache of the resolved source file. The wrap search walks the whole
9
+ // project tree and was measured at ~7.6s on a large repo; it re-ran on every
10
+ // generate for the same picked element (re-rolls, param passes). Keyed by the
11
+ // target signature (locator + route), so it invalidates automatically when the
12
+ // element or route changes; a failed resolution evicts its entry (see below).
13
+ const sourceResolutionCache = new Map();
14
+
15
+ /** Test/lifecycle hook: drop all cached source resolutions. */
16
+ export function clearSourceResolutionCache() {
17
+ sourceResolutionCache.clear();
18
+ }
19
+
20
+ function targetSignature(event) {
21
+ const isInsert = event.mode === 'insert';
22
+ const target = isInsert ? insertTarget(event) : replaceTarget(event);
23
+ return JSON.stringify({
24
+ mode: isInsert ? 'insert' : 'replace',
25
+ position: isInsert ? target.position : null,
26
+ elementId: target.elementId || null,
27
+ classes: target.classes || null,
28
+ tag: target.tag || null,
29
+ pageUrl: event.pageUrl || null,
30
+ });
31
+ }
32
+
33
+ export function buildGenerationPreflight(event, scriptsDir, { cache = null } = {}) {
34
+ if (!event || event.type !== 'generate' || !event.id) return null;
35
+
36
+ const isInsert = event.mode === 'insert';
37
+ const target = isInsert ? insertTarget(event) : replaceTarget(event);
38
+ if (!target.elementId && !target.classes) return null;
39
+
40
+ const script = path.join(scriptsDir, isInsert ? 'live-insert.mjs' : 'live-wrap.mjs');
41
+ const args = [script, '--id', event.id, '--count', String(event.count || 3)];
42
+ // Compute the scaffold but do not write it into source for source-preview
43
+ // targets. The agent writes wrapper + variants atomically; a premature
44
+ // server-side write reloads the framework and strands the browser at 0/N.
45
+ // No-op on the svelte-component path, which never writes the route source.
46
+ args.push('--defer-source-write');
47
+ if (isInsert) args.push('--position', target.position);
48
+ if (target.elementId) args.push('--element-id', target.elementId);
49
+ if (target.classes) args.push('--classes', target.classes);
50
+ if (target.tag) args.push('--tag', target.tag);
51
+ if (target.text) args.push('--text', target.text);
52
+ if (!isInsert && event.pageUrl) args.push('--page-url', event.pageUrl);
53
+ const signature = targetSignature(event);
54
+ // A cached resolution points the helper straight at the file, skipping the
55
+ // tree search. The helper still reads current content, so line ranges stay
56
+ // fresh; only discovery is cached.
57
+ const cachedFile = cache ? cache.get(signature) : null;
58
+ if (cachedFile) args.push('--file', cachedFile);
59
+ return { script, args, mode: isInsert ? 'insert' : 'replace', signature };
60
+ }
61
+
62
+ /**
63
+ * Scaffold the source for a generate event before handing it to an agent.
64
+ *
65
+ * Async on purpose. This spawns `live-wrap.mjs`, which walks the project's
66
+ * source tree and can take seconds (measured at ~7.6s on a large repo when the
67
+ * element is not found, with a 15s ceiling). The live server is single-threaded
68
+ * and calls this while leasing a poll, so a synchronous spawn froze the whole
69
+ * server for that entire window: Accept and Discard POSTs, SSE progress
70
+ * broadcasts, and every other poll stalled behind it.
71
+ */
72
+ export async function runGenerationPreflight(event, {
73
+ cwd = process.cwd(),
74
+ scriptsDir,
75
+ execFileImpl = execFileAsync,
76
+ timeoutMs = PREFLIGHT_TIMEOUT_MS,
77
+ cache = sourceResolutionCache,
78
+ } = {}) {
79
+ const command = buildGenerationPreflight(event, scriptsDir, { cache });
80
+ if (!command) {
81
+ return { ok: false, skipped: true, reason: 'insufficient_locator' };
82
+ }
83
+
84
+ const startedAt = performance.now();
85
+ try {
86
+ const { stdout } = await execFileImpl(process.execPath, command.args, {
87
+ cwd,
88
+ encoding: 'utf-8',
89
+ timeout: timeoutMs,
90
+ });
91
+ const line = String(stdout).trim().split('\n').filter(Boolean).pop();
92
+ if (!line) throw new Error('preflight returned no scaffold metadata');
93
+ const scaffold = JSON.parse(line);
94
+ // Cache the resolved SOURCE file (route source, not the svelte manifest) so
95
+ // the next generate on this target skips the tree search.
96
+ const resolvedSource = scaffold.sourceFile || scaffold.file;
97
+ if (cache && command.signature && typeof resolvedSource === 'string') {
98
+ cache.set(command.signature, resolvedSource);
99
+ }
100
+ return {
101
+ ok: true,
102
+ mode: command.mode,
103
+ durationMs: performance.now() - startedAt,
104
+ scaffold,
105
+ };
106
+ } catch (error) {
107
+ // Evict a stale/failed resolution so the next attempt does a full search
108
+ // (the element may have moved out of the previously cached file).
109
+ if (cache && command.signature) cache.delete(command.signature);
110
+ return {
111
+ ok: false,
112
+ mode: command.mode,
113
+ durationMs: performance.now() - startedAt,
114
+ error: compactError(error),
115
+ };
116
+ }
117
+ }
118
+
119
+ function replaceTarget(event) {
120
+ return normalizeTarget(event.element || {});
121
+ }
122
+
123
+ function insertTarget(event) {
124
+ return {
125
+ ...normalizeTarget(event.insert?.anchor || {}),
126
+ position: event.insert?.position === 'before' ? 'before' : 'after',
127
+ };
128
+ }
129
+
130
+ function normalizeTarget(target) {
131
+ const classes = Array.isArray(target.classes)
132
+ ? target.classes.join(' ')
133
+ : String(target.classes || '').trim();
134
+ const text = typeof target.textContent === 'string'
135
+ ? target.textContent.trim().slice(0, 80)
136
+ : '';
137
+ return {
138
+ elementId: target.id || target.elementId || undefined,
139
+ classes: classes || undefined,
140
+ tag: target.tagName || target.tag || undefined,
141
+ text: text || undefined,
142
+ };
143
+ }
144
+
145
+ function compactError(error) {
146
+ const stderr = error?.stderr ? String(error.stderr).trim() : '';
147
+ const message = stderr.split('\n').filter(Boolean).pop() || error?.message || 'preflight failed';
148
+ return String(message).slice(0, 500);
149
+ }
@@ -0,0 +1,142 @@
1
+ /**
2
+ * Just-in-time agent instructions for live mode.
3
+ *
4
+ * The live scripts, not the reference doc, own situational plumbing: every
5
+ * event printed by live-poll carries an `_instructions` string describing
6
+ * exactly what to do NEXT, with real ids, paths, and line numbers already
7
+ * substituted and only the active path's rules included (a svelte-component
8
+ * session never sees JSX guidance, and vice versa). live.md stays lean: the
9
+ * session contract, harness policy, and design-quality guidance that is not
10
+ * situational (identity lock, variation axes, parameter budgets).
11
+ *
12
+ * Keep these strings imperative, concrete, and short. They are read by an
13
+ * agent mid-session; every sentence must earn its tokens. Instructions are
14
+ * versioned with the scripts, so they cannot drift from behavior the way a
15
+ * hand-maintained doc can.
16
+ */
17
+
18
+ const PLAN_POINTER = 'Plan per live.md section 4: extract the identity lock, pick default vs departure mode, commit each variant to a DIFFERENT primary axis, squint-test the trio. Size parameter knobs per section 7 budgets.';
19
+
20
+ function pollCmd(scriptsPath) {
21
+ return `node ${scriptsPath}/live-poll.mjs`;
22
+ }
23
+
24
+ function replyCmd(scriptsPath, id, rest) {
25
+ return `${pollCmd(scriptsPath)} --reply ${id} ${rest}`;
26
+ }
27
+
28
+ export function instructionsForEvent(event, { scriptsPath = '{{scripts_path}}' } = {}) {
29
+ if (!event || typeof event !== 'object') return undefined;
30
+ switch (event.type) {
31
+ case 'generate':
32
+ return generateInstructions(event, scriptsPath);
33
+ case 'steer':
34
+ return `Do what the message asks (page edits, navigation help, or a short answer). Then reply exactly once: ${replyCmd(scriptsPath, event.id, 'steer_done ["optional short toast"]')} (on failure: --reply ${event.id} error "Short reason"). No pickup ack; poll again immediately after.`;
35
+ case 'prefetch':
36
+ return `Speculative pre-read, no reply owed: resolve ${JSON.stringify(event.pageUrl || '/')} to its source file (root "/" is usually the boot's pageFile; multi-page sites map /foo to public/foo/index.html; SPAs map all routes to one entry), read it into context, then poll again. Skip if you cannot resolve it confidently.`;
37
+ case 'variant_mount_failed':
38
+ return `The browser could NOT render variant ${event.variant}${event.url ? ` (module: ${event.url})` : ''}${event.error ? `: ${String(event.error).slice(0, 200)}` : ''}. The user sees a persistent error card, not variants. Fix the variant source files, then reply ${replyCmd(scriptsPath, event.id, 'done --file <manifest or source path>')}; the browser retries on its own. Poll again after the reply.`;
39
+ case 'accept':
40
+ return acceptInstructions(event, scriptsPath);
41
+ case 'discard':
42
+ return event?._completionAck?.ok === true
43
+ ? 'Original restored and durable completion acknowledged; nothing to do. Poll again.'
44
+ : `Completion was not acknowledged: run node ${scriptsPath}/live-complete.mjs --id ${event.id} --discarded, then poll again.`;
45
+ case 'manual_edit_apply':
46
+ return `The user already clicked Apply; never ask, discard, or redirect. Delegate the source edits to the impeccable_manual_edit_applier subagent when available (pass cwd, scripts path, event id, page URL, chunk/deadline, batch, evidencePath); it must not poll or reply. ${event.repair ? 'A `repair` payload is present: the previous Apply changed source but validation failed; fix the CURRENT source, never roll back yourself. ' : ''}Reply exactly once: ${replyCmd(scriptsPath, event.id, `done --data '{"status":"done","appliedEntryIds":[...],"failed":[],"files":[...],"notes":[]}'`)} (status "partial"/"error" with failed[] when not every entry applied). Then poll again.`;
47
+ case 'timeout':
48
+ return 'No event arrived; poll again immediately.';
49
+ case 'exit':
50
+ return `Session over: kill any background poll, then node ${scriptsPath}/live-server.mjs stop (removes the injected script tag). Sweep leftover impeccable-variants-start / impeccable-carbonize-start markers from source.`;
51
+ default:
52
+ return undefined;
53
+ }
54
+ }
55
+
56
+ function generateInstructions(event, scriptsPath) {
57
+ const id = event.id;
58
+ const scaffold = event.scaffold;
59
+ const steps = [];
60
+
61
+ if (event.screenshotPath) {
62
+ steps.push(`Read the annotated screenshot first: ${event.screenshotPath}. Comment {x,y} positions bind text to the child under that point; strokes read by shape (loop = emphasis on this thing, arrow = direction, cross = delete).`);
63
+ } else {
64
+ steps.push('No screenshot was sent (the user did not annotate); do not ask for one and do not screenshot the page. Work from element.outerHTML, the computed styles, and the prompt.');
65
+ }
66
+
67
+ if (event.mode === 'insert') {
68
+ steps.push(insertScaffoldInstructions(event, scriptsPath));
69
+ } else if (scaffold?.previewMode === 'svelte-component') {
70
+ steps.push(svelteComponentInstructions(event, scaffold, scriptsPath));
71
+ } else if (scaffold && scaffold.sourceWritten === false) {
72
+ steps.push(deferredWrapperInstructions(event, scaffold, scriptsPath));
73
+ } else if (scaffold) {
74
+ steps.push(`The wrapper is already written into ${scaffold.file}. Splice preview CSS plus all ${event.count} variants at line ${scaffold.insertLine} in ONE edit, following the returned cssAuthoring contract (styleTag, selector strategy, forbidden patterns). Each variant div holds exactly ONE top-level element (same tag as the original); first visible, others display: none.`);
75
+ } else {
76
+ steps.push(`Preflight could not scaffold${event.scaffoldError ? ` (${event.scaffoldError})` : ''}. Run node ${scriptsPath}/live-wrap.mjs --id ${id} --count ${event.count} --element-id "${event.element?.id || ''}" --classes "${(event.element?.classes || []).join(',')}" --tag "${event.element?.tagName || ''}" --text "<first ~80 chars of the picked element's textContent>". Keep the flags separate; --text disambiguates repeated siblings. On a fallback error, follow live.md's Handle fallback.`);
77
+ }
78
+
79
+ steps.push(event.action && event.action !== 'impeccable'
80
+ ? `Action is "${event.action}": read reference/${event.action}.md before planning; its MUST params are non-negotiable. ${PLAN_POINTER}`
81
+ : `Freeform action: work from SKILL.md rules plus craft-floor.md; no sub-command file. ${PLAN_POINTER}`);
82
+
83
+ steps.push(`When all ${event.count} variants are delivered: ${replyCmd(scriptsPath, id, 'done --file <project-root-relative path you wrote>')}. Then poll again. If generation fails after the browser flipped to GENERATING, reply --reply ${id} error "Short reason" so the bar resets (never live-accept --discard for this).`);
84
+
85
+ return steps.map((s, i) => `${i + 1}. ${s}`).join('\n');
86
+ }
87
+
88
+ function svelteComponentInstructions(event, scaffold, scriptsPath) {
89
+ const dir = scaffold.componentDir;
90
+ const count = event.count;
91
+ return `Svelte component preview. EDIT the existing stubs ${dir}/v1.svelte ... v${count}.svelte in place; never delete or recreate them; do not read them back (the prop-substituted markup is in scaffold.componentStubMarkup). Keep the stub's control flow ({#each}, {#if}) and propContract prop names exactly; never flatten a loop into literal items. The stub <style> is seeded with the source rules that style the selection; restyle or delete freely, and know that any seeded rule you do not re-declare is REMOVED from source on accept (the preview never applied it). ALL your CSS goes inside that ONE existing <style> block: Svelte forbids a second top-level style element, and a publish with a non-compiling variant is bounced back to you with file and line. Semantic class selectors only: no @scope, no data-impeccable-* attributes. Params go in ${dir}/params.json keyed by variant number (never an attribute); author knob CSS against var(--p-<id>, default) and :global([data-p-<id>="..."]). Reply with --file ${scaffold.file}. Accept later merges everything into ${scaffold.sourceFile} mechanically; you have no post-accept cleanup.`;
92
+ }
93
+
94
+ function deferredWrapperInstructions(event, scaffold, scriptsPath) {
95
+ const insertNote = Number(scaffold.replaceEndLine) < Number(scaffold.replaceStartLine)
96
+ ? ` (replaceEndLine < replaceStartLine: this is an INSERTION at line ${scaffold.replaceStartLine}; remove nothing)`
97
+ : '';
98
+ return `The wrapper is NOT in source yet. In ONE edit to ${scaffold.file}: splice preview CSS plus all ${event.count} variants into scaffold.wrapperBlock at the "Variants: insert below this line" marker, then replace lines ${scaffold.replaceStartLine}-${scaffold.replaceEndLine}${insertNote} with the result. Two separate writes reload the framework mid-publish and strand the browser at 0/N. Author CSS per the returned cssAuthoring contract; each variant div holds exactly ONE top-level element (same tag as the original); first visible, others display: none. On JSX/TSX wrap the <style> content in a template literal and use className / style={{...}}.`;
99
+ }
100
+
101
+ function insertScaffoldInstructions(event, scriptsPath) {
102
+ const scaffold = event.scaffold;
103
+ const base = `Insert mode: net-new content sized around ${event.placeholder?.width || '?'}x${event.placeholder?.height || '?'} at the chosen anchor; load craft-floor.md before writing net-new markup.`;
104
+ if (scaffold?.previewMode === 'svelte-component') {
105
+ return `${base} Write each inserted variant as a single-root Svelte component under ${scaffold.componentDir} (no data-impeccable-* attributes, CSS in each component's <style>). Never edit the route during generation; reply with --file ${scaffold.file}.`;
106
+ }
107
+ if (scaffold && scaffold.sourceWritten === false) {
108
+ return `${base} Splice your variants into scaffold.wrapperBlock at the marker and insert the result at line ${scaffold.replaceStartLine} of ${scaffold.file} in ONE edit.`;
109
+ }
110
+ return `${base} If no scaffold payload is present, run node ${scriptsPath}/live-insert.mjs --id ${event.id} --count ${event.count} --position ${event.insert?.position || 'after'} with the anchor flags from event.insert.anchor, then splice variants at the returned insertLine.`;
111
+ }
112
+
113
+ function acceptInstructions(event, scriptsPath) {
114
+ const result = event._acceptResult || {};
115
+ const ackOk = event._completionAck?.ok === true;
116
+ const prefix = ackOk ? '' : `Completion was NOT acknowledged: run node ${scriptsPath}/live-status.mjs, finish any cleanup, then node ${scriptsPath}/live-complete.mjs --id ${event.id}. `;
117
+
118
+ if (result.handled === true && result.carbonize === true) {
119
+ return `${prefix}Carbonize cleanup is REQUIRED now, before the next poll, in ${result.file}: (1) locate the impeccable-carbonize-start/end block and read the impeccable-param-values comment; (2) move the CSS rules into the stylesheet that owns this area; (3) bake params while rewriting selectors (@scope wrappers to semantic classes, keep only the chosen data-p branch, substitute range literals); (4) unwrap the accepted content and drop every data-impeccable-* / data-p-* attribute; (5) delete the inline <style>, the param-values comment, and both markers plus dead @scope rules. Then run node ${scriptsPath}/live-complete.mjs --id ${event.id} and verify phase "completed"; it refuses with source_dirty while leftovers remain. Poll again only after that.`;
120
+ }
121
+ if (result.handled === true) {
122
+ return `${prefix}Accept was merged into source mechanically; nothing to clean up. Poll again.`;
123
+ }
124
+ if (result.mode === 'fallback') {
125
+ return `${prefix}The session lived in a generated file, so accept refused to persist there. Write the accepted variant into the true source you identified during Handle fallback, remove the temporary wrapper from the served file, then poll again.`;
126
+ }
127
+ if (result.mode === 'error') {
128
+ if (result.error === 'source_locked') {
129
+ return `${prefix}The source file is briefly locked by a publisher. Re-run the exact same live-accept.mjs command (idempotent); do NOT hand-edit the file, and do not poll past this.`;
130
+ }
131
+ if (result.error === 'accept_receipt_conflict') {
132
+ return `${prefix}This session already resolved as ${result.priorOperation || 'a prior operation'}; do not edit anything. Run node ${scriptsPath}/live-status.mjs and tell the user what the session resolved to.`;
133
+ }
134
+ return `${prefix}Accept failed: ${result.error || 'unknown error'}. Source was not touched; do not hand-edit. Run node ${scriptsPath}/live-status.mjs before continuing.`;
135
+ }
136
+ return `${prefix}No mechanical accept result; read ${result.file || 'the session source file'}, find the impeccable markers, and finish the merge by hand. Poll again after.`;
137
+ }
138
+
139
+ /** Boot instructions attached to live.mjs's success payload. */
140
+ export function bootInstructions({ scriptsPath = '{{scripts_path}}' } = {}) {
141
+ return `Open the app URL that serves a pageFiles entry (never serverPort; that is the helper). Then start the poll loop per your harness policy in live.md and re-run ${pollCmd(scriptsPath)} immediately after every event or reply. Every event carries _instructions: follow them; they are the authoritative next step with real ids and paths filled in. A poll that is running is a poll you are SERVICING: never announce you are waiting and idle your turn; stay on the exec session until it returns an event, and never end a turn while a poll is outstanding.`;
142
+ }
@@ -0,0 +1,14 @@
1
+ export function eventPriority(event = {}) {
2
+ if (event.type === 'accept' || event.type === 'discard' || event.type === 'exit') return 0;
3
+ if (event.type === 'manual_edit_apply' || event.type === 'steer' || event.type === 'carbonize_cleanup') return 1;
4
+ if (event.type === 'generate') return 2;
5
+ return 3;
6
+ }
7
+
8
+ export function selectAvailablePendingEvent(entries, { now = Date.now(), types = null } = {}) {
9
+ const allowed = types instanceof Set ? types : (Array.isArray(types) ? new Set(types) : null);
10
+ return entries
11
+ .filter((entry) => !(entry.leaseUntil && entry.leaseUntil > now))
12
+ .filter((entry) => !allowed || allowed.has(entry.event?.type))
13
+ .sort((a, b) => eventPriority(a.event) - eventPriority(b.event) || a.seq - b.seq)[0] || null;
14
+ }