dot-studio 0.0.1 → 0.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +20 -200
- package/client/assets/ActFrame-BYOBkLYW.js +1 -0
- package/client/assets/ActFrame-C_WEt6bv.css +1 -0
- package/client/assets/ActInspectorPanel-C3VlS7tB.js +1 -0
- package/client/assets/ActInspectorPanel-CE6s6GYv.css +1 -0
- package/client/assets/AssistantChat-BOyW0K79.js +1 -0
- package/client/assets/AssistantChat-DoVmHvMJ.css +1 -0
- package/client/assets/CanvasTerminalFrame-BC-79q9U.css +1 -0
- package/client/assets/CanvasTerminalFrame-DxKbexK6.js +4 -0
- package/client/assets/CanvasTrackingFrame-DumxhNwg.js +1 -0
- package/client/assets/CanvasTrackingFrame-G4rRrfne.css +1 -0
- package/client/assets/CanvasWindowFrame-ziJeVfHG.js +1 -0
- package/client/assets/DanceBundleEditorFrame-CH8VDUMK.js +1 -0
- package/client/assets/DanceBundleEditorFrame-DaLqMflT.css +1 -0
- package/client/assets/MarkdownEditorFrame-DVecIZpZ.css +1 -0
- package/client/assets/MarkdownEditorFrame-Dwpgs2GX.js +2 -0
- package/client/assets/MarkdownRenderer-Cz8A4AgP.js +1 -0
- package/client/assets/PublishModal-DUlHz0fT.js +1 -0
- package/client/assets/TodoDock-DcVf7zQG.js +1 -0
- package/client/assets/WorkspaceToolbar-CXYi_sMD.js +2 -0
- package/client/assets/WorkspaceToolbar-CiQvVocC.css +1 -0
- package/client/assets/chat-message-visibility-YwJ-AQno.js +11 -0
- package/client/assets/dnd-vendor-CIAZE2P2.js +5 -0
- package/client/assets/flow-vendor-BZV40eAE.css +1 -0
- package/client/assets/flow-vendor-C868rU-6.js +23 -0
- package/client/assets/icon-vendor-I2JVIi1s.js +501 -0
- package/client/assets/index-BMY4hrBP.js +3 -0
- package/client/assets/index-C-vnj9y3.js +1 -0
- package/client/assets/index-C9HTqfZw.css +1 -0
- package/client/assets/index-CWrv6O3o.js +64 -0
- package/client/assets/index-DMS12-Q2.js +8 -0
- package/client/assets/index-Dn7t_Y7G.js +1 -0
- package/client/assets/index-p-wk7iGH.css +1 -0
- package/client/assets/markdown-vendor-BSTcku12.css +10 -0
- package/client/assets/markdown-vendor-DnTJ9hmR.js +35 -0
- package/client/assets/participant-labels-Cf3qP3GB.js +1 -0
- package/client/assets/queries-Dm1jEHfc.js +1 -0
- package/client/assets/query-vendor-_taqgrbn.js +1 -0
- package/client/assets/react-vendor-DzpMUNDT.js +49 -0
- package/client/assets/settings-utils-l7KCS3Ev.js +1 -0
- package/client/assets/terminal-vendor-6GBZ9nXN.css +32 -0
- package/client/assets/terminal-vendor-D0xRnmbI.js +112 -0
- package/client/index.html +13 -3
- package/dist/cli.js +25 -3
- package/dist/server/app.js +72 -0
- package/dist/server/index.js +2 -62
- package/dist/server/lib/act-session-policy.js +31 -0
- package/dist/server/lib/chat-session.js +101 -0
- package/dist/server/lib/config.js +18 -4
- package/dist/server/lib/dot-authoring.js +171 -102
- package/dist/server/lib/dot-loader.js +9 -8
- package/dist/server/lib/dot-login.js +8 -190
- package/dist/server/lib/dot-source.js +11 -0
- package/dist/server/lib/model-catalog.js +74 -15
- package/dist/server/lib/opencode-auth.js +4 -1
- package/dist/server/lib/opencode-errors.js +70 -38
- package/dist/server/lib/opencode-sidecar.js +5 -2
- package/dist/server/lib/project-config.js +8 -0
- package/dist/server/lib/runtime-tools.js +46 -8
- package/dist/server/lib/safe-mode.js +410 -0
- package/dist/server/lib/session-execution.js +81 -0
- package/dist/server/lib/sse.js +22 -0
- package/dist/server/routes/act-runtime-threads.js +156 -0
- package/dist/server/routes/act-runtime-tools.js +157 -0
- package/dist/server/routes/act-runtime.js +7 -0
- package/dist/server/routes/adapter.js +32 -0
- package/dist/server/routes/assets-collection.js +16 -0
- package/dist/server/routes/assets-detail.js +38 -0
- package/dist/server/routes/assets.js +4 -158
- package/dist/server/routes/chat-messages.js +104 -0
- package/dist/server/routes/chat-sessions.js +104 -0
- package/dist/server/routes/chat-stream.js +15 -0
- package/dist/server/routes/chat.js +6 -353
- package/dist/server/routes/compile.js +5 -91
- package/dist/server/routes/dot-assets.js +77 -0
- package/dist/server/routes/dot-core.js +62 -0
- package/dist/server/routes/dot-performer.js +80 -0
- package/dist/server/routes/dot.js +6 -267
- package/dist/server/routes/drafts-collection.js +40 -0
- package/dist/server/routes/drafts-dance-bundle.js +113 -0
- package/dist/server/routes/drafts-item.js +86 -0
- package/dist/server/routes/drafts.js +9 -0
- package/dist/server/routes/health.js +18 -33
- package/dist/server/routes/opencode-core.js +120 -0
- package/dist/server/routes/opencode-file.js +67 -0
- package/dist/server/routes/opencode-mcp.js +74 -0
- package/dist/server/routes/opencode-provider.js +41 -0
- package/dist/server/routes/opencode.js +8 -418
- package/dist/server/routes/route-errors.js +10 -0
- package/dist/server/routes/safe-actions.js +60 -0
- package/dist/server/routes/safe-summary.js +20 -0
- package/dist/server/routes/safe.js +7 -0
- package/dist/server/routes/workspaces.js +47 -0
- package/dist/server/services/act-runtime/act-context-builder.js +81 -0
- package/dist/server/services/act-runtime/act-runtime-service.js +313 -0
- package/dist/server/services/act-runtime/act-runtime-utils.js +10 -0
- package/dist/server/services/act-runtime/act-tool-projection.js +26 -0
- package/dist/server/services/act-runtime/act-tools.js +151 -0
- package/dist/server/services/act-runtime/board-persistence.js +38 -0
- package/dist/server/services/act-runtime/event-logger.js +73 -0
- package/dist/server/services/act-runtime/event-router.js +102 -0
- package/dist/server/services/act-runtime/mailbox.js +149 -0
- package/dist/server/services/act-runtime/safety-guard.js +162 -0
- package/dist/server/services/act-runtime/session-queue.js +114 -0
- package/dist/server/services/act-runtime/thread-manager.js +351 -0
- package/dist/server/services/act-runtime/wake-cascade.js +306 -0
- package/dist/server/services/act-runtime/wake-evaluator.js +43 -0
- package/dist/server/services/act-runtime/wake-performer-resolver.js +68 -0
- package/dist/server/services/act-runtime/wake-prompt-builder.js +77 -0
- package/dist/server/services/adapter-view-service.js +6 -0
- package/dist/server/services/asset-service.js +366 -0
- package/dist/server/services/chat-event-stream-service.js +157 -0
- package/dist/server/services/chat-service.js +207 -0
- package/dist/server/services/chat-session-service.js +203 -0
- package/dist/server/services/compile-service.js +4 -0
- package/dist/server/services/dance-bundle-service.js +222 -0
- package/dist/server/services/dot-add-service.js +59 -0
- package/dist/server/services/dot-service.js +178 -0
- package/dist/server/services/draft-service.js +367 -0
- package/dist/server/services/opencode-projection/dance-compiler.js +164 -0
- package/dist/server/services/opencode-projection/performer-compiler.js +195 -0
- package/dist/server/services/opencode-projection/preview-service.js +31 -0
- package/dist/server/services/opencode-projection/projection-manifest.js +98 -0
- package/dist/server/services/opencode-projection/stage-projection-service.js +188 -0
- package/dist/server/services/opencode-service.js +338 -0
- package/dist/server/services/safe-service.js +33 -0
- package/dist/server/services/studio-assistant/assistant-service.js +172 -0
- package/dist/server/services/studio-service.js +69 -0
- package/dist/server/services/workspace-service.js +224 -0
- package/dist/server/terminal.js +57 -11
- package/dist/shared/act-types.js +4 -0
- package/dist/shared/adapter-view.js +1 -0
- package/dist/shared/asset-contracts.js +1 -0
- package/dist/shared/assistant-actions.js +1 -0
- package/dist/shared/chat-contracts.js +1 -0
- package/dist/shared/dot-contracts.js +1 -0
- package/dist/shared/dot-types.js +4 -0
- package/dist/shared/draft-contracts.js +2 -0
- package/dist/shared/model-types.js +2 -0
- package/dist/shared/performer-mcp-portability.js +10 -0
- package/dist/shared/safe-mode.js +1 -0
- package/dist/shared/session-metadata.js +4 -3
- package/package.json +6 -4
- package/client/assets/index-C2eIILoa.css +0 -41
- package/client/assets/index-DUPZ_Lw5.js +0 -616
- package/dist/server/lib/act-runtime.js +0 -1282
- package/dist/server/lib/prompt.js +0 -222
- package/dist/server/routes/stages.js +0 -137
|
@@ -1,421 +1,11 @@
|
|
|
1
|
-
// OpenCode SDK Proxy Routes
|
|
2
|
-
// Models, Agents, Tools, Config, Provider Auth, File, Find, VCS, LSP, MCP
|
|
3
1
|
import { Hono } from 'hono';
|
|
4
|
-
import
|
|
5
|
-
import
|
|
6
|
-
import
|
|
7
|
-
import
|
|
8
|
-
import { canRestartOpencodeSidecar, isManagedOpencode, restartOpencodeSidecar } from '../lib/opencode-sidecar.js';
|
|
9
|
-
import { OPENCODE_URL } from '../lib/config.js';
|
|
10
|
-
import { clearStoredProviderAuth } from '../lib/opencode-auth.js';
|
|
11
|
-
import { jsonOpencodeError, unwrapOpencodeResult } from '../lib/opencode-errors.js';
|
|
12
|
-
import { listRuntimeModels } from '../lib/model-catalog.js';
|
|
13
|
-
import { readProjectMcpCatalog, summarizeProjectMcpCatalog } from '../lib/project-config.js';
|
|
2
|
+
import opencodeCore from './opencode-core.js';
|
|
3
|
+
import opencodeProvider from './opencode-provider.js';
|
|
4
|
+
import opencodeMcp from './opencode-mcp.js';
|
|
5
|
+
import opencodeFile from './opencode-file.js';
|
|
14
6
|
const opencode = new Hono();
|
|
15
|
-
|
|
16
|
-
opencode.
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
const res = await oc.project.current(requestDirectoryQuery(c));
|
|
20
|
-
const data = res.data;
|
|
21
|
-
return c.json({
|
|
22
|
-
connected: true,
|
|
23
|
-
url: OPENCODE_URL,
|
|
24
|
-
project: data,
|
|
25
|
-
managed: isManagedOpencode(),
|
|
26
|
-
mode: isManagedOpencode() ? 'managed' : 'external',
|
|
27
|
-
restartAvailable: canRestartOpencodeSidecar(),
|
|
28
|
-
});
|
|
29
|
-
}
|
|
30
|
-
catch (err) {
|
|
31
|
-
return c.json({
|
|
32
|
-
connected: false,
|
|
33
|
-
error: err.message,
|
|
34
|
-
url: OPENCODE_URL,
|
|
35
|
-
managed: isManagedOpencode(),
|
|
36
|
-
mode: isManagedOpencode() ? 'managed' : 'external',
|
|
37
|
-
restartAvailable: canRestartOpencodeSidecar(),
|
|
38
|
-
}, 503);
|
|
39
|
-
}
|
|
40
|
-
});
|
|
41
|
-
opencode.post('/api/opencode/restart', async (c) => {
|
|
42
|
-
try {
|
|
43
|
-
await restartOpencodeSidecar();
|
|
44
|
-
return c.json({
|
|
45
|
-
ok: true,
|
|
46
|
-
managed: isManagedOpencode(),
|
|
47
|
-
mode: isManagedOpencode() ? 'managed' : 'external',
|
|
48
|
-
});
|
|
49
|
-
}
|
|
50
|
-
catch (err) {
|
|
51
|
-
return c.json({ error: err.message }, 400);
|
|
52
|
-
}
|
|
53
|
-
});
|
|
54
|
-
// ── Models ──────────────────────────────────────────────
|
|
55
|
-
opencode.get('/api/models', async (c) => {
|
|
56
|
-
try {
|
|
57
|
-
const cwd = resolveRequestWorkingDir(c);
|
|
58
|
-
return c.json(await listRuntimeModels(cwd));
|
|
59
|
-
}
|
|
60
|
-
catch {
|
|
61
|
-
return c.json([]);
|
|
62
|
-
}
|
|
63
|
-
});
|
|
64
|
-
opencode.get('/api/providers', async (c) => {
|
|
65
|
-
try {
|
|
66
|
-
const cwd = resolveRequestWorkingDir(c);
|
|
67
|
-
const oc = await getOpencode();
|
|
68
|
-
const data = unwrapOpencodeResult(await oc.provider.list({ directory: cwd }));
|
|
69
|
-
const connected = new Set((data?.connected || []));
|
|
70
|
-
const providers = (data?.all || []).map((provider) => ({
|
|
71
|
-
id: provider.id,
|
|
72
|
-
name: provider.name || provider.id,
|
|
73
|
-
source: provider.source || 'builtin',
|
|
74
|
-
env: Array.isArray(provider.env) ? provider.env : [],
|
|
75
|
-
connected: connected.has(provider.id),
|
|
76
|
-
modelCount: provider.models ? Object.keys(provider.models).length : 0,
|
|
77
|
-
defaultModel: data?.default?.[provider.id] || null,
|
|
78
|
-
}));
|
|
79
|
-
return c.json(providers);
|
|
80
|
-
}
|
|
81
|
-
catch (err) {
|
|
82
|
-
return jsonOpencodeError(c, err, { defaultStatus: 503 });
|
|
83
|
-
}
|
|
84
|
-
});
|
|
85
|
-
// ── Agents ──────────────────────────────────────────────
|
|
86
|
-
opencode.get('/api/agents', async (c) => {
|
|
87
|
-
try {
|
|
88
|
-
const oc = await getOpencode();
|
|
89
|
-
const res = await oc.app.agents(requestDirectoryQuery(c));
|
|
90
|
-
const data = res.data;
|
|
91
|
-
return c.json(data || []);
|
|
92
|
-
}
|
|
93
|
-
catch {
|
|
94
|
-
return c.json([]);
|
|
95
|
-
}
|
|
96
|
-
});
|
|
97
|
-
// ── Tools ───────────────────────────────────────────────
|
|
98
|
-
opencode.get('/api/tools', async (c) => {
|
|
99
|
-
try {
|
|
100
|
-
const oc = await getOpencode();
|
|
101
|
-
const res = await oc.tool.ids(requestDirectoryQuery(c));
|
|
102
|
-
const data = res.data;
|
|
103
|
-
return c.json(data || []);
|
|
104
|
-
}
|
|
105
|
-
catch {
|
|
106
|
-
return c.json([]);
|
|
107
|
-
}
|
|
108
|
-
});
|
|
109
|
-
opencode.get('/api/tools/:provider/:model', async (c) => {
|
|
110
|
-
try {
|
|
111
|
-
const oc = await getOpencode();
|
|
112
|
-
const res = await oc.tool.list({
|
|
113
|
-
...requestDirectoryQuery(c),
|
|
114
|
-
provider: c.req.param('provider'),
|
|
115
|
-
model: c.req.param('model'),
|
|
116
|
-
});
|
|
117
|
-
const data = res.data;
|
|
118
|
-
return c.json(data || []);
|
|
119
|
-
}
|
|
120
|
-
catch (err) {
|
|
121
|
-
return c.json({ error: err.message }, 500);
|
|
122
|
-
}
|
|
123
|
-
});
|
|
124
|
-
opencode.post('/api/runtime/tools', async (c) => {
|
|
125
|
-
const { model = null, mcpServerNames = [] } = await c.req.json();
|
|
126
|
-
try {
|
|
127
|
-
const resolution = await resolveRuntimeTools(resolveRequestWorkingDir(c), model, mcpServerNames);
|
|
128
|
-
return c.json(resolution);
|
|
129
|
-
}
|
|
130
|
-
catch (err) {
|
|
131
|
-
return c.json({ error: err.message }, 500);
|
|
132
|
-
}
|
|
133
|
-
});
|
|
134
|
-
// ── Config ──────────────────────────────────────────────
|
|
135
|
-
opencode.get('/api/config', async (c) => {
|
|
136
|
-
try {
|
|
137
|
-
const oc = await getOpencode();
|
|
138
|
-
const res = await oc.config.get(requestDirectoryQuery(c));
|
|
139
|
-
const data = res.data;
|
|
140
|
-
return c.json(data || {});
|
|
141
|
-
}
|
|
142
|
-
catch (err) {
|
|
143
|
-
return c.json({ error: err.message }, 500);
|
|
144
|
-
}
|
|
145
|
-
});
|
|
146
|
-
opencode.get('/api/config/project', async (c) => {
|
|
147
|
-
const cwd = resolveRequestWorkingDir(c);
|
|
148
|
-
try {
|
|
149
|
-
const oc = await getOpencode();
|
|
150
|
-
const res = await oc.file.read({
|
|
151
|
-
directory: cwd,
|
|
152
|
-
path: 'config.json',
|
|
153
|
-
});
|
|
154
|
-
const data = res.data;
|
|
155
|
-
const raw = typeof data?.content === 'string' ? data.content : '{}';
|
|
156
|
-
const config = JSON.parse(raw);
|
|
157
|
-
return c.json({
|
|
158
|
-
exists: true,
|
|
159
|
-
path: `${cwd}/config.json`,
|
|
160
|
-
config,
|
|
161
|
-
});
|
|
162
|
-
}
|
|
163
|
-
catch {
|
|
164
|
-
return c.json({
|
|
165
|
-
exists: false,
|
|
166
|
-
path: `${cwd}/config.json`,
|
|
167
|
-
config: {},
|
|
168
|
-
});
|
|
169
|
-
}
|
|
170
|
-
});
|
|
171
|
-
opencode.put('/api/config', async (c) => {
|
|
172
|
-
const body = await c.req.json();
|
|
173
|
-
try {
|
|
174
|
-
const oc = await getOpencode();
|
|
175
|
-
const res = await oc.config.update({ ...requestDirectoryQuery(c), config: body });
|
|
176
|
-
const data = res.data;
|
|
177
|
-
invalidate('mcp-servers');
|
|
178
|
-
return c.json(data);
|
|
179
|
-
}
|
|
180
|
-
catch (err) {
|
|
181
|
-
return c.json({ error: err.message }, 500);
|
|
182
|
-
}
|
|
183
|
-
});
|
|
184
|
-
// ── Provider Auth ───────────────────────────────────────
|
|
185
|
-
opencode.get('/api/provider/auth', async (c) => {
|
|
186
|
-
try {
|
|
187
|
-
const oc = await getOpencode();
|
|
188
|
-
const data = unwrapOpencodeResult(await oc.provider.auth(requestDirectoryQuery(c)));
|
|
189
|
-
return c.json(data || {});
|
|
190
|
-
}
|
|
191
|
-
catch (err) {
|
|
192
|
-
return jsonOpencodeError(c, err, { defaultStatus: 503 });
|
|
193
|
-
}
|
|
194
|
-
});
|
|
195
|
-
opencode.post('/api/provider/:id/oauth/authorize', async (c) => {
|
|
196
|
-
const { method } = await c.req.json();
|
|
197
|
-
try {
|
|
198
|
-
const oc = await getOpencode();
|
|
199
|
-
const data = unwrapOpencodeResult(await oc.provider.oauth.authorize({
|
|
200
|
-
providerID: c.req.param('id'),
|
|
201
|
-
...requestDirectoryQuery(c),
|
|
202
|
-
method,
|
|
203
|
-
}));
|
|
204
|
-
return c.json(data);
|
|
205
|
-
}
|
|
206
|
-
catch (err) {
|
|
207
|
-
return jsonOpencodeError(c, err, { providerId: c.req.param('id'), defaultStatus: 500 });
|
|
208
|
-
}
|
|
209
|
-
});
|
|
210
|
-
opencode.post('/api/provider/:id/oauth/callback', async (c) => {
|
|
211
|
-
const { method, code } = await c.req.json();
|
|
212
|
-
try {
|
|
213
|
-
const oc = await getOpencode();
|
|
214
|
-
const data = unwrapOpencodeResult(await oc.provider.oauth.callback({
|
|
215
|
-
providerID: c.req.param('id'),
|
|
216
|
-
...requestDirectoryQuery(c),
|
|
217
|
-
method,
|
|
218
|
-
...(code ? { code } : {}),
|
|
219
|
-
}));
|
|
220
|
-
unwrapOpencodeResult(await oc.instance.dispose(requestDirectoryQuery(c)));
|
|
221
|
-
return c.json(data);
|
|
222
|
-
}
|
|
223
|
-
catch (err) {
|
|
224
|
-
return jsonOpencodeError(c, err, { providerId: c.req.param('id'), defaultStatus: 500 });
|
|
225
|
-
}
|
|
226
|
-
});
|
|
227
|
-
opencode.put('/api/provider/:id/auth', async (c) => {
|
|
228
|
-
const auth = await c.req.json();
|
|
229
|
-
try {
|
|
230
|
-
const oc = await getOpencode();
|
|
231
|
-
const data = unwrapOpencodeResult(await oc.auth.set({
|
|
232
|
-
providerID: c.req.param('id'),
|
|
233
|
-
auth,
|
|
234
|
-
}));
|
|
235
|
-
unwrapOpencodeResult(await oc.instance.dispose(requestDirectoryQuery(c)));
|
|
236
|
-
return c.json(data);
|
|
237
|
-
}
|
|
238
|
-
catch (err) {
|
|
239
|
-
return jsonOpencodeError(c, err, { providerId: c.req.param('id'), defaultStatus: 500 });
|
|
240
|
-
}
|
|
241
|
-
});
|
|
242
|
-
opencode.delete('/api/provider/:id/auth', async (c) => {
|
|
243
|
-
try {
|
|
244
|
-
const oc = await getOpencode();
|
|
245
|
-
await clearStoredProviderAuth(c.req.param('id'));
|
|
246
|
-
unwrapOpencodeResult(await oc.instance.dispose(requestDirectoryQuery(c)));
|
|
247
|
-
return c.json({ ok: true });
|
|
248
|
-
}
|
|
249
|
-
catch (err) {
|
|
250
|
-
return jsonOpencodeError(c, err, { providerId: c.req.param('id'), defaultStatus: 500 });
|
|
251
|
-
}
|
|
252
|
-
});
|
|
253
|
-
// ── LSP ─────────────────────────────────────────────────
|
|
254
|
-
opencode.get('/api/lsp/status', async (c) => {
|
|
255
|
-
try {
|
|
256
|
-
const oc = await getOpencode();
|
|
257
|
-
const res = await oc.lsp.status(requestDirectoryQuery(c));
|
|
258
|
-
const data = res.data;
|
|
259
|
-
return c.json(data || []);
|
|
260
|
-
}
|
|
261
|
-
catch (err) {
|
|
262
|
-
return c.json({ error: err.message }, 500);
|
|
263
|
-
}
|
|
264
|
-
});
|
|
265
|
-
// ── MCP Servers ─────────────────────────────────────────
|
|
266
|
-
opencode.get('/api/mcp/servers', async (c) => {
|
|
267
|
-
try {
|
|
268
|
-
const cwd = resolveRequestWorkingDir(c);
|
|
269
|
-
return c.json(await cached(`mcp-servers-${cwd}`, TTL.MCP_SERVERS, async () => {
|
|
270
|
-
const oc = await getOpencode();
|
|
271
|
-
const res = await oc.mcp.status({ directory: cwd });
|
|
272
|
-
const data = (res.data || {});
|
|
273
|
-
const catalog = await readProjectMcpCatalog(cwd);
|
|
274
|
-
return summarizeProjectMcpCatalog(catalog, data);
|
|
275
|
-
}));
|
|
276
|
-
}
|
|
277
|
-
catch {
|
|
278
|
-
return c.json([]);
|
|
279
|
-
}
|
|
280
|
-
});
|
|
281
|
-
opencode.post('/api/mcp/add', async (c) => {
|
|
282
|
-
const { name, config } = await c.req.json();
|
|
283
|
-
try {
|
|
284
|
-
const oc = await getOpencode();
|
|
285
|
-
const res = await oc.mcp.add({
|
|
286
|
-
...requestDirectoryQuery(c),
|
|
287
|
-
name,
|
|
288
|
-
config: config,
|
|
289
|
-
});
|
|
290
|
-
const data = res.data;
|
|
291
|
-
invalidate('mcp-servers');
|
|
292
|
-
return c.json(data);
|
|
293
|
-
}
|
|
294
|
-
catch (err) {
|
|
295
|
-
return c.json({ error: err.message }, 500);
|
|
296
|
-
}
|
|
297
|
-
});
|
|
298
|
-
opencode.post('/api/mcp/:name/connect', async (c) => {
|
|
299
|
-
try {
|
|
300
|
-
const oc = await getOpencode();
|
|
301
|
-
const res = await oc.mcp.connect({
|
|
302
|
-
name: c.req.param('name'),
|
|
303
|
-
...requestDirectoryQuery(c),
|
|
304
|
-
});
|
|
305
|
-
const data = res.data;
|
|
306
|
-
invalidate('mcp-servers');
|
|
307
|
-
return c.json(data);
|
|
308
|
-
}
|
|
309
|
-
catch (err) {
|
|
310
|
-
return c.json({ error: err.message }, 500);
|
|
311
|
-
}
|
|
312
|
-
});
|
|
313
|
-
opencode.post('/api/mcp/:name/disconnect', async (c) => {
|
|
314
|
-
try {
|
|
315
|
-
const oc = await getOpencode();
|
|
316
|
-
const res = await oc.mcp.disconnect({
|
|
317
|
-
name: c.req.param('name'),
|
|
318
|
-
...requestDirectoryQuery(c),
|
|
319
|
-
});
|
|
320
|
-
const data = res.data;
|
|
321
|
-
invalidate('mcp-servers');
|
|
322
|
-
return c.json(data);
|
|
323
|
-
}
|
|
324
|
-
catch (err) {
|
|
325
|
-
return c.json({ error: err.message }, 500);
|
|
326
|
-
}
|
|
327
|
-
});
|
|
328
|
-
// ── File ────────────────────────────────────────────────
|
|
329
|
-
opencode.get('/api/file/list', async (c) => {
|
|
330
|
-
const dirPath = c.req.query('path') || '.';
|
|
331
|
-
try {
|
|
332
|
-
const oc = await getOpencode();
|
|
333
|
-
const res = await oc.file.list({ ...requestDirectoryQuery(c), path: dirPath });
|
|
334
|
-
const data = res.data;
|
|
335
|
-
return c.json(data || []);
|
|
336
|
-
}
|
|
337
|
-
catch {
|
|
338
|
-
return c.json([]);
|
|
339
|
-
}
|
|
340
|
-
});
|
|
341
|
-
opencode.get('/api/file/read', async (c) => {
|
|
342
|
-
const filePath = c.req.query('path');
|
|
343
|
-
if (!filePath)
|
|
344
|
-
return c.json({ error: 'path required' }, 400);
|
|
345
|
-
try {
|
|
346
|
-
const oc = await getOpencode();
|
|
347
|
-
const res = await oc.file.read({ ...requestDirectoryQuery(c), path: filePath });
|
|
348
|
-
const data = res.data;
|
|
349
|
-
return c.json(data);
|
|
350
|
-
}
|
|
351
|
-
catch (err) {
|
|
352
|
-
return c.json({ error: err.message }, 500);
|
|
353
|
-
}
|
|
354
|
-
});
|
|
355
|
-
opencode.get('/api/file/status', async (c) => {
|
|
356
|
-
try {
|
|
357
|
-
const oc = await getOpencode();
|
|
358
|
-
const res = await oc.file.status(requestDirectoryQuery(c));
|
|
359
|
-
const data = res.data;
|
|
360
|
-
return c.json(data || []);
|
|
361
|
-
}
|
|
362
|
-
catch {
|
|
363
|
-
return c.json([]);
|
|
364
|
-
}
|
|
365
|
-
});
|
|
366
|
-
// ── Find ────────────────────────────────────────────────
|
|
367
|
-
opencode.get('/api/find/text', async (c) => {
|
|
368
|
-
const pattern = c.req.query('pattern');
|
|
369
|
-
if (!pattern)
|
|
370
|
-
return c.json({ error: 'pattern required' }, 400);
|
|
371
|
-
try {
|
|
372
|
-
const oc = await getOpencode();
|
|
373
|
-
const res = await oc.find.text({ ...requestDirectoryQuery(c), pattern });
|
|
374
|
-
const data = res.data;
|
|
375
|
-
return c.json(data || []);
|
|
376
|
-
}
|
|
377
|
-
catch (err) {
|
|
378
|
-
return c.json({ error: err.message }, 500);
|
|
379
|
-
}
|
|
380
|
-
});
|
|
381
|
-
opencode.get('/api/find/files', async (c) => {
|
|
382
|
-
const pattern = c.req.query('pattern');
|
|
383
|
-
if (!pattern)
|
|
384
|
-
return c.json({ error: 'pattern required' }, 400);
|
|
385
|
-
try {
|
|
386
|
-
const oc = await getOpencode();
|
|
387
|
-
const res = await oc.find.files({ ...requestDirectoryQuery(c), query: pattern });
|
|
388
|
-
const data = res.data;
|
|
389
|
-
return c.json(data || []);
|
|
390
|
-
}
|
|
391
|
-
catch (err) {
|
|
392
|
-
return c.json({ error: err.message }, 500);
|
|
393
|
-
}
|
|
394
|
-
});
|
|
395
|
-
opencode.get('/api/find/symbols', async (c) => {
|
|
396
|
-
const pattern = c.req.query('pattern');
|
|
397
|
-
if (!pattern)
|
|
398
|
-
return c.json({ error: 'pattern required' }, 400);
|
|
399
|
-
try {
|
|
400
|
-
const oc = await getOpencode();
|
|
401
|
-
const res = await oc.find.symbols({ ...requestDirectoryQuery(c), query: pattern });
|
|
402
|
-
const data = res.data;
|
|
403
|
-
return c.json(data || []);
|
|
404
|
-
}
|
|
405
|
-
catch (err) {
|
|
406
|
-
return c.json({ error: err.message }, 500);
|
|
407
|
-
}
|
|
408
|
-
});
|
|
409
|
-
// ── VCS / Git ───────────────────────────────────────────
|
|
410
|
-
opencode.get('/api/vcs', async (c) => {
|
|
411
|
-
try {
|
|
412
|
-
const oc = await getOpencode();
|
|
413
|
-
const res = await oc.vcs.get(requestDirectoryQuery(c));
|
|
414
|
-
const data = res.data;
|
|
415
|
-
return c.json(data || {});
|
|
416
|
-
}
|
|
417
|
-
catch (err) {
|
|
418
|
-
return c.json({ error: err.message }, 500);
|
|
419
|
-
}
|
|
420
|
-
});
|
|
7
|
+
opencode.route('/', opencodeCore);
|
|
8
|
+
opencode.route('/', opencodeProvider);
|
|
9
|
+
opencode.route('/', opencodeMcp);
|
|
10
|
+
opencode.route('/', opencodeFile);
|
|
421
11
|
export default opencode;
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { resolveRequestWorkingDir } from '../lib/request-context.js';
|
|
2
|
+
export function jsonError(c, message, status = 400) {
|
|
3
|
+
return c.json({ error: message }, { status });
|
|
4
|
+
}
|
|
5
|
+
export function requestWorkingDir(c) {
|
|
6
|
+
return resolveRequestWorkingDir(c);
|
|
7
|
+
}
|
|
8
|
+
export function jsonServiceFailure(c, result) {
|
|
9
|
+
return c.json({ error: result.error }, { status: result.status });
|
|
10
|
+
}
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import { Hono } from 'hono';
|
|
2
|
+
import { applySafeOwnerSummary, discardAllSafeOwnerSummaryChanges, discardSafeOwnerSummaryFile, parseSafeOwnerKind, undoLastSafeOwnerSummaryApply, } from '../services/safe-service.js';
|
|
3
|
+
import { jsonError, requestWorkingDir } from './route-errors.js';
|
|
4
|
+
const safeActions = new Hono();
|
|
5
|
+
function errorMessage(error, fallback) {
|
|
6
|
+
return error instanceof Error && error.message ? error.message : fallback;
|
|
7
|
+
}
|
|
8
|
+
safeActions.post('/api/safe/:ownerKind/:ownerId/apply', async (c) => {
|
|
9
|
+
const ownerKind = parseSafeOwnerKind(c.req.param('ownerKind'));
|
|
10
|
+
if (!ownerKind) {
|
|
11
|
+
return jsonError(c, 'Invalid owner kind.');
|
|
12
|
+
}
|
|
13
|
+
try {
|
|
14
|
+
return c.json(await applySafeOwnerSummary(requestWorkingDir(c), ownerKind, c.req.param('ownerId')));
|
|
15
|
+
}
|
|
16
|
+
catch (error) {
|
|
17
|
+
return jsonError(c, errorMessage(error, 'Failed to apply safe mode changes.'), 500);
|
|
18
|
+
}
|
|
19
|
+
});
|
|
20
|
+
safeActions.post('/api/safe/:ownerKind/:ownerId/discard', async (c) => {
|
|
21
|
+
const ownerKind = parseSafeOwnerKind(c.req.param('ownerKind'));
|
|
22
|
+
if (!ownerKind) {
|
|
23
|
+
return jsonError(c, 'Invalid owner kind.');
|
|
24
|
+
}
|
|
25
|
+
const body = await c.req.json().catch(() => ({}));
|
|
26
|
+
if (!body.filePath || !body.filePath.trim()) {
|
|
27
|
+
return jsonError(c, 'filePath is required.');
|
|
28
|
+
}
|
|
29
|
+
try {
|
|
30
|
+
return c.json(await discardSafeOwnerSummaryFile(requestWorkingDir(c), ownerKind, c.req.param('ownerId'), body.filePath.trim()));
|
|
31
|
+
}
|
|
32
|
+
catch (error) {
|
|
33
|
+
return jsonError(c, errorMessage(error, 'Failed to discard the file.'), 500);
|
|
34
|
+
}
|
|
35
|
+
});
|
|
36
|
+
safeActions.post('/api/safe/:ownerKind/:ownerId/discard-all', async (c) => {
|
|
37
|
+
const ownerKind = parseSafeOwnerKind(c.req.param('ownerKind'));
|
|
38
|
+
if (!ownerKind) {
|
|
39
|
+
return jsonError(c, 'Invalid owner kind.');
|
|
40
|
+
}
|
|
41
|
+
try {
|
|
42
|
+
return c.json(await discardAllSafeOwnerSummaryChanges(requestWorkingDir(c), ownerKind, c.req.param('ownerId')));
|
|
43
|
+
}
|
|
44
|
+
catch (error) {
|
|
45
|
+
return jsonError(c, errorMessage(error, 'Failed to discard pending changes.'), 500);
|
|
46
|
+
}
|
|
47
|
+
});
|
|
48
|
+
safeActions.post('/api/safe/:ownerKind/:ownerId/undo-last-apply', async (c) => {
|
|
49
|
+
const ownerKind = parseSafeOwnerKind(c.req.param('ownerKind'));
|
|
50
|
+
if (!ownerKind) {
|
|
51
|
+
return jsonError(c, 'Invalid owner kind.');
|
|
52
|
+
}
|
|
53
|
+
try {
|
|
54
|
+
return c.json(await undoLastSafeOwnerSummaryApply(requestWorkingDir(c), ownerKind, c.req.param('ownerId')));
|
|
55
|
+
}
|
|
56
|
+
catch (error) {
|
|
57
|
+
return jsonError(c, errorMessage(error, 'Failed to undo the last apply.'), 500);
|
|
58
|
+
}
|
|
59
|
+
});
|
|
60
|
+
export default safeActions;
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { Hono } from 'hono';
|
|
2
|
+
import { parseSafeOwnerKind, readSafeOwnerSummary, } from '../services/safe-service.js';
|
|
3
|
+
import { jsonError, requestWorkingDir } from './route-errors.js';
|
|
4
|
+
const safeSummary = new Hono();
|
|
5
|
+
function errorMessage(error) {
|
|
6
|
+
return error instanceof Error && error.message ? error.message : 'Failed to load safe mode summary.';
|
|
7
|
+
}
|
|
8
|
+
safeSummary.get('/api/safe/:ownerKind/:ownerId', async (c) => {
|
|
9
|
+
const ownerKind = parseSafeOwnerKind(c.req.param('ownerKind'));
|
|
10
|
+
if (!ownerKind) {
|
|
11
|
+
return jsonError(c, 'Invalid owner kind.');
|
|
12
|
+
}
|
|
13
|
+
try {
|
|
14
|
+
return c.json(await readSafeOwnerSummary(requestWorkingDir(c), ownerKind, c.req.param('ownerId')));
|
|
15
|
+
}
|
|
16
|
+
catch (error) {
|
|
17
|
+
return jsonError(c, errorMessage(error), 500);
|
|
18
|
+
}
|
|
19
|
+
});
|
|
20
|
+
export default safeSummary;
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
// Workspace CRUD Routes — with path validation
|
|
2
|
+
import { Hono } from 'hono';
|
|
3
|
+
import { deleteSavedWorkspace, getSavedWorkspace, listSavedWorkspaces, saveWorkspaceSnapshot, setSavedWorkspaceHidden, } from '../services/workspace-service.js';
|
|
4
|
+
import { jsonServiceFailure } from './route-errors.js';
|
|
5
|
+
const workspaces = new Hono();
|
|
6
|
+
function registerWorkspaceRoutes(basePath) {
|
|
7
|
+
workspaces.get(basePath, async (c) => {
|
|
8
|
+
try {
|
|
9
|
+
return c.json(await listSavedWorkspaces(c.req.query('includeHidden') === '1'));
|
|
10
|
+
}
|
|
11
|
+
catch {
|
|
12
|
+
return c.json([]);
|
|
13
|
+
}
|
|
14
|
+
});
|
|
15
|
+
workspaces.get(`${basePath}/:id`, async (c) => {
|
|
16
|
+
const result = await getSavedWorkspace(c.req.param('id'));
|
|
17
|
+
if (!result.ok) {
|
|
18
|
+
return jsonServiceFailure(c, result);
|
|
19
|
+
}
|
|
20
|
+
return c.json(result.workspace);
|
|
21
|
+
});
|
|
22
|
+
workspaces.put(basePath, async (c) => {
|
|
23
|
+
const body = await c.req.json();
|
|
24
|
+
const result = await saveWorkspaceSnapshot(body);
|
|
25
|
+
if (!result.ok) {
|
|
26
|
+
return jsonServiceFailure(c, result);
|
|
27
|
+
}
|
|
28
|
+
return c.json(result);
|
|
29
|
+
});
|
|
30
|
+
workspaces.patch(`${basePath}/:id`, async (c) => {
|
|
31
|
+
const body = await c.req.json().catch(() => ({}));
|
|
32
|
+
const result = await setSavedWorkspaceHidden(c.req.param('id'), body.hiddenFromList === true);
|
|
33
|
+
if (!result.ok) {
|
|
34
|
+
return jsonServiceFailure(c, result);
|
|
35
|
+
}
|
|
36
|
+
return c.json(result);
|
|
37
|
+
});
|
|
38
|
+
workspaces.delete(`${basePath}/:id`, async (c) => {
|
|
39
|
+
const result = await deleteSavedWorkspace(c.req.param('id'));
|
|
40
|
+
if (!result.ok) {
|
|
41
|
+
return jsonServiceFailure(c, result);
|
|
42
|
+
}
|
|
43
|
+
return c.json(result);
|
|
44
|
+
});
|
|
45
|
+
}
|
|
46
|
+
registerWorkspaceRoutes('/api/workspaces');
|
|
47
|
+
export default workspaces;
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* act-context-builder.ts — Collaboration context injection
|
|
3
|
+
*
|
|
4
|
+
* PRD §9: Stable collaboration context is injected at the agent/system level.
|
|
5
|
+
* Includes: goal, participants, collaboration tools, relations, subscriptions, and rules.
|
|
6
|
+
*/
|
|
7
|
+
function participantDisplayName(actDefinition, participantKey) {
|
|
8
|
+
return actDefinition.participants[participantKey]?.displayName || participantKey;
|
|
9
|
+
}
|
|
10
|
+
/**
|
|
11
|
+
* Build markdown Act context for a participant's agent prompt.
|
|
12
|
+
*/
|
|
13
|
+
export function buildActContext(actDefinition, participantKey) {
|
|
14
|
+
const lines = [];
|
|
15
|
+
const selfName = participantDisplayName(actDefinition, participantKey);
|
|
16
|
+
// ── Header ──────────────────────────────────────
|
|
17
|
+
lines.push('# Collaboration Context');
|
|
18
|
+
if (actDefinition.description) {
|
|
19
|
+
lines.push(`- Goal: ${actDefinition.description}`);
|
|
20
|
+
}
|
|
21
|
+
lines.push(`- Team: ${actDefinition.name}`);
|
|
22
|
+
lines.push(`- Your role: ${selfName}`);
|
|
23
|
+
// ── Participants ─────────────────────────────────
|
|
24
|
+
lines.push('- Team members:');
|
|
25
|
+
for (const key of Object.keys(actDefinition.participants)) {
|
|
26
|
+
const isSelf = key === participantKey;
|
|
27
|
+
lines.push(` - ${participantDisplayName(actDefinition, key)}${isSelf ? ' (you)' : ''}`);
|
|
28
|
+
}
|
|
29
|
+
lines.push('');
|
|
30
|
+
// ── Collaboration Runtime ────────────────────────
|
|
31
|
+
lines.push('# Coordination Tools');
|
|
32
|
+
lines.push('- Use `message_teammate` for direct coordination with one teammate.');
|
|
33
|
+
lines.push('- Use `update_shared_board` to publish durable notes, findings, tasks, and handoffs for the whole team.');
|
|
34
|
+
lines.push('- Use `read_shared_board` to review current shared context before acting.');
|
|
35
|
+
lines.push('- Use `wait_until` when you need to pause until future messages or shared updates arrive.');
|
|
36
|
+
lines.push('');
|
|
37
|
+
// ── Available Relations ─────────────────────────
|
|
38
|
+
const myRelations = actDefinition.relations.filter((rel) => rel.between.includes(participantKey));
|
|
39
|
+
if (myRelations.length > 0) {
|
|
40
|
+
lines.push('# Team Connections');
|
|
41
|
+
for (const rel of myRelations) {
|
|
42
|
+
const partner = rel.between[0] === participantKey ? rel.between[1] : rel.between[0];
|
|
43
|
+
const partnerName = participantDisplayName(actDefinition, partner);
|
|
44
|
+
const dirLabel = rel.direction === 'one-way'
|
|
45
|
+
? (rel.between[0] === participantKey ? '→' : '←')
|
|
46
|
+
: '↔';
|
|
47
|
+
lines.push(`- ${selfName} ${dirLabel} ${partnerName}: ${rel.name}${rel.description ? ` — ${rel.description}` : ''}`);
|
|
48
|
+
}
|
|
49
|
+
lines.push('');
|
|
50
|
+
}
|
|
51
|
+
// ── Subscriptions ───────────────────────────────
|
|
52
|
+
const binding = actDefinition.participants[participantKey];
|
|
53
|
+
if (binding?.subscriptions) {
|
|
54
|
+
const subs = binding.subscriptions;
|
|
55
|
+
lines.push('# Notifications You Receive');
|
|
56
|
+
if (subs.messagesFrom?.length) {
|
|
57
|
+
lines.push(`- Direct messages from: ${subs.messagesFrom.map((key) => participantDisplayName(actDefinition, key)).join(', ')}`);
|
|
58
|
+
}
|
|
59
|
+
if (subs.messageTags?.length) {
|
|
60
|
+
lines.push(`- Message labels: ${subs.messageTags.join(', ')}`);
|
|
61
|
+
}
|
|
62
|
+
if (subs.callboardKeys?.length) {
|
|
63
|
+
lines.push(`- Shared note keys: ${subs.callboardKeys.join(', ')}`);
|
|
64
|
+
}
|
|
65
|
+
if (subs.eventTypes?.length) {
|
|
66
|
+
lines.push(`- System updates: ${subs.eventTypes.join(', ')}`);
|
|
67
|
+
}
|
|
68
|
+
lines.push('');
|
|
69
|
+
}
|
|
70
|
+
// activeDances section removed per PRD-005
|
|
71
|
+
// Performer uses all its dances by default
|
|
72
|
+
// ── Act Rules ───────────────────────────────────
|
|
73
|
+
if (actDefinition.actRules && actDefinition.actRules.length > 0) {
|
|
74
|
+
lines.push('# Working Rules');
|
|
75
|
+
for (const rule of actDefinition.actRules) {
|
|
76
|
+
lines.push(`- ${rule}`);
|
|
77
|
+
}
|
|
78
|
+
lines.push('');
|
|
79
|
+
}
|
|
80
|
+
return lines.join('\n');
|
|
81
|
+
}
|