codebay 0.5.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 (114) hide show
  1. package/.mochi/manifest.json +286 -227
  2. package/.mochi/svelte-client/HydratableIsland-qyjx1d98.js +1 -0
  3. package/.mochi/svelte-client/_hydrate-AppShell_2rtnxn6pgp2rh-fkna7bj2.js +2 -0
  4. package/.mochi/svelte-client/_hydrate-AvatarsView_257s9yq1wwr4f-89wtkb86.js +13 -0
  5. package/.mochi/svelte-client/_hydrate-InstanceView_2ma45l9bybfhl-eamnbyqk.js +1 -0
  6. package/.mochi/svelte-client/{_hydrate-SettingsView_8hmarwmf8onq-r9vvc7rx.js → _hydrate-SettingsView_8hmarwmf8onq-kdra4mcb.js} +3 -3
  7. package/.mochi/svelte-client/chunk-330mrspw.js +2 -0
  8. package/.mochi/svelte-client/{chunk-dz1019cy.js → chunk-4jgkak13.js} +1 -1
  9. package/.mochi/svelte-client/chunk-fqg2qzj8.js +2 -0
  10. package/.mochi/svelte-client/chunk-k5m4kt20.js +2 -0
  11. package/.mochi/svelte-client/{chunk-nmf4dq86.js → chunk-qj7zy2d9.js} +1 -1
  12. package/.mochi/svelte-client/{chunk-ssa0ad2f.js → chunk-rpdphch7.js} +1 -1
  13. package/.mochi/svelte-compile/{App-9qjy14bc.server.js → App-6rcf0d74.server.js} +113 -46
  14. package/.mochi/svelte-compile/{Avatars-sq8mjn6k.server.js → Avatars-pzyz0tv3.server.js} +75 -15
  15. package/.mochi/svelte-compile/{Instance-13j59daw.server.js → Instance-49ksrp11.server.js} +15 -3
  16. package/.mochi/svelte-compile/{Settings-p0s2awg1.server.js → Settings-sz5d6qj7.server.js} +3 -3
  17. package/.mochi/svelte-compile/{chunk-dfe2km6a.js → chunk-q8rbesaw.js} +324 -123
  18. package/.mochi/svelte-css/Avatar-3pi30db6ozvf0.css +1 -0
  19. package/.mochi/svelte-css/AvatarEditor-2ewwtejaml4e2.css +1 -0
  20. package/.mochi/svelte-css/{AvatarsView-3hq37u4dgtljn.css → AvatarsView-2ughbzc26luyb.css} +1 -1
  21. package/.mochi/svelte-css/InstanceCard-3vnltxnbxkvay.css +1 -0
  22. package/.mochi/svelte-css/InstanceFilter-3q6x0jt0hcgpz.css +1 -0
  23. package/.mochi/svelte-css/{InstanceView-wq85bxtusont.css → InstanceView-3vzow3ttxzlh3.css} +1 -1
  24. package/README.md +2 -0
  25. package/package.json +2 -2
  26. package/src/avatars/anchor.ts +1 -0
  27. package/src/avatars/ant-head.ts +17 -0
  28. package/src/avatars/apple.ts +17 -0
  29. package/src/avatars/bear.ts +1 -0
  30. package/src/avatars/bee.ts +1 -0
  31. package/src/avatars/bodybuilder.ts +17 -0
  32. package/src/avatars/cat.ts +1 -0
  33. package/src/avatars/cherry.ts +1 -0
  34. package/src/avatars/crab.ts +1 -0
  35. package/src/avatars/crown.ts +1 -0
  36. package/src/avatars/diamond.ts +1 -0
  37. package/src/avatars/dog.ts +1 -0
  38. package/src/avatars/editor.ts +17 -0
  39. package/src/avatars/fish.ts +1 -0
  40. package/src/avatars/flower.ts +1 -0
  41. package/src/avatars/fox.ts +1 -0
  42. package/src/avatars/frog.ts +1 -0
  43. package/src/avatars/ghost.ts +1 -0
  44. package/src/avatars/heart.ts +8 -8
  45. package/src/avatars/horse.ts +17 -0
  46. package/src/avatars/index.ts +20 -0
  47. package/src/avatars/invader.ts +1 -0
  48. package/src/avatars/key.ts +1 -0
  49. package/src/avatars/lightning.ts +1 -0
  50. package/src/avatars/mushroom.ts +1 -0
  51. package/src/avatars/octopus.ts +1 -0
  52. package/src/avatars/owl.ts +1 -0
  53. package/src/avatars/penguin.ts +1 -0
  54. package/src/avatars/planet.ts +1 -0
  55. package/src/avatars/praying-mantis.ts +17 -0
  56. package/src/avatars/rabbit.ts +1 -0
  57. package/src/avatars/robot.ts +1 -0
  58. package/src/avatars/rocket.ts +1 -0
  59. package/src/avatars/serialize.ts +4 -3
  60. package/src/avatars/skull.ts +6 -6
  61. package/src/avatars/snail.ts +1 -0
  62. package/src/avatars/snowflake.ts +17 -0
  63. package/src/avatars/star.ts +1 -0
  64. package/src/avatars/strawberry.ts +17 -0
  65. package/src/avatars/target.ts +1 -0
  66. package/src/avatars/tree.ts +1 -0
  67. package/src/avatars/types.ts +6 -3
  68. package/src/avatars/vangogh-almond-blossoms.ts +17 -0
  69. package/src/avatars/wasp.ts +17 -0
  70. package/src/avatars/whale.ts +1 -0
  71. package/src/avatars/windmill.ts +17 -0
  72. package/src/components/AppShell.svelte +13 -0
  73. package/src/components/Avatar.svelte +4 -1
  74. package/src/components/AvatarEditor.svelte +83 -5
  75. package/src/components/AvatarsView.svelte +14 -1
  76. package/src/components/DashboardView.svelte +39 -4
  77. package/src/components/InstanceCard.svelte +55 -6
  78. package/src/components/InstanceFilter.svelte +68 -0
  79. package/src/components/InstanceView.svelte +41 -8
  80. package/src/components/SettingsView.svelte +2 -2
  81. package/src/components/TopBar.svelte +9 -1
  82. package/src/container-injections/attention-hooks.ts +19 -38
  83. package/src/container-injections/claude-aliases.ts +7 -23
  84. package/src/container-injections/claude-code-credentials.ts +12 -8
  85. package/src/container-injections/claude-code-custom.ts +35 -48
  86. package/src/container-injections/claude-code-ide-extension.ts +39 -0
  87. package/src/container-injections/claude-code-models.ts +8 -24
  88. package/src/container-injections/claude-model.ts +5 -28
  89. package/src/container-injections/claude-no-coauthor.ts +5 -17
  90. package/src/container-injections/claude-skip-permissions.ts +7 -17
  91. package/src/container-injections/claude-statusline.ts +16 -18
  92. package/src/container-injections/claude-trust.ts +73 -0
  93. package/src/container-injections/host-env-vars.ts +13 -24
  94. package/src/container-injections/tmux.ts +2 -11
  95. package/src/index.ts +2 -0
  96. package/src/lib/claude-settings.server.ts +35 -0
  97. package/src/lib/container-files.server.ts +219 -0
  98. package/src/lib/devcontainer.server.ts +38 -1
  99. package/src/lib/exec.server.ts +2 -7
  100. package/src/lib/injections.server.ts +4 -0
  101. package/src/lib/instances.server.ts +14 -0
  102. package/src/lib/theme.server.ts +7 -3
  103. package/src/shell.html +2 -0
  104. package/src/types.ts +3 -0
  105. package/.mochi/svelte-client/HydratableIsland-79z9xq4b.js +0 -1
  106. package/.mochi/svelte-client/_hydrate-AppShell_2rtnxn6pgp2rh-f5rzyjm8.js +0 -2
  107. package/.mochi/svelte-client/_hydrate-AvatarsView_257s9yq1wwr4f-fxyd5qx4.js +0 -13
  108. package/.mochi/svelte-client/_hydrate-InstanceView_2ma45l9bybfhl-nv31ptdp.js +0 -1
  109. package/.mochi/svelte-client/chunk-6eexkr6p.js +0 -2
  110. package/.mochi/svelte-client/chunk-7znwaf7t.js +0 -2
  111. package/.mochi/svelte-client/chunk-zmmb1c4b.js +0 -2
  112. package/.mochi/svelte-css/Avatar-24th63awm9mna.css +0 -1
  113. package/.mochi/svelte-css/AvatarEditor-1ryrs1md5g36y.css +0 -1
  114. package/.mochi/svelte-css/InstanceCard-16f77aysm7lgp.css +0 -1
