offsite 0.0.3 → 0.0.5

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 (118) hide show
  1. package/README.md +20 -8
  2. package/apps/server/dist/main.mjs +5772 -0
  3. package/apps/server/dist/main.mjs.map +1 -0
  4. package/apps/web/dist/apple-touch-icon.png +0 -0
  5. package/apps/web/dist/assets/{angular-html-ji4UO7hp.js → angular-html-B53hPuXT.js} +1 -1
  6. package/apps/web/dist/assets/{angular-ts-CkobLhDa.js → angular-ts--nhprFvo.js} +1 -1
  7. package/apps/web/dist/assets/{apl-DAjPJTs4.js → apl-BMZ6gSxk.js} +1 -1
  8. package/apps/web/dist/assets/{astro-DlwA-zmc.js → astro-BTM15MDF.js} +1 -1
  9. package/apps/web/dist/assets/{blade-wTlHdbgB.js → blade-Dr8Nx-1X.js} +1 -1
  10. package/apps/web/dist/assets/{c-HyCIpwKL.js → c-CYWvPMKX.js} +1 -1
  11. package/apps/web/dist/assets/{chapel-SOYLpFSa.js → chapel-C8sB6Foh.js} +1 -1
  12. package/apps/web/dist/assets/{cobol-DlvLD04V.js → cobol-FnuKKfgs.js} +1 -1
  13. package/apps/web/dist/assets/{coffee-CGp5oJTY.js → coffee-DJrh6kIB.js} +1 -1
  14. package/apps/web/dist/assets/{cpp-CzmH13Nm.js → cpp-BLAvrTU1.js} +1 -1
  15. package/apps/web/dist/assets/{crystal-zS14MbR_.js → crystal-BthZctDJ.js} +1 -1
  16. package/apps/web/dist/assets/{css-DQEQn59R.js → css-DjklwMwW.js} +1 -1
  17. package/apps/web/dist/assets/{edge-Bkv0KzZU.js → edge-BunAX5o-.js} +1 -1
  18. package/apps/web/dist/assets/{elixir-B8tse0js.js → elixir-DgeksfSS.js} +1 -1
  19. package/apps/web/dist/assets/{elm-F2InAxd7.js → elm-l1eWnD1P.js} +1 -1
  20. package/apps/web/dist/assets/{erb-CAIamwOm.js → erb-JKFWiSFc.js} +1 -1
  21. package/apps/web/dist/assets/{git-rebase-U0z47rUi.js → git-rebase-AsNqLj-a.js} +1 -1
  22. package/apps/web/dist/assets/{glimmer-js-Bg_zPoN-.js → glimmer-js-B8iwahHO.js} +1 -1
  23. package/apps/web/dist/assets/{glimmer-ts-v3suqAPH.js → glimmer-ts-7zfF4XN6.js} +1 -1
  24. package/apps/web/dist/assets/{glsl-8io-Pcmd.js → glsl-BJka2Ayq.js} +1 -1
  25. package/apps/web/dist/assets/{graphql-B_q9cV-C.js → graphql-7lx4uUDH.js} +1 -1
  26. package/apps/web/dist/assets/{hack-DosfNWDX.js → hack-Jm3cv9jc.js} +1 -1
  27. package/apps/web/dist/assets/{haml-DcBtkGn5.js → haml-Csl_BhoG.js} +1 -1
  28. package/apps/web/dist/assets/{handlebars-2F0KxPFu.js → handlebars-CFp1rmy8.js} +1 -1
  29. package/apps/web/dist/assets/{html-DrWZZyp3.js → html-D_zffrV4.js} +1 -1
  30. package/apps/web/dist/assets/{html-derivative-BaV8vDp-.js → html-derivative-B-pqZuPW.js} +1 -1
  31. package/apps/web/dist/assets/{http-Dwo7FxJA.js → http-CU_emOoa.js} +1 -1
  32. package/apps/web/dist/assets/{hurl-9r6SjmMP.js → hurl-BRBJ1eQP.js} +1 -1
  33. package/apps/web/dist/assets/index-0B-Gdd7b.css +2 -0
  34. package/apps/web/dist/assets/index-CJuLsqhP.js +1148 -0
  35. package/apps/web/dist/assets/{java-CAkt7S2h.js → java-DWuVSV9c.js} +1 -1
  36. package/apps/web/dist/assets/{javascript-CMo8GEjU.js → javascript-CPq3YNXl.js} +1 -1
  37. package/apps/web/dist/assets/{jinja-XhRt7Tzv.js → jinja-Cwr4gaQT.js} +1 -1
  38. package/apps/web/dist/assets/{jison-BXZQEb4C.js → jison-tIc7kJPc.js} +1 -1
  39. package/apps/web/dist/assets/{json-SyJDQmRp.js → json-CuLUmV8d.js} +1 -1
  40. package/apps/web/dist/assets/{jsx-B76-zKzH.js → jsx-c0vioNM-.js} +1 -1
  41. package/apps/web/dist/assets/{julia-Ca5lbuMA.js → julia-DL1_3nCX.js} +1 -1
  42. package/apps/web/dist/assets/{just-CDt2RojJ.js → just-Dz1Oq8ln.js} +1 -1
  43. package/apps/web/dist/assets/{latex-D9bybvWo.js → latex-BtJjjmHB.js} +1 -1
  44. package/apps/web/dist/assets/{liquid-DMp-tByG.js → liquid-CUxfxikC.js} +1 -1
  45. package/apps/web/dist/assets/{lua-zNnfh_4o.js → lua-FURW1z3g.js} +1 -1
  46. package/apps/web/dist/assets/{marko-Ce5B11L0.js → marko-D33gqJht.js} +1 -1
  47. package/apps/web/dist/assets/{mdc-Btapt9E8.js → mdc-rJL-euOm.js} +1 -1
  48. package/apps/web/dist/assets/{nginx-Bzjverzh.js → nginx-CChB1oIE.js} +1 -1
  49. package/apps/web/dist/assets/{nim-D6zpNhUX.js → nim-C3VcT8nQ.js} +1 -1
  50. package/apps/web/dist/assets/{org-DTy-FvFD.js → org-CX9ySstM.js} +1 -1
  51. package/apps/web/dist/assets/{perl-BV8Dxusy.js → perl-BmdWqdcq.js} +1 -1
  52. package/apps/web/dist/assets/{php-BjkIa26S.js → php-CMtd7vHw.js} +1 -1
  53. package/apps/web/dist/assets/{pug-DdfmTHk6.js → pug-DRlx8d5w.js} +1 -1
  54. package/apps/web/dist/assets/{qml-BWLYImhB.js → qml-WYwqwy0P.js} +1 -1
  55. package/apps/web/dist/assets/{r-CKc9klse.js → r-C1yAXCUm.js} +1 -1
  56. package/apps/web/dist/assets/{razor-YcF2a59Y.js → razor-RKu7WkDv.js} +1 -1
  57. package/apps/web/dist/assets/{regexp-D3esVJ1X.js → regexp-DuLU1P7q.js} +1 -1
  58. package/apps/web/dist/assets/{rst-DVaj4AQD.js → rst-CmK0AAXk.js} +1 -1
  59. package/apps/web/dist/assets/{ruby-DBJQEVev.js → ruby-DwgaoIUu.js} +1 -1
  60. package/apps/web/dist/assets/{sas-NSuLkGD1.js → sas-iTrXuHXc.js} +1 -1
  61. package/apps/web/dist/assets/{scss-TMy8m-so.js → scss-CEysq-zA.js} +1 -1
  62. package/apps/web/dist/assets/{shellscript-BVuIsFkY.js → shellscript-B0mTpBTm.js} +1 -1
  63. package/apps/web/dist/assets/{shellsession-CV7MHIu6.js → shellsession-BuzD9EVx.js} +1 -1
  64. package/apps/web/dist/assets/{soy-DDY0EoKE.js → soy-ClDsFuFk.js} +1 -1
  65. package/apps/web/dist/assets/{sql-CoZqqtiv.js → sql-Dc1h3orO.js} +1 -1
  66. package/apps/web/dist/assets/{stata-B8C1noIb.js → stata-l31dxrtC.js} +1 -1
  67. package/apps/web/dist/assets/{surrealql-BYiUJt-V.js → surrealql-x6LM7pkl.js} +1 -1
  68. package/apps/web/dist/assets/{svelte-DGeZ8dPs.js → svelte-CtkYFYuK.js} +1 -1
  69. package/apps/web/dist/assets/{templ-Dn21SE_C.js → templ-DHMinkR-.js} +1 -1
  70. package/apps/web/dist/assets/{tex-Da9GBCsM.js → tex-CXbWoQMY.js} +1 -1
  71. package/apps/web/dist/assets/{ts-tags-BuL1T6K3.js → ts-tags-BikYq-3m.js} +1 -1
  72. package/apps/web/dist/assets/{tsx-DiLCnfgl.js → tsx-zHJnYG9T.js} +1 -1
  73. package/apps/web/dist/assets/{twig-Cx1peiH-.js → twig-DKCfiSr9.js} +1 -1
  74. package/apps/web/dist/assets/{typescript-pVxvHJ4R.js → typescript-K9TDgxRD.js} +1 -1
  75. package/apps/web/dist/assets/{typst-CJQbitzj.js → typst-BpXkFpDR.js} +1 -1
  76. package/apps/web/dist/assets/{vue-CXKyVnbB.js → vue-BYYRFXPM.js} +1 -1
  77. package/apps/web/dist/assets/{vue-html-AQjnBMTh.js → vue-html-BR347tzO.js} +1 -1
  78. package/apps/web/dist/assets/{vue-vine-DYxt9AbK.js → vue-vine-Jv4OHYgW.js} +1 -1
  79. package/apps/web/dist/assets/{xml-CEJ01uJ1.js → xml-DuYGU-7M.js} +1 -1
  80. package/apps/web/dist/assets/{xsl-CULFBy6v.js → xsl-B950Zbyt.js} +1 -1
  81. package/apps/web/dist/assets/{yaml-BNf68xM_.js → yaml-XFYTn8dR.js} +1 -1
  82. package/apps/web/dist/icon-192.png +0 -0
  83. package/apps/web/dist/icon-512.png +0 -0
  84. package/apps/web/dist/icon-maskable-512.png +0 -0
  85. package/apps/web/dist/icon.svg +5 -0
  86. package/apps/web/dist/index.html +4 -2
  87. package/apps/web/dist/sw.js +1 -81
  88. package/bin/offsite.js +1 -1
  89. package/package.json +5 -1
  90. package/apps/server/dist/args.js +0 -11
  91. package/apps/server/dist/claude.js +0 -245
  92. package/apps/server/dist/config.js +0 -191
  93. package/apps/server/dist/content.js +0 -172
  94. package/apps/server/dist/db.js +0 -13
  95. package/apps/server/dist/files.js +0 -50
  96. package/apps/server/dist/git.js +0 -133
  97. package/apps/server/dist/history.js +0 -137
  98. package/apps/server/dist/hub.js +0 -10
  99. package/apps/server/dist/main.js +0 -70
  100. package/apps/server/dist/projects.js +0 -92
  101. package/apps/server/dist/protocol.js +0 -20
  102. package/apps/server/dist/push.js +0 -152
  103. package/apps/server/dist/run.js +0 -375
  104. package/apps/server/dist/runs.js +0 -102
  105. package/apps/server/dist/schemes.js +0 -262
  106. package/apps/server/dist/sessions.js +0 -99
  107. package/apps/server/dist/socket.js +0 -193
  108. package/apps/server/dist/storage.js +0 -71
  109. package/apps/server/dist/terminal/alerts.js +0 -145
  110. package/apps/server/dist/terminal/process.js +0 -207
  111. package/apps/server/dist/terminal/shell-check.js +0 -91
  112. package/apps/server/dist/terminal/shell-integration.js +0 -112
  113. package/apps/server/dist/terminal/terminal.js +0 -402
  114. package/apps/web/dist/assets/index-CIBt6t2M.css +0 -2
  115. package/apps/web/dist/assets/index-CPpMMYyZ.js +0 -902
  116. /package/apps/server/src/{terminal → services/terminal}/shell-integration/bash/offsite.bash +0 -0
  117. /package/apps/server/src/{terminal → services/terminal}/shell-integration/fish/offsite.fish +0 -0
  118. /package/apps/server/src/{terminal → services/terminal}/shell-integration/zsh/.zshenv +0 -0
