@openchambery/web 2.1.7 → 2.1.8-beta.3
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/dist/assets/{AgentAvatar-CAR4F5Sn.js → AgentAvatar-DTgZob6V.js} +1 -1
- package/dist/assets/{AssistantView-DgjRT4M4.js → AssistantView-CzNcYiVL.js} +3 -3
- package/dist/assets/{DiagramView-Dd_3w4Hk.js → DiagramView-Cmdi3PAV.js} +1 -1
- package/dist/assets/{FadeInOnReveal-CCVddfP5.js → FadeInOnReveal-Dcu_ZfKa.js} +1 -1
- package/dist/assets/{Icon-DDB7S6Vz.js → Icon-BKVaYkO0.js} +1 -1
- package/dist/assets/{ImageLoadingPlaceholder-C6fDEcU1.js → ImageLoadingPlaceholder-CICdqe37.js} +1 -1
- package/dist/assets/{LoadingImage-ByBH-5WW.js → LoadingImage-DC63uLZK.js} +1 -1
- package/dist/assets/MarkdownRenderer-CIapvMEi.js +2 -0
- package/dist/assets/{MarkdownRendererImpl-BXgUthom.js → MarkdownRendererImpl-CuovZBls.js} +1 -1
- package/dist/assets/{MarkstreamRendererImpl-5W9P9U-w.js → MarkstreamRendererImpl-DtQlVw4f.js} +1 -1
- package/dist/assets/{MobileDetailNavigation-Bk6C9i9l.js → MobileDetailNavigation-BcQ1gCG1.js} +1 -1
- package/dist/assets/{MobileShareBridge-B5nF-gT6.js → MobileShareBridge-CZbknYvz.js} +1 -1
- package/dist/assets/MobileTabPageHeader-DjbyneLy.js +2 -0
- package/dist/assets/{MultiRunWindow-CpuFaAyG.js → MultiRunWindow-CsDXEsR_.js} +1 -1
- package/dist/assets/{OnboardingScreen-DINUboLT.js → OnboardingScreen-B8R06QbP.js} +1 -1
- package/dist/assets/{OverlayScrollbar-BkxmoyYl.js → OverlayScrollbar-BrYVChrM.js} +1 -1
- package/dist/assets/{SettingsView--C3eizlJ.js → SettingsView-bWUvVuP2.js} +3 -2
- package/dist/assets/{SettingsWindow-DYUvg92F.js → SettingsWindow-Cs1Z7BAg.js} +1 -1
- package/dist/assets/{TerminalView-BqAariXf.js → TerminalView-Cfa5bIj1.js} +1 -1
- package/dist/assets/{ToolOutputDialog-D6lPUZrN.js → ToolOutputDialog-ChVqyMGX.js} +1 -1
- package/dist/assets/{appThemeRegistry-wWazoyp8.js → appThemeRegistry-CuS2weCQ.js} +1 -1
- package/dist/assets/{button-DymteyMv.js → button-NnBwy1et.js} +1 -1
- package/dist/assets/{collapsible-Dzp5rO0Q.js → collapsible-Divs2HzS.js} +1 -1
- package/dist/assets/{diagram-CQs9px6y.js → diagram-Dw2fVTEr.js} +1 -1
- package/dist/assets/{dialog-DfUeXqdE.js → dialog-thtcgEoi.js} +1 -1
- package/dist/assets/{dropdown-menu.styles-B6YMNOZz.js → dropdown-menu.styles-DG86fojG.js} +1 -1
- package/dist/assets/{es-2YvsazK2.js → es-CyvQWK39.js} +1 -1
- package/dist/assets/{fileMentionTouchSelection-CEIhM6Ov.js → fileMentionTouchSelection-D9YYbFDF.js} +1 -1
- package/dist/assets/{fr-Cy0M48Gw.js → fr-BgKUUIer.js} +1 -1
- package/dist/assets/{gitApi-BP68uLBQ.js → gitApi-q2aVvcM1.js} +1 -1
- package/dist/assets/{input-BvpZiRHI.js → input-BFFtmAyl.js} +1 -1
- package/dist/assets/{insertionBoundaries-BywXllQ9.js → insertionBoundaries-B2M9QiEF.js} +1 -1
- package/dist/assets/{ja-1zLWWJ2R.js → ja-vAsqZ3i2.js} +1 -1
- package/dist/assets/{ko-BLk_5Dhc.js → ko-CjgHIGr_.js} +1 -1
- package/dist/assets/{main-DdyFxokk.js → main-4h6m9pZ0.js} +4 -4
- package/dist/assets/{main-DSY3-ZQZ.js → main-B3grbXe8.js} +2 -2
- package/dist/assets/{markdownHeightCache-MW1NYOaG.js → markdownHeightCache-qy-s2Sd8.js} +1 -1
- package/dist/assets/{mcpQueries-BaQ2_bdm.js → mcpQueries-BD28dy9B.js} +1 -1
- package/dist/assets/{miniChat-B43ASec3.js → miniChat-ChSEmnwp.js} +2 -2
- package/dist/assets/{mobile-DloCio4f.js → mobile-CrKlS4SH.js} +2 -2
- package/dist/assets/{multirun-Blywdd6A.js → multirun-Dhq8Cx1W.js} +1 -1
- package/dist/assets/{pl-BE8MC0XQ.js → pl-CNRmHctC.js} +1 -1
- package/dist/assets/{projectMeta-BwPtPeMh.js → projectMeta-2J4Ull4h.js} +1 -1
- package/dist/assets/{pt-BR-ubhNymyH.js → pt-BR-B4NRHMT2.js} +1 -1
- package/dist/assets/{renderElectronMiniChatApp-DCRctqrx.js → renderElectronMiniChatApp-DsPg8kQs.js} +2 -2
- package/dist/assets/{renderMobileApp-DuFdSBXi.js → renderMobileApp-Zl-L5gSE.js} +4 -4
- package/dist/assets/{runtimeConfig-CqpbN2lM.js → runtimeConfig-GAVzvQGc.js} +1 -1
- package/dist/assets/{runtimeEndpointReset-bWBhgTs_.js → runtimeEndpointReset-DdNzM2Ae.js} +2 -2
- package/dist/assets/{scheduledTaskNavigation-BnKGGUlX.js → scheduledTaskNavigation-DqwoOss-.js} +1 -1
- package/dist/assets/{sessionChangeSummary-BlR9MyHu.js → sessionChangeSummary-CFlwf4sL.js} +1 -1
- package/dist/assets/{sessionLookup-6gcNEZnB.js → sessionLookup-BPCTTSdg.js} +1 -1
- package/dist/assets/{sortable-tabs-strip-CWR8KhJB.js → sortable-tabs-strip-BLrK5Ln9.js} +1 -1
- package/dist/assets/speechSettingsQueries-D4rx8jJk.js +4 -0
- package/dist/assets/{store-n-H5RvRn.js → store-_hKtW1V3.js} +2 -2
- package/dist/assets/{textarea-ClPlugKE.js → textarea-CN-vZS5F.js} +1 -1
- package/dist/assets/{tooltip-D-1Pgmq1.js → tooltip-uzT2SsYJ.js} +1 -1
- package/dist/assets/{uk-BNyyigDo.js → uk-CXna2F44.js} +1 -1
- package/dist/assets/{useAppFontEffects-8UJ5f0dG.js → useAppFontEffects-BlstuBSz.js} +7 -7
- package/dist/assets/{useDesktopWindowControlsLayout-B_hNd3pD.js → useDesktopWindowControlsLayout-BhS1NmBt.js} +1 -1
- package/dist/assets/{useEffectiveDirectory-DISvoVLe.js → useEffectiveDirectory-CiR2SqiL.js} +1 -1
- package/dist/assets/{useMobileNavigationStore-BE_8Q8WJ.js → useMobileNavigationStore-BRqifj9r.js} +7 -7
- package/dist/assets/{useWorkerHighlightedLines-BFygybD8.js → useWorkerHighlightedLines-Jea_E56b.js} +1 -1
- package/dist/assets/{zh-CN-CNWzMPgL.js → zh-CN-C0S7hK8T.js} +1 -1
- package/dist/assets/{zh-TW-DrZ9S1yn.js → zh-TW-CVG-Rqd-.js} +1 -1
- package/dist/index.html +2 -2
- package/dist/mini-chat.html +2 -2
- package/dist/mobile.html +2 -2
- package/package.json +1 -1
- package/server/lib/config-sync/DOCUMENTATION.md +33 -11
- package/server/lib/config-sync/config-sync.test.js +11 -11
- package/server/lib/config-sync/constants.js +0 -3
- package/server/lib/config-sync/contract.js +8 -8
- package/server/lib/config-sync/credentials.js +101 -0
- package/server/lib/config-sync/credentials.test.js +98 -0
- package/server/lib/config-sync/engine.js +17 -11
- package/server/lib/config-sync/index.js +0 -3
- package/server/lib/config-sync/local-backup.js +0 -13
- package/server/lib/config-sync/magpie.js +207 -0
- package/server/lib/config-sync/magpie.test.js +165 -0
- package/server/lib/config-sync/plan.js +32 -37
- package/server/lib/config-sync/receiver.js +28 -25
- package/server/lib/config-sync/routes.js +23 -2
- package/server/lib/config-sync/routes.test.js +64 -5
- package/server/lib/config-sync/scripts.js +2 -30
- package/server/lib/config-sync/selections.js +14 -10
- package/server/lib/opencode/DOCUMENTATION.md +2 -1
- package/server/lib/opencode/auth.d.ts +1 -0
- package/server/lib/opencode/auth.js +1 -1
- package/dist/assets/MarkdownRenderer-YbG78e0Y.js +0 -2
- package/dist/assets/MobileTabPageHeader-D7r6pKco.js +0 -2
- package/dist/assets/speechSettingsQueries-Bp5LgcR7.js +0 -4
|
@@ -2,7 +2,7 @@ import { createConfigSyncReceiver } from './receiver.js';
|
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
4
|
* Register HTTP config-sync receive/download routes for direct (and later relay) hosts.
|
|
5
|
-
* Auth is the global `/api` UI/client-token gate. Selected kinds (including
|
|
5
|
+
* Auth is the global `/api` UI/client-token gate. Selected kinds (including credentials)
|
|
6
6
|
* sync when present in the plan — no extra credential grant checks.
|
|
7
7
|
*
|
|
8
8
|
* @param {import('express').Express} app
|
|
@@ -70,11 +70,32 @@ export const registerConfigSyncRoutes = (app, deps = {}) => {
|
|
|
70
70
|
}
|
|
71
71
|
});
|
|
72
72
|
|
|
73
|
+
app.get('/api/openchamber/config-sync/magpie/inventory', async (_req, res) => {
|
|
74
|
+
try { res.json({ magpie: await receiver.magpieInventory() }); }
|
|
75
|
+
catch (error) { sendError(res, error); }
|
|
76
|
+
});
|
|
77
|
+
|
|
78
|
+
app.put('/api/openchamber/config-sync/magpie', async (req, res) => {
|
|
79
|
+
try { res.json(await receiver.importMagpie(req)); }
|
|
80
|
+
catch (error) { sendError(res, error); }
|
|
81
|
+
});
|
|
82
|
+
|
|
83
|
+
app.get('/api/openchamber/config-sync/credentials/inventory', async (_req, res) => {
|
|
84
|
+
try { res.json({ providerCredentials: await receiver.credentialInventory() }); }
|
|
85
|
+
catch (error) { sendError(res, error); }
|
|
86
|
+
});
|
|
87
|
+
|
|
88
|
+
app.put('/api/openchamber/config-sync/credentials', async (req, res) => {
|
|
89
|
+
try { res.json(await receiver.importCredentials(req)); }
|
|
90
|
+
catch (error) { sendError(res, error); }
|
|
91
|
+
});
|
|
92
|
+
|
|
73
93
|
app.get('/api/openchamber/config-sync/download/:kind', async (req, res) => {
|
|
74
94
|
try {
|
|
75
95
|
const kind = String(req.params.kind || '').trim();
|
|
76
96
|
const buffer = await receiver.download({ kind });
|
|
77
|
-
res.setHeader('Content-Type', 'application/gzip');
|
|
97
|
+
res.setHeader('Content-Type', kind === 'credentials' || kind === 'magpie' ? 'application/octet-stream' : 'application/gzip');
|
|
98
|
+
res.setHeader('Cache-Control', 'no-store');
|
|
78
99
|
res.setHeader('Content-Length', String(buffer.byteLength));
|
|
79
100
|
res.send(buffer);
|
|
80
101
|
} catch (error) {
|
|
@@ -27,7 +27,7 @@ afterEach(async () => {
|
|
|
27
27
|
}
|
|
28
28
|
});
|
|
29
29
|
|
|
30
|
-
const createApp = async () => {
|
|
30
|
+
const createApp = async (credentials, magpie) => {
|
|
31
31
|
const home = await makeTempDir();
|
|
32
32
|
const configDir = path.join(home, '.config', 'opencode');
|
|
33
33
|
await fsp.mkdir(configDir, { recursive: true });
|
|
@@ -36,6 +36,8 @@ const createApp = async () => {
|
|
|
36
36
|
|
|
37
37
|
const receiver = createConfigSyncReceiver({
|
|
38
38
|
homedir: () => home,
|
|
39
|
+
...(credentials ? { credentials } : {}),
|
|
40
|
+
...(magpie ? { magpie } : {}),
|
|
39
41
|
});
|
|
40
42
|
|
|
41
43
|
const app = express();
|
|
@@ -44,6 +46,63 @@ const createApp = async () => {
|
|
|
44
46
|
};
|
|
45
47
|
|
|
46
48
|
describe('config-sync HTTP routes', () => {
|
|
49
|
+
it('discovers Magpie without import and requires a selected transfer before finalizing', async () => {
|
|
50
|
+
const payload = Buffer.from('fixture-magpie-payload');
|
|
51
|
+
const received = [];
|
|
52
|
+
const { app } = await createApp(undefined, {
|
|
53
|
+
inventory: async () => ({ available: true, installed: false }),
|
|
54
|
+
download: async () => payload,
|
|
55
|
+
import: async (buffer) => { received.push(buffer); return { ok: true, magpieWarnings: ['sign_in_required'] }; },
|
|
56
|
+
});
|
|
57
|
+
const probe = await request(app).post('/api/openchamber/config-sync/probe').send({ plan: {} });
|
|
58
|
+
expect(probe.body.inventory.magpie).toEqual({ available: true, installed: false });
|
|
59
|
+
expect(received).toEqual([]);
|
|
60
|
+
const download = await request(app).get('/api/openchamber/config-sync/download/magpie').expect(200);
|
|
61
|
+
expect(download.headers['cache-control']).toBe('no-store');
|
|
62
|
+
expect(download.body).toEqual(payload);
|
|
63
|
+
await request(app).put('/api/openchamber/config-sync/magpie')
|
|
64
|
+
.set('Content-Type', 'application/octet-stream').send(payload).expect(200);
|
|
65
|
+
const plan = { files: [], directories: [], deletes: [], magpie: { bytes: 0 } };
|
|
66
|
+
await request(app).post('/api/openchamber/config-sync/prepare').send({ plan, syncRunId: 'magpie-run' }).expect(200);
|
|
67
|
+
await request(app).post('/api/openchamber/config-sync/finalize').send({ syncRunId: 'magpie-run' }).expect(500);
|
|
68
|
+
await request(app).put('/api/openchamber/config-sync/put/magpie?syncRunId=magpie-run')
|
|
69
|
+
.set('Content-Type', 'application/octet-stream').send(payload).expect(200);
|
|
70
|
+
const receipt = await request(app).post('/api/openchamber/config-sync/finalize').send({ syncRunId: 'magpie-run' }).expect(200);
|
|
71
|
+
expect(receipt.body.magpieWarnings).toEqual(['sign_in_required']);
|
|
72
|
+
expect(received).toEqual([payload, payload]);
|
|
73
|
+
});
|
|
74
|
+
|
|
75
|
+
it('transfers credential bytes through HTTP without putting values in inventory or filesystem backups', async () => {
|
|
76
|
+
const payload = Buffer.from(JSON.stringify({ format: 'opencode-credentials-v1', entries: [{ fixture: 'private-value' }] }));
|
|
77
|
+
const received = [];
|
|
78
|
+
const { app, home } = await createApp({
|
|
79
|
+
inventory: async () => ({ bytes: payload.length }),
|
|
80
|
+
download: async () => payload,
|
|
81
|
+
import: async (buffer) => { received.push(buffer); return { ok: true }; },
|
|
82
|
+
});
|
|
83
|
+
const plan = { direction: 'push', files: [], directories: [], deletes: [], providerCredentials: { bytes: payload.length } };
|
|
84
|
+
const inventory = await request(app).get('/api/openchamber/config-sync/credentials/inventory');
|
|
85
|
+
expect(inventory.body).toEqual({ providerCredentials: { bytes: payload.length } });
|
|
86
|
+
const download = await request(app).get('/api/openchamber/config-sync/download/credentials');
|
|
87
|
+
expect(download.headers['cache-control']).toBe('no-store');
|
|
88
|
+
expect(download.body).toEqual(payload);
|
|
89
|
+
await request(app).post('/api/openchamber/config-sync/prepare').send({ plan, syncRunId: 'credential-run' }).expect(200);
|
|
90
|
+
await request(app).post('/api/openchamber/config-sync/finalize').send({ syncRunId: 'credential-run' }).expect(500);
|
|
91
|
+
await request(app).put('/api/openchamber/config-sync/put/credentials?syncRunId=credential-run')
|
|
92
|
+
.set('Content-Type', 'application/octet-stream').send(download.body).expect(200);
|
|
93
|
+
await request(app).post('/api/openchamber/config-sync/finalize').send({ syncRunId: 'credential-run' }).expect(200);
|
|
94
|
+
await request(app).put('/api/openchamber/config-sync/credentials')
|
|
95
|
+
.set('Content-Type', 'application/octet-stream').send(payload).expect(200);
|
|
96
|
+
expect(received).toEqual([payload, payload]);
|
|
97
|
+
await expect(fsp.stat(path.join(home, '.openchamber.sync-backup-auth'))).rejects.toThrow();
|
|
98
|
+
await expect(fsp.stat(path.join(home, '.local', 'share', 'opencode', 'auth.json'))).rejects.toThrow();
|
|
99
|
+
await request(app).post('/api/openchamber/config-sync/prepare')
|
|
100
|
+
.send({ plan: { ...plan, providerCredentials: null }, syncRunId: 'unselected' }).expect(200);
|
|
101
|
+
await request(app).put('/api/openchamber/config-sync/put/credentials?syncRunId=unselected')
|
|
102
|
+
.set('Content-Type', 'application/octet-stream').send(payload).expect(500);
|
|
103
|
+
expect(received).toHaveLength(2);
|
|
104
|
+
});
|
|
105
|
+
|
|
47
106
|
it.each(['http-config', 'http-agents', 'local-pack', 'ssh-config', 'ssh-agents'])(
|
|
48
107
|
'%s archive excludes inventory-skipped files, including inside followed symlinks',
|
|
49
108
|
async (transport) => {
|
|
@@ -91,7 +150,7 @@ describe('config-sync HTTP routes', () => {
|
|
|
91
150
|
directories: [],
|
|
92
151
|
deletes: ['config.json', 'opencode.json'],
|
|
93
152
|
agentsRoot: null,
|
|
94
|
-
|
|
153
|
+
providerCredentials: null,
|
|
95
154
|
totalBytes: 3,
|
|
96
155
|
};
|
|
97
156
|
|
|
@@ -124,7 +183,7 @@ describe('config-sync HTTP routes', () => {
|
|
|
124
183
|
directories: [],
|
|
125
184
|
deletes: [],
|
|
126
185
|
agentsRoot: null,
|
|
127
|
-
|
|
186
|
+
providerCredentials: null,
|
|
128
187
|
totalBytes: 2,
|
|
129
188
|
};
|
|
130
189
|
const first = await request(app).post('/api/openchamber/config-sync/prepare').send({ plan, syncRunId: 'run-a' });
|
|
@@ -143,7 +202,7 @@ describe('config-sync HTTP routes', () => {
|
|
|
143
202
|
directories: [],
|
|
144
203
|
deletes: [],
|
|
145
204
|
agentsRoot: null,
|
|
146
|
-
|
|
205
|
+
providerCredentials: null,
|
|
147
206
|
totalBytes: 0,
|
|
148
207
|
};
|
|
149
208
|
await request(app).post('/api/openchamber/config-sync/prepare').send({ plan, syncRunId: 'run-stream' });
|
|
@@ -151,7 +210,7 @@ describe('config-sync HTTP routes', () => {
|
|
|
151
210
|
// Tiny invalid tar still proves chunk aggregation reached extract.
|
|
152
211
|
await expect(receiver.put({
|
|
153
212
|
syncRunId: 'run-stream',
|
|
154
|
-
kind: '
|
|
213
|
+
kind: 'config',
|
|
155
214
|
stream: Readable.from([Buffer.from('aa'), Buffer.from('bb')]),
|
|
156
215
|
})).rejects.toThrow(/tar|failed|Local tar extract/i);
|
|
157
216
|
|
|
@@ -3,8 +3,6 @@ import path from 'node:path';
|
|
|
3
3
|
import {
|
|
4
4
|
OPENCODE_AGENTS_ROOT_PROBE_MARKER,
|
|
5
5
|
OPENCODE_AGENTS_SYNC_BACKUP_DIR,
|
|
6
|
-
OPENCODE_AUTH_FILE_PROBE_MARKER,
|
|
7
|
-
OPENCODE_AUTH_SYNC_BACKUP_DIR,
|
|
8
6
|
OPENCODE_CONFIG_SYNC_ALLOWLIST,
|
|
9
7
|
OPENCODE_CONFIG_SYNC_BACKUP_DIR,
|
|
10
8
|
OPENCODE_CONFIG_SYNC_BACKUP_GENERATIONS,
|
|
@@ -60,7 +58,7 @@ const generationalBackupSetupLines = ({ backupVar, runVar, quotedRunId, generati
|
|
|
60
58
|
* {@link OPENCODE_CONFIG_SYNC_BACKUP_GENERATIONS} are pruned; prepare no longer
|
|
61
59
|
* `rm -rf`s the entire backup root at start.
|
|
62
60
|
*
|
|
63
|
-
* @param {{ files: { path: string }[], directories: { path: string }[], deletes: string[], agentsRoot?: { fileCount: number, bytes: number } | null
|
|
61
|
+
* @param {{ files: { path: string }[], directories: { path: string }[], deletes: string[], agentsRoot?: { fileCount: number, bytes: number } | null }} plan
|
|
64
62
|
* @param {{ syncRunId: string, generations?: number }} options
|
|
65
63
|
* @returns {string}
|
|
66
64
|
*/
|
|
@@ -134,19 +132,6 @@ export const buildRemoteSyncPrepareScript = (plan, options) => {
|
|
|
134
132
|
lines.push('rm -rf -- "$HOME/.agents"');
|
|
135
133
|
}
|
|
136
134
|
|
|
137
|
-
if (plan?.authFile) {
|
|
138
|
-
lines.push(`AUTH_BK="$HOME/${OPENCODE_AUTH_SYNC_BACKUP_DIR}"`);
|
|
139
|
-
lines.push(...generationalBackupSetupLines({
|
|
140
|
-
backupVar: 'AUTH_BK',
|
|
141
|
-
runVar: 'AUTH_RUN_BK',
|
|
142
|
-
quotedRunId,
|
|
143
|
-
generations,
|
|
144
|
-
}));
|
|
145
|
-
lines.push('if [ -e "$HOME/.local/share/opencode/auth.json" ]; then');
|
|
146
|
-
lines.push(' cp -a "$HOME/.local/share/opencode/auth.json" "$AUTH_RUN_BK/auth.json"');
|
|
147
|
-
lines.push('fi');
|
|
148
|
-
}
|
|
149
|
-
|
|
150
135
|
lines.push("printf 'SYNC_READY\\n'");
|
|
151
136
|
return lines.join('\n');
|
|
152
137
|
};
|
|
@@ -164,9 +149,6 @@ export const buildRemoteSyncProbeScript = (uniqueProbePaths) => {
|
|
|
164
149
|
lines.push(
|
|
165
150
|
`[ -e "$HOME/.agents" ] && printf '%s\\n' ${shellQuote(OPENCODE_AGENTS_ROOT_PROBE_MARKER)}`,
|
|
166
151
|
);
|
|
167
|
-
lines.push(
|
|
168
|
-
`[ -e "$HOME/.local/share/opencode/auth.json" ] && printf '%s\\n' ${shellQuote(OPENCODE_AUTH_FILE_PROBE_MARKER)}`,
|
|
169
|
-
);
|
|
170
152
|
lines.push('exit 0');
|
|
171
153
|
return lines.join('\n');
|
|
172
154
|
};
|
|
@@ -228,14 +210,9 @@ export const buildRemoteSyncInventoryScript = () => {
|
|
|
228
210
|
lines.push(" ABYTES=\"$(find \"$HOME/.agents\" -type f ! -path '*/node_modules/*' ! -path '*/.venv-asc/*' ! -name '*.backup' -exec wc -c {} + 2>/dev/null | awk 'END{print $1+0}')\"");
|
|
229
211
|
lines.push(' AGENTS="{\\"fileCount\\":$ACOUNT,\\"bytes\\":$ABYTES}"');
|
|
230
212
|
lines.push('fi');
|
|
231
|
-
lines.push('AUTH="null"');
|
|
232
|
-
lines.push('if [ -f "$HOME/.local/share/opencode/auth.json" ]; then');
|
|
233
|
-
lines.push(' AUBYTES="$(wc -c < "$HOME/.local/share/opencode/auth.json" | tr -d \' \')"');
|
|
234
|
-
lines.push(' AUTH="{\\"bytes\\":$AUBYTES}"');
|
|
235
|
-
lines.push('fi');
|
|
236
213
|
lines.push('FILES="${FILES%,}"');
|
|
237
214
|
lines.push('DIRS="${DIRS%,}"');
|
|
238
|
-
lines.push('printf \'SYNC_INVENTORY={"files":[%s],"directories":[%s],"agentsRoot":%s
|
|
215
|
+
lines.push('printf \'SYNC_INVENTORY={"files":[%s],"directories":[%s],"agentsRoot":%s}\\n\' "$FILES" "$DIRS" "$AGENTS"');
|
|
239
216
|
lines.push('exit 0');
|
|
240
217
|
return lines.join('\n');
|
|
241
218
|
};
|
|
@@ -265,9 +242,4 @@ export const buildRemoteAgentsTarScript = () => [
|
|
|
265
242
|
`cd "$HOME" && tar ${OPENCODE_CONFIG_SYNC_TAR_EXCLUDES.map(shellQuote).join(' ')} -h -czf - .agents`,
|
|
266
243
|
].join('\n');
|
|
267
244
|
|
|
268
|
-
export const buildRemoteAuthTarScript = () => [
|
|
269
|
-
'set -e',
|
|
270
|
-
'cd "$HOME/.local/share/opencode" && tar -h -czf - auth.json',
|
|
271
|
-
].join('\n');
|
|
272
|
-
|
|
273
245
|
export { shellQuote };
|
|
@@ -6,13 +6,14 @@ import { OPENCODE_CONFIG_SYNC_ALLOWLIST } from './constants.js';
|
|
|
6
6
|
* singleFiles: boolean[],
|
|
7
7
|
* directories: boolean[],
|
|
8
8
|
* agentsRoot: boolean,
|
|
9
|
-
*
|
|
9
|
+
* providerCredentials: boolean,
|
|
10
|
+
* magpie?: boolean,
|
|
10
11
|
* }} SyncSelections
|
|
11
12
|
*/
|
|
12
13
|
|
|
13
14
|
/**
|
|
14
|
-
* Default: everything selected except
|
|
15
|
-
* @param {{
|
|
15
|
+
* Default: everything selected except providerCredentials (credentials stay opt-in).
|
|
16
|
+
* @param {{ includeProviderCredentials?: boolean }} [options]
|
|
16
17
|
* @returns {SyncSelections}
|
|
17
18
|
*/
|
|
18
19
|
export const buildDefaultSyncSelections = (options = {}) => ({
|
|
@@ -20,13 +21,14 @@ export const buildDefaultSyncSelections = (options = {}) => ({
|
|
|
20
21
|
singleFiles: OPENCODE_CONFIG_SYNC_ALLOWLIST.singleFiles.map(() => true),
|
|
21
22
|
directories: OPENCODE_CONFIG_SYNC_ALLOWLIST.directories.map(() => true),
|
|
22
23
|
agentsRoot: true,
|
|
23
|
-
|
|
24
|
+
providerCredentials: options.includeProviderCredentials === true,
|
|
25
|
+
magpie: false,
|
|
24
26
|
});
|
|
25
27
|
|
|
26
28
|
/**
|
|
27
29
|
* Normalize a partial selections object against the allowlist shape.
|
|
28
30
|
* @param {Partial<SyncSelections> | null | undefined} raw
|
|
29
|
-
* @param {{
|
|
31
|
+
* @param {{ includeProviderCredentials?: boolean }} [options]
|
|
30
32
|
* @returns {SyncSelections}
|
|
31
33
|
*/
|
|
32
34
|
export const normalizeSyncSelections = (raw, options = {}) => {
|
|
@@ -48,7 +50,8 @@ export const normalizeSyncSelections = (raw, options = {}) => {
|
|
|
48
50
|
singleFiles,
|
|
49
51
|
directories,
|
|
50
52
|
agentsRoot: raw.agentsRoot !== false,
|
|
51
|
-
|
|
53
|
+
providerCredentials: raw.providerCredentials === true,
|
|
54
|
+
magpie: raw.magpie === true,
|
|
52
55
|
};
|
|
53
56
|
};
|
|
54
57
|
|
|
@@ -59,7 +62,7 @@ export const normalizeSyncSelections = (raw, options = {}) => {
|
|
|
59
62
|
* @param {SyncSelections} selections
|
|
60
63
|
*/
|
|
61
64
|
export const filterPlanBySelections = (plan, selections) => {
|
|
62
|
-
const selected = normalizeSyncSelections(selections, {
|
|
65
|
+
const selected = normalizeSyncSelections(selections, { includeProviderCredentials: selections?.providerCredentials === true });
|
|
63
66
|
const selectedFileNames = new Set();
|
|
64
67
|
const selectedDeleteNames = new Set();
|
|
65
68
|
|
|
@@ -91,13 +94,13 @@ export const filterPlanBySelections = (plan, selections) => {
|
|
|
91
94
|
const directories = (Array.isArray(plan?.directories) ? plan.directories : []).filter((entry) => selectedDirNames.has(entry.path));
|
|
92
95
|
const deletes = (Array.isArray(plan?.deletes) ? plan.deletes : []).filter((name) => selectedDeleteNames.has(name) || selectedDirLegacy.has(name));
|
|
93
96
|
const agentsRoot = selected.agentsRoot ? (plan?.agentsRoot ?? null) : null;
|
|
94
|
-
const
|
|
97
|
+
const providerCredentials = selected.providerCredentials ? (plan?.providerCredentials ?? null) : null;
|
|
95
98
|
|
|
96
99
|
let totalBytes = 0;
|
|
97
100
|
for (const entry of files) totalBytes += Number(entry.bytes) || 0;
|
|
98
101
|
for (const entry of directories) totalBytes += Number(entry.bytes) || 0;
|
|
99
102
|
if (agentsRoot) totalBytes += Number(agentsRoot.bytes) || 0;
|
|
100
|
-
if (
|
|
103
|
+
if (providerCredentials) totalBytes += Number(providerCredentials.bytes) || 0;
|
|
101
104
|
|
|
102
105
|
return {
|
|
103
106
|
...plan,
|
|
@@ -105,7 +108,8 @@ export const filterPlanBySelections = (plan, selections) => {
|
|
|
105
108
|
directories,
|
|
106
109
|
deletes,
|
|
107
110
|
agentsRoot,
|
|
108
|
-
|
|
111
|
+
providerCredentials,
|
|
112
|
+
magpie: selected.magpie && plan?.magpieAvailable ? { bytes: 0 } : null,
|
|
109
113
|
totalBytes,
|
|
110
114
|
selections: selected,
|
|
111
115
|
};
|
|
@@ -73,11 +73,12 @@ This module provides OpenCode server integration utilities for the web server ru
|
|
|
73
73
|
|
|
74
74
|
## Public exports (auth.js)
|
|
75
75
|
- `configureOpenCodeCredentials(resolveClient)`: host composition injects a call-time SDK client resolver; `null` detaches it. Web/Electron share server wiring; VS Code wires its manager in extension activation. Mobile clients use their host.
|
|
76
|
+
- `currentClient()`: trusted host-only client resolver used by config-sync to retain full V2 credential account records instead of the active-account quota projection.
|
|
76
77
|
- `openCodeCredentialSource({ buildOpenCodeUrl, getOpenCodeAuthHeaders })`: resolves the current endpoint/auth at each read rather than capturing a previous runtime.
|
|
77
78
|
- `readOpenCodeCredentials()`: async SDK `credential.list()` read of the running service; validates entries and projects only active accounts into the quota/TTS credential shape. OAuth `metadata.accountID` becomes `accountId`. No local `auth.json`, local environment, or local provider-config fallback; external service environment-only keys are not exposed by the credential API.
|
|
78
79
|
- `getProviderAuth(providerId)`: async selected stored credential or authoritative `null`; network/auth/schema failures reject with a sanitized error, never empty success.
|
|
79
80
|
- `removeProviderAuth(providerId)`: deletes every stored account for that integration through SDK `credential.remove`, preserving unrelated integrations. Partial failure rejects explicitly; retry lists remaining accounts. Auth-only disconnect requires no process restart.
|
|
80
|
-
- Credential values remain host-only. `credential-boundary.js` blocks raw credential list/creation responses (GET/HEAD/POST `/api/credential`, including encoded/trailing-slash forms) in Web proxy and VS Code bridge because v2 replies contain keys. Provider-source responses expose only existence; errors never include upstream credential bodies/headers.
|
|
81
|
+
- Credential values remain host-only outside explicitly selected instance sync. `credential-boundary.js` blocks raw credential list/creation responses (GET/HEAD/POST `/api/credential`, including encoded/trailing-slash forms) in Web proxy and VS Code bridge because v2 replies contain keys. Provider-source responses expose only existence; errors never include upstream credential bodies/headers. The authenticated config-sync routes own explicit V2 credential transfer; previews and run logs contain only metadata.
|
|
81
82
|
|
|
82
83
|
## Public exports (shared.js)
|
|
83
84
|
- `OPENCODE_CONFIG_DIR`, `AGENT_DIR`, `COMMAND_DIR`, `SKILL_DIR`, `CONFIG_FILE`, `CUSTOM_CONFIG_FILE`: Path constants.
|
|
@@ -4,6 +4,7 @@ export type ProviderCredential =
|
|
|
4
4
|
| { type: 'api'; key: string }
|
|
5
5
|
| { type: 'oauth'; access: string; refresh: string; expires: number; accountId?: string; enterpriseUrl?: string };
|
|
6
6
|
export function configureOpenCodeCredentials(resolveClient: (() => OpenCodeClient) | null): void;
|
|
7
|
+
export function currentClient(): OpenCodeClient;
|
|
7
8
|
export function openCodeCredentialSource(deps: {
|
|
8
9
|
buildOpenCodeUrl: (path: string, prefix?: string) => string;
|
|
9
10
|
getOpenCodeAuthHeaders: () => Record<string, string>;
|
|
@@ -1,2 +0,0 @@
|
|
|
1
|
-
const __vite__mapDeps=(i,m=__vite__mapDeps,d=(m.f||(m.f=["assets/MarkstreamRendererImpl-5W9P9U-w.js","assets/rolldown-runtime-hePW80VL.js","assets/vendor-base-ui-CdzJ6My_.js","assets/useUIStore-CDMI_Yzu.js","assets/runtime-switch-3ad3yzM7.js","assets/runtime-auth-C8w0nlKy.js","assets/vendor-zustand-o69pgTEK.js","assets/vendor-react-BP2cRVqX.js","assets/vendor-markstream-react-Bm0cO70Z.js","assets/vendor-aparajita-capacitor-secure-storage-xol_6BsB.js","assets/vendor-markstream-core-Cm34iPLL.js","assets/vendor-floating-ui-dom-BHhLtF5l.js","assets/vendor-floating-ui-core-Co1I1lFV.js","assets/vendor-reactuses-core-BpfIZ1tg.js","assets/vendor-lodash-es-DfLbG5Af.js","assets/vendor-js-cookie-hSOiFTtX.js","assets/button-DymteyMv.js","assets/persistence-B7ORJ371.js","assets/runtime-fetch-QCWYlAx0.js","assets/vendor-pathe-vBmvQE8f.js","assets/vendor-tanstack-query-core-BWz0ose6.js","assets/store-n-H5RvRn.js","assets/vendor-class-variance-authority-BLUaYARZ.js","assets/vendor-tailwind-merge-BicNWLTg.js","assets/useMobileNavigationStore-BE_8Q8WJ.js","assets/platform-CiBU2bCp.js","assets/vendor-opencode-client-MF2GBrFx.js","assets/vendor-tanstack-react-query-CdqCAt40.js","assets/vendor-sonner-ZS8XIOVl.js","assets/useAssistantUIStore-Dlvb7P0q.js","assets/vendor-zod-Dzk5kdUU.js","assets/vendor-fuse.js-DB5wDJbI.js","assets/useThemeSystem-8jhE4Zyk.js","assets/tooltip-D-1Pgmq1.js","assets/image-loading-qNtUCy69.js","assets/fileQueries-BGE5l3Jd.js","assets/useRuntimeAPIs-Cx8S1HLz.js","assets/relay-image-stream-qI2NTXbG.js","assets/image-loading-CObM4tcX.css","assets/url-nbXEti6c.js","assets/useEffectiveDirectory-DISvoVLe.js","assets/LoadingImage-ByBH-5WW.js","assets/ImageLoadingPlaceholder-C6fDEcU1.js","assets/markdownHeightCache-MW1NYOaG.js","assets/dualLimitLru-D8Sphgua.js","assets/MarkdownRendererImpl-BXgUthom.js","assets/vendor-katex-DNVSTX6g.js","assets/markdown-worker-DFNZ3KJ_.js","assets/FadeInOnReveal-CCVddfP5.js","assets/markdownTheme-CV7_0QAL.js","assets/vendor-pierre-diffs-DPBtNDJ5.js","assets/vendor-hast-util-to-html-Bw_SgZ1t.js","assets/vendor-character-entities-legacy-Wut6vMuj.js","assets/vendor-character-entities-html4-DlN_yAFd.js","assets/vendor-ccount-CyGsA0u7.js","assets/vendor-comma-separated-tokens-B9ouxNNS.js","assets/vendor-oniguruma-to-es-CrHzjjSU.js","assets/vendor-oniguruma-parser-D2DIvhSP.js","assets/vendor-diff-Dq7CZNim.js","assets/vendor-lru_map-BMOrLc9L.js","assets/vendor-morphdom-BbKiNDAu.js","assets/vendor-dompurify-CeJNOzik.js","assets/vendor-pele-C1WTNWUm.js","assets/vendor-marked-WVekxjAN.js","assets/vendor-remend-C3cXc-tf.js","assets/MarkstreamRendererImpl-DKhVy3nF.css"])))=>i.map(i=>d[i]);
|
|
2
|
-
import{r as e}from"./rolldown-runtime-hePW80VL.js";import{a as t}from"./vendor-zustand-o69pgTEK.js";import{it as n,rt as r}from"./vendor-base-ui-CdzJ6My_.js";import{n as i}from"./vendor-react-BP2cRVqX.js";import{o as a}from"./vendor-aparajita-capacitor-secure-storage-xol_6BsB.js";import{r as o}from"./button-DymteyMv.js";import{i as s,n as c,t as l}from"./markdownHeightCache-MW1NYOaG.js";var u=i(),d=e(n(),1),f=`openchamber:chunk-import-reload`,p=250,m=3e4,h=[/Importing a module script failed/i,/Failed to fetch dynamically imported module/i,/error loading dynamically imported module/i,/Loading chunk \S+ failed/i,/ChunkLoadError/i];function g(e){if(e instanceof Error)return`${e.name}\n${e.message}\n${e.stack??``}`;if(typeof e==`string`)return e;try{return JSON.stringify(e)}catch{return String(e)}}function _(e){let t=g(e);return h.some(e=>e.test(t))}function v(e){return`2.1.7:${g(e).slice(0,500)}`}function y(e){if(typeof window>`u`)return;let t=Date.now(),n=v(e),r=null;try{let e=window.sessionStorage.getItem(f);if(e)try{r=JSON.parse(e)}catch{r=null}}catch{return}let i=typeof r?.timestamp==`number`?r.timestamp:0;if(!(r?.signature===n&&t-i<m)){try{window.sessionStorage.setItem(f,JSON.stringify({signature:n,timestamp:t}))}catch{return}console.error(`[refresh-debug] chunk-import-reload`,{error:g(e).slice(0,1e3)}),window.setTimeout(()=>{window.location.reload()},0)}}async function b(e,t={}){let n=t.retries??1,r;for(let t=0;t<=n;t+=1)try{return await e()}catch(e){if(r=e,!_(e)||t>=n)break;await new Promise(e=>setTimeout(e,p*(t+1)))}throw _(r)&&y(r),r}var x=e=>(0,d.lazy)(()=>b(e)),S=(e,t)=>{try{let n=t??(typeof localStorage>`u`?null:localStorage);return n?n.getItem(e)===`1`:!1}catch{return!1}},C=(e,t)=>{try{let n=t??(typeof localStorage>`u`?null:localStorage);return!n||n.getItem(e)!==`0`}catch{return!0}},w=(e,t)=>{try{typeof localStorage<`u`&&localStorage.setItem(e,t?`1`:`0`)}catch{}},T=`oc:legend-timeline`,E=e=>S(T,e),D=`oc:markstream-react`,O=e=>C(D,e),k=t(e=>({legendTimelineEnabled:E(),setLegendTimelineEnabled:t=>{w(T,t),e({legendTimelineEnabled:t})},markstreamReactEnabled:O(),setMarkstreamReactEnabled:t=>{w(D,t),e({markstreamReactEnabled:t})}})),A=null,j=()=>(A??=a(()=>import(`./MarkstreamRendererImpl-5W9P9U-w.js`),__vite__mapDeps([0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,65])).catch(e=>{throw A=null,e}),A),M=()=>{j().catch(()=>void 0)},N=null,P=()=>(N??=a(()=>import(`./MarkdownRendererImpl-BXgUthom.js`).then(e=>e.n),__vite__mapDeps([45,1,4,5,18,17,6,2,3,7,19,20,25,26,9,46,13,14,15,16,21,22,23,24,27,28,29,30,31,44,32,34,35,36,37,38,39,47,40,48,49,50,51,52,53,54,55,56,57,58,59,43,60,61,62,63,64])).catch(e=>{throw N=null,e}),N),F=()=>{P().catch(()=>void 0),O()&&M()},I=class extends d.Component{state={hasError:!1};static getDerivedStateFromError(){return{hasError:!0}}componentDidCatch(e){console.warn(`[markstream-react] falling back to the current Markdown renderer`,e)}render(){return this.state.hasError?this.props.fallback:this.props.children}},L=d.createContext(!0),R=()=>d.useContext(L),z=r(),B=x(()=>P().then(e=>({default:e.MarkdownRenderer}))),V=x(()=>j().then(e=>({default:e.MarkstreamRenderer}))),H=x(()=>P().then(e=>({default:e.SimpleMarkdownRenderer}))),U=e=>e===`tool`?`markdown-content markdown-tool`:e===`reasoning`?`markdown-content markdown-reasoning`:`markdown-content leading-relaxed`,W=e=>{let t=(0,u.c)(15),n=k(q),r=typeof e.content==`string`?e.content:``,i=typeof e.variant==`string`?e.variant:`assistant`,a;t[0]!==r||t[1]!==n||t[2]!==e.reserveMeasuredHeight||t[3]!==i?(a=e.reserveMeasuredHeight?c(l(r,n?`markstream:${i}`:i)):void 0,t[0]=r,t[1]=n,t[2]=e.reserveMeasuredHeight,t[3]=i,t[4]=a):a=t[4];let d=a,f;t[5]!==e.className||t[6]!==e.variant?(f=o(`relative break-words w-full min-w-0`,U(e.variant),typeof e.className==`string`?e.className:void 0),t[5]=e.className,t[6]=e.variant,t[7]=f):f=t[7];let p;t[8]!==r||t[9]!==e.animated||t[10]!==d?(p=(0,z.jsx)(s,{animated:e.animated,content:r,reservedHeight:d}),t[8]=r,t[9]=e.animated,t[10]=d,t[11]=p):p=t[11];let m;return t[12]!==f||t[13]!==p?(m=(0,z.jsx)(`div`,{className:f,"aria-busy":`true`,"data-markdown-hydration":`deferred`,"data-markdown-ready":`false`,children:p}),t[12]=f,t[13]=p,t[14]=m):m=t[14],m},G=e=>{let t=(0,u.c)(9),n=R(),r=k(J);if(!n&&e.isStreaming!==!0){let n;return t[0]===e?n=t[1]:(n=(0,z.jsx)(W,{...e,animated:!1,reserveMeasuredHeight:!0}),t[0]=e,t[1]=n),n}let i;t[2]===e?i=t[3]:(i=(0,z.jsx)(d.Suspense,{fallback:(0,z.jsx)(W,{...e,reserveMeasuredHeight:!0}),children:(0,z.jsx)(B,{...e})}),t[2]=e,t[3]=i);let a=i;if(!r)return a;let o;t[4]===e?o=t[5]:(o=(0,z.jsx)(d.Suspense,{fallback:(0,z.jsx)(W,{...e,reserveMeasuredHeight:!0}),children:(0,z.jsx)(V,{...e})}),t[4]=e,t[5]=o);let s;return t[6]!==a||t[7]!==o?(s=(0,z.jsx)(I,{fallback:a,children:o}),t[6]=a,t[7]=o,t[8]=s):s=t[8],s},K=e=>{let t=(0,u.c)(4);if(!R()){let n;return t[0]===e?n=t[1]:(n=(0,z.jsx)(W,{...e,animated:!1}),t[0]=e,t[1]=n),n}let n;return t[2]===e?n=t[3]:(n=(0,z.jsx)(d.Suspense,{fallback:(0,z.jsx)(W,{...e}),children:(0,z.jsx)(H,{...e})}),t[2]=e,t[3]=n),n};function q(e){return e.markstreamReactEnabled}function J(e){return e.markstreamReactEnabled}export{k as a,F as i,K as n,x as o,L as r,G as t};
|