@flowdular/sandbox 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +696 -0
- package/bin/flowdular-sandbox.mjs +394 -0
- package/bin/register-types.mjs +53 -0
- package/dist/client/assets/App-ClMOrpyg.js +11 -0
- package/dist/client/assets/PreviewHost-BHiHrfbQ.js +1 -0
- package/dist/client/assets/auto-buGEq6de.js +3 -0
- package/dist/client/assets/ibm-plex-mono-cyrillic-400-normal-BSMlKf0J.woff2 +0 -0
- package/dist/client/assets/ibm-plex-mono-cyrillic-400-normal-CEL4l2ZJ.woff +0 -0
- package/dist/client/assets/ibm-plex-mono-cyrillic-500-normal-Ael50iVv.woff +0 -0
- package/dist/client/assets/ibm-plex-mono-cyrillic-500-normal-Bq9vWWag.woff2 +0 -0
- package/dist/client/assets/ibm-plex-mono-cyrillic-ext-400-normal-DMdlQ8Kv.woff +0 -0
- package/dist/client/assets/ibm-plex-mono-cyrillic-ext-400-normal-xuaO2J-f.woff2 +0 -0
- package/dist/client/assets/ibm-plex-mono-cyrillic-ext-500-normal-BIfNGwUT.woff +0 -0
- package/dist/client/assets/ibm-plex-mono-cyrillic-ext-500-normal-BqneJy0T.woff2 +0 -0
- package/dist/client/assets/ibm-plex-mono-latin-400-normal-CvHOgSBP.woff +0 -0
- package/dist/client/assets/ibm-plex-mono-latin-400-normal-DMJ8VG8y.woff2 +0 -0
- package/dist/client/assets/ibm-plex-mono-latin-500-normal-CB9ihrfo.woff +0 -0
- package/dist/client/assets/ibm-plex-mono-latin-500-normal-DSY6xOcd.woff2 +0 -0
- package/dist/client/assets/ibm-plex-mono-latin-ext-400-normal-BmRBH3aV.woff2 +0 -0
- package/dist/client/assets/ibm-plex-mono-latin-ext-400-normal-D3D2R8hC.woff +0 -0
- package/dist/client/assets/ibm-plex-mono-latin-ext-500-normal-CAhNIIs5.woff2 +0 -0
- package/dist/client/assets/ibm-plex-mono-latin-ext-500-normal-CZ70TYgx.woff +0 -0
- package/dist/client/assets/ibm-plex-mono-vietnamese-400-normal-BulugwFq.woff2 +0 -0
- package/dist/client/assets/ibm-plex-mono-vietnamese-400-normal-DDuiU_S-.woff +0 -0
- package/dist/client/assets/ibm-plex-mono-vietnamese-500-normal-C8zxqsMH.woff +0 -0
- package/dist/client/assets/ibm-plex-mono-vietnamese-500-normal-DZ4AoWbu.woff2 +0 -0
- package/dist/client/assets/ibm-plex-sans-cyrillic-ext-wght-normal-d45eAU9y.woff2 +0 -0
- package/dist/client/assets/ibm-plex-sans-cyrillic-wght-normal-BAAhND-U.woff2 +0 -0
- package/dist/client/assets/ibm-plex-sans-greek-wght-normal-CmyJS8uq.woff2 +0 -0
- package/dist/client/assets/ibm-plex-sans-latin-ext-wght-normal-CIII54If.woff2 +0 -0
- package/dist/client/assets/ibm-plex-sans-latin-wght-normal-IvpUvPa2.woff2 +0 -0
- package/dist/client/assets/ibm-plex-sans-vietnamese-wght-normal-Dg1JeJN0.woff2 +0 -0
- package/dist/client/assets/index-CvwhlQ87.js +4 -0
- package/dist/client/assets/styles-BPWaGf55.js +3 -0
- package/dist/client/assets/styles-Dx1_KOag.css +1 -0
- package/dist/client/favicon.svg +1 -0
- package/dist/server/assets/auto-CVGNYyb3.js +12785 -0
- package/dist/server/assets/chunk-DDJLRBDX-3OUNo51g.js +4125 -0
- package/dist/server/assets/nodefs-DVSI7kG0.js +24 -0
- package/dist/server/assets/opfs-ahp-D56iokt1.js +388 -0
- package/dist/server/assets/token-Bvaq7Anz.js +55 -0
- package/dist/server/assets/token-util-BqSvdIPQ.js +3 -0
- package/dist/server/assets/token-util-CktFFT4z.js +494 -0
- package/dist/server/entry.js +91671 -0
- package/dist/server/favicon.svg +1 -0
- package/dist/server/index.html +161 -0
- package/index.html +159 -0
- package/internal/coding-agent/package.json +44 -0
- package/internal/coding-agent/src/drivers/byok.ts +322 -0
- package/internal/coding-agent/src/drivers/claude-code.ts +290 -0
- package/internal/coding-agent/src/drivers/codex.ts +281 -0
- package/internal/coding-agent/src/index.ts +56 -0
- package/internal/coding-agent/src/registry.ts +119 -0
- package/internal/coding-agent/src/roles/contract.ts +60 -0
- package/internal/coding-agent/src/roles/defaults.ts +134 -0
- package/internal/coding-agent/src/roles/handoff.ts +41 -0
- package/internal/coding-agent/src/roles/registry.ts +156 -0
- package/internal/coding-agent/src/roles/skills.ts +72 -0
- package/internal/coding-agent/src/roles/sync.ts +88 -0
- package/internal/coding-agent/src/types.ts +102 -0
- package/internal/coding-agent/src/workspace.ts +275 -0
- package/octane.config.ts +36 -0
- package/package.json +68 -0
- package/public/favicon.svg +1 -0
- package/public/og.png +0 -0
- package/src/App.tsrx +924 -0
- package/src/client/ApprovalHandoff.tsrx +39 -0
- package/src/client/ChatPane.tsrx +694 -0
- package/src/client/ConnectView.tsrx +86 -0
- package/src/client/DiffPane.tsrx +150 -0
- package/src/client/EjectModal.tsrx +571 -0
- package/src/client/GateResults.tsrx +60 -0
- package/src/client/GitHubSettingsModal.tsrx +219 -0
- package/src/client/NewSessionForm.tsrx +214 -0
- package/src/client/SessionBar.tsrx +151 -0
- package/src/client/SessionPicker.tsrx +472 -0
- package/src/client/SpecEditor.tsrx +109 -0
- package/src/client/SpecReviewCard.tsrx +321 -0
- package/src/client/WorkCard.tsrx +128 -0
- package/src/client/WorkbenchModal.tsrx +161 -0
- package/src/client/WorkspaceMenu.tsrx +100 -0
- package/src/client/api.ts +797 -0
- package/src/client/attachments.ts +73 -0
- package/src/client/dashboard.ts +46 -0
- package/src/client/github-settings.ts +48 -0
- package/src/client/highlight.ts +105 -0
- package/src/client/i18n.ts +32 -0
- package/src/client/locales/en.json +466 -0
- package/src/client/locales/pl.json +466 -0
- package/src/client/session-labels.ts +77 -0
- package/src/client/state.ts +108 -0
- package/src/index.ts +10 -0
- package/src/preview/PreviewHost.tsrx +373 -0
- package/src/preview/load-module.ts +16 -0
- package/src/server/attachments.ts +308 -0
- package/src/server/auto-review.ts +181 -0
- package/src/server/checkpoints.ts +90 -0
- package/src/server/config.ts +460 -0
- package/src/server/dashboard.ts +245 -0
- package/src/server/delivery/configuration.ts +193 -0
- package/src/server/delivery/git-pr.ts +1473 -0
- package/src/server/delivery/index.ts +83 -0
- package/src/server/delivery/local.ts +151 -0
- package/src/server/delivery/official-modules.ts +516 -0
- package/src/server/delivery/plan.ts +218 -0
- package/src/server/delivery/policies.ts +239 -0
- package/src/server/delivery/record.ts +41 -0
- package/src/server/delivery/steps.ts +464 -0
- package/src/server/delivery/types.ts +158 -0
- package/src/server/dependencies.ts +88 -0
- package/src/server/diff.ts +230 -0
- package/src/server/gates.ts +388 -0
- package/src/server/index.ts +139 -0
- package/src/server/path-guard.ts +282 -0
- package/src/server/planning.ts +749 -0
- package/src/server/platform-client.ts +189 -0
- package/src/server/preview-database-host.ts +340 -0
- package/src/server/preview-database-protocol.ts +163 -0
- package/src/server/preview-database-proxy.ts +356 -0
- package/src/server/preview-database.ts +109 -0
- package/src/server/preview-ipc.ts +15 -0
- package/src/server/preview-modules.ts +83 -0
- package/src/server/preview-revision.ts +44 -0
- package/src/server/preview-runtime.ts +467 -0
- package/src/server/preview-worker-manager.ts +477 -0
- package/src/server/preview-worker.ts +168 -0
- package/src/server/reference.ts +251 -0
- package/src/server/routes.ts +2258 -0
- package/src/server/runtime.ts +188 -0
- package/src/server/session-owner.ts +23 -0
- package/src/server/sessions.ts +849 -0
- package/src/server/spec.ts +471 -0
- package/src/server/turn-lifecycle.ts +56 -0
- package/src/server/turns.ts +993 -0
- package/src/server/workspace-install.ts +266 -0
- package/src/server/workspace-root.ts +73 -0
- package/src/styles.css +1573 -0
- package/vite.config.ts +134 -0
|
@@ -0,0 +1,188 @@
|
|
|
1
|
+
import { randomBytes } from 'node:crypto';
|
|
2
|
+
import {
|
|
3
|
+
createByokDriver,
|
|
4
|
+
createClaudeCodeDriver,
|
|
5
|
+
createCodexDriver,
|
|
6
|
+
createCodingAgentRegistry,
|
|
7
|
+
loadAgentRoles,
|
|
8
|
+
type AgentRoleDefinition,
|
|
9
|
+
type CodingAgentDriver,
|
|
10
|
+
type CodingAgentRegistry,
|
|
11
|
+
} from '#coding-agent';
|
|
12
|
+
import {
|
|
13
|
+
loadSandboxConfiguration,
|
|
14
|
+
openSecret,
|
|
15
|
+
saveSandboxConfiguration,
|
|
16
|
+
type SandboxConfiguration,
|
|
17
|
+
} from './config.ts';
|
|
18
|
+
import { PlatformClient, type PlatformAuthority } from './platform-client.ts';
|
|
19
|
+
import { SandboxSetupError } from './workspace-root.ts';
|
|
20
|
+
|
|
21
|
+
export interface SandboxConnection {
|
|
22
|
+
readonly connected: boolean;
|
|
23
|
+
readonly authority: PlatformAuthority | null;
|
|
24
|
+
readonly error: { readonly code: string; readonly message: string } | null;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export interface BrowserSession {
|
|
28
|
+
readonly id: string;
|
|
29
|
+
readonly token: string;
|
|
30
|
+
readonly authority: PlatformAuthority;
|
|
31
|
+
readonly createdAt: number;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/* Matches the cookie lifetime, so a session the browser still presents is
|
|
35
|
+
also one the server still honours. */
|
|
36
|
+
export const BROWSER_SESSION_TTL_MS = 12 * 60 * 60 * 1000;
|
|
37
|
+
|
|
38
|
+
export interface SandboxRuntime {
|
|
39
|
+
readonly workspaceRoot: string;
|
|
40
|
+
configuration(): SandboxConfiguration;
|
|
41
|
+
registry(): CodingAgentRegistry;
|
|
42
|
+
roles(): readonly AgentRoleDefinition[];
|
|
43
|
+
platform(): PlatformClient | null;
|
|
44
|
+
connection(): SandboxConnection;
|
|
45
|
+
refresh(): Promise<SandboxConnection>;
|
|
46
|
+
update(patch: Partial<SandboxConfiguration>): Promise<SandboxConnection>;
|
|
47
|
+
/* Self-hosted sandboxes keep one browser session per operator token. A
|
|
48
|
+
loopback sandbox uses the configured connection directly. */
|
|
49
|
+
openBrowserSession(token: string): Promise<BrowserSession>;
|
|
50
|
+
browserSession(id: string | null): BrowserSession | null;
|
|
51
|
+
closeBrowserSession(id: string): void;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
async function buildDrivers(
|
|
55
|
+
workspaceRoot: string,
|
|
56
|
+
configuration: SandboxConfiguration,
|
|
57
|
+
): Promise<readonly CodingAgentDriver[]> {
|
|
58
|
+
const drivers: CodingAgentDriver[] = [
|
|
59
|
+
createClaudeCodeDriver({ defaultModel: configuration.driverModel }),
|
|
60
|
+
createCodexDriver({ defaultModel: configuration.driverModel }),
|
|
61
|
+
];
|
|
62
|
+
if (configuration.byok) {
|
|
63
|
+
const credential = configuration.byok.credential
|
|
64
|
+
? await openSecret(workspaceRoot, configuration.byok.credential)
|
|
65
|
+
: '';
|
|
66
|
+
drivers.push(
|
|
67
|
+
createByokDriver({
|
|
68
|
+
configuration: {
|
|
69
|
+
kind: configuration.byok.kind,
|
|
70
|
+
model: configuration.byok.model,
|
|
71
|
+
credential,
|
|
72
|
+
...(configuration.byok.resourceName
|
|
73
|
+
? { resourceName: configuration.byok.resourceName }
|
|
74
|
+
: {}),
|
|
75
|
+
...(configuration.byok.baseURL
|
|
76
|
+
? { baseURL: configuration.byok.baseURL }
|
|
77
|
+
: {}),
|
|
78
|
+
},
|
|
79
|
+
}),
|
|
80
|
+
);
|
|
81
|
+
}
|
|
82
|
+
return drivers;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
export async function createSandboxRuntime(
|
|
86
|
+
workspaceRoot: string,
|
|
87
|
+
): Promise<SandboxRuntime> {
|
|
88
|
+
let configuration = await loadSandboxConfiguration(workspaceRoot);
|
|
89
|
+
let roles = await loadAgentRoles(workspaceRoot);
|
|
90
|
+
let registry = createCodingAgentRegistry({
|
|
91
|
+
mode: configuration.mode,
|
|
92
|
+
drivers: await buildDrivers(workspaceRoot, configuration),
|
|
93
|
+
});
|
|
94
|
+
let platform: PlatformClient | null = null;
|
|
95
|
+
let connection: SandboxConnection = {
|
|
96
|
+
connected: false,
|
|
97
|
+
authority: null,
|
|
98
|
+
error: null,
|
|
99
|
+
};
|
|
100
|
+
const browserSessions = new Map<string, BrowserSession>();
|
|
101
|
+
|
|
102
|
+
const rebuild = async (): Promise<SandboxConnection> => {
|
|
103
|
+
roles = await loadAgentRoles(workspaceRoot);
|
|
104
|
+
registry = createCodingAgentRegistry({
|
|
105
|
+
mode: configuration.mode,
|
|
106
|
+
drivers: await buildDrivers(workspaceRoot, configuration),
|
|
107
|
+
});
|
|
108
|
+
if (!configuration.platformToken) {
|
|
109
|
+
platform = null;
|
|
110
|
+
connection = {
|
|
111
|
+
connected: false,
|
|
112
|
+
authority: null,
|
|
113
|
+
error: {
|
|
114
|
+
code: 'PLATFORM_TOKEN_MISSING',
|
|
115
|
+
message:
|
|
116
|
+
'Paste an API token from the Flowdular application to connect this sandbox.',
|
|
117
|
+
},
|
|
118
|
+
};
|
|
119
|
+
return connection;
|
|
120
|
+
}
|
|
121
|
+
platform = new PlatformClient({
|
|
122
|
+
platformUrl: configuration.platformUrl,
|
|
123
|
+
token: await openSecret(workspaceRoot, configuration.platformToken),
|
|
124
|
+
});
|
|
125
|
+
try {
|
|
126
|
+
const authority = await platform.authority();
|
|
127
|
+
connection = { connected: true, authority, error: null };
|
|
128
|
+
} catch (error) {
|
|
129
|
+
connection = {
|
|
130
|
+
connected: false,
|
|
131
|
+
authority: null,
|
|
132
|
+
error:
|
|
133
|
+
error instanceof SandboxSetupError
|
|
134
|
+
? { code: error.code, message: error.message }
|
|
135
|
+
: {
|
|
136
|
+
code: 'PLATFORM_UNREACHABLE',
|
|
137
|
+
message: `The sandbox could not reach ${configuration.platformUrl}.`,
|
|
138
|
+
},
|
|
139
|
+
};
|
|
140
|
+
}
|
|
141
|
+
return connection;
|
|
142
|
+
};
|
|
143
|
+
|
|
144
|
+
await rebuild();
|
|
145
|
+
|
|
146
|
+
return {
|
|
147
|
+
workspaceRoot,
|
|
148
|
+
configuration: () => configuration,
|
|
149
|
+
registry: () => registry,
|
|
150
|
+
roles: () => roles,
|
|
151
|
+
platform: () => platform,
|
|
152
|
+
connection: () => connection,
|
|
153
|
+
refresh: rebuild,
|
|
154
|
+
update: async (patch) => {
|
|
155
|
+
configuration = await saveSandboxConfiguration(workspaceRoot, {
|
|
156
|
+
...configuration,
|
|
157
|
+
...patch,
|
|
158
|
+
version: 1,
|
|
159
|
+
});
|
|
160
|
+
return rebuild();
|
|
161
|
+
},
|
|
162
|
+
openBrowserSession: async (token) => {
|
|
163
|
+
const client = new PlatformClient({
|
|
164
|
+
platformUrl: configuration.platformUrl,
|
|
165
|
+
token,
|
|
166
|
+
});
|
|
167
|
+
const authority = await client.authority();
|
|
168
|
+
if (!authority.authority.granted) {
|
|
169
|
+
throw new SandboxSetupError(
|
|
170
|
+
'SANDBOX_ACCESS_DENIED',
|
|
171
|
+
'This account has no active sandbox grant in the connected workspace.',
|
|
172
|
+
);
|
|
173
|
+
}
|
|
174
|
+
const session: BrowserSession = {
|
|
175
|
+
id: randomBytes(24).toString('base64url'),
|
|
176
|
+
token,
|
|
177
|
+
authority,
|
|
178
|
+
createdAt: Date.now(),
|
|
179
|
+
};
|
|
180
|
+
browserSessions.set(session.id, session);
|
|
181
|
+
return session;
|
|
182
|
+
},
|
|
183
|
+
browserSession: (id) => (id ? (browserSessions.get(id) ?? null) : null),
|
|
184
|
+
closeBrowserSession: (id) => {
|
|
185
|
+
browserSessions.delete(id);
|
|
186
|
+
},
|
|
187
|
+
};
|
|
188
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import type { SandboxSession, SessionOwner } from './sessions.ts';
|
|
2
|
+
|
|
3
|
+
export function ownsSession(
|
|
4
|
+
session: SandboxSession,
|
|
5
|
+
owner: SessionOwner | null,
|
|
6
|
+
): boolean {
|
|
7
|
+
return Boolean(
|
|
8
|
+
owner &&
|
|
9
|
+
session.owner &&
|
|
10
|
+
session.owner.accountId === owner.accountId &&
|
|
11
|
+
session.owner.tenantId === owner.tenantId &&
|
|
12
|
+
session.owner.platformUrl.replace(/\/+$/, '') ===
|
|
13
|
+
owner.platformUrl.replace(/\/+$/, ''),
|
|
14
|
+
);
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export function canReadSession(
|
|
18
|
+
session: SandboxSession,
|
|
19
|
+
owner: SessionOwner | null,
|
|
20
|
+
local: boolean,
|
|
21
|
+
): boolean {
|
|
22
|
+
return ownsSession(session, owner) || (local && !session.owner);
|
|
23
|
+
}
|