habithive-code 0.2.1 → 0.2.3
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/README.md +23 -0
- package/package.json +1 -1
- package/src/logo.js +34 -20
package/README.md
CHANGED
|
@@ -113,6 +113,29 @@ launch (habithive reopens your session automatically after a change).
|
|
|
113
113
|
Tested against: **opencode 1.18.x**, **oh-my-openagent 4.19.x** (pinned in the installer).
|
|
114
114
|
opencode auto-updates its own binary; if a release changes internals, open an issue.
|
|
115
115
|
|
|
116
|
+
## Migrating from the previous package name
|
|
117
|
+
|
|
118
|
+
`habithive-code` is a rebrand of an earlier package that used a different name and
|
|
119
|
+
plugin entry. `habithive setup` only manages its own plugin entry, so if the old
|
|
120
|
+
package is still installed or wired into your opencode config, both load together
|
|
121
|
+
and you'll see two wordmarks stacked on the home screen. Fix it once with:
|
|
122
|
+
|
|
123
|
+
```sh
|
|
124
|
+
npm rm -g maliv-code
|
|
125
|
+
rm -rf ~/.maliv
|
|
126
|
+
node -e "
|
|
127
|
+
const fs=require('fs'), os=require('os'), path=require('path');
|
|
128
|
+
const p=path.join(os.homedir(),'.config','opencode','tui.json');
|
|
129
|
+
const c=JSON.parse(fs.readFileSync(p,'utf8'));
|
|
130
|
+
c.plugin=(c.plugin||[]).filter(e=>!String(e).includes('maliv'));
|
|
131
|
+
fs.writeFileSync(p, JSON.stringify(c,null,2)+'\n');
|
|
132
|
+
console.log('cleaned:', p);
|
|
133
|
+
"
|
|
134
|
+
habithive setup
|
|
135
|
+
```
|
|
136
|
+
This is a one-time cleanup — anyone installing `habithive-code` fresh, who never had
|
|
137
|
+
the old package, can skip this section entirely.
|
|
138
|
+
|
|
116
139
|
## Uninstall
|
|
117
140
|
|
|
118
141
|
```sh
|
package/package.json
CHANGED
package/src/logo.js
CHANGED
|
@@ -1,18 +1,21 @@
|
|
|
1
1
|
// habithive-code — home-screen wordmark in opencode's TUI.
|
|
2
2
|
//
|
|
3
|
-
// Renders a
|
|
4
|
-
//
|
|
5
|
-
//
|
|
6
|
-
//
|
|
7
|
-
//
|
|
8
|
-
//
|
|
9
|
-
//
|
|
3
|
+
// Renders a two-line mark into the `home_logo` slot:
|
|
4
|
+
// HIVE <- big <ascii_font> (block font: white
|
|
5
|
+
// HABIT Intelligent Value Engineering fill, black outline), animated
|
|
6
|
+
// <- small caption underneath
|
|
7
|
+
// A @opentui/core renderable is a valid slot node, so there's no JSX build step.
|
|
8
|
+
// We probe-construct once at register time (inside try/catch, OUTSIDE opencode's
|
|
9
|
+
// render loop) so any failure aborts gracefully instead of crashing the home
|
|
10
|
+
// screen — the slot is only registered if the probe succeeds.
|
|
10
11
|
|
|
11
|
-
const
|
|
12
|
-
const FONT = "block";
|
|
12
|
+
const TITLE_TEXT = "hive"; // ascii_font uppercases it
|
|
13
|
+
const FONT = "block"; // tiny | slick | block | huge | shade | grid | pallet
|
|
13
14
|
// `block` renders two color layers: [fill, outline]. White-on-black, opencode-style.
|
|
14
15
|
const FILL = "#ffffff";
|
|
15
16
|
const OUTLINE = "#000000";
|
|
17
|
+
const CAPTION_TEXT = "HABIT Intelligent Value Engineering";
|
|
18
|
+
const CAPTION_COLOR = "#999999";
|
|
16
19
|
const PULSE_MS = 90; // animation frame interval
|
|
17
20
|
const PULSE_STEPS = 40; // full breathing cycle length
|
|
18
21
|
|
|
@@ -33,44 +36,55 @@ export async function registerLogo(api) {
|
|
|
33
36
|
try { rctx = (rnd && rnd.renderContext) || (rnd && rnd.root && rnd.root.ctx) || null; } catch {}
|
|
34
37
|
if (!rctx) return;
|
|
35
38
|
|
|
36
|
-
let AsciiFont, RenderableEvents;
|
|
39
|
+
let AsciiFont, TextRenderable, BoxRenderable, RenderableEvents;
|
|
37
40
|
try {
|
|
38
41
|
const mod = await import("@opentui/core");
|
|
39
42
|
AsciiFont = mod.ASCIIFontRenderable;
|
|
43
|
+
TextRenderable = mod.TextRenderable;
|
|
44
|
+
BoxRenderable = mod.BoxRenderable;
|
|
40
45
|
RenderableEvents = mod.RenderableEvents;
|
|
41
46
|
} catch { return; }
|
|
42
|
-
if (typeof AsciiFont !== "function") return;
|
|
47
|
+
if (typeof AsciiFont !== "function" || typeof TextRenderable !== "function" || typeof BoxRenderable !== "function") return;
|
|
43
48
|
|
|
44
|
-
const
|
|
49
|
+
const makeTitle = () => new AsciiFont(rctx, { text: TITLE_TEXT, font: FONT, color: [FILL, OUTLINE] });
|
|
50
|
+
const makeCaption = () => new TextRenderable(rctx, { content: CAPTION_TEXT, fg: CAPTION_COLOR });
|
|
51
|
+
const make = () => {
|
|
52
|
+
const box = new BoxRenderable(rctx, { flexDirection: "column", rowGap: 1 });
|
|
53
|
+
const title = makeTitle();
|
|
54
|
+
const caption = makeCaption();
|
|
55
|
+
box.add(title);
|
|
56
|
+
box.add(caption);
|
|
57
|
+
return { box, title };
|
|
58
|
+
};
|
|
45
59
|
|
|
46
60
|
// Prove construction works before registering (a throw here is caught → no crash).
|
|
47
61
|
try {
|
|
48
62
|
const probe = make();
|
|
49
|
-
if (probe && typeof probe.destroyRecursively === "function") probe.destroyRecursively();
|
|
63
|
+
if (probe.box && typeof probe.box.destroyRecursively === "function") probe.box.destroyRecursively();
|
|
50
64
|
} catch { return; }
|
|
51
65
|
|
|
52
66
|
api.slots.register({
|
|
53
67
|
slots: {
|
|
54
68
|
home_logo: () => {
|
|
55
|
-
const
|
|
69
|
+
const { box, title } = make();
|
|
56
70
|
try {
|
|
57
71
|
let step = 0;
|
|
58
72
|
const timer = setInterval(() => {
|
|
59
73
|
try {
|
|
60
74
|
step = (step + 1) % PULSE_STEPS;
|
|
61
|
-
|
|
75
|
+
title.color = [breathGray(step), OUTLINE];
|
|
62
76
|
} catch { clearInterval(timer); }
|
|
63
77
|
}, PULSE_MS);
|
|
64
78
|
const stop = () => clearInterval(timer);
|
|
65
|
-
if (RenderableEvents && typeof
|
|
66
|
-
|
|
67
|
-
} else if (typeof
|
|
68
|
-
|
|
79
|
+
if (RenderableEvents && typeof box.once === "function") {
|
|
80
|
+
box.once(RenderableEvents.DESTROYED, stop);
|
|
81
|
+
} else if (typeof box.on === "function") {
|
|
82
|
+
box.on("destroyed", stop);
|
|
69
83
|
}
|
|
70
84
|
} catch {
|
|
71
85
|
// animation is best-effort; a static logo still renders if this fails
|
|
72
86
|
}
|
|
73
|
-
return
|
|
87
|
+
return box;
|
|
74
88
|
},
|
|
75
89
|
},
|
|
76
90
|
});
|