mirror of
https://github.com/openclaw/openclaw.git
synced 2026-07-25 08:21:17 +00:00
* feat(onboarding): recommend plugins and skills from installed apps Scan installed macOS apps during classic onboarding (TCC-free), gather candidates from official catalogs + ClawHub search, let the configured model pick genuine matches, and offer an opt-in multiselect install step. Adds a device.apps node-host command (default-off sharing, Android-parity envelope) so remote gateways can request a paired Mac's inventory, and a wizard.appRecommendations kill switch. Custom setup-inference completions no longer inherit the 32-token verification-probe output cap. * feat(onboarding): recommend apps in guided flow * fix(onboarding): harden app recommendations against ClawHub self-promotion Third-party ClawHub skills are never pre-selected regardless of model tier (publisher-controlled listing text reaches the matcher prompt and could promote itself); their labels now say they install third-party code. Installed-app scans follow symlinked .app bundles. Matcher output stays bounded by the resolved model's own maxTokens budget (documented invariant). * fix(onboarding): key official catalog candidates by resolved plugin id Real catalog entries are package manifests without a top-level id; keying the candidate map and channel/provider classification by entry.id collapsed the whole official catalog into one undefined-keyed entry, so no official plugin or channel was ever recommended. Regression test runs against the bundled catalogs. * fix(onboarding): satisfy lint, types, deadcode, and migration gates Split the guided-onboarding test into a self-contained custodian suite to stay under max-lines. Narrow app-recommendation exports (drop dead node-payload normalizer, unexport internal types/helpers, route candidate tests through the public API), replace map-spread with a helper, unexport device.apps result types, add installedAppsSharing to node-host migration expectations, cast the wizard multiselect mock, and regenerate the docs map. * test(onboarding): register new live test in the shard classifier
56 lines
1.6 KiB
TypeScript
56 lines
1.6 KiB
TypeScript
import { describe, expect, it, vi } from "vitest";
|
|
import type { scanInstalledApps } from "../infra/installed-apps.js";
|
|
import { invokeDeviceApps } from "./invoke-device-apps.js";
|
|
|
|
const scan = vi.fn<typeof scanInstalledApps>(async () => ({
|
|
status: "ok",
|
|
apps: [
|
|
{ label: "Calendar", bundleId: "com.apple.iCal", path: "/System/Calendar.app", system: true },
|
|
{
|
|
label: "Notes App",
|
|
bundleId: "com.example.notes",
|
|
path: "/Applications/Notes.app",
|
|
system: false,
|
|
},
|
|
{ label: "Other", path: "/Applications/Other.app", system: false },
|
|
],
|
|
}));
|
|
|
|
describe("invokeDeviceApps", () => {
|
|
it("returns the typed privacy error while sharing is disabled", async () => {
|
|
await expect(
|
|
invokeDeviceApps({ sharingEnabled: false, platform: "darwin", scan }),
|
|
).resolves.toEqual({
|
|
ok: false,
|
|
code: "INSTALLED_APPS_SHARING_DISABLED",
|
|
message: "INSTALLED_APPS_SHARING_DISABLED: enable Installed Apps in node-host settings",
|
|
});
|
|
expect(scan).not.toHaveBeenCalled();
|
|
});
|
|
|
|
it("matches the Android count envelope with macOS app fields", async () => {
|
|
const result = await invokeDeviceApps({
|
|
sharingEnabled: true,
|
|
platform: "darwin",
|
|
paramsJSON: JSON.stringify({ query: "app", limit: 1, includeSystem: false }),
|
|
scan,
|
|
});
|
|
expect(result).toEqual({
|
|
ok: true,
|
|
payload: {
|
|
count: 1,
|
|
totalMatched: 1,
|
|
truncated: false,
|
|
apps: [
|
|
{
|
|
label: "Notes App",
|
|
bundleId: "com.example.notes",
|
|
path: "/Applications/Notes.app",
|
|
system: false,
|
|
},
|
|
],
|
|
},
|
|
});
|
|
});
|
|
});
|