Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
155 changes: 150 additions & 5 deletions src/lib/embedded-skills.ts
Original file line number Diff line number Diff line change
Expand Up @@ -458,30 +458,175 @@ Create or update documentation:

### iOS (Swift)

**Initialization Pattern:**
**SwiftUI App Pattern (simple initialization):**

\`\`\`swift
import SwiftUI
import Clix

@main
struct MyApp: App {
init() {
// Load credentials from your app configuration (do NOT hardcode).
// Example: store values in Info.plist keys.
let projectId = Bundle.main.object(forInfoDictionaryKey: "CLIX_PROJECT_ID") as? String ?? ""
let apiKey = Bundle.main.object(forInfoDictionaryKey: "CLIX_PUBLIC_API_KEY") as? String

let config = ClixConfig(projectId: projectId, apiKey: apiKey)
Clix.initialize(config: config)
}

var body: some Scene {
WindowGroup {
ContentView()
}
}
}
\`\`\`

**AppDelegate Pattern (RECOMMENDED for push notifications):**

For apps that need push notifications, use the AppDelegate pattern with full delegate methods:

\`\`\`swift
import UIKit
import UserNotifications
import Clix

@main
class AppDelegate: UIResponder, UIApplicationDelegate, UNUserNotificationCenterDelegate {

func application(_ application: UIApplication,
didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
// Initialize Clix SDK
let projectId = Bundle.main.object(forInfoDictionaryKey: "CLIX_PROJECT_ID") as? String ?? ""
let apiKey = Bundle.main.object(forInfoDictionaryKey: "CLIX_PUBLIC_API_KEY") as? String
let config = ClixConfig(projectId: projectId, apiKey: apiKey)
Clix.initialize(config: config)

// Set notification delegate
UNUserNotificationCenter.current().delegate = self

// Request push notification permission
UNUserNotificationCenter.current().requestAuthorization(options: [.alert, .badge, .sound]) { granted, error in
if granted {
DispatchQueue.main.async {
application.registerForRemoteNotifications()
}
}
}

return true
}

// MARK: - Push Token Registration

func application(_ application: UIApplication,
didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) {
// Pass the device token to Clix for push notification delivery
Clix.setPushToken(deviceToken)
}

func application(_ application: UIApplication,
didFailToRegisterForRemoteNotificationsWithError error: Error) {
print("Failed to register for push notifications: \\(error)")
}

// MARK: - UNUserNotificationCenterDelegate

// Handle foreground notifications - show banner even when app is active
func userNotificationCenter(_ center: UNUserNotificationCenter,
willPresent notification: UNNotification,
withCompletionHandler completionHandler: @escaping (UNNotificationPresentationOptions) -> Void) {
completionHandler([.banner, .sound, .badge])
}

// Handle notification tap - track engagement and process deep links
func userNotificationCenter(_ center: UNUserNotificationCenter,
didReceive response: UNNotificationResponse,
withCompletionHandler completionHandler: @escaping () -> Void) {
Clix.handleNotificationResponse(response)
completionHandler()
}
}
\`\`\`

**SwiftUI App with AppDelegate (hybrid pattern):**

For SwiftUI apps that need push notification handling:

\`\`\`swift
import SwiftUI
import UserNotifications
import Clix

class AppDelegate: NSObject, UIApplicationDelegate, UNUserNotificationCenterDelegate {
func application(_ application: UIApplication,
didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
// Initialize Clix SDK
let projectId = Bundle.main.object(forInfoDictionaryKey: "CLIX_PROJECT_ID") as? String ?? ""
let apiKey = Bundle.main.object(forInfoDictionaryKey: "CLIX_PUBLIC_API_KEY") as? String
let config = ClixConfig(projectId: projectId, apiKey: apiKey)
Clix.initialize(config: config)

// Set notification delegate
UNUserNotificationCenter.current().delegate = self

// Request push notification permission
UNUserNotificationCenter.current().requestAuthorization(options: [.alert, .badge, .sound]) { granted, error in
if granted {
DispatchQueue.main.async {
application.registerForRemoteNotifications()
}
}
}

return true
}

func application(_ application: UIApplication,
didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) {
Clix.setPushToken(deviceToken)
}

func application(_ application: UIApplication,
didFailToRegisterForRemoteNotificationsWithError error: Error) {
print("Failed to register for push notifications: \\(error)")
}

func userNotificationCenter(_ center: UNUserNotificationCenter,
willPresent notification: UNNotification,
withCompletionHandler completionHandler: @escaping (UNNotificationPresentationOptions) -> Void) {
completionHandler([.banner, .sound, .badge])
}

func userNotificationCenter(_ center: UNUserNotificationCenter,
didReceive response: UNNotificationResponse,
withCompletionHandler completionHandler: @escaping () -> Void) {
Clix.handleNotificationResponse(response)
completionHandler()
}
}

@main
struct MyApp: App {
@UIApplicationDelegateAdaptor(AppDelegate.self) var appDelegate

var body: some Scene {
WindowGroup {
ContentView()
}
}
}
\`\`\`

**Key Points:**

- Initialize in \`@main\` app struct or \`AppDelegate\`
- Use environment variables, never hardcode
- Handle optional API key for analytics-only mode
- For push notifications, use the AppDelegate pattern (not just SwiftUI \`init\`)
- Set \`UNUserNotificationCenter.current().delegate = self\` before registering
- Implement all delegate methods: \`didRegisterForRemoteNotificationsWithDeviceToken\`, \`willPresent\`, \`didReceive\`
- Call \`Clix.setPushToken(deviceToken)\` in the token registration callback
- Call \`Clix.handleNotificationResponse(response)\` when notification is tapped
- Use environment variables (Info.plist), never hardcode credentials

### Android (Kotlin)

Expand Down
51 changes: 35 additions & 16 deletions src/lib/skills.ts
Original file line number Diff line number Diff line change
Expand Up @@ -185,24 +185,43 @@ COMPLETION CRITERIA:

/**
* Interactive mode instruction for Guided Interactive Workflow.
* Instructs the agent to follow the Confirm → Propose → Validate → Implement → Verify pattern.
* Instructs the agent to be proactive about automatable tasks while asking for confirmation when needed.
*/
const INTERACTIVE_MODE_INSTRUCTION = `
IMPORTANT: This is an interactive conversation session. Follow the Guided Interactive Workflow.

