@lobu/cli 6.1.1 → 7.1.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/dist/commands/_lib/apply/apply-cmd.d.ts +36 -0
- package/dist/commands/_lib/apply/apply-cmd.d.ts.map +1 -1
- package/dist/commands/_lib/apply/apply-cmd.js +696 -40
- package/dist/commands/_lib/apply/apply-cmd.js.map +1 -1
- package/dist/commands/_lib/apply/client.d.ts +285 -0
- package/dist/commands/_lib/apply/client.d.ts.map +1 -1
- package/dist/commands/_lib/apply/client.js +469 -28
- package/dist/commands/_lib/apply/client.js.map +1 -1
- package/dist/commands/_lib/apply/desired-state.d.ts +187 -3
- package/dist/commands/_lib/apply/desired-state.d.ts.map +1 -1
- package/dist/commands/_lib/apply/desired-state.js +879 -88
- package/dist/commands/_lib/apply/desired-state.js.map +1 -1
- package/dist/commands/_lib/apply/diff.d.ts +72 -3
- package/dist/commands/_lib/apply/diff.d.ts.map +1 -1
- package/dist/commands/_lib/apply/diff.js +473 -84
- package/dist/commands/_lib/apply/diff.js.map +1 -1
- package/dist/commands/_lib/apply/prompt.d.ts +6 -0
- package/dist/commands/_lib/apply/prompt.d.ts.map +1 -1
- package/dist/commands/_lib/apply/prompt.js +16 -0
- package/dist/commands/_lib/apply/prompt.js.map +1 -1
- package/dist/commands/_lib/apply/render.d.ts +9 -0
- package/dist/commands/_lib/apply/render.d.ts.map +1 -1
- package/dist/commands/_lib/apply/render.js +80 -3
- package/dist/commands/_lib/apply/render.js.map +1 -1
- package/dist/commands/_lib/connector-loader.d.ts +3 -0
- package/dist/commands/_lib/connector-loader.d.ts.map +1 -0
- package/dist/commands/_lib/connector-loader.js +129 -0
- package/dist/commands/_lib/connector-loader.js.map +1 -0
- package/dist/commands/_lib/connector-run-cmd.d.ts +35 -0
- package/dist/commands/_lib/connector-run-cmd.d.ts.map +1 -0
- package/dist/commands/_lib/connector-run-cmd.js +351 -0
- package/dist/commands/_lib/connector-run-cmd.js.map +1 -0
- package/dist/commands/_lib/export/export-cmd.d.ts +35 -0
- package/dist/commands/_lib/export/export-cmd.d.ts.map +1 -0
- package/dist/commands/_lib/export/export-cmd.js +329 -0
- package/dist/commands/_lib/export/export-cmd.js.map +1 -0
- package/dist/commands/agent.d.ts.map +1 -1
- package/dist/commands/agent.js +11 -14
- package/dist/commands/agent.js.map +1 -1
- package/dist/commands/chat.d.ts.map +1 -1
- package/dist/commands/chat.js +28 -7
- package/dist/commands/chat.js.map +1 -1
- package/dist/commands/connector.d.ts +3 -0
- package/dist/commands/connector.d.ts.map +1 -0
- package/dist/commands/connector.js +5 -0
- package/dist/commands/connector.js.map +1 -0
- package/dist/commands/dev.d.ts +23 -0
- package/dist/commands/dev.d.ts.map +1 -1
- package/dist/commands/dev.js +273 -8
- package/dist/commands/dev.js.map +1 -1
- package/dist/commands/doctor.d.ts.map +1 -1
- package/dist/commands/doctor.js +2 -3
- package/dist/commands/doctor.js.map +1 -1
- package/dist/commands/eval.d.ts.map +1 -1
- package/dist/commands/eval.js +28 -18
- package/dist/commands/eval.js.map +1 -1
- package/dist/commands/init.d.ts +2 -0
- package/dist/commands/init.d.ts.map +1 -1
- package/dist/commands/init.js +29 -1
- package/dist/commands/init.js.map +1 -1
- package/dist/commands/login.d.ts.map +1 -1
- package/dist/commands/login.js +22 -16
- package/dist/commands/login.js.map +1 -1
- package/dist/commands/memory/_lib/browser-auth-cmd.d.ts.map +1 -1
- package/dist/commands/memory/_lib/browser-auth-cmd.js +15 -144
- package/dist/commands/memory/_lib/browser-auth-cmd.js.map +1 -1
- package/dist/commands/memory/_lib/schema.d.ts +28 -1
- package/dist/commands/memory/_lib/schema.d.ts.map +1 -1
- package/dist/commands/memory/_lib/schema.js +120 -4
- package/dist/commands/memory/_lib/schema.js.map +1 -1
- package/dist/commands/memory/_lib/seed-cmd.d.ts.map +1 -1
- package/dist/commands/memory/_lib/seed-cmd.js +41 -18
- package/dist/commands/memory/_lib/seed-cmd.js.map +1 -1
- package/dist/commands/org.d.ts +4 -0
- package/dist/commands/org.d.ts.map +1 -1
- package/dist/commands/org.js +10 -0
- package/dist/commands/org.js.map +1 -1
- package/dist/commands/token.d.ts +9 -0
- package/dist/commands/token.d.ts.map +1 -1
- package/dist/commands/token.js +54 -3
- package/dist/commands/token.js.map +1 -1
- package/dist/commands/validate.d.ts.map +1 -1
- package/dist/commands/validate.js +4 -13
- package/dist/commands/validate.js.map +1 -1
- package/dist/config/loader.js +2 -2
- package/dist/config/loader.js.map +1 -1
- package/dist/connectors/README.md +2 -3
- package/dist/connectors/apple_health.ts +138 -0
- package/dist/connectors/apple_photos.ts +178 -0
- package/dist/connectors/apple_screen_time.ts +82 -0
- package/dist/connectors/browser/evaluate.ts +120 -0
- package/dist/connectors/browser/fill_form.ts +107 -0
- package/dist/connectors/browser/page_text.ts +108 -0
- package/dist/connectors/browser-scraper-utils.ts +111 -3
- package/dist/connectors/capterra.ts +5 -1
- package/dist/connectors/chrome_tabs.ts +74 -0
- package/dist/connectors/g2.ts +5 -1
- package/dist/connectors/github.ts +16 -38
- package/dist/connectors/glassdoor.ts +5 -1
- package/dist/connectors/google_calendar.ts +28 -6
- package/dist/connectors/google_gmail.ts +6 -3
- package/dist/connectors/google_play.ts +32 -5
- package/dist/connectors/hackernews.ts +37 -2
- package/dist/connectors/index.ts +14 -1
- package/dist/connectors/linkedin.ts +32 -9
- package/dist/connectors/local_directory.ts +91 -0
- package/dist/connectors/reddit.ts +1 -0
- package/dist/connectors/revolut.ts +569 -0
- package/dist/connectors/rss.ts +33 -8
- package/dist/connectors/trustpilot.ts +36 -21
- package/dist/connectors/website.ts +8 -69
- package/dist/connectors/whatsapp.ts +21 -22
- package/dist/connectors/whatsapp_local.ts +125 -0
- package/dist/connectors/x.ts +17 -7
- package/dist/db/migrations/20260510220000_connector_required_capability.sql +47 -0
- package/dist/db/migrations/20260512000000_device_worker_connection_binding.sql +113 -0
- package/dist/db/migrations/20260512131703_connections_slug.sql +131 -0
- package/dist/db/migrations/20260513000000_chat_user_identities.sql +24 -0
- package/dist/db/migrations/20260513120000_auth_profiles_device_binding.sql +50 -0
- package/dist/db/migrations/20260513150000_auth_profiles_cdp_url.sql +43 -0
- package/dist/db/migrations/20260513200000_notifications_as_events.sql +86 -0
- package/dist/db/migrations/20260514000000_scheduled_jobs.sql +97 -0
- package/dist/db/migrations/20260514120000_auth_profiles_connector_key_nullable.sql +42 -0
- package/dist/db/migrations/20260514130000_connection_action_modes.sql +103 -0
- package/dist/db/migrations/20260514160000_auth_profiles_mirror_mode.sql +32 -0
- package/dist/db/migrations/20260515120000_agents_per_org_pk.sql +66 -0
- package/dist/db/migrations/20260515150000_geo_enrichment.sql +208 -0
- package/dist/db/migrations/20260515160000_drop_agents_org_id_unique.sql +24 -0
- package/dist/db/migrations/20260515170000_auth_profiles_default_for_connector.sql +23 -0
- package/dist/db/migrations/20260516120000_agents_per_org_pk_swap.sql +125 -0
- package/dist/db/migrations/20260516200000_events_search_tsv.sql +134 -0
- package/dist/db/migrations/20260516200100_events_lifecycle_changes_index.sql +25 -0
- package/dist/db/migrations/20260517010000_drop_unused_indexes.sql +49 -0
- package/dist/db/migrations/20260517020000_softdelete_orphan_feeds.sql +56 -0
- package/dist/db/migrations/20260517030000_pat_worker_id_binding.sql +27 -0
- package/dist/db/migrations/20260517040000_archive_orphan_watchers.sql +30 -0
- package/dist/db/migrations/20260517050000_watcher_agent_id_not_null.sql +34 -0
- package/dist/db/migrations/20260517060000_watcher_schema_additions.sql +78 -0
- package/dist/db/migrations/20260517150000_goals_primitive.sql +55 -0
- package/dist/db/migrations/20260517160000_drop_goals_primitive.sql +45 -0
- package/dist/db/migrations/20260518000000_pending_interactions.sql +49 -0
- package/dist/db/migrations/20260518010000_runs_heartbeat_reaper_index.sql +22 -0
- package/dist/eval/client.d.ts.map +1 -1
- package/dist/eval/client.js +11 -0
- package/dist/eval/client.js.map +1 -1
- package/dist/eval/grader.js +2 -1
- package/dist/eval/grader.js.map +1 -1
- package/dist/eval/types.d.ts +2 -0
- package/dist/eval/types.d.ts.map +1 -1
- package/dist/index.d.ts +11 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +115 -114
- package/dist/index.js.map +1 -1
- package/dist/internal/context.d.ts +9 -0
- package/dist/internal/context.d.ts.map +1 -1
- package/dist/internal/context.js +41 -6
- package/dist/internal/context.js.map +1 -1
- package/dist/internal/credentials.d.ts +5 -0
- package/dist/internal/credentials.d.ts.map +1 -1
- package/dist/internal/credentials.js +75 -1
- package/dist/internal/credentials.js.map +1 -1
- package/dist/internal/gateway-url.d.ts +14 -0
- package/dist/internal/gateway-url.d.ts.map +1 -1
- package/dist/internal/gateway-url.js +19 -0
- package/dist/internal/gateway-url.js.map +1 -1
- package/dist/internal/index.d.ts +1 -1
- package/dist/internal/index.d.ts.map +1 -1
- package/dist/internal/index.js +1 -1
- package/dist/internal/index.js.map +1 -1
- package/dist/internal/local-env.d.ts.map +1 -1
- package/dist/internal/local-env.js +9 -2
- package/dist/internal/local-env.js.map +1 -1
- package/dist/server.bundle.mjs +42251 -36931
- package/dist/start-local.bundle.mjs +16437 -9882
- package/dist/templates/TESTING.md.tmpl +9 -9
- package/package.json +8 -6
- package/dist/connectors/google_photos.ts +0 -776
package/dist/commands/token.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import chalk from "chalk";
|
|
2
|
+
import postgres from "postgres";
|
|
2
3
|
import { getToken, resolveContext } from "../internal/index.js";
|
|
3
4
|
import { resolveApiClient } from "../internal/api-client.js";
|
|
4
5
|
export async function tokenCommand(options) {
|
|
@@ -22,7 +23,7 @@ export async function tokenCreateCommand(options) {
|
|
|
22
23
|
context: options.context,
|
|
23
24
|
org: options.org,
|
|
24
25
|
});
|
|
25
|
-
const name = options.name?.trim() ||
|
|
26
|
+
const name = options.name?.trim() || `lobu-cli-${new Date().toISOString().slice(0, 10)}`;
|
|
26
27
|
const scope = options.scope?.trim() || "mcp:read mcp:write";
|
|
27
28
|
const response = await client.post(`/api/${encodeURIComponent(orgSlug)}/tokens`, {
|
|
28
29
|
name,
|
|
@@ -49,7 +50,57 @@ export async function tokenCreateCommand(options) {
|
|
|
49
50
|
console.log(chalk.yellow("\n Save this token now; it will not be shown again:"));
|
|
50
51
|
console.log(` ${response.token.token}\n`);
|
|
51
52
|
}
|
|
52
|
-
|
|
53
|
-
|
|
53
|
+
/**
|
|
54
|
+
* Revoke a token by its `jti`. Inserts a row into `public.revoked_tokens`
|
|
55
|
+
* (created on demand) — the gateway's RevokedTokenStore checks this on every
|
|
56
|
+
* worker-token / settings-cookie verification, so the token is dead within
|
|
57
|
+
* one cache TTL (≤60s).
|
|
58
|
+
*/
|
|
59
|
+
export async function tokenRevokeCommand(jti, options) {
|
|
60
|
+
jti = jti.trim();
|
|
61
|
+
if (!jti) {
|
|
62
|
+
console.error(chalk.red("\n Missing <jti>.\n"));
|
|
63
|
+
process.exitCode = 1;
|
|
64
|
+
return;
|
|
65
|
+
}
|
|
66
|
+
const databaseUrl = process.env.DATABASE_URL?.trim();
|
|
67
|
+
if (!databaseUrl) {
|
|
68
|
+
console.error(chalk.red("\n DATABASE_URL is not set. Run this from the same environment as the gateway.\n"));
|
|
69
|
+
process.exitCode = 1;
|
|
70
|
+
return;
|
|
71
|
+
}
|
|
72
|
+
let expiresAt;
|
|
73
|
+
if (options.expiresAt) {
|
|
74
|
+
expiresAt = new Date(options.expiresAt);
|
|
75
|
+
if (Number.isNaN(expiresAt.getTime())) {
|
|
76
|
+
console.error(chalk.red("\n --expires-at must be a valid ISO date.\n"));
|
|
77
|
+
process.exitCode = 1;
|
|
78
|
+
return;
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
else {
|
|
82
|
+
expiresAt = new Date(Date.now() + 24 * 60 * 60 * 1000);
|
|
83
|
+
}
|
|
84
|
+
const sql = postgres(databaseUrl, { max: 1 });
|
|
85
|
+
try {
|
|
86
|
+
await sql.unsafe(`
|
|
87
|
+
CREATE TABLE IF NOT EXISTS public.revoked_tokens (
|
|
88
|
+
jti text PRIMARY KEY,
|
|
89
|
+
expires_at timestamptz NOT NULL
|
|
90
|
+
)
|
|
91
|
+
`);
|
|
92
|
+
await sql `
|
|
93
|
+
INSERT INTO public.revoked_tokens (jti, expires_at)
|
|
94
|
+
VALUES (${jti}, ${expiresAt})
|
|
95
|
+
ON CONFLICT (jti) DO UPDATE SET expires_at = GREATEST(public.revoked_tokens.expires_at, EXCLUDED.expires_at)
|
|
96
|
+
`;
|
|
97
|
+
}
|
|
98
|
+
finally {
|
|
99
|
+
await sql.end({ timeout: 5 });
|
|
100
|
+
}
|
|
101
|
+
console.log(chalk.cyan("\n Token revoked"));
|
|
102
|
+
console.log(chalk.dim(` jti: ${jti}`));
|
|
103
|
+
console.log(chalk.dim(` expires: ${expiresAt.toISOString()}`));
|
|
104
|
+
console.log(chalk.dim(" Effective within ~60s (gateway revocation cache TTL).\n"));
|
|
54
105
|
}
|
|
55
106
|
//# sourceMappingURL=token.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"token.js","sourceRoot":"","sources":["../../src/commands/token.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,EAAE,QAAQ,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAChE,OAAO,EAAE,gBAAgB,EAAE,MAAM,2BAA2B,CAAC;AAuB7D,MAAM,CAAC,KAAK,UAAU,YAAY,CAAC,OAGlC;IACC,MAAM,MAAM,GAAG,MAAM,cAAc,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC;IACrD,MAAM,KAAK,GAAG,MAAM,QAAQ,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;IAE1C,IAAI,CAAC,KAAK,EAAE,CAAC;QACX,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,8CAA8C,CAAC,CAAC,CAAC;QACzE,OAAO,CAAC,QAAQ,GAAG,CAAC,CAAC;QACrB,OAAO;IACT,CAAC;IAED,IAAI,OAAO,CAAC,GAAG,EAAE,CAAC;QAChB,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,GAAG,KAAK,IAAI,CAAC,CAAC;QACnC,OAAO;IACT,CAAC;IAED,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,gBAAgB,MAAM,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC;IACvD,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,cAAc,MAAM,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC;IACtD,OAAO,CAAC,GAAG,CAAC,2DAA2D,CAAC,CAAC;AAC3E,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,kBAAkB,CACtC,OAA2B;IAE3B,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,WAAW,EAAE,GAAG,MAAM,gBAAgB,CAAC;QAC9D,OAAO,EAAE,OAAO,CAAC,OAAO;QACxB,GAAG,EAAE,OAAO,CAAC,GAAG;KACjB,CAAC,CAAC;IACH,MAAM,IAAI,
|
|
1
|
+
{"version":3,"file":"token.js","sourceRoot":"","sources":["../../src/commands/token.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"validate.d.ts","sourceRoot":"","sources":["../../src/commands/validate.ts"],"names":[],"mappings":"AAGA,wBAAsB,eAAe,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,
|
|
1
|
+
{"version":3,"file":"validate.d.ts","sourceRoot":"","sources":["../../src/commands/validate.ts"],"names":[],"mappings":"AAGA,wBAAsB,eAAe,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAmCnE"}
|
|
@@ -14,28 +14,19 @@ export async function validateCommand(cwd) {
|
|
|
14
14
|
}
|
|
15
15
|
const { config } = result;
|
|
16
16
|
const warnings = [];
|
|
17
|
-
const errors = [];
|
|
18
17
|
for (const [agentId, agentEntry] of Object.entries(config.agents)) {
|
|
19
18
|
if (agentEntry.providers.length === 0) {
|
|
20
19
|
warnings.push(`[agents.${agentId}] No providers configured. Agent will need provider keys at runtime.`);
|
|
21
20
|
}
|
|
22
21
|
}
|
|
22
|
+
const agentCount = Object.keys(config.agents).length;
|
|
23
23
|
console.log();
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
console.log(chalk.green(` lobu.toml is valid`));
|
|
27
|
-
console.log(chalk.dim(` ${agentCount} agent(s) configured`));
|
|
28
|
-
}
|
|
29
|
-
else {
|
|
30
|
-
console.log(chalk.red(` Validation failed`));
|
|
31
|
-
}
|
|
32
|
-
for (const err of errors) {
|
|
33
|
-
console.log(chalk.red(` ${err}`));
|
|
34
|
-
}
|
|
24
|
+
console.log(chalk.green(` lobu.toml is valid`));
|
|
25
|
+
console.log(chalk.dim(` ${agentCount} agent(s) configured`));
|
|
35
26
|
for (const warn of warnings) {
|
|
36
27
|
console.log(chalk.yellow(` ${warn}`));
|
|
37
28
|
}
|
|
38
29
|
console.log();
|
|
39
|
-
return
|
|
30
|
+
return true;
|
|
40
31
|
}
|
|
41
32
|
//# sourceMappingURL=validate.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"validate.js","sourceRoot":"","sources":["../../src/commands/validate.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,EAAE,WAAW,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAC;AAE9D,MAAM,CAAC,KAAK,UAAU,eAAe,CAAC,GAAW;IAC/C,MAAM,MAAM,GAAG,MAAM,UAAU,CAAC,GAAG,CAAC,CAAC;IAErC,IAAI,WAAW,CAAC,MAAM,CAAC,EAAE,CAAC;QACxB,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,OAAO,MAAM,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC;QAChD,IAAI,MAAM,CAAC,OAAO,EAAE,CAAC;YACnB,KAAK,MAAM,MAAM,IAAI,MAAM,CAAC,OAAO,EAAE,CAAC;gBACpC,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,KAAK,MAAM,EAAE,CAAC,CAAC,CAAC;YAC1C,CAAC;QACH,CAAC;QACD,OAAO,CAAC,GAAG,EAAE,CAAC;QACd,OAAO,KAAK,CAAC;IACf,CAAC;IAED,MAAM,EAAE,MAAM,EAAE,GAAG,MAAM,CAAC;IAC1B,MAAM,QAAQ,GAAa,EAAE,CAAC;
|
|
1
|
+
{"version":3,"file":"validate.js","sourceRoot":"","sources":["../../src/commands/validate.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,EAAE,WAAW,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAC;AAE9D,MAAM,CAAC,KAAK,UAAU,eAAe,CAAC,GAAW;IAC/C,MAAM,MAAM,GAAG,MAAM,UAAU,CAAC,GAAG,CAAC,CAAC;IAErC,IAAI,WAAW,CAAC,MAAM,CAAC,EAAE,CAAC;QACxB,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,OAAO,MAAM,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC;QAChD,IAAI,MAAM,CAAC,OAAO,EAAE,CAAC;YACnB,KAAK,MAAM,MAAM,IAAI,MAAM,CAAC,OAAO,EAAE,CAAC;gBACpC,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,KAAK,MAAM,EAAE,CAAC,CAAC,CAAC;YAC1C,CAAC;QACH,CAAC;QACD,OAAO,CAAC,GAAG,EAAE,CAAC;QACd,OAAO,KAAK,CAAC;IACf,CAAC;IAED,MAAM,EAAE,MAAM,EAAE,GAAG,MAAM,CAAC;IAC1B,MAAM,QAAQ,GAAa,EAAE,CAAC;IAE9B,KAAK,MAAM,CAAC,OAAO,EAAE,UAAU,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,MAAM,CAAC,EAAE,CAAC;QAClE,IAAI,UAAU,CAAC,SAAS,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YACtC,QAAQ,CAAC,IAAI,CACX,WAAW,OAAO,sEAAsE,CACzF,CAAC;QACJ,CAAC;IACH,CAAC;IAED,MAAM,UAAU,GAAG,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,MAAM,CAAC;IACrD,OAAO,CAAC,GAAG,EAAE,CAAC;IACd,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,KAAK,CAAC,sBAAsB,CAAC,CAAC,CAAC;IACjD,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,KAAK,UAAU,sBAAsB,CAAC,CAAC,CAAC;IAC9D,KAAK,MAAM,IAAI,IAAI,QAAQ,EAAE,CAAC;QAC5B,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,MAAM,CAAC,KAAK,IAAI,EAAE,CAAC,CAAC,CAAC;IACzC,CAAC;IACD,OAAO,CAAC,GAAG,EAAE,CAAC;IAEd,OAAO,IAAI,CAAC;AACd,CAAC"}
|
package/dist/config/loader.js
CHANGED
|
@@ -24,14 +24,14 @@ export async function loadConfig(cwd) {
|
|
|
24
24
|
}
|
|
25
25
|
catch (err) {
|
|
26
26
|
return {
|
|
27
|
-
error: `Invalid TOML syntax in ${
|
|
27
|
+
error: `Invalid TOML syntax in ${configPath}`,
|
|
28
28
|
details: [err instanceof Error ? err.message : String(err)],
|
|
29
29
|
};
|
|
30
30
|
}
|
|
31
31
|
const result = lobuConfigSchema.safeParse(parsed);
|
|
32
32
|
if (!result.success) {
|
|
33
33
|
const details = result.error.issues.map((issue) => `${issue.path.join(".")}: ${issue.message}`);
|
|
34
|
-
return { error: `Invalid ${
|
|
34
|
+
return { error: `Invalid ${configPath}`, details };
|
|
35
35
|
}
|
|
36
36
|
return { config: result.data, path: configPath };
|
|
37
37
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"loader.js","sourceRoot":"","sources":["../../src/config/loader.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAC5C,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,KAAK,IAAI,SAAS,EAAE,MAAM,WAAW,CAAC;AAC/C,OAAO,EAAuB,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAEpE,MAAM,CAAC,MAAM,eAAe,GAAG,WAAW,CAAC;AAY3C;;GAEG;AACH,MAAM,CAAC,KAAK,UAAU,UAAU,CAAC,GAAW;IAC1C,MAAM,UAAU,GAAG,IAAI,CAAC,GAAG,EAAE,eAAe,CAAC,CAAC;IAE9C,IAAI,GAAW,CAAC;IAChB,IAAI,CAAC;QACH,GAAG,GAAG,MAAM,QAAQ,CAAC,UAAU,EAAE,OAAO,CAAC,CAAC;IAC5C,CAAC;IAAC,MAAM,CAAC;QACP,OAAO;YACL,KAAK,EAAE,MAAM,eAAe,aAAa,GAAG,EAAE;YAC9C,OAAO,EAAE,CAAC,gCAAgC,CAAC;SAC5C,CAAC;IACJ,CAAC;IAED,IAAI,MAA+B,CAAC;IACpC,IAAI,CAAC;QACH,MAAM,GAAG,SAAS,CAAC,GAAG,CAA4B,CAAC;IACrD,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,OAAO;YACL,KAAK,EAAE,0BAA0B,
|
|
1
|
+
{"version":3,"file":"loader.js","sourceRoot":"","sources":["../../src/config/loader.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAC5C,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,KAAK,IAAI,SAAS,EAAE,MAAM,WAAW,CAAC;AAC/C,OAAO,EAAuB,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAEpE,MAAM,CAAC,MAAM,eAAe,GAAG,WAAW,CAAC;AAY3C;;GAEG;AACH,MAAM,CAAC,KAAK,UAAU,UAAU,CAAC,GAAW;IAC1C,MAAM,UAAU,GAAG,IAAI,CAAC,GAAG,EAAE,eAAe,CAAC,CAAC;IAE9C,IAAI,GAAW,CAAC;IAChB,IAAI,CAAC;QACH,GAAG,GAAG,MAAM,QAAQ,CAAC,UAAU,EAAE,OAAO,CAAC,CAAC;IAC5C,CAAC;IAAC,MAAM,CAAC;QACP,OAAO;YACL,KAAK,EAAE,MAAM,eAAe,aAAa,GAAG,EAAE;YAC9C,OAAO,EAAE,CAAC,gCAAgC,CAAC;SAC5C,CAAC;IACJ,CAAC;IAED,IAAI,MAA+B,CAAC;IACpC,IAAI,CAAC;QACH,MAAM,GAAG,SAAS,CAAC,GAAG,CAA4B,CAAC;IACrD,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,OAAO;YACL,KAAK,EAAE,0BAA0B,UAAU,EAAE;YAC7C,OAAO,EAAE,CAAC,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;SAC5D,CAAC;IACJ,CAAC;IAED,MAAM,MAAM,GAAG,gBAAgB,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC;IAClD,IAAI,CAAC,MAAM,CAAC,OAAO,EAAE,CAAC;QACpB,MAAM,OAAO,GAAG,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,GAAG,CACrC,CAAC,KAAK,EAAE,EAAE,CAAC,GAAG,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,KAAK,KAAK,CAAC,OAAO,EAAE,CACvD,CAAC;QACF,OAAO,EAAE,KAAK,EAAE,WAAW,UAAU,EAAE,EAAE,OAAO,EAAE,CAAC;IACrD,CAAC;IAED,OAAO,EAAE,MAAM,EAAE,MAAM,CAAC,IAAI,EAAE,IAAI,EAAE,UAAU,EAAE,CAAC;AACnD,CAAC;AAED,MAAM,UAAU,WAAW,CACzB,MAA8B;IAE9B,OAAO,OAAO,IAAI,MAAM,CAAC;AAC3B,CAAC"}
|
|
@@ -465,7 +465,7 @@ Browser connectors use `patchright` (an npm alias for Playwright). The SDK also
|
|
|
465
465
|
|
|
466
466
|
Connector code runs in a worker subprocess with a restricted environment. Key things to know:
|
|
467
467
|
|
|
468
|
-
- **Minimal env vars**: Only `PATH`, `HOME`, `TMPDIR`, `TZ`, `NODE_ENV`, and `
|
|
468
|
+
- **Minimal env vars**: Only `PATH`, `HOME`, `TMPDIR`, `TZ`, `NODE_ENV`, `NODE_PATH`, and `PLAYWRIGHT_BROWSERS_PATH` are available. No access to the host's env vars.
|
|
469
469
|
- **Secrets via ctx**: API keys and tokens flow through `ctx.credentials` and `ctx.config`, not environment variables. The `env_keys` auth method stores secrets on auth profiles, and the platform injects them into `ctx.config` at sync time.
|
|
470
470
|
- **No filesystem persistence**: Don't write to disk expecting it to survive between syncs. Use `checkpoint` for state.
|
|
471
471
|
|
|
@@ -506,7 +506,7 @@ Connectors can also be installed manually via `client.connections.installConnect
|
|
|
506
506
|
2. If `compiled_code` is NULL (bundled connectors), it compiles from `connectors/{source_path}` on disk via esbuild
|
|
507
507
|
3. The compiled code is sent to the worker, written to a temp file (`.connector-child-{pid}.mjs`), and loaded via dynamic `import()`
|
|
508
508
|
4. Each sync/action runs in an **isolated child process** with a 10-minute timeout and 512MB memory limit
|
|
509
|
-
5. The child process has a restricted environment — only `PATH`, `HOME`, `TMPDIR`, `TZ`, `NODE_ENV`, and `PLAYWRIGHT_BROWSERS_PATH` are available as env vars
|
|
509
|
+
5. The child process has a restricted environment — only `PATH`, `HOME`, `TMPDIR`, `TZ`, `NODE_ENV`, `NODE_PATH`, and `PLAYWRIGHT_BROWSERS_PATH` are available as env vars
|
|
510
510
|
6. Secrets flow through `ctx.credentials` and `ctx.config`, not environment variables
|
|
511
511
|
|
|
512
512
|
This means edits to `.ts` files in `connectors/` take effect on the next sync without reinstalling.
|
|
@@ -520,7 +520,6 @@ This means edits to `.ts` files in `connectors/` take effect on the next sync wi
|
|
|
520
520
|
| `github` | oauth/env_keys | issues, PRs, comments, discussions | create/close/reopen issues, PRs |
|
|
521
521
|
| `glassdoor` | none | reviews | - |
|
|
522
522
|
| `gmaps` | env_keys | reviews | - |
|
|
523
|
-
| `google_photos` | browser (CDP) | photos | - |
|
|
524
523
|
| `google_play` | none | reviews | - |
|
|
525
524
|
| `hackernews` | none | stories, comments | - |
|
|
526
525
|
| `ios_appstore` | none | reviews | - |
|
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Apple Health Connector (V1 runtime) — Lobu device app.
|
|
3
|
+
*
|
|
4
|
+
* Runs on a device bridge with HealthKit access. On iOS this reads the phone's
|
|
5
|
+
* Health store directly; on supported macOS installs HealthKit exposes the
|
|
6
|
+
* per-user store synced from iPhone and Apple Watch via iCloud Health. The
|
|
7
|
+
* Lobu device bridge holds the HealthKit entitlement, requests read permission
|
|
8
|
+
* once via a system sheet, and queries:
|
|
9
|
+
*
|
|
10
|
+
* - `daily_summaries`: daily totals for steps, distance, active energy,
|
|
11
|
+
* exercise minutes, and resting heart rate.
|
|
12
|
+
* - `workouts`: individual workout sessions (type, duration, energy, distance).
|
|
13
|
+
*
|
|
14
|
+
* The connector DEFINITION (feeds, event kinds, options) is the source of truth
|
|
15
|
+
* for what data ends up in Lobu and how it's shaped. The EXECUTION lives in the
|
|
16
|
+
* Lobu device app, which polls /api/workers/* as a user-scoped worker
|
|
17
|
+
* advertising the `healthkit` capability and streams events back through the
|
|
18
|
+
* standard worker protocol — same `runs` lifecycle as every other connector.
|
|
19
|
+
*
|
|
20
|
+
* The TS sync()/execute() here are safety stubs: if a server-side worker
|
|
21
|
+
* somehow bypassed the capability gate (`required_capability='healthkit'`),
|
|
22
|
+
* the run would throw immediately instead of silently producing no events.
|
|
23
|
+
*/
|
|
24
|
+
|
|
25
|
+
import {
|
|
26
|
+
type ActionResult,
|
|
27
|
+
type ConnectorDefinition,
|
|
28
|
+
ConnectorRuntime,
|
|
29
|
+
type SyncContext,
|
|
30
|
+
type SyncResult,
|
|
31
|
+
} from '@lobu/connector-sdk';
|
|
32
|
+
|
|
33
|
+
const BRIDGE_ONLY_MESSAGE =
|
|
34
|
+
'apple.health runs only on a worker advertising capability "healthkit" (Lobu with Apple Health permission). ' +
|
|
35
|
+
'This run was claimed by a worker without that capability — check connector_definitions.required_capability and the poll-time capability filter.';
|
|
36
|
+
|
|
37
|
+
export default class AppleHealthConnector extends ConnectorRuntime {
|
|
38
|
+
readonly definition: ConnectorDefinition = {
|
|
39
|
+
key: 'apple.health',
|
|
40
|
+
name: 'Apple Health',
|
|
41
|
+
description:
|
|
42
|
+
'Sync Apple Health daily activity summaries and workouts from Lobu on your device. ' +
|
|
43
|
+
'macOS reads HealthKit data synced from the user\'s iPhone (and Apple Watch) via iCloud Health.',
|
|
44
|
+
version: '0.1.0',
|
|
45
|
+
faviconDomain: 'apple.com',
|
|
46
|
+
requiredCapability: 'healthkit',
|
|
47
|
+
runtime: {
|
|
48
|
+
platforms: ['ios', 'macos'],
|
|
49
|
+
scopes: ['steps', 'distance', 'active-calories', 'exercise-minutes', 'workouts', 'resting-heart-rate'],
|
|
50
|
+
},
|
|
51
|
+
authSchema: {
|
|
52
|
+
methods: [{ type: 'none' }],
|
|
53
|
+
},
|
|
54
|
+
feeds: {
|
|
55
|
+
daily_summaries: {
|
|
56
|
+
key: 'daily_summaries',
|
|
57
|
+
name: 'Daily summaries',
|
|
58
|
+
description:
|
|
59
|
+
'Daily Apple Health activity summaries: steps, distance, active energy, ' +
|
|
60
|
+
'exercise minutes, and resting heart rate.',
|
|
61
|
+
configSchema: {
|
|
62
|
+
type: 'object',
|
|
63
|
+
properties: {
|
|
64
|
+
backfill_days: {
|
|
65
|
+
type: 'integer',
|
|
66
|
+
minimum: 1,
|
|
67
|
+
maximum: 3650,
|
|
68
|
+
default: 30,
|
|
69
|
+
description: 'How many days the bridge backfills on a fresh sync (incremental syncs only re-query changed days).',
|
|
70
|
+
},
|
|
71
|
+
},
|
|
72
|
+
},
|
|
73
|
+
eventKinds: {
|
|
74
|
+
health_daily_summary: {
|
|
75
|
+
description: 'A daily summary of Apple Health activity data.',
|
|
76
|
+
metadataSchema: {
|
|
77
|
+
type: 'object',
|
|
78
|
+
required: ['source', 'origin_id', 'date'],
|
|
79
|
+
properties: {
|
|
80
|
+
source: { type: 'string', const: 'apple_health' },
|
|
81
|
+
origin_id: { type: 'string' },
|
|
82
|
+
date: { type: 'string', format: 'date' },
|
|
83
|
+
steps: { type: 'number' },
|
|
84
|
+
distance_m: { type: 'number' },
|
|
85
|
+
active_energy_kcal: { type: 'number' },
|
|
86
|
+
exercise_minutes: { type: 'number' },
|
|
87
|
+
resting_heart_rate_bpm: { type: ['number', 'null'] },
|
|
88
|
+
},
|
|
89
|
+
},
|
|
90
|
+
},
|
|
91
|
+
},
|
|
92
|
+
},
|
|
93
|
+
workouts: {
|
|
94
|
+
key: 'workouts',
|
|
95
|
+
name: 'Workouts',
|
|
96
|
+
description: 'Workout sessions recorded in Apple Health.',
|
|
97
|
+
configSchema: {
|
|
98
|
+
type: 'object',
|
|
99
|
+
properties: {
|
|
100
|
+
backfill_days: {
|
|
101
|
+
type: 'integer',
|
|
102
|
+
minimum: 1,
|
|
103
|
+
maximum: 3650,
|
|
104
|
+
default: 30,
|
|
105
|
+
description: 'How many days the bridge backfills on a fresh sync.',
|
|
106
|
+
},
|
|
107
|
+
},
|
|
108
|
+
},
|
|
109
|
+
eventKinds: {
|
|
110
|
+
health_workout: {
|
|
111
|
+
description: 'A workout recorded in Apple Health.',
|
|
112
|
+
metadataSchema: {
|
|
113
|
+
type: 'object',
|
|
114
|
+
required: ['source', 'origin_id', 'workout_type'],
|
|
115
|
+
properties: {
|
|
116
|
+
source: { type: 'string', const: 'apple_health' },
|
|
117
|
+
origin_id: { type: 'string' },
|
|
118
|
+
workout_type: { type: 'string' },
|
|
119
|
+
started_at: { type: 'string' },
|
|
120
|
+
duration_s: { type: 'number' },
|
|
121
|
+
active_energy_kcal: { type: ['number', 'null'] },
|
|
122
|
+
distance_m: { type: ['number', 'null'] },
|
|
123
|
+
},
|
|
124
|
+
},
|
|
125
|
+
},
|
|
126
|
+
},
|
|
127
|
+
},
|
|
128
|
+
},
|
|
129
|
+
};
|
|
130
|
+
|
|
131
|
+
async sync(_ctx: SyncContext): Promise<SyncResult> {
|
|
132
|
+
throw new Error(BRIDGE_ONLY_MESSAGE);
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
async execute(): Promise<ActionResult> {
|
|
136
|
+
throw new Error(BRIDGE_ONLY_MESSAGE);
|
|
137
|
+
}
|
|
138
|
+
}
|
|
@@ -0,0 +1,178 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Apple Photos Connector (V1 runtime) — Lobu Mac app.
|
|
3
|
+
*
|
|
4
|
+
* Runs on a Mac advertising the `photos` capability. The bridge holds the
|
|
5
|
+
* `NSPhotoLibraryUsageDescription` Info.plist string and prompts the user via
|
|
6
|
+
* TCC the first time a job is claimed. Once granted, PhotoKit exposes the
|
|
7
|
+
* user's local Photos library — which is mirrored from iCloud Photos when
|
|
8
|
+
* that's enabled — including the rich metadata Google's Photos Library API
|
|
9
|
+
* does NOT expose: location (lat/lng), people (Apple's on-device face
|
|
10
|
+
* recognition), albums, captions, keywords, and Vision OCR text.
|
|
11
|
+
*
|
|
12
|
+
* One feed in v1:
|
|
13
|
+
*
|
|
14
|
+
* - `library`: every PHAsset in the user's library, with stable origin ids
|
|
15
|
+
* derived from the asset's localIdentifier. Re-runs upsert by origin id.
|
|
16
|
+
*
|
|
17
|
+
* v1 ingests metadata + remote references (asset_local_id, asset_cloud_id,
|
|
18
|
+
* source_url for the photos.apple.com deep link). The actual image bytes
|
|
19
|
+
* are NOT embedded in events; future connector actions (`fetch_thumbnail`,
|
|
20
|
+
* `fetch_original`) will let an agent pull bytes on demand via the Mac
|
|
21
|
+
* worker.
|
|
22
|
+
*
|
|
23
|
+
* The connector DEFINITION here is the source of truth for shape; EXECUTION
|
|
24
|
+
* lives in the Mac app's PhotosSyncService, which polls /api/workers/* with
|
|
25
|
+
* `photos: true` and streams events back through the standard worker
|
|
26
|
+
* protocol — same `runs` lifecycle as every other device-bound connector.
|
|
27
|
+
*
|
|
28
|
+
* The TS sync()/execute() are safety stubs: if a server-side worker somehow
|
|
29
|
+
* bypassed the capability gate (`required_capability='photos'`), the run
|
|
30
|
+
* throws immediately instead of silently producing zero events.
|
|
31
|
+
*/
|
|
32
|
+
|
|
33
|
+
import {
|
|
34
|
+
type ActionResult,
|
|
35
|
+
type ConnectorDefinition,
|
|
36
|
+
ConnectorRuntime,
|
|
37
|
+
type SyncContext,
|
|
38
|
+
type SyncResult,
|
|
39
|
+
} from '@lobu/connector-sdk';
|
|
40
|
+
|
|
41
|
+
const BRIDGE_ONLY_MESSAGE =
|
|
42
|
+
'apple.photos runs only on a worker advertising capability "photos" (Lobu Mac app with Photos permission). ' +
|
|
43
|
+
'This run was claimed by a worker without that capability — check connector_definitions.required_capability and the poll-time capability filter.';
|
|
44
|
+
|
|
45
|
+
export default class ApplePhotosConnector extends ConnectorRuntime {
|
|
46
|
+
readonly definition: ConnectorDefinition = {
|
|
47
|
+
key: 'apple.photos',
|
|
48
|
+
name: 'Apple Photos',
|
|
49
|
+
description:
|
|
50
|
+
'Sync your Photos library (local or iCloud-mirrored) from the Lobu Mac app. ' +
|
|
51
|
+
'Includes location, people, albums, captions, keywords, and Vision OCR text — ' +
|
|
52
|
+
'data Google Photos\' API does not expose.',
|
|
53
|
+
version: '0.1.0',
|
|
54
|
+
faviconDomain: 'apple.com',
|
|
55
|
+
requiredCapability: 'photos',
|
|
56
|
+
runtime: {
|
|
57
|
+
platforms: ['macos'],
|
|
58
|
+
scopes: ['date', 'location', 'people', 'albums', 'captions', 'keywords', 'ocr'],
|
|
59
|
+
},
|
|
60
|
+
authSchema: {
|
|
61
|
+
methods: [{ type: 'none' }],
|
|
62
|
+
},
|
|
63
|
+
feeds: {
|
|
64
|
+
library: {
|
|
65
|
+
key: 'library',
|
|
66
|
+
name: 'Library',
|
|
67
|
+
description:
|
|
68
|
+
'Every photo in your library. Each event carries the photo\'s metadata ' +
|
|
69
|
+
'(date taken, location, people, albums, captions, OCR text) plus stable ' +
|
|
70
|
+
'asset identifiers so agents can fetch the image bytes on demand.',
|
|
71
|
+
configSchema: {
|
|
72
|
+
type: 'object',
|
|
73
|
+
properties: {
|
|
74
|
+
backfill_days: {
|
|
75
|
+
type: 'integer',
|
|
76
|
+
minimum: 1,
|
|
77
|
+
maximum: 36500,
|
|
78
|
+
default: 3650,
|
|
79
|
+
description:
|
|
80
|
+
'How many days back the bridge backfills on a fresh sync. Default 10 years; ' +
|
|
81
|
+
'incremental runs only re-query the modification window since last_sync_at.',
|
|
82
|
+
},
|
|
83
|
+
include_screenshots: {
|
|
84
|
+
type: 'boolean',
|
|
85
|
+
default: true,
|
|
86
|
+
description: 'Include screenshots (PHAssetMediaSubtype.photoScreenshot).',
|
|
87
|
+
},
|
|
88
|
+
include_videos: {
|
|
89
|
+
type: 'boolean',
|
|
90
|
+
default: false,
|
|
91
|
+
description: 'Include video assets in addition to photos.',
|
|
92
|
+
},
|
|
93
|
+
},
|
|
94
|
+
},
|
|
95
|
+
eventKinds: {
|
|
96
|
+
photo: {
|
|
97
|
+
description:
|
|
98
|
+
'A single photo (or video, if enabled) from the user\'s Apple Photos library. ' +
|
|
99
|
+
'v1 (this PR) populates: asset_local_id, media_type, media_subtypes, ' +
|
|
100
|
+
'date_taken, date_modified, width, height, duration_s, latitude/longitude/altitude_m, ' +
|
|
101
|
+
'albums, is_favorite, is_hidden — everything PhotoKit\'s public API exposes. ' +
|
|
102
|
+
'v2 will add: asset_cloud_id, place_name (reverse geocoding), people, ' +
|
|
103
|
+
'keywords, caption, ocr_text — all of which require direct reads against ' +
|
|
104
|
+
'the Photos.sqlite bundle (FDA + schema-pinned, osxphotos-style). ' +
|
|
105
|
+
'Schema allows nulls so v1 events validate cleanly.',
|
|
106
|
+
metadataSchema: {
|
|
107
|
+
type: 'object',
|
|
108
|
+
required: ['source', 'origin_id', 'asset_local_id'],
|
|
109
|
+
properties: {
|
|
110
|
+
source: { type: 'string', const: 'apple_photos' },
|
|
111
|
+
origin_id: { type: 'string' },
|
|
112
|
+
asset_local_id: {
|
|
113
|
+
type: 'string',
|
|
114
|
+
description: 'PHAsset.localIdentifier — stable per-device handle.',
|
|
115
|
+
},
|
|
116
|
+
asset_cloud_id: {
|
|
117
|
+
type: ['string', 'null'],
|
|
118
|
+
description: 'iCloud asset id when synced via iCloud Photos.',
|
|
119
|
+
},
|
|
120
|
+
media_type: {
|
|
121
|
+
type: 'string',
|
|
122
|
+
enum: ['image', 'video', 'audio', 'unknown'],
|
|
123
|
+
},
|
|
124
|
+
media_subtypes: {
|
|
125
|
+
type: 'array',
|
|
126
|
+
items: { type: 'string' },
|
|
127
|
+
description:
|
|
128
|
+
'PHAssetMediaSubtype flags: live, hdr, screenshot, panorama, portrait, etc.',
|
|
129
|
+
},
|
|
130
|
+
date_taken: { type: ['string', 'null'], format: 'date-time' },
|
|
131
|
+
date_modified: { type: ['string', 'null'], format: 'date-time' },
|
|
132
|
+
width: { type: ['integer', 'null'] },
|
|
133
|
+
height: { type: ['integer', 'null'] },
|
|
134
|
+
duration_s: {
|
|
135
|
+
type: ['number', 'null'],
|
|
136
|
+
description: 'Duration in seconds — videos and Live Photos only.',
|
|
137
|
+
},
|
|
138
|
+
latitude: { type: ['number', 'null'] },
|
|
139
|
+
longitude: { type: ['number', 'null'] },
|
|
140
|
+
altitude_m: { type: ['number', 'null'] },
|
|
141
|
+
place_name: {
|
|
142
|
+
type: ['string', 'null'],
|
|
143
|
+
description:
|
|
144
|
+
'Reverse-geocoded human-readable place from CLGeocoder when available offline.',
|
|
145
|
+
},
|
|
146
|
+
people: {
|
|
147
|
+
type: 'array',
|
|
148
|
+
items: { type: 'string' },
|
|
149
|
+
description: 'Named-person tags from Apple\'s on-device face recognition.',
|
|
150
|
+
},
|
|
151
|
+
albums: {
|
|
152
|
+
type: 'array',
|
|
153
|
+
items: { type: 'string' },
|
|
154
|
+
description: 'User album names this asset belongs to.',
|
|
155
|
+
},
|
|
156
|
+
keywords: {
|
|
157
|
+
type: 'array',
|
|
158
|
+
items: { type: 'string' },
|
|
159
|
+
},
|
|
160
|
+
caption: { type: ['string', 'null'] },
|
|
161
|
+
is_favorite: { type: 'boolean' },
|
|
162
|
+
is_hidden: { type: 'boolean' },
|
|
163
|
+
},
|
|
164
|
+
},
|
|
165
|
+
},
|
|
166
|
+
},
|
|
167
|
+
},
|
|
168
|
+
},
|
|
169
|
+
};
|
|
170
|
+
|
|
171
|
+
async sync(_ctx: SyncContext): Promise<SyncResult> {
|
|
172
|
+
throw new Error(BRIDGE_ONLY_MESSAGE);
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
async execute(): Promise<ActionResult> {
|
|
176
|
+
throw new Error(BRIDGE_ONLY_MESSAGE);
|
|
177
|
+
}
|
|
178
|
+
}
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Apple Screen Time Connector (V1 runtime) — Lobu for Mac only.
|
|
3
|
+
*
|
|
4
|
+
* Runs on Lobu for Mac, which reads `~/Library/Application Support/
|
|
5
|
+
* Knowledge/knowledgeC.db` (the on-device Knowledge store backing Apple's
|
|
6
|
+
* Settings → Screen Time UI). With Full Disk Access granted, the Mac can
|
|
7
|
+
* pull per-app foreground time by day for both Mac usage and (if the user
|
|
8
|
+
* enables Screen Time iCloud sync) iOS usage.
|
|
9
|
+
*
|
|
10
|
+
* iOS does NOT advertise the `screentime` capability — Apple's
|
|
11
|
+
* FamilyControls + DeviceActivityReport design prevents per-app data from
|
|
12
|
+
* leaving the device on iOS. The Mac path is the workable one.
|
|
13
|
+
*/
|
|
14
|
+
|
|
15
|
+
import {
|
|
16
|
+
type ActionResult,
|
|
17
|
+
type ConnectorDefinition,
|
|
18
|
+
ConnectorRuntime,
|
|
19
|
+
type SyncContext,
|
|
20
|
+
type SyncResult,
|
|
21
|
+
} from '@lobu/connector-sdk';
|
|
22
|
+
|
|
23
|
+
const BRIDGE_ONLY =
|
|
24
|
+
'Apple Screen Time runs only on a worker advertising capability "screentime" (Lobu for Mac with Full Disk Access).';
|
|
25
|
+
|
|
26
|
+
export default class AppleScreenTimeConnector extends ConnectorRuntime {
|
|
27
|
+
readonly definition: ConnectorDefinition = {
|
|
28
|
+
key: 'apple.screen_time',
|
|
29
|
+
name: 'Apple Screen Time',
|
|
30
|
+
description:
|
|
31
|
+
'Daily per-app usage totals from Lobu for Mac, sourced from the Apple Knowledge store. Captures both Mac usage and (if Screen Time iCloud sync is on) the user\'s iOS device usage.',
|
|
32
|
+
version: '0.1.0',
|
|
33
|
+
faviconDomain: 'apple.com',
|
|
34
|
+
requiredCapability: 'screentime',
|
|
35
|
+
runtime: { platforms: ['macos'] },
|
|
36
|
+
authSchema: { methods: [{ type: 'none' }] },
|
|
37
|
+
feeds: {
|
|
38
|
+
daily_app_usage: {
|
|
39
|
+
key: 'daily_app_usage',
|
|
40
|
+
name: 'Daily app usage',
|
|
41
|
+
description:
|
|
42
|
+
'Per-day total foreground time for each application (identified by bundle id).',
|
|
43
|
+
configSchema: {
|
|
44
|
+
type: 'object',
|
|
45
|
+
properties: {
|
|
46
|
+
backfill_days: {
|
|
47
|
+
type: 'integer',
|
|
48
|
+
minimum: 1,
|
|
49
|
+
maximum: 90,
|
|
50
|
+
default: 14,
|
|
51
|
+
description: 'How many days the bridge should backfill on each sync.',
|
|
52
|
+
},
|
|
53
|
+
},
|
|
54
|
+
},
|
|
55
|
+
eventKinds: {
|
|
56
|
+
screen_time_daily_app: {
|
|
57
|
+
description: 'Total time the user spent in one application on a given day.',
|
|
58
|
+
metadataSchema: {
|
|
59
|
+
type: 'object',
|
|
60
|
+
required: ['source', 'origin_id', 'date', 'bundle_id', 'seconds'],
|
|
61
|
+
properties: {
|
|
62
|
+
source: { type: 'string', const: 'apple_screen_time' },
|
|
63
|
+
origin_id: { type: 'string' },
|
|
64
|
+
date: { type: 'string', format: 'date' },
|
|
65
|
+
bundle_id: { type: 'string' },
|
|
66
|
+
seconds: { type: 'number', minimum: 0 },
|
|
67
|
+
},
|
|
68
|
+
},
|
|
69
|
+
},
|
|
70
|
+
},
|
|
71
|
+
},
|
|
72
|
+
},
|
|
73
|
+
};
|
|
74
|
+
|
|
75
|
+
async sync(_ctx: SyncContext): Promise<SyncResult> {
|
|
76
|
+
throw new Error(BRIDGE_ONLY);
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
async execute(): Promise<ActionResult> {
|
|
80
|
+
throw new Error(BRIDGE_ONLY);
|
|
81
|
+
}
|
|
82
|
+
}
|