@@ -0,0 +1 @@
1
+ .avatar.svelte-1pre9qb{display:grid;grid-template-columns:repeat(10,1fr);grid-template-rows:repeat(10,1fr);border:1px solid var(--ink);background:var(--bg);flex:none}.px.svelte-1pre9qb{box-sizing:border-box;padding:0 var(--gap)var(--gap)0;background-clip:content-box;background-color:var(--rule-soft)}.px.gray.svelte-1pre9qb{background-color:var(--led-gray)}.px.on.svelte-1pre9qb{background-color:var(--ink)}@property --hue{syntax:"<angle>";inherits:false;initial-value:0deg}@property --spin{syntax:"<angle>";inherits:false;initial-value:0deg}.avatar.interactive.svelte-1pre9qb{position:relative;cursor:pointer;touch-action:none}.invert.svelte-1pre9qb{position:absolute;pointer-events:none;opacity:0;mix-blend-mode:difference;-webkit-mask:radial-gradient(circle at var(--bx)var(--by),#000 0%,#000000eb 24%,#0000 58%);mask:radial-gradient(circle at var(--bx)var(--by),#000 0%,#000000eb 24%,#0000 58%);background:#fff;inset:0}.avatar.pressed.svelte-1pre9qb .invert:where(.svelte-1pre9qb){opacity:1}.avatar.ghosting.svelte-1pre9qb .invert:where(.svelte-1pre9qb){opacity:0;transition:opacity .25s ease-out}.bloom.svelte-1pre9qb{position:absolute;pointer-events:none;opacity:0;mix-blend-mode:screen;filter:hue-rotate(var(--hue,0deg));background:conic-gradient(from var(--spin,0deg)at var(--bx)var(--by),#ff0080,#ffae00,#00ff6a,#00b3ff,#7a00ff,#ff0080),radial-gradient(circle at var(--bx)var(--by),#0d0e0ad9 0%,#0d0e0a66 18%,transparent 45%);-webkit-mask:radial-gradient(circle at var(--bx)var(--by),transparent 8%,#000 26%,#000 38%,transparent 60%);mask:radial-gradient(circle at var(--bx)var(--by),transparent 8%,#000 26%,#000 38%,transparent 60%);transition:--hue .35s ease-out,--spin .35s ease-out;inset:0}.avatar.pressed.svelte-1pre9qb .bloom:where(.svelte-1pre9qb){opacity:.45}.avatar.ghosting.svelte-1pre9qb .bloom:where(.svelte-1pre9qb){opacity:0;transition:opacity .25s ease-out}@media (prefers-reduced-motion:no-preference){.avatar.interactive.svelte-1pre9qb{transition:transform .25s ease-out}.avatar.pressed.svelte-1pre9qb{transition:transform 60ms ease-out;transform:scale(.97)}}
@@ -0,0 +1 @@
1
+ .editor.svelte-qu6vp4{display:flex;background:var(--bg-card);border:1px solid var(--rule);overflow:hidden;flex-direction:column;width:100%}.head.svelte-qu6vp4{display:flex;border-bottom:1px solid var(--ink);background:var(--ink);align-items: center;padding:14px 18px}.head.svelte-qu6vp4 h2:where(.svelte-qu6vp4){font-family:var(--font-display);text-transform:uppercase;letter-spacing:.06em;color:var(--bg);margin:0;font-size:17px;font-weight:700}.body.svelte-qu6vp4{display:flex;flex-wrap:wrap;gap:18px;padding:18px}.grid-frame.svelte-qu6vp4{display:grid;grid-template-columns:repeat(10,40px);grid-template-rows:repeat(10,40px);border:1px solid var(--ink);background:var(--bg);flex:none;width:400px;height:400px}.ring-cell.svelte-qu6vp4{box-sizing:border-box;background-clip:content-box;background-color:var(--rule-soft);opacity:.4;padding:0 1px 1px 0}.grid.svelte-qu6vp4{display:grid;grid-template-columns:repeat(8,1fr);grid-template-rows:repeat(8,1fr);grid-column:2/10;grid-row:2/10;cursor:crosshair;touch-action:none}.cell.svelte-qu6vp4{box-sizing:border-box;background-clip:content-box;background-color:var(--rule-soft);padding:0 1px 1px 0}.cell.gray.svelte-qu6vp4{background-color:var(--led-gray)}.cell.on.svelte-qu6vp4{background-color:var(--ink)}.side.svelte-qu6vp4{display:flex;flex-direction:column;flex:1;gap:16px;min-width:160px}.preview-label.svelte-qu6vp4{text-transform:uppercase;letter-spacing:.06em;color:var(--ink-faint);font-size:11px;font-family:var(--font-mono)}.preview-row.svelte-qu6vp4{display:flex;align-items: flex-end;gap:10px;margin-top:6px}.name-field.svelte-qu6vp4{display:flex;flex-direction:column;gap:6px}.name-field.svelte-qu6vp4 input:where(.svelte-qu6vp4){font-family:var(--font-mono);border:1px solid var(--ink);background:var(--bg);color:var(--ink);padding:8px 12px;font-size:13px}.name-field.svelte-qu6vp4 input:where(.svelte-qu6vp4)::placeholder{color:var(--ink-faint)}.name-field.svelte-qu6vp4 input:where(.svelte-qu6vp4):focus{outline:none;box-shadow:inset 3px 3px 0 var(--rule-soft)}.mode-field.svelte-qu6vp4{display:flex;flex-direction:column;gap:6px}.modes.svelte-qu6vp4{display:flex;border:1px solid var(--ink)}.mode.svelte-qu6vp4{border:none;border-right:1px solid var(--ink);background:var(--bg);color:var(--ink);font-family:var(--font-mono);text-transform:uppercase;letter-spacing:.06em;cursor:pointer;flex:1;padding:7px 6px;font-size:11px}.mode.svelte-qu6vp4:last-child{border-right:none}.mode.active.svelte-qu6vp4{background:var(--ink);color:var(--bg)}.mode.svelte-qu6vp4:focus-visible{outline:none;box-shadow:inset 0 0 0 2px var(--rule-soft)}.tools.svelte-qu6vp4{display:flex;gap:8px}.foot.svelte-qu6vp4{display:flex;border-top:1px solid var(--ink);flex-wrap:wrap;justify-content:space-between;align-items: center;gap:12px;padding:14px 18px}.hint.svelte-qu6vp4{font-family:var(--font-mono);color:var(--ink-faint);flex:1;min-width:180px;font-size:12px}.actions.svelte-qu6vp4{display:flex;gap:8px}.actions.svelte-qu6vp4 .btn{white-space:nowrap}
@@ -1 +1 @@
1
- .page.svelte-fkq7sr{display:flex;flex-direction:column;min-height:100vh}.title.svelte-fkq7sr{display:inline-flex;font-family:var(--font-mono);text-transform:uppercase;letter-spacing:.08em;color:var(--ink-soft);align-items: center;padding:0 14px;font-size:12px}.content.svelte-fkq7sr{display:flex;flex-direction:column;flex:1;align-items: center;gap:24px;padding:32px 20px}.content.svelte-fkq7sr>*{width:100%;max-width:720px}.catalog.svelte-fkq7sr{background:var(--bg-card);border:1px solid var(--rule);padding:18px}.catalog.svelte-fkq7sr header:where(.svelte-fkq7sr){margin-bottom:20px}.catalog.svelte-fkq7sr h2:where(.svelte-fkq7sr){font-family:var(--font-display);text-transform:uppercase;letter-spacing:.06em;margin:0;font-size:17px;font-weight:700}.catalog.svelte-fkq7sr header:where(.svelte-fkq7sr) p:where(.svelte-fkq7sr){font-family:var(--font-mono);color:var(--ink-soft);margin:4px 0 0;font-size:12px}ul.svelte-fkq7sr{list-style:none;display:grid;grid-template-columns:repeat(auto-fill,minmax(110px,1fr));gap:20px;margin:0;padding:0}li.svelte-fkq7sr{display:flex;flex-direction:column;align-items: center;gap:8px}.label.svelte-fkq7sr{font-family:var(--font-mono);text-transform:uppercase;letter-spacing:.08em;color:var(--ink-soft);font-size:11px}
1
+ .page.svelte-fkq7sr{display:flex;flex-direction:column;min-height:100vh}.title.svelte-fkq7sr{display:inline-flex;font-family:var(--font-mono);text-transform:uppercase;letter-spacing:.08em;color:var(--ink-soft);align-items: center;padding:0 14px;font-size:12px}.content.svelte-fkq7sr{display:flex;flex-direction:column;flex:1;align-items: center;gap:24px;padding:32px 20px}.content.svelte-fkq7sr>*{width:100%;max-width:720px}.catalog.svelte-fkq7sr{background:var(--bg-card);border:1px solid var(--rule);padding:18px}.catalog.svelte-fkq7sr header:where(.svelte-fkq7sr){margin-bottom:20px}.catalog.svelte-fkq7sr h2:where(.svelte-fkq7sr){font-family:var(--font-display);text-transform:uppercase;letter-spacing:.06em;margin:0;font-size:17px;font-weight:700}.catalog.svelte-fkq7sr header:where(.svelte-fkq7sr) p:where(.svelte-fkq7sr){font-family:var(--font-mono);color:var(--ink-soft);margin:4px 0 0;font-size:12px}ul.svelte-fkq7sr{list-style:none;display:grid;grid-template-columns:repeat(auto-fill,minmax(110px,1fr));gap:20px;margin:0;padding:0}li.svelte-fkq7sr{display:flex;flex-direction:column;align-items: center;gap:8px}.label.svelte-fkq7sr{display:inline-flex;font-family:var(--font-mono);text-transform:uppercase;letter-spacing:.08em;color:var(--ink-soft);align-items: center;gap:4px;font-size:11px}.robot-mark.svelte-fkq7sr{display:inline-flex;color:var(--ink-faint)}
@@ -0,0 +1 @@
1
+ .card.svelte-13338y7{position:relative;background:var(--bg-card);padding:16px 16px 14px;transition:transform 80ms steps(2,end),box-shadow 80ms steps(2,end)}.card.svelte-13338y7:hover:not(.busy){box-shadow:6px 6px 0 var(--ink);transform:translate(-1px,-1px)}.busy-overlay.svelte-13338y7{position:absolute;z-index:1;display:flex;background:color-mix(in srgb,var(--bg-card)78%,transparent);justify-content:center;align-items: center;inset:0}.busy-label.svelte-13338y7{font-family:var(--font-mono);text-transform:uppercase;letter-spacing:.1em;border:1px solid var(--ink);background:var(--ink);color:var(--bg);animation:svelte-13338y7-lcd-blink 1.1s steps(1)infinite;padding:4px 9px;font-size:12px;font-weight:600}@keyframes svelte-13338y7-lcd-blink{50%{background:0 0;color:var(--ink)}}@media (prefers-reduced-motion:reduce){.busy-label.svelte-13338y7{animation:none}}.card-head.svelte-13338y7{display:flex;align-items: center;gap:11px}.attn.svelte-13338y7{border:1px solid var(--ink);flex:none;width:14px;height:14px}.attn.attn-done.svelte-13338y7{background:var(--attn-done);animation:svelte-13338y7-card-attn-pulse 1.4s ease-in-out infinite}.attn.attn-waiting.svelte-13338y7{background:var(--attn-waiting);animation:svelte-13338y7-card-attn-pulse 1.4s ease-in-out infinite}@keyframes svelte-13338y7-card-attn-pulse{0%,to{box-shadow:0 0 #0000;filter:brightness(.85)}50%{box-shadow:0 0 7px 2px color-mix(in srgb,currentColor 60%,transparent);filter:brightness(1.15)}}.attn.attn-done.svelte-13338y7{color:var(--attn-done)}.attn.attn-waiting.svelte-13338y7{color:var(--attn-waiting)}@media (prefers-reduced-motion:reduce){.attn.svelte-13338y7{animation:none;filter:none}}.name.svelte-13338y7{font-family:var(--font-mono);overflow-wrap:anywhere;color:var(--ink);text-align:left;cursor:pointer;background:0 0;border:1px solid #0000;flex:1;min-width:0;margin:0;padding:2px 4px;font-size:15px;font-weight:600}.name.svelte-13338y7:hover{border-color:var(--ink-faint)}.name-edit.svelte-13338y7{font-family:var(--font-mono);border:1px solid var(--ink);background:var(--bg);color:var(--ink);outline:none;flex:1;min-width:0;margin:0;padding:2px 4px;font-size:15px;font-weight:600}.path.svelte-13338y7{font-family:var(--font-mono);color:var(--ink-soft);overflow:hidden;text-overflow:ellipsis;white-space:nowrap;margin-top:10px;font-size:12px}.card-error.svelte-13338y7{font-family:var(--font-mono);color:var(--ink);background:var(--bg);border:1px solid var(--ink);overflow:auto;max-height:80px;margin-top:10px;padding:8px 10px;font-size:12px}.actions.svelte-13338y7{display:flex;flex-wrap:wrap;gap:8px;margin-top:16px}
@@ -0,0 +1 @@
1
+ .picker.svelte-12yor8r{display:inline-flex;border:1px solid var(--ink);background:var(--bg-card);flex:none}.segment.svelte-12yor8r{display:inline-flex;font-family:var(--font-mono);text-transform:uppercase;letter-spacing:.06em;color:var(--ink);cursor:pointer;background:0 0;border:none;align-items: center;gap:6px;padding:7px 12px;font-size:12px;font-weight:600}.segment.svelte-12yor8r+.segment:where(.svelte-12yor8r){border-left:1px solid var(--ink)}.segment.svelte-12yor8r:hover:not(.active){background:var(--ink);color:var(--bg)}.segment.active.svelte-12yor8r{background:var(--ink);color:var(--bg);cursor:default;font-weight:700}.segment.svelte-12yor8r:focus-visible{outline:2px solid var(--ink);outline-offset:-2px}
@@ -1 +1 @@
1
- .topbar.svelte-15fxkvm{display:flex;border-bottom:1px solid var(--rule);align-items: center;gap:18px;padding:16px 24px}.back.svelte-15fxkvm{display:inline-flex;font-family:var(--font-mono);text-transform:uppercase;letter-spacing:.06em;color:var(--ink-soft);text-decoration:none;align-items: center;gap:5px;font-size:12px}.back.svelte-15fxkvm:hover{color:var(--ink)}.title.svelte-15fxkvm{display:flex;flex:1;align-items: center;gap:12px}.name.svelte-15fxkvm{font-family:var(--font-display);text-transform:uppercase;letter-spacing:.03em;font-size:20px;font-weight:700}.open.svelte-15fxkvm{display:inline-flex;font-family:var(--font-mono);text-transform:uppercase;letter-spacing:.06em;color:var(--ink);text-decoration:none;border:1px solid var(--ink);align-items: center;gap:6px;padding:7px 12px;font-size:12px;font-weight:600}.open.svelte-15fxkvm:hover{background:var(--ink);color:var(--bg)}.restart.svelte-15fxkvm{display:inline-flex;font-family:var(--font-mono);text-transform:uppercase;letter-spacing:.06em;color:var(--ink);background:var(--bg);border:1px solid var(--ink);cursor:pointer;align-items: center;gap:6px;padding:7px 12px;font-size:12px;font-weight:600}.restart.svelte-15fxkvm:hover:not(:disabled){background:var(--ink);color:var(--bg)}.restart.svelte-15fxkvm:disabled{opacity:.5;cursor:not-allowed}.restart-err.svelte-15fxkvm{font-family:var(--font-mono);color:var(--danger);margin:0;padding:8px 24px 0;font-size:12px}.stage.svelte-15fxkvm{max-width:1200px;margin:0 auto;padding:20px 24px 40px}.meta.svelte-15fxkvm{display:grid;grid-template-columns:max-content 1fr;align-items: center;gap:6px 14px;margin-bottom:18px}.meta.svelte-15fxkvm .k:where(.svelte-15fxkvm){font-family:var(--font-display);letter-spacing:.14em;text-transform:uppercase;color:var(--ink-faint);font-size:12px;font-weight:700}.meta.svelte-15fxkvm code:where(.svelte-15fxkvm){font-family:var(--font-mono);color:var(--ink-soft);font-size:13px}.meta.svelte-15fxkvm code.muted:where(.svelte-15fxkvm){color:var(--ink-faint)}.healthslot.svelte-15fxkvm,.ports.svelte-15fxkvm{margin-bottom:18px}.ports-bar.svelte-15fxkvm{display:flex;justify-content:space-between;align-items: center}.rebuild.svelte-15fxkvm{font-family:var(--font-mono);text-transform:uppercase;letter-spacing:.08em;background:var(--bg);color:var(--ink);border:1px solid var(--bg);cursor:pointer;padding:4px 9px;font-size:10px;font-weight:600}.rebuild.svelte-15fxkvm:hover:not(:disabled){color:var(--bg);background:0 0}.rebuild.svelte-15fxkvm:disabled{opacity:.5;cursor:not-allowed}.ports-body.svelte-15fxkvm{background:var(--bg-card);padding:12px 14px 14px}.port-list.svelte-15fxkvm{list-style:none;display:flex;flex-direction:column;gap:6px;margin:0 0 12px;padding:0}.port-list.svelte-15fxkvm li:where(.svelte-15fxkvm){display:flex;font-family:var(--font-mono);align-items: center;gap:8px;font-size:13px}.port-list.svelte-15fxkvm .cp:where(.svelte-15fxkvm){color:var(--ink);font-weight:600}.port-list.svelte-15fxkvm .arr:where(.svelte-15fxkvm){color:var(--ink-faint)}.port-list.svelte-15fxkvm a:where(.svelte-15fxkvm){display:inline-flex;color:var(--ink);text-decoration:none;border-bottom:1px solid var(--ink-faint);align-items: center;gap:4px}.port-list.svelte-15fxkvm a:where(.svelte-15fxkvm):hover{border-bottom-color:var(--ink)}.rm.svelte-15fxkvm{border:1px solid var(--ink-faint);color:var(--ink-soft);cursor:pointer;background:0 0;width:20px;height:20px;margin-left:auto;font-size:15px;line-height:1}.rm.svelte-15fxkvm:hover{border-color:var(--danger);color:var(--danger)}.empty.svelte-15fxkvm{font-family:var(--font-mono);color:var(--ink-faint);margin:0 0 12px;font-size:12px}.add.svelte-15fxkvm{display:flex;gap:8px}.add.svelte-15fxkvm input:where(.svelte-15fxkvm){font-family:var(--font-mono);border:1px solid var(--ink);background:var(--bg);color:var(--ink);outline:none;flex:1;min-width:0;padding:6px 9px;font-size:13px}.add.svelte-15fxkvm button:where(.svelte-15fxkvm){font-family:var(--font-mono);text-transform:uppercase;letter-spacing:.06em;border:1px solid var(--ink);background:var(--bg-card);color:var(--ink);cursor:pointer;padding:6px 14px;font-size:12px;font-weight:600}.add.svelte-15fxkvm button:where(.svelte-15fxkvm):hover{background:var(--ink);color:var(--bg)}.port-err.svelte-15fxkvm{font-family:var(--font-mono);color:var(--danger);margin:10px 0 0;font-size:12px}.hint.svelte-15fxkvm{font-family:var(--font-mono);color:var(--ink-faint);margin:10px 0 0;font-size:11px}.hint.pending.svelte-15fxkvm{color:var(--ink-soft)}.hint.svelte-15fxkvm code:where(.svelte-15fxkvm){color:var(--ink)}.logwrap.svelte-15fxkvm{overflow:hidden}.log-bar.svelte-15fxkvm{display:flex;justify-content:space-between;align-items: center}.copy.svelte-15fxkvm{font-family:var(--font-mono);text-transform:uppercase;letter-spacing:.08em;background:var(--bg);color:var(--ink);border:1px solid var(--bg);cursor:pointer;padding:4px 9px;font-size:10px;font-weight:600}.copy.svelte-15fxkvm:hover:not(:disabled){color:var(--bg);background:0 0}.copy.svelte-15fxkvm:disabled{opacity:.5;cursor:not-allowed}.logs.svelte-15fxkvm{position:relative;background:repeating-linear-gradient(0deg,var(--screen-line)0 1px,transparent 1px 3px),var(--screen-bg);color:var(--screen-ink);overflow:auto;height:calc(100vh - 320px);min-height:360px;padding:14px}.logs.svelte-15fxkvm pre:where(.svelte-15fxkvm){font-family:var(--font-mono);white-space:pre-wrap;word-break:break-word;margin:0;font-size:12.5px;line-height:1.5}@keyframes svelte-15fxkvm-lcd-blink{50%{background:0 0}}.caret.svelte-15fxkvm{display:inline-block;background:var(--screen-ink);vertical-align:text-bottom;animation:svelte-15fxkvm-lcd-blink 1.05s steps(1)infinite;width:.6em;height:1.05em;margin-left:2px}.err.svelte-15fxkvm{background:var(--bg-card);color:var(--ink);border-top:2px solid var(--ink);font-family:var(--font-mono);padding:12px 14px;font-size:13px}
1
+ .topbar.svelte-15fxkvm{display:flex;border-bottom:1px solid var(--rule);align-items: center;gap:18px;padding:16px 24px}.back.svelte-15fxkvm{display:inline-flex;font-family:var(--font-mono);text-transform:uppercase;letter-spacing:.06em;color:var(--ink-soft);text-decoration:none;align-items: center;gap:5px;font-size:12px}.back.svelte-15fxkvm:hover{color:var(--ink)}.title.svelte-15fxkvm{display:flex;flex:1;align-items: center;gap:12px}.name.svelte-15fxkvm{font-family:var(--font-display);text-transform:uppercase;letter-spacing:.03em;font-size:20px;font-weight:700}.open.svelte-15fxkvm{display:inline-flex;font-family:var(--font-mono);text-transform:uppercase;letter-spacing:.06em;color:var(--ink);text-decoration:none;border:1px solid var(--ink);align-items: center;gap:6px;padding:7px 12px;font-size:12px;font-weight:600}.open.svelte-15fxkvm:hover{background:var(--ink);color:var(--bg)}.restart.svelte-15fxkvm{display:inline-flex;font-family:var(--font-mono);text-transform:uppercase;letter-spacing:.06em;color:var(--ink);background:var(--bg);border:1px solid var(--ink);cursor:pointer;align-items: center;gap:6px;padding:7px 12px;font-size:12px;font-weight:600}.restart.svelte-15fxkvm:hover:not(:disabled){background:var(--ink);color:var(--bg)}.restart.svelte-15fxkvm:disabled{opacity:.5;cursor:not-allowed}.restart-err.svelte-15fxkvm{font-family:var(--font-mono);color:var(--danger);margin:0;padding:8px 24px 0;font-size:12px}.stage.svelte-15fxkvm{max-width:1200px;margin:0 auto;padding:20px 24px 40px}.meta.svelte-15fxkvm{display:grid;grid-template-columns:max-content 1fr;align-items: center;gap:6px 14px;margin-bottom:18px}.meta.svelte-15fxkvm .k:where(.svelte-15fxkvm){font-family:var(--font-display);letter-spacing:.14em;text-transform:uppercase;color:var(--ink-faint);font-size:12px;font-weight:700}.meta.svelte-15fxkvm code:where(.svelte-15fxkvm){font-family:var(--font-mono);color:var(--ink-soft);font-size:13px}.meta.svelte-15fxkvm code.muted:where(.svelte-15fxkvm){color:var(--ink-faint)}.healthslot.svelte-15fxkvm,.ports.svelte-15fxkvm{margin-bottom:18px}.ports-bar.svelte-15fxkvm{display:flex;justify-content:space-between;align-items: center}.rebuild.svelte-15fxkvm{font-family:var(--font-mono);text-transform:uppercase;letter-spacing:.08em;background:var(--bg);color:var(--ink);border:1px solid var(--bg);cursor:pointer;padding:4px 9px;font-size:10px;font-weight:600}.rebuild.svelte-15fxkvm:hover:not(:disabled){color:var(--bg);background:0 0}.rebuild.svelte-15fxkvm:disabled{opacity:.5;cursor:not-allowed}.ports-body.svelte-15fxkvm{background:var(--bg-card);padding:12px 14px 14px}.port-list.svelte-15fxkvm{list-style:none;display:flex;flex-direction:column;gap:6px;margin:0 0 12px;padding:0}.port-list.svelte-15fxkvm li:where(.svelte-15fxkvm){display:flex;font-family:var(--font-mono);align-items: center;gap:8px;font-size:13px}.port-list.svelte-15fxkvm .cp:where(.svelte-15fxkvm){color:var(--ink);font-weight:600}.port-list.svelte-15fxkvm .arr:where(.svelte-15fxkvm){color:var(--ink-faint)}.port-list.svelte-15fxkvm a:where(.svelte-15fxkvm){display:inline-flex;color:var(--ink);text-decoration:none;border-bottom:1px solid var(--ink-faint);align-items: center;gap:4px}.port-list.svelte-15fxkvm a:where(.svelte-15fxkvm):hover{border-bottom-color:var(--ink)}.rm.svelte-15fxkvm{border:1px solid var(--ink-faint);color:var(--ink-soft);cursor:pointer;background:0 0;width:20px;height:20px;margin-left:auto;font-size:15px;line-height:1}.rm.svelte-15fxkvm:hover{border-color:var(--danger);color:var(--danger)}.empty.svelte-15fxkvm{font-family:var(--font-mono);color:var(--ink-faint);margin:0 0 12px;font-size:12px}.add.svelte-15fxkvm{display:flex;gap:8px}.add.svelte-15fxkvm input:where(.svelte-15fxkvm){font-family:var(--font-mono);border:1px solid var(--ink);background:var(--bg);color:var(--ink);outline:none;flex:1;min-width:0;padding:6px 9px;font-size:13px}.add.svelte-15fxkvm button:where(.svelte-15fxkvm){font-family:var(--font-mono);text-transform:uppercase;letter-spacing:.06em;border:1px solid var(--ink);background:var(--bg-card);color:var(--ink);cursor:pointer;padding:6px 14px;font-size:12px;font-weight:600}.add.svelte-15fxkvm button:where(.svelte-15fxkvm):hover{background:var(--ink);color:var(--bg)}.port-err.svelte-15fxkvm{font-family:var(--font-mono);color:var(--danger);margin:10px 0 0;font-size:12px}.hint.svelte-15fxkvm{font-family:var(--font-mono);color:var(--ink-faint);margin:10px 0 0;font-size:11px}.hint.pending.svelte-15fxkvm{color:var(--ink-soft)}.hint.svelte-15fxkvm code:where(.svelte-15fxkvm){color:var(--ink)}.logwrap.svelte-15fxkvm{overflow:hidden}.log-bar.svelte-15fxkvm{display:flex;justify-content:space-between;align-items: center}.log-actions.svelte-15fxkvm{display:flex;align-items: center;gap:6px}.copy.svelte-15fxkvm{font-family:var(--font-mono);text-transform:uppercase;letter-spacing:.08em;background:var(--bg);color:var(--ink);border:1px solid var(--bg);cursor:pointer;padding:4px 9px;font-size:10px;font-weight:600}.copy.svelte-15fxkvm:hover:not(:disabled),.copy.active.svelte-15fxkvm{color:var(--bg);background:0 0}.copy.svelte-15fxkvm:disabled{opacity:.5;cursor:not-allowed}.logs.svelte-15fxkvm{position:relative;background:repeating-linear-gradient(0deg,var(--screen-line)0 1px,transparent 1px 3px),var(--screen-bg);color:var(--screen-ink);overflow:auto;height:calc(100vh - 320px);min-height:360px;padding:14px}.logs.svelte-15fxkvm pre:where(.svelte-15fxkvm){font-family:var(--font-mono);white-space:pre-wrap;word-break:break-word;margin:0;font-size:12.5px;line-height:1.5}@keyframes svelte-15fxkvm-lcd-blink{50%{background:0 0}}.caret.svelte-15fxkvm{display:inline-block;background:var(--screen-ink);vertical-align:text-bottom;animation:svelte-15fxkvm-lcd-blink 1.05s steps(1)infinite;width:.6em;height:1.05em;margin-left:2px}.err.svelte-15fxkvm{background:var(--bg-card);color:var(--ink);border-top:2px solid var(--ink);font-family:var(--font-mono);padding:12px 14px;font-size:13px}
package/README.md CHANGED
@@ -35,6 +35,8 @@ bun run dev # dev server, local ./.codebay DATA_DIR, no browser launch
35
35
  bun run checks # format + typecheck + tests
36
36
  ```
37
37
 
38
+ The repo also ships a minimal Bun devcontainer (`.devcontainer/`) for a containerized setup. New to authoring devcontainers? See the general [Devcontainer guide](./DEVCONTAINER_GUIDE.md).
39
+
38
40
  ## License
39
41
 
40
42
  MIT
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "codebay",
3
- "version": "0.5.0",
3
+ "version": "0.7.0",
4
4
  "description": "Web UI for spinning up isolated devcontainer instances from any local folder, each with a browser-based VS Code (code-server) — built for parallel Claude Code workflows.",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -52,7 +52,7 @@
52
52
  "test": "bun test",
53
53
  "lint": "prettier --check . && eslint .",
54
54
  "format": "prettier --write .",
55
- "checks": "bun run format && bun run typecheck && bun run test",
55
+ "checks": "bun run format && eslint . && bun run typecheck && bun run test",
56
56
  "clean": "rimraf .mochi",
57
57
  "gen:chimes": "bun scripts/gen-chimes.ts",
58
58
  "debug:tokens": "bun scripts/debug-tokens.ts",
@@ -2,6 +2,7 @@ import type { AvatarArt } from './types.ts';
2
2
 
3
3
  const art: AvatarArt = {
4
4
  name: 'anchor',
5
+ robot: true,
5
6
  pixels: [
6
7
  '...##...',
7
8
  '..#..#..',
@@ -0,0 +1,17 @@
1
+ import type { AvatarArt } from './types.ts';
2
+
3
+ const art: AvatarArt = {
4
+ name: 'ant-head',
5
+ pixels: [
6
+ '#......#',
7
+ '.#....#.',
8
+ '.######.',
9
+ '#..##..#',
10
+ '#..##..#',
11
+ '#..##..#',
12
+ '.######.',
13
+ '...##...'
14
+ ]
15
+ };
16
+
17
+ export default art;
@@ -0,0 +1,17 @@
1
+ import type { AvatarArt } from './types.ts';
2
+
3
+ const art: AvatarArt = {
4
+ name: 'apple',
5
+ pixels: [
6
+ '...##...',
7
+ '...#....',
8
+ '.##..##.',
9
+ '#.######',
10
+ '#.######',
11
+ '#.######',
12
+ '.#.####.',
13
+ '..####..'
14
+ ]
15
+ };
16
+
17
+ export default art;
@@ -2,6 +2,7 @@ import type { AvatarArt } from './types.ts';
2
2
 
3
3
  const art: AvatarArt = {
4
4
  name: 'bear',
5
+ robot: true,
5
6
  pixels: [
6
7
  '##....##',
7
8
  '###..###',
@@ -2,6 +2,7 @@ import type { AvatarArt } from './types.ts';
2
2
 
3
3
  const art: AvatarArt = {
4
4
  name: 'bee',
5
+ robot: true,
5
6
  pixels: [
6
7
  '.#....#.',
7
8
  '##.##.##',
@@ -0,0 +1,17 @@
1
+ import type { AvatarArt } from './types.ts';
2
+
3
+ const art: AvatarArt = {
4
+ name: 'bodybuilder',
5
+ pixels: [
6
+ '...##...',
7
+ '...##...',
8
+ '.#....#.',
9
+ '#..##..#',
10
+ '##....##',
11
+ '##.##.##',
12
+ '........',
13
+ '...##...'
14
+ ]
15
+ };
16
+
17
+ export default art;
@@ -2,6 +2,7 @@ import type { AvatarArt } from './types.ts';
2
2
 
3
3
  const art: AvatarArt = {
4
4
  name: 'cat',
5
+ robot: true,
5
6
  pixels: [
6
7
  '##....##',
7
8
  '##....##',
@@ -2,6 +2,7 @@ import type { AvatarArt } from './types.ts';
2
2
 
3
3
  const art: AvatarArt = {
4
4
  name: 'cherry',
5
+ robot: true,
5
6
  pixels: [
6
7
  '......##',
7
8
  '....###.',
@@ -2,6 +2,7 @@ import type { AvatarArt } from './types.ts';
2
2
 
3
3
  const art: AvatarArt = {
4
4
  name: 'crab',
5
+ robot: true,
5
6
  pixels: [
6
7
  '.#....#.',
7
8
  '##....##',
@@ -2,6 +2,7 @@ import type { AvatarArt } from './types.ts';
2
2
 
3
3
  const art: AvatarArt = {
4
4
  name: 'crown',
5
+ robot: true,
5
6
  pixels: [
6
7
  '#......#',
7
8
  '#..##..#',
@@ -2,6 +2,7 @@ import type { AvatarArt } from './types.ts';
2
2
 
3
3
  const art: AvatarArt = {
4
4
  name: 'diamond',
5
+ robot: true,
5
6
  pixels: [
6
7
  '.######.',
7
8
  '#.#..#.#',
@@ -2,6 +2,7 @@ import type { AvatarArt } from './types.ts';
2
2
 
3
3
  const art: AvatarArt = {
4
4
  name: 'dog',
5
+ robot: true,
5
6
  pixels: [
6
7
  '##....##',
7
8
  '##.##.##',
@@ -0,0 +1,17 @@
1
+ // Drawing modes for the avatar editor: how a click advances a cell's value.
2
+ import { ON, OFF, GRAY } from './types.ts';
3
+
4
+ export type Mode = 'black' | 'gray' | 'cycle';
5
+
6
+ export const MODES: { id: Mode; label: string }[] = [
7
+ { id: 'black', label: 'Black' },
8
+ { id: 'gray', label: 'Gray' },
9
+ { id: 'cycle', label: 'Cycle' }
10
+ ];
11
+
12
+ // black toggles off↔on, gray toggles off↔gray, cycle steps off→gray→on→off.
13
+ export function nextValue(mode: Mode, current: number): number {
14
+ if (mode === 'black') return current === ON ? OFF : ON;
15
+ if (mode === 'gray') return current === GRAY ? OFF : GRAY;
16
+ return current === OFF ? GRAY : current === GRAY ? ON : OFF;
17
+ }
@@ -2,6 +2,7 @@ import type { AvatarArt } from './types.ts';
2
2
 
3
3
  const art: AvatarArt = {
4
4
  name: 'fish',
5
+ robot: true,
5
6
  pixels: [
6
7
  '......#.',
7
8
  '.###.##.',
@@ -2,6 +2,7 @@ import type { AvatarArt } from './types.ts';
2
2
 
3
3
  const art: AvatarArt = {
4
4
  name: 'flower',
5
+ robot: true,
5
6
  pixels: [
6
7
  '..#..#..',
7
8
  '.###.##.',
@@ -2,6 +2,7 @@ import type { AvatarArt } from './types.ts';
2
2
 
3
3
  const art: AvatarArt = {
4
4
  name: 'fox',
5
+ robot: true,
5
6
  pixels: [
6
7
  '##....##',
7
8
  '##....##',
@@ -2,6 +2,7 @@ import type { AvatarArt } from './types.ts';
2
2
 
3
3
  const art: AvatarArt = {
4
4
  name: 'frog',
5
+ robot: true,
5
6
  pixels: [
6
7
  '.#....#.',
7
8
  '###..###',
@@ -2,6 +2,7 @@ import type { AvatarArt } from './types.ts';
2
2
 
3
3
  const art: AvatarArt = {
4
4
  name: 'ghost',
5
+ robot: true,
5
6
  pixels: [
6
7
  '..####..',
7
8
  '.######.',
@@ -3,14 +3,14 @@ import type { AvatarArt } from './types.ts';
3
3
  const art: AvatarArt = {
4
4
  name: 'heart',
5
5
  pixels: [
6
- '.##..##.',
7
- '########',
8
- '########',
9
- '########',
10
- '.######.',
11
- '..####..',
12
- '...##...',
13
- '........'
6
+ '........',
7
+ '........',
8
+ '.##.##..',
9
+ '#..#..#.',
10
+ '#.....#.',
11
+ '.#...#..',
12
+ '..#.#...',
13
+ '...#....'
14
14
  ]
15
15
  };
16
16
 
@@ -0,0 +1,17 @@
1
+ import type { AvatarArt } from './types.ts';
2
+
3
+ const art: AvatarArt = {
4
+ name: 'horse',
5
+ pixels: [
6
+ '....#.#.',
7
+ '....####',
8
+ '....####',
9
+ '....##..',
10
+ '######..',
11
+ '#.#.##..',
12
+ '#.#.##..',
13
+ '#.#.##..'
14
+ ]
15
+ };
16
+
17
+ export default art;
@@ -1,9 +1,12 @@
1
1
  import type { AvatarArt } from './types.ts';
2
2
 
3
3
  import anchor from './anchor.ts';
4
+ import antHead from './ant-head.ts';
5
+ import apple from './apple.ts';
4
6
  import bear from './bear.ts';
5
7
  import bee from './bee.ts';
6
8
  import bobMarley from './bob-marley.ts';
9
+ import bodybuilder from './bodybuilder.ts';
7
10
  import car from './car.ts';
8
11
  import carpathians from './carpathians.ts';
9
12
  import cat from './cat.ts';
@@ -26,6 +29,7 @@ import ghost from './ghost.ts';
26
29
  import giraffe from './giraffe.ts';
27
30
  import glasses from './glasses.ts';
28
31
  import heart from './heart.ts';
32
+ import horse from './horse.ts';
29
33
  import invader from './invader.ts';
30
34
  import kangaroo from './kangaroo.ts';
31
35
  import key from './key.ts';
@@ -35,6 +39,7 @@ import octopus from './octopus.ts';
35
39
  import owl from './owl.ts';
36
40
  import penguin from './penguin.ts';
37
41
  import planet from './planet.ts';
42
+ import prayingMantis from './praying-mantis.ts';
38
43
  import rabbit from './rabbit.ts';
39
44
  import rat from './rat.ts';
40
45
  import robot from './robot.ts';
@@ -44,21 +49,29 @@ import skull from './skull.ts';
44
49
  import snail from './snail.ts';
45
50
  import snake from './snake.ts';
46
51
  import snakegame from './snakegame.ts';
52
+ import snowflake from './snowflake.ts';
47
53
  import star from './star.ts';
54
+ import strawberry from './strawberry.ts';
48
55
  import svelte from './svelte.ts';
49
56
  import target from './target.ts';
50
57
  import tree from './tree.ts';
51
58
  import ukraine from './ukraine.ts';
59
+ import vangoghAlmondBlossoms from './vangogh-almond-blossoms.ts';
60
+ import wasp from './wasp.ts';
52
61
  import whale from './whale.ts';
53
62
  import wheat from './wheat.ts';
63
+ import windmill from './windmill.ts';
54
64
  import yinyan from './yinyan.ts';
55
65
 
56
66
  // Order must stay stable, or every container's artwork changes on the next restart.
57
67
  export const avatars: AvatarArt[] = [
58
68
  anchor,
69
+ antHead,
70
+ apple,
59
71
  bear,
60
72
  bee,
61
73
  bobMarley,
74
+ bodybuilder,
62
75
  car,
63
76
  carpathians,
64
77
  cat,
@@ -81,6 +94,7 @@ export const avatars: AvatarArt[] = [
81
94
  giraffe,
82
95
  glasses,
83
96
  heart,
97
+ horse,
84
98
  invader,
85
99
  kangaroo,
86
100
  key,
@@ -90,6 +104,7 @@ export const avatars: AvatarArt[] = [
90
104
  owl,
91
105
  penguin,
92
106
  planet,
107
+ prayingMantis,
93
108
  rabbit,
94
109
  rat,
95
110
  robot,
@@ -99,13 +114,18 @@ export const avatars: AvatarArt[] = [
99
114
  snail,
100
115
  snake,
101
116
  snakegame,
117
+ snowflake,
102
118
  star,
119
+ strawberry,
103
120
  svelte,
104
121
  target,
105
122
  tree,
106
123
  ukraine,
124
+ vangoghAlmondBlossoms,
125
+ wasp,
107
126
  whale,
108
127
  wheat,
128
+ windmill,
109
129
  yinyan
110
130
  ];
111
131
 
@@ -2,6 +2,7 @@ import type { AvatarArt } from './types.ts';
2
2
 
3
3
  const art: AvatarArt = {
4
4
  name: 'invader',
5
+ robot: true,
5
6
  pixels: [
6
7
  '#......#',
7
8
  '.#....#.',
@@ -2,6 +2,7 @@ import type { AvatarArt } from './types.ts';
2
2
 
3
3
  const art: AvatarArt = {
4
4
  name: 'key',
5
+ robot: true,
5
6
  pixels: [
6
7
  '.####...',
7
8
  '##..##..',
@@ -2,6 +2,7 @@ import type { AvatarArt } from './types.ts';
2
2
 
3
3
  const art: AvatarArt = {
4
4
  name: 'lightning',
5
+ robot: true,
5
6
  pixels: [
6
7
  '...#####',
7
8
  '..####..',
@@ -2,6 +2,7 @@ import type { AvatarArt } from './types.ts';
2
2
 
3
3
  const art: AvatarArt = {
4
4
  name: 'mushroom',
5
+ robot: true,
5
6
  pixels: [
6
7
  '..####..',
7
8
  '.######.',
@@ -2,6 +2,7 @@ import type { AvatarArt } from './types.ts';
2
2
 
3
3
  const art: AvatarArt = {
4
4
  name: 'octopus',
5
+ robot: true,
5
6
  pixels: [
6
7
  '..####..',
7
8
  '.######.',
@@ -2,6 +2,7 @@ import type { AvatarArt } from './types.ts';
2
2
 
3
3
  const art: AvatarArt = {
4
4
  name: 'owl',
5
+ robot: true,
5
6
  pixels: [
6
7
  '#......#',
7
8
  '##....##',
@@ -2,6 +2,7 @@ import type { AvatarArt } from './types.ts';
2
2
 
3
3
  const art: AvatarArt = {
4
4
  name: 'penguin',
5
+ robot: true,
5
6
  pixels: [
6
7
  '..####..',
7
8
  '.######.',
@@ -2,6 +2,7 @@ import type { AvatarArt } from './types.ts';
2
2
 
3
3
  const art: AvatarArt = {
4
4
  name: 'planet',
5
+ robot: true,
5
6
  pixels: [
6
7
  '...###..',
7
8
  '..#####.',
@@ -0,0 +1,17 @@
1
+ import type { AvatarArt } from './types.ts';
2
+
3
+ const art: AvatarArt = {
4
+ name: 'praying-mantis',
5
+ pixels: [
6
+ '#.....#.',
7
+ '.#...#..',
8
+ '.##.##..',
9
+ '#..#..#.',
10
+ '#..#..#.',
11
+ '.#####..',
12
+ '..#.#...',
13
+ '...#....'
14
+ ]
15
+ };
16
+
17
+ export default art;
@@ -2,6 +2,7 @@ import type { AvatarArt } from './types.ts';
2
2
 
3
3
  const art: AvatarArt = {
4
4
  name: 'rabbit',
5
+ robot: true,
5
6
  pixels: [
6
7
  '.#....#.',
7
8
  '.##..##.',
@@ -2,6 +2,7 @@ import type { AvatarArt } from './types.ts';
2
2
 
3
3
  const art: AvatarArt = {
4
4
  name: 'robot',
5
+ robot: true,
5
6
  pixels: [
6
7
  '...##...',
7
8
  '...#....',
@@ -2,6 +2,7 @@ import type { AvatarArt } from './types.ts';
2
2
 
3
3
  const art: AvatarArt = {
4
4
  name: 'rocket',
5
+ robot: true,
5
6
  pixels: [
6
7
  '...##...',
7
8
  '..####..',
@@ -1,6 +1,6 @@
1
1
  // Turns an avatar-editor drawing into the two things a contribution needs:
2
2
  // module source and a pre-filled issue URL.
3
- import { type AvatarArt, ROWS, COLS, ON } from './types.ts';
3
+ import { type AvatarArt, ROWS, COLS, ON, GRAY } from './types.ts';
4
4
 
5
5
  export const REPO_URL = 'https://github.com/khromov/codebay';
6
6
 
@@ -18,7 +18,8 @@ export function cellsToPixels(cells: number[]): string[] {
18
18
  for (let r = 0; r < ROWS; r++) {
19
19
  let row = '';
20
20
  for (let c = 0; c < COLS; c++) {
21
- row += cells[r * COLS + c] === ON ? '#' : '.';
21
+ const cell = cells[r * COLS + c];
22
+ row += cell === ON ? '#' : cell === GRAY ? '+' : '.';
22
23
  }
23
24
  rows.push(row);
24
25
  }
@@ -58,7 +59,7 @@ export function toIssueUrl(art: AvatarArt): string {
58
59
  toModuleSource(art).trimEnd(),
59
60
  '```',
60
61
  '',
61
- '_It should satisfy `src/avatars/avatars.test.ts`: exactly 8×8, only `#`/`.` pixels, unique name._'
62
+ '_It should satisfy `src/avatars/avatars.test.ts`: exactly 8×8, only `#`/`+`/`.` pixels, unique name._'
62
63
  ].join('\n');
63
64
  const params = new URLSearchParams({ title, body });
64
65
  return `${REPO_URL}/issues/new?${params}`;
@@ -4,13 +4,13 @@ const art: AvatarArt = {
4
4
  name: 'skull',
5
5
  pixels: [
6
6
  '.######.',
7
+ '#..#..##',
8
+ '#..#..##',
7
9
  '########',
8
- '#.####.#',
9
- '#.#..#.#',
10
- '########',
11
- '##.##.##',
12
- '.#.##.#.',
13
- '.##.##..'
10
+ '.##.##..',
11
+ '.#####..',
12
+ '.#.#.#..',
13
+ '........'
14
14
  ]
15
15
  };
16
16
 
@@ -2,6 +2,7 @@ import type { AvatarArt } from './types.ts';
2
2
 
3
3
  const art: AvatarArt = {
4
4
  name: 'snail',
5
+ robot: true,
5
6
  pixels: [
6
7
  '.####..#',
7
8
  '#....#.#',
@@ -0,0 +1,17 @@
1
+ import type { AvatarArt } from './types.ts';
2
+
3
+ const art: AvatarArt = {
4
+ name: 'snowflake',
5
+ pixels: [
6
+ '#..##..#',
7
+ '.##..##.',
8
+ '.#.##.#.',
9
+ '#.####.#',
10
+ '#.####.#',
11
+ '.#.##.#.',
12
+ '.##..##.',
13
+ '#..##..#'
14
+ ]
15
+ };
16
+
17
+ export default art;
@@ -2,6 +2,7 @@ import type { AvatarArt } from './types.ts';
2
2
 
3
3
  const art: AvatarArt = {
4
4
  name: 'star',
5
+ robot: true,
5
6
  pixels: [
6
7
  '...##...',
7
8
  '...##...',