sideby 0.0.0-stage → 0.1.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.
Files changed (145) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +453 -2
  3. package/README.zh-CN.md +455 -0
  4. package/dist/build.json +1 -0
  5. package/dist/src/cli/args.d.ts +13 -0
  6. package/dist/src/cli/args.js +38 -0
  7. package/dist/src/cli/commands.d.ts +37 -0
  8. package/dist/src/cli/commands.js +487 -0
  9. package/dist/src/cli/format.d.ts +16 -0
  10. package/dist/src/cli/format.js +80 -0
  11. package/dist/src/cli/json-schemas.d.ts +2 -0
  12. package/dist/src/cli/json-schemas.js +224 -0
  13. package/dist/src/cli/main.d.ts +2 -0
  14. package/dist/src/cli/main.js +186 -0
  15. package/dist/src/cli/schemas.d.ts +1 -0
  16. package/dist/src/cli/schemas.js +16 -0
  17. package/dist/src/core/account-name.d.ts +2 -0
  18. package/dist/src/core/account-name.js +2 -0
  19. package/dist/src/core/accounts.d.ts +18 -0
  20. package/dist/src/core/accounts.js +116 -0
  21. package/dist/src/core/config.d.ts +60 -0
  22. package/dist/src/core/config.js +181 -0
  23. package/dist/src/core/create.d.ts +30 -0
  24. package/dist/src/core/create.js +126 -0
  25. package/dist/src/core/doctor.d.ts +41 -0
  26. package/dist/src/core/doctor.js +171 -0
  27. package/dist/src/core/errors.d.ts +12 -0
  28. package/dist/src/core/errors.js +14 -0
  29. package/dist/src/core/file-memo.d.ts +24 -0
  30. package/dist/src/core/file-memo.js +41 -0
  31. package/dist/src/core/fs-safe.d.ts +38 -0
  32. package/dist/src/core/fs-safe.js +205 -0
  33. package/dist/src/core/handoff.d.ts +41 -0
  34. package/dist/src/core/handoff.js +54 -0
  35. package/dist/src/core/identity.d.ts +23 -0
  36. package/dist/src/core/identity.js +79 -0
  37. package/dist/src/core/last-doctor.d.ts +36 -0
  38. package/dist/src/core/last-doctor.js +69 -0
  39. package/dist/src/core/launch.d.ts +35 -0
  40. package/dist/src/core/launch.js +108 -0
  41. package/dist/src/core/login-path.d.ts +23 -0
  42. package/dist/src/core/login-path.js +96 -0
  43. package/dist/src/core/paths.d.ts +13 -0
  44. package/dist/src/core/paths.js +32 -0
  45. package/dist/src/core/quota-levels.d.ts +19 -0
  46. package/dist/src/core/quota-levels.js +34 -0
  47. package/dist/src/core/secret-file.d.ts +30 -0
  48. package/dist/src/core/secret-file.js +116 -0
  49. package/dist/src/core/share-mode-names.d.ts +1 -0
  50. package/dist/src/core/share-mode-names.js +10 -0
  51. package/dist/src/core/share-modes.d.ts +24 -0
  52. package/dist/src/core/share-modes.js +405 -0
  53. package/dist/src/core/shell-init.d.ts +25 -0
  54. package/dist/src/core/shell-init.js +61 -0
  55. package/dist/src/core/skill-check.d.ts +11 -0
  56. package/dist/src/core/skill-check.js +57 -0
  57. package/dist/src/core/usage-days.d.ts +15 -0
  58. package/dist/src/core/usage-days.js +33 -0
  59. package/dist/src/core/version.d.ts +9 -0
  60. package/dist/src/core/version.js +46 -0
  61. package/dist/src/desktop/app.d.ts +60 -0
  62. package/dist/src/desktop/app.js +316 -0
  63. package/dist/src/desktop/icon.d.ts +16 -0
  64. package/dist/src/desktop/icon.js +174 -0
  65. package/dist/src/families/claude/index.d.ts +10 -0
  66. package/dist/src/families/claude/index.js +124 -0
  67. package/dist/src/families/claude/layout.d.ts +6 -0
  68. package/dist/src/families/claude/layout.js +5 -0
  69. package/dist/src/families/claude/quota-cache.d.ts +31 -0
  70. package/dist/src/families/claude/quota-cache.js +111 -0
  71. package/dist/src/families/claude/quota.d.ts +3 -0
  72. package/dist/src/families/claude/quota.js +53 -0
  73. package/dist/src/families/claude/usage.d.ts +22 -0
  74. package/dist/src/families/claude/usage.js +146 -0
  75. package/dist/src/families/codex/index.d.ts +5 -0
  76. package/dist/src/families/codex/index.js +67 -0
  77. package/dist/src/families/codex/rollout.d.ts +67 -0
  78. package/dist/src/families/codex/rollout.js +298 -0
  79. package/dist/src/families/grok/index.d.ts +8 -0
  80. package/dist/src/families/grok/index.js +78 -0
  81. package/dist/src/families/index.d.ts +3 -0
  82. package/dist/src/families/index.js +40 -0
  83. package/dist/src/families/logos.d.ts +21 -0
  84. package/dist/src/families/logos.js +26 -0
  85. package/dist/src/families/pi/index.d.ts +3 -0
  86. package/dist/src/families/pi/index.js +54 -0
  87. package/dist/src/families/shared/toml.d.ts +5 -0
  88. package/dist/src/families/shared/toml.js +16 -0
  89. package/dist/src/index.d.ts +5 -0
  90. package/dist/src/index.js +4 -0
  91. package/dist/src/panel/background.d.ts +62 -0
  92. package/dist/src/panel/background.js +274 -0
  93. package/dist/src/panel/handler.d.ts +93 -0
  94. package/dist/src/panel/handler.js +411 -0
  95. package/dist/src/panel/i18n.d.ts +287 -0
  96. package/dist/src/panel/i18n.js +570 -0
  97. package/dist/src/panel/page-logic.d.ts +154 -0
  98. package/dist/src/panel/page-logic.js +326 -0
  99. package/dist/src/panel/page-script.d.ts +2 -0
  100. package/dist/src/panel/page-script.js +1633 -0
  101. package/dist/src/panel/page-styles.d.ts +7 -0
  102. package/dist/src/panel/page-styles.js +514 -0
  103. package/dist/src/panel/page.d.ts +20 -0
  104. package/dist/src/panel/page.js +96 -0
  105. package/dist/src/panel/server.d.ts +32 -0
  106. package/dist/src/panel/server.js +133 -0
  107. package/dist/src/panel/theme.d.ts +116 -0
  108. package/dist/src/panel/theme.js +132 -0
  109. package/dist/src/plugins/account-script.d.ts +4 -0
  110. package/dist/src/plugins/account-script.js +66 -0
  111. package/dist/src/plugins/bus.d.ts +33 -0
  112. package/dist/src/plugins/bus.js +84 -0
  113. package/dist/src/plugins/loader.d.ts +58 -0
  114. package/dist/src/plugins/loader.js +250 -0
  115. package/dist/src/quota/claude-statusline.d.ts +28 -0
  116. package/dist/src/quota/claude-statusline.js +301 -0
  117. package/dist/src/quota/statusline-tap.d.ts +11 -0
  118. package/dist/src/quota/statusline-tap.js +104 -0
  119. package/dist/src/runtime.d.ts +149 -0
  120. package/dist/src/runtime.js +371 -0
  121. package/dist/src/types.d.ts +278 -0
  122. package/dist/src/types.js +3 -0
  123. package/dist/testing/demo.d.ts +8 -0
  124. package/dist/testing/demo.js +50 -0
  125. package/dist/testing/index.d.ts +36 -0
  126. package/dist/testing/index.js +117 -0
  127. package/package.json +66 -4
  128. package/schemas/alias.json +102 -0
  129. package/schemas/app-install.json +74 -0
  130. package/schemas/app-uninstall.json +54 -0
  131. package/schemas/config.json +166 -0
  132. package/schemas/doctor.json +229 -0
  133. package/schemas/error.json +25 -0
  134. package/schemas/list.json +177 -0
  135. package/schemas/new.json +181 -0
  136. package/schemas/next.json +127 -0
  137. package/schemas/plugins.json +74 -0
  138. package/schemas/quota-setup.json +60 -0
  139. package/schemas/quota-teardown.json +30 -0
  140. package/schemas/quota.json +203 -0
  141. package/skills/sideby/SKILL.md +52 -0
  142. package/skills/sideby/references/accounts.md +31 -0
  143. package/skills/sideby/references/diagnose.md +47 -0
  144. package/skills/sideby/references/handoff.md +41 -0
  145. package/skills/sideby/references/quota.md +14 -0
