@elizaos/capacitor-eliza-tasks 2.0.11-beta.7

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.
@@ -0,0 +1,19 @@
1
+ require 'json'
2
+
3
+ package = JSON.parse(File.read(File.join(__dir__, 'package.json')))
4
+
5
+ Pod::Spec.new do |s|
6
+ s.name = 'ElizaosCapacitorElizaTasks'
7
+ s.version = package['version']
8
+ s.summary = package['description']
9
+ s.license = package['license'] || { :type => 'MIT' }
10
+ s.homepage = 'https://elizaos.ai'
11
+ s.authors = { 'elizaOS' => 'dev@elizaos.ai' }
12
+ s.source = { :git => 'https://github.com/elizaOS/eliza.git', :tag => s.version.to_s }
13
+ s.source_files = 'ios/Sources/**/*.{swift,h,m}'
14
+ s.ios.deployment_target = '15.0'
15
+ s.dependency 'Capacitor'
16
+ s.swift_version = '5.9'
17
+ # BackgroundTasks ships in the iOS SDK; only the framework needs declaring.
18
+ s.frameworks = 'UIKit', 'BackgroundTasks', 'UserNotifications'
19
+ end
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Shaw Walters and elizaOS Contributors
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,116 @@
1
+ # @elizaos/capacitor-eliza-tasks
2
+
3
+ Capacitor plugin that bridges iOS `BGTaskScheduler` background-wake events into the elizaOS Capacitor runtime.
4
+
5
+ ## What it does
6
+
7
+ iOS suspends apps when they leave the foreground. This plugin registers two background task identifiers with `BGTaskScheduler` so the elizaOS iOS app can be woken by the OS on a schedule:
8
+
9
+ - **`BGAppRefreshTask`** (`ai.eliza.tasks.refresh`) — short wake (~25s budget), network available. Used for polling the agent's loopback `/api/internal/wake` route.
10
+ - **`BGProcessingTask`** (`ai.eliza.tasks.processing`) — long-running wake (~120s budget), requires device to be charging and idle. Used for local-LLM warmup passes.
11
+ - **Silent APNs push** (`remote-push`) — optional; gated on `ELIZA_APNS_ENABLED` in `Info.plist`. Forwarded through `AppDelegate` via `ElizaCompanionRemotePush` `NSNotification`.
12
+
13
+ All three wake paths emit the same `wake` event to the JS layer, so a single handler can drain them:
14
+
15
+ ```ts
16
+ import { ElizaTasks } from "@elizaos/capacitor-eliza-tasks";
17
+
18
+ await ElizaTasks.addListener("wake", (event) => {
19
+ console.log(event.kind, event.deadlineSec, event.firedAtMs);
20
+ // event.kind: "refresh" | "processing" | "remote-push"
21
+ });
22
+
23
+ // Arm the first wake
24
+ await ElizaTasks.scheduleNext({ earliestBeginSec: 900 });
25
+ ```
26
+
27
+ On web and non-iOS platforms the plugin returns `supported: false`; scheduling reports no iOS wake path, and cancellation reports that no web wake requests were cancelled. The app should call `getStatus()` and fall back to `@capacitor/background-runner` polling when `supported` is false.
28
+
29
+ ## Installation
30
+
31
+ ```bash
32
+ npm install @elizaos/capacitor-eliza-tasks
33
+ npx cap sync
34
+ ```
35
+
36
+ ### iOS setup
37
+
38
+ Add both identifiers to `Info.plist`:
39
+
40
+ ```xml
41
+ <key>BGTaskSchedulerPermittedIdentifiers</key>
42
+ <array>
43
+ <string>ai.eliza.tasks.refresh</string>
44
+ <string>ai.eliza.tasks.processing</string>
45
+ </array>
46
+ ```
47
+
48
+ For silent-push support also add:
49
+
50
+ ```xml
51
+ <key>ELIZA_APNS_ENABLED</key>
52
+ <string>1</string>
53
+ ```
54
+
55
+ And enable the **Background Modes** capability in Xcode: check `Background fetch` and `Remote notifications`.
56
+
57
+ ## API
58
+
59
+ ### `scheduleNext(options?)`
60
+
61
+ Enqueues the next `BGAppRefreshTask`. Idempotent — replaces any pending request.
62
+
63
+ ```ts
64
+ interface ElizaTasksScheduleOptions {
65
+ earliestBeginSec?: number; // default 900 (15 min), floor 1
66
+ alsoProcessing?: boolean; // also schedule a BGProcessingTask
67
+ }
68
+ ```
69
+
70
+ Returns `ElizaTasksScheduleResult` with `{ scheduled, identifier, earliestBeginAtMs, reason }`.
71
+
72
+ ### `getStatus()`
73
+
74
+ Returns the plugin's view of `BGTaskScheduler` state:
75
+
76
+ ```ts
77
+ interface ElizaTasksStatus {
78
+ supported: boolean;
79
+ platform: "ios" | "android" | "web";
80
+ refreshScheduled: boolean;
81
+ processingScheduled: boolean;
82
+ lastWakeFiredAtMs: number | null;
83
+ lastWakeKind: ElizaTaskKind | null;
84
+ reason: string | null;
85
+ }
86
+ ```
87
+
88
+ ### `cancelAll()`
89
+
90
+ Cancels all pending refresh and processing task requests.
91
+
92
+ ### `addListener("wake", fn)`
93
+
94
+ Registers a listener for `ElizaTasksWakeEvent`:
95
+
96
+ ```ts
97
+ interface ElizaTasksWakeEvent {
98
+ kind: "refresh" | "processing" | "remote-push";
99
+ identifier: string;
100
+ deadlineSec: number;
101
+ firedAtMs: number;
102
+ payload: Record<string, unknown>;
103
+ }
104
+ ```
105
+
106
+ ### `removeAllListeners()`
107
+
108
+ Removes all `wake` listeners.
109
+
110
+ ## Platform support
111
+
112
+ | Platform | Support |
113
+ |---|---|
114
+ | iOS 15+ | Full — `BGTaskScheduler` + optional APNs |
115
+ | Android | Unsupported in this iOS BGTaskScheduler bridge |
116
+ | Web / Electron | Unsupported fallback (`supported: false`) |
@@ -0,0 +1,84 @@
1
+ import type { PluginListenerHandle } from "@capacitor/core";
2
+ /**
3
+ * Background task kinds the native plugin can wake the JS layer with.
4
+ *
5
+ * - `refresh` → iOS `BGAppRefreshTaskRequest` — short (~30s), network-OK
6
+ * foreground-equivalent wake. Used for the polling poke
7
+ * against `/api/internal/wake`.
8
+ * - `processing` → iOS `BGProcessingTaskRequest` — long-running (~minutes),
9
+ * runs while the device is charging and idle. Used for the
10
+ * local-LLM warmup pass that has no time pressure.
11
+ * - `remote-push` → silent APNs `content-available:1` push (gated on
12
+ * `ELIZA_APNS_ENABLED` in Info.plist). Mirrors the BG-task
13
+ * contract so the JS side can treat all three uniformly.
14
+ */
15
+ export type ElizaTaskKind = "refresh" | "processing" | "remote-push";
16
+ export type ElizaTaskIdentifier = "ai.eliza.tasks.refresh" | "ai.eliza.tasks.processing";
17
+ /**
18
+ * Wake event delivered to JS listeners. Mirrors the `addEventListener("wake")`
19
+ * contract in `runners/eliza-tasks.js` so the BackgroundRunner runner and the
20
+ * BGTaskScheduler-driven runner share one client-side handler.
21
+ */
22
+ export interface ElizaTasksWakeEvent {
23
+ kind: ElizaTaskKind;
24
+ identifier: ElizaTaskIdentifier | "ai.eliza.tasks.remote-push";
25
+ deadlineSec: number;
26
+ /** When the OS dispatched the wake (epoch ms). */
27
+ firedAtMs: number;
28
+ /**
29
+ * For `remote-push`, the raw `userInfo` from APNs (minus `aps`). For
30
+ * BGTaskScheduler wakes, an empty object — wake-time payload lives in the
31
+ * agent's loopback HTTP route.
32
+ */
33
+ payload: Record<string, unknown>;
34
+ }
35
+ export interface ElizaTasksScheduleOptions {
36
+ /**
37
+ * Earliest begin date for the next wake, expressed as seconds from now.
38
+ * `BGTaskScheduler` treats this as a hint — the OS controls the actual
39
+ * dispatch time. Must be ≥ 1.
40
+ */
41
+ earliestBeginSec?: number;
42
+ /**
43
+ * If true, also enqueue the long-running BGProcessingTask. The processing
44
+ * variant only fires while the device is charging and idle.
45
+ */
46
+ alsoProcessing?: boolean;
47
+ }
48
+ export interface ElizaTasksScheduleResult {
49
+ scheduled: boolean;
50
+ identifier: ElizaTaskIdentifier;
51
+ earliestBeginAtMs: number | null;
52
+ reason: string | null;
53
+ }
54
+ export interface ElizaTasksStatus {
55
+ supported: boolean;
56
+ platform: "ios" | "android" | "web";
57
+ refreshScheduled: boolean;
58
+ processingScheduled: boolean;
59
+ lastWakeFiredAtMs: number | null;
60
+ lastWakeKind: ElizaTaskKind | null;
61
+ reason: string | null;
62
+ }
63
+ export interface ElizaTasksPlugin {
64
+ /**
65
+ * Enqueue the next BG refresh wake. Idempotent — calling repeatedly
66
+ * replaces the pending request rather than stacking.
67
+ */
68
+ scheduleNext(options?: ElizaTasksScheduleOptions): Promise<ElizaTasksScheduleResult>;
69
+ /**
70
+ * Snapshot of the plugin's view of BGTaskScheduler state. Used by the JS
71
+ * layer to decide whether to fall back to the BackgroundRunner repeat poll.
72
+ */
73
+ getStatus(): Promise<ElizaTasksStatus>;
74
+ /**
75
+ * Cancel any pending refresh + processing requests. Used during the
76
+ * `disable mobile background tasks` flow.
77
+ */
78
+ cancelAll(): Promise<{
79
+ cancelled: boolean;
80
+ }>;
81
+ addListener(eventName: "wake", listenerFunc: (event: ElizaTasksWakeEvent) => void): Promise<PluginListenerHandle>;
82
+ removeAllListeners(): Promise<void>;
83
+ }
84
+ //# sourceMappingURL=definitions.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"definitions.d.ts","sourceRoot":"","sources":["../../src/definitions.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,iBAAiB,CAAC;AAE5D;;;;;;;;;;;;GAYG;AACH,MAAM,MAAM,aAAa,GAAG,SAAS,GAAG,YAAY,GAAG,aAAa,CAAC;AAErE,MAAM,MAAM,mBAAmB,GAC3B,wBAAwB,GACxB,2BAA2B,CAAC;AAEhC;;;;GAIG;AACH,MAAM,WAAW,mBAAmB;IAClC,IAAI,EAAE,aAAa,CAAC;IACpB,UAAU,EAAE,mBAAmB,GAAG,4BAA4B,CAAC;IAC/D,WAAW,EAAE,MAAM,CAAC;IACpB,kDAAkD;IAClD,SAAS,EAAE,MAAM,CAAC;IAClB;;;;OAIG;IACH,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CAClC;AAED,MAAM,WAAW,yBAAyB;IACxC;;;;OAIG;IACH,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B;;;OAGG;IACH,cAAc,CAAC,EAAE,OAAO,CAAC;CAC1B;AAED,MAAM,WAAW,wBAAwB;IACvC,SAAS,EAAE,OAAO,CAAC;IACnB,UAAU,EAAE,mBAAmB,CAAC;IAChC,iBAAiB,EAAE,MAAM,GAAG,IAAI,CAAC;IACjC,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;CACvB;AAED,MAAM,WAAW,gBAAgB;IAC/B,SAAS,EAAE,OAAO,CAAC;IACnB,QAAQ,EAAE,KAAK,GAAG,SAAS,GAAG,KAAK,CAAC;IACpC,gBAAgB,EAAE,OAAO,CAAC;IAC1B,mBAAmB,EAAE,OAAO,CAAC;IAC7B,iBAAiB,EAAE,MAAM,GAAG,IAAI,CAAC;IACjC,YAAY,EAAE,aAAa,GAAG,IAAI,CAAC;IACnC,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;CACvB;AAED,MAAM,WAAW,gBAAgB;IAC/B;;;OAGG;IACH,YAAY,CACV,OAAO,CAAC,EAAE,yBAAyB,GAClC,OAAO,CAAC,wBAAwB,CAAC,CAAC;IAErC;;;OAGG;IACH,SAAS,IAAI,OAAO,CAAC,gBAAgB,CAAC,CAAC;IAEvC;;;OAGG;IACH,SAAS,IAAI,OAAO,CAAC;QAAE,SAAS,EAAE,OAAO,CAAA;KAAE,CAAC,CAAC;IAE7C,WAAW,CACT,SAAS,EAAE,MAAM,EACjB,YAAY,EAAE,CAAC,KAAK,EAAE,mBAAmB,KAAK,IAAI,GACjD,OAAO,CAAC,oBAAoB,CAAC,CAAC;IAEjC,kBAAkB,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;CACrC"}
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,4 @@
1
+ import type { ElizaTasksPlugin } from "./definitions";
2
+ export * from "./definitions";
3
+ export declare const ElizaTasks: ElizaTasksPlugin;
4
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,eAAe,CAAC;AAEtD,cAAc,eAAe,CAAC;AAI9B,eAAO,MAAM,UAAU,kBAErB,CAAC"}
@@ -0,0 +1,6 @@
1
+ import { registerPlugin } from "@capacitor/core";
2
+ export * from "./definitions";
3
+ const loadWeb = () => import("./web").then((m) => new m.ElizaTasksWeb());
4
+ export const ElizaTasks = registerPlugin("ElizaTasks", {
5
+ web: loadWeb,
6
+ });
@@ -0,0 +1,17 @@
1
+ import { WebPlugin } from "@capacitor/core";
2
+ import type { ElizaTasksPlugin, ElizaTasksScheduleOptions, ElizaTasksScheduleResult, ElizaTasksStatus } from "./definitions";
3
+ /**
4
+ * Web fallback for the ElizaTasks plugin.
5
+ *
6
+ * Browsers have no `BGTaskScheduler` equivalent. The plugin resolves to a
7
+ * `supported: false` status so the runtime knows to fall back to the
8
+ * BackgroundRunner repeat poll (already configured in `capacitor.config.ts`).
9
+ */
10
+ export declare class ElizaTasksWeb extends WebPlugin implements ElizaTasksPlugin {
11
+ scheduleNext(_options?: ElizaTasksScheduleOptions): Promise<ElizaTasksScheduleResult>;
12
+ getStatus(): Promise<ElizaTasksStatus>;
13
+ cancelAll(): Promise<{
14
+ cancelled: boolean;
15
+ }>;
16
+ }
17
+ //# sourceMappingURL=web.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"web.d.ts","sourceRoot":"","sources":["../../src/web.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAC5C,OAAO,KAAK,EACV,gBAAgB,EAChB,yBAAyB,EACzB,wBAAwB,EACxB,gBAAgB,EACjB,MAAM,eAAe,CAAC;AAEvB;;;;;;GAMG;AACH,qBAAa,aAAc,SAAQ,SAAU,YAAW,gBAAgB;IACtE,YAAY,CACV,QAAQ,CAAC,EAAE,yBAAyB,GACnC,OAAO,CAAC,wBAAwB,CAAC;IASpC,SAAS,IAAI,OAAO,CAAC,gBAAgB,CAAC;IAYtC,SAAS,IAAI,OAAO,CAAC;QAAE,SAAS,EAAE,OAAO,CAAA;KAAE,CAAC;CAG7C"}
@@ -0,0 +1,32 @@
1
+ import { WebPlugin } from "@capacitor/core";
2
+ /**
3
+ * Web fallback for the ElizaTasks plugin.
4
+ *
5
+ * Browsers have no `BGTaskScheduler` equivalent. The plugin resolves to a
6
+ * `supported: false` status so the runtime knows to fall back to the
7
+ * BackgroundRunner repeat poll (already configured in `capacitor.config.ts`).
8
+ */
9
+ export class ElizaTasksWeb extends WebPlugin {
10
+ scheduleNext(_options) {
11
+ return Promise.resolve({
12
+ scheduled: false,
13
+ identifier: "ai.eliza.tasks.refresh",
14
+ earliestBeginAtMs: null,
15
+ reason: "BGTaskScheduler is iOS-only; web has no background wake path.",
16
+ });
17
+ }
18
+ getStatus() {
19
+ return Promise.resolve({
20
+ supported: false,
21
+ platform: "web",
22
+ refreshScheduled: false,
23
+ processingScheduled: false,
24
+ lastWakeFiredAtMs: null,
25
+ lastWakeKind: null,
26
+ reason: "BGTaskScheduler is iOS-only; web has no background wake path.",
27
+ });
28
+ }
29
+ cancelAll() {
30
+ return Promise.resolve({ cancelled: false });
31
+ }
32
+ }
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=web.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"web.test.d.ts","sourceRoot":"","sources":["../../src/web.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,34 @@
1
+ import { describe, expect, it } from "vitest";
2
+ import { ElizaTasksWeb } from "./web";
3
+ describe("ElizaTasksWeb fallback", () => {
4
+ it("reports the browser as unsupported without throwing", async () => {
5
+ await expect(new ElizaTasksWeb().getStatus()).resolves.toEqual({
6
+ supported: false,
7
+ platform: "web",
8
+ refreshScheduled: false,
9
+ processingScheduled: false,
10
+ lastWakeFiredAtMs: null,
11
+ lastWakeKind: null,
12
+ reason: "BGTaskScheduler is iOS-only; web has no background wake path.",
13
+ });
14
+ });
15
+ it.each([
16
+ undefined,
17
+ {},
18
+ { earliestBeginSec: Number.NaN, alsoProcessing: true },
19
+ { earliestBeginSec: Number.POSITIVE_INFINITY, alsoProcessing: true },
20
+ { earliestBeginSec: -1, alsoProcessing: true },
21
+ ])("ignores schedule options on web %#", async (options) => {
22
+ await expect(new ElizaTasksWeb().scheduleNext(options)).resolves.toEqual({
23
+ scheduled: false,
24
+ identifier: "ai.eliza.tasks.refresh",
25
+ earliestBeginAtMs: null,
26
+ reason: "BGTaskScheduler is iOS-only; web has no background wake path.",
27
+ });
28
+ });
29
+ it("cancelAll reports that no web wake requests were cancelled", async () => {
30
+ await expect(new ElizaTasksWeb().cancelAll()).resolves.toEqual({
31
+ cancelled: false,
32
+ });
33
+ });
34
+ });
@@ -0,0 +1,48 @@
1
+ 'use strict';
2
+
3
+ var core = require('@capacitor/core');
4
+
5
+ const loadWeb = () => Promise.resolve().then(function () { return web; }).then((m) => new m.ElizaTasksWeb());
6
+ const ElizaTasks = core.registerPlugin("ElizaTasks", {
7
+ web: loadWeb,
8
+ });
9
+
10
+ /**
11
+ * Web fallback for the ElizaTasks plugin.
12
+ *
13
+ * Browsers have no `BGTaskScheduler` equivalent. The plugin resolves to a
14
+ * `supported: false` status so the runtime knows to fall back to the
15
+ * BackgroundRunner repeat poll (already configured in `capacitor.config.ts`).
16
+ */
17
+ class ElizaTasksWeb extends core.WebPlugin {
18
+ scheduleNext(_options) {
19
+ return Promise.resolve({
20
+ scheduled: false,
21
+ identifier: "ai.eliza.tasks.refresh",
22
+ earliestBeginAtMs: null,
23
+ reason: "BGTaskScheduler is iOS-only; web has no background wake path.",
24
+ });
25
+ }
26
+ getStatus() {
27
+ return Promise.resolve({
28
+ supported: false,
29
+ platform: "web",
30
+ refreshScheduled: false,
31
+ processingScheduled: false,
32
+ lastWakeFiredAtMs: null,
33
+ lastWakeKind: null,
34
+ reason: "BGTaskScheduler is iOS-only; web has no background wake path.",
35
+ });
36
+ }
37
+ cancelAll() {
38
+ return Promise.resolve({ cancelled: false });
39
+ }
40
+ }
41
+
42
+ var web = /*#__PURE__*/Object.freeze({
43
+ __proto__: null,
44
+ ElizaTasksWeb: ElizaTasksWeb
45
+ });
46
+
47
+ exports.ElizaTasks = ElizaTasks;
48
+ //# sourceMappingURL=plugin.cjs.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"plugin.cjs.js","sources":["esm/index.js","esm/web.js"],"sourcesContent":["import { registerPlugin } from \"@capacitor/core\";\nexport * from \"./definitions\";\nconst loadWeb = () => import(\"./web\").then((m) => new m.ElizaTasksWeb());\nexport const ElizaTasks = registerPlugin(\"ElizaTasks\", {\n web: loadWeb,\n});\n","import { WebPlugin } from \"@capacitor/core\";\n/**\n * Web fallback for the ElizaTasks plugin.\n *\n * Browsers have no `BGTaskScheduler` equivalent. The plugin resolves to a\n * `supported: false` status so the runtime knows to fall back to the\n * BackgroundRunner repeat poll (already configured in `capacitor.config.ts`).\n */\nexport class ElizaTasksWeb extends WebPlugin {\n scheduleNext(_options) {\n return Promise.resolve({\n scheduled: false,\n identifier: \"ai.eliza.tasks.refresh\",\n earliestBeginAtMs: null,\n reason: \"BGTaskScheduler is iOS-only; web has no background wake path.\",\n });\n }\n getStatus() {\n return Promise.resolve({\n supported: false,\n platform: \"web\",\n refreshScheduled: false,\n processingScheduled: false,\n lastWakeFiredAtMs: null,\n lastWakeKind: null,\n reason: \"BGTaskScheduler is iOS-only; web has no background wake path.\",\n });\n }\n cancelAll() {\n return Promise.resolve({ cancelled: false });\n }\n}\n"],"names":["registerPlugin","WebPlugin"],"mappings":";;;;AAEA,MAAM,OAAO,GAAG,MAAM,mDAAe,CAAC,IAAI,CAAC,CAAC,CAAC,KAAK,IAAI,CAAC,CAAC,aAAa,EAAE,CAAC;AAC5D,MAAC,UAAU,GAAGA,mBAAc,CAAC,YAAY,EAAE;AACvD,IAAI,GAAG,EAAE,OAAO;AAChB,CAAC;;ACJD;AACA;AACA;AACA;AACA;AACA;AACA;AACO,MAAM,aAAa,SAASC,cAAS,CAAC;AAC7C,IAAI,YAAY,CAAC,QAAQ,EAAE;AAC3B,QAAQ,OAAO,OAAO,CAAC,OAAO,CAAC;AAC/B,YAAY,SAAS,EAAE,KAAK;AAC5B,YAAY,UAAU,EAAE,wBAAwB;AAChD,YAAY,iBAAiB,EAAE,IAAI;AACnC,YAAY,MAAM,EAAE,+DAA+D;AACnF,SAAS,CAAC;AACV,IAAI;AACJ,IAAI,SAAS,GAAG;AAChB,QAAQ,OAAO,OAAO,CAAC,OAAO,CAAC;AAC/B,YAAY,SAAS,EAAE,KAAK;AAC5B,YAAY,QAAQ,EAAE,KAAK;AAC3B,YAAY,gBAAgB,EAAE,KAAK;AACnC,YAAY,mBAAmB,EAAE,KAAK;AACtC,YAAY,iBAAiB,EAAE,IAAI;AACnC,YAAY,YAAY,EAAE,IAAI;AAC9B,YAAY,MAAM,EAAE,+DAA+D;AACnF,SAAS,CAAC;AACV,IAAI;AACJ,IAAI,SAAS,GAAG;AAChB,QAAQ,OAAO,OAAO,CAAC,OAAO,CAAC,EAAE,SAAS,EAAE,KAAK,EAAE,CAAC;AACpD,IAAI;AACJ;;;;;;;;;"}
package/dist/plugin.js ADDED
@@ -0,0 +1,51 @@
1
+ var capacitorElizaTasks = (function (exports, core) {
2
+ 'use strict';
3
+
4
+ const loadWeb = () => Promise.resolve().then(function () { return web; }).then((m) => new m.ElizaTasksWeb());
5
+ const ElizaTasks = core.registerPlugin("ElizaTasks", {
6
+ web: loadWeb,
7
+ });
8
+
9
+ /**
10
+ * Web fallback for the ElizaTasks plugin.
11
+ *
12
+ * Browsers have no `BGTaskScheduler` equivalent. The plugin resolves to a
13
+ * `supported: false` status so the runtime knows to fall back to the
14
+ * BackgroundRunner repeat poll (already configured in `capacitor.config.ts`).
15
+ */
16
+ class ElizaTasksWeb extends core.WebPlugin {
17
+ scheduleNext(_options) {
18
+ return Promise.resolve({
19
+ scheduled: false,
20
+ identifier: "ai.eliza.tasks.refresh",
21
+ earliestBeginAtMs: null,
22
+ reason: "BGTaskScheduler is iOS-only; web has no background wake path.",
23
+ });
24
+ }
25
+ getStatus() {
26
+ return Promise.resolve({
27
+ supported: false,
28
+ platform: "web",
29
+ refreshScheduled: false,
30
+ processingScheduled: false,
31
+ lastWakeFiredAtMs: null,
32
+ lastWakeKind: null,
33
+ reason: "BGTaskScheduler is iOS-only; web has no background wake path.",
34
+ });
35
+ }
36
+ cancelAll() {
37
+ return Promise.resolve({ cancelled: false });
38
+ }
39
+ }
40
+
41
+ var web = /*#__PURE__*/Object.freeze({
42
+ __proto__: null,
43
+ ElizaTasksWeb: ElizaTasksWeb
44
+ });
45
+
46
+ exports.ElizaTasks = ElizaTasks;
47
+
48
+ return exports;
49
+
50
+ })({}, capacitorExports);
51
+ //# sourceMappingURL=plugin.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"plugin.js","sources":["esm/index.js","esm/web.js"],"sourcesContent":["import { registerPlugin } from \"@capacitor/core\";\nexport * from \"./definitions\";\nconst loadWeb = () => import(\"./web\").then((m) => new m.ElizaTasksWeb());\nexport const ElizaTasks = registerPlugin(\"ElizaTasks\", {\n web: loadWeb,\n});\n","import { WebPlugin } from \"@capacitor/core\";\n/**\n * Web fallback for the ElizaTasks plugin.\n *\n * Browsers have no `BGTaskScheduler` equivalent. The plugin resolves to a\n * `supported: false` status so the runtime knows to fall back to the\n * BackgroundRunner repeat poll (already configured in `capacitor.config.ts`).\n */\nexport class ElizaTasksWeb extends WebPlugin {\n scheduleNext(_options) {\n return Promise.resolve({\n scheduled: false,\n identifier: \"ai.eliza.tasks.refresh\",\n earliestBeginAtMs: null,\n reason: \"BGTaskScheduler is iOS-only; web has no background wake path.\",\n });\n }\n getStatus() {\n return Promise.resolve({\n supported: false,\n platform: \"web\",\n refreshScheduled: false,\n processingScheduled: false,\n lastWakeFiredAtMs: null,\n lastWakeKind: null,\n reason: \"BGTaskScheduler is iOS-only; web has no background wake path.\",\n });\n }\n cancelAll() {\n return Promise.resolve({ cancelled: false });\n }\n}\n"],"names":["registerPlugin","WebPlugin"],"mappings":";;;IAEA,MAAM,OAAO,GAAG,MAAM,mDAAe,CAAC,IAAI,CAAC,CAAC,CAAC,KAAK,IAAI,CAAC,CAAC,aAAa,EAAE,CAAC;AAC5D,UAAC,UAAU,GAAGA,mBAAc,CAAC,YAAY,EAAE;IACvD,IAAI,GAAG,EAAE,OAAO;IAChB,CAAC;;ICJD;IACA;IACA;IACA;IACA;IACA;IACA;IACO,MAAM,aAAa,SAASC,cAAS,CAAC;IAC7C,IAAI,YAAY,CAAC,QAAQ,EAAE;IAC3B,QAAQ,OAAO,OAAO,CAAC,OAAO,CAAC;IAC/B,YAAY,SAAS,EAAE,KAAK;IAC5B,YAAY,UAAU,EAAE,wBAAwB;IAChD,YAAY,iBAAiB,EAAE,IAAI;IACnC,YAAY,MAAM,EAAE,+DAA+D;IACnF,SAAS,CAAC;IACV,IAAI;IACJ,IAAI,SAAS,GAAG;IAChB,QAAQ,OAAO,OAAO,CAAC,OAAO,CAAC;IAC/B,YAAY,SAAS,EAAE,KAAK;IAC5B,YAAY,QAAQ,EAAE,KAAK;IAC3B,YAAY,gBAAgB,EAAE,KAAK;IACnC,YAAY,mBAAmB,EAAE,KAAK;IACtC,YAAY,iBAAiB,EAAE,IAAI;IACnC,YAAY,YAAY,EAAE,IAAI;IAC9B,YAAY,MAAM,EAAE,+DAA+D;IACnF,SAAS,CAAC;IACV,IAAI;IACJ,IAAI,SAAS,GAAG;IAChB,QAAQ,OAAO,OAAO,CAAC,OAAO,CAAC,EAAE,SAAS,EAAE,KAAK,EAAE,CAAC;IACpD,IAAI;IACJ;;;;;;;;;;;;;;;"}
@@ -0,0 +1,326 @@
1
+ import BackgroundTasks
2
+ import Capacitor
3
+ import Foundation
4
+ import UIKit
5
+ import UserNotifications
6
+
7
+ /// ElizaTasksPlugin — Capacitor bridge for iOS `BGTaskScheduler`.
8
+ ///
9
+ /// Registers two namespaced identifiers in `BGTaskScheduler.shared.register`:
10
+ ///
11
+ /// - `ai.eliza.tasks.refresh` → `BGAppRefreshTask` (≤ ~30s, network-OK)
12
+ /// - `ai.eliza.tasks.processing` → `BGProcessingTask` (long-running,
13
+ /// requires charger, no network)
14
+ ///
15
+ /// On wake, the plugin emits a `wake` event to the JS layer carrying
16
+ /// `{kind, identifier, deadlineSec, firedAtMs, payload}`. The Wave 3D JS
17
+ /// runner under `runners/eliza-tasks.js` consumes the same event shape from
18
+ /// the `@capacitor/background-runner` repeat poll, so the JS-side handler is
19
+ /// shared between the two wake paths.
20
+ ///
21
+ /// Silent-push wake (`remote-notification` UIBackgroundMode) is plumbed
22
+ /// through `AppDelegate.application:didReceiveRemoteNotification:` which
23
+ /// posts an `ElizaCompanionRemotePush` `NSNotification`. This plugin
24
+ /// observes that notification and forwards the payload as a third wake
25
+ /// `kind: "remote-push"` event. APNs registration is still gated on the
26
+ /// `ELIZA_APNS_ENABLED` Info.plist flag and defaults off.
27
+ ///
28
+ /// JS-callable methods:
29
+ /// - `scheduleNext({ earliestBeginSec, alsoProcessing })`
30
+ /// - `getStatus()`
31
+ /// - `cancelAll()`
32
+ @objc(ElizaTasksPlugin)
33
+ public class ElizaTasksPlugin: CAPPlugin, CAPBridgedPlugin {
34
+ public let identifier = "ElizaTasksPlugin"
35
+ public let jsName = "ElizaTasks"
36
+ public let pluginMethods: [CAPPluginMethod] = [
37
+ CAPPluginMethod(name: "scheduleNext", returnType: CAPPluginReturnPromise),
38
+ CAPPluginMethod(name: "getStatus", returnType: CAPPluginReturnPromise),
39
+ CAPPluginMethod(name: "cancelAll", returnType: CAPPluginReturnPromise),
40
+ ]
41
+
42
+ // The identifiers MUST match the values declared in Info.plist's
43
+ // `BGTaskSchedulerPermittedIdentifiers` array. If they drift, `register`
44
+ // returns false and the OS refuses to dispatch tasks.
45
+ private static let refreshIdentifier = "ai.eliza.tasks.refresh"
46
+ private static let processingIdentifier = "ai.eliza.tasks.processing"
47
+ private static let remotePushIdentifier = "ai.eliza.tasks.remote-push"
48
+
49
+ // Default earliestBegin if the JS caller does not supply one. Apple's
50
+ // documented practical minimum is 15 minutes; we honor that as the floor.
51
+ private static let defaultEarliestBeginSec: Double = 15 * 60
52
+
53
+ // Apple's WWDC guidance: BGAppRefreshTask gets ~30s, BGProcessingTask
54
+ // gets minutes. The JS runner consumes deadlineSec to size its own
55
+ // hard-deadline race.
56
+ private static let refreshDeadlineSec: Double = 25
57
+ private static let processingDeadlineSec: Double = 120
58
+
59
+ // Persistence keys — used by `getStatus` so the JS side can observe wake
60
+ // events that landed before the webview was ready to receive listeners.
61
+ private static let lastWakeFiredAtKey = "ai.eliza.tasks.lastWakeFiredAtMs"
62
+ private static let lastWakeKindKey = "ai.eliza.tasks.lastWakeKind"
63
+ private static let refreshScheduledKey = "ai.eliza.tasks.refreshScheduled"
64
+ private static let processingScheduledKey = "ai.eliza.tasks.processingScheduled"
65
+
66
+ private var remotePushObserver: NSObjectProtocol?
67
+
68
+ public override func load() {
69
+ registerBackgroundTasks()
70
+ observeRemotePush()
71
+ }
72
+
73
+ deinit {
74
+ if let observer = remotePushObserver {
75
+ NotificationCenter.default.removeObserver(observer)
76
+ }
77
+ }
78
+
79
+ // MARK: - JS-callable surface
80
+
81
+ @objc func scheduleNext(_ call: CAPPluginCall) {
82
+ let earliestBeginSec = call.getDouble("earliestBeginSec")
83
+ ?? Self.defaultEarliestBeginSec
84
+ let alsoProcessing = call.getBool("alsoProcessing") ?? false
85
+
86
+ // Floor at 1s — BGTaskScheduler returns an error for negative or
87
+ // zero values, and very small intervals are silently coerced anyway.
88
+ let normalizedBegin = max(1.0, earliestBeginSec)
89
+ let beginDate = Date(timeIntervalSinceNow: normalizedBegin)
90
+
91
+ let refreshResult = submitRefreshRequest(beginDate: beginDate)
92
+ if alsoProcessing {
93
+ _ = submitProcessingRequest(beginDate: beginDate)
94
+ }
95
+
96
+ call.resolve([
97
+ "scheduled": refreshResult.scheduled,
98
+ "identifier": Self.refreshIdentifier,
99
+ "earliestBeginAtMs": refreshResult.scheduled
100
+ ? Int64(beginDate.timeIntervalSince1970 * 1000)
101
+ : NSNull(),
102
+ "reason": refreshResult.reason as Any? ?? NSNull(),
103
+ ])
104
+ }
105
+
106
+ @objc func getStatus(_ call: CAPPluginCall) {
107
+ let defaults = UserDefaults.standard
108
+ let lastWakeMs = defaults.object(forKey: Self.lastWakeFiredAtKey) as? Int64
109
+ let lastKind = defaults.string(forKey: Self.lastWakeKindKey)
110
+
111
+ call.resolve([
112
+ "supported": true,
113
+ "platform": "ios",
114
+ "refreshScheduled": defaults.bool(forKey: Self.refreshScheduledKey),
115
+ "processingScheduled": defaults.bool(forKey: Self.processingScheduledKey),
116
+ "lastWakeFiredAtMs": lastWakeMs.map { $0 as Any } ?? NSNull(),
117
+ "lastWakeKind": lastKind as Any? ?? NSNull(),
118
+ "reason": NSNull(),
119
+ ])
120
+ }
121
+
122
+ @objc func cancelAll(_ call: CAPPluginCall) {
123
+ BGTaskScheduler.shared.cancelAllTaskRequests()
124
+ let defaults = UserDefaults.standard
125
+ defaults.set(false, forKey: Self.refreshScheduledKey)
126
+ defaults.set(false, forKey: Self.processingScheduledKey)
127
+ call.resolve(["cancelled": true])
128
+ }
129
+
130
+ // MARK: - BGTaskScheduler registration
131
+
132
+ /// Register the two BG task handlers. Must run before
133
+ /// `application:didFinishLaunchingWithOptions:` returns. CAPPlugin.load()
134
+ /// runs after `didFinishLaunching` but BGTaskScheduler tolerates this if
135
+ /// the identifier is in Info.plist's permitted list — the OS queues the
136
+ /// dispatch until a handler is registered. Confirmed on iOS 15+.
137
+ private func registerBackgroundTasks() {
138
+ let scheduler = BGTaskScheduler.shared
139
+
140
+ let refreshRegistered = scheduler.register(
141
+ forTaskWithIdentifier: Self.refreshIdentifier,
142
+ using: nil
143
+ ) { [weak self] task in
144
+ guard let self = self else {
145
+ task.setTaskCompleted(success: false)
146
+ return
147
+ }
148
+ self.handleRefreshTask(task)
149
+ }
150
+
151
+ let processingRegistered = scheduler.register(
152
+ forTaskWithIdentifier: Self.processingIdentifier,
153
+ using: nil
154
+ ) { [weak self] task in
155
+ guard let self = self else {
156
+ task.setTaskCompleted(success: false)
157
+ return
158
+ }
159
+ self.handleProcessingTask(task)
160
+ }
161
+
162
+ if !refreshRegistered {
163
+ NSLog(
164
+ "[ElizaTasksPlugin] BGTaskScheduler.register(%@) returned false — verify Info.plist BGTaskSchedulerPermittedIdentifiers",
165
+ Self.refreshIdentifier
166
+ )
167
+ }
168
+ if !processingRegistered {
169
+ NSLog(
170
+ "[ElizaTasksPlugin] BGTaskScheduler.register(%@) returned false — verify Info.plist BGTaskSchedulerPermittedIdentifiers",
171
+ Self.processingIdentifier
172
+ )
173
+ }
174
+ }
175
+
176
+ // MARK: - Task handlers
177
+
178
+ private func handleRefreshTask(_ task: BGTask) {
179
+ // Always set an expiration handler before doing async work, otherwise
180
+ // iOS escalates the task termination to a force-kill.
181
+ task.expirationHandler = { [weak task] in
182
+ task?.setTaskCompleted(success: false)
183
+ }
184
+
185
+ let firedAtMs = Int64(Date().timeIntervalSince1970 * 1000)
186
+ persistWake(kind: "refresh", firedAtMs: firedAtMs)
187
+
188
+ // BG refresh consumers are expected to re-enqueue the next wake before
189
+ // resolving — without this the chain dies after one fire.
190
+ let nextBegin = Date(timeIntervalSinceNow: Self.defaultEarliestBeginSec)
191
+ _ = submitRefreshRequest(beginDate: nextBegin)
192
+
193
+ emitWake(
194
+ kind: "refresh",
195
+ identifier: Self.refreshIdentifier,
196
+ deadlineSec: Self.refreshDeadlineSec,
197
+ firedAtMs: firedAtMs,
198
+ payload: [:]
199
+ )
200
+
201
+ // The JS handler runs in the webview, which may be backgrounded. We
202
+ // signal completion eagerly — the runner's HTTP poke is fire-and-forget
203
+ // from the OS's perspective; the agent's loopback `/api/internal/wake`
204
+ // route owns durability.
205
+ task.setTaskCompleted(success: true)
206
+ }
207
+
208
+ private func handleProcessingTask(_ task: BGTask) {
209
+ task.expirationHandler = { [weak task] in
210
+ task?.setTaskCompleted(success: false)
211
+ }
212
+
213
+ let firedAtMs = Int64(Date().timeIntervalSince1970 * 1000)
214
+ persistWake(kind: "processing", firedAtMs: firedAtMs)
215
+
216
+ emitWake(
217
+ kind: "processing",
218
+ identifier: Self.processingIdentifier,
219
+ deadlineSec: Self.processingDeadlineSec,
220
+ firedAtMs: firedAtMs,
221
+ payload: [:]
222
+ )
223
+
224
+ // Processing tasks are not auto-rescheduled — the JS layer requests
225
+ // the next processing wake explicitly when a warmup window is needed.
226
+ task.setTaskCompleted(success: true)
227
+ }
228
+
229
+ // MARK: - Submit helpers
230
+
231
+ private struct SubmitResult {
232
+ let scheduled: Bool
233
+ let reason: String?
234
+ }
235
+
236
+ private func submitRefreshRequest(beginDate: Date) -> SubmitResult {
237
+ let request = BGAppRefreshTaskRequest(identifier: Self.refreshIdentifier)
238
+ request.earliestBeginDate = beginDate
239
+ do {
240
+ try BGTaskScheduler.shared.submit(request)
241
+ UserDefaults.standard.set(true, forKey: Self.refreshScheduledKey)
242
+ return SubmitResult(scheduled: true, reason: nil)
243
+ } catch {
244
+ UserDefaults.standard.set(false, forKey: Self.refreshScheduledKey)
245
+ let message = "BGTaskScheduler.submit(refresh) failed: \(error.localizedDescription)"
246
+ NSLog("[ElizaTasksPlugin] %@", message)
247
+ return SubmitResult(scheduled: false, reason: message)
248
+ }
249
+ }
250
+
251
+ private func submitProcessingRequest(beginDate: Date) -> SubmitResult {
252
+ let request = BGProcessingTaskRequest(identifier: Self.processingIdentifier)
253
+ request.earliestBeginDate = beginDate
254
+ // Eliza's processing task is the local-LLM warmup pass. Real-world
255
+ // semantics: only run while plugged in, no network needed (the agent
256
+ // is reachable on loopback inside the app process).
257
+ request.requiresExternalPower = true
258
+ request.requiresNetworkConnectivity = false
259
+ do {
260
+ try BGTaskScheduler.shared.submit(request)
261
+ UserDefaults.standard.set(true, forKey: Self.processingScheduledKey)
262
+ return SubmitResult(scheduled: true, reason: nil)
263
+ } catch {
264
+ UserDefaults.standard.set(false, forKey: Self.processingScheduledKey)
265
+ let message = "BGTaskScheduler.submit(processing) failed: \(error.localizedDescription)"
266
+ NSLog("[ElizaTasksPlugin] %@", message)
267
+ return SubmitResult(scheduled: false, reason: message)
268
+ }
269
+ }
270
+
271
+ // MARK: - Remote push plumbing
272
+
273
+ /// AppDelegate's `application:didReceiveRemoteNotification:` posts an
274
+ /// `ElizaCompanionRemotePush` notification with the userInfo dictionary
275
+ /// in `object`. We surface that to JS as a third wake kind so the same
276
+ /// `wake` event handler can drain it. Gated on the operator flipping
277
+ /// `ELIZA_APNS_ENABLED=1` in Info.plist — silent until then.
278
+ private func observeRemotePush() {
279
+ remotePushObserver = NotificationCenter.default.addObserver(
280
+ forName: Notification.Name("ElizaCompanionRemotePush"),
281
+ object: nil,
282
+ queue: .main
283
+ ) { [weak self] notification in
284
+ guard let self = self else { return }
285
+ let userInfo = (notification.object as? [AnyHashable: Any]) ?? [:]
286
+ var payload: [String: Any] = [:]
287
+ for (key, value) in userInfo {
288
+ guard let stringKey = key as? String, stringKey != "aps" else { continue }
289
+ payload[stringKey] = value
290
+ }
291
+ let firedAtMs = Int64(Date().timeIntervalSince1970 * 1000)
292
+ self.persistWake(kind: "remote-push", firedAtMs: firedAtMs)
293
+ self.emitWake(
294
+ kind: "remote-push",
295
+ identifier: Self.remotePushIdentifier,
296
+ deadlineSec: Self.refreshDeadlineSec,
297
+ firedAtMs: firedAtMs,
298
+ payload: payload
299
+ )
300
+ }
301
+ }
302
+
303
+ // MARK: - Event emission
304
+
305
+ private func emitWake(
306
+ kind: String,
307
+ identifier: String,
308
+ deadlineSec: Double,
309
+ firedAtMs: Int64,
310
+ payload: [String: Any]
311
+ ) {
312
+ notifyListeners("wake", data: [
313
+ "kind": kind,
314
+ "identifier": identifier,
315
+ "deadlineSec": deadlineSec,
316
+ "firedAtMs": firedAtMs,
317
+ "payload": payload,
318
+ ])
319
+ }
320
+
321
+ private func persistWake(kind: String, firedAtMs: Int64) {
322
+ let defaults = UserDefaults.standard
323
+ defaults.set(firedAtMs, forKey: Self.lastWakeFiredAtKey)
324
+ defaults.set(kind, forKey: Self.lastWakeKindKey)
325
+ }
326
+ }
package/package.json ADDED
@@ -0,0 +1,84 @@
1
+ {
2
+ "name": "@elizaos/capacitor-eliza-tasks",
3
+ "version": "2.0.11-beta.7",
4
+ "description": "Bridges iOS BGTaskScheduler (BGAppRefreshTask + BGProcessingTask) wake events into the Eliza Capacitor runtime.",
5
+ "keywords": [
6
+ "background",
7
+ "bgtaskscheduler",
8
+ "ios",
9
+ "wake",
10
+ "eliza"
11
+ ],
12
+ "main": "./dist/plugin.cjs.js",
13
+ "module": "./dist/esm/index.js",
14
+ "types": "./dist/esm/index.d.ts",
15
+ "exports": {
16
+ ".": {
17
+ "types": "./dist/esm/index.d.ts",
18
+ "bun": "./src/index.ts",
19
+ "development": "./src/index.ts",
20
+ "import": "./dist/esm/index.js",
21
+ "require": "./dist/plugin.cjs.js"
22
+ },
23
+ "./package.json": "./package.json"
24
+ },
25
+ "unpkg": "dist/plugin.js",
26
+ "files": [
27
+ "android/src/main/",
28
+ "android/build.gradle",
29
+ "dist/",
30
+ "ios/Sources/",
31
+ "*.podspec",
32
+ "dist"
33
+ ],
34
+ "author": "elizaOS",
35
+ "license": "MIT",
36
+ "repository": {
37
+ "type": "git",
38
+ "url": "https://github.com/elizaOS/eliza"
39
+ },
40
+ "scripts": {
41
+ "build": "node ../../packages/scripts/with-package-build-lock.mjs plugins/plugin-native-eliza-tasks -- bun run build:unlocked",
42
+ "clean": "node ../../packages/scripts/rm-path-recursive.mjs dist",
43
+ "prepublishOnly": "bun run build",
44
+ "test": "vitest run --passWithNoTests",
45
+ "watch": "tsc --watch",
46
+ "build:unlocked": "bun run clean && bunx tsc -p tsconfig.json && bunx rollup -c rollup.config.mjs"
47
+ },
48
+ "devDependencies": {
49
+ "@capacitor/core": "^8.3.1",
50
+ "@rollup/plugin-node-resolve": "^16.0.0",
51
+ "rollup": "^4.60.2",
52
+ "typescript": "^6.0.3",
53
+ "vitest": "^4.0.17"
54
+ },
55
+ "peerDependencies": {
56
+ "@capacitor/core": "^8.3.1"
57
+ },
58
+ "publishConfig": {
59
+ "access": "public"
60
+ },
61
+ "capacitor": {
62
+ "ios": {
63
+ "src": "ios",
64
+ "podName": "ElizaosCapacitorElizaTasks"
65
+ },
66
+ "android": {
67
+ "src": "android"
68
+ }
69
+ },
70
+ "elizaos": {
71
+ "platforms": [
72
+ "browser",
73
+ "node"
74
+ ],
75
+ "runtime": "both",
76
+ "platformDetails": {
77
+ "browser": "Unsupported web fallback; BGTaskScheduler is iOS-only.",
78
+ "node": "No desktop equivalent; runtime ignores this plugin off-mobile.",
79
+ "ios": true,
80
+ "android": false
81
+ }
82
+ },
83
+ "gitHead": "cdbc876f793d96073d7eb0d09715a031ce0cd32e"
84
+ }