@agent-native/core 0.59.1 → 0.61.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/dist/a2a/index.d.ts +2 -0
- package/dist/a2a/index.d.ts.map +1 -1
- package/dist/a2a/index.js +1 -0
- package/dist/a2a/index.js.map +1 -1
- package/dist/a2a/invoke.d.ts +63 -0
- package/dist/a2a/invoke.d.ts.map +1 -0
- package/dist/a2a/invoke.js +157 -0
- package/dist/a2a/invoke.js.map +1 -0
- package/dist/agent/run-store.d.ts +15 -0
- package/dist/agent/run-store.d.ts.map +1 -1
- package/dist/agent/run-store.js +28 -0
- package/dist/agent/run-store.js.map +1 -1
- package/dist/chat-threads/store.d.ts +21 -0
- package/dist/chat-threads/store.d.ts.map +1 -1
- package/dist/chat-threads/store.js +128 -0
- package/dist/chat-threads/store.js.map +1 -1
- package/dist/cli/agent.d.ts +23 -0
- package/dist/cli/agent.d.ts.map +1 -0
- package/dist/cli/agent.js +300 -0
- package/dist/cli/agent.js.map +1 -0
- package/dist/cli/agents.d.ts +14 -0
- package/dist/cli/agents.d.ts.map +1 -0
- package/dist/cli/agents.js +95 -0
- package/dist/cli/agents.js.map +1 -0
- package/dist/cli/code-agent-executor.d.ts.map +1 -1
- package/dist/cli/code-agent-executor.js +264 -2
- package/dist/cli/code-agent-executor.js.map +1 -1
- package/dist/cli/create.d.ts +3 -2
- package/dist/cli/create.d.ts.map +1 -1
- package/dist/cli/create.js +154 -83
- package/dist/cli/create.js.map +1 -1
- package/dist/cli/index.js +50 -2
- package/dist/cli/index.js.map +1 -1
- package/dist/cli/invoke.d.ts +26 -0
- package/dist/cli/invoke.d.ts.map +1 -0
- package/dist/cli/invoke.js +227 -0
- package/dist/cli/invoke.js.map +1 -0
- package/dist/cli/templates-meta.d.ts +1 -1
- package/dist/cli/templates-meta.d.ts.map +1 -1
- package/dist/cli/templates-meta.js +9 -8
- package/dist/cli/templates-meta.js.map +1 -1
- package/dist/cli/workspacify.d.ts +1 -1
- package/dist/cli/workspacify.d.ts.map +1 -1
- package/dist/cli/workspacify.js +6 -6
- package/dist/cli/workspacify.js.map +1 -1
- package/dist/client/NewWorkspaceAppFlow.d.ts.map +1 -1
- package/dist/client/NewWorkspaceAppFlow.js +5 -4
- package/dist/client/NewWorkspaceAppFlow.js.map +1 -1
- package/dist/client/blocks/library/diagram.d.ts.map +1 -1
- package/dist/client/blocks/library/diagram.js +23 -17
- package/dist/client/blocks/library/diagram.js.map +1 -1
- package/dist/client/blocks/types.d.ts +2 -0
- package/dist/client/blocks/types.d.ts.map +1 -1
- package/dist/client/blocks/types.js.map +1 -1
- package/dist/client/chat/index.d.ts +1 -1
- package/dist/client/chat/index.d.ts.map +1 -1
- package/dist/client/chat/index.js.map +1 -1
- package/dist/client/index.d.ts +1 -1
- package/dist/client/index.d.ts.map +1 -1
- package/dist/client/index.js.map +1 -1
- package/dist/client/settings/useBuilderStatus.d.ts +10 -0
- package/dist/client/settings/useBuilderStatus.d.ts.map +1 -1
- package/dist/client/settings/useBuilderStatus.js.map +1 -1
- package/dist/client/use-chat-threads.d.ts +13 -0
- package/dist/client/use-chat-threads.d.ts.map +1 -1
- package/dist/client/use-chat-threads.js +41 -0
- package/dist/client/use-chat-threads.js.map +1 -1
- package/dist/integrations/plugin.d.ts.map +1 -1
- package/dist/integrations/plugin.js +2 -2
- package/dist/integrations/plugin.js.map +1 -1
- package/dist/onboarding/default-steps.d.ts.map +1 -1
- package/dist/onboarding/default-steps.js +102 -0
- package/dist/onboarding/default-steps.js.map +1 -1
- package/dist/provider-api/actions/github-repo-files.d.ts +84 -0
- package/dist/provider-api/actions/github-repo-files.d.ts.map +1 -0
- package/dist/provider-api/actions/github-repo-files.js +213 -0
- package/dist/provider-api/actions/github-repo-files.js.map +1 -0
- package/dist/provider-api/github-repo.d.ts +11 -0
- package/dist/provider-api/github-repo.d.ts.map +1 -0
- package/dist/provider-api/github-repo.js +553 -0
- package/dist/provider-api/github-repo.js.map +1 -0
- package/dist/provider-api/index.d.ts +184 -11
- package/dist/provider-api/index.d.ts.map +1 -1
- package/dist/provider-api/index.js +519 -0
- package/dist/provider-api/index.js.map +1 -1
- package/dist/scripts/docs/search.d.ts.map +1 -1
- package/dist/scripts/docs/search.js +38 -13
- package/dist/scripts/docs/search.js.map +1 -1
- package/dist/secrets/register-framework-secrets.d.ts.map +1 -1
- package/dist/secrets/register-framework-secrets.js +11 -0
- package/dist/secrets/register-framework-secrets.js.map +1 -1
- package/dist/server/agent-chat-plugin.d.ts +32 -0
- package/dist/server/agent-chat-plugin.d.ts.map +1 -1
- package/dist/server/agent-chat-plugin.js +297 -2
- package/dist/server/agent-chat-plugin.js.map +1 -1
- package/dist/server/auth-marketing.d.ts.map +1 -1
- package/dist/server/auth-marketing.js +17 -7
- package/dist/server/auth-marketing.js.map +1 -1
- package/dist/server/auth.d.ts.map +1 -1
- package/dist/server/auth.js +6 -0
- package/dist/server/auth.js.map +1 -1
- package/dist/server/builder-browser.d.ts +11 -0
- package/dist/server/builder-browser.d.ts.map +1 -1
- package/dist/server/builder-browser.js.map +1 -1
- package/dist/server/builder-space.d.ts +47 -0
- package/dist/server/builder-space.d.ts.map +1 -0
- package/dist/server/builder-space.js +142 -0
- package/dist/server/builder-space.js.map +1 -0
- package/dist/server/core-routes-plugin.d.ts.map +1 -1
- package/dist/server/core-routes-plugin.js +39 -98
- package/dist/server/core-routes-plugin.js.map +1 -1
- package/dist/server/credential-provider.d.ts.map +1 -1
- package/dist/server/credential-provider.js +29 -6
- package/dist/server/credential-provider.js.map +1 -1
- package/dist/styles/blocks.css +30 -8
- package/dist/styles/rich-markdown-editor.css +10 -4
- package/dist/templates/{starter-shell-sync.spec.ts → chat-shell-sync.spec.ts} +21 -21
- package/dist/templates/default/.agents/skills/actions/SKILL.md +5 -5
- package/dist/templates/default/.agents/skills/agent-native-docs/SKILL.md +63 -0
- package/dist/templates/default/AGENTS.md +22 -1
- package/dist/templates/default/actions/hello.ts +1 -1
- package/dist/templates/default/actions/navigate.ts +1 -1
- package/dist/templates/default/actions/view-screen.ts +1 -1
- package/dist/templates/headless/.agents/skills/agent-native-docs/SKILL.md +63 -0
- package/dist/templates/headless/.env.example +4 -0
- package/dist/templates/headless/.prettierrc +5 -0
- package/dist/templates/headless/AGENTS.md +58 -0
- package/dist/templates/headless/DEVELOPING.md +22 -0
- package/dist/templates/headless/_gitignore +36 -0
- package/dist/templates/headless/actions/hello.ts +14 -0
- package/dist/templates/headless/actions/run.ts +3 -0
- package/dist/templates/headless/package.json +22 -0
- package/dist/templates/headless/tsconfig.json +7 -0
- package/dist/templates/ui-primitives-sync.spec.ts +2 -2
- package/dist/templates/workspace-core/.agents/skills/actions/SKILL.md +5 -5
- package/dist/templates/workspace-core/.agents/skills/agent-native-docs/SKILL.md +63 -0
- package/dist/templates/workspace-core/.agents/skills/composable-mini-apps/SKILL.md +93 -0
- package/dist/templates/workspace-core/.agents/skills/secrets/SKILL.md +1 -1
- package/dist/templates/workspace-core/AGENTS.md +20 -3
- package/dist/templates/workspace-core/src/server/index.ts +1 -1
- package/dist/templates/workspace-root/AGENTS.md +25 -5
- package/dist/templates/workspace-root/README.md +7 -7
- package/dist/triggers/dispatcher.d.ts +2 -3
- package/dist/triggers/dispatcher.d.ts.map +1 -1
- package/dist/triggers/dispatcher.js +2 -3
- package/dist/triggers/dispatcher.js.map +1 -1
- package/dist/triggers/routes.d.ts +38 -0
- package/dist/triggers/routes.d.ts.map +1 -0
- package/dist/triggers/routes.js +202 -0
- package/dist/triggers/routes.js.map +1 -0
- package/docs/AGENTS.md +57 -0
- package/docs/SKILL.md +40 -0
- package/docs/content/a2a-protocol.md +1 -1
- package/docs/content/actions.md +48 -8
- package/docs/content/agent-surfaces.md +76 -14
- package/docs/content/cli-adapters.md +1 -1
- package/docs/content/cloneable-saas.md +5 -4
- package/docs/content/code-agents-ui.md +1 -1
- package/docs/content/components.md +1 -1
- package/docs/content/context-awareness.md +1 -1
- package/docs/content/creating-templates.md +9 -7
- package/docs/content/drop-in-agent.md +1 -1
- package/docs/content/faq.md +6 -4
- package/docs/content/getting-started.md +63 -73
- package/docs/content/key-concepts.md +24 -24
- package/docs/content/native-chat-ui.md +4 -4
- package/docs/content/pure-agent-apps.md +34 -10
- package/docs/content/security.md +1 -1
- package/docs/content/server.md +1 -1
- package/docs/content/template-chat.md +85 -0
- package/docs/content/template-dispatch.md +1 -1
- package/docs/content/tracking.md +1 -1
- package/docs/content/what-is-agent-native.md +7 -6
- package/package.json +10 -1
- package/src/templates/{starter-shell-sync.spec.ts → chat-shell-sync.spec.ts} +21 -21
- package/src/templates/default/.agents/skills/actions/SKILL.md +5 -5
- package/src/templates/default/.agents/skills/agent-native-docs/SKILL.md +63 -0
- package/src/templates/default/AGENTS.md +22 -1
- package/src/templates/default/actions/hello.ts +1 -1
- package/src/templates/default/actions/navigate.ts +1 -1
- package/src/templates/default/actions/view-screen.ts +1 -1
- package/src/templates/headless/.agents/skills/agent-native-docs/SKILL.md +63 -0
- package/src/templates/headless/.env.example +4 -0
- package/src/templates/headless/.prettierrc +5 -0
- package/src/templates/headless/AGENTS.md +58 -0
- package/src/templates/headless/DEVELOPING.md +22 -0
- package/src/templates/headless/_gitignore +36 -0
- package/src/templates/headless/actions/hello.ts +14 -0
- package/src/templates/headless/actions/run.ts +3 -0
- package/src/templates/headless/package.json +22 -0
- package/src/templates/headless/tsconfig.json +7 -0
- package/src/templates/ui-primitives-sync.spec.ts +2 -2
- package/src/templates/workspace-core/.agents/skills/actions/SKILL.md +5 -5
- package/src/templates/workspace-core/.agents/skills/agent-native-docs/SKILL.md +63 -0
- package/src/templates/workspace-core/.agents/skills/composable-mini-apps/SKILL.md +93 -0
- package/src/templates/workspace-core/.agents/skills/secrets/SKILL.md +1 -1
- package/src/templates/workspace-core/AGENTS.md +20 -3
- package/src/templates/workspace-core/src/server/index.ts +1 -1
- package/src/templates/workspace-root/AGENTS.md +25 -5
- package/src/templates/workspace-root/README.md +7 -7
- package/docs/content/template-starter.md +0 -78
package/dist/cli/create.js
CHANGED
|
@@ -33,12 +33,11 @@ export class ValidationError extends Error {
|
|
|
33
33
|
}
|
|
34
34
|
}
|
|
35
35
|
/**
|
|
36
|
-
* Move
|
|
37
|
-
*
|
|
38
|
-
* Starter is pre-selected.
|
|
36
|
+
* Move the primitive-first and chat on-ramps to the top of the list so they
|
|
37
|
+
* line up with clack's default highlight.
|
|
39
38
|
*/
|
|
40
|
-
function
|
|
41
|
-
return moveTemplatesToFront(templates, ["
|
|
39
|
+
function onRampFirst(templates) {
|
|
40
|
+
return moveTemplatesToFront(templates, ["headless", "chat"]);
|
|
42
41
|
}
|
|
43
42
|
function moveTemplatesToFront(templates, preferredNames) {
|
|
44
43
|
const preferred = preferredNames
|
|
@@ -49,11 +48,11 @@ function moveTemplatesToFront(templates, preferredNames) {
|
|
|
49
48
|
const preferredSet = new Set(preferred.map((t) => t.name));
|
|
50
49
|
return [...preferred, ...templates.filter((t) => !preferredSet.has(t.name))];
|
|
51
50
|
}
|
|
52
|
-
/**
|
|
53
|
-
const
|
|
54
|
-
name: "
|
|
55
|
-
label: "
|
|
56
|
-
hint: "
|
|
51
|
+
/** Primitive-first scaffold option appended to standalone pickers. */
|
|
52
|
+
const HEADLESS_OPTION = {
|
|
53
|
+
name: "headless",
|
|
54
|
+
label: "Headless",
|
|
55
|
+
hint: "Action-first app with one hello primitive and no UI shell",
|
|
57
56
|
};
|
|
58
57
|
/**
|
|
59
58
|
* Main entry for `agent-native create [name]`.
|
|
@@ -83,6 +82,10 @@ export async function createApp(name, opts) {
|
|
|
83
82
|
// Use `--template a,b` or pass no --template to opt into the workspace
|
|
84
83
|
// flow with the multi-select picker.
|
|
85
84
|
const parsed = parseTemplateList(opts?.template);
|
|
85
|
+
if (parsed.includes("headless") && parsed.length > 1) {
|
|
86
|
+
clack.cancel("The headless scaffold is standalone-only. Use `agent-native create my-app --headless`, or use the Chat template when adding a UI app to a workspace.");
|
|
87
|
+
process.exit(1);
|
|
88
|
+
}
|
|
86
89
|
if (parsed.length === 1) {
|
|
87
90
|
await createStandaloneApp(name, opts, clack);
|
|
88
91
|
return;
|
|
@@ -102,8 +105,8 @@ async function createWorkspaceInteractive(name, opts, clack) {
|
|
|
102
105
|
"container — it isn't an app itself. Inside it you pick one or more apps",
|
|
103
106
|
"(below), and each app gets its own route, agent, and UI. Apps in the",
|
|
104
107
|
"same workspace share auth, database, and the agent chat. Add more apps",
|
|
105
|
-
"later with `npx @agent-native/core@latest add-app`.
|
|
106
|
-
"
|
|
108
|
+
"later with `npx @agent-native/core@latest add-app`. Chat is the UI on-ramp",
|
|
109
|
+
"for a minimal chat-first app with the browser shell already wired.",
|
|
107
110
|
"Dispatch is always included as the workspace control plane —",
|
|
108
111
|
"it owns shared secrets, messaging, approvals, and cross-app routing.",
|
|
109
112
|
].join("\n"), "About workspaces");
|
|
@@ -114,8 +117,8 @@ async function createWorkspaceInteractive(name, opts, clack) {
|
|
|
114
117
|
const optionalPicks = preselected.length > 0
|
|
115
118
|
? preselected.filter((t) => t !== "dispatch")
|
|
116
119
|
: await promptTemplatePicker(preselected, clack, {
|
|
117
|
-
defaultTemplates: ["
|
|
118
|
-
preferredFirst: ["
|
|
120
|
+
defaultTemplates: ["chat"],
|
|
121
|
+
preferredFirst: ["chat"],
|
|
119
122
|
excludeNames: ["dispatch"],
|
|
120
123
|
});
|
|
121
124
|
const templates = ["dispatch", ...optionalPicks];
|
|
@@ -126,37 +129,49 @@ async function createWorkspaceInteractive(name, opts, clack) {
|
|
|
126
129
|
}
|
|
127
130
|
const s = clack.spinner();
|
|
128
131
|
s.start(`Scaffolding workspace "${name}"...`);
|
|
132
|
+
const appNames = new Set();
|
|
133
|
+
const scaffoldedApps = [];
|
|
129
134
|
try {
|
|
130
135
|
await scaffoldWorkspaceRoot(targetDir, name);
|
|
131
136
|
const workspaceCoreName = `@${name}/shared`;
|
|
132
137
|
for (let i = 0; i < templates.length; i++) {
|
|
133
|
-
const
|
|
138
|
+
const templateName = templates[i];
|
|
139
|
+
const appName = workspaceAppNameForTemplateSelection(templateName);
|
|
140
|
+
validateWorkspaceAppName(appName, clack, {
|
|
141
|
+
allowDispatch: appName === "dispatch" && templateName === "dispatch",
|
|
142
|
+
});
|
|
143
|
+
if (appNames.has(appName)) {
|
|
144
|
+
clack.cancel(`Workspace app "${appName}" is selected more than once. Choose unique app templates or app names.`);
|
|
145
|
+
process.exit(1);
|
|
146
|
+
}
|
|
147
|
+
appNames.add(appName);
|
|
148
|
+
scaffoldedApps.push(appName);
|
|
134
149
|
// Distinguish download vs local copy in the spinner so a multi-second
|
|
135
150
|
// GitHub fetch doesn't look like a frozen "Scaffolding..." message.
|
|
136
151
|
// Mirrors the local-vs-remote decision inside scaffoldAppTemplate.
|
|
137
|
-
const willDownload =
|
|
152
|
+
const willDownload = templateName !== "headless" && templateName.startsWith("github:")
|
|
138
153
|
? true
|
|
139
|
-
: !findLocalTemplate(normalizeTemplateName(
|
|
154
|
+
: !findLocalTemplate(normalizeTemplateName(templateName));
|
|
140
155
|
s.message(willDownload
|
|
141
|
-
? `Downloading ${titleCase(
|
|
142
|
-
: `Scaffolding ${titleCase(
|
|
143
|
-
const appDir = path.join(targetDir, "apps",
|
|
144
|
-
await scaffoldAppTemplate(appDir,
|
|
145
|
-
s.message(`Configuring ${titleCase(
|
|
146
|
-
replacePlaceholders(appDir,
|
|
147
|
-
rewriteTrackingAppId(appDir,
|
|
156
|
+
? `Downloading ${titleCase(appName)} template (${i + 1}/${templates.length})...`
|
|
157
|
+
: `Scaffolding ${titleCase(appName)} (${i + 1}/${templates.length})...`);
|
|
158
|
+
const appDir = path.join(targetDir, "apps", appName);
|
|
159
|
+
await scaffoldAppTemplate(appDir, templateName);
|
|
160
|
+
s.message(`Configuring ${titleCase(appName)} (${i + 1}/${templates.length})...`);
|
|
161
|
+
replacePlaceholders(appDir, appName, appTitleForScaffold(appName), name);
|
|
162
|
+
rewriteTrackingAppId(appDir, appName, templateName);
|
|
148
163
|
workspacifyApp({
|
|
149
164
|
appDir,
|
|
150
|
-
appName
|
|
151
|
-
templateName
|
|
165
|
+
appName,
|
|
166
|
+
templateName,
|
|
152
167
|
workspaceRoot: targetDir,
|
|
153
168
|
workspaceCoreName,
|
|
154
169
|
coreDependencyVersion: getCoreDependencyVersion(),
|
|
155
170
|
dispatchDependencyVersion: getDispatchDependencyVersion(),
|
|
156
171
|
});
|
|
157
|
-
fixPackageJsonName(appDir,
|
|
158
|
-
fixWebManifestName(appDir,
|
|
159
|
-
rewriteNetlifyToml(appDir,
|
|
172
|
+
fixPackageJsonName(appDir, appName, templateName);
|
|
173
|
+
fixWebManifestName(appDir, appName, templateName);
|
|
174
|
+
rewriteNetlifyToml(appDir, appName, "workspace");
|
|
160
175
|
renameGitignore(appDir);
|
|
161
176
|
// Each app owns its own .claude / .agents symlinks.
|
|
162
177
|
setupAgentSymlinks(appDir);
|
|
@@ -180,8 +195,7 @@ async function createWorkspaceInteractive(name, opts, clack) {
|
|
|
180
195
|
// makes the structure concrete.
|
|
181
196
|
const treeLines = [
|
|
182
197
|
` ${name}/ ← your workspace`,
|
|
183
|
-
...
|
|
184
|
-
` ← app`),
|
|
198
|
+
...scaffoldedApps.map((appName, i) => ` ${i === scaffoldedApps.length - 1 ? "└─" : "├─"} apps/${appName}/`.padEnd(30) + ` ← app`),
|
|
185
199
|
];
|
|
186
200
|
const dispatchNextStep = [
|
|
187
201
|
`Once running, open Dispatch — you'll see "Workspace: ${titleCase(name)}"`,
|
|
@@ -215,6 +229,23 @@ async function createWorkspaceInteractive(name, opts, clack) {
|
|
|
215
229
|
`Deploy the whole workspace: pnpm exec agent-native deploy`,
|
|
216
230
|
].join("\n"));
|
|
217
231
|
}
|
|
232
|
+
function workspaceAppNameForTemplateSelection(templateName) {
|
|
233
|
+
const normalized = normalizeTemplateName(templateName);
|
|
234
|
+
if (!normalized.startsWith("github:"))
|
|
235
|
+
return templateName;
|
|
236
|
+
const repo = normalized.slice("github:".length).trim();
|
|
237
|
+
const repoName = repo.split("/").filter(Boolean).pop() ?? "app";
|
|
238
|
+
let appName = repoName
|
|
239
|
+
.toLowerCase()
|
|
240
|
+
.replace(/[^a-z0-9-]+/g, "-")
|
|
241
|
+
.replace(/-+/g, "-")
|
|
242
|
+
.replace(/^-+|-+$/g, "");
|
|
243
|
+
if (!appName)
|
|
244
|
+
appName = "app";
|
|
245
|
+
if (!/^[a-z]/.test(appName))
|
|
246
|
+
appName = `app-${appName}`;
|
|
247
|
+
return appName;
|
|
248
|
+
}
|
|
218
249
|
/**
|
|
219
250
|
* Detect whether pnpm is on PATH. End-user machines often have npm/yarn but
|
|
220
251
|
* not pnpm; the workspace scaffold uses pnpm workspaces, so we surface a
|
|
@@ -321,6 +352,10 @@ export async function addAppToWorkspace(name, opts) {
|
|
|
321
352
|
const installed = listInstalledApps(workspace.workspaceRoot);
|
|
322
353
|
// Non-interactive path: name + single --template
|
|
323
354
|
const preselected = parseTemplateList(opts?.template);
|
|
355
|
+
if (preselected.includes("headless")) {
|
|
356
|
+
clack.cancel("The headless scaffold is standalone-only. Use `agent-native create my-app --headless` outside a workspace, or use the Chat template when adding a UI app to a workspace.");
|
|
357
|
+
process.exit(1);
|
|
358
|
+
}
|
|
324
359
|
if (name && preselected.length === 1) {
|
|
325
360
|
const tpl = preselected[0];
|
|
326
361
|
await scaffoldOneAppIntoWorkspace(workspace, name, tpl, clack);
|
|
@@ -331,7 +366,7 @@ export async function addAppToWorkspace(name, opts) {
|
|
|
331
366
|
excludeNames: installed,
|
|
332
367
|
message: "Which apps do you want to add?",
|
|
333
368
|
defaultTemplates: hasDispatch ? undefined : ["dispatch"],
|
|
334
|
-
preferredFirst: hasDispatch ? ["
|
|
369
|
+
preferredFirst: hasDispatch ? ["chat"] : ["dispatch", "chat"],
|
|
335
370
|
recommendedNames: hasDispatch ? [] : ["dispatch"],
|
|
336
371
|
});
|
|
337
372
|
if (templates.length === 0) {
|
|
@@ -359,7 +394,7 @@ async function scaffoldOneAppIntoWorkspace(workspace, appName, templateName, cla
|
|
|
359
394
|
s.start(`Working... no action needed. Scaffolding apps/${appName} from ${templateName}.`);
|
|
360
395
|
try {
|
|
361
396
|
await scaffoldAppTemplate(appDir, templateName);
|
|
362
|
-
replacePlaceholders(appDir, appName, appTitleForScaffold(appName
|
|
397
|
+
replacePlaceholders(appDir, appName, appTitleForScaffold(appName), path.basename(workspace.workspaceRoot));
|
|
363
398
|
rewriteTrackingAppId(appDir, appName, templateName);
|
|
364
399
|
workspacifyApp({
|
|
365
400
|
appDir,
|
|
@@ -410,16 +445,18 @@ async function createStandaloneApp(name, opts, clack) {
|
|
|
410
445
|
const picked = await clack.select({
|
|
411
446
|
message: "Which template would you like to use?",
|
|
412
447
|
options: [
|
|
413
|
-
|
|
448
|
+
{
|
|
449
|
+
value: HEADLESS_OPTION.name,
|
|
450
|
+
label: HEADLESS_OPTION.label,
|
|
451
|
+
hint: HEADLESS_OPTION.hint,
|
|
452
|
+
},
|
|
453
|
+
...onRampFirst(coreTemplates())
|
|
454
|
+
.filter((t) => t.name !== HEADLESS_OPTION.name)
|
|
455
|
+
.map((t) => ({
|
|
414
456
|
value: t.name,
|
|
415
457
|
label: t.label,
|
|
416
458
|
hint: t.hint,
|
|
417
459
|
})),
|
|
418
|
-
{
|
|
419
|
-
value: BLANK_OPTION.name,
|
|
420
|
-
label: BLANK_OPTION.label,
|
|
421
|
-
hint: BLANK_OPTION.hint,
|
|
422
|
-
},
|
|
423
460
|
],
|
|
424
461
|
});
|
|
425
462
|
if (clack.isCancel(picked)) {
|
|
@@ -430,7 +467,9 @@ async function createStandaloneApp(name, opts, clack) {
|
|
|
430
467
|
}
|
|
431
468
|
template = normalizeTemplateName(template);
|
|
432
469
|
const s = clack.spinner();
|
|
433
|
-
s.start(
|
|
470
|
+
s.start(template === "headless"
|
|
471
|
+
? "Scaffolding the headless action app..."
|
|
472
|
+
: `Downloading the ${template} template from GitHub...`);
|
|
434
473
|
try {
|
|
435
474
|
await scaffoldAppTemplate(targetDir, template);
|
|
436
475
|
s.message(`Setting up ${name}…`);
|
|
@@ -444,7 +483,21 @@ async function createStandaloneApp(name, opts, clack) {
|
|
|
444
483
|
process.exit(1);
|
|
445
484
|
}
|
|
446
485
|
tryGitInit(targetDir);
|
|
447
|
-
|
|
486
|
+
if (template === "headless") {
|
|
487
|
+
clack.outro([
|
|
488
|
+
"Done! Next steps:",
|
|
489
|
+
"",
|
|
490
|
+
` cd ${name}`,
|
|
491
|
+
" pnpm install",
|
|
492
|
+
" pnpm action hello --name Builder",
|
|
493
|
+
` pnpm agent "Call hello for Builder"`,
|
|
494
|
+
"",
|
|
495
|
+
"Add a UI later by starting from the Chat template; `agent-native add` is reserved for integration blueprints.",
|
|
496
|
+
].join("\n"));
|
|
497
|
+
}
|
|
498
|
+
else {
|
|
499
|
+
clack.outro(`Done! Next steps:\n\n cd ${name}\n pnpm install\n pnpm dev`);
|
|
500
|
+
}
|
|
448
501
|
}
|
|
449
502
|
/**
|
|
450
503
|
* Remove a partially-scaffolded target directory after a scaffold failure so a
|
|
@@ -467,42 +520,48 @@ function cleanupOnFailure(targetDir) {
|
|
|
467
520
|
* ───────────────────────────────────────────────────────────────────────── */
|
|
468
521
|
/**
|
|
469
522
|
* Scaffold a single app template into `targetDir`. Resolves:
|
|
470
|
-
* - "blank" → bundled
|
|
523
|
+
* - "headless" / legacy "blank" → bundled action-first template
|
|
471
524
|
* - "github:user/repo" → download the whole repo
|
|
472
525
|
* - first-party template name → download that subdir from BuilderIO/agent-native
|
|
473
526
|
*/
|
|
474
527
|
async function scaffoldAppTemplate(targetDir, template) {
|
|
475
528
|
fs.mkdirSync(path.dirname(targetDir), { recursive: true });
|
|
476
|
-
|
|
529
|
+
// Normalize legacy / renamed aliases.
|
|
530
|
+
let resolved = normalizeTemplateName(template);
|
|
531
|
+
if (resolved === "headless") {
|
|
477
532
|
const packageRoot = path.resolve(__dirname, "../..");
|
|
478
|
-
const
|
|
479
|
-
if (!fs.existsSync(
|
|
480
|
-
throw new Error(`
|
|
533
|
+
const headlessDir = path.join(packageRoot, "src/templates/headless");
|
|
534
|
+
if (!fs.existsSync(headlessDir)) {
|
|
535
|
+
throw new Error(`Headless template not found at ${headlessDir}. Is the package installed correctly?`);
|
|
481
536
|
}
|
|
482
|
-
copyDir(
|
|
537
|
+
copyDir(headlessDir, targetDir);
|
|
483
538
|
return;
|
|
484
539
|
}
|
|
485
|
-
// Normalize legacy / renamed aliases.
|
|
486
|
-
let resolved = normalizeTemplateName(template);
|
|
487
540
|
if (resolved.startsWith("github:")) {
|
|
488
541
|
const repo = resolved.slice("github:".length);
|
|
489
542
|
await downloadGitHubRepo(repo, targetDir);
|
|
490
543
|
return;
|
|
491
544
|
}
|
|
492
|
-
if (!
|
|
545
|
+
if (!getTemplate(resolved)) {
|
|
493
546
|
throw new Error(`Unknown template "${template}". Known: ${allTemplateNames().join(", ")} — or use github:user/repo for community templates.`);
|
|
494
547
|
}
|
|
495
548
|
// If running from the framework monorepo with a local templates/ dir, use
|
|
496
549
|
// that. Otherwise download from GitHub. This keeps `agent-native create`
|
|
497
550
|
// fast during framework development.
|
|
498
|
-
const
|
|
551
|
+
const sourceTemplate = templateSourceName(resolved);
|
|
552
|
+
const localTemplate = findLocalTemplate(sourceTemplate);
|
|
499
553
|
if (localTemplate) {
|
|
500
554
|
copyDir(localTemplate, targetDir);
|
|
501
555
|
}
|
|
502
556
|
else {
|
|
503
|
-
await downloadGitHubSubdir(REPO, `${TEMPLATES_DIR}/${
|
|
557
|
+
await downloadGitHubSubdir(REPO, `${TEMPLATES_DIR}/${sourceTemplate}`, targetDir);
|
|
504
558
|
}
|
|
505
559
|
}
|
|
560
|
+
function templateSourceName(name) {
|
|
561
|
+
if (name === "starter")
|
|
562
|
+
return "chat";
|
|
563
|
+
return name;
|
|
564
|
+
}
|
|
506
565
|
/**
|
|
507
566
|
* When developing the framework itself, prefer the sibling templates/<name>
|
|
508
567
|
* directory. Returns undefined when running as a published package.
|
|
@@ -522,6 +581,8 @@ function findLocalTemplate(name) {
|
|
|
522
581
|
return undefined;
|
|
523
582
|
}
|
|
524
583
|
function normalizeTemplateName(template) {
|
|
584
|
+
if (template === "blank")
|
|
585
|
+
return "headless";
|
|
525
586
|
if (template === "video")
|
|
526
587
|
return "videos";
|
|
527
588
|
if (template === "image" || template === "images" || template === "asset") {
|
|
@@ -633,7 +694,7 @@ async function scaffoldRequiredPackages(templateNames, workspaceRoot) {
|
|
|
633
694
|
* workspace:* deps, set up agent symlinks, etc.
|
|
634
695
|
*/
|
|
635
696
|
function postProcessStandalone(name, targetDir, templateName) {
|
|
636
|
-
const appTitle = appTitleForScaffold(name
|
|
697
|
+
const appTitle = appTitleForScaffold(name);
|
|
637
698
|
replacePlaceholders(targetDir, name, appTitle);
|
|
638
699
|
rewriteTrackingAppId(targetDir, name, templateName);
|
|
639
700
|
fixPackageJsonName(targetDir, name, templateName);
|
|
@@ -648,7 +709,7 @@ function postProcessStandalone(name, targetDir, templateName) {
|
|
|
648
709
|
}
|
|
649
710
|
renameGitignore(targetDir);
|
|
650
711
|
// No monorepo-only files to drop for standalone scaffolds.
|
|
651
|
-
// DEVELOPING.md is intentionally kept: it documents
|
|
712
|
+
// DEVELOPING.md is intentionally kept: it documents local run commands,
|
|
652
713
|
// DATABASE_URL defaults, and other local-run instructions that are equally
|
|
653
714
|
// valid for standalone apps.
|
|
654
715
|
// Resolve workspace:* and catalog: deps for standalone projects.
|
|
@@ -709,17 +770,20 @@ function postProcessStandalone(name, targetDir, templateName) {
|
|
|
709
770
|
const existing = fs.existsSync(wsPath)
|
|
710
771
|
? fs.readFileSync(wsPath, "utf-8")
|
|
711
772
|
: "";
|
|
712
|
-
const
|
|
713
|
-
overrides: {
|
|
714
|
-
'"@assistant-ui/store"': '">=0.2.9 <0.2.14"',
|
|
715
|
-
'"@assistant-ui/tap"': '"^0.5.14"',
|
|
716
|
-
},
|
|
773
|
+
const sections = {
|
|
717
774
|
allowBuilds: {
|
|
718
775
|
"better-sqlite3": "true",
|
|
719
776
|
esbuild: "true",
|
|
720
777
|
"node-pty": "true",
|
|
721
778
|
},
|
|
722
|
-
}
|
|
779
|
+
};
|
|
780
|
+
if (templateName !== "headless") {
|
|
781
|
+
sections.overrides = {
|
|
782
|
+
'"@assistant-ui/store"': '">=0.2.9 <0.2.14"',
|
|
783
|
+
'"@assistant-ui/tap"': '"^0.5.14"',
|
|
784
|
+
};
|
|
785
|
+
}
|
|
786
|
+
const updated = mergeWorkspaceYamlSections(existing, sections);
|
|
723
787
|
if (updated !== existing) {
|
|
724
788
|
fs.writeFileSync(wsPath, updated);
|
|
725
789
|
}
|
|
@@ -762,7 +826,7 @@ async function promptTemplatePicker(preselected, clack, opts) {
|
|
|
762
826
|
const excluded = new Set(opts?.excludeNames ?? []);
|
|
763
827
|
const orderedTemplates = opts?.preferredFirst
|
|
764
828
|
? moveTemplatesToFront(coreTemplates(), opts.preferredFirst)
|
|
765
|
-
:
|
|
829
|
+
: onRampFirst(coreTemplates());
|
|
766
830
|
const recommendedNames = new Set(opts?.recommendedNames ?? []);
|
|
767
831
|
const options = orderedTemplates
|
|
768
832
|
.filter((t) => !excluded.has(t.name))
|
|
@@ -780,13 +844,13 @@ async function promptTemplatePicker(preselected, clack, opts) {
|
|
|
780
844
|
if (options.length === 0)
|
|
781
845
|
return [];
|
|
782
846
|
// Default pre-selection: what the user passed via --template, falling
|
|
783
|
-
// back to caller defaults, then to "
|
|
847
|
+
// back to caller defaults, then to "chat" when available.
|
|
784
848
|
const defaults = preselected.length > 0
|
|
785
849
|
? preselected.filter((p) => options.some((o) => o.value === p))
|
|
786
850
|
: opts?.defaultTemplates
|
|
787
851
|
? opts.defaultTemplates.filter((p) => options.some((o) => o.value === p))
|
|
788
|
-
: options.some((o) => o.value === "
|
|
789
|
-
? ["
|
|
852
|
+
: options.some((o) => o.value === "chat")
|
|
853
|
+
? ["chat"]
|
|
790
854
|
: [];
|
|
791
855
|
const baseMessage = opts?.message ?? "Which apps would you like to include?";
|
|
792
856
|
const result = await clack.multiselect({
|
|
@@ -849,7 +913,7 @@ export function detectWorkspace(startDir) {
|
|
|
849
913
|
}
|
|
850
914
|
export { parseWorkspaceScope };
|
|
851
915
|
/** @internal — exported for E2E tests */
|
|
852
|
-
export { scaffoldWorkspaceRoot as _scaffoldWorkspaceRoot, scaffoldAppTemplate as _scaffoldAppTemplate, scaffoldRequiredPackages as _scaffoldRequiredPackages, postProcessStandalone as _postProcessStandalone, loadCatalog as _loadCatalog, fixPackageJsonName as _fixPackageJsonName, renameGitignore as _renameGitignore, rewriteNetlifyToml as _rewriteNetlifyToml, getCoreDependencyVersion as _getCoreDependencyVersion, getDispatchDependencyVersion as _getDispatchDependencyVersion, getGitHubTemplateRef as _getGitHubTemplateRef, getGitHubTemplateRefCandidates as _getGitHubTemplateRefCandidates, shouldSkipScaffoldEntry as _shouldSkipScaffoldEntry, tarExtractArgs as _tarExtractArgs, };
|
|
916
|
+
export { scaffoldWorkspaceRoot as _scaffoldWorkspaceRoot, scaffoldAppTemplate as _scaffoldAppTemplate, scaffoldRequiredPackages as _scaffoldRequiredPackages, postProcessStandalone as _postProcessStandalone, loadCatalog as _loadCatalog, fixPackageJsonName as _fixPackageJsonName, renameGitignore as _renameGitignore, rewriteNetlifyToml as _rewriteNetlifyToml, getCoreDependencyVersion as _getCoreDependencyVersion, getDispatchDependencyVersion as _getDispatchDependencyVersion, getGitHubTemplateRef as _getGitHubTemplateRef, getGitHubTemplateRefCandidates as _getGitHubTemplateRefCandidates, workspaceAppNameForTemplateSelection as _workspaceAppNameForTemplateSelection, shouldSkipScaffoldEntry as _shouldSkipScaffoldEntry, tarExtractArgs as _tarExtractArgs, };
|
|
853
917
|
/* ─────────────────────────────────────────────────────────────────────────
|
|
854
918
|
* Download / copy helpers
|
|
855
919
|
* ───────────────────────────────────────────────────────────────────────── */
|
|
@@ -998,16 +1062,17 @@ function titleCase(name) {
|
|
|
998
1062
|
.map((w) => (w ? w[0].toUpperCase() + w.slice(1) : w))
|
|
999
1063
|
.join(" ");
|
|
1000
1064
|
}
|
|
1001
|
-
function appTitleForScaffold(appName
|
|
1002
|
-
if (appName === "starter" && (!templateName || templateName === "starter")) {
|
|
1003
|
-
return "Blank app";
|
|
1004
|
-
}
|
|
1065
|
+
function appTitleForScaffold(appName) {
|
|
1005
1066
|
return titleCase(appName);
|
|
1006
1067
|
}
|
|
1007
|
-
function
|
|
1008
|
-
|
|
1009
|
-
|
|
1010
|
-
|
|
1068
|
+
function isChatOnRampTemplate(templateName) {
|
|
1069
|
+
return templateName === "chat" || templateName === "starter";
|
|
1070
|
+
}
|
|
1071
|
+
function trackingTemplateName(templateName) {
|
|
1072
|
+
return templateName === "starter" ? "chat" : templateName;
|
|
1073
|
+
}
|
|
1074
|
+
function defaultPackageDescriptionForScaffold(appName) {
|
|
1075
|
+
const appTitle = appTitleForScaffold(appName);
|
|
1011
1076
|
return `Workspace app for ${appTitle}.`;
|
|
1012
1077
|
}
|
|
1013
1078
|
function shouldReplaceScaffoldDescription(value) {
|
|
@@ -1022,22 +1087,24 @@ function fixPackageJsonName(appDir, name, templateName) {
|
|
|
1022
1087
|
try {
|
|
1023
1088
|
const pkg = JSON.parse(fs.readFileSync(pkgPath, "utf-8"));
|
|
1024
1089
|
pkg.name = name;
|
|
1025
|
-
|
|
1090
|
+
const appTitle = appTitleForScaffold(name);
|
|
1091
|
+
// When the user picked a custom name (e.g. `add-app todo --template=chat`)
|
|
1026
1092
|
// the template's displayName would otherwise leak into the workspace apps
|
|
1027
1093
|
// grid as the new app's label. Overwrite it so the app shows up as "Todo"
|
|
1028
1094
|
// instead of the source template's branding.
|
|
1029
1095
|
if (templateName && name !== templateName) {
|
|
1030
|
-
pkg.displayName =
|
|
1096
|
+
pkg.displayName = appTitle;
|
|
1031
1097
|
}
|
|
1032
|
-
if (shouldReplaceScaffoldDescription(pkg.description)
|
|
1033
|
-
|
|
1098
|
+
if (shouldReplaceScaffoldDescription(pkg.description) ||
|
|
1099
|
+
(isChatOnRampTemplate(templateName) && name !== templateName)) {
|
|
1100
|
+
pkg.description = defaultPackageDescriptionForScaffold(name);
|
|
1034
1101
|
}
|
|
1035
1102
|
fs.writeFileSync(pkgPath, JSON.stringify(pkg, null, 2) + "\n");
|
|
1036
1103
|
}
|
|
1037
1104
|
catch { }
|
|
1038
1105
|
}
|
|
1039
1106
|
function fixWebManifestName(appDir, name, templateName) {
|
|
1040
|
-
if (templateName
|
|
1107
|
+
if (!isChatOnRampTemplate(templateName) || name === templateName)
|
|
1041
1108
|
return;
|
|
1042
1109
|
const manifestPath = path.join(appDir, "public", "manifest.json");
|
|
1043
1110
|
if (!fs.existsSync(manifestPath))
|
|
@@ -1048,8 +1115,8 @@ function fixWebManifestName(appDir, name, templateName) {
|
|
|
1048
1115
|
manifest.name = appTitle;
|
|
1049
1116
|
manifest.short_name = appTitle;
|
|
1050
1117
|
if (typeof manifest.description !== "string" ||
|
|
1051
|
-
/\b(blank app|starter)\b/i.test(manifest.description)) {
|
|
1052
|
-
manifest.description = defaultPackageDescriptionForScaffold(name
|
|
1118
|
+
/\b(blank app|starter|chat-first)\b/i.test(manifest.description)) {
|
|
1119
|
+
manifest.description = defaultPackageDescriptionForScaffold(name);
|
|
1053
1120
|
}
|
|
1054
1121
|
fs.writeFileSync(manifestPath, JSON.stringify(manifest, null, 2) + "\n");
|
|
1055
1122
|
}
|
|
@@ -1246,18 +1313,22 @@ function rewriteTrackingAppId(appDir, appName, templateName) {
|
|
|
1246
1313
|
return;
|
|
1247
1314
|
try {
|
|
1248
1315
|
const content = fs.readFileSync(rootPath, "utf-8");
|
|
1316
|
+
const trackedTemplateName = trackingTemplateName(templateName);
|
|
1249
1317
|
const sourceAppIds = ["agent-native-[^\"']+", "\\{\\{APP_NAME\\}\\}"];
|
|
1250
1318
|
if (templateName && templateName !== appName) {
|
|
1251
1319
|
sourceAppIds.push(escapeRegExp(templateName));
|
|
1252
1320
|
}
|
|
1321
|
+
if (isChatOnRampTemplate(templateName)) {
|
|
1322
|
+
sourceAppIds.push("starter", "chat");
|
|
1323
|
+
}
|
|
1253
1324
|
const pattern = new RegExp(`(^\\s*app:\\s*)(["'])(?:${sourceAppIds.join("|")})\\2(\\s*,?)`, "m");
|
|
1254
1325
|
if (!pattern.test(content))
|
|
1255
1326
|
return;
|
|
1256
1327
|
let next = content.replace(pattern, (_match, prefix, quote, suffix) => `${prefix}${quote}${appName}${quote}${suffix}`);
|
|
1257
|
-
if (
|
|
1258
|
-
|
|
1328
|
+
if (trackedTemplateName &&
|
|
1329
|
+
trackedTemplateName !== appName &&
|
|
1259
1330
|
!hasTrackingTemplate(next)) {
|
|
1260
|
-
next = next.replace(/(^\s*app:\s*["'][^"']+["'],?\s*$)/m, (line) => `${line}\n template: ${JSON.stringify(
|
|
1331
|
+
next = next.replace(/(^\s*app:\s*["'][^"']+["'],?\s*$)/m, (line) => `${line}\n template: ${JSON.stringify(trackedTemplateName)},`);
|
|
1261
1332
|
}
|
|
1262
1333
|
if (next !== content) {
|
|
1263
1334
|
fs.writeFileSync(rootPath, next);
|