@hanzo/build 0.2.67 → 0.2.68
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/lib/gear.js +41 -11
- package/package.json +1 -1
package/lib/gear.js
CHANGED
|
@@ -9,9 +9,13 @@
|
|
|
9
9
|
*
|
|
10
10
|
* Both live in the account, so a choice follows the person to every device. A
|
|
11
11
|
* conversation that has none of its own reads the default; changing one writes
|
|
12
|
-
* that conversation's
|
|
12
|
+
* that conversation's. A conversation not begun holds its choice on the page
|
|
13
|
+
* (`draft`) and hands it to the conversation once it has an id. What carries
|
|
14
|
+
* over to the next new conversation is only the switches (`STICKY`: Research,
|
|
15
|
+
* Memory, the mode); a skill or a plugin is picked for the conversation it was
|
|
16
|
+
* picked in.
|
|
13
17
|
*/
|
|
14
|
-
import { useCallback, useEffect, useMemo, useState, useSyncExternalStore } from 'react';
|
|
18
|
+
import { useCallback, useEffect, useMemo, useRef, useState, useSyncExternalStore } from 'react';
|
|
15
19
|
import { call } from './api/call.js';
|
|
16
20
|
/**
|
|
17
21
|
* The modes the platform honours. Manual and Accept edits are not here: a cloud
|
|
@@ -32,6 +36,9 @@ export const BARE = {
|
|
|
32
36
|
memory: true,
|
|
33
37
|
mode: 'auto',
|
|
34
38
|
};
|
|
39
|
+
/** What a new conversation carries over from the last: the switches, never a pick. */
|
|
40
|
+
const STICKY = ['research', 'memory', 'mode'];
|
|
41
|
+
const pick = (g) => ({ research: g.research, memory: g.memory, mode: g.mode });
|
|
35
42
|
/** How many conversations keep a choice of their own: the document holds 16 KiB in all. */
|
|
36
43
|
export const KEEP = 30;
|
|
37
44
|
const list = (v) => (Array.isArray(v) ? v.filter((x) => typeof x === 'string' && x !== '') : []);
|
|
@@ -62,7 +69,7 @@ export function shelve(gears, key, g) {
|
|
|
62
69
|
}
|
|
63
70
|
return out;
|
|
64
71
|
}
|
|
65
|
-
let doc = { gear: BARE, gears: {}, language: null };
|
|
72
|
+
let doc = { gear: BARE, gears: {}, draft: null, language: null };
|
|
66
73
|
let loaded = null;
|
|
67
74
|
const listeners = new Set();
|
|
68
75
|
const emit = () => listeners.forEach((f) => f());
|
|
@@ -81,7 +88,7 @@ function load(t) {
|
|
|
81
88
|
const gear = gearOf(raw.gear);
|
|
82
89
|
const all = raw.gears && typeof raw.gears === 'object' ? raw.gears : {};
|
|
83
90
|
const language = typeof raw.language === 'string' && raw.language ? raw.language : null;
|
|
84
|
-
doc = { gear, gears: Object.fromEntries(Object.entries(all).map(([k, v]) => [k, gearOf(v, gear)])), language };
|
|
91
|
+
doc = { gear, gears: Object.fromEntries(Object.entries(all).map(([k, v]) => [k, gearOf(v, gear)])), draft: doc.draft, language };
|
|
85
92
|
emit();
|
|
86
93
|
})
|
|
87
94
|
.catch(() => {
|
|
@@ -96,16 +103,39 @@ export function useGear(t, key = '') {
|
|
|
96
103
|
useEffect(() => load(t), [t]);
|
|
97
104
|
const now = useSyncExternalStore(subscribe, () => doc, () => doc);
|
|
98
105
|
const [error, setError] = useState(null);
|
|
99
|
-
|
|
100
|
-
const
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
emit();
|
|
106
|
+
// A conversation with no choice of its own starts from the switches alone.
|
|
107
|
+
const fresh = useMemo(() => ({ ...BARE, ...pick(now.gear) }), [now.gear]);
|
|
108
|
+
const gear = key ? (now.gears[key] ?? fresh) : (now.draft ?? fresh);
|
|
109
|
+
const save = useCallback((patch) => {
|
|
104
110
|
if (!t.token())
|
|
105
111
|
return;
|
|
106
|
-
const patch = key ? { gears: fresh.gears } : { gear: g };
|
|
107
112
|
call(t, 'PATCH', '/v1/pref', patch).then(() => setError(null), (e) => setError(e instanceof Error ? e.message : 'Your choice was not saved.'));
|
|
108
|
-
}, [
|
|
113
|
+
}, [t]);
|
|
114
|
+
// The conversation just begun takes what was picked before it had an id.
|
|
115
|
+
const was = useRef(key);
|
|
116
|
+
useEffect(() => {
|
|
117
|
+
const from = was.current;
|
|
118
|
+
was.current = key;
|
|
119
|
+
if (from || !key || !doc.draft || doc.gears[key])
|
|
120
|
+
return;
|
|
121
|
+
doc = { ...doc, gears: shelve(doc.gears, key, doc.draft), draft: null };
|
|
122
|
+
emit();
|
|
123
|
+
save({ gears: doc.gears });
|
|
124
|
+
}, [key, save]);
|
|
125
|
+
const write = useCallback((g) => {
|
|
126
|
+
if (key) {
|
|
127
|
+
doc = { ...doc, gears: shelve(doc.gears, key, g) };
|
|
128
|
+
emit();
|
|
129
|
+
return save({ gears: doc.gears });
|
|
130
|
+
}
|
|
131
|
+
// Not begun: the page holds it; the switches become the default too.
|
|
132
|
+
const sticky = { ...doc.gear, ...pick(g) };
|
|
133
|
+
const moved = STICKY.some((k) => sticky[k] !== doc.gear[k]);
|
|
134
|
+
doc = { ...doc, draft: g, ...(moved ? { gear: sticky } : null) };
|
|
135
|
+
emit();
|
|
136
|
+
if (moved)
|
|
137
|
+
save({ gear: sticky });
|
|
138
|
+
}, [key, save]);
|
|
109
139
|
return useMemo(() => ({
|
|
110
140
|
gear,
|
|
111
141
|
error,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@hanzo/build",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.68",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"license": "Apache-2.0 OR MIT",
|
|
6
6
|
"description": "Hanzo Build — say what you want, watch it built, deployed and running. The builder as a component, mounted by the Hanzo app at hanzo.ai.",
|