@agent-native/core 0.72.4 → 0.74.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/core/CHANGELOG.md +67 -0
- package/corpus/core/docs/content/skills-guide.md +14 -0
- package/corpus/core/docs/content/template-clips.md +7 -1
- package/corpus/core/package.json +1 -1
- package/corpus/core/src/agent/durable-background.ts +35 -12
- package/corpus/core/src/agent/production-agent.ts +55 -8
- package/corpus/core/src/cli/create.ts +1 -1
- package/corpus/core/src/cli/skills.ts +450 -19
- package/corpus/core/src/client/ConnectBuilderCard.tsx +7 -7
- package/corpus/core/src/client/NewWorkspaceAppFlow.tsx +1 -1
- package/corpus/core/src/client/blocks/library/AnnotatedCodeBlock.tsx +33 -18
- package/corpus/core/src/client/blocks/library/annotation-rail.tsx +3 -4
- package/corpus/core/src/client/components/CodeRequiredDialog.tsx +5 -8
- package/corpus/core/src/server/agent-chat-plugin.ts +7 -7
- package/corpus/core/src/server/auth.ts +7 -0
- package/corpus/core/src/server/onboarding-html.ts +95 -9
- package/corpus/core/src/server/self-dispatch.ts +8 -1
- package/corpus/core/src/templates/default/AGENTS.md +4 -0
- package/corpus/core/src/templates/default/package.json +2 -1
- package/corpus/core/src/templates/headless/AGENTS.md +4 -0
- package/corpus/core/src/templates/headless/package.json +1 -0
- package/corpus/core/src/templates/workspace-root/AGENTS.md +4 -0
- package/corpus/core/src/templates/workspace-root/README.md +4 -0
- package/corpus/core/src/templates/workspace-root/package.json +1 -0
- package/corpus/templates/analytics/actions/compose-dashboard.ts +34 -0
- package/corpus/templates/analytics/actions/install-dashboard-template.ts +51 -3
- package/corpus/templates/analytics/actions/update-dashboard.ts +3 -4
- package/corpus/templates/analytics/app/components/dashboard/SqlChart.tsx +175 -48
- package/corpus/templates/analytics/app/global.css +15 -13
- package/corpus/templates/analytics/app/pages/adhoc/sql-dashboard/PanelEditorDialog.tsx +9 -32
- package/corpus/templates/analytics/app/pages/adhoc/sql-dashboard/SqlChartCard.tsx +0 -26
- package/corpus/templates/analytics/app/pages/adhoc/sql-dashboard/index.tsx +0 -23
- package/corpus/templates/analytics/app/pages/adhoc/sql-dashboard/pivot.ts +65 -2
- package/corpus/templates/analytics/app/pages/adhoc/sql-dashboard/types.ts +3 -4
- package/corpus/templates/analytics/changelog/2026-06-24-dashboard-charts-now-fill-sparse-template-time-series-suppor.md +6 -0
- package/corpus/templates/analytics/changelog/2026-06-24-dashboard-filters-now-apply-consistently-to-first-party-traf.md +6 -0
- package/corpus/templates/analytics/changelog/2026-06-24-dashboard-rows-now-auto-fit-panels-so-one-two-or-three-chart.md +6 -0
- package/corpus/templates/analytics/changelog/2026-06-24-dashboard-traffic-tables-now-show-top-urls-and-shared-clips-.md +6 -0
- package/corpus/templates/analytics/changelog/2026-06-24-first-party-signup-and-pageview-panels-now-honor-dashboard-filters.md +5 -0
- package/corpus/templates/analytics/changelog/2026-06-24-first-party-template-dashboards-now-include-repeat-users-ret.md +6 -0
- package/corpus/templates/analytics/changelog/2026-06-24-retention-charts-now-break-out-1-day-and-7-day-return-rates-.md +6 -0
- package/corpus/templates/analytics/seeds/dashboards/agent-native-templates-first-party.json +330 -49
- package/corpus/templates/analytics/server/lib/dashboard-catalog.ts +7 -2
- package/corpus/templates/analytics/server/lib/first-party-analytics.ts +35 -8
- package/corpus/templates/analytics/server/lib/first-party-metric-catalog.ts +337 -45
- package/corpus/templates/calendar/changelog/2026-06-23-added-a-heads-up-explaining-google-s-app-not-verified-screen.md +1 -1
- package/corpus/templates/calendar/server/plugins/auth.ts +12 -0
- package/corpus/templates/clips/.agents/skills/recording/SKILL.md +7 -7
- package/corpus/templates/clips/AGENTS.md +6 -2
- package/corpus/templates/clips/app/components/capture-install-options.tsx +20 -4
- package/corpus/templates/clips/app/components/library/library-layout.tsx +7 -0
- package/corpus/templates/clips/app/components/player/player-controls.tsx +62 -32
- package/corpus/templates/clips/app/lib/capture-install-options.ts +39 -5
- package/corpus/templates/clips/app/routes/_app.settings._index.tsx +786 -323
- package/corpus/templates/clips/app/routes/download.tsx +2 -2
- package/corpus/templates/clips/app/routes/share.$shareId.tsx +1 -1
- package/corpus/templates/clips/changelog/2026-06-24-inline-slack-playback-controls-no-longer-shift-when-adjustin.md +6 -0
- package/corpus/templates/clips/changelog/2026-06-24-settings-now-puts-what-s-new-in-a-compact-sidebar-prioritize.md +6 -0
- package/corpus/templates/clips/changelog/2026-06-24-shared-clips-now-expose-their-full-console-log-stream-all-le.md +6 -0
- package/corpus/templates/clips/changelog/2026-06-24-shared-clips-now-expose-their-full-fetch-xhr-network-request.md +6 -0
- package/corpus/templates/clips/changelog/2026-06-24-the-chrome-extension-option-now-only-appears-on-supported-hosts.md +5 -0
- package/corpus/templates/clips/chrome-extension/STORE_DRAFT.md +13 -8
- package/corpus/templates/clips/chrome-extension/public/manifest.json +1 -1
- package/corpus/templates/clips/chrome-extension/scripts/package.ts +15 -2
- package/corpus/templates/clips/chrome-extension/src/overlay.css +4 -25
- package/corpus/templates/clips/chrome-extension/src/overlay.ts +1 -3
- package/corpus/templates/clips/server/lib/public-agent-context.ts +67 -24
- package/corpus/templates/mail/server/plugins/auth.ts +4 -1
- package/corpus/templates/plan/app/pages/PlansPage.tsx +271 -197
- package/corpus/templates/plan/changelog/2026-06-24-annotated-code-callouts-now-use-numbered-gutter-markers-that.md +6 -0
- package/corpus/templates/plan/server/plan-content.ts +45 -2
- package/dist/agent/durable-background.d.ts +9 -4
- package/dist/agent/durable-background.d.ts.map +1 -1
- package/dist/agent/durable-background.js +34 -11
- package/dist/agent/durable-background.js.map +1 -1
- package/dist/agent/production-agent.d.ts.map +1 -1
- package/dist/agent/production-agent.js +52 -8
- package/dist/agent/production-agent.js.map +1 -1
- package/dist/cli/create.js +1 -1
- package/dist/cli/create.js.map +1 -1
- package/dist/cli/skills.d.ts.map +1 -1
- package/dist/cli/skills.js +361 -19
- package/dist/cli/skills.js.map +1 -1
- package/dist/client/ConnectBuilderCard.d.ts.map +1 -1
- package/dist/client/ConnectBuilderCard.js +6 -6
- package/dist/client/ConnectBuilderCard.js.map +1 -1
- package/dist/client/NewWorkspaceAppFlow.js +1 -1
- package/dist/client/NewWorkspaceAppFlow.js.map +1 -1
- package/dist/client/blocks/library/AnnotatedCodeBlock.d.ts.map +1 -1
- package/dist/client/blocks/library/AnnotatedCodeBlock.js +14 -10
- package/dist/client/blocks/library/AnnotatedCodeBlock.js.map +1 -1
- package/dist/client/blocks/library/annotation-rail.d.ts +3 -4
- package/dist/client/blocks/library/annotation-rail.d.ts.map +1 -1
- package/dist/client/blocks/library/annotation-rail.js +3 -4
- package/dist/client/blocks/library/annotation-rail.js.map +1 -1
- package/dist/client/components/CodeRequiredDialog.d.ts.map +1 -1
- package/dist/client/components/CodeRequiredDialog.js +2 -1
- package/dist/client/components/CodeRequiredDialog.js.map +1 -1
- package/dist/server/agent-chat-plugin.js +7 -7
- package/dist/server/agent-chat-plugin.js.map +1 -1
- package/dist/server/auth.d.ts +7 -0
- package/dist/server/auth.d.ts.map +1 -1
- package/dist/server/auth.js +1 -0
- package/dist/server/auth.js.map +1 -1
- package/dist/server/onboarding-html.d.ts +15 -0
- package/dist/server/onboarding-html.d.ts.map +1 -1
- package/dist/server/onboarding-html.js +73 -9
- package/dist/server/onboarding-html.js.map +1 -1
- package/dist/server/self-dispatch.d.ts.map +1 -1
- package/dist/server/self-dispatch.js +5 -1
- package/dist/server/self-dispatch.js.map +1 -1
- package/dist/templates/default/AGENTS.md +4 -0
- package/dist/templates/default/package.json +2 -1
- package/dist/templates/headless/AGENTS.md +4 -0
- package/dist/templates/headless/package.json +1 -0
- package/dist/templates/workspace-root/AGENTS.md +4 -0
- package/dist/templates/workspace-root/README.md +4 -0
- package/dist/templates/workspace-root/package.json +1 -0
- package/docs/content/skills-guide.md +14 -0
- package/docs/content/template-clips.md +7 -1
- package/package.json +1 -1
- package/src/templates/default/AGENTS.md +4 -0
- package/src/templates/default/package.json +2 -1
- package/src/templates/headless/AGENTS.md +4 -0
- package/src/templates/headless/package.json +1 -0
- package/src/templates/workspace-root/AGENTS.md +4 -0
- package/src/templates/workspace-root/README.md +4 -0
- package/src/templates/workspace-root/package.json +1 -0
|
@@ -31,13 +31,14 @@ import {
|
|
|
31
31
|
} from "./context-xray-local.js";
|
|
32
32
|
import { CLIENTS, type ClientId } from "./mcp-config-writers.js";
|
|
33
33
|
import { PR_VISUAL_RECAP_SETUP, writePrVisualRecapWorkflow } from "./recap.js";
|
|
34
|
+
import { setupAgentSymlinks } from "./setup-agents.js";
|
|
34
35
|
|
|
35
36
|
const HELP = `npx @agent-native/core@latest skills
|
|
36
37
|
|
|
37
38
|
Usage:
|
|
38
39
|
npx @agent-native/core@latest skills list
|
|
39
|
-
npx @agent-native/core@latest skills status [assets|content|design-exploration|visual-plan|visual-recap|context-xray] [--client codex|claude-code|pi|all] [--scope user|project] [--json]
|
|
40
|
-
npx @agent-native/core@latest skills update [assets|content|design-exploration|visual-plan|visual-recap|context-xray] [--client codex|claude-code|pi|all] [--scope user|project] [--dry-run] [--json]
|
|
40
|
+
npx @agent-native/core@latest skills status [assets|content|design-exploration|visual-plan|visual-recap|context-xray|scaffold] [--client codex|claude-code|pi|all] [--scope user|project] [--json]
|
|
41
|
+
npx @agent-native/core@latest skills update [assets|content|design-exploration|visual-plan|visual-recap|context-xray|scaffold] [--client codex|claude-code|pi|all] [--scope user|project] [--dry-run] [--json]
|
|
41
42
|
npx @agent-native/core@latest skills add assets|content|design-exploration|visual-plan|visual-recap|context-xray [--client codex|claude-code|cowork|cursor|opencode|github-copilot|all] [--scope user|project] [--mode hosted|local-files|self-hosted] [--mcp-url <url>] [--no-connect] [--with-github-action] [--yes] [--dry-run] [--json]
|
|
42
43
|
npx @agent-native/core@latest skills add <manifest-or-app-dir|skill-repo> [--skill <name>] [--client ...] [--yes]
|
|
43
44
|
|
|
@@ -52,6 +53,7 @@ Examples:
|
|
|
52
53
|
npx @agent-native/core@latest skills add visual-plan --mode self-hosted --mcp-url https://my-plan-app.example.com
|
|
53
54
|
npx @agent-native/core@latest skills status visual-plan
|
|
54
55
|
npx @agent-native/core@latest skills update visual-plan
|
|
56
|
+
npx @agent-native/core@latest skills update scaffold --project
|
|
55
57
|
npx @agent-native/core@latest skills add visual-plan --no-connect
|
|
56
58
|
npx @agent-native/core@latest skills add context-xray --client all
|
|
57
59
|
npx @agent-native/core@latest skills add assets --client claude-code
|
|
@@ -101,7 +103,10 @@ run "npx @agent-native/core@latest recap setup" / "npx @agent-native/core@latest
|
|
|
101
103
|
verify GitHub Actions. Docs: https://www.agent-native.com/docs/pr-visual-recap.
|
|
102
104
|
|
|
103
105
|
The status/update commands inspect copied Agent Native skill folders and refresh
|
|
104
|
-
their instruction files from the current @agent-native/core package
|
|
106
|
+
their instruction files from the current @agent-native/core package. In generated
|
|
107
|
+
apps/workspaces, "skills update scaffold --project" refreshes the framework
|
|
108
|
+
skills copied into the scaffold and repairs AGENTS.md / CLAUDE.md and
|
|
109
|
+
.agents/skills / .claude/skills compatibility links.`;
|
|
105
110
|
|
|
106
111
|
const ASSETS_SKILL_MD = `---
|
|
107
112
|
name: assets
|
|
@@ -2844,6 +2849,19 @@ interface SkillInstallState {
|
|
|
2844
2849
|
managed: boolean;
|
|
2845
2850
|
}
|
|
2846
2851
|
|
|
2852
|
+
interface ScaffoldGuidanceState {
|
|
2853
|
+
kind: "workspace-core" | "standalone";
|
|
2854
|
+
displayName: string;
|
|
2855
|
+
templateName: "workspace-core" | "headless" | "default";
|
|
2856
|
+
path: string;
|
|
2857
|
+
sourcePath: string;
|
|
2858
|
+
projectRoot: string;
|
|
2859
|
+
workspaceRoot?: string;
|
|
2860
|
+
sharedPackageDir?: string;
|
|
2861
|
+
current: boolean;
|
|
2862
|
+
skillCount: number;
|
|
2863
|
+
}
|
|
2864
|
+
|
|
2847
2865
|
interface SkillInstallTarget {
|
|
2848
2866
|
id: string;
|
|
2849
2867
|
displayName: string;
|
|
@@ -3591,7 +3609,368 @@ function skillSearchRoots(input: {
|
|
|
3591
3609
|
});
|
|
3592
3610
|
}
|
|
3593
3611
|
|
|
3612
|
+
const SCAFFOLD_GUIDANCE_TARGETS = new Set([
|
|
3613
|
+
"scaffold",
|
|
3614
|
+
"generated",
|
|
3615
|
+
"generated-app",
|
|
3616
|
+
"generated-workspace",
|
|
3617
|
+
"workspace",
|
|
3618
|
+
"workspace-core",
|
|
3619
|
+
"framework-guidance",
|
|
3620
|
+
]);
|
|
3621
|
+
|
|
3622
|
+
function isScaffoldGuidanceTarget(value: string | undefined): boolean {
|
|
3623
|
+
if (!value) return false;
|
|
3624
|
+
return SCAFFOLD_GUIDANCE_TARGETS.has(value.trim().toLowerCase());
|
|
3625
|
+
}
|
|
3626
|
+
|
|
3627
|
+
function corePackageRootDir(): string {
|
|
3628
|
+
const here = path.dirname(fileURLToPath(import.meta.url));
|
|
3629
|
+
return path.resolve(here, "../..");
|
|
3630
|
+
}
|
|
3631
|
+
|
|
3632
|
+
function bundledScaffoldSkillsDir(
|
|
3633
|
+
templateName: ScaffoldGuidanceState["templateName"],
|
|
3634
|
+
): string {
|
|
3635
|
+
return path.join(
|
|
3636
|
+
corePackageRootDir(),
|
|
3637
|
+
"src",
|
|
3638
|
+
"templates",
|
|
3639
|
+
templateName,
|
|
3640
|
+
".agents",
|
|
3641
|
+
"skills",
|
|
3642
|
+
);
|
|
3643
|
+
}
|
|
3644
|
+
|
|
3645
|
+
function readJsonRecord(file: string): Record<string, unknown> | undefined {
|
|
3646
|
+
try {
|
|
3647
|
+
const parsed = JSON.parse(fs.readFileSync(file, "utf-8"));
|
|
3648
|
+
if (parsed && typeof parsed === "object" && !Array.isArray(parsed)) {
|
|
3649
|
+
return parsed as Record<string, unknown>;
|
|
3650
|
+
}
|
|
3651
|
+
} catch {}
|
|
3652
|
+
return undefined;
|
|
3653
|
+
}
|
|
3654
|
+
|
|
3655
|
+
function readPackageJson(dir: string): Record<string, unknown> | undefined {
|
|
3656
|
+
return readJsonRecord(path.join(dir, "package.json"));
|
|
3657
|
+
}
|
|
3658
|
+
|
|
3659
|
+
function packageName(pkg: Record<string, unknown> | undefined): string | null {
|
|
3660
|
+
return typeof pkg?.name === "string" ? pkg.name : null;
|
|
3661
|
+
}
|
|
3662
|
+
|
|
3663
|
+
function workspaceCorePackageName(
|
|
3664
|
+
pkg: Record<string, unknown> | undefined,
|
|
3665
|
+
): string | null {
|
|
3666
|
+
const agentNative = pkg?.["agent-native"];
|
|
3667
|
+
if (
|
|
3668
|
+
agentNative &&
|
|
3669
|
+
typeof agentNative === "object" &&
|
|
3670
|
+
!Array.isArray(agentNative) &&
|
|
3671
|
+
typeof (agentNative as Record<string, unknown>).workspaceCore === "string"
|
|
3672
|
+
) {
|
|
3673
|
+
return (agentNative as Record<string, string>).workspaceCore;
|
|
3674
|
+
}
|
|
3675
|
+
return null;
|
|
3676
|
+
}
|
|
3677
|
+
|
|
3678
|
+
function hasAgentNativeCoreDependency(
|
|
3679
|
+
pkg: Record<string, unknown> | undefined,
|
|
3680
|
+
): boolean {
|
|
3681
|
+
for (const field of ["dependencies", "devDependencies", "peerDependencies"]) {
|
|
3682
|
+
const deps = pkg?.[field];
|
|
3683
|
+
if (
|
|
3684
|
+
deps &&
|
|
3685
|
+
typeof deps === "object" &&
|
|
3686
|
+
!Array.isArray(deps) &&
|
|
3687
|
+
"@agent-native/core" in deps
|
|
3688
|
+
) {
|
|
3689
|
+
return true;
|
|
3690
|
+
}
|
|
3691
|
+
}
|
|
3692
|
+
return false;
|
|
3693
|
+
}
|
|
3694
|
+
|
|
3695
|
+
function findWorkspaceCorePackageDir(
|
|
3696
|
+
workspaceRoot: string,
|
|
3697
|
+
workspaceCoreName: string,
|
|
3698
|
+
): string | undefined {
|
|
3699
|
+
const packagesDir = path.join(workspaceRoot, "packages");
|
|
3700
|
+
if (!fs.existsSync(packagesDir)) return undefined;
|
|
3701
|
+
for (const entry of fs.readdirSync(packagesDir, { withFileTypes: true })) {
|
|
3702
|
+
if (!entry.isDirectory()) continue;
|
|
3703
|
+
const candidate = path.join(packagesDir, entry.name);
|
|
3704
|
+
if (packageName(readPackageJson(candidate)) === workspaceCoreName) {
|
|
3705
|
+
return candidate;
|
|
3706
|
+
}
|
|
3707
|
+
}
|
|
3708
|
+
const fallback = path.join(workspaceRoot, "packages", "shared");
|
|
3709
|
+
return fs.existsSync(path.join(fallback, "package.json"))
|
|
3710
|
+
? fallback
|
|
3711
|
+
: undefined;
|
|
3712
|
+
}
|
|
3713
|
+
|
|
3714
|
+
function findGeneratedWorkspace(startDir: string):
|
|
3715
|
+
| {
|
|
3716
|
+
workspaceRoot: string;
|
|
3717
|
+
sharedPackageDir: string;
|
|
3718
|
+
}
|
|
3719
|
+
| undefined {
|
|
3720
|
+
let current = path.resolve(startDir);
|
|
3721
|
+
while (true) {
|
|
3722
|
+
const pkg = readPackageJson(current);
|
|
3723
|
+
const workspaceCoreName = workspaceCorePackageName(pkg);
|
|
3724
|
+
if (workspaceCoreName && fs.existsSync(path.join(current, "apps"))) {
|
|
3725
|
+
const sharedPackageDir = findWorkspaceCorePackageDir(
|
|
3726
|
+
current,
|
|
3727
|
+
workspaceCoreName,
|
|
3728
|
+
);
|
|
3729
|
+
if (sharedPackageDir) {
|
|
3730
|
+
return { workspaceRoot: current, sharedPackageDir };
|
|
3731
|
+
}
|
|
3732
|
+
}
|
|
3733
|
+
const parent = path.dirname(current);
|
|
3734
|
+
if (parent === current) break;
|
|
3735
|
+
current = parent;
|
|
3736
|
+
}
|
|
3737
|
+
return undefined;
|
|
3738
|
+
}
|
|
3739
|
+
|
|
3740
|
+
function detectStandaloneScaffoldTemplate(
|
|
3741
|
+
projectRoot: string,
|
|
3742
|
+
): "headless" | "default" | undefined {
|
|
3743
|
+
const pkg = readPackageJson(projectRoot);
|
|
3744
|
+
if (!hasAgentNativeCoreDependency(pkg)) return undefined;
|
|
3745
|
+
if (!fs.existsSync(path.join(projectRoot, ".agents", "skills"))) {
|
|
3746
|
+
return undefined;
|
|
3747
|
+
}
|
|
3748
|
+
|
|
3749
|
+
const hasAppDir = fs.existsSync(path.join(projectRoot, "app"));
|
|
3750
|
+
const hasHeadlessHello = fs.existsSync(
|
|
3751
|
+
path.join(projectRoot, "actions", "hello.ts"),
|
|
3752
|
+
);
|
|
3753
|
+
if (!hasAppDir && hasHeadlessHello) return "headless";
|
|
3754
|
+
|
|
3755
|
+
const looksLikeDefaultTemplate =
|
|
3756
|
+
fs.existsSync(path.join(projectRoot, "app", "routes", "database.tsx")) &&
|
|
3757
|
+
fs.existsSync(path.join(projectRoot, "app", "routes", "_index.tsx")) &&
|
|
3758
|
+
fs.existsSync(path.join(projectRoot, "actions", "view-screen.ts"));
|
|
3759
|
+
return looksLikeDefaultTemplate ? "default" : undefined;
|
|
3760
|
+
}
|
|
3761
|
+
|
|
3762
|
+
function listImmediateSkillDirs(dir: string): string[] {
|
|
3763
|
+
if (!fs.existsSync(dir)) return [];
|
|
3764
|
+
return fs
|
|
3765
|
+
.readdirSync(dir, { withFileTypes: true })
|
|
3766
|
+
.filter((entry) => entry.isDirectory())
|
|
3767
|
+
.map((entry) => entry.name)
|
|
3768
|
+
.sort();
|
|
3769
|
+
}
|
|
3770
|
+
|
|
3771
|
+
function skillDirContentsMatch(sourceDir: string, targetDir: string): boolean {
|
|
3772
|
+
const expected = listSkillFolderFiles(sourceDir);
|
|
3773
|
+
const actual = listSkillFolderFiles(targetDir);
|
|
3774
|
+
const expectedFiles = Object.keys(expected).sort();
|
|
3775
|
+
const actualFiles = Object.keys(actual).sort();
|
|
3776
|
+
if (expectedFiles.length !== actualFiles.length) return false;
|
|
3777
|
+
for (let i = 0; i < expectedFiles.length; i += 1) {
|
|
3778
|
+
if (expectedFiles[i] !== actualFiles[i]) return false;
|
|
3779
|
+
}
|
|
3780
|
+
return expectedFiles.every((file) => expected[file] === actual[file]);
|
|
3781
|
+
}
|
|
3782
|
+
|
|
3783
|
+
function scaffoldGuidanceCurrent(
|
|
3784
|
+
sourceRoot: string,
|
|
3785
|
+
targetRoot: string,
|
|
3786
|
+
): boolean {
|
|
3787
|
+
const skills = listImmediateSkillDirs(sourceRoot);
|
|
3788
|
+
if (skills.length === 0) return false;
|
|
3789
|
+
return skills.every((skill) =>
|
|
3790
|
+
skillDirContentsMatch(
|
|
3791
|
+
path.join(sourceRoot, skill),
|
|
3792
|
+
path.join(targetRoot, skill),
|
|
3793
|
+
),
|
|
3794
|
+
);
|
|
3795
|
+
}
|
|
3796
|
+
|
|
3797
|
+
function collectScaffoldGuidanceStates(
|
|
3798
|
+
parsed: ParsedSkillsArgs,
|
|
3799
|
+
options: RunSkillsOptions,
|
|
3800
|
+
): ScaffoldGuidanceState[] {
|
|
3801
|
+
if (parsed.target && !isScaffoldGuidanceTarget(parsed.target)) return [];
|
|
3802
|
+
if (parsed.scopeExplicit && parsed.scope !== "project") return [];
|
|
3803
|
+
|
|
3804
|
+
const baseDir = path.resolve(options.baseDir ?? process.cwd());
|
|
3805
|
+
const workspace = findGeneratedWorkspace(baseDir);
|
|
3806
|
+
if (workspace) {
|
|
3807
|
+
const sourcePath = bundledScaffoldSkillsDir("workspace-core");
|
|
3808
|
+
const targetPath = path.join(
|
|
3809
|
+
workspace.sharedPackageDir,
|
|
3810
|
+
".agents",
|
|
3811
|
+
"skills",
|
|
3812
|
+
);
|
|
3813
|
+
if (!fs.existsSync(sourcePath)) return [];
|
|
3814
|
+
return [
|
|
3815
|
+
{
|
|
3816
|
+
kind: "workspace-core",
|
|
3817
|
+
displayName: "Generated workspace framework skills",
|
|
3818
|
+
templateName: "workspace-core",
|
|
3819
|
+
path: targetPath,
|
|
3820
|
+
sourcePath,
|
|
3821
|
+
projectRoot: workspace.workspaceRoot,
|
|
3822
|
+
workspaceRoot: workspace.workspaceRoot,
|
|
3823
|
+
sharedPackageDir: workspace.sharedPackageDir,
|
|
3824
|
+
current: scaffoldGuidanceCurrent(sourcePath, targetPath),
|
|
3825
|
+
skillCount: listImmediateSkillDirs(sourcePath).length,
|
|
3826
|
+
},
|
|
3827
|
+
];
|
|
3828
|
+
}
|
|
3829
|
+
|
|
3830
|
+
const templateName = detectStandaloneScaffoldTemplate(baseDir);
|
|
3831
|
+
if (!templateName) return [];
|
|
3832
|
+
const sourcePath = bundledScaffoldSkillsDir(templateName);
|
|
3833
|
+
const targetPath = path.join(baseDir, ".agents", "skills");
|
|
3834
|
+
if (!fs.existsSync(sourcePath)) return [];
|
|
3835
|
+
return [
|
|
3836
|
+
{
|
|
3837
|
+
kind: "standalone",
|
|
3838
|
+
displayName: `Generated ${templateName} app framework skills`,
|
|
3839
|
+
templateName,
|
|
3840
|
+
path: targetPath,
|
|
3841
|
+
sourcePath,
|
|
3842
|
+
projectRoot: baseDir,
|
|
3843
|
+
current: scaffoldGuidanceCurrent(sourcePath, targetPath),
|
|
3844
|
+
skillCount: listImmediateSkillDirs(sourcePath).length,
|
|
3845
|
+
},
|
|
3846
|
+
];
|
|
3847
|
+
}
|
|
3848
|
+
|
|
3849
|
+
function copyScaffoldGuidanceSkills(
|
|
3850
|
+
sourceRoot: string,
|
|
3851
|
+
targetRoot: string,
|
|
3852
|
+
): void {
|
|
3853
|
+
fs.mkdirSync(targetRoot, { recursive: true });
|
|
3854
|
+
for (const skill of listImmediateSkillDirs(sourceRoot)) {
|
|
3855
|
+
const targetSkillDir = path.join(targetRoot, skill);
|
|
3856
|
+
if (
|
|
3857
|
+
fs.existsSync(targetSkillDir) &&
|
|
3858
|
+
fs.lstatSync(targetSkillDir).isSymbolicLink()
|
|
3859
|
+
) {
|
|
3860
|
+
continue;
|
|
3861
|
+
}
|
|
3862
|
+
fs.rmSync(targetSkillDir, { recursive: true, force: true });
|
|
3863
|
+
fs.cpSync(path.join(sourceRoot, skill), targetSkillDir, {
|
|
3864
|
+
recursive: true,
|
|
3865
|
+
});
|
|
3866
|
+
}
|
|
3867
|
+
}
|
|
3868
|
+
|
|
3869
|
+
function updateScaffoldGuidanceStates(
|
|
3870
|
+
states: ScaffoldGuidanceState[],
|
|
3871
|
+
dryRun: boolean,
|
|
3872
|
+
): ScaffoldGuidanceState[] {
|
|
3873
|
+
const updated: ScaffoldGuidanceState[] = [];
|
|
3874
|
+
for (const state of states) {
|
|
3875
|
+
if (state.current) continue;
|
|
3876
|
+
if (!dryRun) {
|
|
3877
|
+
copyScaffoldGuidanceSkills(state.sourcePath, state.path);
|
|
3878
|
+
}
|
|
3879
|
+
updated.push({
|
|
3880
|
+
...state,
|
|
3881
|
+
current: !dryRun,
|
|
3882
|
+
});
|
|
3883
|
+
}
|
|
3884
|
+
return updated;
|
|
3885
|
+
}
|
|
3886
|
+
|
|
3887
|
+
function ensureWorkspaceRootSkillsLink(
|
|
3888
|
+
workspaceRoot: string,
|
|
3889
|
+
sharedPackageDir: string,
|
|
3890
|
+
): void {
|
|
3891
|
+
const sharedSkillsDir = path.join(sharedPackageDir, ".agents", "skills");
|
|
3892
|
+
if (!fs.existsSync(sharedSkillsDir)) return;
|
|
3893
|
+
|
|
3894
|
+
const agentsDir = path.join(workspaceRoot, ".agents");
|
|
3895
|
+
const linkPath = path.join(agentsDir, "skills");
|
|
3896
|
+
const target = path.relative(agentsDir, sharedSkillsDir);
|
|
3897
|
+
|
|
3898
|
+
fs.mkdirSync(agentsDir, { recursive: true });
|
|
3899
|
+
try {
|
|
3900
|
+
const stat = fs.lstatSync(linkPath);
|
|
3901
|
+
if (stat.isSymbolicLink()) {
|
|
3902
|
+
if (fs.readlinkSync(linkPath) === target) return;
|
|
3903
|
+
fs.unlinkSync(linkPath);
|
|
3904
|
+
} else {
|
|
3905
|
+
copyScaffoldGuidanceSkills(sharedSkillsDir, linkPath);
|
|
3906
|
+
return;
|
|
3907
|
+
}
|
|
3908
|
+
} catch {}
|
|
3909
|
+
|
|
3910
|
+
try {
|
|
3911
|
+
fs.symlinkSync(
|
|
3912
|
+
target,
|
|
3913
|
+
linkPath,
|
|
3914
|
+
process.platform === "win32" ? "junction" : "dir",
|
|
3915
|
+
);
|
|
3916
|
+
} catch {
|
|
3917
|
+
try {
|
|
3918
|
+
fs.cpSync(sharedSkillsDir, linkPath, { recursive: true });
|
|
3919
|
+
} catch {}
|
|
3920
|
+
}
|
|
3921
|
+
}
|
|
3922
|
+
|
|
3923
|
+
function refreshCopiedClaudeSkills(projectRoot: string): void {
|
|
3924
|
+
const agentsSkillsDir = path.join(projectRoot, ".agents", "skills");
|
|
3925
|
+
const claudeSkillsDir = path.join(projectRoot, ".claude", "skills");
|
|
3926
|
+
if (!fs.existsSync(agentsSkillsDir) || !fs.existsSync(claudeSkillsDir)) {
|
|
3927
|
+
return;
|
|
3928
|
+
}
|
|
3929
|
+
try {
|
|
3930
|
+
if (fs.lstatSync(claudeSkillsDir).isSymbolicLink()) return;
|
|
3931
|
+
copyScaffoldGuidanceSkills(agentsSkillsDir, claudeSkillsDir);
|
|
3932
|
+
} catch {}
|
|
3933
|
+
}
|
|
3934
|
+
|
|
3935
|
+
function repairScaffoldAgentLinks(states: ScaffoldGuidanceState[]): void {
|
|
3936
|
+
const seen = new Set<string>();
|
|
3937
|
+
for (const state of states) {
|
|
3938
|
+
if (state.workspaceRoot && state.sharedPackageDir) {
|
|
3939
|
+
const key = `workspace:${state.workspaceRoot}`;
|
|
3940
|
+
if (seen.has(key)) continue;
|
|
3941
|
+
seen.add(key);
|
|
3942
|
+
ensureWorkspaceRootSkillsLink(
|
|
3943
|
+
state.workspaceRoot,
|
|
3944
|
+
state.sharedPackageDir,
|
|
3945
|
+
);
|
|
3946
|
+
setupAgentSymlinks(state.workspaceRoot);
|
|
3947
|
+
refreshCopiedClaudeSkills(state.workspaceRoot);
|
|
3948
|
+
setupAgentSymlinks(state.sharedPackageDir);
|
|
3949
|
+
refreshCopiedClaudeSkills(state.sharedPackageDir);
|
|
3950
|
+
const appsDir = path.join(state.workspaceRoot, "apps");
|
|
3951
|
+
if (fs.existsSync(appsDir)) {
|
|
3952
|
+
for (const entry of fs.readdirSync(appsDir, { withFileTypes: true })) {
|
|
3953
|
+
if (!entry.isDirectory()) continue;
|
|
3954
|
+
const appDir = path.join(appsDir, entry.name);
|
|
3955
|
+
if (fs.existsSync(path.join(appDir, "package.json"))) {
|
|
3956
|
+
setupAgentSymlinks(appDir);
|
|
3957
|
+
refreshCopiedClaudeSkills(appDir);
|
|
3958
|
+
}
|
|
3959
|
+
}
|
|
3960
|
+
}
|
|
3961
|
+
continue;
|
|
3962
|
+
}
|
|
3963
|
+
|
|
3964
|
+
const key = `standalone:${state.projectRoot}`;
|
|
3965
|
+
if (seen.has(key)) continue;
|
|
3966
|
+
seen.add(key);
|
|
3967
|
+
setupAgentSymlinks(state.projectRoot);
|
|
3968
|
+
refreshCopiedClaudeSkills(state.projectRoot);
|
|
3969
|
+
}
|
|
3970
|
+
}
|
|
3971
|
+
|
|
3594
3972
|
function targetIdsForStatus(parsed: ParsedSkillsArgs): BuiltInAppSkillId[] {
|
|
3973
|
+
if (isScaffoldGuidanceTarget(parsed.target)) return [];
|
|
3595
3974
|
if (!parsed.target) {
|
|
3596
3975
|
return (Object.keys(BUILT_IN_APP_SKILLS) as BuiltInAppSkillId[]).filter(
|
|
3597
3976
|
(id) => !isLocalOnlyBuiltInSkill(BUILT_IN_APP_SKILLS[id]),
|
|
@@ -5423,6 +5802,27 @@ function formatSkillState(state: SkillInstallState): string {
|
|
|
5423
5802
|
return `${state.skillName.padEnd(22)} ${status.padEnd(7)} ${state.scope}/${state.client} ${managed}${hashes}\n ${state.path}`;
|
|
5424
5803
|
}
|
|
5425
5804
|
|
|
5805
|
+
function scaffoldStateJson(state: ScaffoldGuidanceState) {
|
|
5806
|
+
return {
|
|
5807
|
+
kind: state.kind,
|
|
5808
|
+
displayName: state.displayName,
|
|
5809
|
+
templateName: state.templateName,
|
|
5810
|
+
path: state.path,
|
|
5811
|
+
sourcePath: state.sourcePath,
|
|
5812
|
+
projectRoot: state.projectRoot,
|
|
5813
|
+
workspaceRoot: state.workspaceRoot,
|
|
5814
|
+
sharedPackageDir: state.sharedPackageDir,
|
|
5815
|
+
skillCount: state.skillCount,
|
|
5816
|
+
status: state.current ? "current" : "stale",
|
|
5817
|
+
managed: true,
|
|
5818
|
+
};
|
|
5819
|
+
}
|
|
5820
|
+
|
|
5821
|
+
function formatScaffoldState(state: ScaffoldGuidanceState): string {
|
|
5822
|
+
const status = state.current ? "current" : "stale";
|
|
5823
|
+
return `${"scaffold".padEnd(22)} ${status.padEnd(7)} project/${state.kind} managed (${state.skillCount} skills)\n ${state.path}`;
|
|
5824
|
+
}
|
|
5825
|
+
|
|
5426
5826
|
function planModeSummary(mode: PlanInstallMode): string {
|
|
5427
5827
|
if (mode === "local-files")
|
|
5428
5828
|
return "Local files - no hosted writes by default";
|
|
@@ -5503,25 +5903,46 @@ function runSkillsStatusOrUpdate(
|
|
|
5503
5903
|
options: RunSkillsOptions,
|
|
5504
5904
|
update: boolean,
|
|
5505
5905
|
): void {
|
|
5506
|
-
const
|
|
5507
|
-
const
|
|
5508
|
-
const
|
|
5906
|
+
const skillBefore = collectSkillInstallStates(parsed, options);
|
|
5907
|
+
const scaffoldBefore = collectScaffoldGuidanceStates(parsed, options);
|
|
5908
|
+
const skillChanged = update
|
|
5909
|
+
? updateSkillInstallStates(skillBefore, parsed.dryRun)
|
|
5910
|
+
: [];
|
|
5911
|
+
const scaffoldChanged = update
|
|
5912
|
+
? updateScaffoldGuidanceStates(scaffoldBefore, parsed.dryRun)
|
|
5913
|
+
: [];
|
|
5914
|
+
if (update && !parsed.dryRun && scaffoldChanged.length > 0) {
|
|
5915
|
+
repairScaffoldAgentLinks(scaffoldChanged);
|
|
5916
|
+
}
|
|
5917
|
+
const skillAfter =
|
|
5509
5918
|
update && !parsed.dryRun
|
|
5510
5919
|
? collectSkillInstallStates(parsed, options)
|
|
5511
|
-
:
|
|
5920
|
+
: skillBefore;
|
|
5921
|
+
const scaffoldAfter =
|
|
5922
|
+
update && !parsed.dryRun
|
|
5923
|
+
? collectScaffoldGuidanceStates(parsed, options)
|
|
5924
|
+
: scaffoldBefore;
|
|
5925
|
+
const beforeCount = skillBefore.length + scaffoldBefore.length;
|
|
5926
|
+
const changedCount = skillChanged.length + scaffoldChanged.length;
|
|
5512
5927
|
|
|
5513
5928
|
if (parsed.printJson) {
|
|
5514
|
-
const
|
|
5929
|
+
const outputSkillStates =
|
|
5930
|
+
update && !parsed.dryRun ? skillAfter : skillBefore;
|
|
5931
|
+
const outputScaffoldStates =
|
|
5932
|
+
update && !parsed.dryRun ? scaffoldAfter : scaffoldBefore;
|
|
5515
5933
|
process.stdout.write(
|
|
5516
5934
|
`${JSON.stringify(
|
|
5517
5935
|
{
|
|
5518
5936
|
ok: true,
|
|
5519
5937
|
command: parsed.command,
|
|
5520
5938
|
dryRun: parsed.dryRun,
|
|
5521
|
-
found:
|
|
5522
|
-
stale:
|
|
5523
|
-
|
|
5524
|
-
|
|
5939
|
+
found: beforeCount,
|
|
5940
|
+
stale:
|
|
5941
|
+
outputSkillStates.filter((state) => !state.current).length +
|
|
5942
|
+
outputScaffoldStates.filter((state) => !state.current).length,
|
|
5943
|
+
updated: changedCount,
|
|
5944
|
+
skills: outputSkillStates.map(skillStateJson),
|
|
5945
|
+
scaffold: outputScaffoldStates.map(scaffoldStateJson),
|
|
5525
5946
|
},
|
|
5526
5947
|
null,
|
|
5527
5948
|
2,
|
|
@@ -5530,10 +5951,13 @@ function runSkillsStatusOrUpdate(
|
|
|
5530
5951
|
return;
|
|
5531
5952
|
}
|
|
5532
5953
|
|
|
5533
|
-
if (
|
|
5954
|
+
if (beforeCount === 0) {
|
|
5534
5955
|
const target = parsed.target ? ` for ${parsed.target}` : "";
|
|
5956
|
+
const hint = isScaffoldGuidanceTarget(parsed.target)
|
|
5957
|
+
? `Run this from a generated Agent Native app or workspace root.\n`
|
|
5958
|
+
: `Run "npx @agent-native/core@latest skills add ${parsed.target ?? "visual-plan"}" to install one.\n`;
|
|
5535
5959
|
process.stdout.write(
|
|
5536
|
-
`No installed Agent Native skill copies found${target}.\
|
|
5960
|
+
`No installed Agent Native skill copies found${target}.\n${hint}`,
|
|
5537
5961
|
);
|
|
5538
5962
|
return;
|
|
5539
5963
|
}
|
|
@@ -5541,20 +5965,27 @@ function runSkillsStatusOrUpdate(
|
|
|
5541
5965
|
if (update) {
|
|
5542
5966
|
if (parsed.dryRun) {
|
|
5543
5967
|
process.stdout.write(
|
|
5544
|
-
|
|
5545
|
-
? `Would update ${
|
|
5968
|
+
changedCount
|
|
5969
|
+
? `Would update ${changedCount} skill folder${changedCount === 1 ? "" : "s"}:\n`
|
|
5546
5970
|
: "All discovered skill folders are already current.\n",
|
|
5547
5971
|
);
|
|
5548
5972
|
} else {
|
|
5549
5973
|
process.stdout.write(
|
|
5550
|
-
|
|
5551
|
-
? `Updated ${
|
|
5974
|
+
changedCount
|
|
5975
|
+
? `Updated ${changedCount} skill folder${changedCount === 1 ? "" : "s"}.\n`
|
|
5552
5976
|
: "All discovered skill folders are already current.\n",
|
|
5553
5977
|
);
|
|
5554
5978
|
}
|
|
5555
5979
|
}
|
|
5556
5980
|
|
|
5557
|
-
const rows =
|
|
5981
|
+
const rows = [
|
|
5982
|
+
...(update && parsed.dryRun ? skillBefore : skillAfter).map(
|
|
5983
|
+
formatSkillState,
|
|
5984
|
+
),
|
|
5985
|
+
...(update && parsed.dryRun ? scaffoldBefore : scaffoldAfter).map(
|
|
5986
|
+
formatScaffoldState,
|
|
5987
|
+
),
|
|
5988
|
+
];
|
|
5558
5989
|
process.stdout.write(`${rows.join("\n")}\n`);
|
|
5559
5990
|
}
|
|
5560
5991
|
|
|
@@ -7,6 +7,9 @@ import { cn } from "./utils.js";
|
|
|
7
7
|
import { agentNativePath } from "./api-path.js";
|
|
8
8
|
|
|
9
9
|
const DESKTOP_DOWNLOAD_URL = "https://www.agent-native.com/download";
|
|
10
|
+
const CODE_CHANGE_FALLBACK_DETAIL =
|
|
11
|
+
"Edit locally or use Builder.io to edit this code in the cloud and continue customizing the app any way you like.";
|
|
12
|
+
const CODE_CHANGE_FALLBACK_TEXT = `This requires a code change. ${CODE_CHANGE_FALLBACK_DETAIL}`;
|
|
10
13
|
|
|
11
14
|
function isLocalBrowserOutsideDesktop() {
|
|
12
15
|
if (typeof window === "undefined" || typeof navigator === "undefined") {
|
|
@@ -200,7 +203,7 @@ export function ConnectBuilderCard({
|
|
|
200
203
|
// so the render tree below stays flat.
|
|
201
204
|
const connectedCapabilityText = builderEnabled
|
|
202
205
|
? "AI credits and cloud code changes are ready to use."
|
|
203
|
-
:
|
|
206
|
+
: `AI credits are ready to use. ${CODE_CHANGE_FALLBACK_TEXT}`;
|
|
204
207
|
let title: string;
|
|
205
208
|
let subtitle: React.ReactNode;
|
|
206
209
|
if (runResult) {
|
|
@@ -215,20 +218,17 @@ export function ConnectBuilderCard({
|
|
|
215
218
|
</>
|
|
216
219
|
);
|
|
217
220
|
} else if (showWaitlist) {
|
|
218
|
-
title =
|
|
219
|
-
? "You're on the waitlist"
|
|
220
|
-
: "Builder Cloud Agents coming soon";
|
|
221
|
+
title = "This requires a code change";
|
|
221
222
|
subtitle = waitlistJoined ? (
|
|
222
223
|
<>
|
|
223
|
-
|
|
224
|
-
workspace.{" "}
|
|
224
|
+
You're on the waitlist. {CODE_CHANGE_FALLBACK_DETAIL}{" "}
|
|
225
225
|
{localBrowser
|
|
226
226
|
? "Since this project is already running locally, open it in the desktop app for local coding tools or keep editing from your clone."
|
|
227
227
|
: "You can still clone the project locally and use the desktop app for code changes."}
|
|
228
228
|
</>
|
|
229
229
|
) : (
|
|
230
230
|
<>
|
|
231
|
-
|
|
231
|
+
{CODE_CHANGE_FALLBACK_DETAIL}{" "}
|
|
232
232
|
{localBrowser
|
|
233
233
|
? "Since this project is already running locally, open it in the desktop app for local coding tools or keep editing from your clone."
|
|
234
234
|
: "You can still clone the project locally and use the desktop app for code changes."}
|
|
@@ -294,7 +294,7 @@ export function NewWorkspaceAppFlow({
|
|
|
294
294
|
} else {
|
|
295
295
|
setStatusMessage(
|
|
296
296
|
result?.message ||
|
|
297
|
-
"
|
|
297
|
+
"This requires a code change. Edit locally or use Builder.io to edit this code in the cloud and continue customizing the app any way you like.",
|
|
298
298
|
);
|
|
299
299
|
}
|
|
300
300
|
}
|