@odla-ai/cli 0.11.1 → 0.12.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/README.md +6 -1
- package/dist/bin.cjs +566 -332
- package/dist/bin.cjs.map +1 -1
- package/dist/bin.js +3 -2
- package/dist/bin.js.map +1 -1
- package/dist/{chunk-DC4MIB4X.js → chunk-Y4HWUEFF.js} +488 -256
- package/dist/chunk-Y4HWUEFF.js.map +1 -0
- package/dist/index.cjs +569 -335
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +50 -51
- package/dist/index.d.ts +50 -51
- package/dist/index.js +5 -5
- package/package.json +1 -1
- package/skills/odla/SKILL.md +40 -10
- package/skills/odla/references/build.md +27 -20
- package/skills/odla/references/sdks.md +29 -17
- package/skills/odla-migrate/SKILL.md +25 -6
- package/skills/odla-migrate/references/phase-1-static.md +5 -1
- package/skills/odla-migrate/references/phase-2b-calendar.md +130 -42
- package/skills/odla-migrate/references/phase-3-auth.md +5 -0
- package/skills/odla-migrate/references/secrets-map.md +3 -0
- package/skills/odla-migrate/references/troubleshooting.md +16 -5
- package/dist/chunk-DC4MIB4X.js.map +0 -1
package/dist/index.d.cts
CHANGED
|
@@ -2,6 +2,10 @@ import { SecurityReport, PlatformSecurityRun } from '@odla-ai/security';
|
|
|
2
2
|
import { HostedSecurityJob, GitHubConnectionStatus, GitHubSecuritySource, HostedSecurityIntentResponse, HostedSecurityPlan, HostedSecurityReport, HostedSecurityJobStatus } from '@odla-ai/security/hosted';
|
|
3
3
|
export { GitHubConnectionAttempt, GitHubConnectionStatus, GitHubSecuritySource, HostedSecurityCounts, HostedSecurityCoverage, HostedSecurityIntent, HostedSecurityIntentResponse, HostedSecurityJob, HostedSecurityJobStatus, HostedSecurityPlan, HostedSecurityPlanRoute, HostedSecurityReport, HostedSecurityReportFinding, HostedSecurityRoute } from '@odla-ai/security/hosted';
|
|
4
4
|
|
|
5
|
+
/** Map a CLI failure to its process exit code: 75 (EX_TEMPFAIL) marks a
|
|
6
|
+
* handshake that is still awaiting human approval — the pending state is
|
|
7
|
+
* persisted and rerunning the same command resumes it — everything else is 1. */
|
|
8
|
+
declare function exitCodeFor(err: unknown): number;
|
|
5
9
|
/** Injectable side-effect boundaries used to run and test the command dispatcher. */
|
|
6
10
|
interface CliDependencies {
|
|
7
11
|
fetch?: typeof fetch;
|
|
@@ -95,7 +99,7 @@ declare function adminAi(options: AdminAiOptions): Promise<void>;
|
|
|
95
99
|
/** Stable, machine-readable division of work between the CLI, coding agent,
|
|
96
100
|
* human operator, and Studio. Printed by `odla-ai capabilities --json`. */
|
|
97
101
|
declare const CAPABILITIES: {
|
|
98
|
-
readonly cli: readonly ["start an email-bound device request without accepting a password or user session token", "register the app and enable configured services per environment", "issue, persist, and explicitly rotate configured service credentials", "write local Worker values and push deployed Worker secrets through Wrangler stdin", "store tenant-vault secrets (including the Clerk webhook secret and reserved Clerk secret key) write-only from stdin or an env var", "push db schema/rules and configure platform AI, auth, and deployment links", "apply
|
|
102
|
+
readonly cli: readonly ["start an email-bound device request without accepting a password or user session token", "register the app and enable configured services per environment", "issue, persist, and explicitly rotate configured service credentials", "write local Worker values and push deployed Worker secrets through Wrangler stdin", "store tenant-vault secrets (including the Clerk webhook secret and reserved Clerk secret key) write-only from stdin or an env var", "push db schema/rules and configure platform AI, auth, and deployment links", "apply Google Calendar booking config, then drive state-bound consent, status, discovery, and disconnect flows (bookings run live through the platform proxy)", "validate config offline and smoke-test a provisioned db environment", "run app-attributed hosted security discovery and independent validation without provider keys", "connect/revoke source-read-only GitHub sources and drive commit-pinned hosted security jobs without PATs or provider keys", "let admins manage system AI policy and credentials, inspect attributed usage, and read immutable admin changes through separate short-lived capability-only approvals"];
|
|
99
103
|
readonly agent: readonly ["install and import the selected odla SDKs", "wrap the Worker with withObservability and choose useful telemetry", "make application-specific schema, rules, auth, UI, and migration decisions", "wire @odla-ai/calendar into trusted Worker code and keep the app admin key out of browsers"];
|
|
100
104
|
readonly human: readonly ["provide the existing odla account email, then sign in and explicitly review/approve the exact device code", "review mirrored calendar/attendee disclosure and complete the server-issued Google consent flow", "consent to production changes with --yes", "request destructive credential rotation explicitly", "review application semantics, security findings, releases, and merges", "approve redacted-source disclosure before hosted security reasoning", "approve GitHub App repository access separately from redacted-snippet disclosure"];
|
|
101
105
|
readonly studio: readonly ["view telemetry and environment state", "let signed-in users inventory/revoke their own agent grants and admins audit/global-revoke them", "review calendar connection, granted read scope, selected calendars, and sync health without exposing provider tokens", "perform manual credential recovery when the CLI's local shown-once copy is unavailable", "configure system AI purposes and view app/environment/run-attributed usage", "connect/revoke GitHub security sources and inspect ref-to-SHA jobs, routes, retention, coverage, and normalized reports"];
|
|
@@ -104,29 +108,28 @@ type Output = Pick<typeof console, "log">;
|
|
|
104
108
|
/** Print the stable responsibility boundary for humans or agent tooling. */
|
|
105
109
|
declare function printCapabilities(json?: boolean, out?: Output): void;
|
|
106
110
|
|
|
107
|
-
declare const CALENDAR_STATES: readonly ["not_connected", "authorizing", "
|
|
108
|
-
/** Connection lifecycle reported by the registry; mirrors the platform's
|
|
111
|
+
declare const CALENDAR_STATES: readonly ["not_connected", "authorizing", "healthy", "degraded", "disconnected", "failed"];
|
|
112
|
+
/** Connection lifecycle reported by the registry; mirrors the platform's
|
|
113
|
+
* calendar states. `degraded` means connected but re-consent is required. */
|
|
109
114
|
type CalendarConnectionState = (typeof CALENDAR_STATES)[number];
|
|
110
|
-
/** Owner-visible, secret-free calendar connection
|
|
115
|
+
/** Owner-visible, secret-free calendar connection health. */
|
|
111
116
|
interface CalendarStatus {
|
|
112
117
|
env: string;
|
|
113
118
|
enabled: boolean;
|
|
114
119
|
/** True when the platform has provider credentials for this connection. */
|
|
115
120
|
connected: boolean;
|
|
121
|
+
/** True when the grant covers booking writes; false means reconnect. */
|
|
122
|
+
writable: boolean;
|
|
116
123
|
provider: "google" | null;
|
|
117
124
|
status: CalendarConnectionState;
|
|
118
|
-
access?: "
|
|
125
|
+
access?: "book";
|
|
126
|
+
/** Calendar that receives created bookings. */
|
|
127
|
+
bookingCalendarId?: string;
|
|
128
|
+
/** Calendars consulted for FreeBusy availability. */
|
|
119
129
|
calendars: string[];
|
|
120
|
-
attendeePolicy?: "full" | "hashed";
|
|
121
|
-
/** True once a booking projection may have established the DB privacy policy. */
|
|
122
|
-
attendeePolicyLocked?: boolean;
|
|
123
130
|
bookingPageUrl?: string | null;
|
|
124
131
|
grantedScopes: string[];
|
|
125
132
|
attemptId?: string;
|
|
126
|
-
lastSuccessfulSyncAt?: number;
|
|
127
|
-
lastFullSyncAt?: number;
|
|
128
|
-
watchExpiresAt?: number;
|
|
129
|
-
bookingCount?: number;
|
|
130
133
|
error?: {
|
|
131
134
|
code?: string;
|
|
132
135
|
message?: string;
|
|
@@ -142,9 +145,9 @@ interface AvailableGoogleCalendar {
|
|
|
142
145
|
}
|
|
143
146
|
|
|
144
147
|
/** Shared inputs for the calendar lifecycle commands (status, connect,
|
|
145
|
-
* calendars,
|
|
146
|
-
*
|
|
147
|
-
*
|
|
148
|
+
* calendars, disconnect): the project config path and env, plus injectable
|
|
149
|
+
* token, output, browser, clock, and polling hooks so agents and tests can
|
|
150
|
+
* drive the flow deterministically. */
|
|
148
151
|
interface CalendarLifecycleOptions {
|
|
149
152
|
/** Path to the checked-in odla project config. */ configPath: string;
|
|
150
153
|
/** Configured environment; defaults to dev when present. */ env?: string;
|
|
@@ -161,16 +164,17 @@ interface CalendarLifecycleOptions {
|
|
|
161
164
|
now?: () => number;
|
|
162
165
|
signal?: AbortSignal;
|
|
163
166
|
}
|
|
164
|
-
/** Read the owner-visible Google connection and
|
|
167
|
+
/** Read the owner-visible Google connection and booking health for one env. */
|
|
165
168
|
declare function calendarStatus(options: CalendarLifecycleOptions): Promise<CalendarStatus>;
|
|
166
169
|
/** List calendars visible to the connected Google identity for config authoring. */
|
|
167
170
|
declare function calendarCalendars(options: CalendarLifecycleOptions): Promise<AvailableGoogleCalendar[]>;
|
|
168
|
-
/** Apply the
|
|
171
|
+
/** Apply the optional booking-page setting, then complete Google consent.
|
|
172
|
+
* A connection whose grant predates booking scopes (`degraded`) re-runs
|
|
173
|
+
* consent so the platform can create events and read FreeBusy. */
|
|
169
174
|
declare function calendarConnect(options: CalendarLifecycleOptions): Promise<CalendarStatus>;
|
|
170
|
-
/**
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
* without purging the mirror or revoking the shared Google project grant. */
|
|
175
|
+
/** Delete this connection's encrypted platform tokens. No calendar data is
|
|
176
|
+
* stored anywhere, so there is nothing else to clean up; the shared Google
|
|
177
|
+
* project grant is not revoked. */
|
|
174
178
|
declare function calendarDisconnect(options: CalendarLifecycleOptions): Promise<CalendarStatus>;
|
|
175
179
|
|
|
176
180
|
interface RunResult {
|
|
@@ -196,42 +200,32 @@ interface ClerkAuthConfig {
|
|
|
196
200
|
audience?: string;
|
|
197
201
|
mode?: "client" | "full";
|
|
198
202
|
}
|
|
199
|
-
/**
|
|
200
|
-
|
|
201
|
-
/** Mirror only events whose summary begins with this value. */
|
|
202
|
-
summaryPrefix?: string;
|
|
203
|
-
/** Require the connected identity to organize the event. Defaults to true. */
|
|
204
|
-
organizerSelf?: boolean;
|
|
205
|
-
/** Require at least one attendee. Defaults to true. */
|
|
206
|
-
requireAttendees?: boolean;
|
|
207
|
-
}
|
|
208
|
-
/** Google Calendar intent. OAuth credentials never belong in this config. */
|
|
203
|
+
/** Google Calendar booking intent. OAuth credentials never belong in this
|
|
204
|
+
* config, and no calendar data is mirrored — Google is the source of truth. */
|
|
209
205
|
interface GoogleCalendarConfig {
|
|
210
|
-
/** One through ten
|
|
211
|
-
|
|
212
|
-
/**
|
|
206
|
+
/** One through ten calendars consulted for availability in each env. */
|
|
207
|
+
availabilityCalendars?: Record<OdlaEnvName, string[]>;
|
|
208
|
+
/** Retired read-mirror spelling of `availabilityCalendars` (still accepted). */
|
|
209
|
+
calendars?: Record<OdlaEnvName, string[]>;
|
|
210
|
+
/** Calendar that receives created bookings per env ("primary" or a concrete
|
|
211
|
+
* id). Defaults to the first availability calendar. */
|
|
212
|
+
bookingCalendar?: Record<OdlaEnvName, string>;
|
|
213
|
+
/** Optional public fallback link (retiring; first-party booking replaces it). */
|
|
213
214
|
bookingPageUrl?: Record<OdlaEnvName, string | null>;
|
|
214
|
-
match?: GoogleCalendarMatchConfig;
|
|
215
|
-
/** Store normalized attendee addresses, or only SHA-256 match keys. */
|
|
216
|
-
attendeePolicy?: "full" | "hashed";
|
|
217
215
|
}
|
|
218
|
-
/** The `calendar` block of `odla.config.mjs` — the Google
|
|
219
|
-
*
|
|
216
|
+
/** The `calendar` block of `odla.config.mjs` — the Google booking settings;
|
|
217
|
+
* valid only alongside the db service (booking rides the app's db key). */
|
|
220
218
|
interface CalendarConfig {
|
|
221
219
|
google: GoogleCalendarConfig;
|
|
222
220
|
}
|
|
223
221
|
/** Canonical, environment-specific config sent to the calendar controller. */
|
|
224
222
|
interface CalendarServiceConfig extends Record<string, unknown> {
|
|
225
223
|
provider: "google";
|
|
226
|
-
access: "
|
|
227
|
-
/**
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
requireAttendees: boolean;
|
|
232
|
-
summaryPrefix?: string;
|
|
233
|
-
};
|
|
234
|
-
attendeePolicy: "full" | "hashed";
|
|
224
|
+
access: "book";
|
|
225
|
+
/** Calendar that receives created bookings. */
|
|
226
|
+
bookingCalendarId: string;
|
|
227
|
+
/** Deduplicated provider ids; the booking proxy accepts at most ten. */
|
|
228
|
+
availabilityCalendars: string[];
|
|
235
229
|
}
|
|
236
230
|
/** Authored `odla.config.mjs` contract consumed by doctor and provision. */
|
|
237
231
|
interface OdlaProjectConfig {
|
|
@@ -325,6 +319,11 @@ interface ProvisionOptions {
|
|
|
325
319
|
/** true forces browser launch, false disables it, undefined auto-opens whenever
|
|
326
320
|
* this machine can show a browser (skipped in CI, over SSH, or with no display). */
|
|
327
321
|
open?: boolean;
|
|
322
|
+
/** Cap the handshake-approval wait, in seconds. When it elapses the command
|
|
323
|
+
* exits with the pending handshake persisted; rerunning resumes it. Defaults
|
|
324
|
+
* to the handshake's own expiry on an interactive terminal and 90 seconds
|
|
325
|
+
* everywhere else (agent tool shells kill long-running commands). */
|
|
326
|
+
wait?: number;
|
|
328
327
|
/** Test/embedding override for opening the approval URL. Defaults to the OS browser opener. */
|
|
329
328
|
openApprovalUrl?: (url: string) => Promise<void>;
|
|
330
329
|
/** Test/embedding override for calendar connection polling. */
|
|
@@ -364,8 +363,8 @@ interface SmokeOptions {
|
|
|
364
363
|
stdout?: Pick<typeof console, "log" | "error">;
|
|
365
364
|
}
|
|
366
365
|
|
|
367
|
-
/** The
|
|
368
|
-
declare const
|
|
366
|
+
/** The Google OAuth scope that authorizes booking writes (events read/write). */
|
|
367
|
+
declare const GOOGLE_CALENDAR_EVENTS_SCOPE = "https://www.googleapis.com/auth/calendar.events";
|
|
369
368
|
/** Resolve the checked-in calendar block into one controller-safe env payload. */
|
|
370
369
|
declare function calendarServiceConfig(cfg: LoadedProjectConfig, env: string): CalendarServiceConfig;
|
|
371
370
|
/** Public Appointment Schedule URL to apply separately from connector config. */
|
|
@@ -803,4 +802,4 @@ declare function installSkill(options?: SkillInstallOptions): SkillInstallResult
|
|
|
803
802
|
*/
|
|
804
803
|
declare function smoke(options: SmokeOptions): Promise<void>;
|
|
805
804
|
|
|
806
|
-
export { AGENT_HARNESSES, type AdminAiOptions, type AgentHarness, type AgentHarnessSelector, type AvailableGoogleCalendar, CAPABILITIES, type CalendarConfig, type CalendarConnectionState, type CalendarLifecycleOptions, type CalendarServiceConfig, type CalendarStatus, type CliDependencies, type ConnectGitHubSecuritySourceOptions, type DisconnectGitHubSecuritySourceOptions, type FollowHostedSecurityJobOptions,
|
|
805
|
+
export { AGENT_HARNESSES, type AdminAiOptions, type AgentHarness, type AgentHarnessSelector, type AvailableGoogleCalendar, CAPABILITIES, type CalendarConfig, type CalendarConnectionState, type CalendarLifecycleOptions, type CalendarServiceConfig, type CalendarStatus, type CliDependencies, type ConnectGitHubSecuritySourceOptions, type DisconnectGitHubSecuritySourceOptions, type FollowHostedSecurityJobOptions, GOOGLE_CALENDAR_EVENTS_SCOPE, type GetHostedSecurityIntentOptions, type GetHostedSecurityJobOptions, type GoogleCalendarConfig, type HarnessInstallResult, type HostedSecurityProfile, type HostedSecurityResult, type HostedSecurityTokenRequest, type ListGitHubSecuritySourcesOptions, type ListHostedSecurityJobsOptions, type LoadedProjectConfig, type LocalCredentials, type OdlaProjectConfig, type ProvisionOptions, type ProvisionPlan, type RunHostedSecurityOptions, SYSTEM_AI_PURPOSES, type ScopedPlatformTokenOptions, type SecretsPushOptions, type SecretsSetOptions, type SkillInstallOptions, type SkillInstallResult, type SmokeOptions, type StartHostedSecurityJobOptions, type SystemAiPurpose, adminAi, calendarBookingPageUrl, calendarCalendars, calendarConnect, calendarDisconnect, calendarServiceConfig, calendarStatus, connectGitHubSecuritySource, disconnectGitHubSecuritySource, doctor, exitCodeFor, followHostedSecurityJob, getHostedSecurityIntent, getHostedSecurityJob, getHostedSecurityPlan, getHostedSecurityReport, getScopedPlatformToken, inferGitHubRepository, initProject, installSkill, isTerminalHostedSecurityStatus, listGitHubSecuritySources, listHostedSecurityJobs, printCapabilities, provision, redactSecrets, repositoryFromGitRemote, runCli, runHostedSecurity, secretsPush, secretsSet, secretsSetClerkKey, smoke, startHostedSecurityJob };
|
package/dist/index.d.ts
CHANGED
|
@@ -2,6 +2,10 @@ import { SecurityReport, PlatformSecurityRun } from '@odla-ai/security';
|
|
|
2
2
|
import { HostedSecurityJob, GitHubConnectionStatus, GitHubSecuritySource, HostedSecurityIntentResponse, HostedSecurityPlan, HostedSecurityReport, HostedSecurityJobStatus } from '@odla-ai/security/hosted';
|
|
3
3
|
export { GitHubConnectionAttempt, GitHubConnectionStatus, GitHubSecuritySource, HostedSecurityCounts, HostedSecurityCoverage, HostedSecurityIntent, HostedSecurityIntentResponse, HostedSecurityJob, HostedSecurityJobStatus, HostedSecurityPlan, HostedSecurityPlanRoute, HostedSecurityReport, HostedSecurityReportFinding, HostedSecurityRoute } from '@odla-ai/security/hosted';
|
|
4
4
|
|
|
5
|
+
/** Map a CLI failure to its process exit code: 75 (EX_TEMPFAIL) marks a
|
|
6
|
+
* handshake that is still awaiting human approval — the pending state is
|
|
7
|
+
* persisted and rerunning the same command resumes it — everything else is 1. */
|
|
8
|
+
declare function exitCodeFor(err: unknown): number;
|
|
5
9
|
/** Injectable side-effect boundaries used to run and test the command dispatcher. */
|
|
6
10
|
interface CliDependencies {
|
|
7
11
|
fetch?: typeof fetch;
|
|
@@ -95,7 +99,7 @@ declare function adminAi(options: AdminAiOptions): Promise<void>;
|
|
|
95
99
|
/** Stable, machine-readable division of work between the CLI, coding agent,
|
|
96
100
|
* human operator, and Studio. Printed by `odla-ai capabilities --json`. */
|
|
97
101
|
declare const CAPABILITIES: {
|
|
98
|
-
readonly cli: readonly ["start an email-bound device request without accepting a password or user session token", "register the app and enable configured services per environment", "issue, persist, and explicitly rotate configured service credentials", "write local Worker values and push deployed Worker secrets through Wrangler stdin", "store tenant-vault secrets (including the Clerk webhook secret and reserved Clerk secret key) write-only from stdin or an env var", "push db schema/rules and configure platform AI, auth, and deployment links", "apply
|
|
102
|
+
readonly cli: readonly ["start an email-bound device request without accepting a password or user session token", "register the app and enable configured services per environment", "issue, persist, and explicitly rotate configured service credentials", "write local Worker values and push deployed Worker secrets through Wrangler stdin", "store tenant-vault secrets (including the Clerk webhook secret and reserved Clerk secret key) write-only from stdin or an env var", "push db schema/rules and configure platform AI, auth, and deployment links", "apply Google Calendar booking config, then drive state-bound consent, status, discovery, and disconnect flows (bookings run live through the platform proxy)", "validate config offline and smoke-test a provisioned db environment", "run app-attributed hosted security discovery and independent validation without provider keys", "connect/revoke source-read-only GitHub sources and drive commit-pinned hosted security jobs without PATs or provider keys", "let admins manage system AI policy and credentials, inspect attributed usage, and read immutable admin changes through separate short-lived capability-only approvals"];
|
|
99
103
|
readonly agent: readonly ["install and import the selected odla SDKs", "wrap the Worker with withObservability and choose useful telemetry", "make application-specific schema, rules, auth, UI, and migration decisions", "wire @odla-ai/calendar into trusted Worker code and keep the app admin key out of browsers"];
|
|
100
104
|
readonly human: readonly ["provide the existing odla account email, then sign in and explicitly review/approve the exact device code", "review mirrored calendar/attendee disclosure and complete the server-issued Google consent flow", "consent to production changes with --yes", "request destructive credential rotation explicitly", "review application semantics, security findings, releases, and merges", "approve redacted-source disclosure before hosted security reasoning", "approve GitHub App repository access separately from redacted-snippet disclosure"];
|
|
101
105
|
readonly studio: readonly ["view telemetry and environment state", "let signed-in users inventory/revoke their own agent grants and admins audit/global-revoke them", "review calendar connection, granted read scope, selected calendars, and sync health without exposing provider tokens", "perform manual credential recovery when the CLI's local shown-once copy is unavailable", "configure system AI purposes and view app/environment/run-attributed usage", "connect/revoke GitHub security sources and inspect ref-to-SHA jobs, routes, retention, coverage, and normalized reports"];
|
|
@@ -104,29 +108,28 @@ type Output = Pick<typeof console, "log">;
|
|
|
104
108
|
/** Print the stable responsibility boundary for humans or agent tooling. */
|
|
105
109
|
declare function printCapabilities(json?: boolean, out?: Output): void;
|
|
106
110
|
|
|
107
|
-
declare const CALENDAR_STATES: readonly ["not_connected", "authorizing", "
|
|
108
|
-
/** Connection lifecycle reported by the registry; mirrors the platform's
|
|
111
|
+
declare const CALENDAR_STATES: readonly ["not_connected", "authorizing", "healthy", "degraded", "disconnected", "failed"];
|
|
112
|
+
/** Connection lifecycle reported by the registry; mirrors the platform's
|
|
113
|
+
* calendar states. `degraded` means connected but re-consent is required. */
|
|
109
114
|
type CalendarConnectionState = (typeof CALENDAR_STATES)[number];
|
|
110
|
-
/** Owner-visible, secret-free calendar connection
|
|
115
|
+
/** Owner-visible, secret-free calendar connection health. */
|
|
111
116
|
interface CalendarStatus {
|
|
112
117
|
env: string;
|
|
113
118
|
enabled: boolean;
|
|
114
119
|
/** True when the platform has provider credentials for this connection. */
|
|
115
120
|
connected: boolean;
|
|
121
|
+
/** True when the grant covers booking writes; false means reconnect. */
|
|
122
|
+
writable: boolean;
|
|
116
123
|
provider: "google" | null;
|
|
117
124
|
status: CalendarConnectionState;
|
|
118
|
-
access?: "
|
|
125
|
+
access?: "book";
|
|
126
|
+
/** Calendar that receives created bookings. */
|
|
127
|
+
bookingCalendarId?: string;
|
|
128
|
+
/** Calendars consulted for FreeBusy availability. */
|
|
119
129
|
calendars: string[];
|
|
120
|
-
attendeePolicy?: "full" | "hashed";
|
|
121
|
-
/** True once a booking projection may have established the DB privacy policy. */
|
|
122
|
-
attendeePolicyLocked?: boolean;
|
|
123
130
|
bookingPageUrl?: string | null;
|
|
124
131
|
grantedScopes: string[];
|
|
125
132
|
attemptId?: string;
|
|
126
|
-
lastSuccessfulSyncAt?: number;
|
|
127
|
-
lastFullSyncAt?: number;
|
|
128
|
-
watchExpiresAt?: number;
|
|
129
|
-
bookingCount?: number;
|
|
130
133
|
error?: {
|
|
131
134
|
code?: string;
|
|
132
135
|
message?: string;
|
|
@@ -142,9 +145,9 @@ interface AvailableGoogleCalendar {
|
|
|
142
145
|
}
|
|
143
146
|
|
|
144
147
|
/** Shared inputs for the calendar lifecycle commands (status, connect,
|
|
145
|
-
* calendars,
|
|
146
|
-
*
|
|
147
|
-
*
|
|
148
|
+
* calendars, disconnect): the project config path and env, plus injectable
|
|
149
|
+
* token, output, browser, clock, and polling hooks so agents and tests can
|
|
150
|
+
* drive the flow deterministically. */
|
|
148
151
|
interface CalendarLifecycleOptions {
|
|
149
152
|
/** Path to the checked-in odla project config. */ configPath: string;
|
|
150
153
|
/** Configured environment; defaults to dev when present. */ env?: string;
|
|
@@ -161,16 +164,17 @@ interface CalendarLifecycleOptions {
|
|
|
161
164
|
now?: () => number;
|
|
162
165
|
signal?: AbortSignal;
|
|
163
166
|
}
|
|
164
|
-
/** Read the owner-visible Google connection and
|
|
167
|
+
/** Read the owner-visible Google connection and booking health for one env. */
|
|
165
168
|
declare function calendarStatus(options: CalendarLifecycleOptions): Promise<CalendarStatus>;
|
|
166
169
|
/** List calendars visible to the connected Google identity for config authoring. */
|
|
167
170
|
declare function calendarCalendars(options: CalendarLifecycleOptions): Promise<AvailableGoogleCalendar[]>;
|
|
168
|
-
/** Apply the
|
|
171
|
+
/** Apply the optional booking-page setting, then complete Google consent.
|
|
172
|
+
* A connection whose grant predates booking scopes (`degraded`) re-runs
|
|
173
|
+
* consent so the platform can create events and read FreeBusy. */
|
|
169
174
|
declare function calendarConnect(options: CalendarLifecycleOptions): Promise<CalendarStatus>;
|
|
170
|
-
/**
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
* without purging the mirror or revoking the shared Google project grant. */
|
|
175
|
+
/** Delete this connection's encrypted platform tokens. No calendar data is
|
|
176
|
+
* stored anywhere, so there is nothing else to clean up; the shared Google
|
|
177
|
+
* project grant is not revoked. */
|
|
174
178
|
declare function calendarDisconnect(options: CalendarLifecycleOptions): Promise<CalendarStatus>;
|
|
175
179
|
|
|
176
180
|
interface RunResult {
|
|
@@ -196,42 +200,32 @@ interface ClerkAuthConfig {
|
|
|
196
200
|
audience?: string;
|
|
197
201
|
mode?: "client" | "full";
|
|
198
202
|
}
|
|
199
|
-
/**
|
|
200
|
-
|
|
201
|
-
/** Mirror only events whose summary begins with this value. */
|
|
202
|
-
summaryPrefix?: string;
|
|
203
|
-
/** Require the connected identity to organize the event. Defaults to true. */
|
|
204
|
-
organizerSelf?: boolean;
|
|
205
|
-
/** Require at least one attendee. Defaults to true. */
|
|
206
|
-
requireAttendees?: boolean;
|
|
207
|
-
}
|
|
208
|
-
/** Google Calendar intent. OAuth credentials never belong in this config. */
|
|
203
|
+
/** Google Calendar booking intent. OAuth credentials never belong in this
|
|
204
|
+
* config, and no calendar data is mirrored — Google is the source of truth. */
|
|
209
205
|
interface GoogleCalendarConfig {
|
|
210
|
-
/** One through ten
|
|
211
|
-
|
|
212
|
-
/**
|
|
206
|
+
/** One through ten calendars consulted for availability in each env. */
|
|
207
|
+
availabilityCalendars?: Record<OdlaEnvName, string[]>;
|
|
208
|
+
/** Retired read-mirror spelling of `availabilityCalendars` (still accepted). */
|
|
209
|
+
calendars?: Record<OdlaEnvName, string[]>;
|
|
210
|
+
/** Calendar that receives created bookings per env ("primary" or a concrete
|
|
211
|
+
* id). Defaults to the first availability calendar. */
|
|
212
|
+
bookingCalendar?: Record<OdlaEnvName, string>;
|
|
213
|
+
/** Optional public fallback link (retiring; first-party booking replaces it). */
|
|
213
214
|
bookingPageUrl?: Record<OdlaEnvName, string | null>;
|
|
214
|
-
match?: GoogleCalendarMatchConfig;
|
|
215
|
-
/** Store normalized attendee addresses, or only SHA-256 match keys. */
|
|
216
|
-
attendeePolicy?: "full" | "hashed";
|
|
217
215
|
}
|
|
218
|
-
/** The `calendar` block of `odla.config.mjs` — the Google
|
|
219
|
-
*
|
|
216
|
+
/** The `calendar` block of `odla.config.mjs` — the Google booking settings;
|
|
217
|
+
* valid only alongside the db service (booking rides the app's db key). */
|
|
220
218
|
interface CalendarConfig {
|
|
221
219
|
google: GoogleCalendarConfig;
|
|
222
220
|
}
|
|
223
221
|
/** Canonical, environment-specific config sent to the calendar controller. */
|
|
224
222
|
interface CalendarServiceConfig extends Record<string, unknown> {
|
|
225
223
|
provider: "google";
|
|
226
|
-
access: "
|
|
227
|
-
/**
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
requireAttendees: boolean;
|
|
232
|
-
summaryPrefix?: string;
|
|
233
|
-
};
|
|
234
|
-
attendeePolicy: "full" | "hashed";
|
|
224
|
+
access: "book";
|
|
225
|
+
/** Calendar that receives created bookings. */
|
|
226
|
+
bookingCalendarId: string;
|
|
227
|
+
/** Deduplicated provider ids; the booking proxy accepts at most ten. */
|
|
228
|
+
availabilityCalendars: string[];
|
|
235
229
|
}
|
|
236
230
|
/** Authored `odla.config.mjs` contract consumed by doctor and provision. */
|
|
237
231
|
interface OdlaProjectConfig {
|
|
@@ -325,6 +319,11 @@ interface ProvisionOptions {
|
|
|
325
319
|
/** true forces browser launch, false disables it, undefined auto-opens whenever
|
|
326
320
|
* this machine can show a browser (skipped in CI, over SSH, or with no display). */
|
|
327
321
|
open?: boolean;
|
|
322
|
+
/** Cap the handshake-approval wait, in seconds. When it elapses the command
|
|
323
|
+
* exits with the pending handshake persisted; rerunning resumes it. Defaults
|
|
324
|
+
* to the handshake's own expiry on an interactive terminal and 90 seconds
|
|
325
|
+
* everywhere else (agent tool shells kill long-running commands). */
|
|
326
|
+
wait?: number;
|
|
328
327
|
/** Test/embedding override for opening the approval URL. Defaults to the OS browser opener. */
|
|
329
328
|
openApprovalUrl?: (url: string) => Promise<void>;
|
|
330
329
|
/** Test/embedding override for calendar connection polling. */
|
|
@@ -364,8 +363,8 @@ interface SmokeOptions {
|
|
|
364
363
|
stdout?: Pick<typeof console, "log" | "error">;
|
|
365
364
|
}
|
|
366
365
|
|
|
367
|
-
/** The
|
|
368
|
-
declare const
|
|
366
|
+
/** The Google OAuth scope that authorizes booking writes (events read/write). */
|
|
367
|
+
declare const GOOGLE_CALENDAR_EVENTS_SCOPE = "https://www.googleapis.com/auth/calendar.events";
|
|
369
368
|
/** Resolve the checked-in calendar block into one controller-safe env payload. */
|
|
370
369
|
declare function calendarServiceConfig(cfg: LoadedProjectConfig, env: string): CalendarServiceConfig;
|
|
371
370
|
/** Public Appointment Schedule URL to apply separately from connector config. */
|
|
@@ -803,4 +802,4 @@ declare function installSkill(options?: SkillInstallOptions): SkillInstallResult
|
|
|
803
802
|
*/
|
|
804
803
|
declare function smoke(options: SmokeOptions): Promise<void>;
|
|
805
804
|
|
|
806
|
-
export { AGENT_HARNESSES, type AdminAiOptions, type AgentHarness, type AgentHarnessSelector, type AvailableGoogleCalendar, CAPABILITIES, type CalendarConfig, type CalendarConnectionState, type CalendarLifecycleOptions, type CalendarServiceConfig, type CalendarStatus, type CliDependencies, type ConnectGitHubSecuritySourceOptions, type DisconnectGitHubSecuritySourceOptions, type FollowHostedSecurityJobOptions,
|
|
805
|
+
export { AGENT_HARNESSES, type AdminAiOptions, type AgentHarness, type AgentHarnessSelector, type AvailableGoogleCalendar, CAPABILITIES, type CalendarConfig, type CalendarConnectionState, type CalendarLifecycleOptions, type CalendarServiceConfig, type CalendarStatus, type CliDependencies, type ConnectGitHubSecuritySourceOptions, type DisconnectGitHubSecuritySourceOptions, type FollowHostedSecurityJobOptions, GOOGLE_CALENDAR_EVENTS_SCOPE, type GetHostedSecurityIntentOptions, type GetHostedSecurityJobOptions, type GoogleCalendarConfig, type HarnessInstallResult, type HostedSecurityProfile, type HostedSecurityResult, type HostedSecurityTokenRequest, type ListGitHubSecuritySourcesOptions, type ListHostedSecurityJobsOptions, type LoadedProjectConfig, type LocalCredentials, type OdlaProjectConfig, type ProvisionOptions, type ProvisionPlan, type RunHostedSecurityOptions, SYSTEM_AI_PURPOSES, type ScopedPlatformTokenOptions, type SecretsPushOptions, type SecretsSetOptions, type SkillInstallOptions, type SkillInstallResult, type SmokeOptions, type StartHostedSecurityJobOptions, type SystemAiPurpose, adminAi, calendarBookingPageUrl, calendarCalendars, calendarConnect, calendarDisconnect, calendarServiceConfig, calendarStatus, connectGitHubSecuritySource, disconnectGitHubSecuritySource, doctor, exitCodeFor, followHostedSecurityJob, getHostedSecurityIntent, getHostedSecurityJob, getHostedSecurityPlan, getHostedSecurityReport, getScopedPlatformToken, inferGitHubRepository, initProject, installSkill, isTerminalHostedSecurityStatus, listGitHubSecuritySources, listHostedSecurityJobs, printCapabilities, provision, redactSecrets, repositoryFromGitRemote, runCli, runHostedSecurity, secretsPush, secretsSet, secretsSetClerkKey, smoke, startHostedSecurityJob };
|
package/dist/index.js
CHANGED
|
@@ -2,19 +2,19 @@
|
|
|
2
2
|
import {
|
|
3
3
|
AGENT_HARNESSES,
|
|
4
4
|
CAPABILITIES,
|
|
5
|
-
|
|
5
|
+
GOOGLE_CALENDAR_EVENTS_SCOPE,
|
|
6
6
|
SYSTEM_AI_PURPOSES,
|
|
7
7
|
adminAi,
|
|
8
8
|
calendarBookingPageUrl,
|
|
9
9
|
calendarCalendars,
|
|
10
10
|
calendarConnect,
|
|
11
11
|
calendarDisconnect,
|
|
12
|
-
calendarResync,
|
|
13
12
|
calendarServiceConfig,
|
|
14
13
|
calendarStatus,
|
|
15
14
|
connectGitHubSecuritySource,
|
|
16
15
|
disconnectGitHubSecuritySource,
|
|
17
16
|
doctor,
|
|
17
|
+
exitCodeFor,
|
|
18
18
|
followHostedSecurityJob,
|
|
19
19
|
getHostedSecurityIntent,
|
|
20
20
|
getHostedSecurityJob,
|
|
@@ -38,23 +38,23 @@ import {
|
|
|
38
38
|
secretsSetClerkKey,
|
|
39
39
|
smoke,
|
|
40
40
|
startHostedSecurityJob
|
|
41
|
-
} from "./chunk-
|
|
41
|
+
} from "./chunk-Y4HWUEFF.js";
|
|
42
42
|
export {
|
|
43
43
|
AGENT_HARNESSES,
|
|
44
44
|
CAPABILITIES,
|
|
45
|
-
|
|
45
|
+
GOOGLE_CALENDAR_EVENTS_SCOPE,
|
|
46
46
|
SYSTEM_AI_PURPOSES,
|
|
47
47
|
adminAi,
|
|
48
48
|
calendarBookingPageUrl,
|
|
49
49
|
calendarCalendars,
|
|
50
50
|
calendarConnect,
|
|
51
51
|
calendarDisconnect,
|
|
52
|
-
calendarResync,
|
|
53
52
|
calendarServiceConfig,
|
|
54
53
|
calendarStatus,
|
|
55
54
|
connectGitHubSecuritySource,
|
|
56
55
|
disconnectGitHubSecuritySource,
|
|
57
56
|
doctor,
|
|
57
|
+
exitCodeFor,
|
|
58
58
|
followHostedSecurityJob,
|
|
59
59
|
getHostedSecurityIntent,
|
|
60
60
|
getHostedSecurityJob,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@odla-ai/cli",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.12.0",
|
|
4
4
|
"description": "Agent-operable CLI for odla provisioning, calendar consent and sync lifecycle, System AI administration, Worker secrets, security jobs, and smoke checks.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"homepage": "https://odla.ai/docs/packages/cli",
|
package/skills/odla/SKILL.md
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
name: odla
|
|
3
3
|
description: >
|
|
4
4
|
Build a new app on odla — a realtime database (odla-db) plus AI, Clerk auth,
|
|
5
|
-
|
|
5
|
+
live Google Calendar booking, and observability on Cloudflare, provisioned by @odla-ai/cli. Use when the user
|
|
6
6
|
wants to create/scaffold an odla app, add odla-db/ai/auth/o11y to a repo, or
|
|
7
7
|
"get started with odla". For moving an existing static or GitHub Pages site to
|
|
8
8
|
odla, use the odla-migrate skill instead.
|
|
@@ -15,7 +15,7 @@ runbookOrder:
|
|
|
15
15
|
|
|
16
16
|
You drive setup and building on **odla** — an agent-operable app platform on
|
|
17
17
|
Cloudflare: a realtime graph database (**odla-db**), multi-provider **AI**,
|
|
18
|
-
**Clerk** auth,
|
|
18
|
+
**Clerk** auth, live **Google Calendar** booking, and OpenTelemetry **observability**, all provisioned by the
|
|
19
19
|
`@odla-ai/cli`. The human approves a couple of browser-only checkpoints; you do
|
|
20
20
|
everything else.
|
|
21
21
|
|
|
@@ -53,7 +53,30 @@ State which path you're taking and what you'll build in one line; get a nod.
|
|
|
53
53
|
explicitly asks.
|
|
54
54
|
5. Google OAuth is a distinct human checkpoint. Never request, paste, print, or
|
|
55
55
|
store a Google authorization code/refresh token. Open only the state-bound
|
|
56
|
-
platform/Google consent URL returned by odla;
|
|
56
|
+
platform/Google consent URL returned by odla; booking runs server-side
|
|
57
|
+
through the SDK with the app's existing key, never from a browser.
|
|
58
|
+
|
|
59
|
+
## Tooling sources
|
|
60
|
+
|
|
61
|
+
- **odla**: this skill plus the installed `@odla-ai/*` packages are the
|
|
62
|
+
complete, offline contract (README + exported declarations/JSDoc, rendered
|
|
63
|
+
at `https://odla.ai/docs/packages/<pkg>`). Never reconstruct odla behavior
|
|
64
|
+
from the web or training memory.
|
|
65
|
+
- **Third-party tools (wrangler, Clerk) — the reverse**: their CLIs and config
|
|
66
|
+
formats evolve, so never work from memorized setup steps. When you reach a
|
|
67
|
+
wrangler or Clerk step, fetch the vendor's current agent docs and follow
|
|
68
|
+
those:
|
|
69
|
+
- Cloudflare: docs index `https://developers.cloudflare.com/llms.txt`; every
|
|
70
|
+
docs page has a markdown twin at `<page>/index.md` (wrangler config:
|
|
71
|
+
`https://developers.cloudflare.com/workers/wrangler/configuration/index.md`).
|
|
72
|
+
With the human's OK (it edits global agent config), you may also follow
|
|
73
|
+
`https://developers.cloudflare.com/agent-setup/prompt.md` to add
|
|
74
|
+
Cloudflare's own skills + MCP servers to your harness.
|
|
75
|
+
- Clerk: agent-first CLI setup `https://clerk.com/docs/cli.md`; docs index
|
|
76
|
+
`https://clerk.com/docs/llms.txt`.
|
|
77
|
+
|
|
78
|
+
Offline? Say so, continue with the vendor steps written in these references,
|
|
79
|
+
and flag that they may be stale.
|
|
57
80
|
|
|
58
81
|
## The flow
|
|
59
82
|
|
|
@@ -72,12 +95,18 @@ guessing which platform/credential steps need manual work. Then:
|
|
|
72
95
|
`npx @odla-ai/cli provision --email <existing-odla-account>
|
|
73
96
|
--write-dev-vars --push-secrets`. A device code prints; that same account
|
|
74
97
|
signs in, reviews the exact code, and approves it at https://odla.ai/studio.
|
|
75
|
-
Opening the link alone is inert.
|
|
98
|
+
Opening the link alone is inert. Relay the printed approval URL to the
|
|
99
|
+
human verbatim — the automatic browser launch is best-effort and may show
|
|
100
|
+
no tab. Outside an interactive terminal the wait is capped (90s default,
|
|
101
|
+
`--wait <seconds>`); exit code 75 means still pending: the handshake is
|
|
102
|
+
persisted, so once the human approves, re-run the same command and it
|
|
103
|
+
resumes the same code and collects the token. It creates the app,
|
|
76
104
|
enables services, issues or reuses configured credentials (db key + o11y
|
|
77
105
|
ingest token when enabled), pushes schema + rules, writes `.dev.vars`, and
|
|
78
106
|
transfers Worker secrets through Wrangler stdin. With calendar enabled it
|
|
79
|
-
then prints a second, server-issued Google URL; the human grants
|
|
80
|
-
and the
|
|
107
|
+
then prints a second, server-issued Google URL; the human grants booking
|
|
108
|
+
consent in a browser and the connection is immediately live — nothing
|
|
109
|
+
syncs.
|
|
81
110
|
4. **run** — `npx wrangler dev` (auto-loads `.dev.vars`); verify locally.
|
|
82
111
|
5. **security** — run the passive `@odla-ai/security` odla profile; inspect
|
|
83
112
|
every lead and keep critical candidate gating enabled. If the human approves
|
|
@@ -98,10 +127,11 @@ guessing which platform/credential steps need manual work. Then:
|
|
|
98
127
|
|
|
99
128
|
`npx @odla-ai/cli doctor` is an offline config check anytime;
|
|
100
129
|
`npx @odla-ai/cli smoke --env dev` verifies a live deployment.
|
|
101
|
-
Use `calendar status --json` for safe connection
|
|
102
|
-
calendars --json` to discover ids
|
|
103
|
-
|
|
104
|
-
`--yes` and
|
|
130
|
+
Use `calendar status --json` for safe connection state (`bookable`, booking
|
|
131
|
+
and availability calendars) and `calendar calendars --json` to discover ids
|
|
132
|
+
after consent; update checked-in config and re-provision. Disconnect always
|
|
133
|
+
requires `--yes` and removes only this connection's sealed grant — Google
|
|
134
|
+
keeps every booked event.
|
|
105
135
|
|
|
106
136
|
The CLI owns deterministic platform work from `odla.config.mjs`: service
|
|
107
137
|
enablement, credential issuance/storage, `.dev.vars`, and Wrangler secret
|
|
@@ -15,25 +15,29 @@ deny-all rules from the schema. To turn on auth/observability, add `"o11y"` to
|
|
|
15
15
|
`services` and an `auth.clerk` block in `odla.config.mjs` (init leaves it
|
|
16
16
|
commented).
|
|
17
17
|
|
|
18
|
-
For
|
|
19
|
-
`calendar.google.
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
18
|
+
For Google Calendar booking, include both `"db"` and `"calendar"`. Configure
|
|
19
|
+
`calendar.google.availabilityCalendars` for every env (start with
|
|
20
|
+
`"primary"`; 1–10 per env) and optionally `bookingCalendar` (defaults to the
|
|
21
|
+
first availability calendar). Do not add OAuth credentials to config — the
|
|
22
|
+
Google grant is platform-side. A legacy per-env `bookingPageUrl` link may be
|
|
23
|
+
kept as a fallback; it is public configuration, never a credential.
|
|
24
24
|
|
|
25
25
|
## 2. Build the Worker shell
|
|
26
26
|
|
|
27
27
|
`npm i` only the SDKs you need and use the local `references/sdks.md` as the
|
|
28
|
-
integration map.
|
|
29
|
-
|
|
30
|
-
`
|
|
31
|
-
|
|
28
|
+
integration map. `npm i -D wrangler` so the project pins its own copy instead
|
|
29
|
+
of relying on an implicit `npx` fetch. Create the Worker entrypoint and
|
|
30
|
+
`wrangler.jsonc` before any deployed-secret transfer — take the current config
|
|
31
|
+
syntax from Cloudflare's live docs (SKILL.md "Tooling sources"), not memory.
|
|
32
|
+
With o11y, install `@odla-ai/o11y`, add `"nodejs_compat"` to
|
|
33
|
+
`compatibility_flags`, and wrap the entrypoint with `withObservability`.
|
|
32
34
|
|
|
33
35
|
Each installed package's README and exported TypeScript declarations/JSDoc are
|
|
34
36
|
the version-matched API contract; resolve public entry points through its
|
|
35
|
-
`package.json` `exports`.
|
|
36
|
-
|
|
37
|
+
`package.json` `exports`. For everything odla, the npm artifacts contain the
|
|
38
|
+
whole setup context — private service source or web documentation is never
|
|
39
|
+
required. Third-party tooling (wrangler, Clerk) is the reverse: use the live
|
|
40
|
+
vendor docs, never memorized steps.
|
|
37
41
|
|
|
38
42
|
## 3. Provision ⏸ device-code approval
|
|
39
43
|
|
|
@@ -54,11 +58,13 @@ anything unset. `--push-secrets` preflights the Wrangler config and login before
|
|
|
54
58
|
issuing or rotating a shown-once credential.
|
|
55
59
|
|
|
56
60
|
Calendar adds a second ⏸ checkpoint after the odla device approval: provision
|
|
57
|
-
prints/opens a state-bound Google URL issued by the platform and waits while
|
|
58
|
-
|
|
59
|
-
|
|
61
|
+
prints/opens a state-bound Google URL issued by the platform and waits while
|
|
62
|
+
the human grants the booking scopes in a browser. The CLI never receives the
|
|
63
|
+
Google callback code or tokens, and nothing syncs afterward — Google stays
|
|
64
|
+
the single source of truth. Once connected, run
|
|
60
65
|
`npx @odla-ai/cli calendar calendars --env dev --json`, refine the checked-in
|
|
61
|
-
calendar ids if needed, re-provision, and verify `calendar status --
|
|
66
|
+
calendar ids if needed, re-provision, and verify `calendar status --env dev`
|
|
67
|
+
reports `bookable: yes`.
|
|
62
68
|
|
|
63
69
|
The CLI stops at the source boundary: it verifies but does not invent your
|
|
64
70
|
application semantics. Do not use Studio to mint a routine o11y token. Manual
|
|
@@ -78,10 +84,11 @@ means the namespace has no rule yet — add one in `src/odla/rules.mjs`
|
|
|
78
84
|
(deliberately; e.g. `{ notes: { view: "auth.signedIn", create: "auth.signedIn" } }`),
|
|
79
85
|
re-provision to push it, and retry.
|
|
80
86
|
|
|
81
|
-
Calendar
|
|
82
|
-
`
|
|
83
|
-
|
|
84
|
-
`@odla-ai/calendar/client`
|
|
87
|
+
Calendar rides the server-only `ODLA_API_KEY`; it adds no Worker secret. Keep
|
|
88
|
+
`initCalendar` in trusted Worker code and expose the app's own slots/booking
|
|
89
|
+
endpoints to the browser — never call the platform calendar routes from
|
|
90
|
+
browser code. Browsers may import only the pure `@odla-ai/calendar/client`
|
|
91
|
+
helpers (`computeBookableSlots`, formatters), never the admin key.
|
|
85
92
|
|
|
86
93
|
## 5. Security preflight
|
|
87
94
|
|