@agent-native/core 0.146.8 → 0.147.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/corpus/README.md +1 -1
- package/corpus/templates/analytics/.agents/skills/turn-into-app/SKILL.md +18 -6
- package/corpus/templates/analytics/.agents/skills/turn-into-app/references/fresh-project.md +8 -1
- package/corpus/templates/analytics/app/routes/status.$slug.tsx +4 -2
- package/corpus/templates/analytics/scripts/first-party-analytics-bigquery-backfill.ts +56 -6
- package/corpus/templates/assets/.agents/skills/turn-into-app/SKILL.md +18 -6
- package/corpus/templates/assets/.agents/skills/turn-into-app/references/fresh-project.md +8 -1
- package/corpus/templates/brain/.agents/skills/adding-a-feature/SKILL.md +9 -0
- package/corpus/templates/brain/.agents/skills/turn-into-app/SKILL.md +18 -6
- package/corpus/templates/brain/.agents/skills/turn-into-app/references/fresh-project.md +8 -1
- package/corpus/templates/calendar/.agents/skills/turn-into-app/SKILL.md +18 -6
- package/corpus/templates/calendar/.agents/skills/turn-into-app/references/fresh-project.md +8 -1
- package/corpus/templates/chat/.agents/skills/adding-a-feature/SKILL.md +9 -0
- package/corpus/templates/chat/.agents/skills/turn-into-app/SKILL.md +18 -6
- package/corpus/templates/chat/.agents/skills/turn-into-app/references/fresh-project.md +8 -1
- package/corpus/templates/clips/.agents/skills/turn-into-app/SKILL.md +18 -6
- package/corpus/templates/clips/.agents/skills/turn-into-app/references/fresh-project.md +8 -1
- package/corpus/templates/clips/app/routes/r.$recordingId.tsx +16 -4
- package/corpus/templates/clips/app/routes/share.meeting.$meetingId.tsx +14 -5
- package/corpus/templates/clips/package.json +1 -0
- package/corpus/templates/clips/react-router.config.ts +7 -0
- package/corpus/templates/clips/server/plugins/auth.ts +6 -1
- package/corpus/templates/clips/shared/prerendered-public-paths.ts +21 -0
- package/corpus/templates/clips/shared/share-meta.ts +8 -3
- package/corpus/templates/content/.agents/skills/turn-into-app/SKILL.md +18 -6
- package/corpus/templates/content/.agents/skills/turn-into-app/references/fresh-project.md +8 -1
- package/corpus/templates/crm/.agents/skills/turn-into-app/SKILL.md +18 -6
- package/corpus/templates/crm/.agents/skills/turn-into-app/references/fresh-project.md +8 -1
- package/corpus/templates/design/.agents/skills/turn-into-app/SKILL.md +18 -6
- package/corpus/templates/design/.agents/skills/turn-into-app/references/fresh-project.md +8 -1
- package/corpus/templates/dispatch/.agents/skills/turn-into-app/SKILL.md +18 -6
- package/corpus/templates/dispatch/.agents/skills/turn-into-app/references/fresh-project.md +8 -1
- package/corpus/templates/dispatch/app/chat-first-pages.ts +747 -0
- package/corpus/templates/dispatch/app/i18n-data.ts +181 -0
- package/corpus/templates/dispatch/app/routes/settings.tsx +62 -1
- package/corpus/templates/dispatch/changelog/2026-08-08-chat-first-navigation-keeps-conversations-central-while-open.md +6 -0
- package/corpus/templates/factory/.agents/skills/adding-a-feature/SKILL.md +9 -0
- package/corpus/templates/factory/.agents/skills/turn-into-app/SKILL.md +18 -6
- package/corpus/templates/factory/.agents/skills/turn-into-app/references/fresh-project.md +8 -1
- package/corpus/templates/factory/app/routes/factory.tsx +108 -76
- package/corpus/templates/factory/changelog/2026-08-08-scheduler-health-moves-to-settings.md +6 -0
- package/corpus/templates/forms/.agents/skills/turn-into-app/SKILL.md +18 -6
- package/corpus/templates/forms/.agents/skills/turn-into-app/references/fresh-project.md +8 -1
- package/corpus/templates/macros/.agents/skills/turn-into-app/SKILL.md +18 -6
- package/corpus/templates/macros/.agents/skills/turn-into-app/references/fresh-project.md +8 -1
- package/corpus/templates/mail/.agents/skills/turn-into-app/SKILL.md +18 -6
- package/corpus/templates/mail/.agents/skills/turn-into-app/references/fresh-project.md +8 -1
- package/corpus/templates/plan/.agents/skills/adding-a-feature/SKILL.md +9 -0
- package/corpus/templates/plan/.agents/skills/turn-into-app/SKILL.md +18 -6
- package/corpus/templates/plan/.agents/skills/turn-into-app/references/fresh-project.md +8 -1
- package/corpus/templates/plan/app/lib/plan-document-title.ts +3 -1
- package/corpus/templates/plan/app/root.tsx +1 -0
- package/corpus/templates/slides/.agents/skills/turn-into-app/SKILL.md +18 -6
- package/corpus/templates/slides/.agents/skills/turn-into-app/references/fresh-project.md +8 -1
- package/corpus/templates/tasks/.agents/skills/adding-a-feature/SKILL.md +9 -0
- package/corpus/templates/tasks/.agents/skills/turn-into-app/SKILL.md +18 -6
- package/corpus/templates/tasks/.agents/skills/turn-into-app/references/fresh-project.md +8 -1
- package/dist/agent/engine/builder-engine.d.ts +11 -1
- package/dist/agent/engine/builder-engine.js +11 -4
- package/dist/chat-threads/store.d.ts +2 -0
- package/dist/chat-threads/store.js +1 -1
- package/dist/cli/agent-plugin.d.ts +5 -2
- package/dist/cli/agent-plugin.js +17 -9
- package/dist/cli/code-agent-executor.js +25 -5
- package/dist/cli/code-agent-mcp-config.d.ts +21 -0
- package/dist/cli/code-agent-mcp-config.js +103 -0
- package/dist/client/NewWorkspaceAppFlow.js +4 -1
- package/dist/client/agent-chat/index.d.ts +4 -1
- package/dist/client/agent-chat/index.js +4 -1
- package/dist/client/agent-page/AgentTabsPage.d.ts +1 -0
- package/dist/client/agent-page/AgentTabsPage.js +4 -3
- package/dist/client/app-providers.d.ts +3 -1
- package/dist/client/app-providers.js +50 -5
- package/dist/client/chat/runtime.js +63 -0
- package/dist/client/chat-first/agents-pane.d.ts +2 -0
- package/dist/client/chat-first/agents-pane.js +6 -0
- package/dist/client/chat-first/app-pane.d.ts +2 -0
- package/dist/client/chat-first/app-pane.js +6 -0
- package/dist/client/chat-first/apps-rail.d.ts +2 -0
- package/dist/client/chat-first/apps-rail.js +103 -0
- package/dist/client/chat-first/browser-pane.d.ts +2 -0
- package/dist/client/chat-first/browser-pane.js +64 -0
- package/dist/client/chat-first/chat-history.d.ts +12 -0
- package/dist/client/chat-first/chat-history.js +10 -0
- package/dist/client/chat-first/copy.d.ts +2 -0
- package/dist/client/chat-first/copy.js +117 -0
- package/dist/client/chat-first/index.d.ts +13 -0
- package/dist/client/chat-first/index.js +12 -0
- package/dist/client/chat-first/primary-nav.d.ts +8 -0
- package/dist/client/chat-first/primary-nav.js +6 -0
- package/dist/client/chat-first/session-watch-pane.d.ts +2 -0
- package/dist/client/chat-first/session-watch-pane.js +9 -0
- package/dist/client/chat-first/surface-panel.d.ts +9 -0
- package/dist/client/chat-first/surface-panel.js +9 -0
- package/dist/client/chat-first/surface-tabs.d.ts +9 -0
- package/dist/client/chat-first/surface-tabs.js +74 -0
- package/dist/client/chat-first/types.d.ts +74 -0
- package/dist/client/chat-first/types.js +1 -0
- package/dist/client/chat-first-agent-activity.d.ts +11 -0
- package/dist/client/chat-first-agent-activity.js +51 -0
- package/dist/client/chat-first-surface-panel-toggle.d.ts +5 -0
- package/dist/client/chat-first-surface-panel-toggle.js +6 -0
- package/dist/client/chat-first.d.ts +208 -0
- package/dist/client/chat-first.js +816 -0
- package/dist/client/extensions/ExtensionViewer.js +8 -1
- package/dist/client/resources/McpIntegrationDialog.js +3 -2
- package/dist/client/resources/McpServerDetail.js +6 -11
- package/dist/client/resources/index.d.ts +1 -0
- package/dist/client/resources/index.js +1 -0
- package/dist/client/resources/use-mcp-servers.d.ts +20 -0
- package/dist/client/resources/use-mcp-servers.js +82 -46
- package/dist/client/settings/index.d.ts +1 -0
- package/dist/client/settings/index.js +1 -0
- package/dist/collab/awareness.d.ts +2 -2
- package/dist/collab/routes.d.ts +1 -1
- package/dist/collab/struct-routes.d.ts +1 -1
- package/dist/jobs/background-automation-runner.js +19 -2
- package/dist/jobs/scheduler-health.d.ts +20 -0
- package/dist/jobs/scheduler-health.js +86 -1
- package/dist/jobs/scheduler.js +38 -1
- package/dist/mcp-client/routes.d.ts +3 -0
- package/dist/mcp-client/routes.js +14 -0
- package/dist/notifications/routes.d.ts +1 -1
- package/dist/observability/routes.d.ts +5 -5
- package/dist/progress/routes.d.ts +1 -1
- package/dist/provider-api/actions/provider-api.d.ts +2 -2
- package/dist/resources/handlers.d.ts +1 -1
- package/dist/secrets/routes.d.ts +3 -3
- package/dist/server/agent-engine-api-key-route.d.ts +1 -1
- package/dist/server/agents-bundle.d.ts +2 -0
- package/dist/server/agents-bundle.js +31 -2
- package/dist/server/credential-provider.d.ts +8 -2
- package/dist/server/credential-provider.js +13 -9
- package/dist/server/realtime-token.d.ts +1 -1
- package/dist/server/transcribe-voice.d.ts +1 -1
- package/dist/shared/chat-first-app-creation.d.ts +19 -0
- package/dist/shared/chat-first-app-creation.js +75 -0
- package/dist/shared/document-title.d.ts +7 -0
- package/dist/shared/document-title.js +29 -0
- package/dist/shared/index.d.ts +2 -0
- package/dist/shared/index.js +2 -0
- package/dist/styles/chat-history-list.css +16 -0
- package/dist/templates/chat/.agents/skills/adding-a-feature/SKILL.md +9 -0
- package/dist/templates/chat/.agents/skills/turn-into-app/SKILL.md +18 -6
- package/dist/templates/chat/.agents/skills/turn-into-app/references/fresh-project.md +8 -1
- package/dist/templates/default/.agents/skills/adding-a-feature/SKILL.md +9 -0
- package/dist/templates/default/.agents/skills/turn-into-app/SKILL.md +18 -6
- package/dist/templates/default/.agents/skills/turn-into-app/references/fresh-project.md +8 -1
- package/dist/templates/default/react-router.config.ts +18 -0
- package/dist/templates/headless/.agents/skills/turn-into-app/SKILL.md +18 -6
- package/dist/templates/headless/.agents/skills/turn-into-app/references/fresh-project.md +8 -1
- package/dist/templates/workspace-core/.agents/skills/adding-a-feature/SKILL.md +9 -0
- package/dist/templates/workspace-core/.agents/skills/turn-into-app/SKILL.md +18 -6
- package/dist/templates/workspace-core/.agents/skills/turn-into-app/references/fresh-project.md +8 -1
- package/dist/templates/workspace-core/.agents/skills/workspace-conventions/SKILL.md +7 -0
- package/package.json +3 -2
- package/src/templates/chat/.agents/skills/adding-a-feature/SKILL.md +9 -0
- package/src/templates/chat/.agents/skills/turn-into-app/SKILL.md +18 -6
- package/src/templates/chat/.agents/skills/turn-into-app/references/fresh-project.md +8 -1
- package/src/templates/default/.agents/skills/adding-a-feature/SKILL.md +9 -0
- package/src/templates/default/.agents/skills/turn-into-app/SKILL.md +18 -6
- package/src/templates/default/.agents/skills/turn-into-app/references/fresh-project.md +8 -1
- package/src/templates/default/react-router.config.ts +18 -0
- package/src/templates/headless/.agents/skills/turn-into-app/SKILL.md +18 -6
- package/src/templates/headless/.agents/skills/turn-into-app/references/fresh-project.md +8 -1
- package/src/templates/workspace-core/.agents/skills/adding-a-feature/SKILL.md +9 -0
- package/src/templates/workspace-core/.agents/skills/turn-into-app/SKILL.md +18 -6
- package/src/templates/workspace-core/.agents/skills/turn-into-app/references/fresh-project.md +8 -1
- package/src/templates/workspace-core/.agents/skills/workspace-conventions/SKILL.md +7 -0
|
@@ -81,6 +81,13 @@ or other file-like payloads, design the upload path in the same change:
|
|
|
81
81
|
provider upload first, then URL/id/blob handle in SQL. Do not add base64/binary
|
|
82
82
|
columns or stuff files into `application_state`.
|
|
83
83
|
|
|
84
|
+
If the feature adds a server-side dependency carrying a native binary or heavy
|
|
85
|
+
runtime — headless browser, ffmpeg, image/video processing, ML runtime — read
|
|
86
|
+
the `performance` skill §9 before adding it. A deployed app has one `/*` page
|
|
87
|
+
function that every visitor's cache miss wakes, and it ships whatever the server
|
|
88
|
+
bundle depends on. Run that work from a background function or a job so the page
|
|
89
|
+
function never carries the weight.
|
|
90
|
+
|
|
84
91
|
**If the action produces or lists a navigable resource**, add a `link` builder that returns `{ url: buildDeepLink({ app, view, params }), label }`. External coding agents and MCP hosts (Claude / ChatGPT / Claude Code / Cowork / Codex, over MCP/A2A) then surface an "Open in … →" deep link that drops the user back into the running UI focused on the record — for free. If a compatible MCP host should render an inline review/edit surface, also add `mcpApp` with `embedApp()` so the action embeds the real React app route instead of a one-off HTML UI. The `link` builder and `mcpApp` metadata must be pure and synchronous (no I/O). Any external-agent read/ingest action must be `http: { method: "GET" }` + `readOnly: true` + `publicAgent: { expose: true, readOnly: true, requiresAuth: true }`. See the `external-agents` skill.
|
|
85
92
|
|
|
86
93
|
### 3. Skills / Instructions
|
|
@@ -195,4 +202,6 @@ TL;DR: declare the vocabulary once with `defineAppRoles({ appId, roles, defaultR
|
|
|
195
202
|
- **create-skill** — How to create skills for new patterns (area 3 in detail)
|
|
196
203
|
- **storing-data** — Where to store the feature's data
|
|
197
204
|
- **real-time-sync** — How the UI stays in sync when the agent writes data
|
|
205
|
+
- **performance** — Query/load cost, and (§9) cold-start artifact size when a
|
|
206
|
+
feature adds a server-side dependency
|
|
198
207
|
- **internationalization** — How to update localized UI copy and catalogs
|
|
@@ -3,8 +3,9 @@ name: turn-into-app
|
|
|
3
3
|
description: >-
|
|
4
4
|
Turn visible project context, a proven thread, skill, or workflow into a
|
|
5
5
|
runnable Agent-Native app with simple buttons, visible agent steps, preview,
|
|
6
|
-
and deployment handoff. Use when a user invokes `/turn-into-app
|
|
7
|
-
make a workflow into an app, including from
|
|
6
|
+
and deployment handoff. Use when a user invokes `/turn-into-app`,
|
|
7
|
+
`/make-into-app`, or asks to make a workflow into an app, including from
|
|
8
|
+
Claude or ChatGPT on the web.
|
|
8
9
|
user-invocable: true
|
|
9
10
|
scope: both
|
|
10
11
|
metadata:
|
|
@@ -38,6 +39,15 @@ The build location depends on the host. Treat this as a hard routing rule:
|
|
|
38
39
|
workspace, follow the local implementation steps below. The local agent may
|
|
39
40
|
scaffold, edit, run, and verify the app there.
|
|
40
41
|
|
|
42
|
+
Once the source brief is sufficient to identify a repeatable workflow, the
|
|
43
|
+
handoff is non-interactive. Do not ask the user for visual, product, copy,
|
|
44
|
+
layout, template, integration, or implementation choices that can be resolved
|
|
45
|
+
from the source. Select the source's recommended option; otherwise choose the
|
|
46
|
+
most direct conventional default and record the assumption for later review.
|
|
47
|
+
Only stop for a genuine hard blocker such as missing authorization, a
|
|
48
|
+
destructive external action, an ambiguous target workspace, or no identifiable
|
|
49
|
+
workflow at all.
|
|
50
|
+
|
|
41
51
|
## Default behavior
|
|
42
52
|
|
|
43
53
|
For a local code-agent runtime this is an end-to-end build skill, not a request
|
|
@@ -104,14 +114,16 @@ before creating the app. Read the host-provided context in this order:
|
|
|
104
114
|
Record the brief with these headings before handoff: source and provenance,
|
|
105
115
|
project goal, configuration and constraints, knowledge sources, repeatable
|
|
106
116
|
workflow, inputs and outputs, judgment and review points, representative runs,
|
|
107
|
-
integrations and permissions, and unknowns. This is the compact contract for
|
|
117
|
+
integrations and permissions, and unknowns and assumptions. This is the compact contract for
|
|
108
118
|
the app. It keeps the new app useful without pretending that hidden Project
|
|
109
119
|
history was imported. See [the fresh Project reference](references/fresh-project.md)
|
|
110
120
|
for the host setup and brief template.
|
|
111
121
|
|
|
112
|
-
If the visible Project context has no concrete repeatable job
|
|
113
|
-
|
|
114
|
-
|
|
122
|
+
If the visible Project context has no concrete repeatable job and no primary
|
|
123
|
+
goal can be inferred, ask for one focused clarification or a representative
|
|
124
|
+
artifact. Otherwise use the project's primary goal and source conventions; do
|
|
125
|
+
not ask a questionnaire and do not fall back to a generic “what app do you
|
|
126
|
+
want to make?” builder.
|
|
115
127
|
|
|
116
128
|
## Source selection guard
|
|
117
129
|
|
|
@@ -36,7 +36,7 @@ Inputs and outputs:
|
|
|
36
36
|
Judgment and review points:
|
|
37
37
|
Representative runs: none, or 1-3 selected examples
|
|
38
38
|
Integrations and permissions:
|
|
39
|
-
Unknowns and
|
|
39
|
+
Unknowns and assumptions:
|
|
40
40
|
```
|
|
41
41
|
|
|
42
42
|
Keep source references bounded. Prefer a file name, URL, resource ID, or short
|
|
@@ -69,6 +69,13 @@ do not fall back to a local sandbox build. Claude Code and Codex Code are the
|
|
|
69
69
|
local-agent exception and may follow the implementation steps in the main
|
|
70
70
|
skill.
|
|
71
71
|
|
|
72
|
+
The brief is an implementation authorization, not a questionnaire. After a
|
|
73
|
+
repeatable workflow is identifiable, choose any source-recommended option
|
|
74
|
+
automatically. For unresolved non-blocking choices, use the most direct
|
|
75
|
+
conventional default, record it under assumptions, and continue. Ask only when
|
|
76
|
+
there is no identifiable workflow, no authorized target workspace, or a
|
|
77
|
+
destructive/credential boundary genuinely prevents the handoff.
|
|
78
|
+
|
|
72
79
|
In a new Project chat, say:
|
|
73
80
|
|
|
74
81
|
```text
|
|
@@ -17,4 +17,14 @@ export declare const BUILDER_CAPABILITIES: EngineCapabilities;
|
|
|
17
17
|
export declare const BUILDER_SUPPORTED_MODELS: readonly ["auto", string, "gpt-5-6-terra", "gpt-5-6-sol", "claude-haiku-4-5", "claude-sonnet-4-6" | "claude-sonnet-5", "claude-opus-4-8", "gemini-3-5-flash", "gemini-3-1-pro"];
|
|
18
18
|
export declare const BUILDER_MODEL_UNAUTHORIZED_ERROR_CODE = "builder_model_unauthorized";
|
|
19
19
|
export declare const BUILDER_DEFAULT_MODEL: string;
|
|
20
|
-
|
|
20
|
+
/**
|
|
21
|
+
* Credentials captured by a durable caller that cannot rely on ambient
|
|
22
|
+
* request context staying attached to a later run-manager callback.
|
|
23
|
+
*/
|
|
24
|
+
export interface BuilderEngineCredentials {
|
|
25
|
+
privateKey: string | null;
|
|
26
|
+
publicKey: string | null;
|
|
27
|
+
userId?: string | null;
|
|
28
|
+
orgName?: string | null;
|
|
29
|
+
}
|
|
30
|
+
export declare function createBuilderEngine(config?: Record<string, unknown>): AgentEngine;
|
|
@@ -95,13 +95,17 @@ async function buildUpgradeUrl() {
|
|
|
95
95
|
return url.toString();
|
|
96
96
|
}
|
|
97
97
|
class BuilderEngine {
|
|
98
|
+
configuredCredentials;
|
|
98
99
|
name = "builder";
|
|
99
100
|
label = "Builder.io Gateway";
|
|
100
101
|
defaultModel = BUILDER_DEFAULT_MODEL;
|
|
101
102
|
supportedModels = BUILDER_SUPPORTED_MODELS;
|
|
102
103
|
capabilities = BUILDER_CAPABILITIES;
|
|
104
|
+
constructor(configuredCredentials) {
|
|
105
|
+
this.configuredCredentials = configuredCredentials;
|
|
106
|
+
}
|
|
103
107
|
async *stream(opts) {
|
|
104
|
-
const creds = await resolveBuilderCredentials();
|
|
108
|
+
const creds = this.configuredCredentials ?? (await resolveBuilderCredentials());
|
|
105
109
|
const authHeader = creds.privateKey ? `Bearer ${creds.privateKey}` : null;
|
|
106
110
|
const spaceId = creds.publicKey;
|
|
107
111
|
const builderUserId = creds.userId;
|
|
@@ -255,7 +259,7 @@ class BuilderEngine {
|
|
|
255
259
|
// self-healing path for workspace/env-managed credentials, which never
|
|
256
260
|
// flow through writeBuilderCredentials.
|
|
257
261
|
try {
|
|
258
|
-
const creds = await resolveBuilderCredentials();
|
|
262
|
+
const creds = this.configuredCredentials ?? (await resolveBuilderCredentials());
|
|
259
263
|
await clearBuilderCredentialAuthFailure({
|
|
260
264
|
privateKey: creds.privateKey,
|
|
261
265
|
publicKey: creds.publicKey,
|
|
@@ -765,8 +769,11 @@ function htmlToText(html) {
|
|
|
765
769
|
.replace(/\n{3,}/g, "\n\n")
|
|
766
770
|
.trim();
|
|
767
771
|
}
|
|
768
|
-
export function createBuilderEngine(
|
|
769
|
-
|
|
772
|
+
export function createBuilderEngine(config = {}) {
|
|
773
|
+
const configuredCredentials = config.credentials && typeof config.credentials === "object"
|
|
774
|
+
? config.credentials
|
|
775
|
+
: undefined;
|
|
776
|
+
return new BuilderEngine(configuredCredentials);
|
|
770
777
|
}
|
|
771
778
|
function resolveMaxBuilderGatewayTimeoutMs() {
|
|
772
779
|
if (isInBackgroundFunctionRuntime()) {
|
|
@@ -73,6 +73,8 @@ export declare function createThread(ownerEmail: string, opts?: {
|
|
|
73
73
|
title?: string;
|
|
74
74
|
scope?: ChatThreadScope | null;
|
|
75
75
|
source?: ChatThreadSource | null;
|
|
76
|
+
/** Explicit owner organization for durable/background callers. */
|
|
77
|
+
orgId?: string | null;
|
|
76
78
|
}): Promise<ChatThread>;
|
|
77
79
|
export declare function registerChatThreadsShareable(): void;
|
|
78
80
|
export declare function ensureChatThreadTables(): Promise<void>;
|
|
@@ -367,7 +367,7 @@ export async function createThread(ownerEmail, opts) {
|
|
|
367
367
|
const title = opts?.title ?? "";
|
|
368
368
|
const scope = opts?.scope ?? null;
|
|
369
369
|
const source = opts?.source ?? null;
|
|
370
|
-
const orgId = getRequestOrgId() ?? null;
|
|
370
|
+
const orgId = opts?.orgId ?? getRequestOrgId() ?? null;
|
|
371
371
|
await client.execute({
|
|
372
372
|
sql: `INSERT INTO chat_threads (id, owner_email, title, preview, thread_data, message_count, created_at, updated_at, scope_type, scope_id, scope_label, source_platform, source_app_id, source_url, org_id, visibility) VALUES (?, ?, ?, '', '{}', 0, ?, ?, ?, ?, ?, ?, ?, ?, ?, 'private')`,
|
|
373
373
|
args: [
|
|
@@ -2,8 +2,9 @@
|
|
|
2
2
|
* Import and validate the portable Agent Plugin format.
|
|
3
3
|
*
|
|
4
4
|
* The importer intentionally handles only local plugin directories. Skills are
|
|
5
|
-
* copied as inert files
|
|
6
|
-
*
|
|
5
|
+
* copied as inert files into the workspace's agent-visible `.agents/skills`
|
|
6
|
+
* tree, and remote Streamable HTTP MCP entries are translated to the
|
|
7
|
+
* Agent-Native `mcp.config.json` shape without copying package headers.
|
|
7
8
|
* A plugin package is not a credential store and this command never executes
|
|
8
9
|
* a plugin's scripts or stdio servers.
|
|
9
10
|
*/
|
|
@@ -62,6 +63,8 @@ export interface LoadedAgentPlugin {
|
|
|
62
63
|
}
|
|
63
64
|
export interface AgentPluginImportOptions {
|
|
64
65
|
targetDir?: string;
|
|
66
|
+
/** Optional skills root used by hosts whose agent cwd is a child workspace. */
|
|
67
|
+
skillsTargetDir?: string;
|
|
65
68
|
force?: boolean;
|
|
66
69
|
dryRun?: boolean;
|
|
67
70
|
}
|
package/dist/cli/agent-plugin.js
CHANGED
|
@@ -2,8 +2,9 @@
|
|
|
2
2
|
* Import and validate the portable Agent Plugin format.
|
|
3
3
|
*
|
|
4
4
|
* The importer intentionally handles only local plugin directories. Skills are
|
|
5
|
-
* copied as inert files
|
|
6
|
-
*
|
|
5
|
+
* copied as inert files into the workspace's agent-visible `.agents/skills`
|
|
6
|
+
* tree, and remote Streamable HTTP MCP entries are translated to the
|
|
7
|
+
* Agent-Native `mcp.config.json` shape without copying package headers.
|
|
7
8
|
* A plugin package is not a credential store and this command never executes
|
|
8
9
|
* a plugin's scripts or stdio servers.
|
|
9
10
|
*/
|
|
@@ -42,7 +43,7 @@ Usage:
|
|
|
42
43
|
Commands:
|
|
43
44
|
import Import a standard Agent Plugin's Skills and remote MCP servers into an Agent-Native workspace.
|
|
44
45
|
|
|
45
|
-
The importer copies Skills into a namespaced skills/<plugin>/<skill> path and
|
|
46
|
+
The importer copies Skills into a namespaced .agents/skills/<plugin>/<skill> path and
|
|
46
47
|
maps Streamable HTTP MCP servers into mcp.config.json. Package headers are
|
|
47
48
|
never imported as credentials; configure authentication through the app's
|
|
48
49
|
normal Connections flow. Stdio and SSE servers are reported and skipped.`;
|
|
@@ -691,10 +692,10 @@ function planMcpServers(plugin, existing, force) {
|
|
|
691
692
|
}
|
|
692
693
|
return planned;
|
|
693
694
|
}
|
|
694
|
-
function planSkills(plugin,
|
|
695
|
+
function planSkills(plugin, skillsRoot, force) {
|
|
695
696
|
return plugin.skills.map((skill) => {
|
|
696
|
-
const destination = path.join(
|
|
697
|
-
assertPathInside(
|
|
697
|
+
const destination = path.join(skillsRoot, skill.name);
|
|
698
|
+
assertPathInside(skillsRoot, destination, "Imported skill destination");
|
|
698
699
|
assertPathOutside(plugin.rootDir, destination, "Imported skill destination");
|
|
699
700
|
assertNoSymlinkInExistingPath(path.dirname(destination), "Imported skill destination");
|
|
700
701
|
if (!pathExists(destination)) {
|
|
@@ -878,12 +879,19 @@ export function importAgentPlugin(input, options = {}) {
|
|
|
878
879
|
}
|
|
879
880
|
assertNoSymlinkInExistingPath(targetDir, "Agent-Native import target");
|
|
880
881
|
const slug = pluginSlug(plugin.manifest.name);
|
|
881
|
-
const
|
|
882
|
+
const skillsTargetDir = canonicalPathForComparison(options.skillsTargetDir ?? path.join(targetDir, ".agents", "skills"));
|
|
883
|
+
if (pathExists(skillsTargetDir) &&
|
|
884
|
+
!fs.statSync(skillsTargetDir).isDirectory()) {
|
|
885
|
+
throw new Error(`Agent-Native skills target must be a directory: ${skillsTargetDir}`);
|
|
886
|
+
}
|
|
887
|
+
assertPathOutside(plugin.rootDir, skillsTargetDir, "Imported skills target");
|
|
888
|
+
assertNoSymlinkInExistingPath(skillsTargetDir, "Imported skills target");
|
|
889
|
+
const skillsRoot = path.join(skillsTargetDir, slug);
|
|
882
890
|
const metadataFile = path.join(targetDir, ".agent-native", "plugins", `${slug}.json`);
|
|
883
891
|
const mcpFile = path.join(targetDir, "mcp.config.json");
|
|
884
|
-
assertPathInside(targetDir, skillsRoot, "Imported skills root");
|
|
885
892
|
assertPathInside(targetDir, metadataFile, "Imported metadata path");
|
|
886
893
|
assertPathInside(targetDir, mcpFile, "Imported MCP config path");
|
|
894
|
+
assertPathInside(skillsTargetDir, skillsRoot, "Imported skills root");
|
|
887
895
|
assertPathOutside(plugin.rootDir, skillsRoot, "Imported skills root");
|
|
888
896
|
assertPathOutside(plugin.rootDir, metadataFile, "Imported metadata path");
|
|
889
897
|
assertPathOutside(plugin.rootDir, mcpFile, "Imported MCP config path");
|
|
@@ -892,7 +900,7 @@ export function importAgentPlugin(input, options = {}) {
|
|
|
892
900
|
const force = options.force ?? false;
|
|
893
901
|
const dryRun = options.dryRun ?? false;
|
|
894
902
|
const existingMcp = readExistingMcpConfig(mcpFile);
|
|
895
|
-
const skillPlans = planSkills(plugin,
|
|
903
|
+
const skillPlans = planSkills(plugin, skillsRoot, force);
|
|
896
904
|
const mcpPlans = planMcpServers(plugin, existingMcp, force);
|
|
897
905
|
const existingMetadata = readExistingMetadata(metadataFile);
|
|
898
906
|
const metadataIsSame = metadataMatches(existingMetadata, plugin);
|
|
@@ -14,6 +14,7 @@ import { readAgentsBundleFromFs, generateDevelopmentSkillsPromptBlock, } from ".
|
|
|
14
14
|
import { getAmbientOrgId, getAmbientUserEmail, runWithRequestContext, } from "../server/request-context.js";
|
|
15
15
|
import { isReasoningEffort, } from "../shared/reasoning-effort.js";
|
|
16
16
|
import { createAgentNativeConfigContext, loadResolvedAgentNativeConfig, } from "../vite/agent-native-config-loader.js";
|
|
17
|
+
import { codexMcpConfigArgs, mergeCodeAgentMcpConfig, restrictCodeAgentMcpConfig, } from "./code-agent-mcp-config.js";
|
|
17
18
|
import { createCodeAgentOutputSmoother } from "./code-agent-output-smoother.js";
|
|
18
19
|
import { addCodeAgentCommandToAllowlist, appendCodeAgentTranscriptEvent, dequeueCodeAgentFollowUp, getCodeAgentRunRecord, isCodeAgentCommandAllowed, listCodeAgentTranscriptEvents, updateCodeAgentRunRecord, } from "./code-agent-runs.js";
|
|
19
20
|
const DEFAULT_COMMAND_TIMEOUT_MS = 120_000;
|
|
@@ -443,20 +444,26 @@ async function executeCodexCliRun(options) {
|
|
|
443
444
|
const model = normalizeCodexCliModel(options.model);
|
|
444
445
|
const streamToolOutputToStdout = options.streamToolOutputToStdout ??
|
|
445
446
|
process.env.AGENT_NATIVE_CODE_AGENT_STRUCTURED_STDOUT !== "1";
|
|
447
|
+
const additionalSkillsRoot = process.env.AGENT_NATIVE_CODE_AGENT_SKILLS_ROOT?.trim();
|
|
446
448
|
const args = [
|
|
449
|
+
...codexMcpConfigArgs(),
|
|
447
450
|
"--ask-for-approval",
|
|
448
451
|
"never",
|
|
449
|
-
"
|
|
452
|
+
"--sandbox",
|
|
453
|
+
codexSandboxForPermissionMode(options.permissionMode),
|
|
450
454
|
"--cd",
|
|
451
455
|
cwd,
|
|
456
|
+
"exec",
|
|
452
457
|
"--color",
|
|
453
458
|
"never",
|
|
454
459
|
"--skip-git-repo-check",
|
|
455
|
-
"--
|
|
456
|
-
codexSandboxForPermissionMode(options.permissionMode),
|
|
460
|
+
"--ignore-user-config",
|
|
457
461
|
"--output-last-message",
|
|
458
462
|
outputPath,
|
|
459
463
|
];
|
|
464
|
+
if (additionalSkillsRoot && fs.existsSync(additionalSkillsRoot)) {
|
|
465
|
+
args.splice(args.indexOf("--output-last-message"), 0, "--add-dir", additionalSkillsRoot);
|
|
466
|
+
}
|
|
460
467
|
if (model)
|
|
461
468
|
args.push("--model", model);
|
|
462
469
|
args.push("-");
|
|
@@ -663,9 +670,15 @@ function buildCodexCliPrompt(run, prompt) {
|
|
|
663
670
|
const modeInstruction = mode === "Plan"
|
|
664
671
|
? "Inspect and explain only. Do not edit files or run mutating commands."
|
|
665
672
|
: "Edit and verify as needed. Do not create, switch, reset, rebase, or stash git branches.";
|
|
673
|
+
const additionalSkillsRoot = process.env.AGENT_NATIVE_CODE_AGENT_SKILLS_ROOT?.trim();
|
|
666
674
|
return [
|
|
667
675
|
`You are running from Agent-Native Code in ${run.cwd || process.cwd()}.`,
|
|
668
676
|
"Follow the repository AGENTS.md and any relevant skill instructions.",
|
|
677
|
+
...(additionalSkillsRoot
|
|
678
|
+
? [
|
|
679
|
+
`Additional installed Agent Plugin skills are available under ${additionalSkillsRoot}. Read any relevant SKILL.md files before acting.`,
|
|
680
|
+
]
|
|
681
|
+
: []),
|
|
669
682
|
`Run mode: ${mode} (${permissionMode}). ${modeInstruction}`,
|
|
670
683
|
"",
|
|
671
684
|
"# User request",
|
|
@@ -933,9 +946,12 @@ async function startCodeAgentMcpManager(runId) {
|
|
|
933
946
|
});
|
|
934
947
|
return null;
|
|
935
948
|
});
|
|
936
|
-
|
|
949
|
+
const effectiveConfig = restrictCodeAgentMcpConfig(mergeCodeAgentMcpConfig(config));
|
|
950
|
+
if (!effectiveConfig ||
|
|
951
|
+
Object.keys(effectiveConfig.servers ?? {}).length === 0) {
|
|
937
952
|
return null;
|
|
938
|
-
|
|
953
|
+
}
|
|
954
|
+
const manager = new McpClientManager(effectiveConfig);
|
|
939
955
|
await manager.start().catch((err) => {
|
|
940
956
|
const message = err instanceof Error ? err.message : String(err);
|
|
941
957
|
appendCodeAgentTranscriptEvent({
|
|
@@ -1299,6 +1315,10 @@ export async function buildCodeAgentSystemPrompt(cwd, permissionMode) {
|
|
|
1299
1315
|
const appConfig = await loadResolvedAgentNativeConfig(cwd, createAgentNativeConfigContext("serve", "development"));
|
|
1300
1316
|
const bundle = readAgentsBundleFromFs(cwd, null, {
|
|
1301
1317
|
instructions: appConfig.instructions,
|
|
1318
|
+
additionalSkillDirs: (process.env.AGENT_NATIVE_CODE_AGENT_SKILLS_ROOT ?? "")
|
|
1319
|
+
.split(path.delimiter)
|
|
1320
|
+
.map((value) => value.trim())
|
|
1321
|
+
.filter(Boolean),
|
|
1302
1322
|
});
|
|
1303
1323
|
// If the bundle has no AGENTS.md, try CLAUDE.md as a fallback — many repos
|
|
1304
1324
|
// use that name for agent instructions (e.g. Claude Code projects).
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import type { McpConfig } from "../mcp-client/config.js";
|
|
2
|
+
/**
|
|
3
|
+
* Keep a desktop coding run on the app registry's MCP servers. The normal
|
|
4
|
+
* server-side manager merges persisted MCP settings for web requests, but a
|
|
5
|
+
* local shell must not inherit arbitrary user MCP servers when the desktop
|
|
6
|
+
* host has supplied an explicit workspace allowlist.
|
|
7
|
+
*/
|
|
8
|
+
export declare function restrictCodeAgentMcpConfig(config: McpConfig | null, environment?: NodeJS.ProcessEnv): McpConfig | null;
|
|
9
|
+
/**
|
|
10
|
+
* Add host-provided app/plugin servers to the normal merged config. The
|
|
11
|
+
* filesystem and environment layers have different precedence rules, so the
|
|
12
|
+
* child process combines them explicitly instead of silently dropping one.
|
|
13
|
+
*/
|
|
14
|
+
export declare function mergeCodeAgentMcpConfig(config: McpConfig | null, environment?: NodeJS.ProcessEnv): McpConfig | null;
|
|
15
|
+
/**
|
|
16
|
+
* Convert the host-scoped HTTP MCP config into Codex CLI's `-c` overrides.
|
|
17
|
+
* The caller adds `--ignore-user-config` in the `exec` segment so a local
|
|
18
|
+
* coding session receives the workspace apps, not the user's global MCP
|
|
19
|
+
* catalog.
|
|
20
|
+
*/
|
|
21
|
+
export declare function codexMcpConfigArgs(environment?: NodeJS.ProcessEnv): string[];
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
const DESKTOP_MCP_ALLOWLIST_ENV = "AGENT_NATIVE_CODE_AGENT_MCP_SERVER_ALLOWLIST";
|
|
2
|
+
function parseServerAllowlist(raw) {
|
|
3
|
+
if (raw === undefined)
|
|
4
|
+
return null;
|
|
5
|
+
return new Set(raw
|
|
6
|
+
.split(",")
|
|
7
|
+
.map((value) => value.trim())
|
|
8
|
+
.filter(Boolean));
|
|
9
|
+
}
|
|
10
|
+
/**
|
|
11
|
+
* Keep a desktop coding run on the app registry's MCP servers. The normal
|
|
12
|
+
* server-side manager merges persisted MCP settings for web requests, but a
|
|
13
|
+
* local shell must not inherit arbitrary user MCP servers when the desktop
|
|
14
|
+
* host has supplied an explicit workspace allowlist.
|
|
15
|
+
*/
|
|
16
|
+
export function restrictCodeAgentMcpConfig(config, environment = process.env) {
|
|
17
|
+
const allowlist = parseServerAllowlist(environment[DESKTOP_MCP_ALLOWLIST_ENV]);
|
|
18
|
+
if (!allowlist || !config)
|
|
19
|
+
return config;
|
|
20
|
+
const servers = Object.fromEntries(Object.entries(config.servers).filter(([id]) => allowlist.has(id)));
|
|
21
|
+
return { ...config, servers };
|
|
22
|
+
}
|
|
23
|
+
function codexConfigKey(serverId) {
|
|
24
|
+
const normalized = serverId.replace(/[^A-Za-z0-9_-]/g, "_");
|
|
25
|
+
return normalized || "workspace";
|
|
26
|
+
}
|
|
27
|
+
function tomlString(value) {
|
|
28
|
+
return JSON.stringify(value);
|
|
29
|
+
}
|
|
30
|
+
function tomlInlineTable(headers) {
|
|
31
|
+
return `{${Object.entries(headers)
|
|
32
|
+
.map(([key, value]) => `${tomlString(key)}=${tomlString(value)}`)
|
|
33
|
+
.join(",")}}`;
|
|
34
|
+
}
|
|
35
|
+
function parseMcpServers(environment) {
|
|
36
|
+
const raw = environment.MCP_SERVERS?.trim();
|
|
37
|
+
if (!raw)
|
|
38
|
+
return {};
|
|
39
|
+
let parsed;
|
|
40
|
+
try {
|
|
41
|
+
parsed = JSON.parse(raw);
|
|
42
|
+
}
|
|
43
|
+
catch {
|
|
44
|
+
throw new Error("MCP_SERVERS is not valid JSON.");
|
|
45
|
+
}
|
|
46
|
+
if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) {
|
|
47
|
+
throw new Error("MCP_SERVERS must contain a servers object.");
|
|
48
|
+
}
|
|
49
|
+
const serverMap = "servers" in parsed &&
|
|
50
|
+
parsed.servers &&
|
|
51
|
+
typeof parsed.servers === "object" &&
|
|
52
|
+
!Array.isArray(parsed.servers)
|
|
53
|
+
? parsed.servers
|
|
54
|
+
: parsed;
|
|
55
|
+
return Object.fromEntries(Object.entries(serverMap).map(([id, value]) => {
|
|
56
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) {
|
|
57
|
+
throw new Error(`MCP_SERVERS entry ${id} is invalid.`);
|
|
58
|
+
}
|
|
59
|
+
return [id, value];
|
|
60
|
+
}));
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* Add host-provided app/plugin servers to the normal merged config. The
|
|
64
|
+
* filesystem and environment layers have different precedence rules, so the
|
|
65
|
+
* child process combines them explicitly instead of silently dropping one.
|
|
66
|
+
*/
|
|
67
|
+
export function mergeCodeAgentMcpConfig(config, environment = process.env) {
|
|
68
|
+
const environmentServers = parseMcpServers(environment);
|
|
69
|
+
if (Object.keys(environmentServers).length === 0)
|
|
70
|
+
return config;
|
|
71
|
+
return {
|
|
72
|
+
...(config ?? { servers: {} }),
|
|
73
|
+
servers: {
|
|
74
|
+
...(config?.servers ?? {}),
|
|
75
|
+
...environmentServers,
|
|
76
|
+
},
|
|
77
|
+
source: config?.source
|
|
78
|
+
? `${config.source}+desktop-environment`
|
|
79
|
+
: "env:MCP_SERVERS",
|
|
80
|
+
};
|
|
81
|
+
}
|
|
82
|
+
/**
|
|
83
|
+
* Convert the host-scoped HTTP MCP config into Codex CLI's `-c` overrides.
|
|
84
|
+
* The caller adds `--ignore-user-config` in the `exec` segment so a local
|
|
85
|
+
* coding session receives the workspace apps, not the user's global MCP
|
|
86
|
+
* catalog.
|
|
87
|
+
*/
|
|
88
|
+
export function codexMcpConfigArgs(environment = process.env) {
|
|
89
|
+
const servers = parseMcpServers(environment);
|
|
90
|
+
if (Object.keys(servers).length === 0)
|
|
91
|
+
return [];
|
|
92
|
+
const args = [];
|
|
93
|
+
for (const [serverId, server] of Object.entries(servers)) {
|
|
94
|
+
if (server.type !== "http" || !server.url)
|
|
95
|
+
continue;
|
|
96
|
+
const key = codexConfigKey(serverId);
|
|
97
|
+
args.push("-c", `mcp_servers.${tomlString(key)}.url=${tomlString(server.url)}`);
|
|
98
|
+
if (server.headers && Object.keys(server.headers).length > 0) {
|
|
99
|
+
args.push("-c", `mcp_servers.${tomlString(key)}.http_headers=${tomlInlineTable(server.headers)}`);
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
return args;
|
|
103
|
+
}
|
|
@@ -43,6 +43,7 @@ const ERROR_FAILURE_REASONS = new Set([
|
|
|
43
43
|
"builder-not-connected",
|
|
44
44
|
"credential-store-unavailable",
|
|
45
45
|
]);
|
|
46
|
+
const LOCAL_APP_DOCS_URL = "https://agent-native.com/docs/multi-app-workspace#adding-a-new-app";
|
|
46
47
|
function isErrorFailureReason(reason) {
|
|
47
48
|
return !!reason && ERROR_FAILURE_REASONS.has(reason);
|
|
48
49
|
}
|
|
@@ -267,7 +268,9 @@ export function NewWorkspaceAppFlow({ sourceApp = "chat", className = "", dispat
|
|
|
267
268
|
}
|
|
268
269
|
return (_jsx("section", { className: `mx-auto flex w-full max-w-5xl flex-col gap-5 px-4 py-6 ${className}`, children: _jsxs("div", { className: "grid gap-5 lg:grid-cols-[minmax(0,1fr)_320px]", children: [_jsxs("div", { className: "flex flex-col gap-3", children: [_jsx(PromptComposer, { autoFocus: true, disabled: isSubmitting, placeholder: "Describe the app your teammate should be able to use...", draftScope: "dispatch:new-app", preserveDraftOnSubmit: true, onSubmit: (text) => submit(text) }), statusMessage ? (_jsxs("div", { className: `flex flex-col gap-2 rounded-md border px-3 py-2 text-sm ${isErrorFailureReason(failureReason)
|
|
269
270
|
? "border-destructive/40 bg-destructive/10 text-destructive"
|
|
270
|
-
: "border-border bg-muted/40 text-muted-foreground"}`, children: [_jsxs("div", { className: "flex flex-wrap items-center gap-2", children: [isErrorFailureReason(failureReason) ? (_jsx(IconAlertTriangle, { className: "h-4 w-4 shrink-0" })) : null, _jsx("span", { children: statusMessage }), branchUrl ? (_jsxs("a", { href: branchUrl, target: "_blank", rel: "noreferrer", className: "inline-flex items-center gap-1 font-medium text-foreground underline", children: ["Open branch ", _jsx(IconArrowUpRight, { className: "h-3 w-3" })] })) : null] }), failureReason === "builder-not-connected" ? (_jsx("button", { type: "button", onClick: () => connectFlow.start(), disabled: connectFlow.connecting, className: "inline-flex w-fit cursor-pointer items-center gap-1 rounded-md border border-border bg-background px-2.5 py-1 text-xs font-medium text-foreground hover:bg-accent/40 disabled:cursor-not-allowed disabled:opacity-60", children: connectFlow.connecting
|
|
271
|
+
: "border-border bg-muted/40 text-muted-foreground"}`, children: [_jsxs("div", { className: "flex flex-wrap items-center gap-2", children: [isErrorFailureReason(failureReason) ? (_jsx(IconAlertTriangle, { className: "h-4 w-4 shrink-0" })) : null, _jsx("span", { children: statusMessage }), branchUrl ? (_jsxs("a", { href: branchUrl, target: "_blank", rel: "noreferrer", className: "inline-flex items-center gap-1 font-medium text-foreground underline", children: ["Open branch ", _jsx(IconArrowUpRight, { className: "h-3 w-3" })] })) : null] }), failureReason === "builder-not-connected" ? (_jsxs("div", { className: "flex flex-wrap items-center gap-2", children: [_jsx("button", { type: "button", onClick: () => connectFlow.start(), disabled: connectFlow.connecting, className: "inline-flex w-fit cursor-pointer items-center gap-1 rounded-md border border-border bg-background px-2.5 py-1 text-xs font-medium text-foreground hover:bg-accent/40 disabled:cursor-not-allowed disabled:opacity-60", children: connectFlow.connecting
|
|
272
|
+
? "Connecting..."
|
|
273
|
+
: "Connect Builder" }), _jsxs("a", { href: LOCAL_APP_DOCS_URL, target: "_blank", rel: "noreferrer", "data-create-app-local-link": true, className: "inline-flex items-center gap-1 text-xs font-medium text-foreground underline underline-offset-2", children: ["Create locally ", _jsx(IconArrowUpRight, { className: "h-3 w-3" })] })] })) : null, failureReason === "credential-store-unavailable" ||
|
|
271
274
|
failureReason === "builder-error" ? (_jsx("button", { type: "button", onClick: () => submit(lastSubmittedPrompt), disabled: isSubmitting, className: "inline-flex w-fit cursor-pointer items-center gap-1 rounded-md border border-border bg-background px-2.5 py-1 text-xs font-medium text-foreground hover:bg-accent/40 disabled:cursor-not-allowed disabled:opacity-60", children: "Try again" })) : null] })) : null] }), _jsxs("aside", { className: "overflow-hidden rounded-lg border border-border bg-card", children: [_jsx("div", { className: "border-b border-border px-4 py-3", children: _jsxs("div", { className: "flex items-center justify-between gap-3", children: [_jsxs("div", { className: "flex items-center gap-2 text-sm font-medium", children: [_jsx(IconKey, { className: "h-4 w-4" }), "Dispatch keys"] }), _jsx("span", { className: "shrink-0 rounded border border-border bg-background/40 px-2 py-0.5 text-[11px] text-muted-foreground", children: selectedSecretLabel })] }) }), _jsx("div", { className: "max-h-[220px] space-y-2 overflow-y-auto p-3", children: vaultAccessMode === "all-apps" ? (_jsx("p", { className: "rounded-md border border-dashed border-border px-3 py-3 text-xs text-muted-foreground", children: "Every saved Dispatch vault key is available to new apps." })) : secretsError ? (_jsx("p", { className: "rounded-md border border-dashed border-border px-3 py-3 text-xs text-muted-foreground", children: secretsError })) : secrets.length === 0 ? (_jsx("p", { className: "rounded-md border border-dashed border-border px-3 py-3 text-xs text-muted-foreground", children: "No Dispatch vault keys found yet." })) : (secrets.map((secret) => {
|
|
272
275
|
const selected = selectedSecretIds.includes(secret.id);
|
|
273
276
|
return (_jsxs("div", { className: `group rounded-md border text-sm transition ${selected
|
|
@@ -11,6 +11,8 @@ export { CREDENTIAL_GAP_SIGNAL, isCredentialGapCodeAgentEvent, } from "../../cod
|
|
|
11
11
|
export { useSendToAgentChat } from "../use-send-to-agent-chat.js";
|
|
12
12
|
export { useChatModels, type UseChatModelsResult, type EngineModelGroup, } from "../use-chat-models.js";
|
|
13
13
|
export { CodeRequiredDialog, type CodeRequiredDialogProps, } from "../components/CodeRequiredDialog.js";
|
|
14
|
+
export { ChatFirstAgentActivityPanel, type ChatFirstAgentActivityPanelProps, } from "../chat-first-agent-activity.js";
|
|
15
|
+
export { ChatFirstSurfacePanelToggle } from "../chat-first-surface-panel-toggle.js";
|
|
14
16
|
export { useAgentEngineConfigured, type AgentEngineConfiguredState, type UseAgentEngineConfiguredResult, } from "../use-agent-engine-configured.js";
|
|
15
17
|
export { BuilderSetupCard } from "../chat/run-recovery.js";
|
|
16
18
|
export { AgentConversation, AgentConversationMessageView, normalizeCodeAgentTranscriptForConversation, useNearBottomAutoscroll, type CodeAgentConversationTranscriptEvent, type CodeAgentConversationTranscriptEventType, type NormalizeCodeAgentTranscriptOptions, type AgentConversationArtifact, type AgentConversationAttachment, type AgentConversationMessage, type AgentConversationMessagePart, type AgentConversationMessageRole, type AgentConversationNotice, type AgentConversationNoticeTone, type AgentConversationToolCall, type AgentConversationToolState, } from "../conversation/index.js";
|
|
@@ -29,7 +31,7 @@ export { useChatThreads, type ChatThreadScope, type ChatThreadSnapshot, type Cha
|
|
|
29
31
|
export { ChatHistoryList, type ChatHistoryItem, type ChatHistorySection, type ChatHistoryListProps, } from "../chat/ChatHistoryList.js";
|
|
30
32
|
export { AgentChatHome, type AgentChatHomeProps } from "../AgentChatHome.js";
|
|
31
33
|
export { AgentChatSurface, AgentPanel, AgentSidebar, AgentToggleButton, focusAgentChat, type AgentChatSurfaceMode, type AgentChatSurfaceProps, type AgentPanelProps, type AgentSidebarProps, } from "../AgentPanel.js";
|
|
32
|
-
export { AgentTabsPage, type AgentPageExtraTabContext, type AgentPageExtraTabFactory, type AgentTabsPageProps, } from "../agent-page/AgentTabsPage.js";
|
|
34
|
+
export { AgentTabsPage, ConnectionsTab, type AgentPageExtraTabContext, type AgentPageExtraTabFactory, type AgentTabsPageProps, } from "../agent-page/AgentTabsPage.js";
|
|
33
35
|
export type { AgentPageScope, AgentPageTabProps } from "../agent-page/types.js";
|
|
34
36
|
export { AGENT_CHAT_HOME_HANDOFF_TTL_MS, AGENT_CHAT_VIEW_TRANSITION_CLASS, AGENT_CHAT_VIEW_TRANSITION_NAME, consumeAgentChatHomeHandoff, getAgentChatViewTransitionStyle, isAgentChatHomeHandoffActive, markAgentChatHomeHandoff, navigateWithAgentChatViewTransition, startAgentChatViewTransition, supportsAgentChatViewTransition, type AgentChatHomeHandoffOptions, type AgentChatViewTransition, type AgentChatViewTransitionOptions, } from "../chat-view-transition.js";
|
|
35
37
|
export { useAgentChatHomeHandoff, useAgentChatHomeHandoffLinks, type UseAgentChatHomeHandoffLinksOptions, type UseAgentChatHomeHandoffOptions, } from "../use-agent-chat-home-handoff.js";
|
|
@@ -37,3 +39,4 @@ export { AGENT_SIDEBAR_DEFAULT_MAX_WIDTH, AGENT_SIDEBAR_MIN_WIDTH, AGENT_SIDEBAR
|
|
|
37
39
|
export { clearReservedToolRenderersForTests, clearToolRenderersForTests, registerActionChatRenderer, registerFallbackToolRenderer, registerReservedActionChatRenderer, registerReservedFallbackToolRenderer, registerReservedToolRenderer, registerToolRenderer, resolveToolRenderer, type ActionChatRendererRegistration, type ToolRendererComponent, type ToolRendererContext, type ToolRendererMatch, type ToolRendererProps, type ToolRendererRegistration, } from "../chat/tool-render-registry.js";
|
|
38
40
|
export * from "../chat/connectors.js";
|
|
39
41
|
export * from "../chat/runtime.js";
|
|
42
|
+
export { CHAT_FIRST_APP_LAYOUT_STORAGE_KEY, CHAT_FIRST_DEFAULT_APP_IDS, CHAT_FIRST_SURFACE_TABS_STORAGE_KEY, CHAT_FIRST_SURFACE_PANEL_STORAGE_KEY, CHAT_FIRST_SURFACE_WIDTH_DEFAULT, CHAT_FIRST_SURFACE_WIDTH_MIN, clampChatFirstSurfaceWidth, CHAT_FIRST_MODE_STORAGE_KEY, CHAT_FIRST_MODE_CHANGED_EVENT, CHAT_FIRST_OPEN_APP_EVENT, CHAT_FIRST_OPEN_BROWSER_EVENT, CHAT_FIRST_WATCH_SESSION_EVENT, CHAT_FIRST_SURFACE_CATALOG, chatFirstSurfaceTabId, closeChatFirstSessionWatch, emitChatFirstOpenApp, emitChatFirstOpenBrowser, emitChatFirstSessionWatch, getChatFirstSessionWatchStore, getChatFirstSurfaceTabsStore, getChatFirstSurfacePanelStore, orderChatFirstAppIds, readChatFirstAppLayout, resolveChatFirstAppTarget, resolveChatFirstBrowserTarget, resolveChatFirstSessionId, normalizeChatFirstSessionReference, readChatFirstMode, readChatFirstModeState, readChatFirstSurfaceWidth, subscribeChatFirstOpenApp, subscribeChatFirstOpenBrowser, subscribeChatFirstSessionWatch, useChatFirstSessionWatch, useChatFirstSurfaceResize, useChatFirstSurfacePanel, useChatFirstSurfaceTabs, writeChatFirstAppLayout, writeChatFirstMode, writeChatFirstSurfaceWidth, type ChatFirstAppLayoutPreference, type ChatFirstModeReadResult, type ChatFirstAppRegistration, type ChatFirstAppResolution, type ChatFirstAppTarget, type ChatFirstAgentActivity, type ChatFirstAgentActivityStatus, type ChatFirstOpenAppDelivery, type ChatFirstOpenAppDetail, type ChatFirstOpenBrowserDetail, type ChatFirstBrowserResolution, type ChatFirstSessionKind, type ChatFirstSessionReference, type ChatFirstSessionWatchDelivery, type ChatFirstSessionWatchState, type ChatFirstSessionWatchStore, type ChatFirstSurfaceKind, type ChatFirstSurfaceTab, type ChatFirstSurfacePanelState, type ChatFirstSurfacePanelStore, type ChatFirstSurfaceTabsState, type ChatFirstSurfaceTabsStore, } from "../chat-first.js";
|
|
@@ -11,6 +11,8 @@ export { CREDENTIAL_GAP_SIGNAL, isCredentialGapCodeAgentEvent, } from "../../cod
|
|
|
11
11
|
export { useSendToAgentChat } from "../use-send-to-agent-chat.js";
|
|
12
12
|
export { useChatModels, } from "../use-chat-models.js";
|
|
13
13
|
export { CodeRequiredDialog, } from "../components/CodeRequiredDialog.js";
|
|
14
|
+
export { ChatFirstAgentActivityPanel, } from "../chat-first-agent-activity.js";
|
|
15
|
+
export { ChatFirstSurfacePanelToggle } from "../chat-first-surface-panel-toggle.js";
|
|
14
16
|
export { useAgentEngineConfigured, } from "../use-agent-engine-configured.js";
|
|
15
17
|
export { BuilderSetupCard } from "../chat/run-recovery.js";
|
|
16
18
|
export { AgentConversation, AgentConversationMessageView, normalizeCodeAgentTranscriptForConversation, useNearBottomAutoscroll, } from "../conversation/index.js";
|
|
@@ -29,10 +31,11 @@ export { useChatThreads, } from "../use-chat-threads.js";
|
|
|
29
31
|
export { ChatHistoryList, } from "../chat/ChatHistoryList.js";
|
|
30
32
|
export { AgentChatHome } from "../AgentChatHome.js";
|
|
31
33
|
export { AgentChatSurface, AgentPanel, AgentSidebar, AgentToggleButton, focusAgentChat, } from "../AgentPanel.js";
|
|
32
|
-
export { AgentTabsPage, } from "../agent-page/AgentTabsPage.js";
|
|
34
|
+
export { AgentTabsPage, ConnectionsTab, } from "../agent-page/AgentTabsPage.js";
|
|
33
35
|
export { AGENT_CHAT_HOME_HANDOFF_TTL_MS, AGENT_CHAT_VIEW_TRANSITION_CLASS, AGENT_CHAT_VIEW_TRANSITION_NAME, consumeAgentChatHomeHandoff, getAgentChatViewTransitionStyle, isAgentChatHomeHandoffActive, markAgentChatHomeHandoff, navigateWithAgentChatViewTransition, startAgentChatViewTransition, supportsAgentChatViewTransition, } from "../chat-view-transition.js";
|
|
34
36
|
export { useAgentChatHomeHandoff, useAgentChatHomeHandoffLinks, } from "../use-agent-chat-home-handoff.js";
|
|
35
37
|
export { AGENT_SIDEBAR_DEFAULT_MAX_WIDTH, AGENT_SIDEBAR_MIN_WIDTH, AGENT_SIDEBAR_WIDE_WIDTH_RATIO, clampAgentSidebarWidth, getAgentSidebarMaxWidth, getAgentSidebarWideWidth, requestAgentSidebarOpen, SIDEBAR_STATE_CHANGE_EVENT, setAgentSidebarOpenPreference, } from "../agent-sidebar-state.js";
|
|
36
38
|
export { clearReservedToolRenderersForTests, clearToolRenderersForTests, registerActionChatRenderer, registerFallbackToolRenderer, registerReservedActionChatRenderer, registerReservedFallbackToolRenderer, registerReservedToolRenderer, registerToolRenderer, resolveToolRenderer, } from "../chat/tool-render-registry.js";
|
|
37
39
|
export * from "../chat/connectors.js";
|
|
38
40
|
export * from "../chat/runtime.js";
|
|
41
|
+
export { CHAT_FIRST_APP_LAYOUT_STORAGE_KEY, CHAT_FIRST_DEFAULT_APP_IDS, CHAT_FIRST_SURFACE_TABS_STORAGE_KEY, CHAT_FIRST_SURFACE_PANEL_STORAGE_KEY, CHAT_FIRST_SURFACE_WIDTH_DEFAULT, CHAT_FIRST_SURFACE_WIDTH_MIN, clampChatFirstSurfaceWidth, CHAT_FIRST_MODE_STORAGE_KEY, CHAT_FIRST_MODE_CHANGED_EVENT, CHAT_FIRST_OPEN_APP_EVENT, CHAT_FIRST_OPEN_BROWSER_EVENT, CHAT_FIRST_WATCH_SESSION_EVENT, CHAT_FIRST_SURFACE_CATALOG, chatFirstSurfaceTabId, closeChatFirstSessionWatch, emitChatFirstOpenApp, emitChatFirstOpenBrowser, emitChatFirstSessionWatch, getChatFirstSessionWatchStore, getChatFirstSurfaceTabsStore, getChatFirstSurfacePanelStore, orderChatFirstAppIds, readChatFirstAppLayout, resolveChatFirstAppTarget, resolveChatFirstBrowserTarget, resolveChatFirstSessionId, normalizeChatFirstSessionReference, readChatFirstMode, readChatFirstModeState, readChatFirstSurfaceWidth, subscribeChatFirstOpenApp, subscribeChatFirstOpenBrowser, subscribeChatFirstSessionWatch, useChatFirstSessionWatch, useChatFirstSurfaceResize, useChatFirstSurfacePanel, useChatFirstSurfaceTabs, writeChatFirstAppLayout, writeChatFirstMode, writeChatFirstSurfaceWidth, } from "../chat-first.js";
|
|
@@ -3,6 +3,7 @@ import type { ResourceView } from "../resources/ResourcesPanel.js";
|
|
|
3
3
|
import type { SettingsTabItem } from "../settings/SettingsTabsPage.js";
|
|
4
4
|
import type { AgentPageTabProps } from "./types.js";
|
|
5
5
|
export declare const AGENT_RESOURCE_DOCS_HREF: Record<ResourceView, string>;
|
|
6
|
+
export declare function ConnectionsTab({ canManageOrg, }?: Partial<AgentPageTabProps>): import("react").JSX.Element;
|
|
6
7
|
export declare const AGENT_ACCESS_DOCS_HREF: {
|
|
7
8
|
readonly mcp: "https://agent-native.com/docs/mcp-protocol";
|
|
8
9
|
readonly a2a: "https://agent-native.com/docs/a2a-protocol";
|
|
@@ -113,7 +113,7 @@ function ServerStatus({ server }) {
|
|
|
113
113
|
}
|
|
114
114
|
return (_jsx("span", { className: "text-[11px] text-muted-foreground", children: "Status unknown" }));
|
|
115
115
|
}
|
|
116
|
-
function ConnectionsTab({ canManageOrg =
|
|
116
|
+
export function ConnectionsTab({ canManageOrg, } = {}) {
|
|
117
117
|
const t = useT();
|
|
118
118
|
const serversQuery = useMcpServers();
|
|
119
119
|
const createServer = useCreateMcpServer();
|
|
@@ -123,8 +123,9 @@ function ConnectionsTab({ canManageOrg = false }) {
|
|
|
123
123
|
const [deleteTarget, setDeleteTarget] = useState(null);
|
|
124
124
|
const [error, setError] = useState(null);
|
|
125
125
|
const data = serversQuery.data;
|
|
126
|
+
const resolvedCanManageOrg = canManageOrg ?? (data?.role === "owner" || data?.role === "admin");
|
|
126
127
|
const hasOrg = Boolean(data?.orgId);
|
|
127
|
-
const canCreateOrgMcp = hasOrg &&
|
|
128
|
+
const canCreateOrgMcp = hasOrg && resolvedCanManageOrg;
|
|
128
129
|
const onCreateMcpServer = useCallback(async (args) => {
|
|
129
130
|
if (args.scope === "org" && !canCreateOrgMcp) {
|
|
130
131
|
throw new Error("Only organization admins can add organization agent integrations.");
|
|
@@ -152,7 +153,7 @@ function ConnectionsTab({ canManageOrg = false }) {
|
|
|
152
153
|
};
|
|
153
154
|
const renderServer = (server) => {
|
|
154
155
|
const key = `${server.scope}:${server.id}`;
|
|
155
|
-
const canDelete = server.scope === "user" ||
|
|
156
|
+
const canDelete = server.scope === "user" || resolvedCanManageOrg;
|
|
156
157
|
const selected = selectedServer?.id === server.id && selectedServer.scope === server.scope;
|
|
157
158
|
return (_jsxs("div", { className: cn("group/connection-row py-4 transition-colors first:pt-5 last:pb-5", selected && "bg-accent/20"), children: [_jsxs("div", { className: "flex items-start gap-3", children: [_jsxs("button", { type: "button", onClick: () => setSelectedServer(selected ? null : server), className: "min-w-0 flex-1 cursor-pointer text-start", children: [_jsx("div", { className: "flex flex-wrap items-center gap-2", children: _jsx("span", { className: "truncate text-sm font-medium text-foreground", children: server.name }) }), _jsx("code", { className: "mt-1 block truncate text-[11px] text-muted-foreground", children: server.url }), _jsxs("div", { className: "mt-2 flex items-center gap-2", children: [_jsx(ServerStatus, { server: server }), server.description && (_jsx("span", { className: "truncate text-[11px] text-muted-foreground/70", children: server.description }))] })] }), canDelete && (_jsx("button", { type: "button", onClick: () => void removeServer(server), disabled: deleteServer.isPending, className: cn("cursor-pointer rounded-md px-2 py-1 text-[11px] font-medium text-muted-foreground hover:bg-destructive/10 hover:text-destructive", deleteTarget === key && "bg-destructive/10 text-destructive"), children: deleteTarget === key ? "Confirm" : "Delete" }))] }), selected && (_jsx("div", { className: "mt-3 border-t border-border/70 pt-3", children: _jsx(McpServerDetail, { server: server }) }))] }, key));
|
|
158
159
|
};
|
|
@@ -108,6 +108,8 @@ export interface AppProvidersProps {
|
|
|
108
108
|
* its own scoped token. Public/SEO routes should use `isPublicPath` instead.
|
|
109
109
|
*/
|
|
110
110
|
sessionBypass?: boolean;
|
|
111
|
+
/** Fallback used if route metadata leaves the browser title empty or structured. */
|
|
112
|
+
documentTitleFallback?: string;
|
|
111
113
|
children: React.ReactNode;
|
|
112
114
|
}
|
|
113
|
-
export declare function AppProviders({ queryClient, isPublicPath, clientOnlyFallback, sessionBypass, defaultTheme, themeAttribute, tooltipDelayDuration, toaster, disableThemeTransitions, i18n, children, }: AppProvidersProps): React.JSX.Element;
|
|
115
|
+
export declare function AppProviders({ queryClient, isPublicPath, clientOnlyFallback, sessionBypass, defaultTheme, themeAttribute, tooltipDelayDuration, toaster, disableThemeTransitions, i18n, documentTitleFallback, children, }: AppProvidersProps): React.JSX.Element;
|