opencode-buddy 0.2.0 → 0.2.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/package.json +1 -1
- package/src/buddy/state.js +9 -2
- package/src/index.js +31 -1
- package/src/persistence.js +10 -0
package/package.json
CHANGED
package/src/buddy/state.js
CHANGED
|
@@ -58,6 +58,7 @@ export function feed(state) {
|
|
|
58
58
|
hunger: CLAMP(state.hunger + 25),
|
|
59
59
|
energy: CLAMP(state.energy - 5),
|
|
60
60
|
lastFed: Date.now(),
|
|
61
|
+
lastTick: Date.now(),
|
|
61
62
|
};
|
|
62
63
|
}
|
|
63
64
|
|
|
@@ -68,6 +69,7 @@ export function play(state) {
|
|
|
68
69
|
energy: CLAMP(state.energy - 10),
|
|
69
70
|
hunger: CLAMP(state.hunger - 5),
|
|
70
71
|
lastPlayed: Date.now(),
|
|
72
|
+
lastTick: Date.now(),
|
|
71
73
|
xp: state.xp + 5,
|
|
72
74
|
};
|
|
73
75
|
}
|
|
@@ -76,15 +78,20 @@ export function rest(state) {
|
|
|
76
78
|
return {
|
|
77
79
|
...state,
|
|
78
80
|
energy: CLAMP(state.energy + 30),
|
|
81
|
+
lastTick: Date.now(),
|
|
79
82
|
};
|
|
80
83
|
}
|
|
81
84
|
|
|
82
85
|
export function rename(state, name) {
|
|
83
|
-
return {
|
|
86
|
+
return {
|
|
87
|
+
...state,
|
|
88
|
+
name: String(name).slice(0, 20),
|
|
89
|
+
lastTick: Date.now(),
|
|
90
|
+
};
|
|
84
91
|
}
|
|
85
92
|
|
|
86
93
|
export function switchSpecies(state, species) {
|
|
87
|
-
return { ...state, species };
|
|
94
|
+
return { ...state, species, lastTick: Date.now() };
|
|
88
95
|
}
|
|
89
96
|
|
|
90
97
|
export function celebrate(state, durationMs = 4000) {
|
package/src/index.js
CHANGED
|
@@ -55,10 +55,14 @@ export async function runInteractive({ autoSplit = true } = {}) {
|
|
|
55
55
|
let state = await loadOrInit();
|
|
56
56
|
let buddyPane = null;
|
|
57
57
|
if (autoSplit) {
|
|
58
|
-
|
|
58
|
+
// The `start` subcommand: split a side pane that runs `render`,
|
|
59
|
+
// then exit so this main-pane process goes back to the shell prompt.
|
|
60
|
+
// The render process owns the TUI; we just kick it off.
|
|
61
|
+
splitRight(
|
|
59
62
|
`cd ${process.cwd()} && exec ${process.execPath} ${process.argv[1]} render`,
|
|
60
63
|
28,
|
|
61
64
|
);
|
|
65
|
+
return;
|
|
62
66
|
}
|
|
63
67
|
|
|
64
68
|
const tui = createTui({
|
|
@@ -134,12 +138,37 @@ export async function runInteractive({ autoSplit = true } = {}) {
|
|
|
134
138
|
let lastActivity = "unknown";
|
|
135
139
|
let lastPoll = 0;
|
|
136
140
|
let lastSave = 0;
|
|
141
|
+
let lastReload = 0;
|
|
142
|
+
let lastKnownMtime = 0;
|
|
137
143
|
let running = true;
|
|
138
144
|
|
|
139
145
|
async function loop() {
|
|
140
146
|
while (running) {
|
|
141
147
|
const now = Date.now();
|
|
142
148
|
|
|
149
|
+
// 0. Reload from disk every 1.5s so the side pane picks up
|
|
150
|
+
// changes made by other processes (opencode plugin, headless
|
|
151
|
+
// CLI invocations from the main pane, etc.). Use mtime to
|
|
152
|
+
// detect external writes — lastTick is not a reliable
|
|
153
|
+
// signal because tick() rewrites it every loop.
|
|
154
|
+
if (now - lastReload > 1500) {
|
|
155
|
+
lastReload = now;
|
|
156
|
+
const mt = await persistence.mtime();
|
|
157
|
+
if (mt > 0 && mt !== lastKnownMtime) {
|
|
158
|
+
lastKnownMtime = mt;
|
|
159
|
+
const onDisk = await persistence.load();
|
|
160
|
+
if (onDisk) {
|
|
161
|
+
// Preserve in-memory transient state overrides
|
|
162
|
+
const transient = {
|
|
163
|
+
state: state.state,
|
|
164
|
+
stateUntil: state.stateUntil,
|
|
165
|
+
stateReason: state.stateReason,
|
|
166
|
+
};
|
|
167
|
+
state = { ...onDisk, ...transient };
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
|
|
143
172
|
// 1. tick attributes for time decay
|
|
144
173
|
state = tick(state, now);
|
|
145
174
|
|
|
@@ -170,6 +199,7 @@ export async function runInteractive({ autoSplit = true } = {}) {
|
|
|
170
199
|
if (now - lastSave > SAVE_EVERY_MS) {
|
|
171
200
|
lastSave = now;
|
|
172
201
|
await persistence.save(state).catch(() => {});
|
|
202
|
+
lastKnownMtime = await persistence.mtime();
|
|
173
203
|
}
|
|
174
204
|
|
|
175
205
|
await new Promise((r) => setTimeout(r, TICK_MS));
|
package/src/persistence.js
CHANGED
|
@@ -16,6 +16,16 @@ export async function load() {
|
|
|
16
16
|
}
|
|
17
17
|
}
|
|
18
18
|
|
|
19
|
+
export async function mtime() {
|
|
20
|
+
try {
|
|
21
|
+
const st = await fs.stat(FILE);
|
|
22
|
+
return st.mtimeMs;
|
|
23
|
+
} catch (err) {
|
|
24
|
+
if (err.code === "ENOENT") return 0;
|
|
25
|
+
throw err;
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
|
|
19
29
|
export async function save(state) {
|
|
20
30
|
await fs.mkdir(DIR, { recursive: true });
|
|
21
31
|
const tmp = FILE + ".tmp";
|