@bitefoundry/retrieviewer 0.0.0-stage → 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/ASSET-PROVENANCE.md +43 -0
- package/ASSETS-LICENSE.md +58 -0
- package/ATTRIBUTION.md +54 -0
- package/EMBEDDING.md +96 -0
- package/INSTALLING.md +107 -0
- package/LICENSE +16 -0
- package/LICENSE-CODE +21 -0
- package/PLUGIN.md +110 -0
- package/PUPPY-MEMORY.md +57 -0
- package/PUPPY-Q5-COMPARISON.md +73 -0
- package/README.md +61 -2
- package/RELEASING.md +61 -0
- package/THIRD-PARTY-NOTICES.md +17 -0
- package/TRADEMARKS.md +21 -0
- package/braille.mjs +45 -0
- package/examples/bridge.py +62 -0
- package/examples/embed.mjs +15 -0
- package/examples/live.mjs +40 -0
- package/examples/plugin.mjs +21 -0
- package/integrations/opencode/runtime.mjs +195 -0
- package/integrations/opencode/tui.tsx +59 -0
- package/locomotion-core.mjs +21 -0
- package/locomotion-puppy.animal +0 -0
- package/package.json +125 -4
- package/pet-q5-manifest.json +118 -0
- package/puppy-clean.mjs +51 -0
- package/puppy-companion-interactions-v3-q5.bin.gz +0 -0
- package/puppy-companion-interactions-v3.json +1 -0
- package/puppy-companion-life.mjs +182 -0
- package/puppy-companion-objects.mjs +30 -0
- package/puppy-companion-sprites.mjs +14 -0
- package/puppy-continuous.mjs +57 -0
- package/puppy-face.mjs +46 -0
- package/puppy-frame-predictive.mjs +147 -0
- package/puppy-frame-store.mjs +108 -0
- package/puppy-mouth-anchor.json +1 -0
- package/puppy-mouth-anchor.mjs +33 -0
- package/puppy-paper-actions-v9-q5.bin.gz +0 -0
- package/puppy-paper-actions-v9.json +1 -0
- package/puppy-paper-actions.mjs +48 -0
- package/puppy-paper-approach-q5.bin.gz +0 -0
- package/puppy-paper-approach.json +1 -0
- package/puppy-paper-area.mjs +15 -0
- package/puppy-paper-arrival-seat-q5.bin.gz +0 -0
- package/puppy-paper-arrival-seat.json +1 -0
- package/puppy-paper-behaviors-q5.bin.gz +0 -0
- package/puppy-paper-behaviors.json +1 -0
- package/puppy-paper-behaviors.mjs +8 -0
- package/puppy-paper-contact.mjs +103 -0
- package/puppy-paper-director.mjs +21 -0
- package/puppy-paper-paw-transport.mjs +76 -0
- package/puppy-paper-rear-gallop-q5.bin.gz +0 -0
- package/puppy-paper-rear-gallop.json +1 -0
- package/puppy-paper-seat-q5.bin.gz +0 -0
- package/puppy-paper-seat.json +14 -0
- package/puppy-paper-seat.mjs +13 -0
- package/puppy-paper-trick-timing.mjs +58 -0
- package/puppy-paper-world.mjs +108 -0
- package/puppy-paper.mjs +271 -0
- package/puppy-stable-meta.json +1606 -0
- package/puppy-stable.mjs +72 -0
- package/puppy-stride-meta.json +343 -0
- package/puppy-stride-tweens-q5.bin.gz +0 -0
- package/puppy-zoomies.mjs +27 -0
- package/puppy-zoomies30.mjs +12 -0
- package/retrieviewer-cli.mjs +81 -0
- package/retrieviewer-config.mjs +49 -0
- package/retrieviewer-install.mjs +157 -0
- package/retrieviewer-plugin.d.mts +44 -0
- package/retrieviewer-plugin.mjs +97 -0
- package/retrieviewer-stdio.mjs +38 -0
- package/retrieviewer.d.mts +85 -0
- package/retrieviewer.mjs +142 -0
- package/vendor/procedural-animals/LICENSE +21 -0
- package/vendor/procedural-animals/package.json +40 -0
- package/vendor/procedural-animals/src/animal.js +146 -0
- package/vendor/procedural-animals/src/bake.js +51 -0
- package/vendor/procedural-animals/src/build.js +81 -0
- package/vendor/procedural-animals/src/core/build/coatKit.js +121 -0
- package/vendor/procedural-animals/src/core/build/featherCards.js +189 -0
- package/vendor/procedural-animals/src/core/build/finEdges.js +85 -0
- package/vendor/procedural-animals/src/core/build/furSlope.js +115 -0
- package/vendor/procedural-animals/src/core/build/mesh.js +67 -0
- package/vendor/procedural-animals/src/core/build/pipeline.js +272 -0
- package/vendor/procedural-animals/src/core/build/seams.js +183 -0
- package/vendor/procedural-animals/src/core/build/warp.js +112 -0
- package/vendor/procedural-animals/src/core/build/weights.js +393 -0
- package/vendor/procedural-animals/src/core/math/vec.js +81 -0
- package/vendor/procedural-animals/src/core/motion/actions.js +800 -0
- package/vendor/procedural-animals/src/core/motion/bird.js +3063 -0
- package/vendor/procedural-animals/src/core/motion/birdActions.js +1059 -0
- package/vendor/procedural-animals/src/core/motion/common.js +158 -0
- package/vendor/procedural-animals/src/core/motion/index.js +22 -0
- package/vendor/procedural-animals/src/core/motion/quadruped.js +2875 -0
- package/vendor/procedural-animals/src/core/motion/snake.js +1594 -0
- package/vendor/procedural-animals/src/core/motion/spider.js +1810 -0
- package/vendor/procedural-animals/src/core/motion/swimmer.js +1047 -0
- package/vendor/procedural-animals/src/core/motion/swimmerActions.js +613 -0
- package/vendor/procedural-animals/src/core/render/animalObject.js +262 -0
- package/vendor/procedural-animals/src/core/render/coatMaterial.js +1301 -0
- package/vendor/procedural-animals/src/core/render/dqs.js +159 -0
- package/vendor/procedural-animals/src/core/render/eyes.js +676 -0
- package/vendor/procedural-animals/src/core/render/membranes.js +77 -0
- package/vendor/procedural-animals/src/core/render/skeleton.js +41 -0
- package/vendor/procedural-animals/src/core/rig/bird.js +327 -0
- package/vendor/procedural-animals/src/core/rig/quadruped.js +76 -0
- package/vendor/procedural-animals/src/core/rig/rig.js +79 -0
- package/vendor/procedural-animals/src/core/rig/snake.js +76 -0
- package/vendor/procedural-animals/src/core/rig/spider.js +110 -0
- package/vendor/procedural-animals/src/core/rig/swimmer.js +181 -0
- package/vendor/procedural-animals/src/core/sdf/eyeSocket.js +53 -0
- package/vendor/procedural-animals/src/core/sdf/mesher.js +238 -0
- package/vendor/procedural-animals/src/core/sdf/sdf.js +263 -0
- package/vendor/procedural-animals/src/index.d.ts +98 -0
- package/vendor/procedural-animals/src/index.js +29 -0
- package/vendor/procedural-animals/src/registry.js +48 -0
- package/vendor/procedural-animals/src/species/bear/behaviour.js +463 -0
- package/vendor/procedural-animals/src/species/bear/claws.js +147 -0
- package/vendor/procedural-animals/src/species/bear/coat.js +726 -0
- package/vendor/procedural-animals/src/species/bear/index.js +139 -0
- package/vendor/procedural-animals/src/species/bear/motion.js +112 -0
- package/vendor/procedural-animals/src/species/bear/regions.js +78 -0
- package/vendor/procedural-animals/src/species/bear/rig.js +112 -0
- package/vendor/procedural-animals/src/species/bear/sculpt.js +272 -0
- package/vendor/procedural-animals/src/species/boar/behaviour.js +335 -0
- package/vendor/procedural-animals/src/species/boar/coat.js +372 -0
- package/vendor/procedural-animals/src/species/boar/index.js +110 -0
- package/vendor/procedural-animals/src/species/boar/motion.js +85 -0
- package/vendor/procedural-animals/src/species/boar/regions.js +88 -0
- package/vendor/procedural-animals/src/species/boar/rig.js +111 -0
- package/vendor/procedural-animals/src/species/boar/sculpt.js +285 -0
- package/vendor/procedural-animals/src/species/cat/behaviour.js +559 -0
- package/vendor/procedural-animals/src/species/cat/coat.js +841 -0
- package/vendor/procedural-animals/src/species/cat/index.js +211 -0
- package/vendor/procedural-animals/src/species/cat/motion.js +101 -0
- package/vendor/procedural-animals/src/species/cat/regions.js +82 -0
- package/vendor/procedural-animals/src/species/cat/rig.js +100 -0
- package/vendor/procedural-animals/src/species/cat/sculpt.js +266 -0
- package/vendor/procedural-animals/src/species/cat/whiskers.js +110 -0
- package/vendor/procedural-animals/src/species/cheetah/coat.js +427 -0
- package/vendor/procedural-animals/src/species/cheetah/index.js +51 -0
- package/vendor/procedural-animals/src/species/cheetah/joints.js +3 -0
- package/vendor/procedural-animals/src/species/cheetah/motion.js +77 -0
- package/vendor/procedural-animals/src/species/cheetah/regions.js +95 -0
- package/vendor/procedural-animals/src/species/cheetah/rig.js +66 -0
- package/vendor/procedural-animals/src/species/cheetah/sculpt.js +158 -0
- package/vendor/procedural-animals/src/species/chicken/coat.js +313 -0
- package/vendor/procedural-animals/src/species/chicken/coverts.js +320 -0
- package/vendor/procedural-animals/src/species/chicken/index.js +110 -0
- package/vendor/procedural-animals/src/species/chicken/motion.js +177 -0
- package/vendor/procedural-animals/src/species/chicken/regions.js +66 -0
- package/vendor/procedural-animals/src/species/chicken/rig.js +144 -0
- package/vendor/procedural-animals/src/species/chicken/sculpt.js +389 -0
- package/vendor/procedural-animals/src/species/chicken/wingLook.js +66 -0
- package/vendor/procedural-animals/src/species/chicken/wingStack.js +124 -0
- package/vendor/procedural-animals/src/species/cow/behaviour.js +521 -0
- package/vendor/procedural-animals/src/species/cow/coat.js +465 -0
- package/vendor/procedural-animals/src/species/cow/index.js +118 -0
- package/vendor/procedural-animals/src/species/cow/motion.js +81 -0
- package/vendor/procedural-animals/src/species/cow/regions.js +98 -0
- package/vendor/procedural-animals/src/species/cow/rig.js +116 -0
- package/vendor/procedural-animals/src/species/cow/sculpt.js +339 -0
- package/vendor/procedural-animals/src/species/crow/coat.js +145 -0
- package/vendor/procedural-animals/src/species/crow/index.js +70 -0
- package/vendor/procedural-animals/src/species/crow/joints.js +3 -0
- package/vendor/procedural-animals/src/species/crow/motion.js +101 -0
- package/vendor/procedural-animals/src/species/crow/regions.js +50 -0
- package/vendor/procedural-animals/src/species/crow/rig.js +83 -0
- package/vendor/procedural-animals/src/species/crow/sculpt.js +118 -0
- package/vendor/procedural-animals/src/species/deer/behaviour.js +513 -0
- package/vendor/procedural-animals/src/species/deer/coat.js +391 -0
- package/vendor/procedural-animals/src/species/deer/index.js +106 -0
- package/vendor/procedural-animals/src/species/deer/motion.js +97 -0
- package/vendor/procedural-animals/src/species/deer/regions.js +60 -0
- package/vendor/procedural-animals/src/species/deer/rig.js +124 -0
- package/vendor/procedural-animals/src/species/deer/sculpt.js +297 -0
- package/vendor/procedural-animals/src/species/dog/behaviour.js +521 -0
- package/vendor/procedural-animals/src/species/dog/coat.js +495 -0
- package/vendor/procedural-animals/src/species/dog/index.js +144 -0
- package/vendor/procedural-animals/src/species/dog/motion.js +118 -0
- package/vendor/procedural-animals/src/species/dog/regions.js +61 -0
- package/vendor/procedural-animals/src/species/dog/rig.js +129 -0
- package/vendor/procedural-animals/src/species/dog/sculpt.js +246 -0
- package/vendor/procedural-animals/src/species/eagle/coat.js +250 -0
- package/vendor/procedural-animals/src/species/eagle/index.js +76 -0
- package/vendor/procedural-animals/src/species/eagle/joints.js +3 -0
- package/vendor/procedural-animals/src/species/eagle/motion.js +137 -0
- package/vendor/procedural-animals/src/species/eagle/regions.js +57 -0
- package/vendor/procedural-animals/src/species/eagle/rig.js +107 -0
- package/vendor/procedural-animals/src/species/eagle/sculpt.js +137 -0
- package/vendor/procedural-animals/src/species/fish/coat.js +271 -0
- package/vendor/procedural-animals/src/species/fish/index.js +88 -0
- package/vendor/procedural-animals/src/species/fish/motion.js +92 -0
- package/vendor/procedural-animals/src/species/fish/regions.js +27 -0
- package/vendor/procedural-animals/src/species/fish/rig.js +143 -0
- package/vendor/procedural-animals/src/species/fish/sculpt.js +214 -0
- package/vendor/procedural-animals/src/species/fish/variants.js +126 -0
- package/vendor/procedural-animals/src/species/fox/behaviour.js +314 -0
- package/vendor/procedural-animals/src/species/fox/coat.js +444 -0
- package/vendor/procedural-animals/src/species/fox/index.js +120 -0
- package/vendor/procedural-animals/src/species/fox/motion.js +81 -0
- package/vendor/procedural-animals/src/species/fox/regions.js +59 -0
- package/vendor/procedural-animals/src/species/fox/rig.js +91 -0
- package/vendor/procedural-animals/src/species/fox/sculpt.js +202 -0
- package/vendor/procedural-animals/src/species/frog/behaviour.js +590 -0
- package/vendor/procedural-animals/src/species/frog/coat.js +305 -0
- package/vendor/procedural-animals/src/species/frog/index.js +97 -0
- package/vendor/procedural-animals/src/species/frog/motion.js +69 -0
- package/vendor/procedural-animals/src/species/frog/regions.js +46 -0
- package/vendor/procedural-animals/src/species/frog/rig.js +156 -0
- package/vendor/procedural-animals/src/species/frog/sculpt.js +240 -0
- package/vendor/procedural-animals/src/species/goat/behaviour.js +509 -0
- package/vendor/procedural-animals/src/species/goat/coat.js +590 -0
- package/vendor/procedural-animals/src/species/goat/index.js +149 -0
- package/vendor/procedural-animals/src/species/goat/motion.js +95 -0
- package/vendor/procedural-animals/src/species/goat/regions.js +98 -0
- package/vendor/procedural-animals/src/species/goat/rig.js +181 -0
- package/vendor/procedural-animals/src/species/goat/sculpt.js +547 -0
- package/vendor/procedural-animals/src/species/horse/coat.js +361 -0
- package/vendor/procedural-animals/src/species/horse/coatSeam.js +122 -0
- package/vendor/procedural-animals/src/species/horse/index.js +80 -0
- package/vendor/procedural-animals/src/species/horse/motion.js +245 -0
- package/vendor/procedural-animals/src/species/horse/regions.js +60 -0
- package/vendor/procedural-animals/src/species/horse/rig.js +117 -0
- package/vendor/procedural-animals/src/species/horse/sculpt.js +316 -0
- package/vendor/procedural-animals/src/species/horse/seamWeights.js +272 -0
- package/vendor/procedural-animals/src/species/lion/behaviour.js +509 -0
- package/vendor/procedural-animals/src/species/lion/coat.js +1016 -0
- package/vendor/procedural-animals/src/species/lion/index.js +111 -0
- package/vendor/procedural-animals/src/species/lion/motion.js +87 -0
- package/vendor/procedural-animals/src/species/lion/regions.js +106 -0
- package/vendor/procedural-animals/src/species/lion/rig.js +110 -0
- package/vendor/procedural-animals/src/species/lion/sculpt.js +384 -0
- package/vendor/procedural-animals/src/species/lion/whiskers.js +132 -0
- package/vendor/procedural-animals/src/species/pig/behaviour.js +575 -0
- package/vendor/procedural-animals/src/species/pig/coat.js +730 -0
- package/vendor/procedural-animals/src/species/pig/ears.js +242 -0
- package/vendor/procedural-animals/src/species/pig/index.js +161 -0
- package/vendor/procedural-animals/src/species/pig/motion.js +105 -0
- package/vendor/procedural-animals/src/species/pig/regions.js +100 -0
- package/vendor/procedural-animals/src/species/pig/rig.js +152 -0
- package/vendor/procedural-animals/src/species/pig/sculpt.js +382 -0
- package/vendor/procedural-animals/src/species/rabbit/behaviour.js +605 -0
- package/vendor/procedural-animals/src/species/rabbit/coat.js +285 -0
- package/vendor/procedural-animals/src/species/rabbit/index.js +85 -0
- package/vendor/procedural-animals/src/species/rabbit/motion.js +85 -0
- package/vendor/procedural-animals/src/species/rabbit/regions.js +48 -0
- package/vendor/procedural-animals/src/species/rabbit/rig.js +99 -0
- package/vendor/procedural-animals/src/species/rabbit/sculpt.js +148 -0
- package/vendor/procedural-animals/src/species/rat/behaviour.js +539 -0
- package/vendor/procedural-animals/src/species/rat/coat.js +341 -0
- package/vendor/procedural-animals/src/species/rat/index.js +111 -0
- package/vendor/procedural-animals/src/species/rat/motion.js +90 -0
- package/vendor/procedural-animals/src/species/rat/regions.js +92 -0
- package/vendor/procedural-animals/src/species/rat/rig.js +112 -0
- package/vendor/procedural-animals/src/species/rat/sculpt.js +163 -0
- package/vendor/procedural-animals/src/species/rat/whiskers.js +119 -0
- package/vendor/procedural-animals/src/species/shark/coat.js +383 -0
- package/vendor/procedural-animals/src/species/shark/index.js +104 -0
- package/vendor/procedural-animals/src/species/shark/motion.js +69 -0
- package/vendor/procedural-animals/src/species/shark/regions.js +34 -0
- package/vendor/procedural-animals/src/species/shark/rig.js +194 -0
- package/vendor/procedural-animals/src/species/shark/sculpt.js +343 -0
- package/vendor/procedural-animals/src/species/shark/variants.js +105 -0
- package/vendor/procedural-animals/src/species/sheep/behaviour.js +522 -0
- package/vendor/procedural-animals/src/species/sheep/coat.js +529 -0
- package/vendor/procedural-animals/src/species/sheep/index.js +152 -0
- package/vendor/procedural-animals/src/species/sheep/motion.js +86 -0
- package/vendor/procedural-animals/src/species/sheep/neck.js +41 -0
- package/vendor/procedural-animals/src/species/sheep/regions.js +62 -0
- package/vendor/procedural-animals/src/species/sheep/rig.js +163 -0
- package/vendor/procedural-animals/src/species/sheep/sculpt.js +542 -0
- package/vendor/procedural-animals/src/species/snake/coat.js +315 -0
- package/vendor/procedural-animals/src/species/snake/index.js +73 -0
- package/vendor/procedural-animals/src/species/snake/motion.js +51 -0
- package/vendor/procedural-animals/src/species/snake/regions.js +51 -0
- package/vendor/procedural-animals/src/species/snake/rig.js +108 -0
- package/vendor/procedural-animals/src/species/snake/sculpt.js +122 -0
- package/vendor/procedural-animals/src/species/spider/coat.js +279 -0
- package/vendor/procedural-animals/src/species/spider/index.js +78 -0
- package/vendor/procedural-animals/src/species/spider/motion.js +72 -0
- package/vendor/procedural-animals/src/species/spider/regions.js +87 -0
- package/vendor/procedural-animals/src/species/spider/rig.js +118 -0
- package/vendor/procedural-animals/src/species/spider/sculpt.js +182 -0
- package/vendor/procedural-animals/src/species/wolf/behaviour.js +160 -0
- package/vendor/procedural-animals/src/species/wolf/coat.js +749 -0
- package/vendor/procedural-animals/src/species/wolf/index.js +107 -0
- package/vendor/procedural-animals/src/species/wolf/motion.js +80 -0
- package/vendor/procedural-animals/src/species/wolf/regions.js +57 -0
- package/vendor/procedural-animals/src/species/wolf/rig.js +87 -0
- package/vendor/procedural-animals/src/species/wolf/sculpt.js +339 -0
- package/vendor/procedural-animals/src/worker.js +29 -0
package/README.md
CHANGED
|
@@ -1,3 +1,62 @@
|
|
|
1
|
-
#
|
|
1
|
+
# Retrieviewer
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
An autonomous, fluffy Braille retriever that lives in a pane of your terminal UI.
|
|
4
|
+
Give it a ball or a treat; otherwise it wanders and plays on its own. By BiteFoundry.
|
|
5
|
+
|
|
6
|
+
**Version 0.0.1.** Source code is MIT; puppy artwork is CC BY-SA 4.0, including
|
|
7
|
+
commercial use and adaptations under its attribution/ShareAlike conditions.
|
|
8
|
+
See [licensing](./LICENSE), [artwork terms](./ASSETS-LICENSE.md),
|
|
9
|
+
[credits](./ATTRIBUTION.md) and [brand notice](./TRADEMARKS.md).
|
|
10
|
+
The complete package is not MIT-only.
|
|
11
|
+
|
|
12
|
+
## Install
|
|
13
|
+
|
|
14
|
+
Node.js >=20 and a terminal font supporting Unicode Braille are required.
|
|
15
|
+
|
|
16
|
+
```sh
|
|
17
|
+
npm install -g @bitefoundry/retrieviewer@0.0.1
|
|
18
|
+
retrieviewer enable --agent opencode --dry-run
|
|
19
|
+
retrieviewer enable --agent opencode --yes
|
|
20
|
+
opencode
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
Without `--agent` / `--yes`, interactive `retrieviewer enable` offers agent
|
|
24
|
+
selection and a preview before changing configuration. The native adapter is
|
|
25
|
+
currently verified only with OpenCode 2.1.2 on Windows. Codex, Claude Code, Cursor
|
|
26
|
+
Agent, Grok and Antigravity native panes are not implemented. MCP connectivity
|
|
27
|
+
alone does not create a pet inside their screens.
|
|
28
|
+
|
|
29
|
+
Inside OpenCode use `/retrieviewer ball`, `/retrieviewer treat`, or
|
|
30
|
+
`/retrieviewer disable`. See [installation and removal](./INSTALLING.md).
|
|
31
|
+
|
|
32
|
+
## Embed in your own TUI
|
|
33
|
+
|
|
34
|
+
Install `@bitefoundry/retrieviewer` in your app, without `-g`, then use the host callbacks:
|
|
35
|
+
|
|
36
|
+
```js
|
|
37
|
+
import {createPetPlugin} from '@bitefoundry/retrieviewer/plugin';
|
|
38
|
+
|
|
39
|
+
const puppy = await createPetPlugin({host: {
|
|
40
|
+
getSize: () => ({columns: pane.width, rows: pane.height}),
|
|
41
|
+
render: ({text}) => pane.setContent(text),
|
|
42
|
+
onError: error => logToYourApp(error),
|
|
43
|
+
}});
|
|
44
|
+
puppy.start();
|
|
45
|
+
// Optional interaction: puppy.interact('ball') / puppy.interact('treat')
|
|
46
|
+
// On unmount: puppy.dispose()
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
`pane` and `logToYourApp` are supplied by your app. The pet does not take over
|
|
50
|
+
stdin, stdout or the screen. Q5 (32-level) artwork is bundled; no model API,
|
|
51
|
+
account or telemetry is needed by the runtime. npm dependencies require an
|
|
52
|
+
initial download or a populated cache. This is not a tiny icon: the complete
|
|
53
|
+
tarball is about 21 MB and a previous Windows sample used about 172 MB RSS.
|
|
54
|
+
|
|
55
|
+
- [Plugin lifecycle](./PLUGIN.md) — host callbacks, clocks and embedding.
|
|
56
|
+
- [Core and JSONL bridge](./EMBEDDING.md) — JS and non-JS TUI integration.
|
|
57
|
+
- [Release process](./RELEASING.md) — checks and support boundaries.
|
|
58
|
+
- [Third-party notices](./THIRD-PARTY-NOTICES.md).
|
|
59
|
+
|
|
60
|
+
The runtime has no install scripts and never edits agent settings automatically.
|
|
61
|
+
Only an explicit `retrieviewer enable` changes settings, after a preview/approval
|
|
62
|
+
or an explicit `--yes`. Unsupported hosts are refused.
|
package/RELEASING.md
ADDED
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
# Retrieviewer 0.0.1 release process
|
|
2
|
+
|
|
3
|
+
Target: `@bitefoundry/retrieviewer@0.0.1`, public npm registry, `latest` tag.
|
|
4
|
+
The npm organization `bitefoundry` uses the free public-packages plan; account
|
|
5
|
+
`shinick` owns the organization.
|
|
6
|
+
|
|
7
|
+
## Approval and licensing
|
|
8
|
+
|
|
9
|
+
The project owner explicitly authorized first publication on 2026-10-23 and
|
|
10
|
+
selected MIT code + CC BY-SA 4.0 artwork. The earlier unpublished restrictive
|
|
11
|
+
artwork draft is superseded. ATTRIBUTION.md retains the photographic references
|
|
12
|
+
and original license links. ASSET-PROVENANCE.md records the bounded review and
|
|
13
|
+
remaining limits; this is not comprehensive legal clearance.
|
|
14
|
+
|
|
15
|
+
`release-policy.json` has four independent approval gates and the CC artwork
|
|
16
|
+
license identifier. The guard still refuses false/missing approvals, private
|
|
17
|
+
packages, missing attribution/notices, install scripts and known leaked paths.
|
|
18
|
+
Passing tests does not itself provide a new publication authorization.
|
|
19
|
+
|
|
20
|
+
## Checks before publication
|
|
21
|
+
|
|
22
|
+
```sh
|
|
23
|
+
npm test
|
|
24
|
+
npm run test:package
|
|
25
|
+
npm run release:check
|
|
26
|
+
npm publish --dry-run --access public --registry=https://registry.npmjs.org/
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
The package test packs the exact candidate, installs it in a fresh offline
|
|
30
|
+
consumer, byte-compares all installed files and checks exports, frames,
|
|
31
|
+
interactions, lifecycle, examples, JSONL and isolated installer settings.
|
|
32
|
+
Its report is `dist/package-check.json`; it does not publish or edit live
|
|
33
|
+
agent configuration. Keep the final tarball hash and file inventory.
|
|
34
|
+
|
|
35
|
+
The product workspace is not a Git repository. No public source repository,
|
|
36
|
+
Actions pipeline or npm trusted publisher is implied by this npm release.
|
|
37
|
+
Do not upload this experimental workspace wholesale: original photos, source
|
|
38
|
+
image sheets, workers, QA receipts, credentials and local settings stay local.
|
|
39
|
+
|
|
40
|
+
## First publish
|
|
41
|
+
|
|
42
|
+
Confirm `npm whoami` is the intended account. Publish only the tested candidate
|
|
43
|
+
with explicit public access; complete any npm browser/2FA verification through
|
|
44
|
+
the user's own verification flow. Never put credentials in files or chat.
|
|
45
|
+
After publication, verify registry name/version/license/integrity and exercise
|
|
46
|
+
a fresh registry installation. A prepared or uploaded candidate is not the same
|
|
47
|
+
as a verified live package.
|
|
48
|
+
|
|
49
|
+
For later CI releases, consider GitHub Actions OIDC trusted publishing after an
|
|
50
|
+
audited source repository and exact workflow exist:
|
|
51
|
+
https://docs.npmjs.com/trusted-publishers/
|
|
52
|
+
|
|
53
|
+
## Support boundaries
|
|
54
|
+
|
|
55
|
+
The default Q5 art and runtime are unchanged by this release. The OpenCode
|
|
56
|
+
2.1.2 Windows directory-based adapter has local host proof; npm `./tui`
|
|
57
|
+
discovery alone is not live-host certification. Other agent-native renderers
|
|
58
|
+
remain unimplemented. MCP alone cannot inject a pet into arbitrary agent UIs.
|
|
59
|
+
See INSTALLING.md for support and removal.
|
|
60
|
+
|
|
61
|
+
Historical research notes remain local and are not current support promises.
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
# Third-party notices
|
|
2
|
+
|
|
3
|
+
- **procedural-animals 0.1.0** — MIT, Copyright (c) 2026 Majid Manzarpour and
|
|
4
|
+
procedural-animals contributors. Source is vendored under
|
|
5
|
+
`vendor/procedural-animals/src`; the full notice is retained at
|
|
6
|
+
`vendor/procedural-animals/LICENSE`.
|
|
7
|
+
Upstream: https://github.com/majidmanzarpour/threejs-procedural-animals
|
|
8
|
+
- **three 0.186.1** — MIT; installed as a pinned npm dependency. Its distribution
|
|
9
|
+
includes its own `LICENSE`. https://github.com/mrdoob/three.js
|
|
10
|
+
- **jsonc-parser 3.3.1** — MIT; installed as a pinned npm dependency. Its
|
|
11
|
+
distribution includes `LICENSE.md`. https://github.com/microsoft/node-jsonc-parser
|
|
12
|
+
|
|
13
|
+
The generated puppy artwork is separately CC BY-SA 4.0, not MIT. Its reference
|
|
14
|
+
photographers (Scott, CC BY 2.0; Stefan Bauer, CC BY-SA 2.5) and adaptation history
|
|
15
|
+
are credited in ATTRIBUTION.md. Original photographs are not bundled. See LICENSE,
|
|
16
|
+
LICENSE-CODE, ASSETS-LICENSE.md and the bounded ASSET-PROVENANCE.md review. No
|
|
17
|
+
comprehensive legal-clearance or exclusive AI-output ownership claim is made.
|
package/TRADEMARKS.md
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
# Names and origin
|
|
2
|
+
|
|
3
|
+
BiteFoundry and Retrieviewer are the project's brand and product names. No claim
|
|
4
|
+
is made here that either is a registered trademark or has passed legal clearance.
|
|
5
|
+
Owning a GitHub/npm namespace is not equivalent to obtaining trademark rights.
|
|
6
|
+
|
|
7
|
+
Neither the MIT code license nor the CC artwork license grants a general
|
|
8
|
+
right to market a different product as an official BiteFoundry/Retrieviewer
|
|
9
|
+
release. Accurate descriptive references and required attribution are allowed.
|
|
10
|
+
Clearly identify modified distributions and unaffiliated integrations; do not
|
|
11
|
+
falsely imply endorsement. Do not use the registered trademark symbol (R) unless
|
|
12
|
+
and until the relevant registration and scope justify it.
|
|
13
|
+
|
|
14
|
+
This notice does not limit lawful referential uses, statutory exceptions or
|
|
15
|
+
the MIT permissions for code or the CC permissions for artwork. It does not
|
|
16
|
+
require separate permission for lawful commercial reuse of the CC artwork, and
|
|
17
|
+
does not claim exclusive rights over generic
|
|
18
|
+
retriever imagery, dog behavior, the Braille rendering technique or ideas.
|
|
19
|
+
|
|
20
|
+
Domestic word-mark research is being conducted separately. No application,
|
|
21
|
+
registration, paid service engagement or fee payment is authorized by this file.
|
package/braille.mjs
ADDED
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
// Unicode 2x4 cells, the same dot numbering used by AuraDeck's Braille canvas.
|
|
2
|
+
export const BRAILLE_BITS=[[1,8],[2,16],[4,32],[64,128]];
|
|
3
|
+
const BAYER=[[0,8,2,10],[12,4,14,6],[3,11,1,9],[15,7,13,5]];
|
|
4
|
+
const clamp=v=>Math.max(0,Math.min(1,v));
|
|
5
|
+
export function rgbaToBraille(rgba,width,height,{brightness=1,contrast=1,method='floyd'}={}){
|
|
6
|
+
if(!Number.isInteger(width)||!Number.isInteger(height)||width<1||height<1||width*height>1_000_000||rgba.length!==width*height*4)throw Error('Invalid RGBA image');
|
|
7
|
+
if(!Number.isFinite(brightness)||brightness<=0||brightness>4||!Number.isFinite(contrast)||contrast<=0||contrast>4||!['floyd','bayer','stable'].includes(method))throw Error('Invalid dithering options');
|
|
8
|
+
const values=new Float32Array(width*height),bits=new Uint8Array(width*height);
|
|
9
|
+
for(let i=0;i<values.length;i++){
|
|
10
|
+
const p=i*4,luma=(.2126*rgba[p]+.7152*rgba[p+1]+.0722*rgba[p+2])/255*(rgba[p+3]/255);
|
|
11
|
+
values[i]=luma===0?0:clamp((Math.pow(luma,.9)*brightness-.5)*contrast+.5);
|
|
12
|
+
}
|
|
13
|
+
if(method==='stable'){
|
|
14
|
+
// Fixed per-pixel threshold, not fresh random noise on every animation tick.
|
|
15
|
+
// Unlike the 4x4 Bayer matrix this avoids a repeating cross-hatch on fur.
|
|
16
|
+
for(let y=0;y<height;y++)for(let x=0;x<width;x++){
|
|
17
|
+
let n=Math.imul(x+1,0x1f123bb5)^Math.imul(y+1,0x5f356495);
|
|
18
|
+
n=Math.imul(n^(n>>>16),0x45d9f3b);n=Math.imul(n^(n>>>16),0x45d9f3b);n=(n^(n>>>16))>>>0;
|
|
19
|
+
bits[y*width+x]=values[y*width+x]>(n+.5)/4294967296?1:0;
|
|
20
|
+
}
|
|
21
|
+
}else if(method==='bayer'){
|
|
22
|
+
for(let y=0;y<height;y++)for(let x=0;x<width;x++)bits[y*width+x]=values[y*width+x]>(BAYER[y%4][x%4]+.5)/16?1:0;
|
|
23
|
+
}else{
|
|
24
|
+
const add=(x,y,error,weight)=>{if(x>=0&&x<width&&y<height)values[y*width+x]+=error*weight/16;};
|
|
25
|
+
for(let y=0;y<height;y++){
|
|
26
|
+
const direction=y%2?-1:1;
|
|
27
|
+
for(let k=0;k<width;k++){
|
|
28
|
+
const x=direction===1?k:width-1-k,i=y*width+x,old=values[i],value=old>=.5?1:0,error=old-value;
|
|
29
|
+
bits[i]=value;add(x+direction,y,error,7);add(x-direction,y+1,error,3);add(x,y+1,error,5);add(x+direction,y+1,error,1);
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
const columns=Math.ceil(width/2),rows=Math.ceil(height/4),lines=[];
|
|
34
|
+
for(let cy=0;cy<rows;cy++){
|
|
35
|
+
let line='';
|
|
36
|
+
for(let cx=0;cx<columns;cx++){
|
|
37
|
+
let mask=0;for(let dy=0;dy<4;dy++)for(let dx=0;dx<2;dx++){
|
|
38
|
+
const x=cx*2+dx,y=cy*4+dy;if(x<width&&y<height&&bits[y*width+x])mask|=BRAILLE_BITS[dy][dx];
|
|
39
|
+
}
|
|
40
|
+
line+=String.fromCodePoint(0x2800+mask);
|
|
41
|
+
}
|
|
42
|
+
lines.push(line);
|
|
43
|
+
}
|
|
44
|
+
return {text:lines.join('\n'),columns,rows,dots:bits.reduce((a,b)=>a+b,0)};
|
|
45
|
+
}
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
"""Minimal non-JS host: one plain frame, no terminal/input ownership.
|
|
2
|
+
|
|
3
|
+
python examples/bridge.py [--bridge /installed/path/retrieviewer-stdio.mjs]
|
|
4
|
+
Use request(op='tick', dt=elapsed_seconds, columns=..., rows=...) in your TUI loop.
|
|
5
|
+
Node >=20 is required. Only Python's standard library is used.
|
|
6
|
+
"""
|
|
7
|
+
import argparse
|
|
8
|
+
import json
|
|
9
|
+
from pathlib import Path
|
|
10
|
+
import subprocess
|
|
11
|
+
import sys
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
class PetBridge:
|
|
15
|
+
def __init__(self, bridge):
|
|
16
|
+
self.process = subprocess.Popen(
|
|
17
|
+
["node", str(bridge)], stdin=subprocess.PIPE, stdout=subprocess.PIPE,
|
|
18
|
+
text=True, encoding="utf-8", bufsize=1,
|
|
19
|
+
)
|
|
20
|
+
self.serial = 0
|
|
21
|
+
try:
|
|
22
|
+
ready = json.loads(self.process.stdout.readline())
|
|
23
|
+
if ready != {"event": "ready", "protocol": 1}:
|
|
24
|
+
raise RuntimeError("Unsupported pet protocol")
|
|
25
|
+
except BaseException:
|
|
26
|
+
self.close()
|
|
27
|
+
raise
|
|
28
|
+
|
|
29
|
+
def request(self, **request):
|
|
30
|
+
self.serial += 1
|
|
31
|
+
request["id"] = self.serial
|
|
32
|
+
self.process.stdin.write(json.dumps(request) + "\n")
|
|
33
|
+
self.process.stdin.flush()
|
|
34
|
+
response = json.loads(self.process.stdout.readline())
|
|
35
|
+
if response.get("id") != self.serial or not response.get("ok"):
|
|
36
|
+
raise RuntimeError(response.get("error", "Pet protocol mismatch"))
|
|
37
|
+
return response
|
|
38
|
+
|
|
39
|
+
def close(self):
|
|
40
|
+
if self.process.stdin and not self.process.stdin.closed:
|
|
41
|
+
self.process.stdin.close() # EOF releases pet even after host errors.
|
|
42
|
+
try:
|
|
43
|
+
self.process.wait(timeout=5)
|
|
44
|
+
except subprocess.TimeoutExpired:
|
|
45
|
+
self.process.terminate()
|
|
46
|
+
self.process.wait(timeout=5)
|
|
47
|
+
finally:
|
|
48
|
+
self.process.stdout.close()
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
if __name__ == "__main__":
|
|
52
|
+
parser = argparse.ArgumentParser(description=__doc__)
|
|
53
|
+
parser.add_argument("--bridge", type=Path,
|
|
54
|
+
default=Path(__file__).resolve().parents[1] / "retrieviewer-stdio.mjs")
|
|
55
|
+
args = parser.parse_args()
|
|
56
|
+
pet = PetBridge(args.bridge)
|
|
57
|
+
try:
|
|
58
|
+
frame = pet.request(op="tick", dt=1 / 30, columns=48, rows=14)
|
|
59
|
+
sys.stdout.reconfigure(encoding="utf-8")
|
|
60
|
+
sys.stdout.write(frame["text"] + "\n")
|
|
61
|
+
finally:
|
|
62
|
+
pet.close()
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
// Minimal embed: print one plain Braille frame and exit. No fullscreen, no ANSI.
|
|
2
|
+
// Run from anywhere: node examples/embed.mjs [columns] [rows]
|
|
3
|
+
import {createPet} from '../retrieviewer.mjs';
|
|
4
|
+
|
|
5
|
+
const columns=Number(process.argv[2]??48),rows=Number(process.argv[3]??14);
|
|
6
|
+
const pet=await createPet();
|
|
7
|
+
try{
|
|
8
|
+
// A real TUI calls step(elapsedSeconds) from ITS OWN loop (timer, render tick,
|
|
9
|
+
// input poll), then frame() with the current pane size. Here we fake 3 s of life.
|
|
10
|
+
for(let i=0;i<90;i++)pet.step(1/30);
|
|
11
|
+
const {text}=pet.frame({columns,rows});
|
|
12
|
+
process.stdout.write(text+'\n');
|
|
13
|
+
}finally{
|
|
14
|
+
pet.dispose(); // release caches/renderer when the pane closes
|
|
15
|
+
}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
// Opt-in terminal host. The imported pet itself never touches terminal I/O.
|
|
3
|
+
import {createPet} from '../retrieviewer.mjs';
|
|
4
|
+
import {once} from 'node:events';
|
|
5
|
+
|
|
6
|
+
const pet=await createPet({artProfile:process.argv.includes('--original')?'original':'q5'}),out=process.stdout,input=process.stdin;
|
|
7
|
+
if(!out.isTTY||!input.isTTY){
|
|
8
|
+
try{out.write(pet.frame({columns:80,rows:24}).text+'\n');}finally{pet.dispose();}
|
|
9
|
+
}else{
|
|
10
|
+
let stopped=false,paused=false,last=performance.now(),previous=[],key='';
|
|
11
|
+
const wasRaw=!!input.isRaw;
|
|
12
|
+
const stop=()=>{stopped=true;};
|
|
13
|
+
const data=bytes=>{for(const c of bytes.toString()){
|
|
14
|
+
if(c==='q'||c==='\x03')stop();
|
|
15
|
+
if(c===' ')paused=!paused;
|
|
16
|
+
if(c==='b'||c==='t'){if(pet.interact(c==='b'?'ball':'treat'))paused=false;}
|
|
17
|
+
}};
|
|
18
|
+
process.on('SIGINT',stop);process.on('SIGTERM',stop);
|
|
19
|
+
input.setRawMode(true);input.resume();input.on('data',data);
|
|
20
|
+
out.write('\x1b[?1049h\x1b[?25l\x1b[2J');
|
|
21
|
+
try{
|
|
22
|
+
while(!stopped){
|
|
23
|
+
const start=performance.now();if(!paused)pet.step((start-last)/1000);last=start;
|
|
24
|
+
const columns=Math.max(1,(out.columns??80)-1),available=Math.max(1,(out.rows??24)-2);
|
|
25
|
+
const rows=Math.min(available,Math.max(1,Math.floor(125000/columns)));
|
|
26
|
+
const nextKey=`${columns}/${rows}`;
|
|
27
|
+
if(key!==nextKey){key=nextKey;previous=[];out.write('\x1b[2J');}
|
|
28
|
+
const frame=pet.frame({columns,rows}),lines=frame.text.split('\n');let batch='';
|
|
29
|
+
for(let y=0;y<rows;y++)if(lines[y]!==previous[y])batch+=`\x1b[${y+1};1H${lines[y]}`;
|
|
30
|
+
previous=lines;
|
|
31
|
+
const status=`${paused?'Paused':frame.report.intent} | B ball T treat Space pause Q quit`.slice(0,columns);
|
|
32
|
+
batch+=`\x1b[${rows+1};1H\x1b[2K${status}`;
|
|
33
|
+
if(!out.write(batch))await once(out,'drain');
|
|
34
|
+
await new Promise(resolve=>setTimeout(resolve,Math.max(1,1000/30-(performance.now()-start))));
|
|
35
|
+
}
|
|
36
|
+
}finally{
|
|
37
|
+
process.off('SIGINT',stop);process.off('SIGTERM',stop);input.off('data',data);
|
|
38
|
+
input.setRawMode(wasRaw);input.pause();out.write('\x1b[0m\x1b[?25h\x1b[?1049l');pet.dispose();
|
|
39
|
+
}
|
|
40
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
// Plugin embed with a host-owned loop: the host supplies the pane size, receives
|
|
2
|
+
// frames and drives time with tick(). No timers, raw mode or escape codes here.
|
|
3
|
+
// Run from an installed package: node examples/plugin.mjs [columns] [rows]
|
|
4
|
+
import {createPetPlugin} from '@bitefoundry/retrieviewer/plugin';
|
|
5
|
+
|
|
6
|
+
const columns=Number(process.argv[2]??48),rows=Number(process.argv[3]??14);
|
|
7
|
+
let latest='';
|
|
8
|
+
const plugin=await createPetPlugin({host:{
|
|
9
|
+
getSize:()=>({columns,rows}), // return null while the pane is hidden
|
|
10
|
+
render:frame=>{latest=frame.text;}, // copy what you keep; pixels are borrowed
|
|
11
|
+
clear:()=>{latest='';},
|
|
12
|
+
}});
|
|
13
|
+
try{
|
|
14
|
+
// A real TUI calls tick(elapsedSeconds) from ITS OWN render loop. Here: 3 s of life.
|
|
15
|
+
for(let i=0;i<90;i++)plugin.tick(1/30);
|
|
16
|
+
const lines=latest.split('\n');
|
|
17
|
+
if(lines.length!==rows||lines.some(l=>[...l].length!==columns||!/^[⠀-⣿]*$/u.test(l)))throw Error('frame is not exact plain Braille');
|
|
18
|
+
process.stdout.write(latest+'\n');
|
|
19
|
+
}finally{
|
|
20
|
+
plugin.dispose(); // stops the pet and calls clear() once
|
|
21
|
+
}
|
|
@@ -0,0 +1,195 @@
|
|
|
1
|
+
// Host-neutral controller behind the OpenCode TUI widget. One pet core is shared by
|
|
2
|
+
// every mounted slot view; the most recently attached view receives frames. Import
|
|
3
|
+
// and creation start no timer and load no art or settings: the first attach() starts
|
|
4
|
+
// a <=1 Hz settings poll, and only an enabled, visible view loads the pet. It never
|
|
5
|
+
// touches stdin/stdout, the alternate screen, processes, windows or the network.
|
|
6
|
+
|
|
7
|
+
export const AGENT='opencode';
|
|
8
|
+
export const DEFAULT_FPS=30;
|
|
9
|
+
export const POLL_MS=1000;
|
|
10
|
+
export const HEARTBEAT_MS=5000;
|
|
11
|
+
// Bounded so the host prompt stays usable: at most 64x12 cells, hidden when the
|
|
12
|
+
// terminal is too small for a legible pet.
|
|
13
|
+
export const LIMITS=Object.freeze({maxColumns:64,maxRows:12,minColumns:20,minRows:5,sideMargin:4,reservedRows:14});
|
|
14
|
+
export const COMMANDS=Object.freeze(['enable','disable','ball','treat','status']);
|
|
15
|
+
|
|
16
|
+
const fn=(value,name)=>{if(typeof value!=='function')throw TypeError(`${name} must be a function`);};
|
|
17
|
+
const defaultScheduler=()=>({now:()=>performance.now(),schedule:(callback,delayMs)=>setTimeout(callback,delayMs),cancel:handle=>clearTimeout(handle)});
|
|
18
|
+
const defaultLoadPlugin=async()=>(await import('../../retrieviewer-plugin.mjs')).createPetPlugin;
|
|
19
|
+
const defaultLoadSettings=()=>import('../../retrieviewer-config.mjs');
|
|
20
|
+
|
|
21
|
+
// Terminal viewport (cells) -> pet pane, or null when hidden/too small.
|
|
22
|
+
export function petViewport(viewport){
|
|
23
|
+
if(!viewport||typeof viewport!=='object')return null;
|
|
24
|
+
const {width,height}=viewport;
|
|
25
|
+
if(!Number.isFinite(width)||!Number.isFinite(height))return null;
|
|
26
|
+
const columns=Math.min(LIMITS.maxColumns,Math.floor(width)-LIMITS.sideMargin);
|
|
27
|
+
const rows=Math.min(LIMITS.maxRows,Math.floor((Math.floor(height)-LIMITS.reservedRows)/2));
|
|
28
|
+
return columns<LIMITS.minColumns||rows<LIMITS.minRows?null:{columns,rows};
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
export function createOpenCodePetController({hostVersion='unknown',scheduler,fps=DEFAULT_FPS,petOptions,loadPlugin=defaultLoadPlugin,loadSettings=defaultLoadSettings,onError}={}){
|
|
32
|
+
if(scheduler!==undefined){fn(scheduler?.now,'scheduler.now');fn(scheduler.schedule,'scheduler.schedule');fn(scheduler.cancel,'scheduler.cancel');}
|
|
33
|
+
fn(loadPlugin,'loadPlugin');fn(loadSettings,'loadSettings');
|
|
34
|
+
if(onError!==undefined)fn(onError,'onError');
|
|
35
|
+
const clock=scheduler??defaultScheduler();
|
|
36
|
+
const views=new Set();
|
|
37
|
+
let active=null,shown=null,enabled=false,disposed=false;
|
|
38
|
+
let plugin=null,loading=false,gen=0;
|
|
39
|
+
let settings=null,pollHandle=null,polling=false,epoch=0,hiddenCheck=null,pollError=null;
|
|
40
|
+
let receipt=null,writes=Promise.resolve();
|
|
41
|
+
const report=error=>{try{onError?.(error);}catch{}};
|
|
42
|
+
const settingsModule=()=>settings??=Promise.resolve().then(loadSettings);
|
|
43
|
+
|
|
44
|
+
// Receipts carry our own state only, serialized so phases never reorder.
|
|
45
|
+
function writeReceipt(phase){
|
|
46
|
+
if(!receipt)return;
|
|
47
|
+
const body={hostVersion:String(hostVersion),phase,firstFrameAt:receipt.firstFrameAt,columns:receipt.columns,rows:receipt.rows,frames:receipt.frames};
|
|
48
|
+
writes=writes.then(async()=>{const m=await settingsModule();await m.writeRuntimeReceipt(AGENT,body);}).catch(report);
|
|
49
|
+
}
|
|
50
|
+
function show(view,text){if(!view)return;view.render(text);shown=text?view:(shown===view?null:shown);}
|
|
51
|
+
function clearShown(){if(shown){const v=shown;shown=null;v.render('');}}
|
|
52
|
+
|
|
53
|
+
const host={
|
|
54
|
+
getSize(){
|
|
55
|
+
const box=active?petViewport(active.getViewport()):null;
|
|
56
|
+
if(!box&&!hiddenCheck)hiddenCheck=clock.schedule(()=>{hiddenCheck=null;reconcile();},0);
|
|
57
|
+
return box;
|
|
58
|
+
},
|
|
59
|
+
render(frame){
|
|
60
|
+
if(!active)return;
|
|
61
|
+
if(shown&&shown!==active)clearShown();
|
|
62
|
+
show(active,frame.text);
|
|
63
|
+
const now=clock.now();
|
|
64
|
+
if(!receipt){receipt={firstFrameAt:new Date().toISOString(),frames:1,beat:now,columns:frame.columns,rows:frame.rows};writeReceipt('rendering');return;}
|
|
65
|
+
receipt.frames++;receipt.columns=frame.columns;receipt.rows=frame.rows;
|
|
66
|
+
if(now-receipt.beat>=HEARTBEAT_MS){receipt.beat=now;writeReceipt('rendering');}
|
|
67
|
+
},
|
|
68
|
+
clear:clearShown,
|
|
69
|
+
onError(error){stopPet();report(error);},
|
|
70
|
+
};
|
|
71
|
+
|
|
72
|
+
function stopPet(){
|
|
73
|
+
gen++;loading=false;
|
|
74
|
+
if(hiddenCheck){clock.cancel(hiddenCheck);hiddenCheck=null;}
|
|
75
|
+
const p=plugin;plugin=null;
|
|
76
|
+
try{p?.dispose();}catch(error){report(error);}
|
|
77
|
+
clearShown();
|
|
78
|
+
if(receipt){writeReceipt('stopped');receipt=null;}
|
|
79
|
+
}
|
|
80
|
+
const wanted=()=>!disposed&&enabled&&views.size>0;
|
|
81
|
+
|
|
82
|
+
async function load(){
|
|
83
|
+
const mine=++gen;loading=true;
|
|
84
|
+
try{
|
|
85
|
+
const create=await loadPlugin();
|
|
86
|
+
if(mine!==gen||!wanted())return;
|
|
87
|
+
const p=await create({host,fps,petOptions,scheduler:clock});
|
|
88
|
+
// Disabled, unmounted or reloaded while the art loaded: release it unseen.
|
|
89
|
+
if(mine!==gen||!wanted()){p.dispose();return;}
|
|
90
|
+
plugin=p;
|
|
91
|
+
}catch(error){if(mine===gen)report(error);return;}
|
|
92
|
+
finally{if(mine===gen)loading=false;}
|
|
93
|
+
reconcile();
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
function reconcile(redraw=false){
|
|
97
|
+
if(!wanted()){if(plugin||loading||receipt)stopPet();return;}
|
|
98
|
+
if(!plugin){if(!loading)load();return;}
|
|
99
|
+
const box=active?petViewport(active.getViewport()):null;
|
|
100
|
+
// Hidden: no timer and no simulated time until a refresh reveals the pane.
|
|
101
|
+
if(!box){plugin.pause();clearShown();return;}
|
|
102
|
+
try{if(!plugin.running)plugin.start();else if(redraw)plugin.render();}
|
|
103
|
+
catch(error){stopPet();report(error);}
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
function schedulePoll(){
|
|
107
|
+
if(disposed||views.size===0||pollHandle!==null)return;
|
|
108
|
+
pollHandle=clock.schedule(()=>{pollHandle=null;poll();},POLL_MS);
|
|
109
|
+
}
|
|
110
|
+
async function poll(){
|
|
111
|
+
if(disposed||views.size===0||polling)return;
|
|
112
|
+
polling=true;const seen=epoch;
|
|
113
|
+
try{
|
|
114
|
+
const m=await settingsModule();
|
|
115
|
+
const s=await m.readAgentSettings(AGENT);
|
|
116
|
+
pollError=null;
|
|
117
|
+
if(seen===epoch&&!disposed){enabled=s?.enabled===true;reconcile();}
|
|
118
|
+
}catch(error){
|
|
119
|
+
// A persistent failure (e.g. missing settings module) is reported once, not per poll.
|
|
120
|
+
const key=String(error?.message??error);
|
|
121
|
+
if(key!==pollError){pollError=key;report(error);}
|
|
122
|
+
}
|
|
123
|
+
finally{polling=false;schedulePoll();}
|
|
124
|
+
}
|
|
125
|
+
function stopPolling(){if(pollHandle!==null){clock.cancel(pollHandle);pollHandle=null;}}
|
|
126
|
+
|
|
127
|
+
async function setEnabled(value){
|
|
128
|
+
if(typeof value!=='boolean')throw TypeError('enabled must be boolean');
|
|
129
|
+
const m=await settingsModule();
|
|
130
|
+
await m.setAgentEnabled(AGENT,value);
|
|
131
|
+
epoch++;
|
|
132
|
+
if(disposed)return;
|
|
133
|
+
enabled=value;reconcile();
|
|
134
|
+
}
|
|
135
|
+
function interact(kind){
|
|
136
|
+
if(kind!=='ball'&&kind!=='treat')throw TypeError("kind must be 'ball' or 'treat'");
|
|
137
|
+
return plugin?plugin.interact(kind):false;
|
|
138
|
+
}
|
|
139
|
+
function status(){
|
|
140
|
+
return {enabled,mounted:views.size,loading,running:!!plugin?.running,frames:receipt?.frames??0,columns:receipt?.columns??null,rows:receipt?.rows??null,firstFrameAt:receipt?.firstFrameAt??null};
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
return {
|
|
144
|
+
// view: {getViewport(): {width,height}|null, render(text: string): void}. Text is
|
|
145
|
+
// plain Braille (rows lines); '' means show nothing.
|
|
146
|
+
attach(view){
|
|
147
|
+
if(disposed)throw Error('OpenCode pet controller is disposed');
|
|
148
|
+
if(!view||typeof view!=='object')throw TypeError('view must be an object');
|
|
149
|
+
fn(view.getViewport,'view.getViewport');fn(view.render,'view.render');
|
|
150
|
+
const record={getViewport:view.getViewport,render:view.render};
|
|
151
|
+
views.add(record);active=record;
|
|
152
|
+
if(views.size===1)poll();
|
|
153
|
+
reconcile(true);
|
|
154
|
+
let attached=true;
|
|
155
|
+
return {
|
|
156
|
+
// Call on resize or visibility change; re-derives the pane from the viewport.
|
|
157
|
+
refresh(){if(attached&&!disposed)reconcile(true);},
|
|
158
|
+
detach(){
|
|
159
|
+
if(!attached)return;attached=false;
|
|
160
|
+
views.delete(record);
|
|
161
|
+
if(shown===record)clearShown();
|
|
162
|
+
if(active===record)active=[...views].at(-1)??null;
|
|
163
|
+
if(views.size===0)stopPolling();
|
|
164
|
+
if(!disposed)reconcile(true);
|
|
165
|
+
},
|
|
166
|
+
};
|
|
167
|
+
},
|
|
168
|
+
setEnabled,
|
|
169
|
+
interact,
|
|
170
|
+
status,
|
|
171
|
+
// Slash handler: '/retrieviewer <enable|disable|ball|treat|status>'.
|
|
172
|
+
async command(argument){
|
|
173
|
+
const word=String(argument??'').trim().toLowerCase()||'status';
|
|
174
|
+
if(word==='enable'||word==='disable'){await setEnabled(word==='enable');return word==='enable'?'Retrieviewer enabled':'Retrieviewer disabled';}
|
|
175
|
+
if(word==='ball'||word==='treat'){
|
|
176
|
+
if(!plugin)return enabled?'Retrieviewer is still loading':'Retrieviewer is disabled; run /retrieviewer enable';
|
|
177
|
+
return interact(word)?`Retrieviewer: ${word} accepted`:`Retrieviewer is busy; ${word} not accepted`;
|
|
178
|
+
}
|
|
179
|
+
if(word==='status'){
|
|
180
|
+
const s=status();
|
|
181
|
+
return `Retrieviewer ${s.enabled?'enabled':'disabled'}, ${s.running?`rendering ${s.columns}x${s.rows}, ${s.frames} frames`:s.loading?'loading':'idle'}, ${s.mounted} view(s)`;
|
|
182
|
+
}
|
|
183
|
+
return `Usage: /retrieviewer ${COMMANDS.join('|')}`;
|
|
184
|
+
},
|
|
185
|
+
// Resolves once queued receipt writes have finished (for clean shutdown/tests).
|
|
186
|
+
settled(){return writes;},
|
|
187
|
+
get disposed(){return disposed;},
|
|
188
|
+
dispose(){
|
|
189
|
+
if(disposed)return writes;
|
|
190
|
+
disposed=true;stopPolling();stopPet();
|
|
191
|
+
views.clear();active=null;
|
|
192
|
+
return writes;
|
|
193
|
+
},
|
|
194
|
+
};
|
|
195
|
+
}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
/** @jsxImportSource @opentui/solid */
|
|
2
|
+
// OpenCode v2 TUI plugin: the Retrieviewer pet drawn inside OpenCode's own UI (home
|
|
3
|
+
// footer and session composer slots). The host resolves @opencode/plugin/tui,
|
|
4
|
+
// @opentui/solid and solid-js and compiles this file; no production dependency here.
|
|
5
|
+
// All lifecycle lives in ./runtime.mjs, which loads nothing until a view mounts.
|
|
6
|
+
import {Plugin} from '@opencode/plugin/tui';
|
|
7
|
+
import {useTerminalDimensions} from '@opentui/solid';
|
|
8
|
+
import {createEffect, createSignal, onCleanup, Show} from 'solid-js';
|
|
9
|
+
import {createOpenCodePetController} from './runtime.mjs';
|
|
10
|
+
|
|
11
|
+
export default Plugin.define({
|
|
12
|
+
id:'retrieviewer.pet',
|
|
13
|
+
setup(context){
|
|
14
|
+
const toast=(message,variant='info')=>context.ui.toast.show({title:'Retrieviewer',message,variant});
|
|
15
|
+
const pet=createOpenCodePetController({
|
|
16
|
+
hostVersion:context.app?.version??'unknown',
|
|
17
|
+
onError:error=>toast(String(error?.message??error),'error'),
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
// One view per mounted slot; all share the single pet core in the controller.
|
|
21
|
+
function PetView(){
|
|
22
|
+
const dimensions=useTerminalDimensions();
|
|
23
|
+
const [text,setText]=createSignal('');
|
|
24
|
+
const view=pet.attach({
|
|
25
|
+
getViewport:()=>{const {width,height}=dimensions();return {width,height};},
|
|
26
|
+
render:value=>setText(value),
|
|
27
|
+
});
|
|
28
|
+
createEffect(()=>{dimensions();view.refresh();});
|
|
29
|
+
onCleanup(()=>view.detach());
|
|
30
|
+
return (
|
|
31
|
+
<Show when={text()}>
|
|
32
|
+
<box flexShrink={0} paddingLeft={2}>
|
|
33
|
+
<text wrapMode="none" fg={context.theme.text.base}>{text()}</text>
|
|
34
|
+
</box>
|
|
35
|
+
</Show>
|
|
36
|
+
);
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
context.ui.slot({append:'home.footer',render:()=><PetView/>});
|
|
40
|
+
context.ui.slot({append:'session.composer.top',render:()=><PetView/>});
|
|
41
|
+
context.keymap.layer(()=>({
|
|
42
|
+
mode:'global',
|
|
43
|
+
commands:[{
|
|
44
|
+
id:'retrieviewer.pet',
|
|
45
|
+
title:'Retrieviewer pet',
|
|
46
|
+
description:'enable | disable | ball | treat | status',
|
|
47
|
+
group:'Retrieviewer',
|
|
48
|
+
palette:true,
|
|
49
|
+
slash:{name:'retrieviewer',arguments:true},
|
|
50
|
+
async run(argument){
|
|
51
|
+
try{toast(await pet.command(argument));}
|
|
52
|
+
catch(error){toast(String(error?.message??error),'error');}
|
|
53
|
+
},
|
|
54
|
+
}],
|
|
55
|
+
}));
|
|
56
|
+
|
|
57
|
+
return ()=>pet.dispose();
|
|
58
|
+
},
|
|
59
|
+
});
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import * as THREE from 'three';
|
|
2
|
+
import {createAnimal} from './vendor/procedural-animals/src/index.js';
|
|
3
|
+
export const LAB_OPTIONS={variant:'retriever',age:'juvenile',seed:2,quality:'low',worker:false,overrides:{colour:'yellow',stanceSoftMargin:.005}};
|
|
4
|
+
export async function makeLabAnimal(extra={}){
|
|
5
|
+
return createAnimal('dog',{...LAB_OPTIONS,...extra,overrides:{...LAB_OPTIONS.overrides,...extra.overrides}});
|
|
6
|
+
}
|
|
7
|
+
// Never translate the mesh externally. The gait engine owns root motion + IK.
|
|
8
|
+
export function makeLabController(animal){
|
|
9
|
+
let target=null,speed=animal.gears.walk;
|
|
10
|
+
return {get target(){return target;},get speed(){return speed;},setSpeed(kind){
|
|
11
|
+
if(!['walk','trot','gallop'].includes(kind))throw Error('Unknown gait');
|
|
12
|
+
speed=animal.gears[kind];if(target)animal.moveTo(target,{speed});
|
|
13
|
+
},go(x,z){
|
|
14
|
+
if(![x,z].every(Number.isFinite))throw Error('Invalid ground target');
|
|
15
|
+
target=new THREE.Vector3(Math.max(-.8,Math.min(.8,x)),0,Math.max(-1.7,Math.min(.3,z)));
|
|
16
|
+
animal.stopAction();animal.moveTo(target,{speed});
|
|
17
|
+
},stop(){target=null;animal.stop();},update(dt){
|
|
18
|
+
if(!Number.isFinite(dt)||dt<0||dt>.1)throw Error('Invalid lab step');animal.update(dt);
|
|
19
|
+
if(target&&animal.position.distanceTo(target)<.025&&animal.speed<.03){target=null;animal.stop();}
|
|
20
|
+
}};
|
|
21
|
+
}
|
|
Binary file
|