Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
128 commits
Select commit Hold shift + click to select a range
d57efd3
fix(den-api): build on Windows
pascalandr May 22, 2026
636c597
feat(desktop): support managed bootstrap state
pascalandr May 22, 2026
bdcc37f
feat(den): support static worker provisioner
pascalandr May 22, 2026
f7ebab2
feat(den): support Entra SSO auto-join
pascalandr May 22, 2026
1304e7d
docs(docker): clean up on-prem runbooks
pascalandr May 22, 2026
af01579
fix(desktop): update bootstrap dependency lockfile
pascalandr May 22, 2026
a33f24f
test(den): keep provisioner tests isolated
pascalandr May 22, 2026
9aef096
feat(den): secure static worker attach
pascalandr May 22, 2026
e1b5888
test(den): cover static attach security
pascalandr May 22, 2026
928a08f
fix(den): make demo seed script portable
pascalandr May 23, 2026
d28b45f
feat(den): sync managed providers to workers
pascalandr May 22, 2026
f592203
fix(server): restore managed provider auth apply
pascalandr May 23, 2026
542a3dc
fix(den): harden provider sync verification
pascalandr May 22, 2026
2860334
feat(den): add provider credential contract base
pascalandr May 23, 2026
9776240
fix(den): treat empty provider sync as applied
pascalandr May 23, 2026
c7ae20f
feat(den): handle OAuth provider credentials
pascalandr May 23, 2026
c53a9cf
fix: type worker organization context
pascalandr May 23, 2026
d91928e
feat(den): add OpenAI OAuth provider flow
pascalandr May 23, 2026
d4b14c4
feat(den): add provider credential contract base
pascalandr May 23, 2026
efdefad
feat(den): handle OAuth provider credentials
pascalandr May 23, 2026
32b39e7
feat(app): import OAuth-backed Den providers
pascalandr May 23, 2026
bf09ed3
fix(server): restore managed provider auth apply
pascalandr May 23, 2026
f7ce71c
fix: TASK-2026-05-26-017 sanitize managed provider model config
pascalandr May 27, 2026
2a26ba3
fix: TASK-2026-05-26-020 filter managed OAuth models
pascalandr May 27, 2026
3690f38
fix: TASK-2026-05-26-021 handle live provider shapes
pascalandr May 28, 2026
976b68c
feat(den): add OpenAI OAuth provider flow
pascalandr May 23, 2026
e5fcafa
fix: TASK-2026-05-26-014 sync managed providers to remote workers
pascalandr May 26, 2026
4dbe93f
fix: TASK-2026-05-26-020 guard managed model picker
pascalandr May 27, 2026
5f52352
merge: TASK-2026-05-26-023 resolve PR 1939 with upstream dev
pascalandr May 28, 2026
7238bb5
chore: resolve pr 1891 conflicts
pascalandr May 28, 2026
0fe5587
chore: resolve pr 1895 conflicts
pascalandr May 28, 2026
0391a6a
chore: resolve pr 1940 conflicts
pascalandr May 28, 2026
e1ba67b
chore: resolve pr 1941 conflicts
pascalandr May 28, 2026
596108c
fix: TASK-2026-05-26-024 surface managed provider connections
pascalandr May 28, 2026
396af65
fix: TASK-2026-05-26-024 apply managed provider auth
pascalandr May 28, 2026
4112a09
fix: TASK-2026-05-26-024 persist Den remote workspace metadata
pascalandr May 28, 2026
0a9862b
fix: TASK-2026-05-28-002 address browser MCP review
pascalandr May 28, 2026
bc58883
merge: TASK-2026-05-28-007 resolve PR 1894 conflicts
pascalandr May 28, 2026
9fba3bf
fix: TASK-2026-05-28-008 address PR 1939 reviews
pascalandr May 28, 2026
c5ae1c6
test: TASK-2026-05-28-008 cover PR 1941 reviews
pascalandr May 28, 2026
95fa681
docs(docker): simplify static deployment runbook
pascalandr Jun 4, 2026
1db5746
fix(desktop): support Den cloud handoff on custom hosts
pascalandr Jun 4, 2026
824c2e4
Merge remote-tracking branch 'upstream/dev' into pr/docker-onprem-run…
pascalandr Jun 4, 2026
ec990c0
Merge remote-tracking branch 'upstream/dev' into pr/static-provisione…
pascalandr Jun 4, 2026
f8c5570
Merge remote-tracking branch 'upstream/dev' into pr/den-api-windows-b…
pascalandr Jun 4, 2026
da26fff
Merge remote-tracking branch 'upstream/dev' into pr/managed-desktop-b…
pascalandr Jun 4, 2026
53a67e1
Merge remote-tracking branch 'upstream/dev' into pr/static-worker-att…
pascalandr Jun 4, 2026
af32033
fix(app): clean cloud worker merge marker
pascalandr Jun 4, 2026
f0df4fd
Merge remote-tracking branch 'upstream/dev' into pr/entra-sso-auto-join
pascalandr Jun 4, 2026
81f6673
Merge remote-tracking branch 'upstream/dev' into pr/den-oauth-provide…
pascalandr Jun 4, 2026
08aa051
Merge remote-tracking branch 'upstream/dev' into pr/credential-contra…
pascalandr Jun 4, 2026
c8d97ca
Merge remote-tracking branch 'upstream/dev' into pr/desktop-import-oa…
pascalandr Jun 4, 2026
33a1f4f
fix: TASK-2026-06-05-001 resolve managed desktop PR review
pascalandr Jun 5, 2026
3736a07
fix: TASK-2026-06-05-001 serialize static worker quota checks
pascalandr Jun 5, 2026
cf99a3c
fix: TASK-2026-06-05-001 cache docker dependency install
pascalandr Jun 5, 2026
c29208e
fix: TASK-2026-06-05-001 restore managed provider config writer
pascalandr Jun 5, 2026
fdd0a38
fix: TASK-2026-06-05-001 align oauth migration test
pascalandr Jun 5, 2026
09c4461
fix: TASK-2026-06-05-001 remove duplicate bootstrap normalizer
pascalandr Jun 5, 2026
2659f50
fix: bump bundled opencode (#2103)
src-opn Jun 9, 2026
d444c16
chore: release v0.15.3
src-opn Jun 9, 2026
f54b60f
Merge remote-tracking branch 'upstream/dev' into pr/den-oauth-provide…
pascalandr Jun 9, 2026
e7cfa82
Merge remote-tracking branch 'upstream/dev' into pr/desktop-import-oa…
pascalandr Jun 9, 2026
0938ba5
Merge remote-tracking branch 'upstream/dev' into pr/credential-contra…
pascalandr Jun 9, 2026
d34c194
Merge remote-tracking branch 'upstream/dev' into pr/docker-onprem-run…
pascalandr Jun 9, 2026
ed8a685
Merge remote-tracking branch 'upstream/dev' into pr/entra-sso-auto-join
pascalandr Jun 9, 2026
ae825dc
Merge remote-tracking branch 'upstream/dev' into pr/static-worker-att…
pascalandr Jun 9, 2026
a321efb
Merge remote-tracking branch 'upstream/dev' into pr/static-provisione…
pascalandr Jun 9, 2026
e5787a8
Merge remote-tracking branch 'upstream/dev' into pr/den-api-windows-b…
pascalandr Jun 9, 2026
fe3229d
Merge remote-tracking branch 'upstream/dev' into pr/managed-desktop-b…
pascalandr Jun 9, 2026
32f4764
chore(aur): update PKGBUILD for 0.15.3
release-bot Jun 9, 2026
68d1a5d
fix(app): tighten session composer spacing (#2104)
src-opn Jun 9, 2026
4eca192
fix(app): persist steps disclosure and cap images (#2105)
src-opn Jun 9, 2026
f2b8205
fix: render artifacts inline (#2106)
src-opn Jun 9, 2026
4e40dd3
fix(docker): make static deployment images build from source
pascalandr Jun 9, 2026
6c59e6b
ignore: update download stats 2026-06-09
actions-user Jun 9, 2026
4334240
docs(runbook): clarify static deployment verification flow
pascalandr Jun 9, 2026
ffcccaa
fix(den): restore static signup worker provisioning
pascalandr Jun 9, 2026
370948e
fix(desktop): connect cloud onboarding to remote workers
pascalandr Jun 9, 2026
1bd73bf
docs(docker): expose static attach policy env
pascalandr Jun 9, 2026
b62fb90
fix(den): align generated desktop app version
pascalandr Jun 9, 2026
303f3ed
Update Models (#2107)
src-opn Jun 9, 2026
1c5a329
fix(docker): pin and verify Bun install
pascalandr Jun 9, 2026
0b904c6
fix(den): harden static signup worker responses
pascalandr Jun 9, 2026
54721ed
fix(docker): select Bun artifact by target arch
pascalandr Jun 9, 2026
8fdf6e3
Merge pr/den-api-windows-build into dev-0.15.3
pascalandr Jun 9, 2026
6b18fca
Merge pr/managed-desktop-bootstrap into dev-0.15.3
pascalandr Jun 9, 2026
fe6c1ab
Merge pr/static-provisioner-backend into dev-0.15.3
pascalandr Jun 9, 2026
e629ab2
Merge pr/static-worker-attach-security into dev-0.15.3
pascalandr Jun 9, 2026
5abdccf
Merge pr/entra-sso-auto-join into dev-0.15.3
pascalandr Jun 9, 2026
38a58ac
Merge pr/docker-onprem-runbook into dev-0.15.3
pascalandr Jun 9, 2026
f7e7e86
Merge pr/credential-contract-managed-sync into dev-0.15.3
pascalandr Jun 9, 2026
1c76acd
Merge pr/den-oauth-provider-flow into dev-0.15.3
pascalandr Jun 9, 2026
b246591
Merge pr/desktop-import-oauth-den-providers into dev-0.15.3
pascalandr Jun 9, 2026
7e758e6
fix(integration): resolve dev-0.15.3 merge regressions
pascalandr Jun 9, 2026
8638399
fix: TASK-2026-06-09-002 harden static Docker provisioning
pascalandr Jun 9, 2026
8b35e83
fix: TASK-2026-06-09-002 repair invite and SSO membership flows
pascalandr Jun 9, 2026
07474f0
fix: TASK-2026-06-09-002 make managed provider sync authoritative
pascalandr Jun 9, 2026
aea30ac
fix: TASK-2026-06-09-002 scope host-token bootstrap access
pascalandr Jun 9, 2026
0c00087
fix: TASK-2026-06-09-002 guard LLM provider access lifecycle
pascalandr Jun 9, 2026
b1e1350
fix: TASK-2026-06-09-002 preserve cloud managed provider identity
pascalandr Jun 9, 2026
764466c
merge: TASK-2026-06-09-002 integrate docker remediation
pascalandr Jun 9, 2026
acd97ec
merge: TASK-2026-06-09-002 integrate Entra invitation remediation
pascalandr Jun 9, 2026
fe09804
merge: TASK-2026-06-09-002 integrate managed credential sync remediation
pascalandr Jun 9, 2026
6d8d90e
merge: TASK-2026-06-09-002 integrate bootstrap security remediation
pascalandr Jun 9, 2026
5f96d31
merge: TASK-2026-06-09-002 integrate provider OAuth access remediation
pascalandr Jun 9, 2026
624976c
merge: TASK-2026-06-09-002 integrate desktop provider import remediation
pascalandr Jun 9, 2026
5514598
test: TASK-2026-06-09-002 cover browser page callbacks
pascalandr Jun 9, 2026
6079aea
merge: TASK-2026-06-09-002 integrate browser callback test
pascalandr Jun 9, 2026
4a245ad
test: TASK-2026-06-09-002 align provider sync proxy auth
pascalandr Jun 9, 2026
63fe351
merge: TASK-2026-06-09-002 integrate provider sync proxy-auth tests
pascalandr Jun 9, 2026
f5bde5d
test: TASK-2026-06-09-002 typecheck browser callback test
pascalandr Jun 9, 2026
a7cb850
merge: TASK-2026-06-09-002 integrate browser callback typecheck fix
pascalandr Jun 9, 2026
a76df15
fix: TASK-2026-06-09-002 type invitation member claim
pascalandr Jun 9, 2026
9d6f5a6
merge: TASK-2026-06-09-002 integrate invitation member type fix
pascalandr Jun 9, 2026
efcb923
fix: TASK-2026-06-09-002 keep host token off workspace discovery
pascalandr Jun 9, 2026
d802374
test: TASK-2026-06-09-002 cover invitation token lifecycle
pascalandr Jun 9, 2026
fc4f9e5
merge: TASK-2026-06-09-002 close desktop host-token discovery gap
pascalandr Jun 9, 2026
d7825d4
merge: TASK-2026-06-09-002 add invitation lifecycle evidence
pascalandr Jun 9, 2026
09a1e4b
fix: TASK-2026-06-10-005 repair invitation member lifecycle
pascalandr Jun 10, 2026
fc10acb
fix: TASK-2026-06-10-005 defer stale auth deletion
pascalandr Jun 10, 2026
2ffcceb
fix: TASK-2026-06-10-005 show invited provider members
pascalandr Jun 10, 2026
b758d46
merge: TASK-2026-06-10-005 integrate PR1895 review fixes
pascalandr Jun 10, 2026
30d38b3
merge: TASK-2026-06-10-005 integrate PR1939 review fixes
pascalandr Jun 10, 2026
56b12be
merge: TASK-2026-06-10-005 integrate PR1940 review fixes
pascalandr Jun 10, 2026
79913b5
fix: TASK-2026-06-10-005 retry stale auth cleanup
pascalandr Jun 10, 2026
d9c2e07
fix: TASK-2026-06-10-005 parse invited provider access
pascalandr Jun 10, 2026
b02e67e
merge: TASK-2026-06-10-005 integrate PR1939 retry cleanup
pascalandr Jun 10, 2026
403fd44
merge: TASK-2026-06-10-005 integrate PR1940 parser contract
pascalandr Jun 10, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions .dockerignore
Original file line number Diff line number Diff line change
@@ -1,10 +1,14 @@
.git
.github
.opencode
.codenomad
node_modules
**/node_modules
tmp
dist
**/dist
artifacts
apps/desktop/src-tauri/target
**/target
.env
.env.*
1 change: 1 addition & 0 deletions STATS.md
Original file line number Diff line number Diff line change
Expand Up @@ -142,3 +142,4 @@ Legacy cumulative release-asset totals. For classified v2 buckets, see `STATS_V2
| 2026-06-06 | 988,487 (+5,040) | 988,487 (+5,040) |
| 2026-06-07 | 992,289 (+3,802) | 992,289 (+3,802) |
| 2026-06-08 | 997,450 (+5,161) | 997,450 (+5,161) |
| 2026-06-09 | 1,002,601 (+5,151) | 1,002,601 (+5,151) |
1 change: 1 addition & 0 deletions STATS_V2.md
Original file line number Diff line number Diff line change
Expand Up @@ -98,3 +98,4 @@ Classified GitHub release asset snapshots. `Manual installs` counts installer do
| 2026-06-06 | 124,222 (+784) | 690,834 (+66) | 173,431 (+4,190) | 988,487 (+5,040) |
| 2026-06-07 | 124,760 (+538) | 690,875 (+41) | 176,654 (+3,223) | 992,289 (+3,802) |
| 2026-06-08 | 125,538 (+778) | 690,913 (+38) | 180,999 (+4,345) | 997,450 (+5,161) |
| 2026-06-09 | 126,150 (+612) | 690,953 (+40) | 185,498 (+4,499) | 1,002,601 (+5,151) |
4 changes: 2 additions & 2 deletions apps/app/package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "@openwork/app",
"private": true,
"version": "0.15.2",
"version": "0.15.3",
"type": "module",
"scripts": {
"dev": "OPENWORK_DEV_MODE=1 vite",
Expand Down Expand Up @@ -50,7 +50,7 @@
"@fontsource-variable/ibm-plex-sans": "^5.2.8",
"@heroicons/react": "^2.2.0",
"@lexical/react": "^0.35.0",
"@opencode-ai/sdk": "^1.15.12",
"@opencode-ai/sdk": "^1.16.2",
"@openwork/types": "workspace:*",
"@openwork/ui": "workspace:*",
"@paper-design/shaders-react": "0.0.72",
Expand Down
54 changes: 53 additions & 1 deletion apps/app/scripts/artifacts.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { describe, expect, it } from "bun:test";
import type { UIMessage } from "ai";

import type { OpenTarget } from "../src/react-app/domains/session/artifacts/open-target";
import { getArtifactsFromMessages } from "../src/lib/artifacts";
import { canPreviewArtifact, getArtifactsFromMessages } from "../src/lib/artifacts";

describe("getArtifactsFromMessages", () => {
it("includes verified slide deck targets mentioned in assistant summaries", () => {
Expand Down Expand Up @@ -58,4 +58,56 @@ describe("getArtifactsFromMessages", () => {
exists: true,
});
});

it("can list artifacts from assistant text without target fallbacks", () => {
const messages: UIMessage[] = [{
id: "msg_text",
role: "assistant",
parts: [{ type: "text", text: "Created reports/artifact-eval.md, decks/update.pptx, and src/widget.tsx", state: "done" }],
}];

expect(getArtifactsFromMessages(messages, [], { includeTargetFallbacks: false }).map((artifact) => artifact.path)).toEqual([
"src/widget.tsx",
"decks/update.pptx",
"reports/artifact-eval.md",
]);
});

it("orders verified artifacts by newest update time and marks unsupported previews", () => {
const messages: UIMessage[] = [{
id: "msg_order",
role: "assistant",
parts: [{ type: "text", text: "Created reports/old.md and reports/new.md and src/widget.tsx", state: "done" }],
}];
const targets: OpenTarget[] = [
{
id: "file:reports/old.md",
kind: "file",
value: "reports/old.md",
name: "old.md",
preview: "markdown",
confidence: 65,
reason: "message",
exists: true,
updatedAt: 1,
},
{
id: "file:reports/new.md",
kind: "file",
value: "reports/new.md",
name: "new.md",
preview: "markdown",
confidence: 65,
reason: "message",
exists: true,
updatedAt: 2,
},
];

const artifacts = getArtifactsFromMessages(messages, targets, { includeTargetFallbacks: false });

expect(artifacts.map((artifact) => artifact.path)).toEqual(["reports/new.md", "reports/old.md", "src/widget.tsx"]);
expect(canPreviewArtifact(artifacts[0])).toBe(true);
expect(canPreviewArtifact(artifacts[2])).toBe(false);
});
});
63 changes: 63 additions & 0 deletions apps/app/src/app/cloud/managed-provider-models.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
import type { CloudImportedProvider } from "./import-state";
import type { ModelOption, ProviderListItem } from "../types";

export function buildCloudManagedModelIdsByProvider(
importedCloudProviders: Record<string, CloudImportedProvider> | null | undefined,
): Map<string, Set<string>> {
const next = new Map<string, Set<string>>();
for (const imported of Object.values(importedCloudProviders ?? {})) {
const providerId = imported.providerId.trim();
if (!providerId) continue;
const modelIds = imported.modelIds.map((id) => id.trim()).filter(Boolean);
if (!modelIds.length) continue;
const merged = next.get(providerId) ?? new Set<string>();
for (const modelId of modelIds) merged.add(modelId);
next.set(providerId, merged);
}
return next;
}

export function isCloudManagedModelAllowed(
cloudManagedModelIdsByProvider: Map<string, Set<string>>,
providerId: string,
modelId: string,
) {
const allowedModelIds = cloudManagedModelIdsByProvider.get(providerId);
return !allowedModelIds || allowedModelIds.has(modelId);
}

export function hasCloudManagedModelAllowlist(
cloudManagedModelIdsByProvider: Map<string, Set<string>>,
providerId: string,
) {
return cloudManagedModelIdsByProvider.has(providerId);
}

export function buildCloudManagedModelOptions(input: {
providers: ProviderListItem[];
cloudManagedModelIdsByProvider: Map<string, Set<string>>;
isRecommendedProvider?: (providerId: string) => boolean;
}): ModelOption[] {
const options: ModelOption[] = [];
for (const provider of input.providers) {
const isCloudManaged = hasCloudManagedModelAllowlist(input.cloudManagedModelIdsByProvider, provider.id);
for (const [modelId, model] of Object.entries(provider.models)) {
if (!isCloudManagedModelAllowed(input.cloudManagedModelIdsByProvider, provider.id, modelId)) continue;
options.push({
providerID: provider.id,
modelID: modelId,
title: model.name || modelId,
description: provider.name,
behaviorTitle: "Reasoning",
behaviorLabel: "Default",
behaviorDescription: "",
behaviorValue: null,
isFree: false,
isConnected: true,
isRecommended: input.isRecommendedProvider?.(provider.id),
source: isCloudManaged || /^lpr_/i.test(provider.id) ? "cloud" : undefined,
});
}
}
return options;
}
107 changes: 106 additions & 1 deletion apps/app/src/app/lib/den.ts
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,15 @@ export type DenWorkerTokens = {
workspaceId: string | null;
};

export type DenStaticWorkerAttachInput = {
name: string;
description?: string | null;
url: string;
clientToken: string;
hostToken: string;
activityToken?: string | null;
};

export type DenOrgLlmProviderModel = {
id: string;
name: string;
Expand All @@ -121,17 +130,29 @@ export type DenOrgLlmProviderModel = {
export type DenOrgLlmProvider = {
id: string;
source: "models_dev" | "custom" | "openwork";
credentialKind: "api_key" | "opencode_oauth";
providerId: string;
name: string;
providerConfig: Record<string, unknown>;
hasApiKey: boolean;
hasOpencodeAuth: boolean;
hasCredential: boolean;
models: DenOrgLlmProviderModel[];
createdAt: string | null;
updatedAt: string | null;
};

export type DenOrgLlmProviderConnection = DenOrgLlmProvider & {
apiKey: string | null;
opencodeAuth: string | null;
};

export type DenManagedProviderSyncResult = {
status: "applied" | "failed";
providerCount: number;
revision: string;
providerIds?: string[];
reason?: string;
};

export type DenPluginConfigObjectType = "skill" | "agent" | "command" | "tool" | "mcp" | "hook" | "context" | "custom";
Expand Down Expand Up @@ -562,8 +583,20 @@ function syncBootstrapSettingsToLocalStorage(config: DenBootstrapConfig) {
return;
}

const previousBaseUrl = window.localStorage.getItem(STORAGE_BASE_URL);
const previousOrigin = normalizeDenBaseUrl(previousBaseUrl) ?? "";
const nextOrigin = normalizeDenBaseUrl(config.baseUrl) ?? "";
const denOriginChanged = Boolean(previousOrigin && nextOrigin && previousOrigin !== nextOrigin);

window.localStorage.setItem(STORAGE_BASE_URL, config.baseUrl);
window.localStorage.setItem(STORAGE_API_BASE_URL, config.apiBaseUrl);

if (denOriginChanged) {
window.localStorage.removeItem(STORAGE_AUTH_TOKEN);
window.localStorage.removeItem(STORAGE_ACTIVE_ORG_ID);
window.localStorage.removeItem(STORAGE_ACTIVE_ORG_SLUG);
window.localStorage.removeItem(STORAGE_ACTIVE_ORG_NAME);
}
}

function getPendingBootstrapConfig(next: DenSettings): DenBootstrapConfig | null {
Expand Down Expand Up @@ -1028,10 +1061,13 @@ function parseDenOrgLlmProvider(value: unknown): DenOrgLlmProvider | null {
return {
id: value.id,
source: value.source,
credentialKind: value.credentialKind === "opencode_oauth" ? "opencode_oauth" : "api_key",
providerId: value.providerId,
name: value.name,
providerConfig: parseJsonRecord(value.providerConfig),
hasApiKey: value.hasApiKey === true,
hasOpencodeAuth: value.hasOpencodeAuth === true,
hasCredential: value.hasCredential === true || value.hasApiKey === true || value.hasOpencodeAuth === true,
models: Array.isArray(value.models)
? value.models.flatMap((model) => {
const parsed = parseDenOrgLlmProviderModel(model);
Expand Down Expand Up @@ -1067,6 +1103,28 @@ function getDenOrgLlmProviderConnection(payload: unknown): DenOrgLlmProviderConn
return {
...provider,
apiKey: typeof payload.llmProvider.apiKey === "string" ? payload.llmProvider.apiKey : null,
opencodeAuth: typeof payload.llmProvider.opencodeAuth === "string" ? payload.llmProvider.opencodeAuth : null,
};
}

function getDenManagedProviderSyncResult(payload: unknown): DenManagedProviderSyncResult | null {
if (!isRecord(payload)) return null;
if (payload.status !== "applied" && payload.status !== "failed") return null;
if (typeof payload.providerCount !== "number" || !Number.isInteger(payload.providerCount) || payload.providerCount < 0) return null;
if (typeof payload.revision !== "string") return null;
const rawProviderIds = Array.isArray(payload.providerIds)
? payload.providerIds
: Array.isArray(payload.appliedProviderIds)
? payload.appliedProviderIds
: undefined;
const providerIds = rawProviderIds ? readStringArray(rawProviderIds) : undefined;
if (rawProviderIds && providerIds?.length !== payload.providerCount) return null;
return {
status: payload.status,
providerCount: payload.providerCount,
revision: payload.revision,
...(providerIds ? { providerIds } : {}),
...(typeof payload.reason === "string" ? { reason: payload.reason } : {}),
};
}

Expand Down Expand Up @@ -1818,6 +1876,32 @@ export function createDenClient(options: { baseUrl: string; apiBaseUrl?: string
return tokens;
},

async attachStaticWorker(orgId: string, input: DenStaticWorkerAttachInput): Promise<DenWorkerSummary> {
const payload = await requestJson<unknown>(baseUrls, "/v1/workers/static-attach", {
method: "POST",
token,
organizationId: orgId,
body: {
name: input.name,
description: input.description ?? undefined,
url: input.url,
clientToken: input.clientToken,
hostToken: input.hostToken,
activityToken: input.activityToken ?? undefined,
},
});
const workers = getWorkers({
workers: isRecord(payload) && isRecord(payload.worker)
? [{ ...payload.worker, instance: isRecord(payload.instance) ? payload.instance : null }]
: [],
});
const worker = workers[0];
if (!worker) {
throw new DenApiError(500, "invalid_worker_attach_payload", "Static worker attach response was missing worker details.");
}
return worker;
},

async listOrgSkills(orgId: string): Promise<DenOrgSkillCard[]> {
const payload = await requestJson<unknown>(baseUrls, "/v1/skills", {
method: "GET",
Expand Down Expand Up @@ -1891,7 +1975,7 @@ export function createDenClient(options: { baseUrl: string; apiBaseUrl?: string
async getOrgLlmProviderConnection(orgId: string, llmProviderId: string): Promise<DenOrgLlmProviderConnection> {
const payload = await requestJson<unknown>(
baseUrls,
`/v1/llm-providers/${encodeURIComponent(llmProviderId)}/connect`,
`/v1/llm-providers/${encodeURIComponent(llmProviderId)}/import-credential`,
{
method: "GET",
token,
Expand All @@ -1905,6 +1989,27 @@ export function createDenClient(options: { baseUrl: string; apiBaseUrl?: string
return provider;
},

async syncWorkerManagedProviders(orgId: string, workerId: string): Promise<DenManagedProviderSyncResult> {
const payload = await requestJson<unknown>(
baseUrls,
`/v1/workers/${encodeURIComponent(workerId)}/managed-providers/sync`,
{
method: "POST",
token,
organizationId: orgId,
body: {},
},
);
const result = getDenManagedProviderSyncResult(payload);
if (!result) {
throw new DenApiError(500, "invalid_managed_provider_sync_payload", "Managed provider sync response was invalid.");
}
if (result.status !== "applied") {
throw new DenApiError(502, "managed_provider_sync_failed", result.reason ?? "Managed provider sync failed.");
}
return result;
},

async listOrgMarketplaces(orgId: string): Promise<DenOrgMarketplace[]> {
const payload = await requestJson<unknown>(
baseUrls,
Expand Down
3 changes: 3 additions & 0 deletions apps/app/src/app/lib/desktop-types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,9 @@ export type WorkspaceInfo = {
openworkHostToken?: string | null;
openworkWorkspaceId?: string | null;
openworkWorkspaceName?: string | null;
openworkDenBaseUrl?: string | null;
openworkDenOrgId?: string | null;
openworkDenWorkerId?: string | null;
sandboxBackend?: "docker" | "microsandbox" | null;
sandboxRunId?: string | null;
sandboxContainerName?: string | null;
Expand Down
Loading
Loading