diff --git a/.env.example b/.env.example index 8f055a8e..26f16565 100644 --- a/.env.example +++ b/.env.example @@ -21,7 +21,6 @@ CUED_IMESSAGE_NATIVE_BINARY= CUED_CALL_HISTORY_DB_PATH= CUED_CONTACTS_NATIVE_BINARY= CUED_CONTACTS_JSON_PATH= -CUED_SIGNAL_CLI_PATH= CUED_SIGNAL_ACCOUNT= CUED_WHATSAPP_HELPER_BINARY= CUED_WHATSAPP_DESKTOP_SOURCE_PATH= diff --git a/native/macos/CuedNative/Sources/CuedNative/RootWindowController.swift b/native/macos/CuedNative/Sources/CuedNative/RootWindowController.swift index e7152660..2d73e3d4 100644 --- a/native/macos/CuedNative/Sources/CuedNative/RootWindowController.swift +++ b/native/macos/CuedNative/Sources/CuedNative/RootWindowController.swift @@ -159,12 +159,13 @@ final class RootWindowController: NSWindowController { let daemonSupervisor = self.daemonSupervisor let statusStore = self.statusStore let shouldEnsurePrerequisites = consumePrerequisiteSetupIntent() - let shouldRefreshPermissions = forceActivePermissionRefresh || shouldRefreshLivePermissions() - let fastPermissionKeys = shouldRefreshPermissions + let shouldRefreshFastPermissions = forceActivePermissionRefresh || shouldRefreshLivePermissions() + let shouldRefreshManagedIntegrations = shouldRefreshFastPermissions + let fastPermissionKeys = shouldRefreshFastPermissions ? (pendingLivePermissionKeys.isEmpty ? liveRefreshPermissionKeys : pendingLivePermissionKeys) : [] - if shouldRefreshPermissions { + if shouldRefreshFastPermissions { applyFastPermissionStatuses(for: fastPermissionKeys) } @@ -190,7 +191,7 @@ final class RootWindowController: NSWindowController { let snapshot = Self.decodeJSON( daemonSupervisor: daemonSupervisor, RootSnapshotResponse.self, - arguments: onboardingSnapshotArguments(refreshPermissions: shouldRefreshPermissions) + arguments: onboardingSnapshotArguments(refreshManagedIntegrations: shouldRefreshManagedIntegrations) ) guard let snapshot else { @@ -952,7 +953,7 @@ func shouldActivelyRefreshPermissions(for flags: [String]) -> Bool { return !keys.isDisjoint(with: liveRefreshPermissionKeys) } -func onboardingSnapshotArguments(refreshPermissions: Bool) -> [String] { +func onboardingSnapshotArguments(refreshManagedIntegrations: Bool) -> [String] { ["onboarding", "snapshot"] + - (refreshPermissions ? ["--refresh-managed", "--refresh-permissions"] : []) + (refreshManagedIntegrations ? ["--refresh-managed"] : []) } diff --git a/native/macos/CuedNative/Tests/CuedNativeTests/RootViewTests.swift b/native/macos/CuedNative/Tests/CuedNativeTests/RootViewTests.swift index d7b43d2e..3132d6ef 100644 --- a/native/macos/CuedNative/Tests/CuedNativeTests/RootViewTests.swift +++ b/native/macos/CuedNative/Tests/CuedNativeTests/RootViewTests.swift @@ -32,11 +32,11 @@ final class RootViewTests: XCTestCase { func testActivePermissionSnapshotRefreshAlsoRefreshesManagedIntegrations() { XCTAssertEqual( - onboardingSnapshotArguments(refreshPermissions: true), - ["onboarding", "snapshot", "--refresh-managed", "--refresh-permissions"] + onboardingSnapshotArguments(refreshManagedIntegrations: true), + ["onboarding", "snapshot", "--refresh-managed"] ) XCTAssertEqual( - onboardingSnapshotArguments(refreshPermissions: false), + onboardingSnapshotArguments(refreshManagedIntegrations: false), ["onboarding", "snapshot"] ) } diff --git a/src/cli.ts b/src/cli.ts index 3cd03997..25a3a6ff 100644 --- a/src/cli.ts +++ b/src/cli.ts @@ -32,7 +32,6 @@ import { } from "./platforms/core/state/status.js"; import { getPlatformFeatureMatrixRow, - getPlatformFutureFeatureNotes, getPlatformHelperRequirements, getPlatformPermissionRequirements, getSupportedHostOsForPlatform, @@ -136,7 +135,7 @@ Usage: cued update install cued cli install|status cued login-item enable|disable|status - cued onboarding complete|snapshot|status [--refresh-managed] [--refresh-permissions] + cued onboarding complete|snapshot|status [--refresh-managed] cued telemetry status|enable|disable|smoke cued skill install-global|status cued permissions doctor|status|request [--all|--contacts|--full-disk-access] @@ -368,7 +367,6 @@ async function handleLocalIntegrationCommand( permissionRequirements: getPlatformPermissionRequirements(platform), helperRequirements: getPlatformHelperRequirements(platform), features: getPlatformFeatureMatrixRow(platform), - futureFeatures: getPlatformFutureFeatureNotes(platform), })); } @@ -685,7 +683,6 @@ async function main(): Promise { } case "onboarding": { const refreshManaged = rest.includes("--refresh-managed"); - const refreshPermissions = rest.includes("--refresh-permissions"); let daemonResponse: Awaited> | null = null; try { switch (subcommand) { @@ -696,7 +693,6 @@ async function main(): Promise { daemonResponse = await sendDaemonRequest({ command: "onboarding-snapshot", refreshManagedIntegrations: refreshManaged, - refreshPermissions, }); break; case "status": @@ -715,7 +711,7 @@ async function main(): Promise { } const db = - subcommand === "snapshot" && !refreshManaged && !refreshPermissions + subcommand === "snapshot" && !refreshManaged ? openCuedDatabaseReadOnly() : openCuedDatabase(); try { @@ -733,12 +729,11 @@ async function main(): Promise { await sendTelemetryEventSafe(db, "onboarding_started", { component: "onboarding", operation: "snapshot", - stage: refreshPermissions ? "permissions" : refreshManaged ? "managed" : "status", + stage: refreshManaged ? "managed" : "status", }); printJson( await buildOnboardingSnapshot(db, { refreshManagedIntegrations: refreshManaged, - refreshPermissions, }), ); return; @@ -747,7 +742,7 @@ async function main(): Promise { return; default: throw new Error( - "Usage: cued onboarding complete | snapshot [--refresh-managed] [--refresh-permissions] | status", + "Usage: cued onboarding complete | snapshot [--refresh-managed] | status", ); } } finally { @@ -907,17 +902,7 @@ async function main(): Promise { printJson(daemonResponse.result ?? null); return; } - const db = openCuedDatabaseReadOnly(); - try { - printJson( - await buildPermissionStatus({ - mode: "passive", - db, - }), - ); - } finally { - db.close(); - } + printJson(await buildPermissionStatus()); } return; case "request": { diff --git a/src/core/platform-capabilities.test.ts b/src/core/platform-capabilities.test.ts index dac600d9..fb81cd0a 100644 --- a/src/core/platform-capabilities.test.ts +++ b/src/core/platform-capabilities.test.ts @@ -1,8 +1,5 @@ import { beforeEach, describe, expect, it, vi } from "vitest"; -import { - getPlatformFeatureSupport, - getPlatformFutureFeatureNotes, -} from "../platforms/core/types.js"; +import { getPlatformFeatureSupport } from "../platforms/core/types.js"; import { summarizePlatformCapability } from "./platform-capabilities.js"; const inspectSlackHelperMock = vi.fn(); @@ -239,11 +236,4 @@ describe("platform capability resolver", () => { expect(getPlatformFeatureSupport("linkedin", "read_receipts")).toBe("partial"); expect(getPlatformFeatureSupport("imessage", "realtime_ingest")).toBe("yes"); }); - - it("does not expose outbound send notes in product capabilities", () => { - expect(getPlatformFutureFeatureNotes("contacts")).toEqual({}); - expect(getPlatformFutureFeatureNotes("gmail")).toEqual({}); - expect(getPlatformFutureFeatureNotes("imessage")).toEqual({}); - expect(getPlatformFutureFeatureNotes("signal")).toEqual({}); - }); }); diff --git a/src/platforms/core/registry.ts b/src/platforms/core/registry.ts index 81b7a7a5..dae2b3b6 100644 --- a/src/platforms/core/registry.ts +++ b/src/platforms/core/registry.ts @@ -11,7 +11,6 @@ export { isAdapterPlatform } from "../../core/types/provider.js"; export interface AdapterDefinition { platform: AdapterPlatform; workerEntrypoint: string; - autoSync: boolean; workerTimeoutMs: number; } @@ -21,49 +20,41 @@ const ADAPTER_DEFINITIONS: Record = { imessage: { platform: "imessage", workerEntrypoint: join(MODULE_DIRNAME, "../imessage/worker.js"), - autoSync: true, workerTimeoutMs: 120_000, }, discord: { platform: "discord", workerEntrypoint: join(MODULE_DIRNAME, "../discord/sync/worker.js"), - autoSync: true, workerTimeoutMs: 120_000, }, contacts: { platform: "contacts", workerEntrypoint: join(MODULE_DIRNAME, "../contacts/worker.js"), - autoSync: true, workerTimeoutMs: 120_000, }, gmail: { platform: "gmail", workerEntrypoint: join(MODULE_DIRNAME, "../gmail/sync/worker.js"), - autoSync: true, workerTimeoutMs: 600_000, }, linkedin: { platform: "linkedin", workerEntrypoint: join(MODULE_DIRNAME, "../linkedin/sync/worker.js"), - autoSync: true, workerTimeoutMs: 120_000, }, slack: { platform: "slack", workerEntrypoint: join(MODULE_DIRNAME, "../slack/sync/worker.js"), - autoSync: true, workerTimeoutMs: 600_000, }, signal: { platform: "signal", workerEntrypoint: join(MODULE_DIRNAME, "../signal/sync/worker.js"), - autoSync: true, workerTimeoutMs: 60_000, }, whatsapp: { platform: "whatsapp", workerEntrypoint: join(MODULE_DIRNAME, "../whatsapp/sync/worker.js"), - autoSync: true, workerTimeoutMs: 60_000, }, }; @@ -72,12 +63,6 @@ export function listAdapterPlatforms(): AdapterPlatform[] { return [...ADAPTER_PLATFORM_VALUES]; } -export function listAutoSyncPlatforms(): AdapterPlatform[] { - return Object.values(ADAPTER_DEFINITIONS) - .filter((definition) => definition.autoSync) - .map((definition) => definition.platform); -} - export function getAdapterDefinition(platform: string): AdapterDefinition | null { return isAdapterPlatform(platform) ? ADAPTER_DEFINITIONS[platform] : null; } diff --git a/src/platforms/core/runner.test.ts b/src/platforms/core/runner.test.ts index 6bbd8029..604d80c4 100644 --- a/src/platforms/core/runner.test.ts +++ b/src/platforms/core/runner.test.ts @@ -8,7 +8,6 @@ const { getAdapterDefinitionMock, spawnMock } = vi.hoisted(() => ({ getAdapterDefinitionMock: vi.fn(() => ({ platform: "slack", workerEntrypoint: "/tmp/fake-worker.js", - autoSync: true, workerTimeoutMs: 50, })), spawnMock: vi.fn(), @@ -39,7 +38,6 @@ describe("adapter runner", () => { getAdapterDefinitionMock.mockReturnValue({ platform: "slack", workerEntrypoint: "/tmp/fake-worker.js", - autoSync: true, workerTimeoutMs: 50, }); while (tempDirs.length > 0) { @@ -102,7 +100,6 @@ describe("adapter runner", () => { getAdapterDefinitionMock.mockReturnValue({ platform: "signal", workerEntrypoint: join(dir, "signal-worker.js"), - autoSync: true, workerTimeoutMs: 50, }); diff --git a/src/platforms/core/state/integration-state.test.ts b/src/platforms/core/state/integration-state.test.ts index c7d2a074..341f75d9 100644 --- a/src/platforms/core/state/integration-state.test.ts +++ b/src/platforms/core/state/integration-state.test.ts @@ -38,7 +38,6 @@ describe("integration state management", () => { delete process.env.CUED_CONTACTS_NATIVE_BINARY; delete process.env.CUED_IMESSAGE_DB_PATH; delete process.env.CUED_SIGNAL_DIR; - delete process.env.CUED_SIGNAL_CLI_PATH; delete process.env.CUED_SLACK_APP_BINARY; delete process.env.CUED_SLACK_HELPER_BINARY; delete process.env.CUED_AUTH_NATIVE_BINARY; @@ -1535,10 +1534,6 @@ process.exit(44); it("refreshes signal and whatsapp managed states for every persisted account", async () => { installSecurityTool({}); - process.env.CUED_SIGNAL_CLI_PATH = join( - createTempDir("cued-missing-signal-cli-"), - "signal-cli", - ); process.env.CUED_WHATSAPP_HELPER_BINARY = join( createTempDir("cued-missing-whatsapp-helper-"), "cued-whatsapp-helper", diff --git a/src/platforms/core/types.ts b/src/platforms/core/types.ts index 43fdfc87..3372eddc 100644 --- a/src/platforms/core/types.ts +++ b/src/platforms/core/types.ts @@ -40,8 +40,6 @@ export type PlatformFeature = (typeof PLATFORM_FEATURE_VALUES)[number]; export const PLATFORM_FEATURE_SUPPORT_VALUES = ["yes", "partial", "no"] as const; export type PlatformFeatureSupport = (typeof PLATFORM_FEATURE_SUPPORT_VALUES)[number]; -export type PlatformFutureFeatureNotes = Record; - type PlatformDefinition = { adapter: boolean; defaultAccountKey: "default" | "local"; @@ -429,11 +427,6 @@ export function getPlatformFeatureMatrixRow( return PLATFORM_FEATURE_MATRIX[platform]; } -export function getPlatformFutureFeatureNotes(platform: Platform): PlatformFutureFeatureNotes { - void platform; - return {}; -} - export function isIntegrationAuthState(value: string): value is IntegrationAuthState { return integrationAuthStateSet.has(value); } diff --git a/src/runtime/daemon/server.ts b/src/runtime/daemon/server.ts index 85bd2271..b3025f2e 100644 --- a/src/runtime/daemon/server.ts +++ b/src/runtime/daemon/server.ts @@ -28,7 +28,7 @@ import { buildAdapterInvocationEnv, selectAdapterInvocationProofs, } from "../../platforms/core/invocation.js"; -import { isAdapterPlatform, listAutoSyncPlatforms } from "../../platforms/core/registry.js"; +import { isAdapterPlatform, listAdapterPlatforms } from "../../platforms/core/registry.js"; import { runAdapter } from "../../platforms/core/runner.js"; import { loadIntegrationSecret } from "../../platforms/core/secrets/keychain.js"; import { refreshLocalIntegrationStates } from "../../platforms/core/state/local-refresh.js"; @@ -419,7 +419,7 @@ export function getAutoSyncTargets( return []; } - return listAutoSyncPlatforms().map((platform) => ({ + return listAdapterPlatforms().map((platform) => ({ platform, accountKey: getDefaultAccountKeyForPlatform(platform), })); @@ -5264,12 +5264,7 @@ async function dispatchRequest( return { id: request.id, ok: true, - result: await db.withBusyTimeout(DAEMON_STATUS_BUSY_TIMEOUT_MS, () => - buildPermissionStatus({ - mode: "passive", - db, - }), - ), + result: await buildPermissionStatus(), }; case "onboarding-status": return { @@ -5292,7 +5287,6 @@ async function dispatchRequest( result: await db.withBusyTimeout(DAEMON_STATUS_BUSY_TIMEOUT_MS, () => buildOnboardingSnapshot(db, { refreshManagedIntegrations: request.refreshManagedIntegrations, - refreshPermissions: request.refreshPermissions, }), ), }; diff --git a/src/runtime/doctor-status.test.ts b/src/runtime/doctor-status.test.ts index 71bbcc4b..5e5ee5ec 100644 --- a/src/runtime/doctor-status.test.ts +++ b/src/runtime/doctor-status.test.ts @@ -20,7 +20,7 @@ import { buildPermissionStatus } from "./doctor.js"; const itDarwin = process.platform === "darwin" ? it : it.skip; -describe("permission status modes", () => { +describe("permission status", () => { const tempDirs: string[] = []; afterEach(() => { @@ -43,7 +43,7 @@ describe("permission status modes", () => { return db; } - itDarwin("omits removed permission checks in passive mode", async () => { + itDarwin("omits removed permission checks", async () => { const db = createDb(); process.env.CUED_CONTACTS_NATIVE_BINARY = "/tmp/cued-native-helper"; process.env.CUED_IMESSAGE_NATIVE_BINARY = "/tmp/cued-native-helper"; @@ -58,10 +58,7 @@ describe("permission status modes", () => { throw new Error(`unexpected command: ${command}`); }); - const status = await buildPermissionStatus({ - mode: "passive", - db, - }); + const status = await buildPermissionStatus(); expect(status.permissions.map((permission) => permission.key)).toEqual([ "contacts", diff --git a/src/runtime/doctor.ts b/src/runtime/doctor.ts index a109c8db..8915253c 100644 --- a/src/runtime/doctor.ts +++ b/src/runtime/doctor.ts @@ -72,13 +72,6 @@ export interface PermissionCheckSummaryInput { messagesNativeHelper: DoctorCheck; } -export type PermissionStatusMode = "active" | "passive"; - -export interface BuildPermissionStatusOptions { - mode?: PermissionStatusMode; - db?: CuedDatabase | null; -} - export function summarizePermissionStatuses( checks: PermissionCheckSummaryInput, ): PermissionStatusSummary[] { @@ -121,9 +114,7 @@ export function summarizePermissionStatuses( ]; } -export async function buildPermissionStatus( - _options: BuildPermissionStatusOptions = {}, -): Promise<{ permissions: PermissionStatusSummary[] }> { +export async function buildPermissionStatus(): Promise<{ permissions: PermissionStatusSummary[] }> { const contacts = process.platform === "darwin" ? getContactsPermissionCheck() diff --git a/src/runtime/ipc.ts b/src/runtime/ipc.ts index 63540e13..0e904d22 100644 --- a/src/runtime/ipc.ts +++ b/src/runtime/ipc.ts @@ -8,7 +8,6 @@ export type DaemonRequest = id: string; command: "onboarding-snapshot"; refreshManagedIntegrations?: boolean; - refreshPermissions?: boolean; } | { id: string; command: "permissions-status" } | { id: string; command: "sql"; query: string } diff --git a/src/runtime/onboarding-permissions.test.ts b/src/runtime/onboarding-permissions.test.ts index c5db368c..0ff3c48f 100644 --- a/src/runtime/onboarding-permissions.test.ts +++ b/src/runtime/onboarding-permissions.test.ts @@ -63,26 +63,12 @@ describe("onboarding permission refresh", () => { }); } - it("uses passive permission checks by default", async () => { + it("loads permission status for onboarding snapshots", async () => { mockSnapshotDependencies(); await buildOnboardingSnapshot(db as never); - expect(buildPermissionStatusMock).toHaveBeenCalledWith({ - mode: "passive", - db: db as never, - }); - }); - - it("can force a live permission refresh for onboarding snapshots", async () => { - mockSnapshotDependencies(); - - await buildOnboardingSnapshot(db as never, { refreshPermissions: true }); - - expect(buildPermissionStatusMock).toHaveBeenCalledWith({ - mode: "active", - db: db as never, - }); + expect(buildPermissionStatusMock).toHaveBeenCalledWith(); }); it("auto-installs the bundled skill when onboarding can resolve it", async () => { diff --git a/src/runtime/onboarding.ts b/src/runtime/onboarding.ts index f011de1d..a09d495e 100644 --- a/src/runtime/onboarding.ts +++ b/src/runtime/onboarding.ts @@ -28,7 +28,6 @@ export async function buildOnboardingSnapshot( db: CuedDatabase, options: { refreshManagedIntegrations?: boolean; - refreshPermissions?: boolean; installGlobalSkill?: boolean; } = {}, ): Promise { @@ -41,10 +40,7 @@ export async function buildOnboardingSnapshot( } } - const permissions = await buildPermissionStatus({ - mode: options.refreshPermissions ? "active" : "passive", - db, - }); + const permissions = await buildPermissionStatus(); permissions.permissions.push({ key: "diagnostics", status: isTelemetryEnabled(db) ? "granted" : "disabled",