quiver-cli 0.6.0 → 0.7.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 (97) hide show
  1. package/LICENSE +21 -0
  2. package/dist/cli.js +125 -43
  3. package/package.json +1 -1
  4. package/template/.agents/skills/agent-browser/SKILL.md +4 -9
  5. package/template/.agents/skills/apps/skybridge/SKILL.md +1 -1
  6. package/template/.agents/skills/code/improve/SKILL.md +9 -5
  7. package/template/.agents/skills/code/improve/references/audit-playbook.md +10 -10
  8. package/template/.agents/skills/code/improve/references/closing-the-loop.md +4 -3
  9. package/template/.agents/skills/code/improve/references/plan-template.md +5 -0
  10. package/template/.agents/skills/design/impeccable/SKILL.md +14 -24
  11. package/template/.agents/skills/design/impeccable/reference/animate.md +1 -1
  12. package/template/.agents/skills/design/impeccable/reference/bolder.md +1 -1
  13. package/template/.agents/skills/design/impeccable/reference/brand.md +2 -2
  14. package/template/.agents/skills/design/impeccable/reference/colorize.md +1 -1
  15. package/template/.agents/skills/design/impeccable/reference/critique.md +6 -6
  16. package/template/.agents/skills/design/impeccable/reference/delight.md +1 -1
  17. package/template/.agents/skills/design/impeccable/reference/distill.md +1 -1
  18. package/template/.agents/skills/design/impeccable/reference/document.md +1 -1
  19. package/template/.agents/skills/design/impeccable/reference/extract.md +1 -1
  20. package/template/.agents/skills/design/impeccable/reference/hooks.md +90 -0
  21. package/template/.agents/skills/design/impeccable/reference/init.md +5 -5
  22. package/template/.agents/skills/design/impeccable/reference/live.md +16 -16
  23. package/template/.agents/skills/design/impeccable/reference/overdrive.md +1 -1
  24. package/template/.agents/skills/design/impeccable/reference/polish.md +2 -2
  25. package/template/.agents/skills/design/impeccable/reference/quieter.md +1 -1
  26. package/template/.agents/skills/design/impeccable/reference/shape.md +2 -2
  27. package/template/.agents/skills/design/impeccable/scripts/context-signals.mjs +1 -1
  28. package/template/.agents/skills/design/impeccable/scripts/context.mjs +724 -33
  29. package/template/.agents/skills/design/impeccable/scripts/critique-storage.mjs +1 -1
  30. package/template/.agents/skills/design/impeccable/scripts/detector/browser/injected/index.mjs +204 -0
  31. package/template/.agents/skills/design/impeccable/scripts/detector/cli/main.mjs +57 -11
  32. package/template/.agents/skills/design/impeccable/scripts/detector/design-system.mjs +750 -0
  33. package/template/.agents/skills/design/impeccable/scripts/detector/detect-antipatterns-browser.js +633 -46
  34. package/template/.agents/skills/design/impeccable/scripts/detector/detect-antipatterns.mjs +7 -0
  35. package/template/.agents/skills/design/impeccable/scripts/detector/engines/browser/detect-url.mjs +29 -4
  36. package/template/.agents/skills/design/impeccable/scripts/detector/engines/regex/detect-text.mjs +43 -10
  37. package/template/.agents/skills/design/impeccable/scripts/detector/engines/static-html/css-cascade.mjs +29 -0
  38. package/template/.agents/skills/design/impeccable/scripts/detector/engines/static-html/detect-html.mjs +27 -1
  39. package/template/.agents/skills/design/impeccable/scripts/detector/node/file-system.mjs +1 -1
  40. package/template/.agents/skills/design/impeccable/scripts/detector/registry/antipatterns.mjs +29 -0
  41. package/template/.agents/skills/design/impeccable/scripts/detector/rules/checks.mjs +401 -46
  42. package/template/.agents/skills/design/impeccable/scripts/detector/shared/inline-ignores.mjs +148 -0
  43. package/template/.agents/skills/design/impeccable/scripts/hook-admin.mjs +661 -0
  44. package/template/.agents/skills/design/impeccable/scripts/hook-before-edit.mjs +476 -0
  45. package/template/.agents/skills/design/impeccable/scripts/hook-lib.mjs +1632 -0
  46. package/template/.agents/skills/design/impeccable/scripts/hook.mjs +61 -0
  47. package/template/.agents/skills/design/impeccable/scripts/{design-parser.mjs → lib/design-parser.mjs} +8 -1
  48. package/template/.agents/skills/design/impeccable/scripts/lib/impeccable-config.mjs +638 -0
  49. package/template/.agents/skills/design/impeccable/scripts/lib/impeccable-paths.mjs +128 -0
  50. package/template/.agents/skills/design/impeccable/scripts/lib/target-args.mjs +42 -0
  51. package/template/.agents/skills/design/impeccable/scripts/live/browser-script-parts.mjs +49 -0
  52. package/template/.agents/skills/design/impeccable/scripts/{live-event-validation.mjs → live/event-validation.mjs} +6 -5
  53. package/template/.agents/skills/design/impeccable/scripts/live/manual-apply.mjs +939 -0
  54. package/template/.agents/skills/design/impeccable/scripts/live/manual-edit-routes.mjs +357 -0
  55. package/template/.agents/skills/design/impeccable/scripts/{live-manual-edits-buffer.mjs → live/manual-edits-buffer.mjs} +1 -1
  56. package/template/.agents/skills/design/impeccable/scripts/{live-session-store.mjs → live/session-store.mjs} +1 -1
  57. package/template/.agents/skills/design/impeccable/scripts/{live-ui-core.mjs → live/ui-core.mjs} +2 -1
  58. package/template/.agents/skills/design/impeccable/scripts/live/vocabulary.mjs +36 -0
  59. package/template/.agents/skills/design/impeccable/scripts/live-accept.mjs +3 -3
  60. package/template/.agents/skills/design/impeccable/scripts/live-browser-dom.js +146 -0
  61. package/template/.agents/skills/design/impeccable/scripts/live-browser.js +1456 -599
  62. package/template/.agents/skills/design/impeccable/scripts/live-commit-manual-edits.mjs +2 -2
  63. package/template/.agents/skills/design/impeccable/scripts/live-complete.mjs +2 -2
  64. package/template/.agents/skills/design/impeccable/scripts/live-discard-manual-edits.mjs +1 -1
  65. package/template/.agents/skills/design/impeccable/scripts/live-inject.mjs +35 -9
  66. package/template/.agents/skills/design/impeccable/scripts/live-insert.mjs +2 -2
  67. package/template/.agents/skills/design/impeccable/scripts/live-manual-edit-evidence.mjs +2 -2
  68. package/template/.agents/skills/design/impeccable/scripts/live-poll.mjs +18 -13
  69. package/template/.agents/skills/design/impeccable/scripts/live-resume.mjs +1 -1
  70. package/template/.agents/skills/design/impeccable/scripts/live-server.mjs +77 -1264
  71. package/template/.agents/skills/design/impeccable/scripts/live-status.mjs +2 -2
  72. package/template/.agents/skills/design/impeccable/scripts/live-target.mjs +30 -0
  73. package/template/.agents/skills/design/impeccable/scripts/live-wrap.mjs +4 -4
  74. package/template/.agents/skills/design/impeccable/scripts/live.mjs +73 -22
  75. package/template/.agents/skills/writing/humanizer/SKILL.md +621 -0
  76. package/template/.agents/upstreams.json +17 -8
  77. package/template/.agents/skills/apps/skybridge/references/architecture.md +0 -175
  78. package/template/.agents/skills/apps/skybridge/references/copy-template.md +0 -24
  79. package/template/.agents/skills/apps/skybridge/references/csp.md +0 -33
  80. package/template/.agents/skills/apps/skybridge/references/deploy.md +0 -33
  81. package/template/.agents/skills/apps/skybridge/references/discover.md +0 -84
  82. package/template/.agents/skills/apps/skybridge/references/download-file.md +0 -77
  83. package/template/.agents/skills/apps/skybridge/references/fetch-and-render-data.md +0 -151
  84. package/template/.agents/skills/apps/skybridge/references/oauth.md +0 -115
  85. package/template/.agents/skills/apps/skybridge/references/open-external-links.md +0 -71
  86. package/template/.agents/skills/apps/skybridge/references/prompt-llm.md +0 -20
  87. package/template/.agents/skills/apps/skybridge/references/publish.md +0 -19
  88. package/template/.agents/skills/apps/skybridge/references/run-locally.md +0 -51
  89. package/template/.agents/skills/apps/skybridge/references/state-and-context.md +0 -151
  90. package/template/.agents/skills/apps/skybridge/references/ui-guidelines.md +0 -205
  91. package/template/.agents/skills/design/impeccable/scripts/cleanup-deprecated.mjs +0 -284
  92. package/template/.agents/skills/design/impeccable/scripts/impeccable-paths.mjs +0 -126
  93. /package/template/.agents/skills/design/impeccable/scripts/{is-generated.mjs → lib/is-generated.mjs} +0 -0
  94. /package/template/.agents/skills/design/impeccable/scripts/{live-completion.mjs → live/completion.mjs} +0 -0
  95. /package/template/.agents/skills/design/impeccable/scripts/{live-insert-ui.mjs → live/insert-ui.mjs} +0 -0
  96. /package/template/.agents/skills/design/impeccable/scripts/{live-svelte-component.mjs → live/svelte-component.mjs} +0 -0
  97. /package/template/.agents/skills/design/impeccable/scripts/{live-sveltekit-adapter.mjs → live/sveltekit-adapter.mjs} +0 -0