@@ -0,0 +1,127 @@
1
+ {
2
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
3
+ "$id": "sideby/next.json",
4
+ "type": "object",
5
+ "required": [
6
+ "schemaVersion",
7
+ "family",
8
+ "pick",
9
+ "accounts",
10
+ "hasQuota"
11
+ ],
12
+ "properties": {
13
+ "schemaVersion": {
14
+ "type": "number",
15
+ "const": 1
16
+ },
17
+ "family": {
18
+ "type": "string"
19
+ },
20
+ "pick": {
21
+ "anyOf": [
22
+ {
23
+ "type": "string"
24
+ },
25
+ {
26
+ "type": "null"
27
+ }
28
+ ],
29
+ "description": "The recommended account; null when none can be used now (exit code 1)."
30
+ },
31
+ "accounts": {
32
+ "type": "array",
33
+ "items": {
34
+ "type": "object",
35
+ "required": [
36
+ "ref",
37
+ "kind",
38
+ "state",
39
+ "pressure"
40
+ ],
41
+ "properties": {
42
+ "ref": {
43
+ "type": "string"
44
+ },
45
+ "kind": {
46
+ "anyOf": [
47
+ {
48
+ "type": "string",
49
+ "const": "subscription"
50
+ },
51
+ {
52
+ "type": "string",
53
+ "const": "api"
54
+ }
55
+ ]
56
+ },
57
+ "state": {
58
+ "anyOf": [
59
+ {
60
+ "type": "string",
61
+ "const": "ready"
62
+ },
63
+ {
64
+ "type": "string",
65
+ "const": "unknown"
66
+ },
67
+ {
68
+ "type": "string",
69
+ "const": "api"
70
+ },
71
+ {
72
+ "type": "string",
73
+ "const": "full"
74
+ },
75
+ {
76
+ "type": "string",
77
+ "const": "logged-out"
78
+ }
79
+ ],
80
+ "description": "ready and unknown can be picked; api only with --include-api; full and logged-out never."
81
+ },
82
+ "pressure": {
83
+ "anyOf": [
84
+ {
85
+ "type": "number"
86
+ },
87
+ {
88
+ "type": "null"
89
+ }
90
+ ],
91
+ "description": "Used percent of the fullest window not reset yet; null without quota."
92
+ },
93
+ "resetsAt": {
94
+ "type": "string",
95
+ "description": "For full: when its last full window resets."
96
+ },
97
+ "observedAt": {
98
+ "type": "string",
99
+ "description": "When the account's quota was recorded (its last session)."
100
+ }
101
+ }
102
+ },
103
+ "description": "Every account of the family, best first."
104
+ },
105
+ "hasQuota": {
106
+ "type": "boolean",
107
+ "description": "False when no account has quota data: the pick is then a guess, and `sideby next` does not start it (exit 1)."
108
+ },
109
+ "earliestReset": {
110
+ "type": "object",
111
+ "required": [
112
+ "ref",
113
+ "at"
114
+ ],
115
+ "properties": {
116
+ "ref": {
117
+ "type": "string"
118
+ },
119
+ "at": {
120
+ "type": "string"
121
+ }
122
+ },
123
+ "description": "Set when nothing can be picked and some accounts are full: the first to come back."
124
+ }
125
+ },
126
+ "title": "sideby next --json"
127
+ }
@@ -0,0 +1,74 @@
1
+ {
2
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
3
+ "$id": "sideby/plugins.json",
4
+ "type": "object",
5
+ "required": [
6
+ "schemaVersion",
7
+ "plugins",
8
+ "errors"
9
+ ],
10
+ "properties": {
11
+ "schemaVersion": {
12
+ "type": "number",
13
+ "const": 1
14
+ },
15
+ "plugins": {
16
+ "type": "array",
17
+ "items": {
18
+ "type": "object",
19
+ "required": [
20
+ "name",
21
+ "version",
22
+ "source",
23
+ "families",
24
+ "configKeys"
25
+ ],
26
+ "properties": {
27
+ "name": {
28
+ "type": "string"
29
+ },
30
+ "version": {
31
+ "type": "string"
32
+ },
33
+ "source": {
34
+ "type": "string"
35
+ },
36
+ "description": {
37
+ "type": "string"
38
+ },
39
+ "families": {
40
+ "type": "array",
41
+ "items": {
42
+ "type": "string"
43
+ }
44
+ },
45
+ "configKeys": {
46
+ "type": "array",
47
+ "items": {
48
+ "type": "string"
49
+ }
50
+ }
51
+ }
52
+ }
53
+ },
54
+ "errors": {
55
+ "type": "array",
56
+ "items": {
57
+ "type": "object",
58
+ "required": [
59
+ "where",
60
+ "message"
61
+ ],
62
+ "properties": {
63
+ "where": {
64
+ "type": "string"
65
+ },
66
+ "message": {
67
+ "type": "string"
68
+ }
69
+ }
70
+ }
71
+ }
72
+ },
73
+ "title": "sideby plugins --json"
74
+ }
@@ -0,0 +1,60 @@
1
+ {
2
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
3
+ "$id": "sideby/quota-setup.json",
4
+ "type": "object",
5
+ "required": [
6
+ "schemaVersion",
7
+ "family",
8
+ "applied",
9
+ "plan"
10
+ ],
11
+ "properties": {
12
+ "schemaVersion": {
13
+ "type": "number",
14
+ "const": 1
15
+ },
16
+ "family": {
17
+ "type": "string"
18
+ },
19
+ "applied": {
20
+ "type": "boolean"
21
+ },
22
+ "plan": {
23
+ "type": "object",
24
+ "required": [
25
+ "status",
26
+ "file",
27
+ "diff",
28
+ "message"
29
+ ],
30
+ "properties": {
31
+ "status": {
32
+ "anyOf": [
33
+ {
34
+ "type": "string",
35
+ "const": "enabled"
36
+ },
37
+ {
38
+ "type": "string",
39
+ "const": "ready"
40
+ },
41
+ {
42
+ "type": "string",
43
+ "const": "blocked"
44
+ }
45
+ ]
46
+ },
47
+ "file": {
48
+ "type": "string"
49
+ },
50
+ "diff": {
51
+ "type": "string"
52
+ },
53
+ "message": {
54
+ "type": "string"
55
+ }
56
+ }
57
+ }
58
+ },
59
+ "title": "sideby quota setup --json"
60
+ }
@@ -0,0 +1,30 @@
1
+ {
2
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
3
+ "$id": "sideby/quota-teardown.json",
4
+ "type": "object",
5
+ "required": [
6
+ "schemaVersion",
7
+ "family",
8
+ "ok",
9
+ "message"
10
+ ],
11
+ "properties": {
12
+ "schemaVersion": {
13
+ "type": "number",
14
+ "const": 1
15
+ },
16
+ "family": {
17
+ "type": "string"
18
+ },
19
+ "ok": {
20
+ "type": "boolean"
21
+ },
22
+ "message": {
23
+ "type": "string"
24
+ },
25
+ "diff": {
26
+ "type": "string"
27
+ }
28
+ },
29
+ "title": "sideby quota teardown --json"
30
+ }
@@ -0,0 +1,203 @@
1
+ {
2
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
3
+ "$id": "sideby/quota.json",
4
+ "type": "object",
5
+ "required": [
6
+ "schemaVersion",
7
+ "accounts"
8
+ ],
9
+ "properties": {
10
+ "schemaVersion": {
11
+ "type": "number",
12
+ "const": 1
13
+ },
14
+ "accounts": {
15
+ "type": "array",
16
+ "items": {
17
+ "type": "object",
18
+ "required": [
19
+ "ref",
20
+ "kind",
21
+ "quota",
22
+ "usage"
23
+ ],
24
+ "properties": {
25
+ "ref": {
26
+ "type": "string"
27
+ },
28
+ "kind": {
29
+ "anyOf": [
30
+ {
31
+ "type": "string",
32
+ "const": "subscription"
33
+ },
34
+ {
35
+ "type": "string",
36
+ "const": "api"
37
+ }
38
+ ]
39
+ },
40
+ "quota": {
41
+ "anyOf": [
42
+ {
43
+ "type": "object",
44
+ "required": [
45
+ "status",
46
+ "windows",
47
+ "observedAt",
48
+ "source"
49
+ ],
50
+ "properties": {
51
+ "status": {
52
+ "type": "string",
53
+ "const": "ok"
54
+ },
55
+ "windows": {
56
+ "type": "array",
57
+ "items": {
58
+ "type": "object",
59
+ "required": [
60
+ "label",
61
+ "windowMinutes",
62
+ "usedPercent",
63
+ "resetsAt"
64
+ ],
65
+ "properties": {
66
+ "label": {
67
+ "type": "string"
68
+ },
69
+ "windowMinutes": {
70
+ "type": "number"
71
+ },
72
+ "usedPercent": {
73
+ "type": "number"
74
+ },
75
+ "resetsAt": {
76
+ "type": "string"
77
+ }
78
+ }
79
+ }
80
+ },
81
+ "observedAt": {
82
+ "type": "string"
83
+ },
84
+ "source": {
85
+ "type": "string"
86
+ },
87
+ "plan": {
88
+ "type": "string"
89
+ }
90
+ }
91
+ },
92
+ {
93
+ "type": "object",
94
+ "required": [
95
+ "status",
96
+ "reason"
97
+ ],
98
+ "properties": {
99
+ "status": {
100
+ "type": "string",
101
+ "const": "unavailable"
102
+ },
103
+ "reason": {
104
+ "type": "string"
105
+ },
106
+ "detail": {
107
+ "type": "string"
108
+ }
109
+ }
110
+ }
111
+ ]
112
+ },
113
+ "usage": {
114
+ "anyOf": [
115
+ {
116
+ "type": "object",
117
+ "required": [
118
+ "status",
119
+ "days",
120
+ "sessions",
121
+ "inputTokens",
122
+ "outputTokens",
123
+ "cacheReadTokens",
124
+ "cacheWriteTokens",
125
+ "totalTokens"
126
+ ],
127
+ "properties": {
128
+ "status": {
129
+ "type": "string",
130
+ "const": "ok"
131
+ },
132
+ "days": {
133
+ "type": "number"
134
+ },
135
+ "sessions": {
136
+ "type": "number"
137
+ },
138
+ "inputTokens": {
139
+ "type": "number"
140
+ },
141
+ "outputTokens": {
142
+ "type": "number"
143
+ },
144
+ "cacheReadTokens": {
145
+ "type": "number"
146
+ },
147
+ "cacheWriteTokens": {
148
+ "type": "number"
149
+ },
150
+ "totalTokens": {
151
+ "type": "number"
152
+ },
153
+ "daily": {
154
+ "type": "array",
155
+ "items": {
156
+ "type": "object",
157
+ "required": [
158
+ "date",
159
+ "totalTokens"
160
+ ],
161
+ "properties": {
162
+ "date": {
163
+ "type": "string"
164
+ },
165
+ "totalTokens": {
166
+ "type": "number"
167
+ }
168
+ }
169
+ },
170
+ "description": "Tokens per local day (YYYY-MM-DD), oldest first, days without records as 0."
171
+ },
172
+ "lastActivityAt": {
173
+ "type": "string"
174
+ }
175
+ }
176
+ },
177
+ {
178
+ "type": "object",
179
+ "required": [
180
+ "status",
181
+ "reason"
182
+ ],
183
+ "properties": {
184
+ "status": {
185
+ "type": "string",
186
+ "const": "unavailable"
187
+ },
188
+ "reason": {
189
+ "type": "string"
190
+ },
191
+ "detail": {
192
+ "type": "string"
193
+ }
194
+ }
195
+ }
196
+ ]
197
+ }
198
+ }
199
+ }
200
+ }
201
+ },
202
+ "title": "sideby quota --json"
203
+ }
@@ -0,0 +1,52 @@
1
+ ---
2
+ name: sideby
3
+ description: Use when the user runs several AI coding accounts (Claude Code, Codex, Grok Build, pi) and wants to see them, check how much quota or usage each has left, move on to another account because one hit its 5-hour or weekly limit, create an account or API account, add a short command (alias) for one, or repair a broken or drifted account directory (skills, hooks, rules or settings not shared, wrong symlinks, credential file permissions). Drives the `sideby` CLI with `--json` and leaves sign-in, credentials and starting sessions to the user.
4
+ metadata:
5
+ version: "0.1.0"
6
+ ---
7
+
8
+ # sideby
9
+
10
+ `sideby` runs each AI coding account from its own directory (`~/.claude-work`, `~/.codex-api`, ...) and keeps skills, hooks and rules shared with the Main Account (`~/.claude`, `~/.codex`, `~/.grok`, `~/.pi/agent`). Use `npx sideby` if the command is not installed. Requires Node 22.18+.
11
+
12
+ ## Hard rules
13
+
14
+ - **Never read credential files**: `proxy.env`, `auth.json`, `.claude.json`, or anything under an account directory that may hold a token. Do not `cat`, `grep`, `head`, open or summarize them. `sideby list --json` gives the signed-in email as `identity.email`; that is all you need.
15
+ - **Never sign in for the user.** Tell them to run `sideby login <ref>` in their own terminal. OAuth needs their browser and their decision.
16
+ - **Never put a secret on the command line or in chat.** For API accounts, the user edits `proxy.env` themselves.
17
+ - **Never start a Host session from your shell.** `sideby run`, `sideby next` (without `--dry-run`) and `sideby login` open an interactive session; give the user the command instead.
18
+ - **Never switch, rotate or proxy accounts.** sideby does not do it, and you must not work around that by editing config, copying session files or moving credentials. Choosing the next account is the user's call; `sideby next` only recommends.
19
+ - **Show before you change.** Read-only commands first; changes only after the user has seen what will change.
20
+ - Do not edit Host config files (`settings.json`, `config.toml`, symlinks in account directories) by hand when a `sideby` command does the job.
21
+
22
+ ## Output and exit codes
23
+
24
+ - Every `--json` output has `schemaVersion: 1`. On an error it is `{ "schemaVersion": 1, "error": "<what to do next>", "code": "<reason>" }`; `code` is `usage` for a malformed command line.
25
+ - Exit codes: `0` done, `1` failed or found a `fail` problem, `2` malformed command line, `10` **needs the user's confirmation**. `run`, `next` and `login` return the Host's own exit code once it starts.
26
+ - On `10`: show the user the change the command printed, ask, and only after a clear yes run the same command again with `--yes` added. Never add `--yes` on your own.
27
+
28
+ ## What do you want to do
29
+
30
+ Account refs are `<family>:<name>`; a bare `<name>` works only when it is unique. Families: `claude`, `codex`, `grok`, `pi`.
31
+
32
+ | The user wants to | Run | Then read |
33
+ |---|---|---|
34
+ | See accounts, health, quota and usage | `sideby list --json`, `sideby doctor --json`, `sideby quota --json` | `references/diagnose.md` |
35
+ | Repair drift or permissions | `sideby doctor [ref] --json`, then `--fix` after they agree | `references/diagnose.md` |
36
+ | Keep working because an account hit its limit | `sideby next <family> --json` | `references/handoff.md` |
37
+ | Create an account, an API account or a short command | `sideby new`, `sideby alias add` | `references/accounts.md` |
38
+ | See Claude quota (it shows `not-enabled`) | `sideby quota setup claude` (exits 10) | `references/quota.md` |
39
+ | See everything at once | `sideby ui` (local panel on `127.0.0.1:17420`; `--no-open` prints the address) | — |
40
+ | Start an account | give them `sideby run <ref> [-- host args]` | — |
41
+
42
+ Read only the reference the task needs.
43
+
44
+ ## Launching and the panel
45
+
46
+ `eval "$(sideby shell-init zsh)"` defines one function per account (`sideby-claude-work`) plus the config `aliases`. Users who source a file instead set config `shellInitFile` (for example `{ "zsh": "~/.config/sideby/shell-init.zsh" }`); `new` and `alias add|rm` keep it current, and `sideby shell-init zsh --write` rewrites it. New functions work in a new shell.
47
+
48
+ For someone who would rather double-click than use a terminal, `sideby app install` adds a desktop app (macOS `~/Applications/sideby.app`, Linux app menu) that runs `sideby ui --background`; `sideby ui --stop` stops it and `sideby app uninstall` removes the app. Ask before `app install`: it writes outside sideby's own directories.
49
+
50
+ ## Keeping this skill current
51
+
52
+ If `sideby doctor --json` reports `skill.outdated`, this skill was written for another sideby version. Tell the user to update it with `npx skills add Adonis0123/sideby -g`.
@@ -0,0 +1,31 @@
1
+ # Create accounts and short commands
2
+
3
+ ## Create an account
4
+
5
+ Check the name first: `^[a-z0-9][a-z0-9-]{0,31}$`, and not already taken (`sideby list --json`).
6
+
7
+ ```sh
8
+ sideby new claude work # subscription account: ~/.claude-work
9
+ sideby new claude deepseek --api # API account: ~/.claude-deepseek with a proxy.env template (mode 600)
10
+ sideby new claude 008 --alias cc008 # also adds the short command cc008 to config aliases
11
+ ```
12
+
13
+ Only pass `--alias` when the user wants a short command; follow their existing pattern (`cc001`…`cc007` for `claude:001`…`claude:007` suggests `cc008`). An invalid, reserved or taken alias is refused before anything is created (error `code: "alias-invalid"`). If `alias.added` is false in `--json`, the account exists but the alias is missing: tell the user the message, do not edit the config by hand.
14
+
15
+ Then:
16
+
17
+ - **Subscription account**: tell the user to run `sideby login claude:work` in their own terminal (for pi, `sideby login pi:<name>` starts pi; then they type `/login`). Do not run it for them.
18
+ - **API account**: tell the user to open the `proxy.env` path printed by `new` in their editor and fill in the values. Do not read or write it yourself. It then shows `login: "not-needed"`.
19
+ - **pi**: a `proxy.env` in a pi account only loads provider keys; the account stays a subscription account and still needs `/login`.
20
+ - Afterwards: `sideby doctor <ref> --json` to confirm the new account is healthy, then the user starts it with `sideby run <ref>`.
21
+
22
+ ## Short commands (aliases)
23
+
24
+ For an account that already exists: `sideby alias add <short> <ref> --json`.
25
+
26
+ To start one account with fixed Host arguments, such as another model, put them after `--`: `sideby alias add pi-kimi pi:main --json -- --model kimi-coding/k3`. It is the same account (same login, same sessions), not a new one; do not create an account per model. Only `sideby run <short>` adds the arguments.
27
+
28
+ - `status: "exists"` means it was already there.
29
+ - A refusal names the next step (`sideby alias rm <short>` first).
30
+ - Entry points that need environment variables are not aliases: leave them in the user's shell rc.
31
+ - Do not edit `aliases` in the config by hand.
@@ -0,0 +1,47 @@
1
+ # Diagnose and repair
2
+
3
+ ## Diagnose
4
+
5
+ Start read-only:
6
+
7
+ ```sh
8
+ sideby list --json # accounts: ref, family, kind (subscription|api), dir, login, identity.email, model, hostInstalled, problems
9
+ sideby doctor --json # findings: level ok|warn|fail, account, item, code, message, hint, fixable
10
+ sideby quota --json # per account: quota windows (5h, 7d, usedPercent, resetsAt, observedAt) and 7-day tokens
11
+ sideby plugins --json # loaded plugins (setting names only, never values) and load errors
12
+ ```
13
+
14
+ Narrow with an account or family: `sideby doctor claude:work --json`, `sideby doctor codex --json`, `sideby quota work --json`. On an ambiguity error, use the full ref from the candidates listed.
15
+
16
+ Shared Items the Main Account does not have are skipped: no Finding, not counted in `shared`. A directory such as `~/.claude-code-router` that holds neither `proxy.env` nor any Shared Item is not listed as an account.
17
+
18
+ | Signal | Meaning | What to do |
19
+ |---|---|---|
20
+ | `fail` / `warn` with `fixable: true` | Safe repair exists | Offer `doctor --fix` (see Repair) |
21
+ | `fixable: false` with a `hint` | sideby will not touch it on purpose (real file where a link belongs, API account item) | Show the hint; the user decides |
22
+ | `warn` `link.other-target` | The link resolves, but not to the Main Account's item; often deliberate | Mention it; change nothing unless the user asks |
23
+ | `fail` `link.dangling` | The link points at nothing | Show the hint (`ls -l <path>`); the user decides how to repair it |
24
+ | `fail` `symlink-forbidden` without `fixable` | The Host needs a real file here, but the link points somewhere other than the Main Account | Show the hint; sideby will not replace a link it did not create |
25
+ | credential item, mode not 600 | `proxy.env`, `auth.json`, `.claude.json` readable by others | `--fix` resets the mode to 600 |
26
+ | `warn` `skill.outdated` (in `general`) | The installed sideby skill is for another sideby version | Tell the user to run `npx skills add Adonis0123/sideby -g` |
27
+ | name looks like a backup (`bak`, `backup`, `old`, `tmp`) | A stray directory was picked up as an account | Suggest adding its ref to `ignore` in `${XDG_CONFIG_HOME:-~/.config}/sideby/config.json` |
28
+ | `login: "not-needed"` (`key` in `sideby list`) | API account; it authenticates with `proxy.env` | Nothing to do |
29
+ | `problems` on an account in `list --json` | A plugin failed while reading it (for example a settings file that is not valid JSON) | Show the message; the account itself still works |
30
+ | quota `unavailable` / `not-enabled` | Claude quota source is off | Offer `sideby quota setup claude` |
31
+ | quota `unavailable` / `no-session` | No session since the source was enabled | Ask the user to start one session with that account |
32
+ | quota `unavailable` / `no-source` | Grok, pi: the Host has no public source | Nothing to fix |
33
+ | quota `unavailable` / `api-account` | API accounts have no quota | Nothing to fix |
34
+ | quota `unavailable` / `unrecognized` | Host changed its file format | Report it; suggest filing an issue with the Host version |
35
+ | host not installed | Accounts exist but the CLI is missing | Point to the Host's install docs; do not install it unasked |
36
+
37
+ Quota is only as fresh as each account's last session; `observedAt` says when it was recorded. A window whose `resetsAt` has passed has reset.
38
+
39
+ ## Repair
40
+
41
+ 1. Run `sideby doctor [ref] --json` and show the user every finding you plan to fix, grouped by account.
42
+ 2. After the user agrees, run `sideby doctor [ref] --fix`, then `sideby doctor [ref] --json` again and report what is still open.
43
+ 3. `--force` is only for `json-key` items (for example `.claude.json#mcpServers`) when a fix would remove entries the account already has. Never add `--force` without telling the user exactly which entries would disappear.
44
+
45
+ `--fix` never replaces a real file with a link, never re-points an existing symlink (wrong or dangling links are only reported), never writes through a link into the Main Account, and never changes credential contents. Findings it skips need a human decision; explain the hint, do not work around it with `rm` or `ln`.
46
+
47
+ `doctor` exits 1 only when a `fail` finding is left; warnings alone exit 0.
@@ -0,0 +1,41 @@
1
+ # Handoff: keep working on another account
2
+
3
+ Use this when the user says an account hit its 5-hour or weekly limit ("usage limit reached", "rate limited", "resets at …") and wants to keep working, or asks which account has room. sideby recommends the account of the same family with the lowest Quota Pressure (the fullest window that has not reset yet). It never switches by itself; the user starts the next account.
4
+
5
+ ## Steps
6
+
7
+ 1. Run `sideby next <family> --json` (`claude` or `codex`). It only recommends; it starts nothing.
8
+ 2. Tell the user the pick and why, from `pick` and `accounts`:
9
+
10
+ | `state` | Meaning | Can be picked |
11
+ |---|---|---|
12
+ | `ready` | Subscription account with room; `pressure` is its fullest live window in percent | Yes, lowest `pressure` first |
13
+ | `unknown` | No quota data yet (no session since quota was turned on, or Claude quota is off) | Yes, after `ready` |
14
+ | `api` | API account, pay per use | Only with `--include-api` |
15
+ | `full` | A live window is at 85% or more; `resetsAt` is when it is usable again | No |
16
+ | `logged-out` | Needs `sideby login <ref>` | No |
17
+
18
+ Each entry's `observedAt` says when its quota was recorded. If `hasQuota` is `false`, no account has quota data: the pick is only a guess, so say so and suggest turning quota on (see the routing table in SKILL.md) or letting the user choose.
19
+ 3. Give the user the command to run in their own terminal: `sideby next <family>` (starts the pick) or `sideby run <pick>`. Host arguments go after `--`. Do not run it yourself.
20
+ 4. Offer a handoff note: the new session starts empty, because each account keeps its own sessions. Write a short note the user can paste into it: the goal, what is done, what is in progress, the files involved, and the next step.
21
+
22
+ ## When nothing can be picked
23
+
24
+ `pick` is `null` and the exit code is 1:
25
+
26
+ - Every account `full`: tell the user `earliestReset.ref` comes back at `earliestReset.at`.
27
+ - Accounts `logged-out`: the user can sign in with `sideby login <ref>`.
28
+ - Only `api` left: ask whether they want to pay per use before suggesting `sideby next <family> --include-api`.
29
+
30
+ ## Other answers
31
+
32
+ - Error `code: "no-quota-source"` (Grok, pi): the Host publishes no quota. The message lists the family's accounts; let the user choose one for `sideby run <ref>`.
33
+ - Error `code: "no-accounts"`: the family has no account yet; see creating accounts.
34
+ - Many `unknown` Claude accounts: Claude quota may be off. `sideby quota --json` shows `not-enabled`; the one-time setup turns it on.
35
+ - Host arguments the user wants (another model, say) go after `--`: `sideby next claude -- --model opus`.
36
+ - Quota is only as fresh as each account's last session. Do not promise an account has room; say what the data shows and when it was recorded.
37
+
38
+ ## Never
39
+
40
+ - Switch accounts by editing config or environment, copy session files between account directories, or read any credential.
41
+ - Start a session for the user.