@agent-native/core 0.146.7 → 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/DEVELOPING.md +59 -0
- package/corpus/templates/analytics/app/routes/status.$slug.tsx +4 -2
- package/corpus/templates/analytics/package.json +1 -0
- package/corpus/templates/analytics/scripts/first-party-analytics-bigquery-backfill.ts +889 -0
- package/corpus/templates/analytics/server/jobs/analytics-bigquery-backfill.ts +70 -0
- package/corpus/templates/analytics/server/lib/first-party-analytics-backend.ts +117 -12
- 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/actions/run-factory-automation.ts +1 -0
- 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/factory/netlify.toml +1 -1
- 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/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/provider-api/actions/provider-api.d.ts +2 -2
- 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/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 +4 -3
- 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
|
@@ -311,8 +311,8 @@ export declare function createProviderApiActions(runtime: Pick<ProviderApiRuntim
|
|
|
311
311
|
notes?: string | undefined;
|
|
312
312
|
scope?: "org" | "user" | undefined;
|
|
313
313
|
}, {
|
|
314
|
-
message?: undefined;
|
|
315
314
|
id?: undefined;
|
|
315
|
+
message?: undefined;
|
|
316
316
|
provider?: undefined;
|
|
317
317
|
deleted?: undefined;
|
|
318
318
|
providers: {
|
|
@@ -329,9 +329,9 @@ export declare function createProviderApiActions(runtime: Pick<ProviderApiRuntim
|
|
|
329
329
|
registered?: undefined;
|
|
330
330
|
label?: undefined;
|
|
331
331
|
} | {
|
|
332
|
+
id?: undefined;
|
|
332
333
|
message?: undefined;
|
|
333
334
|
count?: undefined;
|
|
334
|
-
id?: undefined;
|
|
335
335
|
deleted?: undefined;
|
|
336
336
|
providers?: undefined;
|
|
337
337
|
found: boolean;
|
|
@@ -96,6 +96,8 @@ export interface AgentsBundle {
|
|
|
96
96
|
}
|
|
97
97
|
export interface AgentsBundleReadOptions {
|
|
98
98
|
instructions?: AgentNativeInstructionsConfig;
|
|
99
|
+
/** Additional skill roots supplied by a local host, such as installed plugins. */
|
|
100
|
+
additionalSkillDirs?: string[];
|
|
99
101
|
}
|
|
100
102
|
export interface AgentInstructionPaths {
|
|
101
103
|
runtime: string;
|
|
@@ -230,6 +230,27 @@ function readSkillsDir(skillsDir, rootForRelative, out, skipExistingNames) {
|
|
|
230
230
|
}
|
|
231
231
|
}
|
|
232
232
|
}
|
|
233
|
+
function readNestedSkillsDir(skillsDir, rootForRelative, out) {
|
|
234
|
+
if (!fs.existsSync(skillsDir))
|
|
235
|
+
return;
|
|
236
|
+
readSkillsDir(skillsDir, rootForRelative, out, true);
|
|
237
|
+
let entries;
|
|
238
|
+
try {
|
|
239
|
+
entries = fs.readdirSync(skillsDir, { withFileTypes: true });
|
|
240
|
+
}
|
|
241
|
+
catch {
|
|
242
|
+
return;
|
|
243
|
+
}
|
|
244
|
+
for (const entry of entries) {
|
|
245
|
+
if (!entry.isDirectory() || entry.name === "." || entry.name === "..") {
|
|
246
|
+
continue;
|
|
247
|
+
}
|
|
248
|
+
const nestedDir = path.join(skillsDir, entry.name);
|
|
249
|
+
if (fs.existsSync(path.join(nestedDir, "SKILL.md")))
|
|
250
|
+
continue;
|
|
251
|
+
readSkillsDir(nestedDir, rootForRelative, out, true);
|
|
252
|
+
}
|
|
253
|
+
}
|
|
233
254
|
/**
|
|
234
255
|
* Read AGENTS.md + all skills directly from the filesystem rooted at `cwd`.
|
|
235
256
|
* Optionally also reads a workspace-core's AGENTS.md and skills directory
|
|
@@ -256,9 +277,9 @@ export function readAgentsBundleFromFs(cwd, workspaceSource = null, options = {}
|
|
|
256
277
|
// overwrite the template's. `.agents/skills` is canonical; `.agent/skills`
|
|
257
278
|
// is accepted as a legacy alias and does not override canonical skills.
|
|
258
279
|
const skills = {};
|
|
259
|
-
for (const
|
|
280
|
+
for (const relSkillsDir of TEMPLATE_SKILLS_DIRS) {
|
|
260
281
|
try {
|
|
261
|
-
|
|
282
|
+
readNestedSkillsDir(path.join(cwd, relSkillsDir), cwd, skills);
|
|
262
283
|
}
|
|
263
284
|
catch { }
|
|
264
285
|
}
|
|
@@ -268,6 +289,14 @@ export function readAgentsBundleFromFs(cwd, workspaceSource = null, options = {}
|
|
|
268
289
|
}
|
|
269
290
|
catch { }
|
|
270
291
|
}
|
|
292
|
+
for (const skillsDir of options.additionalSkillDirs ?? []) {
|
|
293
|
+
try {
|
|
294
|
+
readNestedSkillsDir(skillsDir, cwd, skills);
|
|
295
|
+
}
|
|
296
|
+
catch {
|
|
297
|
+
// Optional host-provided skills must not make the coding session fail.
|
|
298
|
+
}
|
|
299
|
+
}
|
|
271
300
|
return {
|
|
272
301
|
// Keep the old field useful for callers that only know about the runtime
|
|
273
302
|
// bundle. Audience-aware consumers should use the explicit fields.
|
|
@@ -85,6 +85,12 @@ export declare function isDeployCredentialFallbackAllowed(): boolean;
|
|
|
85
85
|
export declare function canUseDeployCredentialFallbackForRequest(key?: string): boolean;
|
|
86
86
|
type BuilderCredentialSource = "user" | "org" | "workspace" | "env";
|
|
87
87
|
export declare function isBuilderPrivateKey(value: string | null | undefined): boolean;
|
|
88
|
+
export interface BuilderCredentialLookupIdentity {
|
|
89
|
+
/** The verified owner of a background run, when it has no browser request. */
|
|
90
|
+
userEmail?: string | null;
|
|
91
|
+
/** The verified organization attached to that run, when one exists. */
|
|
92
|
+
orgId?: string | null;
|
|
93
|
+
}
|
|
88
94
|
/**
|
|
89
95
|
* Resolve a Builder credential for the current request. User/org credentials
|
|
90
96
|
* win; deployment env is only a fallback. This lets local/root .env keys keep
|
|
@@ -153,13 +159,13 @@ export interface BuilderCredentialsDetailed {
|
|
|
153
159
|
* Callers that only need the plain credential bundle (the historical shape)
|
|
154
160
|
* should use `resolveBuilderCredentials()` instead.
|
|
155
161
|
*/
|
|
156
|
-
export declare function resolveBuilderCredentialsDetailed(): Promise<BuilderCredentialsDetailed>;
|
|
162
|
+
export declare function resolveBuilderCredentialsDetailed(identity?: BuilderCredentialLookupIdentity): Promise<BuilderCredentialsDetailed>;
|
|
157
163
|
/**
|
|
158
164
|
* Resolve the Builder assistant credential bundle from one complete scope.
|
|
159
165
|
* Kept to its original return shape (no `source`/`lookupFailed`) for existing
|
|
160
166
|
* callers; use `resolveBuilderCredentialsDetailed()` for those fields.
|
|
161
167
|
*/
|
|
162
|
-
export declare function resolveBuilderCredentials(): Promise<{
|
|
168
|
+
export declare function resolveBuilderCredentials(identity?: BuilderCredentialLookupIdentity): Promise<{
|
|
163
169
|
privateKey: string | null;
|
|
164
170
|
publicKey: string | null;
|
|
165
171
|
userId: string | null;
|
|
@@ -444,8 +444,8 @@ async function resolveScopedBuilderCredential(key) {
|
|
|
444
444
|
cause: orgLookupCause,
|
|
445
445
|
};
|
|
446
446
|
}
|
|
447
|
-
async function resolveScopedBuilderCredentials() {
|
|
448
|
-
const email = getRequestUserEmail();
|
|
447
|
+
async function resolveScopedBuilderCredentials(identity) {
|
|
448
|
+
const email = identity?.userEmail?.trim() || getRequestUserEmail();
|
|
449
449
|
if (!email)
|
|
450
450
|
return { creds: null, lookupFailed: false };
|
|
451
451
|
const traceLookup = shouldTraceCredentialResolve();
|
|
@@ -463,7 +463,7 @@ async function resolveScopedBuilderCredentials() {
|
|
|
463
463
|
if (await isCompleteBuilderConnection(userCreds)) {
|
|
464
464
|
return { creds: userCreds, lookupFailed: false };
|
|
465
465
|
}
|
|
466
|
-
let orgId = getRequestOrgId();
|
|
466
|
+
let orgId = identity?.orgId?.trim() || getRequestOrgId();
|
|
467
467
|
let orgSource = orgId
|
|
468
468
|
? "request"
|
|
469
469
|
: "none";
|
|
@@ -527,8 +527,12 @@ export async function resolveBuilderCredential(key) {
|
|
|
527
527
|
const envValue = canUseBuilderDeployCredentialFallbackForRequest()
|
|
528
528
|
? (readDeployCredentialEnv(key) ?? null)
|
|
529
529
|
: null;
|
|
530
|
-
if (envValue)
|
|
530
|
+
if (envValue) {
|
|
531
|
+
// A deploy fallback is still useful, but it must not turn a transient
|
|
532
|
+
// credential-store failure into a clean connected result for Builder.
|
|
533
|
+
assertCredentialStoreReadable(scoped);
|
|
531
534
|
return envValue;
|
|
535
|
+
}
|
|
532
536
|
// Nothing answered AND the store never gave a real answer: that is not
|
|
533
537
|
// "not connected", it is "we could not look".
|
|
534
538
|
assertCredentialStoreReadable(scoped);
|
|
@@ -589,8 +593,8 @@ export async function resolveBuilderCredentialSource() {
|
|
|
589
593
|
* Callers that only need the plain credential bundle (the historical shape)
|
|
590
594
|
* should use `resolveBuilderCredentials()` instead.
|
|
591
595
|
*/
|
|
592
|
-
export async function resolveBuilderCredentialsDetailed() {
|
|
593
|
-
const { creds: scoped, lookupFailed, cause, } = await resolveScopedBuilderCredentials();
|
|
596
|
+
export async function resolveBuilderCredentialsDetailed(identity) {
|
|
597
|
+
const { creds: scoped, lookupFailed, cause, } = await resolveScopedBuilderCredentials(identity);
|
|
594
598
|
if (scoped) {
|
|
595
599
|
const { privateKey, publicKey, userId, orgName, orgKind, subscription, subscriptionLevel, subscriptionName, isEnterprise, isFreeAccount, source, } = scoped;
|
|
596
600
|
return {
|
|
@@ -683,8 +687,8 @@ export async function resolveBuilderCredentialsDetailed() {
|
|
|
683
687
|
* Kept to its original return shape (no `source`/`lookupFailed`) for existing
|
|
684
688
|
* callers; use `resolveBuilderCredentialsDetailed()` for those fields.
|
|
685
689
|
*/
|
|
686
|
-
export async function resolveBuilderCredentials() {
|
|
687
|
-
const { privateKey, publicKey, userId, orgName, orgKind, subscription, subscriptionLevel, subscriptionName, isEnterprise, isFreeAccount, } = await resolveBuilderCredentialsDetailed();
|
|
690
|
+
export async function resolveBuilderCredentials(identity) {
|
|
691
|
+
const { privateKey, publicKey, userId, orgName, orgKind, subscription, subscriptionLevel, subscriptionName, isEnterprise, isFreeAccount, } = await resolveBuilderCredentialsDetailed(identity);
|
|
688
692
|
return {
|
|
689
693
|
privateKey,
|
|
690
694
|
publicKey,
|
|
@@ -1210,7 +1214,7 @@ export async function resolveSecretDetailed(key) {
|
|
|
1210
1214
|
}
|
|
1211
1215
|
return {
|
|
1212
1216
|
value: envFallback,
|
|
1213
|
-
lookupFailed
|
|
1217
|
+
lookupFailed,
|
|
1214
1218
|
cause,
|
|
1215
1219
|
};
|
|
1216
1220
|
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
export type ChatFirstAppCreationVaultAccessMode = "all-apps" | "manual";
|
|
2
|
+
export interface ChatFirstAppCreationResource {
|
|
3
|
+
name: string;
|
|
4
|
+
kind: string;
|
|
5
|
+
path: string;
|
|
6
|
+
}
|
|
7
|
+
export interface ChatFirstAppCreationPromptInput {
|
|
8
|
+
appId: string;
|
|
9
|
+
prompt: string;
|
|
10
|
+
selectedKeys: string[];
|
|
11
|
+
selectedResources: ChatFirstAppCreationResource[];
|
|
12
|
+
vaultAccessMode: ChatFirstAppCreationVaultAccessMode;
|
|
13
|
+
appRoot?: string;
|
|
14
|
+
mountPath?: string;
|
|
15
|
+
scaffoldCommand?: string;
|
|
16
|
+
additionalInstructions?: string[];
|
|
17
|
+
}
|
|
18
|
+
export declare function titleFromChatFirstAppPrompt(prompt: string): string;
|
|
19
|
+
export declare function buildChatFirstAppCreationPrompt(input: ChatFirstAppCreationPromptInput): string;
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
function slugify(value) {
|
|
2
|
+
return value
|
|
3
|
+
.toLowerCase()
|
|
4
|
+
.replace(/[^a-z0-9]+/g, "-")
|
|
5
|
+
.replace(/^-+|-+$/g, "")
|
|
6
|
+
.replace(/^[^a-z]+/, "")
|
|
7
|
+
.slice(0, 48);
|
|
8
|
+
}
|
|
9
|
+
export function titleFromChatFirstAppPrompt(prompt) {
|
|
10
|
+
const cleaned = prompt
|
|
11
|
+
.replace(/\b(build|create|make|an?|the|app|tool|dashboard)\b/gi, " ")
|
|
12
|
+
.replace(/\s+/g, " ")
|
|
13
|
+
.trim();
|
|
14
|
+
return slugify(cleaned || "new-app") || "new-app";
|
|
15
|
+
}
|
|
16
|
+
export function buildChatFirstAppCreationPrompt(input) {
|
|
17
|
+
const appRoot = input.appRoot?.trim() || `apps/${input.appId}`;
|
|
18
|
+
const mountPath = input.mountPath?.trim() || `/${input.appId}`;
|
|
19
|
+
const packagePath = `${appRoot.replace(/\/+$/, "")}/package.json`;
|
|
20
|
+
const keyList = input.selectedKeys.join(", ");
|
|
21
|
+
const grantRequest = input.vaultAccessMode === "all-apps"
|
|
22
|
+
? "Dispatch vault access: all saved vault keys are available to every workspace app by default. No per-app vault grants are needed."
|
|
23
|
+
: keyList
|
|
24
|
+
? `Requested Dispatch vault key grants for this app: ${keyList}`
|
|
25
|
+
: "Requested Dispatch vault key grants for this app: none";
|
|
26
|
+
const resourceList = input.selectedResources.length
|
|
27
|
+
? input.selectedResources
|
|
28
|
+
.map((resource) => `- ${resource.name} (${resource.kind}, ${resource.path})`)
|
|
29
|
+
.join("\n")
|
|
30
|
+
: "none";
|
|
31
|
+
const scaffoldInstructions = input.scaffoldCommand
|
|
32
|
+
? ["", "Scaffold instructions:", input.scaffoldCommand]
|
|
33
|
+
: [];
|
|
34
|
+
return [
|
|
35
|
+
"Create a new agent-native app in this workspace.",
|
|
36
|
+
"This is a new workspace app request, not a feature request for the current app.",
|
|
37
|
+
...scaffoldInstructions,
|
|
38
|
+
"",
|
|
39
|
+
`Suggested app name: ${input.appId} (you may adjust the slug if it conflicts)`,
|
|
40
|
+
`User prompt: ${input.prompt.trim()}`,
|
|
41
|
+
`Generate a concise one-sentence app description from the user prompt before coding; save it in ${packagePath} \"description\" so Dispatch and A2A can describe the app.`,
|
|
42
|
+
"If the user mentions a product or company such as Granola, Loom, Superhuman, Linear, or Notion, treat it as product inspiration unless they explicitly ask to connect to that service. Do not invent or require third-party API keys like GRANOLA_API_KEY just because a product is named.",
|
|
43
|
+
grantRequest,
|
|
44
|
+
`Requested Dispatch workspace resources for this app:\n${resourceList}`,
|
|
45
|
+
"Dispatch workspace resources with scope=all are inherited workspace context. Do not copy or sync them into the new app; every workspace app reads them at runtime and may override with app shared or personal resources.",
|
|
46
|
+
"",
|
|
47
|
+
"Pick a UI template that fits the user's prompt - analytics, assets, brain, calendar, chat, content, design, dispatch, forms, mail, slides, or clips when none of the others fit.",
|
|
48
|
+
'If you use the chat template, treat it as scaffolding only: the finished app must use the requested app\'s real name, home screen, navigation, package metadata, and manifest, and it must not leave visible "Chat", "Starter", "Blank app", or "New app" UI behind.',
|
|
49
|
+
`Use the workspace app layout: create it under ${appRoot}, mount it at ${mountPath}, keep it on the shared workspace database/hosting model, and avoid table-name collisions by namespacing any new domain tables to the app.`,
|
|
50
|
+
`Important routing rule: from outside the app, link to ${mountPath}; inside ${appRoot}, React Router routes are app-local. Use <Link to=\"/review\"> and navigate(\"/review\"), not \"${mountPath}/review\"; APP_BASE_PATH supplies the mounted prefix, and hardcoding it causes doubled URLs.`,
|
|
51
|
+
'Prefer useActionQuery/useActionMutation for actions. If you must raw-fetch framework endpoints, wrap them with agentNativePath("/_agent-native/actions/<name>") so mounted apps call the right URL.',
|
|
52
|
+
`Use relative workspace links like ${mountPath}. Do not hardcode localhost, 127.0.0.1, 8080, 8100, or any dev port; the active workspace gateway or Desktop shell owns the port.`,
|
|
53
|
+
"Use the framework/template UI stack: shadcn/ui components and @tabler/icons-react. Do not add lucide-react or another icon library for standard UI.",
|
|
54
|
+
"Existing first-party apps are neighbors, not implementation details for this app. If the user's prompt mentions Mail, Calendar, Analytics, Brain, Assets, Dispatch, or other templates, treat them as existing hosted/connected apps that this app can link to or call through A2A/default connected agents. For example, Mail, Calendar, Analytics, Brain, and Assets already exist at https://mail.agent-native.com, https://calendar.agent-native.com, https://analytics.agent-native.com, https://brain.agent-native.com, and https://assets.agent-native.com.",
|
|
55
|
+
`Do not create wrapper apps or scaffold child apps/routes for Mail, Calendar, Analytics, Brain, Assets, etc. inside ${appRoot} just so this app can access them. If the request is a cross-app dashboard or overview, build only the new dashboard/overview app and delegate to the existing apps for domain work.`,
|
|
56
|
+
"Only create another first-party app when the user explicitly asks for a customized app from that template; otherwise keep using the hosted/shared app so improvements to the base app keep flowing to users.",
|
|
57
|
+
"Do not satisfy this by adding a route, page, component, or file inside apps/chat or another existing app unless the user explicitly asks to modify that existing app.",
|
|
58
|
+
input.vaultAccessMode === "all-apps"
|
|
59
|
+
? "Do not create per-app Dispatch vault grants unless the workspace switches vault access to manual or the user explicitly asks for manual grants."
|
|
60
|
+
: keyList
|
|
61
|
+
? `After the app exists, grant the selected Dispatch vault keys to appId "${input.appId}" and sync them once the app server is available. Treat these as requested grants, not active grants before creation succeeds.`
|
|
62
|
+
: "Do not grant any Dispatch vault keys unless the user asks later.",
|
|
63
|
+
input.selectedResources.length
|
|
64
|
+
? `After the app exists, grant the selected Dispatch workspace resources to appId "${input.appId}". Do not sync All-app workspace resources; they are inherited.`
|
|
65
|
+
: "Do not grant any selected-only Dispatch workspace resources unless the user asks later.",
|
|
66
|
+
"",
|
|
67
|
+
"App readiness requirements before handing off:",
|
|
68
|
+
`- Ensure ${packagePath} exists with displayName/name and a concise description; Dispatch discovers workspace apps from the workspace filesystem and app metadata.`,
|
|
69
|
+
"- Update the app manifest/package/deploy metadata needed by the existing workspace deployment model.",
|
|
70
|
+
`- Ensure the React Router client entry preserves APP_BASE_PATH/VITE_APP_BASE_PATH so ${mountPath} hydrates correctly.`,
|
|
71
|
+
"- Verify the app's agent card/A2A metadata is ready so Dispatch can discover and delegate to the app after deployment. Every sibling workspace app is available over A2A by default through call-agent, with names and descriptions from the workspace app registry.",
|
|
72
|
+
`When it is ready, start or update the workspace dev server and navigate the user to ${mountPath} on the workspace origin. Do not prefix it with /dispatch/, /apps/, /workspace/, or any other Dispatch tab.`,
|
|
73
|
+
...(input.additionalInstructions ?? []),
|
|
74
|
+
].join("\n");
|
|
75
|
+
}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Browser titles must be human-readable strings. React Router stringifies a
|
|
3
|
+
* structured `title` value, which otherwise leaks the whole payload into the
|
|
4
|
+
* browser tab.
|
|
5
|
+
*/
|
|
6
|
+
export declare function isHumanReadableDocumentTitle(value: unknown): value is string;
|
|
7
|
+
export declare function normalizeDocumentTitle(value: unknown, fallbackTitle: string): string;
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
const STRUCTURED_TITLE_START = /^[\[{]/;
|
|
2
|
+
/**
|
|
3
|
+
* Browser titles must be human-readable strings. React Router stringifies a
|
|
4
|
+
* structured `title` value, which otherwise leaks the whole payload into the
|
|
5
|
+
* browser tab.
|
|
6
|
+
*/
|
|
7
|
+
export function isHumanReadableDocumentTitle(value) {
|
|
8
|
+
if (typeof value !== "string")
|
|
9
|
+
return false;
|
|
10
|
+
const title = value.trim();
|
|
11
|
+
if (!title)
|
|
12
|
+
return false;
|
|
13
|
+
if (!STRUCTURED_TITLE_START.test(title))
|
|
14
|
+
return true;
|
|
15
|
+
try {
|
|
16
|
+
const parsed = JSON.parse(title);
|
|
17
|
+
return parsed === null || typeof parsed !== "object";
|
|
18
|
+
}
|
|
19
|
+
catch {
|
|
20
|
+
return true;
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
export function normalizeDocumentTitle(value, fallbackTitle) {
|
|
24
|
+
if (isHumanReadableDocumentTitle(value))
|
|
25
|
+
return value.trim();
|
|
26
|
+
if (isHumanReadableDocumentTitle(fallbackTitle))
|
|
27
|
+
return fallbackTitle.trim();
|
|
28
|
+
return "Agent Native";
|
|
29
|
+
}
|
package/dist/shared/index.d.ts
CHANGED
|
@@ -3,6 +3,7 @@ export { agentEnv, type EnvVar } from "./agent-env.js";
|
|
|
3
3
|
export { extractOAuthStateAppId } from "./oauth-state.js";
|
|
4
4
|
export { SIGN_IN_CONTINUATION_MAX_LENGTH, SIGN_IN_CONTINUATION_PARAM, SIGN_IN_ENTRY_PATH, SIGN_IN_LEGACY_ENTRY_PATH, SIGN_IN_LEGACY_RETURN_PARAM, decodeContinuation, encodeContinuation, normalizeAppPath, signInJourney, signInJourneyInlineScript, type SignInJourney, type SignInJourneyInput, } from "./sign-in-journey.js";
|
|
5
5
|
export { truncate } from "./truncate.js";
|
|
6
|
+
export { isHumanReadableDocumentTitle, normalizeDocumentTitle, } from "./document-title.js";
|
|
6
7
|
export { injectDocumentMarkup } from "./html-document.js";
|
|
7
8
|
export { withBuilderUtmTrackingParams } from "./builder-link-tracking.js";
|
|
8
9
|
export { buildRuntimeConfigPrompt, formatRuntimeConfigReport, getRuntimeConfigReport, parseRuntimeConfigReport, runtimeConfigRequirementsFromSearchParams, type RuntimeConfigEnvironment, type RuntimeConfigIssue, type RuntimeConfigIssueCode, type RuntimeConfigIssueSeverity, type RuntimeConfigPhase, type RuntimeConfigReport, type RuntimeConfigRequirements, } from "./runtime-config.js";
|
|
@@ -10,6 +11,7 @@ export { llmConnectionTrackingProperties, normalizeLlmConnection, type LlmConnec
|
|
|
10
11
|
export { DISPATCH_WORKSPACE_ROOT_REDIRECTS, RESERVED_WORKSPACE_APP_IDS, assertValidWorkspaceAppId, getWorkspaceAppIdValidationError, isValidWorkspaceAppIdFormat, } from "./workspace-app-id.js";
|
|
11
12
|
export { DEFAULT_WORKSPACE_APP_AUDIENCE, WORKSPACE_APP_AUDIENCES, normalizeWorkspaceAppAudience, normalizeWorkspaceAppPathList, workspaceAppAudienceFromEnv, workspaceAppAudienceFromPackageJson, workspaceAppRouteAccessFromEnv, workspaceAppRouteAccessFromPackageJson, type WorkspaceAppRouteAccess, type WorkspaceAppRouteAccessFromConfig, type WorkspaceAppAudience, } from "./workspace-app-audience.js";
|
|
12
13
|
export { AGENT_NATIVE_OPEN_PATH, AGENT_SIDEBAR_QUERY_PARAM, AGENT_SIDEBAR_QUERY_VALUE_CLOSED, isAgentNativeOpenDeepLink, withCollapsedAgentSidebarParam, } from "./agent-sidebar-url.js";
|
|
14
|
+
export { buildChatFirstAppCreationPrompt, titleFromChatFirstAppPrompt, type ChatFirstAppCreationPromptInput, type ChatFirstAppCreationResource, type ChatFirstAppCreationVaultAccessMode, } from "./chat-first-app-creation.js";
|
|
13
15
|
export { createPollEngine, type PollEngineOptions, type PollEngineHandle, } from "./poll-engine.js";
|
|
14
16
|
export { AGENT_NATIVE_DEFAULT_SOCIAL_IMAGE, AGENT_NATIVE_SOCIAL_IMAGE_CACHE_BUSTER, AGENT_NATIVE_SOCIAL_IMAGE_ALT, AGENT_NATIVE_SOCIAL_IMAGE_HEIGHT, AGENT_NATIVE_SOCIAL_IMAGE_PATH, AGENT_NATIVE_SOCIAL_IMAGE_TYPE, AGENT_NATIVE_SOCIAL_IMAGE_WIDTH, defaultSocialImageMeta, withAgentNativeSocialImageCacheBuster, withDefaultSocialImage, type SocialMetaDescriptor, } from "./social-meta.js";
|
|
15
17
|
export { EMBED_MODE_QUERY_PARAM, EMBED_SESSION_COOKIE, EMBED_START_PATH, EMBED_TOKEN_QUERY_PARAM, } from "./embed-auth.js";
|
package/dist/shared/index.js
CHANGED
|
@@ -3,6 +3,7 @@ export { agentEnv } from "./agent-env.js";
|
|
|
3
3
|
export { extractOAuthStateAppId } from "./oauth-state.js";
|
|
4
4
|
export { SIGN_IN_CONTINUATION_MAX_LENGTH, SIGN_IN_CONTINUATION_PARAM, SIGN_IN_ENTRY_PATH, SIGN_IN_LEGACY_ENTRY_PATH, SIGN_IN_LEGACY_RETURN_PARAM, decodeContinuation, encodeContinuation, normalizeAppPath, signInJourney, signInJourneyInlineScript, } from "./sign-in-journey.js";
|
|
5
5
|
export { truncate } from "./truncate.js";
|
|
6
|
+
export { isHumanReadableDocumentTitle, normalizeDocumentTitle, } from "./document-title.js";
|
|
6
7
|
export { injectDocumentMarkup } from "./html-document.js";
|
|
7
8
|
export { withBuilderUtmTrackingParams } from "./builder-link-tracking.js";
|
|
8
9
|
export { buildRuntimeConfigPrompt, formatRuntimeConfigReport, getRuntimeConfigReport, parseRuntimeConfigReport, runtimeConfigRequirementsFromSearchParams, } from "./runtime-config.js";
|
|
@@ -10,6 +11,7 @@ export { llmConnectionTrackingProperties, normalizeLlmConnection, } from "./llm-
|
|
|
10
11
|
export { DISPATCH_WORKSPACE_ROOT_REDIRECTS, RESERVED_WORKSPACE_APP_IDS, assertValidWorkspaceAppId, getWorkspaceAppIdValidationError, isValidWorkspaceAppIdFormat, } from "./workspace-app-id.js";
|
|
11
12
|
export { DEFAULT_WORKSPACE_APP_AUDIENCE, WORKSPACE_APP_AUDIENCES, normalizeWorkspaceAppAudience, normalizeWorkspaceAppPathList, workspaceAppAudienceFromEnv, workspaceAppAudienceFromPackageJson, workspaceAppRouteAccessFromEnv, workspaceAppRouteAccessFromPackageJson, } from "./workspace-app-audience.js";
|
|
12
13
|
export { AGENT_NATIVE_OPEN_PATH, AGENT_SIDEBAR_QUERY_PARAM, AGENT_SIDEBAR_QUERY_VALUE_CLOSED, isAgentNativeOpenDeepLink, withCollapsedAgentSidebarParam, } from "./agent-sidebar-url.js";
|
|
14
|
+
export { buildChatFirstAppCreationPrompt, titleFromChatFirstAppPrompt, } from "./chat-first-app-creation.js";
|
|
13
15
|
export { createPollEngine, } from "./poll-engine.js";
|
|
14
16
|
export { AGENT_NATIVE_DEFAULT_SOCIAL_IMAGE, AGENT_NATIVE_SOCIAL_IMAGE_CACHE_BUSTER, AGENT_NATIVE_SOCIAL_IMAGE_ALT, AGENT_NATIVE_SOCIAL_IMAGE_HEIGHT, AGENT_NATIVE_SOCIAL_IMAGE_PATH, AGENT_NATIVE_SOCIAL_IMAGE_TYPE, AGENT_NATIVE_SOCIAL_IMAGE_WIDTH, defaultSocialImageMeta, withAgentNativeSocialImageCacheBuster, withDefaultSocialImage, } from "./social-meta.js";
|
|
15
17
|
export { EMBED_MODE_QUERY_PARAM, EMBED_SESSION_COOKIE, EMBED_START_PATH, EMBED_TOKEN_QUERY_PARAM, } from "./embed-auth.js";
|
|
@@ -1 +1,17 @@
|
|
|
1
1
|
@import "@agent-native/toolkit/chat-history.css";
|
|
2
|
+
|
|
3
|
+
/* Chat-first rails share this geometry across Dispatch and Electron. Keep
|
|
4
|
+
the row at the same compact rhythm as the primary nav and app list. */
|
|
5
|
+
section[data-chat-first-chat-history]
|
|
6
|
+
.an-chat-history--rail
|
|
7
|
+
.an-chat-history-row {
|
|
8
|
+
margin-inline: 0;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
section[data-chat-first-chat-history]
|
|
12
|
+
.an-chat-history--rail
|
|
13
|
+
.an-chat-history-row__button {
|
|
14
|
+
min-height: 28px;
|
|
15
|
+
padding-block: 4px;
|
|
16
|
+
padding-inline: 8px 32px;
|
|
17
|
+
}
|
|
@@ -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
|
|
@@ -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
|
|
@@ -4,4 +4,22 @@ export default {
|
|
|
4
4
|
appDirectory: "app",
|
|
5
5
|
ssr: true,
|
|
6
6
|
routeDiscovery: { mode: "initial" },
|
|
7
|
+
|
|
8
|
+
// Prerendering writes a route's HTML to a static file at build time, so a CDN
|
|
9
|
+
// cache miss serves that file instead of cold-starting the SSR function
|
|
10
|
+
// (seconds of TTFB). It is off here because every route this app ships with is
|
|
11
|
+
// signed-in and personalized, and a prerendered file is served without the
|
|
12
|
+
// auth middleware ever running — freezing the wrong page for every visitor is
|
|
13
|
+
// far worse than a slow first byte.
|
|
14
|
+
//
|
|
15
|
+
// Turn it on only for paths that are all of: publicly reachable, rendered from
|
|
16
|
+
// build-time content alone (no loader data, query string, cookie, session, or
|
|
17
|
+
// database read), and never answering a redirect — prerender would bake a 301
|
|
18
|
+
// into a 200 HTML page. Keep the list in one shared constant and derive the
|
|
19
|
+
// auth plugin's `publicPaths` from it so the two cannot drift:
|
|
20
|
+
//
|
|
21
|
+
// import { PRERENDERED_PUBLIC_PAGE_PATHS } from "./shared/prerendered-public-paths";
|
|
22
|
+
// prerender: { paths: () => [...PRERENDERED_PUBLIC_PAGE_PATHS] },
|
|
23
|
+
//
|
|
24
|
+
// See `.agents/skills/performance/SKILL.md` §9.
|
|
7
25
|
} satisfies Config;
|