EXECUTION GUIDELINES:
- ALWAYS follow the workflow steps in order: Confirm → Propose → Validate → Implement → Verify
- DO NOT skip to implementation without completing earlier steps
- ASK for required inputs before proceeding (platform, goals, preferences)
- PROPOSE your plan and wait for user approval before making changes
- NEVER modify files without explicit user confirmation
- If information is missing, ASK the user rather than assuming

WORKFLOW ENFORCEMENT:
- Start by confirming the minimum required inputs from the user
- Present your proposed plan for review
- Only proceed to implementation after the user approves the plan
- Validate before implementing, verify after implementing
IMPORTANT: This is an interactive conversation session.

AUTOMATION GUIDELINES:
Distinguish between what CAN and CANNOT be automated:

**CAN AUTOMATE (use Write/Edit tools immediately without asking):**
- Creating new files (configuration files, source code, entitlements)
- Modifying existing source code (adding initialization code, imports, delegate methods)
- Updating config files (Podfile, package.json, build.gradle, pubspec.yaml)
- Creating extension files (NotificationService.swift, Info.plist, entitlements)
- Running installation commands (pod install, npm install, flutter pub get)

**CANNOT AUTOMATE (provide clear instructions):**
- Xcode UI actions (File > New > Target, Signing & Capabilities)
- Apple Developer Portal configuration (App IDs, certificates, provisioning profiles)
- IDE-specific settings (Build Settings, linking entitlements)
- Android Studio capability configuration

EXECUTION WORKFLOW:
1. Analyze the project and detect platform/configuration
2. For automatable tasks: DO THEM DIRECTLY using Write/Edit/Bash tools
3. For non-automatable tasks: Provide clear step-by-step instructions
4. Verify the integration and report what was done

ASK FOR CONFIRMATION ONLY WHEN:
- Multiple valid implementation approaches exist (user preference matters)
- Destructive changes are needed (deleting files, overwriting significant code)
- Critical decisions require user input (which package manager to use)

DO NOT ASK FOR CONFIRMATION FOR:
- Standard file creation/modification (always proceed)
- Adding initialization code to entry points
- Creating configuration files
- Running standard installation commands
`;

/**
Expand Down
Loading