sideby 0.14.0 → 0.16.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 -0
- package/dist/build.json +1 -1
- package/dist/src/cli/commands.d.ts +7 -0
- package/dist/src/cli/commands.js +259 -9
- package/dist/src/cli/json-schemas.js +109 -2
- package/dist/src/cli/main.js +30 -6
- package/dist/src/core/config.d.ts +1 -0
- package/dist/src/core/config.js +8 -2
- package/dist/src/core/local-build.d.ts +63 -0
- package/dist/src/core/local-build.js +189 -0
- package/dist/src/core/skill-check.d.ts +14 -0
- package/dist/src/core/skill-check.js +29 -3
- package/dist/src/core/update.d.ts +73 -1
- package/dist/src/core/update.js +155 -23
- package/dist/src/panel/handler.d.ts +12 -1
- package/dist/src/panel/handler.js +84 -5
- package/dist/src/panel/i18n.d.ts +125 -5
- package/dist/src/panel/i18n.js +280 -40
- package/dist/src/panel/page-logic.d.ts +41 -0
- package/dist/src/panel/page-logic.js +46 -0
- package/dist/src/panel/page-script.js +616 -162
- package/dist/src/panel/page-styles.js +74 -23
- package/dist/src/panel/page.js +3 -0
- package/dist/src/runtime.d.ts +2 -0
- package/package.json +3 -2
- package/schemas/alias.json +1 -1
- package/schemas/app-install.json +1 -1
- package/schemas/app-uninstall.json +1 -1
- package/schemas/browser-open.json +1 -1
- package/schemas/browser-switch.json +1 -1
- package/schemas/browser.json +1 -1
- package/schemas/config.json +15 -1
- package/schemas/desktop-remove.json +1 -1
- package/schemas/desktop.json +1 -1
- package/schemas/doctor.json +1 -1
- package/schemas/error.json +1 -1
- package/schemas/families.json +1 -1
- package/schemas/handoff-disable.json +1 -1
- package/schemas/handoff-enable.json +1 -1
- package/schemas/handoff-ready.json +1 -1
- package/schemas/handoff-setup.json +1 -1
- package/schemas/handoff-status.json +282 -1
- package/schemas/handoff-teardown.json +1 -1
- package/schemas/list.json +6 -1
- package/schemas/local.json +165 -0
- package/schemas/model.json +1 -1
- package/schemas/new.json +1 -1
- package/schemas/next.json +1 -1
- package/schemas/order.json +148 -0
- package/schemas/pin.json +126 -0
- package/schemas/plugins.json +1 -1
- package/schemas/quota-check.json +88 -0
- package/schemas/quota-setup.json +1 -1
- package/schemas/quota-teardown.json +1 -1
- package/schemas/quota.json +1 -1
- package/schemas/remote-control.json +1 -1
- package/schemas/tune-change.json +1 -1
- package/schemas/tune.json +1 -1
- package/schemas/unpin.json +126 -0
- package/schemas/update-auto.json +84 -0
- package/schemas/update.json +79 -1
- package/skills/sideby/SKILL.md +8 -3
- package/skills/sideby/references/handoff.md +8 -0
- package/skills/sideby/references/panel.md +28 -0
- package/skills/sideby/references/quota.md +6 -0
- package/skills/sideby/references/update.md +15 -2
|
@@ -108,6 +108,7 @@ code, .mono { font-family: var(--mono); font-size: 0.92em; }
|
|
|
108
108
|
.ic { width: 15px; height: 15px; flex: none; fill: none; stroke: currentColor; stroke-width: 2; stroke-linecap: round; stroke-linejoin: round; }
|
|
109
109
|
|
|
110
110
|
/* Summary: four quiet numbers in one surface. */
|
|
111
|
+
.summary[hidden], #checkup[hidden] { display: none; }
|
|
111
112
|
.summary { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); background: var(--surface); border: 1px solid var(--border); border-radius: var(--radius); box-shadow: var(--shadow); margin-bottom: 18px; overflow: hidden; }
|
|
112
113
|
.stat { display: flex; align-items: flex-end; justify-content: space-between; gap: 10px; min-width: 0; padding: 14px 18px; border-left: 1px solid var(--border); text-align: left; }
|
|
113
114
|
.stat:first-child { border-left: 0; }
|
|
@@ -170,36 +171,67 @@ code, .mono { font-family: var(--mono); font-size: 0.92em; }
|
|
|
170
171
|
/* List rows: identity, one column per quota window, last used, menu; a click opens the details (model, tokens,
|
|
171
172
|
Health) under them. Every column but the first has a fixed width, so the rows of all groups line up under the
|
|
172
173
|
same column titles. --qn is the number of quota columns; the page sets it on #accounts. */
|
|
173
|
-
#accounts { --qn: 2; --q-w: 176px; --l-w: 92px; --m-w:
|
|
174
|
+
#accounts { --qn: 2; --q-w: 176px; --l-w: 92px; --m-w: 92px; --col-gap: 28px; }
|
|
174
175
|
.row, .col-head { display: grid; grid-template-columns: minmax(0, 1fr) calc(var(--qn) * var(--q-w) + (var(--qn) - 1) * var(--col-gap)) var(--l-w) var(--m-w); column-gap: var(--col-gap); align-items: center; min-width: 0; }
|
|
175
176
|
.row { grid-template-areas: "id quota last more" "detail detail detail detail" "notes notes notes notes"; padding: 11px 10px 11px 16px; border-top: 1px solid var(--border); transition: background-color .12s; }
|
|
176
177
|
.rows .row:hover { background: color-mix(in srgb, var(--hover) 55%, transparent); }
|
|
177
178
|
.row:first-child { border-top: 0; }
|
|
178
179
|
.row:last-child { border-radius: 0 0 var(--radius) var(--radius); }
|
|
179
180
|
.row-error .ident-name .name { color: var(--fail); }
|
|
180
|
-
/* A login group (spec §3.21): ordinary rows that share one quota, tied together by a rail on the left. */
|
|
181
|
-
.login { position: relative; border-top: 1px solid var(--border); }
|
|
182
|
-
.login:first-child { border-top: 0; }
|
|
183
|
-
.login::before { content: ""; position: absolute; left: 5px; top: 12px; bottom: 12px; width: 3px; border-radius: 3px; background: var(--border-strong); }
|
|
184
|
-
.login-rows > .row:first-child { border-top: 0; }
|
|
185
|
-
.login-rows > .row + .row { border-top: 1px dashed var(--border); }
|
|
186
|
-
.login-rows > .row:last-child { border-radius: 0 0 var(--radius) var(--radius); }
|
|
187
|
-
.q-shared { gap: 6px; color: var(--faint); }
|
|
188
|
-
.q-shared .ic { width: 13px; height: 13px; }
|
|
189
|
-
/* Display Order (spec §3.25): a grip at the start of a group head or row, shown on hover or focus, always on touch
|
|
190
|
-
screens. A row's grip sits in its left padding, so the row's layout is the same with or without it. */
|
|
191
181
|
.row { position: relative; }
|
|
192
|
-
|
|
182
|
+
/* Old quota keeps its colour (the colour is how full it is) and says its age in words. */
|
|
183
|
+
.att-tag { font-weight: 500; }
|
|
184
|
+
.att-tag .dot { width: 6px; height: 6px; }
|
|
185
|
+
.more-opts { display: flex; flex-direction: column; gap: 12px; }
|
|
186
|
+
.more-opts > summary { cursor: pointer; color: var(--muted); font-size: 13px; }
|
|
187
|
+
.more-opts[open] > summary { margin-bottom: 4px; }
|
|
188
|
+
.tune-custom > summary { cursor: pointer; color: var(--muted); font-size: 13px; margin: 4px 0; }
|
|
189
|
+
.ai-asks { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 6px; }
|
|
190
|
+
.ai-ask { display: flex; align-items: center; gap: 8px; width: 100%; padding: 8px 10px; border: 1px solid var(--border); border-radius: var(--ctl-radius); background: var(--surface); color: var(--text); font: inherit; text-align: left; cursor: pointer; }
|
|
191
|
+
.ai-ask:hover { border-color: var(--btn-hover-border); color: var(--accent); }
|
|
192
|
+
.ai-ask .ic { width: 14px; height: 14px; color: var(--muted); flex: none; }
|
|
193
|
+
.arrange-text .link-btn { margin-left: 6px; }
|
|
194
|
+
.q-asof { grid-column: 1 / -1; display: inline-flex; align-items: center; gap: 4px; color: var(--muted); font-size: 11px; }
|
|
195
|
+
.q-asof .ic { width: 11px; height: 11px; }
|
|
196
|
+
.stat-act { align-self: flex-end; color: var(--accent); font-size: 12px; white-space: nowrap; }
|
|
197
|
+
.next-why { margin: 0 0 10px; max-width: 280px; line-height: 1.5; }
|
|
198
|
+
.next-cmd { display: block; margin-top: 8px; color: var(--muted); font-size: 11px; }
|
|
199
|
+
/* A Same Login (spec §3.21, ADR-0026): one row; opened, a short line per directory. */
|
|
200
|
+
.tag-login { font-weight: 400; }
|
|
201
|
+
.login-detail { flex-direction: column; gap: 8px; }
|
|
202
|
+
.login-detail .rd-note { margin: 0; }
|
|
203
|
+
/* The directories share one set of columns (subgrid), so a wider cell in one line moves every line alike. */
|
|
204
|
+
.login-dirs { display: grid; grid-template-columns: minmax(120px, 1fr) auto var(--l-w) minmax(0, 1.4fr) auto auto auto; column-gap: 14px; border: 1px solid var(--border); border-radius: var(--ctl-radius); background: var(--surface); }
|
|
205
|
+
.login-dir { grid-column: 1 / -1; display: grid; grid-template-columns: subgrid; align-items: center; padding: 6px 6px 6px 12px; }
|
|
206
|
+
.login-dir > * { justify-self: start; min-width: 0; }
|
|
207
|
+
.login-dir + .login-dir { border-top: 1px solid var(--border); }
|
|
208
|
+
.login-dir .ld-name { display: flex; align-items: center; gap: 6px; min-width: 0; }
|
|
209
|
+
.login-dir .ld-name .name { font-weight: var(--strong-weight); }
|
|
210
|
+
.login-dir .usage { justify-content: flex-start; }
|
|
211
|
+
.login-dir .btn .ic { width: 13px; height: 13px; }
|
|
212
|
+
/* The arrange mode (spec §3.25): a bar over the list, short rows, grips, up and down, pin. Drag only here. */
|
|
213
|
+
.arrange-bar { display: flex; align-items: center; justify-content: space-between; gap: 12px; flex-wrap: wrap; margin-bottom: 12px; padding: 8px 10px 8px 14px; border: 1px solid var(--primary-border); border-radius: var(--radius); background: var(--accent-soft); color: var(--text); }
|
|
214
|
+
.arrange-text { display: inline-flex; align-items: center; gap: 8px; }
|
|
215
|
+
.arrange-text .ic { width: 14px; height: 14px; color: var(--accent); }
|
|
216
|
+
.arrange-actions { display: inline-flex; align-items: center; gap: 12px; }
|
|
217
|
+
.row.row-arrange { display: flex; align-items: center; justify-content: space-between; gap: 12px; padding: 6px 10px 6px 8px; }
|
|
218
|
+
.row-arrange .ident { flex: 1; }
|
|
219
|
+
.row-arrange.is-pinned { background: color-mix(in srgb, var(--accent-soft) 60%, transparent); }
|
|
220
|
+
.arrange-tools { display: inline-flex; align-items: center; gap: 2px; }
|
|
221
|
+
.arrange-tools .icon-btn { width: 28px; height: 28px; }
|
|
222
|
+
.arrange-tools .icon-btn .ic { width: 14px; height: 14px; }
|
|
223
|
+
.pin-btn { color: var(--faint); }
|
|
224
|
+
.pin-btn[aria-pressed="true"] { color: var(--accent); }
|
|
225
|
+
.pin-btn[aria-pressed="true"] .ic { fill: currentColor; }
|
|
226
|
+
.drag-handle { width: 20px; height: 28px; color: var(--muted); cursor: grab; }
|
|
227
|
+
.drag-handle:hover { color: var(--accent); }
|
|
193
228
|
.drag-handle .ic { width: 14px; height: 14px; }
|
|
194
229
|
.drag-handle:active { cursor: grabbing; }
|
|
195
|
-
.row > .ident > .drag-handle { position: absolute; left: 0; top: 13px; }
|
|
196
230
|
.group-head > .drag-handle { margin-right: -8px; }
|
|
197
|
-
.group-head:hover > .drag-handle, .row:hover > .ident > .drag-handle, .drag-handle:focus-visible { opacity: 1; }
|
|
198
|
-
@media (hover: none) { .drag-handle { opacity: 1; } }
|
|
199
231
|
.is-dragging { opacity: .45; }
|
|
200
232
|
.drop-before { box-shadow: inset 0 2px 0 var(--accent); }
|
|
201
233
|
.drop-after { box-shadow: inset 0 -2px 0 var(--accent); }
|
|
202
|
-
.
|
|
234
|
+
.menu-head { padding: 6px 10px 2px; color: var(--faint); font-size: 11px; font-weight: var(--strong-weight); }
|
|
203
235
|
/* The arrow at a row's start opens and closes its details; so does a click anywhere else in the row. */
|
|
204
236
|
.row-toggle { width: 28px; height: 28px; margin: -4px -6px -4px -8px; }
|
|
205
237
|
.fold-hit { cursor: pointer; }
|
|
@@ -249,7 +281,20 @@ code, .mono { font-family: var(--mono); font-size: 0.92em; }
|
|
|
249
281
|
.plan { text-transform: capitalize; }
|
|
250
282
|
.row > .quota { grid-area: quota; }
|
|
251
283
|
.row > .last { grid-area: last; }
|
|
252
|
-
.row > .
|
|
284
|
+
.row > .row-end { grid-area: more; display: flex; align-items: center; justify-content: flex-end; gap: 4px; }
|
|
285
|
+
/* The row's pin (spec §3.25): filled and always there on a pinned row; on the others it shows on hover or focus. */
|
|
286
|
+
.row-run { width: 28px; height: 28px; color: var(--muted); }
|
|
287
|
+
.row-run .ic { width: 15px; height: 15px; }
|
|
288
|
+
.row-run:hover { color: var(--accent); }
|
|
289
|
+
.row-pin { width: 28px; height: 28px; color: var(--faint); opacity: 0; transition: opacity .12s, color .12s; }
|
|
290
|
+
.row-pin .ic { width: 15px; height: 15px; }
|
|
291
|
+
.row:hover .row-pin, .card:hover .row-pin, .row-pin:focus-visible, .row-pin.is-on { opacity: 1; }
|
|
292
|
+
.card-head > .row-end { display: flex; align-items: center; gap: 2px; margin-left: auto; }
|
|
293
|
+
.row-pin:hover { color: var(--accent); }
|
|
294
|
+
.row-pin.is-on { color: var(--accent); }
|
|
295
|
+
.row-pin.is-on .ic { fill: currentColor; }
|
|
296
|
+
.row-pin[aria-disabled="true"] { cursor: not-allowed; }
|
|
297
|
+
@media (hover: none) { .row-pin { opacity: .6; } }
|
|
253
298
|
.row-notes { grid-area: notes; display: flex; flex-direction: column; gap: 6px; margin-top: 8px; }
|
|
254
299
|
|
|
255
300
|
/* Quota meters: percent and countdown over a bar colored by level (ok, warn at 60%, fail at 85% used). */
|
|
@@ -262,18 +307,13 @@ code, .mono { font-family: var(--mono); font-size: 0.92em; }
|
|
|
262
307
|
.m-unit { color: var(--faint); font-weight: 400; font-size: 11.5px; }
|
|
263
308
|
.m-reset { margin-left: auto; color: var(--faint); font-size: 11.5px; font-variant-numeric: tabular-nums; overflow: hidden; text-overflow: ellipsis; }
|
|
264
309
|
.m-passed { color: var(--muted); }
|
|
265
|
-
.m-asof { display: inline-flex; margin-left: 4px; color: var(--faint); vertical-align: -1px; }
|
|
266
|
-
.m-asof .ic { width: 12px; height: 12px; }
|
|
267
310
|
.m-none { color: var(--faint); }
|
|
268
311
|
.bar { height: 6px; border-radius: 999px; background: var(--track); overflow: hidden; margin-top: 5px; }
|
|
269
312
|
.bar > span { display: block; height: 100%; min-width: 0; border-radius: inherit; background: var(--ok-bar); transition: width .4s ease; }
|
|
270
313
|
.lvl-warn .bar > span { background: var(--warn-bar); } .lvl-warn .m-pct { color: var(--warn); }
|
|
271
314
|
.lvl-fail .bar > span { background: var(--fail-bar); } .lvl-fail .m-pct { color: var(--fail); }
|
|
272
315
|
.lvl-reset .m-pct { color: var(--muted); }
|
|
273
|
-
.lvl-stale.lvl-ok .m-pct { color: var(--muted); }
|
|
274
316
|
/* Old numbers keep their level's color, paler, so the bar and the number agree. */
|
|
275
|
-
.lvl-stale .bar > span { opacity: .45; }
|
|
276
|
-
.lvl-stale.lvl-ok .bar > span { background: var(--faint); }
|
|
277
317
|
.q-note { grid-column: 1 / -1; display: flex; align-items: center; gap: 8px; flex-wrap: wrap; color: var(--muted); font-size: var(--small); }
|
|
278
318
|
.link-btn { padding: 0; border: 0; background: none; color: var(--accent); font: inherit; font-weight: var(--strong-weight); cursor: pointer; }
|
|
279
319
|
.link-btn:hover:not(:disabled) { text-decoration: underline; }
|
|
@@ -620,6 +660,7 @@ select:is(:hover, :focus) { --chevron: var(--text); }
|
|
|
620
660
|
.app-actions { width: 100%; justify-content: flex-start; }
|
|
621
661
|
.row { grid-template-columns: minmax(0, 1fr) auto var(--m-w); grid-template-areas: "id last more" "quota quota quota" "detail detail detail" "notes notes notes"; row-gap: 10px; }
|
|
622
662
|
.row-detail { margin-left: 0; }
|
|
663
|
+
|
|
623
664
|
.row > .quota { grid-template-columns: repeat(var(--qn), minmax(0, 1fr)); max-width: 560px; }
|
|
624
665
|
.rows .m-label, .rows .m-unit, .rows .u-unit { display: inline; }
|
|
625
666
|
.rows .usage { justify-content: flex-start; }
|
|
@@ -651,6 +692,16 @@ select:is(:hover, :focus) { --chevron: var(--text); }
|
|
|
651
692
|
.toolbar > .btn-primary { flex: 1; }
|
|
652
693
|
.row { padding: 10px 12px; }
|
|
653
694
|
#accounts { --col-gap: 14px; }
|
|
695
|
+
/* One window per line, so the reset time is never cut off. */
|
|
696
|
+
.row > .quota { grid-template-columns: 1fr; row-gap: 10px; max-width: none; }
|
|
697
|
+
/* On a phone the summary keeps what needs a look and the next reset. */
|
|
698
|
+
.stat:nth-child(1), .stat:nth-child(3) { display: none; }
|
|
699
|
+
.stat:nth-child(n) { border-top: 0; }
|
|
700
|
+
.stat:nth-child(4) { border-left: 1px solid var(--border); }
|
|
701
|
+
.row-end .icon-btn { width: 36px; height: 36px; }
|
|
702
|
+
.login-dirs { grid-template-columns: minmax(0, 1fr); }
|
|
703
|
+
.login-dir { grid-template-columns: minmax(0, 1fr) auto auto; column-gap: 14px; row-gap: 6px; }
|
|
704
|
+
.login-dir .usage, .login-dir .health { display: none; }
|
|
654
705
|
.grid { grid-template-columns: 1fr; }
|
|
655
706
|
.panel { padding: 14px; }
|
|
656
707
|
.dlg-head { padding: 14px 14px 2px; } .dlg-body { padding: 10px 14px 14px; } .dlg-foot { padding: 10px 14px; }
|
package/dist/src/panel/page.js
CHANGED
|
@@ -5,6 +5,7 @@ import { createHash } from 'node:crypto';
|
|
|
5
5
|
import { FAVICON_SVG, MARK_SVG } from '../core/brand-mark.js';
|
|
6
6
|
import { ALIAS_NAME, RESERVED_ALIASES } from '../core/config.js';
|
|
7
7
|
import { QUOTA_FAIL_PERCENT, QUOTA_WARN_PERCENT, USAGE_DAYS } from '../core/quota-levels.js';
|
|
8
|
+
import { SKILL_INSTALL } from '../core/skill-check.js';
|
|
8
9
|
import { MESSAGES } from './i18n.js';
|
|
9
10
|
import { PAGE_SCRIPT } from './page-script.js';
|
|
10
11
|
import { pageStyles } from './page-styles.js';
|
|
@@ -47,6 +48,8 @@ export function renderPage(opts) {
|
|
|
47
48
|
// The alias rules of the config, so the new-account dialog checks a short command as sideby will.
|
|
48
49
|
aliasPattern: ALIAS_NAME.source,
|
|
49
50
|
reservedAliases: [...RESERVED_ALIASES],
|
|
51
|
+
// The command that installs the sideby Agent Skill, which the Panel offers so an AI assistant can do the same.
|
|
52
|
+
skillInstall: SKILL_INSTALL,
|
|
50
53
|
});
|
|
51
54
|
return `<!doctype html>
|
|
52
55
|
<html lang="${lang === 'zh' ? 'zh-CN' : 'en'}">
|
package/dist/src/runtime.d.ts
CHANGED
|
@@ -112,6 +112,8 @@ export interface AccountStatus extends Account {
|
|
|
112
112
|
* The other Accounts signed in as the same login, which share its Quota (spec §3.21); absent when there are none.
|
|
113
113
|
*/
|
|
114
114
|
sameLogin?: string[];
|
|
115
|
+
/** Pinned to the top of its Family (spec §3.25); set by `sideby list` only, absent when not pinned. */
|
|
116
|
+
pinned?: true;
|
|
115
117
|
/** Plugin errors met while reading this Account (for example an unreadable settings file). */
|
|
116
118
|
problems?: string[];
|
|
117
119
|
/**
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "sideby",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.16.0",
|
|
4
4
|
"description": "Run work, personal and API-key accounts at the same time, without their configs drifting apart.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "Adonis0123 (https://github.com/Adonis0123)",
|
|
@@ -56,6 +56,7 @@
|
|
|
56
56
|
"scripts": {
|
|
57
57
|
"build": "rm -rf dist && tsc -p tsconfig.build.json && chmod +x dist/src/cli/main.js && node scripts/write-build-id.ts",
|
|
58
58
|
"local": "node scripts/local.ts",
|
|
59
|
+
"release": "node scripts/release.ts",
|
|
59
60
|
"typecheck": "tsc --noEmit",
|
|
60
61
|
"lint": "biome check .",
|
|
61
62
|
"format": "biome check --write .",
|
|
@@ -79,5 +80,5 @@
|
|
|
79
80
|
},
|
|
80
81
|
"packageManager": "pnpm@10.15.0",
|
|
81
82
|
"readmeFilename": "README.md",
|
|
82
|
-
"readme": "<p align=\"center\">\n <img alt=\"sideby: work, personal and API-key accounts, one terminal each, one shared config\" src=\"https://raw.githubusercontent.com/Adonis0123/sideby/main/docs/assets/banner.jpg\" width=\"880\">\n</p>\n\n<p align=\"center\">\n <b>Run work, personal and API-key accounts at the same time, without their configs drifting apart.</b><br>\n Each account is its own directory and its own terminal. Skills, hooks and settings stay linked to your main account. Claude Code, Codex, Grok Build and pi.\n</p>\n\n<p align=\"center\">\n <a href=\"https://www.npmjs.com/package/sideby\"><img alt=\"npm\" src=\"https://img.shields.io/npm/v/sideby\"></a>\n <a href=\"https://github.com/Adonis0123/sideby/actions/workflows/ci.yml\"><img alt=\"CI\" src=\"https://github.com/Adonis0123/sideby/actions/workflows/ci.yml/badge.svg\"></a>\n <img alt=\"Node 22.18+\" src=\"https://img.shields.io/badge/node-%E2%89%A522.18-339933\">\n <a href=\"LICENSE\"><img alt=\"MIT\" src=\"https://img.shields.io/badge/license-MIT-blue\"></a>\n</p>\n\n<p align=\"center\">English | <a href=\"README.zh-CN.md\">中文</a></p>\n\n## Quick start\n\nRequires Node 22.18+ and at least one Host CLI (Claude Code, Codex, Grok Build or pi) installed. AI agents: follow the setup steps in [`llms.txt`](llms.txt) (\"Set up sideby for a user\") instead.\n\n```sh\nnpm i -g sideby\nsideby new claude work # create ~/.claude-work, sharing ~/.claude's skills and hooks\nsideby login claude:work # sign in once\nsideby run work # Claude Code on the work account\nsideby quota setup claude --yes # Claude quota in the panel; undo: sideby quota teardown claude\nsideby ui # every account's quota at http://127.0.0.1:17420\n```\n\n`sideby update` installs a newer sideby when there is one; sideby says so after a command and in the panel. `sideby run claude:main` keeps using `~/.claude` in another terminal at the same time. Arguments after `--` go to the Host: `sideby run work -- --resume`. To try it without installing, run `npx sideby`.\n\n## Set up with your AI agent\n\nPaste this into Claude Code, Codex or any coding agent:\n\n```text\nInstall the sideby CLI (npm package `sideby`) and its agent skill, then set up a second Claude Code account for me.\nFollow \"Set up sideby for a user\" in https://raw.githubusercontent.com/Adonis0123/sideby/main/llms.txt\n```\n\nThe agent checks Node and your Host CLIs, installs sideby and the skill, creates the account, tells you what it shares with your main one and makes its short command work. You sign in once in your browser; the agent gives you that one command. Once the skill is installed, short requests work too: \"add another Claude account, cc008\", \"what do my Codex accounts share?\", \"which account still has quota?\".\n\n## What it looks like\n\nThe 25-second story: one account buried in tasks, then accounts side by side sharing one setup, and a task moving on when one runs out.\n\nhttps://github.com/user-attachments/assets/3a470c03-9009-4f1d-b7f6-8b4625d74958\n\n<img alt=\"Two terminals: the personal account and the work account running at the same time, both linked to the main account's skills and settings, then the local quota panel, and at 95% Auto Handoff moving work's session to the next account\" src=\"https://raw.githubusercontent.com/Adonis0123/sideby/main/docs/assets/demo.gif\" width=\"1280\">\n\n<picture>\n <source media=\"(prefers-color-scheme: dark)\" srcset=\"https://raw.githubusercontent.com/Adonis0123/sideby/main/docs/assets/panel-dark.png\">\n <source media=\"(prefers-color-scheme: light)\" srcset=\"https://raw.githubusercontent.com/Adonis0123/sideby/main/docs/assets/panel.png\">\n <img alt=\"sideby panel: every account's 5h and 7d quota, 7-day token usage and health in one page\" src=\"https://raw.githubusercontent.com/Adonis0123/sideby/main/docs/assets/panel.png\" width=\"1280\">\n</picture>\n\n## Why not just an alias?\n\n`CLAUDE_CONFIG_DIR` plus a shell alias already starts a second account. It does not keep skills and settings in one place, and it does not show quota for every account. [Does this break a provider's terms?](docs/guide/faq.md#terms)\n\n| | At the same time | Skills, hooks, settings | Quota and usage | Setup |\n|---|---|---|---|---|\n| `CLAUDE_CONFIG_DIR` and an alias | Yes. Each terminal exports the variable. | Each directory is its own copy. They drift unless you symlink by hand. | That session's status line | One alias per account |\n| [cc-switch](https://github.com/farion1231/cc-switch) | Enabling a provider writes the host's live config, so open sessions share that switch. | Plugin settings are copied across providers as a separate step. | The active provider, from its quota endpoint | Install the desktop app |\n| sideby | Yes. `sideby run` selects the directory for that process and leaves your shell alone. | Linked to the main account. `sideby doctor --fix` repairs copies. Sign-in and sessions stay separate. | Every account, from local files. Claude needs `quota setup`. | `npm i -g sideby`, then `sideby new` and sign in |\n\ncc-switch's docs describe that switch: it writes the live settings file ([README](https://github.com/farion1231/cc-switch#readme)). [#1105](https://github.com/farion1231/cc-switch/issues/1105) and [#2908](https://github.com/farion1231/cc-switch/issues/2908) ask for several sessions at once. [#1106](https://github.com/farion1231/cc-switch/issues/1106) is closed; the maintainer says Claude Code's \"open terminal\" can start one provider without changing the global config.\n\n## What else it does\n\n| You want to | Run | Guide |\n|---|---|---|\n| Add an API key account (DeepSeek, a gateway, …) | `sideby new claude deepseek --api` | [API accounts](docs/guide/usage.md#api-accounts) |\n| Find and fix config drift between accounts | `sideby doctor --fix` | [Doctor](docs/guide/usage.md#doctor) |\n| See Claude quota (Codex needs no setup) | `sideby quota setup claude --yes` | [Claude quota](docs/guide/usage.md#claude-quota) |\n| Find the cheapest auto-compact size from your own sessions, and use it in one click | `sideby tune` (or the panel's Context tuning tab) | [Context tuning](docs/guide/usage.md#context-tuning) |\n| See each account's model and effort, and set them per account | `sideby model <account>` (or click the model in the panel) | [Model and effort](docs/guide/usage.md#model-and-effort) |\n| Choose whether Claude sessions connect to claude.ai by themselves (Remote Control), for every account at once | `sideby remote-control off` or `on` (or the panel's Settings) | [Remote Control](docs/guide/usage.md#remote-control) |\n| Move on when an account hits its limit | `sideby next claude` | [Handoff](docs/guide/usage.md#when-an-account-hits-its-limit) |\n| Let a running task move to the next account by itself when quota runs low (off by default; see the risk) | `sideby handoff enable` (or the panel) | [Auto Handoff](docs/guide/usage.md#auto-handoff) |\n| Short commands such as `ccw` | `sideby alias add ccw claude:work` | [Shell functions](docs/guide/configuration.md#shell-functions) |\n| Reopen a session from Orca and the like in the account that holds it | `\"resumeRouting\": true` in config | [Resuming from other tools](docs/guide/configuration.md#resuming-from-other-tools) |\n| Open Claude Desktop or the Codex app as one account, several side by side (macOS) | `sideby desktop claude:work` (or the panel) | [Desktop apps](docs/guide/usage.md#desktop-apps) |\n| Keep several Grok Bot windows open, each signed in to its own account (macOS) | `sideby desktop grok-bot:002` (or the panel) | [Grok Bot windows](docs/guide/usage.md#grok-bot-windows) |\n| Open the panel from the Dock or app menu | `sideby app install` | [Panel app](docs/guide/panel.md#panel-app) |\n| Show the panel inside your own local page | `createPanelHandler()` | [Embed the panel](docs/guide/panel.md#embed-the-panel) |\n| Add a Host or a pre-launch check | a local plugin | [Plugins](docs/guide/plugins.md) |\n\n## Supported hosts\n\n| Host | Account directories | Sign-in | Quota | Usage (7 days) |\n|---|---|---|---|---|\n| Claude Code | `~/.claude`, `~/.claude-<name>` | `claude auth login` | ✓ after `quota setup claude` | ✓ |\n| Codex CLI | `~/.codex`, `~/.codex-<name>` | `codex login` | ✓ | ✓ |\n| Grok Build | `~/.grok`, `~/.grok-<name>` | `grok login` | weekly, asked from the `grok` CLI | no public source |\n| pi | `~/.pi/agent`, `~/.pi-<name>/agent` | `/login` inside pi | no public source | no public source |\n\nsideby starts the official binary on your `PATH` and never patches it. Tested versions and per-Host notes are in the [guide](docs/guide/usage.md#host-notes).\n\n## Platforms\n\nmacOS and Linux. CI runs the suite on `ubuntu-latest` and `macos-latest`, Node 22 and 24. **Windows is untested.** `sideby app` only installs a launcher on macOS and Linux. Linked items are symlinks, `sideby shell-init` prints bash and zsh functions, and the Claude quota wrapper runs `/bin/sh`.\n\n## Roadmap\n\n**Gemini CLI.** Gemini can point at another config directory with `GEMINI_CONFIG_DIR`. Older docs use `GEMINI_CLI_HOME`; current builds treat that name as deprecated, and exit on startup if it is set together with an exact directory override. A sideby family still needs a tested Gemini version, a login check that does not read tokens, and a list of which files to link or copy. That is more than a small patch, so it is not in this version.\n\n## Safe by design\n\n- It never edits a Host's global config to switch accounts. It moves a task to another account only when you turn on Auto Handoff, and never proxies requests or pools logins.\n- It never reads, prints or sends a credential value. Nothing about your accounts leaves your machine: the only request sideby makes on its own is a daily check of the npm registry for its newest version (off with `NO_UPDATE_NOTIFIER=1`; see [Updates](docs/guide/configuration.md#updates)).\n- `doctor --fix` never replaces a real file and never changes where a link points.\n\nDetails and the terms-of-service question are in the [FAQ](docs/guide/faq.md).\n\nUsage questions and ideas go in [Discussions](https://github.com/Adonis0123/sideby/discussions).\n\n## Docs\n\n- [Using sideby](docs/guide/usage.md): accounts, API accounts, Doctor, quota, Handoff, Host notes\n- [Commands](docs/guide/commands.md): every command, exit codes and `--json`\n- [Configuration](docs/guide/configuration.md): `config.json`, aliases, shell functions\n- [Panel](docs/guide/panel.md): the panel, panel app and embedding\n- [Plugins](docs/guide/plugins.md): write your own Family or launch hook\n- [FAQ](docs/guide/faq.md): terms of service, data locations, alternatives, uninstall\n- [Changelog](https://github.com/Adonis0123/sideby/releases)\n\n## For AI agents\n\n- [`llms.txt`](llms.txt): setup steps, commands, JSON contract and plugin API in one index. `sideby families --json` states what each Host's accounts share.\n- [`skills/sideby/SKILL.md`](skills/sideby/SKILL.md): one Agent Skill for seeing, repairing and creating accounts and for moving on when one hits its limit. Install with `npx skills add Adonis0123/sideby -g`; `sideby doctor` warns when the installed copy is for another sideby version.\n- [`AGENTS.md`](AGENTS.md): rules for agents working on this repository.\n\n## License\n\n[MIT](LICENSE)\n"
|
|
83
|
+
"readme": "<p align=\"center\">\n <img alt=\"sideby: work, personal and API-key accounts, one terminal each, one shared config\" src=\"https://raw.githubusercontent.com/Adonis0123/sideby/main/docs/assets/banner.jpg\" width=\"880\">\n</p>\n\n<p align=\"center\">\n <b>Run work, personal and API-key accounts at the same time, without their configs drifting apart.</b><br>\n Each account is its own directory and its own terminal. Skills, hooks and settings stay linked to your main account. Claude Code, Codex, Grok Build and pi.\n</p>\n\n<p align=\"center\">\n <a href=\"https://www.npmjs.com/package/sideby\"><img alt=\"npm\" src=\"https://img.shields.io/npm/v/sideby\"></a>\n <a href=\"https://github.com/Adonis0123/sideby/actions/workflows/ci.yml\"><img alt=\"CI\" src=\"https://github.com/Adonis0123/sideby/actions/workflows/ci.yml/badge.svg\"></a>\n <img alt=\"Node 22.18+\" src=\"https://img.shields.io/badge/node-%E2%89%A522.18-339933\">\n <a href=\"LICENSE\"><img alt=\"MIT\" src=\"https://img.shields.io/badge/license-MIT-blue\"></a>\n</p>\n\n<p align=\"center\">English | <a href=\"README.zh-CN.md\">中文</a></p>\n\n## Quick start\n\nRequires Node 22.18+ and at least one Host CLI (Claude Code, Codex, Grok Build or pi) installed. AI agents: follow the setup steps in [`llms.txt`](llms.txt) (\"Set up sideby for a user\") instead.\n\n```sh\nnpm i -g sideby\nsideby new claude work # create ~/.claude-work, sharing ~/.claude's skills and hooks\nsideby login claude:work # sign in once\nsideby run work # Claude Code on the work account\nsideby quota setup claude --yes # Claude quota in the panel; undo: sideby quota teardown claude\nsideby ui # every account's quota at http://127.0.0.1:17420\n```\n\n`sideby update` installs a newer sideby when there is one; sideby says so after a command and in the panel. `sideby run claude:main` keeps using `~/.claude` in another terminal at the same time. Arguments after `--` go to the Host: `sideby run work -- --resume`. To try it without installing, run `npx sideby`.\n\n## Set up with your AI agent\n\nPaste this into Claude Code, Codex or any coding agent:\n\n```text\nInstall the sideby CLI (npm package `sideby`) and its agent skill, then set up a second Claude Code account for me.\nFollow \"Set up sideby for a user\" in https://raw.githubusercontent.com/Adonis0123/sideby/main/llms.txt\n```\n\nThe agent checks Node and your Host CLIs, installs sideby and the skill, creates the account, tells you what it shares with your main one and makes its short command work. You sign in once in your browser; the agent gives you that one command. Once the skill is installed, short requests work too: \"add another Claude account, cc008\", \"what do my Codex accounts share?\", \"which account still has quota?\".\n\n## What it looks like\n\nThe 25-second story: one account buried in tasks, then accounts side by side sharing one setup, and a task moving on when one runs out.\n\nhttps://github.com/user-attachments/assets/3a470c03-9009-4f1d-b7f6-8b4625d74958\n\n<img alt=\"Two terminals: the personal account and the work account running at the same time, both linked to the main account's skills and settings, then the local quota panel, and at 95% Auto Handoff moving work's session to the next account\" src=\"https://raw.githubusercontent.com/Adonis0123/sideby/main/docs/assets/demo.gif\" width=\"1280\">\n\n<picture>\n <source media=\"(prefers-color-scheme: dark)\" srcset=\"https://raw.githubusercontent.com/Adonis0123/sideby/main/docs/assets/panel-dark.png\">\n <source media=\"(prefers-color-scheme: light)\" srcset=\"https://raw.githubusercontent.com/Adonis0123/sideby/main/docs/assets/panel.png\">\n <img alt=\"sideby panel: every account's 5h and 7d quota, 7-day token usage and health in one page\" src=\"https://raw.githubusercontent.com/Adonis0123/sideby/main/docs/assets/panel.png\" width=\"1280\">\n</picture>\n\n## Why not just an alias?\n\n`CLAUDE_CONFIG_DIR` plus a shell alias already starts a second account. It does not keep skills and settings in one place, and it does not show quota for every account. [Does this break a provider's terms?](docs/guide/faq.md#terms)\n\n| | At the same time | Skills, hooks, settings | Quota and usage | Setup |\n|---|---|---|---|---|\n| `CLAUDE_CONFIG_DIR` and an alias | Yes. Each terminal exports the variable. | Each directory is its own copy. They drift unless you symlink by hand. | That session's status line | One alias per account |\n| [cc-switch](https://github.com/farion1231/cc-switch) | Enabling a provider writes the host's live config, so open sessions share that switch. | Plugin settings are copied across providers as a separate step. | The active provider, from its quota endpoint | Install the desktop app |\n| sideby | Yes. `sideby run` selects the directory for that process and leaves your shell alone. | Linked to the main account. `sideby doctor --fix` repairs copies. Sign-in and sessions stay separate. | Every account, from local files. Claude needs `quota setup`. | `npm i -g sideby`, then `sideby new` and sign in |\n\ncc-switch's docs describe that switch: it writes the live settings file ([README](https://github.com/farion1231/cc-switch#readme)). [#1105](https://github.com/farion1231/cc-switch/issues/1105) and [#2908](https://github.com/farion1231/cc-switch/issues/2908) ask for several sessions at once. [#1106](https://github.com/farion1231/cc-switch/issues/1106) is closed; the maintainer says Claude Code's \"open terminal\" can start one provider without changing the global config.\n\n## What else it does\n\n| You want to | Run | Guide |\n|---|---|---|\n| Add an API key account (DeepSeek, a gateway, …) | `sideby new claude deepseek --api` | [API accounts](docs/guide/usage.md#api-accounts) |\n| Find and fix config drift between accounts | `sideby doctor --fix` | [Doctor](docs/guide/usage.md#doctor) |\n| See Claude quota (Codex needs no setup) | `sideby quota setup claude --yes` | [Claude quota](docs/guide/usage.md#claude-quota) |\n| Find the cheapest auto-compact size from your own sessions, and use it in one click | `sideby tune` (or the panel's Context tuning tab) | [Context tuning](docs/guide/usage.md#context-tuning) |\n| See each account's model and effort, and set them per account | `sideby model <account>` (or click the model in the panel) | [Model and effort](docs/guide/usage.md#model-and-effort) |\n| Choose whether Claude sessions connect to claude.ai by themselves (Remote Control), for every account at once | `sideby remote-control off` or `on` (or the panel's Settings) | [Remote Control](docs/guide/usage.md#remote-control) |\n| Pin the accounts you use most and put tools and accounts in your own order | `sideby pin claude:work`, `sideby order` (or the panel's Settings) | [Your own order](docs/guide/usage.md#your-own-order) |\n| Move on when an account hits its limit | `sideby next claude` | [Handoff](docs/guide/usage.md#when-an-account-hits-its-limit) |\n| Let a running task move to the next account by itself when quota runs low (off by default; see the risk) | `sideby handoff enable` (or the panel) | [Auto Handoff](docs/guide/usage.md#auto-handoff) |\n| Short commands such as `ccw` | `sideby alias add ccw claude:work` | [Shell functions](docs/guide/configuration.md#shell-functions) |\n| Reopen a session from Orca and the like in the account that holds it | `\"resumeRouting\": true` in config | [Resuming from other tools](docs/guide/configuration.md#resuming-from-other-tools) |\n| Open Claude Desktop or the Codex app as one account, several side by side (macOS) | `sideby desktop claude:work` (or the panel) | [Desktop apps](docs/guide/usage.md#desktop-apps) |\n| Keep several Grok Bot windows open, each signed in to its own account (macOS) | `sideby desktop grok-bot:002` (or the panel) | [Grok Bot windows](docs/guide/usage.md#grok-bot-windows) |\n| Open the panel from the Dock or app menu | `sideby app install` | [Panel app](docs/guide/panel.md#panel-app) |\n| Show the panel inside your own local page | `createPanelHandler()` | [Embed the panel](docs/guide/panel.md#embed-the-panel) |\n| Add a Host or a pre-launch check | a local plugin | [Plugins](docs/guide/plugins.md) |\n\n## Supported hosts\n\n| Host | Account directories | Sign-in | Quota | Usage (7 days) |\n|---|---|---|---|---|\n| Claude Code | `~/.claude`, `~/.claude-<name>` | `claude auth login` | ✓ after `quota setup claude` | ✓ |\n| Codex CLI | `~/.codex`, `~/.codex-<name>` | `codex login` | ✓ | ✓ |\n| Grok Build | `~/.grok`, `~/.grok-<name>` | `grok login` | weekly, asked from the `grok` CLI | no public source |\n| pi | `~/.pi/agent`, `~/.pi-<name>/agent` | `/login` inside pi | no public source | no public source |\n\nsideby starts the official binary on your `PATH` and never patches it. Tested versions and per-Host notes are in the [guide](docs/guide/usage.md#host-notes).\n\n## Platforms\n\nmacOS and Linux. CI runs the suite on `ubuntu-latest` and `macos-latest`, Node 22 and 24. **Windows is untested.** `sideby app` only installs a launcher on macOS and Linux. Linked items are symlinks, `sideby shell-init` prints bash and zsh functions, and the Claude quota wrapper runs `/bin/sh`.\n\n## Roadmap\n\n**Gemini CLI.** Gemini can point at another config directory with `GEMINI_CONFIG_DIR`. Older docs use `GEMINI_CLI_HOME`; current builds treat that name as deprecated, and exit on startup if it is set together with an exact directory override. A sideby family still needs a tested Gemini version, a login check that does not read tokens, and a list of which files to link or copy. That is more than a small patch, so it is not in this version.\n\n## Safe by design\n\n- It never edits a Host's global config to switch accounts. It moves a task to another account only when you turn on Auto Handoff, and never proxies requests or pools logins.\n- It never reads, prints or sends a credential value. Nothing about your accounts leaves your machine: the only request sideby makes on its own is a daily check of the npm registry for its newest version (off with `NO_UPDATE_NOTIFIER=1`; see [Updates](docs/guide/configuration.md#updates)).\n- `doctor --fix` never replaces a real file and never changes where a link points.\n\nDetails and the terms-of-service question are in the [FAQ](docs/guide/faq.md).\n\nUsage questions and ideas go in [Discussions](https://github.com/Adonis0123/sideby/discussions).\n\n## Docs\n\n- [Using sideby](docs/guide/usage.md): accounts, API accounts, Doctor, quota, Handoff, Host notes\n- [Commands](docs/guide/commands.md): every command, exit codes and `--json`\n- [Configuration](docs/guide/configuration.md): `config.json`, aliases, shell functions\n- [Panel](docs/guide/panel.md): the panel, panel app and embedding\n- [Plugins](docs/guide/plugins.md): write your own Family or launch hook\n- [FAQ](docs/guide/faq.md): terms of service, data locations, alternatives, uninstall\n- [Changelog](https://github.com/Adonis0123/sideby/releases)\n\n## For AI agents\n\n- [`llms.txt`](llms.txt): setup steps, commands, JSON contract and plugin API in one index. `sideby families --json` states what each Host's accounts share.\n- [`skills/sideby/SKILL.md`](skills/sideby/SKILL.md): one Agent Skill for seeing, repairing and creating accounts and for moving on when one hits its limit. Install with `npx skills add Adonis0123/sideby -g`; `sideby doctor` warns when the installed copy is for another sideby version.\n- [`AGENTS.md`](AGENTS.md): rules for agents working on this repository.\n\n## License\n\n[MIT](LICENSE)\n"
|
|
83
84
|
}
|
package/schemas/alias.json
CHANGED
|
@@ -149,7 +149,7 @@
|
|
|
149
149
|
},
|
|
150
150
|
"command": {
|
|
151
151
|
"type": "string",
|
|
152
|
-
"description": "
|
|
152
|
+
"description": "`sideby update`, which updates the skill with sideby: run it after the user agrees; it shows the plan and exits 10, then --yes."
|
|
153
153
|
},
|
|
154
154
|
"message": {
|
|
155
155
|
"type": "string"
|
package/schemas/app-install.json
CHANGED
|
@@ -121,7 +121,7 @@
|
|
|
121
121
|
},
|
|
122
122
|
"command": {
|
|
123
123
|
"type": "string",
|
|
124
|
-
"description": "
|
|
124
|
+
"description": "`sideby update`, which updates the skill with sideby: run it after the user agrees; it shows the plan and exits 10, then --yes."
|
|
125
125
|
},
|
|
126
126
|
"message": {
|
|
127
127
|
"type": "string"
|
|
@@ -101,7 +101,7 @@
|
|
|
101
101
|
},
|
|
102
102
|
"command": {
|
|
103
103
|
"type": "string",
|
|
104
|
-
"description": "
|
|
104
|
+
"description": "`sideby update`, which updates the skill with sideby: run it after the user agrees; it shows the plan and exits 10, then --yes."
|
|
105
105
|
},
|
|
106
106
|
"message": {
|
|
107
107
|
"type": "string"
|
|
@@ -94,7 +94,7 @@
|
|
|
94
94
|
},
|
|
95
95
|
"command": {
|
|
96
96
|
"type": "string",
|
|
97
|
-
"description": "
|
|
97
|
+
"description": "`sideby update`, which updates the skill with sideby: run it after the user agrees; it shows the plan and exits 10, then --yes."
|
|
98
98
|
},
|
|
99
99
|
"message": {
|
|
100
100
|
"type": "string"
|
|
@@ -89,7 +89,7 @@
|
|
|
89
89
|
},
|
|
90
90
|
"command": {
|
|
91
91
|
"type": "string",
|
|
92
|
-
"description": "
|
|
92
|
+
"description": "`sideby update`, which updates the skill with sideby: run it after the user agrees; it shows the plan and exits 10, then --yes."
|
|
93
93
|
},
|
|
94
94
|
"message": {
|
|
95
95
|
"type": "string"
|
package/schemas/browser.json
CHANGED
|
@@ -146,7 +146,7 @@
|
|
|
146
146
|
},
|
|
147
147
|
"command": {
|
|
148
148
|
"type": "string",
|
|
149
|
-
"description": "
|
|
149
|
+
"description": "`sideby update`, which updates the skill with sideby: run it after the user agrees; it shows the plan and exits 10, then --yes."
|
|
150
150
|
},
|
|
151
151
|
"message": {
|
|
152
152
|
"type": "string"
|
package/schemas/config.json
CHANGED
|
@@ -277,10 +277,24 @@
|
|
|
277
277
|
}
|
|
278
278
|
},
|
|
279
279
|
"description": "Per family, account names (not refs or short commands) in the order they are shown; accounts not listed follow, main first, then by name."
|
|
280
|
+
},
|
|
281
|
+
"pinned": {
|
|
282
|
+
"type": "object",
|
|
283
|
+
"patternProperties": {
|
|
284
|
+
"^.*$": {
|
|
285
|
+
"type": "array",
|
|
286
|
+
"items": {
|
|
287
|
+
"type": "string",
|
|
288
|
+
"minLength": 1
|
|
289
|
+
},
|
|
290
|
+
"uniqueItems": true
|
|
291
|
+
}
|
|
292
|
+
},
|
|
293
|
+
"description": "Per family, the names of the accounts pinned to the top of their group, in the order they are shown; they lead the group in every sort. Resetting the order keeps them."
|
|
280
294
|
}
|
|
281
295
|
},
|
|
282
296
|
"additionalProperties": false,
|
|
283
|
-
"description": "Display Order (spec §3.25): the order you
|
|
297
|
+
"description": "Display Order (spec §3.25): the order you gave families and accounts in the Panel, and the accounts you pinned. Display only: it never changes which account a Handoff picks."
|
|
284
298
|
},
|
|
285
299
|
"quota": {
|
|
286
300
|
"type": "object",
|
|
@@ -80,7 +80,7 @@
|
|
|
80
80
|
},
|
|
81
81
|
"command": {
|
|
82
82
|
"type": "string",
|
|
83
|
-
"description": "
|
|
83
|
+
"description": "`sideby update`, which updates the skill with sideby: run it after the user agrees; it shows the plan and exits 10, then --yes."
|
|
84
84
|
},
|
|
85
85
|
"message": {
|
|
86
86
|
"type": "string"
|
package/schemas/desktop.json
CHANGED
|
@@ -128,7 +128,7 @@
|
|
|
128
128
|
},
|
|
129
129
|
"command": {
|
|
130
130
|
"type": "string",
|
|
131
|
-
"description": "
|
|
131
|
+
"description": "`sideby update`, which updates the skill with sideby: run it after the user agrees; it shows the plan and exits 10, then --yes."
|
|
132
132
|
},
|
|
133
133
|
"message": {
|
|
134
134
|
"type": "string"
|
package/schemas/doctor.json
CHANGED
|
@@ -276,7 +276,7 @@
|
|
|
276
276
|
},
|
|
277
277
|
"command": {
|
|
278
278
|
"type": "string",
|
|
279
|
-
"description": "
|
|
279
|
+
"description": "`sideby update`, which updates the skill with sideby: run it after the user agrees; it shows the plan and exits 10, then --yes."
|
|
280
280
|
},
|
|
281
281
|
"message": {
|
|
282
282
|
"type": "string"
|
package/schemas/error.json
CHANGED
|
@@ -72,7 +72,7 @@
|
|
|
72
72
|
},
|
|
73
73
|
"command": {
|
|
74
74
|
"type": "string",
|
|
75
|
-
"description": "
|
|
75
|
+
"description": "`sideby update`, which updates the skill with sideby: run it after the user agrees; it shows the plan and exits 10, then --yes."
|
|
76
76
|
},
|
|
77
77
|
"message": {
|
|
78
78
|
"type": "string"
|
package/schemas/families.json
CHANGED
|
@@ -262,7 +262,7 @@
|
|
|
262
262
|
},
|
|
263
263
|
"command": {
|
|
264
264
|
"type": "string",
|
|
265
|
-
"description": "
|
|
265
|
+
"description": "`sideby update`, which updates the skill with sideby: run it after the user agrees; it shows the plan and exits 10, then --yes."
|
|
266
266
|
},
|
|
267
267
|
"message": {
|
|
268
268
|
"type": "string"
|
|
@@ -153,7 +153,7 @@
|
|
|
153
153
|
},
|
|
154
154
|
"command": {
|
|
155
155
|
"type": "string",
|
|
156
|
-
"description": "
|
|
156
|
+
"description": "`sideby update`, which updates the skill with sideby: run it after the user agrees; it shows the plan and exits 10, then --yes."
|
|
157
157
|
},
|
|
158
158
|
"message": {
|
|
159
159
|
"type": "string"
|
|
@@ -153,7 +153,7 @@
|
|
|
153
153
|
},
|
|
154
154
|
"command": {
|
|
155
155
|
"type": "string",
|
|
156
|
-
"description": "
|
|
156
|
+
"description": "`sideby update`, which updates the skill with sideby: run it after the user agrees; it shows the plan and exits 10, then --yes."
|
|
157
157
|
},
|
|
158
158
|
"message": {
|
|
159
159
|
"type": "string"
|
|
@@ -77,7 +77,7 @@
|
|
|
77
77
|
},
|
|
78
78
|
"command": {
|
|
79
79
|
"type": "string",
|
|
80
|
-
"description": "
|
|
80
|
+
"description": "`sideby update`, which updates the skill with sideby: run it after the user agrees; it shows the plan and exits 10, then --yes."
|
|
81
81
|
},
|
|
82
82
|
"message": {
|
|
83
83
|
"type": "string"
|
|
@@ -107,7 +107,7 @@
|
|
|
107
107
|
},
|
|
108
108
|
"command": {
|
|
109
109
|
"type": "string",
|
|
110
|
-
"description": "
|
|
110
|
+
"description": "`sideby update`, which updates the skill with sideby: run it after the user agrees; it shows the plan and exits 10, then --yes."
|
|
111
111
|
},
|
|
112
112
|
"message": {
|
|
113
113
|
"type": "string"
|