sideby 0.13.0 → 0.14.0
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 +1 -1
- package/dist/build.json +1 -1
- package/dist/src/cli/commands.d.ts +3 -2
- package/dist/src/cli/commands.js +69 -8
- package/dist/src/cli/format.js +7 -3
- package/dist/src/cli/json-schemas.js +62 -2
- package/dist/src/cli/main.js +42 -4
- package/dist/src/core/config.d.ts +27 -0
- package/dist/src/core/config.js +48 -1
- package/dist/src/core/handoff-enable.js +10 -5
- package/dist/src/core/launch.d.ts +5 -0
- package/dist/src/core/launch.js +14 -3
- package/dist/src/core/quota-fetch.d.ts +22 -0
- package/dist/src/core/quota-fetch.js +98 -0
- package/dist/src/core/quota-levels.d.ts +3 -2
- package/dist/src/core/quota-levels.js +8 -4
- package/dist/src/core/quota-store.d.ts +19 -0
- package/dist/src/core/quota-store.js +62 -0
- package/dist/src/core/skill-check.d.ts +15 -0
- package/dist/src/core/skill-check.js +49 -3
- package/dist/src/core/update.d.ts +45 -0
- package/dist/src/core/update.js +72 -1
- package/dist/src/families/grok/handoff-hook.d.ts +6 -0
- package/dist/src/families/grok/handoff-hook.js +45 -2
- package/dist/src/families/grok/handoff.d.ts +6 -1
- package/dist/src/families/grok/handoff.js +30 -13
- package/dist/src/families/grok/index.js +5 -0
- package/dist/src/families/grok/quota-log.d.ts +30 -0
- package/dist/src/families/grok/quota-log.js +140 -0
- package/dist/src/families/grok/quota.d.ts +5 -0
- package/dist/src/families/grok/quota.js +112 -0
- package/dist/src/panel/handler.d.ts +9 -3
- package/dist/src/panel/handler.js +65 -3
- package/dist/src/panel/i18n.d.ts +25 -5
- package/dist/src/panel/i18n.js +52 -12
- package/dist/src/panel/page-logic.d.ts +18 -2
- package/dist/src/panel/page-logic.js +53 -6
- package/dist/src/panel/page-script.js +286 -92
- package/dist/src/panel/page-styles.js +30 -10
- package/dist/src/runtime.d.ts +30 -2
- package/dist/src/runtime.js +64 -21
- package/dist/src/types.d.ts +49 -1
- package/package.json +2 -2
- package/schemas/alias.json +62 -0
- package/schemas/app-install.json +62 -0
- package/schemas/app-uninstall.json +62 -0
- package/schemas/browser-open.json +62 -0
- package/schemas/browser-switch.json +62 -0
- package/schemas/browser.json +62 -0
- package/schemas/config.json +46 -0
- package/schemas/desktop-remove.json +62 -0
- package/schemas/desktop.json +62 -0
- package/schemas/doctor.json +62 -0
- package/schemas/error.json +62 -0
- package/schemas/families.json +62 -0
- package/schemas/handoff-disable.json +62 -0
- package/schemas/handoff-enable.json +62 -0
- package/schemas/handoff-ready.json +62 -0
- package/schemas/handoff-setup.json +62 -0
- package/schemas/handoff-status.json +62 -0
- package/schemas/handoff-teardown.json +62 -0
- package/schemas/list.json +62 -0
- package/schemas/model.json +62 -0
- package/schemas/new.json +62 -0
- package/schemas/next.json +62 -0
- package/schemas/plugins.json +62 -0
- package/schemas/quota-setup.json +62 -0
- package/schemas/quota-teardown.json +62 -0
- package/schemas/quota.json +76 -1
- package/schemas/remote-control.json +62 -0
- package/schemas/tune-change.json +62 -0
- package/schemas/tune.json +62 -0
- package/schemas/update.json +107 -1
- package/skills/sideby/SKILL.md +4 -2
- package/skills/sideby/references/diagnose.md +3 -2
- package/skills/sideby/references/handoff.md +1 -1
- package/skills/sideby/references/quota.md +5 -1
- package/skills/sideby/references/update.md +16 -0
package/dist/src/panel/i18n.js
CHANGED
|
@@ -21,7 +21,10 @@ const en = {
|
|
|
21
21
|
'upd.runs': 'Updating runs:',
|
|
22
22
|
'upd.after': 'A background panel restarts by itself and this page reloads. A sideby ui running in a terminal and sessions already running keep the old version until you restart them.',
|
|
23
23
|
'upd.cannot': 'sideby cannot update itself here: {why}. Run this yourself:',
|
|
24
|
-
'upd.skill': 'If you use the sideby skill,
|
|
24
|
+
'upd.skill': 'If you use the sideby skill, install it with:',
|
|
25
|
+
'upd.skillToo': 'The sideby skill agents read is updated with it.',
|
|
26
|
+
'upd.skillDone': 'The sideby skill was updated too; agents load it in their next session.',
|
|
27
|
+
'upd.skillManaged': 'sideby leaves the skill alone ({why}). Update it with:',
|
|
25
28
|
'upd.checksOff': 'Update checks are off ({why}).',
|
|
26
29
|
'upd.latest': 'This is the newest version',
|
|
27
30
|
'upd.latestNow': 'You have the newest version (checked just now).',
|
|
@@ -140,6 +143,26 @@ const en = {
|
|
|
140
143
|
'sort.pressure': 'Sort: quota used',
|
|
141
144
|
'sort.name': 'Sort: name',
|
|
142
145
|
'sort.recent': 'Sort: last used',
|
|
146
|
+
'sort.manual': 'Sort: my order',
|
|
147
|
+
'order.handle': 'Drag to move, or use the arrow keys',
|
|
148
|
+
'order.moveFamily': 'Move {name}',
|
|
149
|
+
'order.moveAccount': 'Move {name}',
|
|
150
|
+
'order.position': '{name}: place {n} of {total}',
|
|
151
|
+
'order.failed': 'Could not save the order: {msg}. It is back as it was.',
|
|
152
|
+
'order.resetButton': 'Default order',
|
|
153
|
+
'order.resetHint': 'Forget the order you dragged tools and accounts into',
|
|
154
|
+
'order.reset': 'Back to the default order',
|
|
155
|
+
'quota.fetchFailed': 'Could not get the quota',
|
|
156
|
+
'quota.checkOff': 'Quota check off',
|
|
157
|
+
'quota.checkOffHint': 'Turn it on in Settings to see this quota.',
|
|
158
|
+
'quota.fetchedFrom': '{host} asked for this quota {ago}',
|
|
159
|
+
'quota.lastCheckFailed': 'The latest check failed: {why}',
|
|
160
|
+
'quota.refreshFailed': 'Could not ask for the newest quota: {msg}',
|
|
161
|
+
'quota.checkOnToast': '{host} quota check is on',
|
|
162
|
+
'quota.checkOffToast': '{host} quota check is off',
|
|
163
|
+
'quota.checkFailed': 'Could not change the setting: {msg}',
|
|
164
|
+
'set.quotaCheck': '{host} quota',
|
|
165
|
+
'set.quotaCheckHint': "{host} asks for each account's quota, at most every {n} minutes. sideby never reads its login.",
|
|
143
166
|
'tb.quota': 'Show quota as',
|
|
144
167
|
'tb.used': 'Used',
|
|
145
168
|
'tb.left': 'Left',
|
|
@@ -198,13 +221,10 @@ const en = {
|
|
|
198
221
|
'quota.dataFrom': 'Data from {ago}',
|
|
199
222
|
'quota.asOf': 'As of {ago}',
|
|
200
223
|
'quota.sharedFrom': 'Same login as {name}; quota read from {name}, {ago}',
|
|
201
|
-
'quota.readFrom': 'Quota read from {name}, {ago}',
|
|
202
|
-
'login.count': '{n} directories share one quota',
|
|
203
224
|
'login.label': 'Same login: {names}',
|
|
225
|
+
'login.shared': "Shares {name}'s quota",
|
|
226
|
+
'login.sharedHint': "Signed in as the same login as {name}: the vendor counts one quota for both, shown on {name}'s row.",
|
|
204
227
|
'login.hint': '{names} are signed in as the same login. The vendor counts one quota for all of them, so it shows once here, and a handoff never moves between them.',
|
|
205
|
-
'login.sharedAbove': 'Uses the quota above',
|
|
206
|
-
'login.collapse': 'Hide {names}',
|
|
207
|
-
'login.expand': 'Show {names}',
|
|
208
228
|
'quota.noWindows': 'No quota windows reported.',
|
|
209
229
|
'quota.off': 'Quota not on',
|
|
210
230
|
'quota.turnOnFamily': 'Turn on quota',
|
|
@@ -630,7 +650,10 @@ const zh = {
|
|
|
630
650
|
'upd.runs': '更新会运行:',
|
|
631
651
|
'upd.after': '后台面板会自己重启,本页随后自动刷新。终端里运行的 sideby ui 和已经在跑的会话要重启后才用新版本。',
|
|
632
652
|
'upd.cannot': '这种安装方式下 sideby 不能自己更新:{why}。请自己运行:',
|
|
633
|
-
'upd.skill': '
|
|
653
|
+
'upd.skill': '如果要用 sideby skill,用这条命令安装:',
|
|
654
|
+
'upd.skillToo': 'agent 读的 sideby skill 会一起更新。',
|
|
655
|
+
'upd.skillDone': 'sideby skill 也已更新,agent 下次开会话时生效。',
|
|
656
|
+
'upd.skillManaged': 'sideby 不会自动更新这个 skill({why})。请用这条命令更新:',
|
|
634
657
|
'upd.checksOff': '检查更新已关闭({why})。',
|
|
635
658
|
'upd.latest': '已是最新版本',
|
|
636
659
|
'upd.latestNow': '已是最新版本(刚刚检查)。',
|
|
@@ -749,6 +772,26 @@ const zh = {
|
|
|
749
772
|
'sort.pressure': '排序:额度用量',
|
|
750
773
|
'sort.name': '排序:名称',
|
|
751
774
|
'sort.recent': '排序:最近使用',
|
|
775
|
+
'sort.manual': '排序:我的顺序',
|
|
776
|
+
'order.handle': '拖动换位置,或用方向键',
|
|
777
|
+
'order.moveFamily': '移动 {name}',
|
|
778
|
+
'order.moveAccount': '移动 {name}',
|
|
779
|
+
'order.position': '{name}:第 {n} 个,共 {total} 个',
|
|
780
|
+
'order.failed': '顺序没有保存:{msg}。已恢复原来的顺序。',
|
|
781
|
+
'order.resetButton': '默认顺序',
|
|
782
|
+
'order.resetHint': '忘掉你拖出来的工具和账号顺序',
|
|
783
|
+
'order.reset': '已恢复默认顺序',
|
|
784
|
+
'quota.fetchFailed': '没拿到额度',
|
|
785
|
+
'quota.checkOff': '额度查询已关',
|
|
786
|
+
'quota.checkOffHint': '在「设置」里打开,就能看到这份额度。',
|
|
787
|
+
'quota.fetchedFrom': '{host} {ago}查询的额度',
|
|
788
|
+
'quota.lastCheckFailed': '最近一次查询失败:{why}',
|
|
789
|
+
'quota.refreshFailed': '没能查询最新额度:{msg}',
|
|
790
|
+
'quota.checkOnToast': '已打开 {host} 额度查询',
|
|
791
|
+
'quota.checkOffToast': '已关闭 {host} 额度查询',
|
|
792
|
+
'quota.checkFailed': '设置没有改成:{msg}',
|
|
793
|
+
'set.quotaCheck': '{host} 额度',
|
|
794
|
+
'set.quotaCheckHint': '{host} 自己查询每个账号的额度,最多每 {n} 分钟一次。sideby 不读它的登录信息。',
|
|
752
795
|
'tb.quota': '额度显示方式',
|
|
753
796
|
'tb.used': '已用',
|
|
754
797
|
'tb.left': '剩余',
|
|
@@ -807,13 +850,10 @@ const zh = {
|
|
|
807
850
|
'quota.dataFrom': '数据来自 {ago}',
|
|
808
851
|
'quota.asOf': '截至 {ago}',
|
|
809
852
|
'quota.sharedFrom': '与 {name} 同一登录;额度读自 {name},{ago}',
|
|
810
|
-
'quota.readFrom': '额度读自 {name},{ago}',
|
|
811
|
-
'login.count': '{n} 个目录共用一份额度',
|
|
812
853
|
'login.label': '同一登录:{names}',
|
|
854
|
+
'login.shared': '与 {name} 共用额度',
|
|
855
|
+
'login.sharedHint': '与 {name} 用同一个身份登录,供应商只算一份额度,显示在 {name} 那一行。',
|
|
813
856
|
'login.hint': '{names} 用同一个身份登录。供应商只算一份额度,所以这里只显示一次,交接也不会在它们之间进行。',
|
|
814
|
-
'login.sharedAbove': '共用上方的额度',
|
|
815
|
-
'login.collapse': '收起 {names}',
|
|
816
|
-
'login.expand': '展开 {names}',
|
|
817
857
|
'quota.noWindows': '没有额度窗口数据。',
|
|
818
858
|
'quota.off': '额度未开启',
|
|
819
859
|
'quota.turnOnFamily': '开启额度显示',
|
|
@@ -20,6 +20,7 @@ export interface LogicAccount {
|
|
|
20
20
|
status: string;
|
|
21
21
|
windows?: {
|
|
22
22
|
label: string;
|
|
23
|
+
name?: string;
|
|
23
24
|
windowMinutes: number;
|
|
24
25
|
usedPercent: number;
|
|
25
26
|
resetsAt: string;
|
|
@@ -88,8 +89,23 @@ export declare function attentionWhy(a: LogicAccount, health: {
|
|
|
88
89
|
key: string;
|
|
89
90
|
vars: Record<string, string | number>;
|
|
90
91
|
} | null;
|
|
91
|
-
/**
|
|
92
|
-
|
|
92
|
+
/**
|
|
93
|
+
* `items` in Display Order (spec §3.25): those whose key is in `order` first, in that order; the others after, in the
|
|
94
|
+
* order they came. Names no longer there are simply not met.
|
|
95
|
+
*/
|
|
96
|
+
export declare function inDisplayOrder<T>(items: readonly T[], key: (t: T) => string, order?: readonly string[]): T[];
|
|
97
|
+
/**
|
|
98
|
+
* The Display Order after a drag (spec §3.25). `all` is every key of the list in the current Display Order, hidden
|
|
99
|
+
* ones included; `shown` is what the screen showed, in its order, as units (one key, or a Same Login group that moves
|
|
100
|
+
* as one). The unit at `from` moves to `to`; the shown keys then fill the places shown keys held in `all`, so keys a
|
|
101
|
+
* filter hides keep their place among themselves.
|
|
102
|
+
*/
|
|
103
|
+
export declare function reorder(all: readonly string[], shown: readonly (readonly string[])[], from: number, to: number): string[];
|
|
104
|
+
/**
|
|
105
|
+
* Sorted copy: `pressure` (fullest Quota first), `name`, `recent` (last activity first), or `manual` (the Family's
|
|
106
|
+
* Display Order `order`, names not in it after). The Main Account leads ties.
|
|
107
|
+
*/
|
|
108
|
+
export declare function sortAccounts<T extends LogicAccount>(list: T[], mode: string, now: number, order?: readonly string[]): T[];
|
|
93
109
|
/**
|
|
94
110
|
* The sorted list with each Same Login together (spec §3.21): an Account, or the shown members of one login, in
|
|
95
111
|
* order, at the place of its first member. A login with one shown member stays a plain Account.
|
|
@@ -44,14 +44,16 @@ export function quotaPressure(a, now) {
|
|
|
44
44
|
const q = a.quota;
|
|
45
45
|
if (q?.status !== 'ok' || !q.windows)
|
|
46
46
|
return -1;
|
|
47
|
+
// A named window covers only some models and never counts (spec §3.26).
|
|
48
|
+
const windows = q.windows.filter((w) => !w.name);
|
|
47
49
|
let max = -1;
|
|
48
|
-
for (const w of
|
|
50
|
+
for (const w of windows) {
|
|
49
51
|
const reset = Date.parse(w.resetsAt);
|
|
50
52
|
if (Number.isFinite(reset) && reset <= now)
|
|
51
53
|
continue;
|
|
52
54
|
max = Math.max(max, Math.max(0, Math.min(100, Number(w.usedPercent) || 0)));
|
|
53
55
|
}
|
|
54
|
-
return
|
|
56
|
+
return windows.length && max < 0 ? 0 : max;
|
|
55
57
|
}
|
|
56
58
|
/**
|
|
57
59
|
* Why an Account needs a look, most serious first: `error`, `health-fail`, `signed-out`, `not-installed`,
|
|
@@ -71,6 +73,8 @@ export function attentionReasons(a, health, now, warn) {
|
|
|
71
73
|
const q = a.quota;
|
|
72
74
|
if (q && q.status === 'ok' && q.windows && !q.from)
|
|
73
75
|
for (const w of q.windows) {
|
|
76
|
+
if (w.name)
|
|
77
|
+
continue;
|
|
74
78
|
const reset = Date.parse(w.resetsAt);
|
|
75
79
|
if (Number.isFinite(reset) && reset <= now)
|
|
76
80
|
continue;
|
|
@@ -96,6 +100,8 @@ export function attentionWhy(a, health, now, warn) {
|
|
|
96
100
|
return { key: `why.${reason}`, vars: {} };
|
|
97
101
|
let top = null;
|
|
98
102
|
for (const w of a.quota?.windows ?? []) {
|
|
103
|
+
if (w.name)
|
|
104
|
+
continue;
|
|
99
105
|
const reset = Date.parse(w.resetsAt);
|
|
100
106
|
if (Number.isFinite(reset) && reset <= now)
|
|
101
107
|
continue;
|
|
@@ -105,16 +111,55 @@ export function attentionWhy(a, health, now, warn) {
|
|
|
105
111
|
}
|
|
106
112
|
return { key: 'why.quota-high', vars: { label: top?.label ?? '', pct: Math.round(top?.pct ?? 0), warn } };
|
|
107
113
|
}
|
|
108
|
-
/**
|
|
109
|
-
|
|
114
|
+
/**
|
|
115
|
+
* `items` in Display Order (spec §3.25): those whose key is in `order` first, in that order; the others after, in the
|
|
116
|
+
* order they came. Names no longer there are simply not met.
|
|
117
|
+
*/
|
|
118
|
+
export function inDisplayOrder(items, key, order) {
|
|
119
|
+
const at = new Map((order ?? []).map((k, i) => [k, i]));
|
|
120
|
+
return items
|
|
121
|
+
.map((t, i) => ({ t, i, r: at.has(key(t)) ? at.get(key(t)) : (order?.length ?? 0) }))
|
|
122
|
+
.sort((x, y) => x.r - y.r || x.i - y.i)
|
|
123
|
+
.map((x) => x.t);
|
|
124
|
+
}
|
|
125
|
+
/**
|
|
126
|
+
* The Display Order after a drag (spec §3.25). `all` is every key of the list in the current Display Order, hidden
|
|
127
|
+
* ones included; `shown` is what the screen showed, in its order, as units (one key, or a Same Login group that moves
|
|
128
|
+
* as one). The unit at `from` moves to `to`; the shown keys then fill the places shown keys held in `all`, so keys a
|
|
129
|
+
* filter hides keep their place among themselves.
|
|
130
|
+
*/
|
|
131
|
+
export function reorder(all, shown, from, to) {
|
|
132
|
+
const units = shown.slice();
|
|
133
|
+
if (from < 0 || from >= units.length || to < 0 || to >= units.length)
|
|
134
|
+
return all.slice();
|
|
135
|
+
const [unit] = units.splice(from, 1);
|
|
136
|
+
units.splice(to, 0, unit);
|
|
137
|
+
const next = units.flat();
|
|
138
|
+
const visible = new Set(next);
|
|
139
|
+
const out = all.slice();
|
|
140
|
+
for (const k of next)
|
|
141
|
+
if (!out.includes(k))
|
|
142
|
+
out.push(k);
|
|
143
|
+
let i = 0;
|
|
144
|
+
for (let at = 0; at < out.length; at++)
|
|
145
|
+
if (visible.has(out[at]))
|
|
146
|
+
out[at] = next[i++];
|
|
147
|
+
return out;
|
|
148
|
+
}
|
|
149
|
+
/**
|
|
150
|
+
* Sorted copy: `pressure` (fullest Quota first), `name`, `recent` (last activity first), or `manual` (the Family's
|
|
151
|
+
* Display Order `order`, names not in it after). The Main Account leads ties.
|
|
152
|
+
*/
|
|
153
|
+
export function sortAccounts(list, mode, now, order) {
|
|
110
154
|
const byName = (x, y) => Number(Boolean(y.isMain)) - Number(Boolean(x.isMain)) ||
|
|
111
155
|
x.name.localeCompare(y.name, undefined, { numeric: true });
|
|
112
156
|
const pressure = (a) => {
|
|
113
157
|
const q = a.quota;
|
|
114
158
|
if (q?.status !== 'ok' || !q.windows)
|
|
115
159
|
return -1;
|
|
116
|
-
|
|
117
|
-
|
|
160
|
+
const windows = q.windows.filter((w) => !w.name);
|
|
161
|
+
let max = windows.length ? 0 : -1;
|
|
162
|
+
for (const w of windows) {
|
|
118
163
|
const reset = Date.parse(w.resetsAt);
|
|
119
164
|
if (!(Number.isFinite(reset) && reset <= now))
|
|
120
165
|
max = Math.max(max, Number(w.usedPercent) || 0);
|
|
@@ -128,6 +173,8 @@ export function sortAccounts(list, mode, now) {
|
|
|
128
173
|
const out = list.slice();
|
|
129
174
|
if (mode === 'name')
|
|
130
175
|
out.sort(byName);
|
|
176
|
+
else if (mode === 'manual')
|
|
177
|
+
return inDisplayOrder(out.sort(byName), (a) => a.name, order);
|
|
131
178
|
else if (mode === 'recent')
|
|
132
179
|
out.sort((x, y) => last(y) - last(x) || byName(x, y));
|
|
133
180
|
else
|