@@ -1,262 +0,0 @@
1
- export const schemes = [
2
- {
3
- id: 'one-dark-darker',
4
- name: 'One Dark Darker',
5
- background: '#15181C',
6
- foreground: '#ABB2BF',
7
- cursor: '#B3BAC5',
8
- selectionBackground: '#3B414D',
9
- palette: [
10
- '#4A4F5A',
11
- '#EE5D69',
12
- '#97C775',
13
- '#B68353',
14
- '#61AFEF',
15
- '#C678DD',
16
- '#56B6C2',
17
- '#CCCCCC',
18
- '#616A7B',
19
- '#FE808A',
20
- '#C2DEAD',
21
- '#D1A47A',
22
- '#93CFFF',
23
- '#E0A8F1',
24
- '#82D2DC',
25
- '#FFFFFF',
26
- ],
27
- },
28
- {
29
- id: 'one-dark-pro',
30
- name: 'One Dark Pro',
31
- background: '#282C34',
32
- foreground: '#ABB2BF',
33
- cursor: '#528BFF',
34
- selectionBackground: '#41454E',
35
- palette: [
36
- '#3F4451',
37
- '#E05561',
38
- '#8CC265',
39
- '#D18F52',
40
- '#4AA5F0',
41
- '#C162DE',
42
- '#42B3C2',
43
- '#D7DAE0',
44
- '#4F5666',
45
- '#FF616E',
46
- '#A5E075',
47
- '#F0A45D',
48
- '#4DC4FF',
49
- '#DE73FF',
50
- '#4CD1E0',
51
- '#E6E6E6',
52
- ],
53
- },
54
- {
55
- id: 'dracula',
56
- name: 'Dracula',
57
- background: '#282A36',
58
- foreground: '#F8F8F2',
59
- cursor: '#F8F8F2',
60
- selectionBackground: '#44475A',
61
- palette: [
62
- '#21222C',
63
- '#FF5555',
64
- '#50FA7B',
65
- '#F1FA8C',
66
- '#BD93F9',
67
- '#FF79C6',
68
- '#8BE9FD',
69
- '#F8F8F2',
70
- '#6272A4',
71
- '#FF6E6E',
72
- '#69FF94',
73
- '#FFFFA5',
74
- '#D6ACFF',
75
- '#FF92DF',
76
- '#A4FFFF',
77
- '#FFFFFF',
78
- ],
79
- },
80
- {
81
- id: 'tokyo-night',
82
- name: 'Tokyo Night',
83
- background: '#1A1B26',
84
- foreground: '#C0CAF5',
85
- cursor: '#C0CAF5',
86
- selectionBackground: '#33467C',
87
- palette: [
88
- '#15161E',
89
- '#F7768E',
90
- '#9ECE6A',
91
- '#E0AF68',
92
- '#7AA2F7',
93
- '#BB9AF7',
94
- '#7DCFFF',
95
- '#A9B1D6',
96
- '#414868',
97
- '#F7768E',
98
- '#9ECE6A',
99
- '#E0AF68',
100
- '#7AA2F7',
101
- '#BB9AF7',
102
- '#7DCFFF',
103
- '#C0CAF5',
104
- ],
105
- },
106
- {
107
- id: 'catppuccin-mocha',
108
- name: 'Catppuccin Mocha',
109
- background: '#1E1E2E',
110
- foreground: '#CDD6F4',
111
- cursor: '#F5E0DC',
112
- selectionBackground: '#585B70',
113
- palette: [
114
- '#45475A',
115
- '#F38BA8',
116
- '#A6E3A1',
117
- '#F9E2AF',
118
- '#89B4FA',
119
- '#F5C2E7',
120
- '#94E2D5',
121
- '#BAC2DE',
122
- '#585B70',
123
- '#F38BA8',
124
- '#A6E3A1',
125
- '#F9E2AF',
126
- '#89B4FA',
127
- '#F5C2E7',
128
- '#94E2D5',
129
- '#A6ADC8',
130
- ],
131
- },
132
- {
133
- id: 'nord',
134
- name: 'Nord',
135
- background: '#2E3440',
136
- foreground: '#D8DEE9',
137
- cursor: '#D8DEE9',
138
- selectionBackground: '#434C5E',
139
- palette: [
140
- '#3B4252',
141
- '#BF616A',
142
- '#A3BE8C',
143
- '#EBCB8B',
144
- '#81A1C1',
145
- '#B48EAD',
146
- '#88C0D0',
147
- '#E5E9F0',
148
- '#4C566A',
149
- '#BF616A',
150
- '#A3BE8C',
151
- '#EBCB8B',
152
- '#81A1C1',
153
- '#B48EAD',
154
- '#8FBCBB',
155
- '#ECEFF4',
156
- ],
157
- },
158
- {
159
- id: 'gruvbox-dark',
160
- name: 'Gruvbox Dark',
161
- background: '#282828',
162
- foreground: '#EBDBB2',
163
- cursor: '#EBDBB2',
164
- selectionBackground: '#504945',
165
- palette: [
166
- '#282828',
167
- '#CC241D',
168
- '#98971A',
169
- '#D79921',
170
- '#458588',
171
- '#B16286',
172
- '#689D6A',
173
- '#A89984',
174
- '#928374',
175
- '#FB4934',
176
- '#B8BB26',
177
- '#FABD2F',
178
- '#83A598',
179
- '#D3869B',
180
- '#8EC07C',
181
- '#EBDBB2',
182
- ],
183
- },
184
- {
185
- id: 'solarized-dark',
186
- name: 'Solarized Dark',
187
- background: '#002B36',
188
- foreground: '#839496',
189
- cursor: '#839496',
190
- selectionBackground: '#073642',
191
- palette: [
192
- '#073642',
193
- '#DC322F',
194
- '#859900',
195
- '#B58900',
196
- '#268BD2',
197
- '#D33682',
198
- '#2AA198',
199
- '#EEE8D5',
200
- '#002B36',
201
- '#CB4B16',
202
- '#586E75',
203
- '#657B83',
204
- '#839496',
205
- '#6C71C4',
206
- '#93A1A1',
207
- '#FDF6E3',
208
- ],
209
- },
210
- {
211
- id: 'github-dark',
212
- name: 'GitHub Dark',
213
- background: '#0D1117',
214
- foreground: '#E6EDF3',
215
- cursor: '#E6EDF3',
216
- selectionBackground: '#264F78',
217
- palette: [
218
- '#484F58',
219
- '#FF7B72',
220
- '#3FB950',
221
- '#D29922',
222
- '#58A6FF',
223
- '#BC8CFF',
224
- '#39C5CF',
225
- '#B1BAC4',
226
- '#6E7681',
227
- '#FFA198',
228
- '#56D364',
229
- '#E3B341',
230
- '#79C0FF',
231
- '#D2A8FF',
232
- '#56D4DD',
233
- '#FFFFFF',
234
- ],
235
- },
236
- {
237
- id: 'rose-pine',
238
- name: 'Rosé Pine',
239
- background: '#191724',
240
- foreground: '#E0DEF4',
241
- cursor: '#E0DEF4',
242
- selectionBackground: '#403D52',
243
- palette: [
244
- '#26233A',
245
- '#EB6F92',
246
- '#31748F',
247
- '#F6C177',
248
- '#9CCFD8',
249
- '#C4A7E7',
250
- '#EBBCBA',
251
- '#E0DEF4',
252
- '#6E6A86',
253
- '#EB6F92',
254
- '#31748F',
255
- '#F6C177',
256
- '#9CCFD8',
257
- '#C4A7E7',
258
- '#EBBCBA',
259
- '#E0DEF4',
260
- ],
261
- },
262
- ];
@@ -1,99 +0,0 @@
1
- import { watch } from 'node:fs';
2
- import path from 'node:path';
3
- import { deleteSession, forkSession, getSessionMessages, listSessions, renameSession, } from '@anthropic-ai/claude-agent-sdk';
4
- import { readConfig } from './config.js';
5
- import { broadcast } from './hub.js';
6
- import { projects } from './projects.js';
7
- import { runs } from './run.js';
8
- import { readJson, writeJson } from './storage.js';
9
- let watcher = null;
10
- let timer;
11
- export async function sessions() {
12
- const marks = readMarks();
13
- const lists = await Promise.all(projects().map(async (project) => (await listSessions({
14
- dir: project.path,
15
- includeWorktrees: false,
16
- includeProgrammatic: false,
17
- })).map((item) => ({
18
- id: item.sessionId,
19
- title: item.summary,
20
- cwd: project.path,
21
- branch: item.gitBranch ?? null,
22
- updatedAt: item.lastModified,
23
- pinned: marks.pinned.includes(item.sessionId),
24
- archived: marks.archived.includes(item.sessionId),
25
- }))));
26
- return lists.flat();
27
- }
28
- export async function publishSessions() {
29
- try {
30
- broadcast({ type: 'sessions', sessions: await sessions() });
31
- }
32
- catch (error) {
33
- console.warn(`could not list threads: ${error}`);
34
- }
35
- }
36
- export function watchSessions() {
37
- watcher?.close();
38
- watcher = null;
39
- const dir = path.join(readConfig().claudeBaseDir, 'projects');
40
- try {
41
- watcher = watch(dir, { recursive: true }, () => {
42
- timer ??= setTimeout(() => {
43
- timer = undefined;
44
- void publishSessions();
45
- }, 1000);
46
- });
47
- }
48
- catch (error) {
49
- if (error.code !== 'ENOENT')
50
- throw error;
51
- console.warn(`${dir} does not exist; threads changed outside offsite will not show`);
52
- return;
53
- }
54
- watcher.on('error', (error) => console.warn(`stopped watching ${dir}: ${error}`));
55
- }
56
- export async function updateSession(id, patch) {
57
- if (patch.title !== undefined)
58
- await renameSession(id, patch.title);
59
- const marks = readMarks();
60
- if (patch.pinned !== undefined)
61
- marks.pinned = mark(marks.pinned, id, patch.pinned);
62
- if (patch.archived !== undefined)
63
- marks.archived = mark(marks.archived, id, patch.archived);
64
- writeMarks(marks);
65
- }
66
- export async function removeSession(id) {
67
- const run = runs.get(id);
68
- if (run !== undefined) {
69
- run.stop();
70
- await run.closed;
71
- }
72
- await deleteSession(id);
73
- const marks = readMarks();
74
- writeMarks({
75
- pinned: mark(marks.pinned, id, false),
76
- archived: mark(marks.archived, id, false),
77
- });
78
- }
79
- export async function fork(sessionId, cwd, messageId) {
80
- const disk = await getSessionMessages(sessionId, { dir: cwd });
81
- const index = disk.findIndex((item) => item.uuid === messageId);
82
- if (index < 0)
83
- throw new Error('Cannot fork the session at that point');
84
- const result = await forkSession(sessionId, {
85
- dir: cwd,
86
- upToMessageId: messageId,
87
- });
88
- return { sessionId: result.sessionId };
89
- }
90
- function readMarks() {
91
- return (readJson('sessions.json') ?? { pinned: [], archived: [] });
92
- }
93
- function writeMarks(marks) {
94
- writeJson('sessions.json', marks);
95
- }
96
- function mark(ids, id, on) {
97
- const rest = ids.filter((item) => item !== id);
98
- return on ? [...rest, id] : rest;
99
- }
@@ -1,193 +0,0 @@
1
- import { accounts, addAccount, capabilities, linkAccount, publishAccounts, removeAccount, updateAccount, } from './claude.js';
2
- import { configInfo, readConfig, saveConfig } from './config.js';
3
- import { listFiles, saveUpload } from './files.js';
4
- import { commit, createPullRequest, gitStatus, push, suggestCommitMessage, workingDiff, } from './git.js';
5
- import { earlier } from './history.js';
6
- import { clients } from './hub.js';
7
- import { addProject, directories, projects, removeProject, updateProject, } from './projects.js';
8
- import { pushKey, subscribe, unsubscribe } from './push.js';
9
- import { activity, runs } from './run.js';
10
- import { open, rewind, send } from './runs.js';
11
- import { fork, publishSessions, removeSession, sessions, updateSession, watchSessions, } from './sessions.js';
12
- import { listShells } from './terminal/process.js';
13
- import { busyTerminal, detachTerminal, savePastedImage, terminalInput, terminalRequest, } from './terminal/terminal.js';
14
- const handlers = {
15
- ping: () => null,
16
- sync: async () => ({
17
- ...configInfo(),
18
- projects: projects(),
19
- sessions: await sessions(),
20
- activity: activity(),
21
- }),
22
- 'config.get': () => configInfo(),
23
- 'config.save': (params) => {
24
- const before = readConfig().claudeBaseDir;
25
- const saved = saveConfig(params);
26
- if (saved.claudeBaseDir === before)
27
- return saved;
28
- watchSessions();
29
- void publishSessions();
30
- void publishAccounts();
31
- return saved;
32
- },
33
- 'projects.add': async (params) => {
34
- const project = await addProject(params.path);
35
- void publishSessions();
36
- return project;
37
- },
38
- 'projects.update': (params) => updateProject(params.path, params.patch),
39
- 'projects.remove': (params) => {
40
- removeProject(params.path);
41
- void publishSessions();
42
- return null;
43
- },
44
- 'directories.list': (params) => directories(params.path),
45
- 'sessions.update': async (params) => {
46
- try {
47
- await updateSession(params.id, params.patch);
48
- }
49
- finally {
50
- void publishSessions();
51
- }
52
- return null;
53
- },
54
- 'sessions.remove': async (params) => {
55
- try {
56
- await removeSession(params.id);
57
- }
58
- finally {
59
- void publishSessions();
60
- }
61
- return null;
62
- },
63
- 'sessions.open': async (params, client) => {
64
- await open(client, params.sessionId, params.cwd);
65
- return null;
66
- },
67
- 'sessions.earlier': (params) => earlier(params.sessionId, params.cwd, params.before),
68
- 'sessions.send': async (params, client) => {
69
- await send(client, params);
70
- return null;
71
- },
72
- 'sessions.unqueue': (params) => {
73
- runs.get(params.sessionId)?.unqueue(params.id);
74
- return null;
75
- },
76
- 'sessions.interrupt': async (params) => {
77
- await runs.get(params.sessionId)?.query.interrupt();
78
- return null;
79
- },
80
- 'sessions.configure': async (params) => {
81
- await runs.get(params.sessionId)?.configure(params.settings);
82
- return null;
83
- },
84
- 'sessions.respond': (params) => {
85
- runs
86
- .get(params.sessionId)
87
- ?.respond(params.requestId, params.decision, params.answers);
88
- return null;
89
- },
90
- 'sessions.rewind': (params) => rewind(params),
91
- 'sessions.fork': async (params) => {
92
- const result = await fork(params.sessionId, params.cwd, params.messageId);
93
- void publishSessions();
94
- return result;
95
- },
96
- 'accounts.list': () => accounts(),
97
- 'accounts.add': (params) => {
98
- addAccount(params.name, params.configDir);
99
- void publishAccounts();
100
- return null;
101
- },
102
- 'accounts.update': (params) => {
103
- updateAccount(params.id, params.name, params.configDir);
104
- void publishAccounts();
105
- return null;
106
- },
107
- 'accounts.remove': (params) => {
108
- removeAccount(params.id);
109
- void publishAccounts();
110
- return null;
111
- },
112
- 'accounts.link': async (params) => {
113
- await linkAccount(params.id);
114
- void publishAccounts();
115
- return null;
116
- },
117
- capabilities: (params) => capabilities(params.accountId, params.cwd),
118
- 'files.list': (params) => listFiles(params.cwd),
119
- 'files.upload': (params) => saveUpload(params.name, Buffer.from(params.data, 'base64')),
120
- 'git.status': (params) => gitStatus(params.cwd),
121
- 'git.diff': (params) => workingDiff(params.cwd),
122
- 'git.commit': (params) => commit(params.cwd, params.message),
123
- 'git.push': (params) => push(params.cwd),
124
- 'git.pullRequest': (params) => createPullRequest(params.cwd),
125
- 'git.message': (params) => suggestCommitMessage(params.accountId, params.cwd),
126
- 'push.key': () => pushKey(),
127
- 'push.subscribe': (params) => {
128
- subscribe(params);
129
- return null;
130
- },
131
- 'push.unsubscribe': (params) => {
132
- unsubscribe(params.endpoint);
133
- return null;
134
- },
135
- terminal: async (params, client) => {
136
- await terminalRequest(client, params);
137
- return null;
138
- },
139
- 'terminal.shells': () => listShells(),
140
- 'terminal.busy': (params) => busyTerminal(params.id),
141
- 'terminal.paste': (params) => savePastedImage(params.type, Buffer.from(params.data, 'base64')),
142
- debug: (params) => {
143
- console.log(`[paste-debug] ${params.line}`);
144
- return null;
145
- },
146
- };
147
- export function connectClient(socket) {
148
- const client = {
149
- socket,
150
- heardAt: Date.now(),
151
- opening: null,
152
- sessionId: null,
153
- send: (message) => socket.send(JSON.stringify(message)),
154
- };
155
- clients.add(client);
156
- socket.on('message', (data, isBinary) => {
157
- client.heardAt = Date.now();
158
- if (isBinary) {
159
- terminalInput(client, data);
160
- return;
161
- }
162
- void answer(client, String(data));
163
- });
164
- socket.on('error', (error) => console.warn(`a browser connection failed: ${error}`));
165
- socket.on('close', () => {
166
- clients.delete(client);
167
- detachTerminal(client);
168
- });
169
- }
170
- async function answer(client, text) {
171
- let call;
172
- try {
173
- call = JSON.parse(text);
174
- }
175
- catch (error) {
176
- console.warn(`ignoring a message that is not JSON: ${error}`);
177
- return;
178
- }
179
- try {
180
- if (!Object.hasOwn(handlers, call.method))
181
- throw new Error(`unknown method ${call.method}`);
182
- const handler = handlers[call.method];
183
- const result = await handler(call.params, client);
184
- client.send({ type: 'reply', id: call.id, result });
185
- }
186
- catch (error) {
187
- client.send({
188
- type: 'reply',
189
- id: call.id,
190
- error: error instanceof Error ? error.message : String(error),
191
- });
192
- }
193
- }
@@ -1,71 +0,0 @@
1
- import { mkdirSync, readFileSync, renameSync, unlinkSync, writeFileSync, } from 'node:fs';
2
- import path from 'node:path';
3
- import { consola } from 'consola';
4
- import { args } from './args.js';
5
- export const home = args.dir;
6
- const lockFile = path.join(home, 'server.pid');
7
- mkdirSync(home, { recursive: true });
8
- lock();
9
- process.on('exit', () => unlinkSync(lockFile));
10
- function lock() {
11
- try {
12
- writeFileSync(lockFile, `${process.pid}\n`, { flag: 'wx' });
13
- return;
14
- }
15
- catch (error) {
16
- if (!hasCode(error, 'EEXIST'))
17
- throw error;
18
- }
19
- let content;
20
- try {
21
- content = readFileSync(lockFile, 'utf8');
22
- }
23
- catch (error) {
24
- if (hasCode(error, 'ENOENT'))
25
- return lock();
26
- throw error;
27
- }
28
- const pid = Number(content);
29
- if (!Number.isInteger(pid) || pid < 1)
30
- throw new Error(`invalid pid ${JSON.stringify(content)} in ${lockFile}`);
31
- if (pid !== process.pid && isRunning(pid)) {
32
- consola.error(`offsite is already running for ${home} (pid ${pid})`);
33
- process.exit(1);
34
- }
35
- unlinkSync(lockFile);
36
- lock();
37
- }
38
- function isRunning(pid) {
39
- try {
40
- process.kill(pid, 0);
41
- return true;
42
- }
43
- catch (error) {
44
- if (hasCode(error, 'ESRCH'))
45
- return false;
46
- if (hasCode(error, 'EPERM'))
47
- return true;
48
- throw error;
49
- }
50
- }
51
- function hasCode(error, code) {
52
- return error instanceof Error && 'code' in error && error.code === code;
53
- }
54
- export function readJson(name) {
55
- try {
56
- return JSON.parse(readFileSync(path.join(home, name), 'utf8'));
57
- }
58
- catch (error) {
59
- if (error.code === 'ENOENT')
60
- return null;
61
- throw error;
62
- }
63
- }
64
- export function writeJson(name, value) {
65
- const file = path.join(home, name);
66
- mkdirSync(home, { recursive: true });
67
- writeFileSync(`${file}.tmp`, `${JSON.stringify(value, null, 2)}\n`, {
68
- mode: 0o600,
69
- });
70
- renameSync(`${file}.tmp`, file);
71
- }