@@ -16,8 +16,8 @@
16
16
  */
17
17
 
18
18
  import { buildManualEditEvidence } from './live-manual-edit-evidence.mjs';
19
- import { readBuffer, readBufferStrict, writeBuffer, countByPage } from './live-manual-edits-buffer.mjs';
20
- import { isGeneratedFile } from './is-generated.mjs';
19
+ import { readBuffer, readBufferStrict, writeBuffer, countByPage } from './live/manual-edits-buffer.mjs';
20
+ import { isGeneratedFile } from './lib/is-generated.mjs';
21
21
  import {
22
22
  runCopyEditBatchAgent,
23
23
  runCopyEditPostApplyChecks,
@@ -3,8 +3,8 @@
3
3
  * Canonical durable completion acknowledgement for Impeccable live sessions.
4
4
  */
5
5
 
6
- import { createLiveSessionStore } from './live-session-store.mjs';
7
- import { readLiveServerInfo } from './impeccable-paths.mjs';
6
+ import { createLiveSessionStore } from './live/session-store.mjs';
7
+ import { readLiveServerInfo } from './lib/impeccable-paths.mjs';
8
8
 
9
9
  function parseArgs(argv) {
10
10
  const out = { status: 'complete' };
@@ -16,7 +16,7 @@
16
16
  * Output JSON: { discarded: N, entries: [...discardedEntries], totalCount: N }
17
17
  */
18
18
 
19
- import { readBuffer, removeEntries, truncateBuffer } from './live-manual-edits-buffer.mjs';
19
+ import { readBuffer, removeEntries, truncateBuffer } from './live/manual-edits-buffer.mjs';
20
20
 
21
21
  function argVal(args, name) {
22
22
  const prefix = name + '=';
@@ -16,12 +16,12 @@
16
16
  import fs from 'node:fs';
17
17
  import path from 'node:path';
18
18
  import { fileURLToPath } from 'node:url';
19
- import { resolveLiveConfigPath } from './impeccable-paths.mjs';
19
+ import { resolveLiveConfigPath } from './lib/impeccable-paths.mjs';
20
20
  import {
21
21
  applySvelteKitLiveAdapter,
22
22
  detectSvelteKitProject,
23
23
  removeSvelteKitLiveAdapter,
24
- } from './live-sveltekit-adapter.mjs';
24
+ } from './live/sveltekit-adapter.mjs';
25
25
 
26
26
  const __dirname = path.dirname(fileURLToPath(import.meta.url));
27
27
  const CONFIG_PATH = resolveLiveConfigPath({ cwd: process.cwd(), scriptsDir: __dirname });
@@ -32,6 +32,8 @@ const IGNORE_MARKER_CLOSE = '# impeccable-live-ignore-end';
32
32
 
33
33
  export const LIVE_IGNORE_PATTERNS = Object.freeze([
34
34
  '.impeccable/hook.cache.json',
35
+ '.impeccable/hook.pending.json',
36
+ '.impeccable/config.local.json',
35
37
  '.impeccable/live/server.json',
36
38
  '.impeccable/live/sessions/',
37
39
  '.impeccable/live/previews/',
@@ -368,8 +370,26 @@ function buildTagBlock(syntax, port, filePath) {
368
370
  );
369
371
  }
370
372
 
373
+ function detectLineEnding(content) {
374
+ if (content.includes('\r\n')) return '\r\n';
375
+ if (content.includes('\r')) return '\r';
376
+ return '\n';
377
+ }
378
+
379
+ function normalizeLineEndings(content, lineEnding) {
380
+ return lineEnding === '\n' ? content : content.replace(/\n/g, lineEnding);
381
+ }
382
+
383
+ function readLineEndingAt(content, index) {
384
+ if (content[index] === '\r' && content[index + 1] === '\n') return '\r\n';
385
+ if (content[index] === '\n') return '\n';
386
+ if (content[index] === '\r') return '\r';
387
+ return '';
388
+ }
389
+
371
390
  function insertTag(content, config, port, filePath) {
372
- const block = buildTagBlock(config.commentSyntax, port, filePath);
391
+ const lineEnding = detectLineEnding(content);
392
+ const block = normalizeLineEndings(buildTagBlock(config.commentSyntax, port, filePath), lineEnding);
373
393
  // insertBefore: match the LAST occurrence. Anchors like `</body>` naturally
374
394
  // belong at the end, and the same literal can appear earlier in code blocks
375
395
  // within rendered documentation pages.
@@ -383,9 +403,15 @@ function insertTag(content, config, port, filePath) {
383
403
  const idx = content.indexOf(config.insertAfter);
384
404
  if (idx === -1) return content;
385
405
  const after = idx + config.insertAfter.length;
386
- // Preserve a single trailing newline if the anchor didn't end with one
387
- const prefix = content[after] === '\n' ? content.slice(0, after + 1) : content.slice(0, after) + '\n';
388
- return prefix + block + content.slice(prefix.length);
406
+ // Preserve an existing trailing newline if the anchor already has one.
407
+ // Slice the remainder from the original anchor offset, not prefix.length:
408
+ // in the no-newline case prefix is one char longer than the anchor (the
409
+ // appended '\n'), so slicing by prefix.length would drop the first real
410
+ // character after the anchor (#227).
411
+ const existingNewline = readLineEndingAt(content, after);
412
+ const prefix = content.slice(0, after) + (existingNewline || lineEnding);
413
+ const rest = content.slice(after + existingNewline.length);
414
+ return prefix + block + rest;
389
415
  }
390
416
 
391
417
  /**
@@ -401,8 +427,8 @@ function insertTag(content, config, port, filePath) {
401
427
  */
402
428
  function removeTag(content, _syntax) {
403
429
  const patterns = [
404
- /([ \t]*)<!--\s*impeccable-live-start\s*-->[\s\S]*?<!--\s*impeccable-live-end\s*-->([ \t]*(?:\n|$)?)/,
405
- /([ \t]*)\{\/\*\s*impeccable-live-start\s*\*\/\}[\s\S]*?\{\/\*\s*impeccable-live-end\s*\*\/\}([ \t]*(?:\n|$)?)/,
430
+ /([ \t]*)<!--\s*impeccable-live-start\s*-->[\s\S]*?<!--\s*impeccable-live-end\s*-->([ \t]*(?:\r\n|\n|\r|$)?)/,
431
+ /([ \t]*)\{\/\*\s*impeccable-live-start\s*\*\/\}[\s\S]*?\{\/\*\s*impeccable-live-end\s*\*\/\}([ \t]*(?:\r\n|\n|\r|$)?)/,
406
432
  ];
407
433
  for (const pat of patterns) {
408
434
  let changed = false;
@@ -410,7 +436,7 @@ function removeTag(content, _syntax) {
410
436
  do {
411
437
  content = next;
412
438
  next = content.replace(pat, (_match, leadingIndent, trailing = '') => {
413
- if (trailing.includes('\n')) return leadingIndent;
439
+ if (/[\r\n]/.test(trailing)) return leadingIndent;
414
440
  return leadingIndent || trailing || '';
415
441
  });
416
442
  if (next !== content) changed = true;
@@ -9,7 +9,7 @@
9
9
 
10
10
  import fs from 'node:fs';
11
11
  import path from 'node:path';
12
- import { isGeneratedFile } from './is-generated.mjs';
12
+ import { isGeneratedFile } from './lib/is-generated.mjs';
13
13
  import {
14
14
  buildSearchQueries,
15
15
  findElement,
@@ -25,7 +25,7 @@ import {
25
25
  buildSvelteComponentCssAuthoring,
26
26
  scaffoldSvelteComponentInsertSession,
27
27
  shouldUseSvelteComponentInjection,
28
- } from './live-svelte-component.mjs';
28
+ } from './live/svelte-component.mjs';
29
29
 
30
30
  const INSERT_POSITIONS = new Set(['before', 'after']);
31
31
 
@@ -10,8 +10,8 @@
10
10
 
11
11
  import fs from 'node:fs';
12
12
  import path from 'node:path';
13
- import { isGeneratedFile } from './is-generated.mjs';
14
- import { readBuffer, getBufferPath } from './live-manual-edits-buffer.mjs';
13
+ import { isGeneratedFile } from './lib/is-generated.mjs';
14
+ import { readBuffer, getBufferPath } from './live/manual-edits-buffer.mjs';
15
15
 
16
16
  const EVIDENCE_VERSION = 1;
17
17
  const TEXT_EXTENSIONS = new Set(['.html', '.jsx', '.tsx', '.vue', '.svelte', '.astro', '.js', '.mjs', '.ts']);
@@ -2,18 +2,23 @@
2
2
  * CLI client for the live variant mode poll/reply protocol.
3
3
  *
4
4
  * Usage:
5
- * npx impeccable poll # Block until browser event, print JSON
6
- * npx impeccable poll --stream # Experimental: keep polling; one JSON line per event
7
- * npx impeccable poll --timeout=600000 # Custom timeout (ms); default is long-poll friendly
8
- * npx impeccable poll --reply <id> done # Reply "done" to event <id>
9
- * npx impeccable poll --reply <id> error "msg" # Reply with error
5
+ * node <scripts_path>/live-poll.mjs # Block until browser event, print JSON
6
+ * node <scripts_path>/live-poll.mjs --stream # Experimental: keep polling; one JSON line per event
7
+ * node <scripts_path>/live-poll.mjs --timeout=600000 # Custom timeout (ms); default is long-poll friendly
8
+ * node <scripts_path>/live-poll.mjs --reply <id> done # Reply "done" to event <id>
9
+ * node <scripts_path>/live-poll.mjs --reply <id> error "msg" # Reply with error
10
10
  */
11
11
 
12
12
  import { execFileSync } from 'node:child_process';
13
13
  import path from 'node:path';
14
14
  import { fileURLToPath } from 'node:url';
15
- import { completionAckForAcceptResult, completionTypeForAcceptResult } from './live-completion.mjs';
16
- import { readLiveServerInfo } from './impeccable-paths.mjs';
15
+ import { completionAckForAcceptResult, completionTypeForAcceptResult } from './live/completion.mjs';
16
+ import { readLiveServerInfo } from './lib/impeccable-paths.mjs';
17
+
18
+ // Absolute path to a sibling script in this skill's scripts dir, so runtime
19
+ // error hints print a directly-runnable command instead of a placeholder.
20
+ const SELF_DIR = path.dirname(fileURLToPath(import.meta.url));
21
+ const scriptCmd = (name) => `node "${path.join(SELF_DIR, name)}"`;
17
22
 
18
23
  // Node's built-in fetch (undici under the hood) enforces a 300s headers
19
24
  // timeout that can't be lowered per-request. We cap each request below
@@ -27,7 +32,7 @@ const EVENT_TYPES_NEEDING_AGENT_REPLY = new Set(['generate', 'steer', 'manual_ed
27
32
  function readServerInfo() {
28
33
  const record = readLiveServerInfo(process.cwd());
29
34
  if (!record) {
30
- console.error('No running live server found. Start one with: npx impeccable live');
35
+ console.error(`No running live server found. Start one with: ${scriptCmd('live.mjs')}`);
31
36
  process.exit(1);
32
37
  }
33
38
  return record.info;
@@ -82,7 +87,7 @@ export function parseReplyArgs(args) {
82
87
  }
83
88
 
84
89
  function validateReplyArgs({ id, status }) {
85
- const usage = "Usage: npx impeccable poll --reply <id> <status> [--file path] [--data '<json>'] [message]";
90
+ const usage = `Usage: ${scriptCmd('live-poll.mjs')} --reply <id> <status> [--file path] [--data '<json>'] [message]`;
86
91
  if (!id || id.startsWith('--')) {
87
92
  const err = new Error(`${usage}\nMissing event id after --reply.`);
88
93
  err.code = 'INVALID_REPLY_ARGS';
@@ -283,11 +288,11 @@ export async function runPollStream(base, token, {
283
288
  function handlePollError(err) {
284
289
  if (err.code === 'AUTH_FAILED') {
285
290
  console.error(err.message);
286
- console.error('Try restarting: npx impeccable live stop && npx impeccable live');
291
+ console.error(`Try restarting: ${scriptCmd('live-server.mjs')} stop && ${scriptCmd('live.mjs')}`);
287
292
  process.exit(1);
288
293
  }
289
294
  if (err.cause?.code === 'ECONNREFUSED') {
290
- console.error('Live server not running. Start one with: npx impeccable live');
295
+ console.error(`Live server not running. Start one with: ${scriptCmd('live.mjs')}`);
291
296
  process.exit(1);
292
297
  }
293
298
  if (err.code === 'ACK_TIMEOUT') {
@@ -331,7 +336,7 @@ Harness note:
331
336
  const info = readServerInfo();
332
337
  const base = `http://localhost:${info.port}`;
333
338
 
334
- // Reply mode: npx impeccable poll --reply <id> <status> [--file path] [--data '<json>'] [message]
339
+ // Reply mode: node <scripts_path>/live-poll.mjs --reply <id> <status> [--file path] [--data '<json>'] [message]
335
340
  if (args.includes('--reply')) {
336
341
  let reply;
337
342
  try {
@@ -345,7 +350,7 @@ Harness note:
345
350
  await postReply(base, info.token, reply);
346
351
  } catch (err) {
347
352
  if (err.cause?.code === 'ECONNREFUSED') {
348
- console.error('Live server not running. Start one with: npx impeccable live');
353
+ console.error(`Live server not running. Start one with: ${scriptCmd('live.mjs')}`);
349
354
  } else {
350
355
  console.error('Reply failed:', err.message);
351
356
  }
@@ -3,7 +3,7 @@
3
3
  * Recover the next agent action from the durable live-session journal.
4
4
  */
5
5
 
6
- import { createLiveSessionStore } from './live-session-store.mjs';
6
+ import { createLiveSessionStore } from './live/session-store.mjs';
7
7
 
8
8
  function manualApplyReplyCommand(eventOrId = 'EVENT_ID') {
9
9
  const id = typeof eventOrId === 'string' ? eventOrId : eventOrId?.id || 'EVENT_ID';