shadok-ai 0.9.7 → 0.9.8
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 +10 -7
- package/package.json +1 -1
- package/public/tour-steps.js +80 -22
package/README.md
CHANGED
|
@@ -144,13 +144,16 @@ Enter to skip; you can add it later from the web UI).
|
|
|
144
144
|
rename, change profile, mirror to Telegram, close — and closing it brings the
|
|
145
145
|
card back. Desktop only: the agents column is hidden on phones.
|
|
146
146
|
- **Guided tour** — on a browser's first visit, a welcome card explains what
|
|
147
|
-
shadok-ai is, then a spotlight walks the real controls: the agents
|
|
148
|
-
agent's ⋯ menu, the toolbar, the quota dials. Skip and
|
|
149
|
-
point; ⋯ → *Guided tour* replays it. A step whose target
|
|
150
|
-
**dropped rather than faked
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
147
|
+
shadok-ai is, then a spotlight walks the real controls: the agents list, an
|
|
148
|
+
agent's ⋯ menu, scheduled prompts, the toolbar, the quota dials. Skip and
|
|
149
|
+
Escape end it at any point; ⋯ → *Guided tour* replays it. A step whose target
|
|
150
|
+
isn't on screen is **dropped rather than faked** — an empty cockpit has no
|
|
151
|
+
agent menu, so it gets a shorter tour instead of a spotlight on nothing. The
|
|
152
|
+
**phone gets the whole tour**, because a step can name the landmark on either
|
|
153
|
+
layout (the agents column *or* the channel picker) and is framed on whichever
|
|
154
|
+
one is rendered. On a brand-new instance it comes **before** the sign-in card
|
|
155
|
+
— being asked to authorise an OAuth flow before you know what the thing is
|
|
156
|
+
takes it backwards.
|
|
154
157
|
- **A lead agent from the start** — an instance with no channel at all gets one:
|
|
155
158
|
`general`, running the **Shadok-Boss** profile, in the launch directory and
|
|
156
159
|
without a worktree. It is created at boot, or right after the first sign-in on
|
package/package.json
CHANGED
package/public/tour-steps.js
CHANGED
|
@@ -13,6 +13,13 @@
|
|
|
13
13
|
*
|
|
14
14
|
* `target` is a CSS selector, an array of them (framed as one rectangle), or
|
|
15
15
|
* null for the centred welcome card.
|
|
16
|
+
*
|
|
17
|
+
* An array is also how a step survives BOTH layouts: the phone and the desktop
|
|
18
|
+
* put the same landmark in different elements (the agents column becomes a
|
|
19
|
+
* `<select>`), and only one of the two is ever on screen. `unionRect` drops the
|
|
20
|
+
* absent one, so the group frames whichever exists. Before that, three of the
|
|
21
|
+
* six steps were silently filtered out on a phone — including every step that
|
|
22
|
+
* mentioned agents at all, i.e. the subject of the product.
|
|
16
23
|
*/
|
|
17
24
|
export const TOUR_STEPS = [
|
|
18
25
|
{
|
|
@@ -28,18 +35,34 @@ export const TOUR_STEPS = [
|
|
|
28
35
|
id: "agents",
|
|
29
36
|
title: "Your agents live here",
|
|
30
37
|
body:
|
|
31
|
-
"
|
|
32
|
-
"
|
|
33
|
-
"
|
|
34
|
-
|
|
38
|
+
"Every agent gets its own git worktree and branch, so several never collide. " +
|
|
39
|
+
"Pick one here to follow it, and “+ New agent” starts another. One of them is this " +
|
|
40
|
+
"cockpit's home agent: the only one that cannot be closed.",
|
|
41
|
+
// The column on desktop, the channel picker on a phone — never both at once.
|
|
42
|
+
//
|
|
43
|
+
// Which is also why this body says neither "at the top" nor "at the bottom",
|
|
44
|
+
// and no longer points at "Tweak Shadok-AI": those describe the COLUMN, and
|
|
45
|
+
// the phone's `<select>` holds one option per agent plus "+ New agent" and
|
|
46
|
+
// nothing else. A tour that names a control the reader cannot find is the
|
|
47
|
+
// same failure as a spotlight on empty space, just harder to notice.
|
|
48
|
+
// (That Tweak is unreachable on a phone at all is a real gap — in the UI,
|
|
49
|
+
// not in the tour.)
|
|
50
|
+
target: ["#tabbar", "#chanSelect"],
|
|
35
51
|
},
|
|
36
52
|
{
|
|
37
53
|
id: "tab",
|
|
38
54
|
title: "Each agent has its own menu",
|
|
39
55
|
body:
|
|
40
|
-
"
|
|
41
|
-
"
|
|
42
|
-
|
|
56
|
+
"This ⋯ holds an agent's controls: mute, reload, rename, change its profile, mirror it " +
|
|
57
|
+
"to a Telegram topic, or have it report to another agent when it finishes. " +
|
|
58
|
+
"“Context sent” shows exactly what shadok told it at spawn — and, except for the home " +
|
|
59
|
+
"agent, this is where you close it.",
|
|
60
|
+
// `#chanMenu`, NOT `.tab.active`. Two reasons, and the second is why it
|
|
61
|
+
// changed: it is literally the button this body tells you to press (the
|
|
62
|
+
// tab's own ⋯ opens the same menu), and it exists on BOTH layouts, whereas
|
|
63
|
+
// a phone has no `.tab` at all — so this step, and the schedule step below
|
|
64
|
+
// it, simply did not happen there.
|
|
65
|
+
target: "#chanMenu",
|
|
43
66
|
},
|
|
44
67
|
{
|
|
45
68
|
// Deliberately its own stop, against this file's own "group landmarks"
|
|
@@ -53,24 +76,45 @@ export const TOUR_STEPS = [
|
|
|
53
76
|
"“Schedule”, in that same ⋯ menu, pairs a recurring prompt with a shell check that runs " +
|
|
54
77
|
"without the model. Silent check → nothing happened, the agent stays asleep at zero " +
|
|
55
78
|
"tokens. Otherwise it wakes up holding the finding, and tells you here or on Telegram.",
|
|
56
|
-
target: "
|
|
79
|
+
target: "#chanMenu",
|
|
57
80
|
},
|
|
58
81
|
{
|
|
59
82
|
id: "tools",
|
|
60
83
|
title: "The toolbar",
|
|
61
|
-
//
|
|
62
|
-
//
|
|
63
|
-
//
|
|
64
|
-
//
|
|
84
|
+
// Not drawn as glyphs: this body is set with textContent, so an inline SVG
|
|
85
|
+
// icon would show as raw markup — and spelling the buttons out as emoji
|
|
86
|
+
// (🔑/👤/🔔) drifted the moment those buttons stopped being emoji.
|
|
87
|
+
//
|
|
88
|
+
// And no longer "left to right" either, which drifted the same way for the
|
|
89
|
+
// same reason: adding the ledger between secrets and profiles shifted every
|
|
90
|
+
// later name onto the wrong icon, so a reader counting along the row was
|
|
91
|
+
// told the ledger was "profiles". An order is a claim about the DOM that
|
|
92
|
+
// no test here can hold; a list of functions is not.
|
|
65
93
|
body:
|
|
66
|
-
"
|
|
67
|
-
"(role, guardrails, model), Telegram
|
|
68
|
-
"
|
|
94
|
+
"The secret vault injected into agents that need it, the shared ledger of what your " +
|
|
95
|
+
"agents have already resolved, profiles (role, guardrails, model), Telegram, and the " +
|
|
96
|
+
"notification sound. On a narrow screen they fold into the ⋯ — which also holds the " +
|
|
97
|
+
"diff of an agent's work, the palette, and replays this tour.",
|
|
69
98
|
// NOT `.hdr-tools`, which is `display: contents` on desktop and therefore
|
|
70
99
|
// generates no box at all — its rect is all zeros, so the step would have
|
|
71
100
|
// been dropped as "not visible" on the very layout where the toolbar is
|
|
72
101
|
// most obvious. Framing the buttons themselves works on both layouts.
|
|
73
|
-
|
|
102
|
+
//
|
|
103
|
+
// Every tool is listed, including the ones `reflowHeaderTools` parks inside
|
|
104
|
+
// the closed ⋯ menu on a phone: those measure {0,0,0,0} and `unionRect`
|
|
105
|
+
// now drops them, so the group frames exactly what is on screen. Listing
|
|
106
|
+
// only some of them was the older bug in the other direction — `#usersBtn`
|
|
107
|
+
// sits left of `#secretsBtn` and stayed outside the spotlight.
|
|
108
|
+
target: [
|
|
109
|
+
"#usersBtn",
|
|
110
|
+
"#secretsBtn",
|
|
111
|
+
"#ledgerBtn",
|
|
112
|
+
"#profilesBtn",
|
|
113
|
+
"#telegramBtn",
|
|
114
|
+
"#muteNotif",
|
|
115
|
+
"#moreBtn",
|
|
116
|
+
"#starBtn",
|
|
117
|
+
],
|
|
74
118
|
},
|
|
75
119
|
{
|
|
76
120
|
id: "quota",
|
|
@@ -78,7 +122,8 @@ export const TOUR_STEPS = [
|
|
|
78
122
|
body:
|
|
79
123
|
"Your 5h and 7d subscription usage. The needle's centre is the pace that would " +
|
|
80
124
|
"spend the window exactly on time, so leaning right means you're burning faster. " +
|
|
81
|
-
"
|
|
125
|
+
"To the left, the cockpit's name is yours to change, and the version beside it opens " +
|
|
126
|
+
"updates and the permission mode.",
|
|
82
127
|
target: ["#quota5h", "#quota7d"],
|
|
83
128
|
},
|
|
84
129
|
];
|
|
@@ -93,13 +138,26 @@ export function visibleSteps(steps, isVisible) {
|
|
|
93
138
|
*
|
|
94
139
|
* Null rather than a zero rect: a caller that framed {0,0,0,0} would put the
|
|
95
140
|
* spotlight on the page's top-left corner instead of skipping the step.
|
|
141
|
+
*
|
|
142
|
+
* EMPTY RECTS ARE NOT POINTS AT THE ORIGIN, and treating them as such is what
|
|
143
|
+
* broke the toolbar step on every phone. `reflowHeaderTools` moves five of the
|
|
144
|
+
* eight tool buttons into the closed ⋯ menu below 640px; a hidden element
|
|
145
|
+
* measures {0,0,0,0}, so the union's `Math.min` pinned top and left to zero and
|
|
146
|
+
* the spotlight stretched from the viewport's corner across the header —
|
|
147
|
+
* framing the brand, the version and both gauges while the body described
|
|
148
|
+
* buttons that were not on screen at all. Same family as the `.hdr-tools`
|
|
149
|
+
* zero-rect trap noted above, except that one dropped the step honestly and
|
|
150
|
+
* this one kept it and lied. Dropping the empty ones here means a group target
|
|
151
|
+
* frames whatever part of it is actually rendered, and yields null — hence a
|
|
152
|
+
* skipped step — only when none of it is.
|
|
96
153
|
*/
|
|
97
154
|
export function unionRect(rects) {
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
const
|
|
101
|
-
const
|
|
102
|
-
const
|
|
155
|
+
const real = (rects ?? []).filter((r) => r && r.width > 0 && r.height > 0);
|
|
156
|
+
if (!real.length) return null;
|
|
157
|
+
const top = Math.min(...real.map((r) => r.top));
|
|
158
|
+
const left = Math.min(...real.map((r) => r.left));
|
|
159
|
+
const bottom = Math.max(...real.map((r) => r.top + r.height));
|
|
160
|
+
const right = Math.max(...real.map((r) => r.left + r.width));
|
|
103
161
|
return { top, left, width: right - left, height: bottom - top };
|
|
104
162
|
}
|
|
105
163
|
|