@odla-ai/cli 0.25.22 → 0.26.1
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 +61 -11
- package/dist/bin.cjs +1061 -341
- package/dist/bin.cjs.map +1 -1
- package/dist/bin.js +1 -1
- package/dist/{chunk-2AFAXLKE.js → chunk-ZAZBUURZ.js} +1023 -294
- package/dist/chunk-ZAZBUURZ.js.map +1 -0
- package/dist/index.cjs +1069 -341
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +52 -23
- package/dist/index.d.ts +52 -23
- package/dist/index.js +9 -1
- package/package.json +2 -2
- package/skills/odla/references/sdks.md +5 -3
- package/skills/odla-migrate/references/phase-2b-calendar.md +13 -8
- package/dist/chunk-2AFAXLKE.js.map +0 -1
package/dist/index.d.cts
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
import { App } from '@odla-ai/apps';
|
|
1
|
+
import { RegistryConfigRevision, ConfigOperationReceipt, App } from '@odla-ai/apps';
|
|
2
2
|
import { SecurityReport, PlatformSecurityRun } from '@odla-ai/security';
|
|
3
3
|
import { HostedSecurityJob, GitHubConnectionStatus, GitHubSecuritySource, HostedSecurityIntentResponse, HostedSecurityPlan, HostedSecurityReport, HostedSecurityJobStatus } from '@odla-ai/security/hosted';
|
|
4
4
|
export { GitHubConnectionAttempt, GitHubConnectionStatus, GitHubSecuritySource, HostedSecurityCounts, HostedSecurityCoverage, HostedSecurityIntent, HostedSecurityIntentResponse, HostedSecurityJob, HostedSecurityJobStatus, HostedSecurityPlan, HostedSecurityPlanRoute, HostedSecurityReport, HostedSecurityReportFinding, HostedSecurityRoute } from '@odla-ai/security/hosted';
|
|
5
5
|
|
|
6
6
|
/** One exact device-grant scope obtainable through the approval flow. */
|
|
7
|
-
type ScopedPlatformScope = "platform:ai:policy:read" | "platform:ai:policy:write" | "platform:ai:credential:read" | "platform:ai:credential:write" | "platform:ai:usage:read" | "platform:ai:audit:read" | "platform:status:read" | "app:config:read" | "app:code:host:connect" | "platform:code:host:connect" | "platform:security:self" | "platform:runbook:write";
|
|
7
|
+
type ScopedPlatformScope = "platform:ai:policy:read" | "platform:ai:policy:write" | "platform:ai:credential:read" | "platform:ai:credential:write" | "platform:ai:usage:read" | "platform:ai:audit:read" | "platform:status:read" | "platform:chat:credential:write" | "app:config:read" | "app:config:write" | "app:code:host:connect" | "platform:code:host:connect" | "platform:security:self" | "platform:runbook:write";
|
|
8
8
|
/** Inputs for obtaining one short-lived, exact-scope device grant. */
|
|
9
9
|
interface ScopedPlatformTokenOptions {
|
|
10
10
|
platform: string;
|
|
@@ -162,6 +162,17 @@ declare function codeConnect(options: CodeConnectOptions): Promise<void>;
|
|
|
162
162
|
/** Run outbound presence and fenced Pi commands without opening a listener. */
|
|
163
163
|
declare function runCodeRuntime(input: CodeRuntimeInput): Promise<void>;
|
|
164
164
|
|
|
165
|
+
interface RunResult {
|
|
166
|
+
code: number;
|
|
167
|
+
stdout: string;
|
|
168
|
+
stderr: string;
|
|
169
|
+
}
|
|
170
|
+
/** Subprocess seam: injectable in tests, `defaultRunner` in production. */
|
|
171
|
+
type CommandRunner = (cmd: string, args: string[], opts?: {
|
|
172
|
+
input?: string;
|
|
173
|
+
cwd?: string;
|
|
174
|
+
}) => Promise<RunResult>;
|
|
175
|
+
|
|
165
176
|
/** Map a CLI failure to its process exit code: 75 (EX_TEMPFAIL) marks work that
|
|
166
177
|
* has not failed but has not finished — a handshake still awaiting human
|
|
167
178
|
* approval (the pending state is persisted, so rerunning resumes it), or a
|
|
@@ -186,6 +197,8 @@ interface CliDependencies {
|
|
|
186
197
|
/** Runs git in the working directory; injected so `runbook impact` can be
|
|
187
198
|
* driven over a fixed diff instead of whatever the checkout happens to be. */
|
|
188
199
|
runGit?: (args: string[]) => string;
|
|
200
|
+
/** Runs Wrangler for one-purpose platform secret rotations. */
|
|
201
|
+
runner?: CommandRunner;
|
|
189
202
|
}
|
|
190
203
|
/**
|
|
191
204
|
* Parse CLI arguments and dispatch the matching odla command.
|
|
@@ -254,7 +267,7 @@ declare function adminAi(options: AdminAiOptions): Promise<void>;
|
|
|
254
267
|
/** Stable, machine-readable division of work between the CLI, coding agent,
|
|
255
268
|
* human operator, and Studio. Printed by `odla-ai capabilities --json`. */
|
|
256
269
|
declare const CAPABILITIES: {
|
|
257
|
-
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", "add or remove app co-owners, each of whom self-provisions their own credentials for the shared db without any secret handoff", "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", "compose declared app-capability schema/rules, create guarded seeds when absent, 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 integration contracts offline and smoke-test a provisioned db environment plus anonymous capability routes", "save and explicitly select non-secret named operator contexts with isolated credential caches; resolve and explain platform, app, environment, and credential provenance without authenticating; then run PM, Discussions, o11y, runbook, and identity operations outside a project checkout", "read one versioned o11y status envelope spanning application RED, exact Worker versions and Cloudflare colos observed in traffic, current live-sync freshness/load, the protected commit-to-visible canary, collector ingest/scheduler trust, provider-owned runtime metrics, account-scoped Durable Object, D1, and R2 evidence under odla-db, and a bounded machine verdict", "read one canonical platform fleet snapshot over private service bindings, including release identities, probe latency, Cloudflare load/runtime freshness, explicit unknowns, and stable next actions through a read-only capability", "compare one project's checked-in Registry intent with live owner-visible state
|
|
270
|
+
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", "add or remove app co-owners, each of whom self-provisions their own credentials for the shared db without any secret handoff", "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", "compose declared app-capability schema/rules, create guarded seeds when absent, 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 integration contracts offline and smoke-test a provisioned db environment plus anonymous capability routes", "save and explicitly select non-secret named operator contexts with isolated credential caches; resolve and explain platform, app, environment, and credential provenance without authenticating; then run PM, Discussions, o11y, runbook, and identity operations outside a project checkout", "read one versioned o11y status envelope spanning application RED, exact Worker versions and Cloudflare colos observed in traffic, current live-sync freshness/load, the protected commit-to-visible canary, collector ingest/scheduler trust, provider-owned runtime metrics, account-scoped Durable Object, D1, and R2 evidence under odla-db, and a bounded machine verdict", "read one canonical platform fleet snapshot over private service bindings, including release identities, probe latency, Cloudflare load/runtime freshness, explicit unknowns, and stable next actions through a read-only capability", "compare one project's checked-in Registry intent with live owner-visible state, freeze a secret-free Registry-revision-bound plan through app:config:read, and conditionally apply checkpoint-free actions through exact app:config:write operation routes", "inspect or bounded-wait one exact durable config-operation journal entry and verify every terminal receipt digest before returning it to remote automation", "inspect durable agent wakeups as a versioned JSON envelope and explicitly requeue one dead-lettered job with a scoped environment credential", "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"];
|
|
258
271
|
readonly agent: readonly ["install and import the selected odla SDKs", "wrap the Worker with withObservability and choose useful telemetry", "install capability packages, mount their runtime routes, and 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"];
|
|
259
272
|
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 changes against an app's live database 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"];
|
|
260
273
|
readonly studio: readonly ["view application telemetry grouped by exact Worker version, reconciled live-sync load/freshness, commit-to-visible canary health, provider-owned Worker runtime metrics, 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 — for the primary owner or any co-owner — 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"];
|
|
@@ -380,17 +393,6 @@ declare function calendarConnect(options: CalendarLifecycleOptions): Promise<Cal
|
|
|
380
393
|
* project grant is not revoked. */
|
|
381
394
|
declare function calendarDisconnect(options: CalendarLifecycleOptions): Promise<CalendarStatus>;
|
|
382
395
|
|
|
383
|
-
interface RunResult {
|
|
384
|
-
code: number;
|
|
385
|
-
stdout: string;
|
|
386
|
-
stderr: string;
|
|
387
|
-
}
|
|
388
|
-
/** Subprocess seam: injectable in tests, `defaultRunner` in production. */
|
|
389
|
-
type CommandRunner = (cmd: string, args: string[], opts?: {
|
|
390
|
-
input?: string;
|
|
391
|
-
cwd?: string;
|
|
392
|
-
}) => Promise<RunResult>;
|
|
393
|
-
|
|
394
396
|
type OdlaEnvName = string;
|
|
395
397
|
type AppRules = Record<string, {
|
|
396
398
|
view?: string;
|
|
@@ -683,6 +685,8 @@ interface ConfigReconciliation {
|
|
|
683
685
|
};
|
|
684
686
|
desiredRevision: ConfigDigest;
|
|
685
687
|
observedRevision: ConfigDigest | null;
|
|
688
|
+
/** Monotonic Registry compare-and-set revision, separate from content hashes. */
|
|
689
|
+
registryRevision: RegistryConfigRevision | null;
|
|
686
690
|
status: ConfigDrift;
|
|
687
691
|
summary: {
|
|
688
692
|
differences: number;
|
|
@@ -704,12 +708,13 @@ interface ConfigDiffDocument extends Omit<ConfigReconciliation, "actions"> {
|
|
|
704
708
|
description: string;
|
|
705
709
|
}>;
|
|
706
710
|
}
|
|
707
|
-
/** Revision-bound `odla.config-plan/
|
|
711
|
+
/** Revision-bound `odla.config-plan/v2` document returned by `configPlan`. */
|
|
708
712
|
interface ConfigPlanDocument extends ConfigReconciliation {
|
|
709
|
-
schemaVersion: "odla.config-plan/
|
|
713
|
+
schemaVersion: "odla.config-plan/v2";
|
|
710
714
|
planDigest: ConfigDigest;
|
|
711
715
|
apply: {
|
|
712
|
-
supported:
|
|
716
|
+
supported: boolean;
|
|
717
|
+
checkpointRequired: boolean;
|
|
713
718
|
reason: string;
|
|
714
719
|
};
|
|
715
720
|
nextActions: Array<{
|
|
@@ -730,6 +735,21 @@ interface ConfigInspectOptions {
|
|
|
730
735
|
stdout?: Pick<typeof console, "log" | "error">;
|
|
731
736
|
now?: () => Date;
|
|
732
737
|
}
|
|
738
|
+
/** Inputs for applying one reviewed, frozen config plan from disk. */
|
|
739
|
+
interface ConfigApplyOptions extends ConfigInspectOptions {
|
|
740
|
+
planPath: string;
|
|
741
|
+
idempotencyKey?: string;
|
|
742
|
+
}
|
|
743
|
+
/** Inputs for exact-id config operation reads and bounded waits. */
|
|
744
|
+
interface ConfigOperationInspectOptions extends ConfigInspectOptions {
|
|
745
|
+
operationId: string;
|
|
746
|
+
intervalSeconds?: number;
|
|
747
|
+
timeoutSeconds?: number;
|
|
748
|
+
pollWait?: (milliseconds: number) => Promise<void>;
|
|
749
|
+
now?: () => Date;
|
|
750
|
+
}
|
|
751
|
+
/** Result returned by config apply or an operation journal command. */
|
|
752
|
+
type ConfigOperationResult = ConfigOperationReceipt;
|
|
733
753
|
/** Secret-free Registry intent normalized from one loaded project configuration. */
|
|
734
754
|
interface DesiredRegistryState {
|
|
735
755
|
appId: string;
|
|
@@ -762,13 +782,22 @@ interface ReconciliationInput {
|
|
|
762
782
|
* the caller explicitly supplies a token. This function performs no writes.
|
|
763
783
|
*/
|
|
764
784
|
declare function configDiff(options: ConfigInspectOptions): Promise<ConfigDiffDocument>;
|
|
765
|
-
/** Freeze
|
|
766
|
-
*
|
|
767
|
-
* The returned plan intentionally has `apply.supported: false`; callers must
|
|
768
|
-
* follow its explicit existing-command or Studio checkpoints separately.
|
|
769
|
-
*/
|
|
785
|
+
/** Freeze content revisions, Registry CAS revision, and ordered actions. */
|
|
770
786
|
declare function configPlan(options: ConfigInspectOptions): Promise<ConfigPlanDocument>;
|
|
771
787
|
|
|
788
|
+
/** Apply one exact frozen plan through the Registry operation journal. */
|
|
789
|
+
declare function configApply(options: ConfigApplyOptions): Promise<ConfigOperationReceipt>;
|
|
790
|
+
/** Read one exact journal entry without replaying effects. */
|
|
791
|
+
declare function configOperationGet(options: ConfigOperationInspectOptions): Promise<ConfigOperationReceipt>;
|
|
792
|
+
/** Poll one exact journal entry until it closes or the bounded wait expires. */
|
|
793
|
+
declare function configOperationWait(options: ConfigOperationInspectOptions): Promise<ConfigOperationReceipt>;
|
|
794
|
+
|
|
795
|
+
/** Stable CLI failure code consumed by `exitCodeFor`. */
|
|
796
|
+
declare class ConfigOperationCommandError extends Error {
|
|
797
|
+
readonly code: string;
|
|
798
|
+
constructor(message: string, code: string);
|
|
799
|
+
}
|
|
800
|
+
|
|
772
801
|
/** Project-config projection owned by Registry reconciliation.
|
|
773
802
|
*
|
|
774
803
|
* This deliberately excludes schema, rules, seeds, secrets, credentials, and
|
|
@@ -1222,4 +1251,4 @@ declare function installSkill(options?: SkillInstallOptions): SkillInstallResult
|
|
|
1222
1251
|
*/
|
|
1223
1252
|
declare function smoke(options: SmokeOptions): Promise<void>;
|
|
1224
1253
|
|
|
1225
|
-
export { AGENT_HARNESSES, type AdminAiOptions, type AgentHarness, type AgentHarnessSelector, type AvailableGoogleCalendar, CAPABILITIES, CODE_BUILD_RECIPES, CODE_PI_IMAGE, COMMAND_SURFACE, type CalendarConfig, type CalendarConnectionState, type CalendarLifecycleOptions, type CalendarServiceConfig, type CalendarStatus, type CliDependencies, type CodeBuildRule, type CodeConnectOptions, type CodeContainerEngine, type CodeHostCapabilities, type CodeLocalSourceDescriptor, type CodeRuntimeInput, type ConfigCoverage, type ConfigDiffDocument, type ConfigDifference, type ConfigDigest, type ConfigDrift, type ConfigInspectOptions, type ConfigPlanAction, type ConfigPlanDocument, type ConfigReconciliation, type ConfigRisk, type ConfigSource, type ConnectGitHubSecuritySourceOptions, type DesiredRegistryState, type DisconnectGitHubSecuritySourceOptions, type FollowHostedSecurityJobOptions, GOOGLE_CALENDAR_EVENTS_SCOPE, type GetHostedSecurityIntentOptions, type GetHostedSecurityJobOptions, type GoogleCalendarConfig, type HarnessInstallResult, type HostedSecurityProfile, type HostedSecurityResult, type HostedSecurityTokenRequest, type IntegrationProbe, type IntegrationSeed, type InvocationProblem, type ListGitHubSecuritySourcesOptions, type ListHostedSecurityJobsOptions, type LoadedProjectConfig, type LocalCredentials, type OdlaIntegration, type OdlaProjectConfig, type ProvisionOptions, type ProvisionPlan, type ReconciliationInput, type RunHostedSecurityOptions, SYSTEM_AI_PURPOSES, type ScopedPlatformTokenOptions, type SecretsPushOptions, type SecretsSetOptions, type SkillInstallOptions, type SkillInstallResult, type SmokeOptions, type StartHostedSecurityJobOptions, type SurfaceNode, type SystemAiPurpose, acceptedAfter, adminAi, calendarBookingPageUrl, calendarCalendars, calendarConnect, calendarDisconnect, calendarServiceConfig, calendarStatus, codeConnect, configDiff, configPlan, connectGitHubSecuritySource, describeProblem, desiredRegistryState, disconnectGitHubSecuritySource, doctor, exitCodeFor, followHostedSecurityJob, getHostedSecurityIntent, getHostedSecurityJob, getHostedSecurityPlan, getHostedSecurityReport, getScopedPlatformToken, inferGitHubRepository, initProject, installSkill, invocationPath, isTerminalHostedSecurityStatus, listGitHubSecuritySources, listHostedSecurityJobs, prepareCodeImages, printCapabilities, provision, reconcileConfig, redactSecrets, repositoryFromGitRemote, runCli, runCodeRuntime, runHostedSecurity, secretsPush, secretsSet, secretsSetClerkKey, smoke, startHostedSecurityJob, surfacePaths, validateInvocation };
|
|
1254
|
+
export { AGENT_HARNESSES, type AdminAiOptions, type AgentHarness, type AgentHarnessSelector, type AvailableGoogleCalendar, CAPABILITIES, CODE_BUILD_RECIPES, CODE_PI_IMAGE, COMMAND_SURFACE, type CalendarConfig, type CalendarConnectionState, type CalendarLifecycleOptions, type CalendarServiceConfig, type CalendarStatus, type CliDependencies, type CodeBuildRule, type CodeConnectOptions, type CodeContainerEngine, type CodeHostCapabilities, type CodeLocalSourceDescriptor, type CodeRuntimeInput, type ConfigApplyOptions, type ConfigCoverage, type ConfigDiffDocument, type ConfigDifference, type ConfigDigest, type ConfigDrift, type ConfigInspectOptions, ConfigOperationCommandError, type ConfigOperationInspectOptions, type ConfigOperationResult, type ConfigPlanAction, type ConfigPlanDocument, type ConfigReconciliation, type ConfigRisk, type ConfigSource, type ConnectGitHubSecuritySourceOptions, type DesiredRegistryState, type DisconnectGitHubSecuritySourceOptions, type FollowHostedSecurityJobOptions, GOOGLE_CALENDAR_EVENTS_SCOPE, type GetHostedSecurityIntentOptions, type GetHostedSecurityJobOptions, type GoogleCalendarConfig, type HarnessInstallResult, type HostedSecurityProfile, type HostedSecurityResult, type HostedSecurityTokenRequest, type IntegrationProbe, type IntegrationSeed, type InvocationProblem, type ListGitHubSecuritySourcesOptions, type ListHostedSecurityJobsOptions, type LoadedProjectConfig, type LocalCredentials, type OdlaIntegration, type OdlaProjectConfig, type ProvisionOptions, type ProvisionPlan, type ReconciliationInput, type RunHostedSecurityOptions, SYSTEM_AI_PURPOSES, type ScopedPlatformTokenOptions, type SecretsPushOptions, type SecretsSetOptions, type SkillInstallOptions, type SkillInstallResult, type SmokeOptions, type StartHostedSecurityJobOptions, type SurfaceNode, type SystemAiPurpose, acceptedAfter, adminAi, calendarBookingPageUrl, calendarCalendars, calendarConnect, calendarDisconnect, calendarServiceConfig, calendarStatus, codeConnect, configApply, configDiff, configOperationGet, configOperationWait, configPlan, connectGitHubSecuritySource, describeProblem, desiredRegistryState, disconnectGitHubSecuritySource, doctor, exitCodeFor, followHostedSecurityJob, getHostedSecurityIntent, getHostedSecurityJob, getHostedSecurityPlan, getHostedSecurityReport, getScopedPlatformToken, inferGitHubRepository, initProject, installSkill, invocationPath, isTerminalHostedSecurityStatus, listGitHubSecuritySources, listHostedSecurityJobs, prepareCodeImages, printCapabilities, provision, reconcileConfig, redactSecrets, repositoryFromGitRemote, runCli, runCodeRuntime, runHostedSecurity, secretsPush, secretsSet, secretsSetClerkKey, smoke, startHostedSecurityJob, surfacePaths, validateInvocation };
|
package/dist/index.d.ts
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
import { App } from '@odla-ai/apps';
|
|
1
|
+
import { RegistryConfigRevision, ConfigOperationReceipt, App } from '@odla-ai/apps';
|
|
2
2
|
import { SecurityReport, PlatformSecurityRun } from '@odla-ai/security';
|
|
3
3
|
import { HostedSecurityJob, GitHubConnectionStatus, GitHubSecuritySource, HostedSecurityIntentResponse, HostedSecurityPlan, HostedSecurityReport, HostedSecurityJobStatus } from '@odla-ai/security/hosted';
|
|
4
4
|
export { GitHubConnectionAttempt, GitHubConnectionStatus, GitHubSecuritySource, HostedSecurityCounts, HostedSecurityCoverage, HostedSecurityIntent, HostedSecurityIntentResponse, HostedSecurityJob, HostedSecurityJobStatus, HostedSecurityPlan, HostedSecurityPlanRoute, HostedSecurityReport, HostedSecurityReportFinding, HostedSecurityRoute } from '@odla-ai/security/hosted';
|
|
5
5
|
|
|
6
6
|
/** One exact device-grant scope obtainable through the approval flow. */
|
|
7
|
-
type ScopedPlatformScope = "platform:ai:policy:read" | "platform:ai:policy:write" | "platform:ai:credential:read" | "platform:ai:credential:write" | "platform:ai:usage:read" | "platform:ai:audit:read" | "platform:status:read" | "app:config:read" | "app:code:host:connect" | "platform:code:host:connect" | "platform:security:self" | "platform:runbook:write";
|
|
7
|
+
type ScopedPlatformScope = "platform:ai:policy:read" | "platform:ai:policy:write" | "platform:ai:credential:read" | "platform:ai:credential:write" | "platform:ai:usage:read" | "platform:ai:audit:read" | "platform:status:read" | "platform:chat:credential:write" | "app:config:read" | "app:config:write" | "app:code:host:connect" | "platform:code:host:connect" | "platform:security:self" | "platform:runbook:write";
|
|
8
8
|
/** Inputs for obtaining one short-lived, exact-scope device grant. */
|
|
9
9
|
interface ScopedPlatformTokenOptions {
|
|
10
10
|
platform: string;
|
|
@@ -162,6 +162,17 @@ declare function codeConnect(options: CodeConnectOptions): Promise<void>;
|
|
|
162
162
|
/** Run outbound presence and fenced Pi commands without opening a listener. */
|
|
163
163
|
declare function runCodeRuntime(input: CodeRuntimeInput): Promise<void>;
|
|
164
164
|
|
|
165
|
+
interface RunResult {
|
|
166
|
+
code: number;
|
|
167
|
+
stdout: string;
|
|
168
|
+
stderr: string;
|
|
169
|
+
}
|
|
170
|
+
/** Subprocess seam: injectable in tests, `defaultRunner` in production. */
|
|
171
|
+
type CommandRunner = (cmd: string, args: string[], opts?: {
|
|
172
|
+
input?: string;
|
|
173
|
+
cwd?: string;
|
|
174
|
+
}) => Promise<RunResult>;
|
|
175
|
+
|
|
165
176
|
/** Map a CLI failure to its process exit code: 75 (EX_TEMPFAIL) marks work that
|
|
166
177
|
* has not failed but has not finished — a handshake still awaiting human
|
|
167
178
|
* approval (the pending state is persisted, so rerunning resumes it), or a
|
|
@@ -186,6 +197,8 @@ interface CliDependencies {
|
|
|
186
197
|
/** Runs git in the working directory; injected so `runbook impact` can be
|
|
187
198
|
* driven over a fixed diff instead of whatever the checkout happens to be. */
|
|
188
199
|
runGit?: (args: string[]) => string;
|
|
200
|
+
/** Runs Wrangler for one-purpose platform secret rotations. */
|
|
201
|
+
runner?: CommandRunner;
|
|
189
202
|
}
|
|
190
203
|
/**
|
|
191
204
|
* Parse CLI arguments and dispatch the matching odla command.
|
|
@@ -254,7 +267,7 @@ declare function adminAi(options: AdminAiOptions): Promise<void>;
|
|
|
254
267
|
/** Stable, machine-readable division of work between the CLI, coding agent,
|
|
255
268
|
* human operator, and Studio. Printed by `odla-ai capabilities --json`. */
|
|
256
269
|
declare const CAPABILITIES: {
|
|
257
|
-
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", "add or remove app co-owners, each of whom self-provisions their own credentials for the shared db without any secret handoff", "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", "compose declared app-capability schema/rules, create guarded seeds when absent, 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 integration contracts offline and smoke-test a provisioned db environment plus anonymous capability routes", "save and explicitly select non-secret named operator contexts with isolated credential caches; resolve and explain platform, app, environment, and credential provenance without authenticating; then run PM, Discussions, o11y, runbook, and identity operations outside a project checkout", "read one versioned o11y status envelope spanning application RED, exact Worker versions and Cloudflare colos observed in traffic, current live-sync freshness/load, the protected commit-to-visible canary, collector ingest/scheduler trust, provider-owned runtime metrics, account-scoped Durable Object, D1, and R2 evidence under odla-db, and a bounded machine verdict", "read one canonical platform fleet snapshot over private service bindings, including release identities, probe latency, Cloudflare load/runtime freshness, explicit unknowns, and stable next actions through a read-only capability", "compare one project's checked-in Registry intent with live owner-visible state
|
|
270
|
+
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", "add or remove app co-owners, each of whom self-provisions their own credentials for the shared db without any secret handoff", "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", "compose declared app-capability schema/rules, create guarded seeds when absent, 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 integration contracts offline and smoke-test a provisioned db environment plus anonymous capability routes", "save and explicitly select non-secret named operator contexts with isolated credential caches; resolve and explain platform, app, environment, and credential provenance without authenticating; then run PM, Discussions, o11y, runbook, and identity operations outside a project checkout", "read one versioned o11y status envelope spanning application RED, exact Worker versions and Cloudflare colos observed in traffic, current live-sync freshness/load, the protected commit-to-visible canary, collector ingest/scheduler trust, provider-owned runtime metrics, account-scoped Durable Object, D1, and R2 evidence under odla-db, and a bounded machine verdict", "read one canonical platform fleet snapshot over private service bindings, including release identities, probe latency, Cloudflare load/runtime freshness, explicit unknowns, and stable next actions through a read-only capability", "compare one project's checked-in Registry intent with live owner-visible state, freeze a secret-free Registry-revision-bound plan through app:config:read, and conditionally apply checkpoint-free actions through exact app:config:write operation routes", "inspect or bounded-wait one exact durable config-operation journal entry and verify every terminal receipt digest before returning it to remote automation", "inspect durable agent wakeups as a versioned JSON envelope and explicitly requeue one dead-lettered job with a scoped environment credential", "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"];
|
|
258
271
|
readonly agent: readonly ["install and import the selected odla SDKs", "wrap the Worker with withObservability and choose useful telemetry", "install capability packages, mount their runtime routes, and 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"];
|
|
259
272
|
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 changes against an app's live database 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"];
|
|
260
273
|
readonly studio: readonly ["view application telemetry grouped by exact Worker version, reconciled live-sync load/freshness, commit-to-visible canary health, provider-owned Worker runtime metrics, 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 — for the primary owner or any co-owner — 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"];
|
|
@@ -380,17 +393,6 @@ declare function calendarConnect(options: CalendarLifecycleOptions): Promise<Cal
|
|
|
380
393
|
* project grant is not revoked. */
|
|
381
394
|
declare function calendarDisconnect(options: CalendarLifecycleOptions): Promise<CalendarStatus>;
|
|
382
395
|
|
|
383
|
-
interface RunResult {
|
|
384
|
-
code: number;
|
|
385
|
-
stdout: string;
|
|
386
|
-
stderr: string;
|
|
387
|
-
}
|
|
388
|
-
/** Subprocess seam: injectable in tests, `defaultRunner` in production. */
|
|
389
|
-
type CommandRunner = (cmd: string, args: string[], opts?: {
|
|
390
|
-
input?: string;
|
|
391
|
-
cwd?: string;
|
|
392
|
-
}) => Promise<RunResult>;
|
|
393
|
-
|
|
394
396
|
type OdlaEnvName = string;
|
|
395
397
|
type AppRules = Record<string, {
|
|
396
398
|
view?: string;
|
|
@@ -683,6 +685,8 @@ interface ConfigReconciliation {
|
|
|
683
685
|
};
|
|
684
686
|
desiredRevision: ConfigDigest;
|
|
685
687
|
observedRevision: ConfigDigest | null;
|
|
688
|
+
/** Monotonic Registry compare-and-set revision, separate from content hashes. */
|
|
689
|
+
registryRevision: RegistryConfigRevision | null;
|
|
686
690
|
status: ConfigDrift;
|
|
687
691
|
summary: {
|
|
688
692
|
differences: number;
|
|
@@ -704,12 +708,13 @@ interface ConfigDiffDocument extends Omit<ConfigReconciliation, "actions"> {
|
|
|
704
708
|
description: string;
|
|
705
709
|
}>;
|
|
706
710
|
}
|
|
707
|
-
/** Revision-bound `odla.config-plan/
|
|
711
|
+
/** Revision-bound `odla.config-plan/v2` document returned by `configPlan`. */
|
|
708
712
|
interface ConfigPlanDocument extends ConfigReconciliation {
|
|
709
|
-
schemaVersion: "odla.config-plan/
|
|
713
|
+
schemaVersion: "odla.config-plan/v2";
|
|
710
714
|
planDigest: ConfigDigest;
|
|
711
715
|
apply: {
|
|
712
|
-
supported:
|
|
716
|
+
supported: boolean;
|
|
717
|
+
checkpointRequired: boolean;
|
|
713
718
|
reason: string;
|
|
714
719
|
};
|
|
715
720
|
nextActions: Array<{
|
|
@@ -730,6 +735,21 @@ interface ConfigInspectOptions {
|
|
|
730
735
|
stdout?: Pick<typeof console, "log" | "error">;
|
|
731
736
|
now?: () => Date;
|
|
732
737
|
}
|
|
738
|
+
/** Inputs for applying one reviewed, frozen config plan from disk. */
|
|
739
|
+
interface ConfigApplyOptions extends ConfigInspectOptions {
|
|
740
|
+
planPath: string;
|
|
741
|
+
idempotencyKey?: string;
|
|
742
|
+
}
|
|
743
|
+
/** Inputs for exact-id config operation reads and bounded waits. */
|
|
744
|
+
interface ConfigOperationInspectOptions extends ConfigInspectOptions {
|
|
745
|
+
operationId: string;
|
|
746
|
+
intervalSeconds?: number;
|
|
747
|
+
timeoutSeconds?: number;
|
|
748
|
+
pollWait?: (milliseconds: number) => Promise<void>;
|
|
749
|
+
now?: () => Date;
|
|
750
|
+
}
|
|
751
|
+
/** Result returned by config apply or an operation journal command. */
|
|
752
|
+
type ConfigOperationResult = ConfigOperationReceipt;
|
|
733
753
|
/** Secret-free Registry intent normalized from one loaded project configuration. */
|
|
734
754
|
interface DesiredRegistryState {
|
|
735
755
|
appId: string;
|
|
@@ -762,13 +782,22 @@ interface ReconciliationInput {
|
|
|
762
782
|
* the caller explicitly supplies a token. This function performs no writes.
|
|
763
783
|
*/
|
|
764
784
|
declare function configDiff(options: ConfigInspectOptions): Promise<ConfigDiffDocument>;
|
|
765
|
-
/** Freeze
|
|
766
|
-
*
|
|
767
|
-
* The returned plan intentionally has `apply.supported: false`; callers must
|
|
768
|
-
* follow its explicit existing-command or Studio checkpoints separately.
|
|
769
|
-
*/
|
|
785
|
+
/** Freeze content revisions, Registry CAS revision, and ordered actions. */
|
|
770
786
|
declare function configPlan(options: ConfigInspectOptions): Promise<ConfigPlanDocument>;
|
|
771
787
|
|
|
788
|
+
/** Apply one exact frozen plan through the Registry operation journal. */
|
|
789
|
+
declare function configApply(options: ConfigApplyOptions): Promise<ConfigOperationReceipt>;
|
|
790
|
+
/** Read one exact journal entry without replaying effects. */
|
|
791
|
+
declare function configOperationGet(options: ConfigOperationInspectOptions): Promise<ConfigOperationReceipt>;
|
|
792
|
+
/** Poll one exact journal entry until it closes or the bounded wait expires. */
|
|
793
|
+
declare function configOperationWait(options: ConfigOperationInspectOptions): Promise<ConfigOperationReceipt>;
|
|
794
|
+
|
|
795
|
+
/** Stable CLI failure code consumed by `exitCodeFor`. */
|
|
796
|
+
declare class ConfigOperationCommandError extends Error {
|
|
797
|
+
readonly code: string;
|
|
798
|
+
constructor(message: string, code: string);
|
|
799
|
+
}
|
|
800
|
+
|
|
772
801
|
/** Project-config projection owned by Registry reconciliation.
|
|
773
802
|
*
|
|
774
803
|
* This deliberately excludes schema, rules, seeds, secrets, credentials, and
|
|
@@ -1222,4 +1251,4 @@ declare function installSkill(options?: SkillInstallOptions): SkillInstallResult
|
|
|
1222
1251
|
*/
|
|
1223
1252
|
declare function smoke(options: SmokeOptions): Promise<void>;
|
|
1224
1253
|
|
|
1225
|
-
export { AGENT_HARNESSES, type AdminAiOptions, type AgentHarness, type AgentHarnessSelector, type AvailableGoogleCalendar, CAPABILITIES, CODE_BUILD_RECIPES, CODE_PI_IMAGE, COMMAND_SURFACE, type CalendarConfig, type CalendarConnectionState, type CalendarLifecycleOptions, type CalendarServiceConfig, type CalendarStatus, type CliDependencies, type CodeBuildRule, type CodeConnectOptions, type CodeContainerEngine, type CodeHostCapabilities, type CodeLocalSourceDescriptor, type CodeRuntimeInput, type ConfigCoverage, type ConfigDiffDocument, type ConfigDifference, type ConfigDigest, type ConfigDrift, type ConfigInspectOptions, type ConfigPlanAction, type ConfigPlanDocument, type ConfigReconciliation, type ConfigRisk, type ConfigSource, type ConnectGitHubSecuritySourceOptions, type DesiredRegistryState, type DisconnectGitHubSecuritySourceOptions, type FollowHostedSecurityJobOptions, GOOGLE_CALENDAR_EVENTS_SCOPE, type GetHostedSecurityIntentOptions, type GetHostedSecurityJobOptions, type GoogleCalendarConfig, type HarnessInstallResult, type HostedSecurityProfile, type HostedSecurityResult, type HostedSecurityTokenRequest, type IntegrationProbe, type IntegrationSeed, type InvocationProblem, type ListGitHubSecuritySourcesOptions, type ListHostedSecurityJobsOptions, type LoadedProjectConfig, type LocalCredentials, type OdlaIntegration, type OdlaProjectConfig, type ProvisionOptions, type ProvisionPlan, type ReconciliationInput, type RunHostedSecurityOptions, SYSTEM_AI_PURPOSES, type ScopedPlatformTokenOptions, type SecretsPushOptions, type SecretsSetOptions, type SkillInstallOptions, type SkillInstallResult, type SmokeOptions, type StartHostedSecurityJobOptions, type SurfaceNode, type SystemAiPurpose, acceptedAfter, adminAi, calendarBookingPageUrl, calendarCalendars, calendarConnect, calendarDisconnect, calendarServiceConfig, calendarStatus, codeConnect, configDiff, configPlan, connectGitHubSecuritySource, describeProblem, desiredRegistryState, disconnectGitHubSecuritySource, doctor, exitCodeFor, followHostedSecurityJob, getHostedSecurityIntent, getHostedSecurityJob, getHostedSecurityPlan, getHostedSecurityReport, getScopedPlatformToken, inferGitHubRepository, initProject, installSkill, invocationPath, isTerminalHostedSecurityStatus, listGitHubSecuritySources, listHostedSecurityJobs, prepareCodeImages, printCapabilities, provision, reconcileConfig, redactSecrets, repositoryFromGitRemote, runCli, runCodeRuntime, runHostedSecurity, secretsPush, secretsSet, secretsSetClerkKey, smoke, startHostedSecurityJob, surfacePaths, validateInvocation };
|
|
1254
|
+
export { AGENT_HARNESSES, type AdminAiOptions, type AgentHarness, type AgentHarnessSelector, type AvailableGoogleCalendar, CAPABILITIES, CODE_BUILD_RECIPES, CODE_PI_IMAGE, COMMAND_SURFACE, type CalendarConfig, type CalendarConnectionState, type CalendarLifecycleOptions, type CalendarServiceConfig, type CalendarStatus, type CliDependencies, type CodeBuildRule, type CodeConnectOptions, type CodeContainerEngine, type CodeHostCapabilities, type CodeLocalSourceDescriptor, type CodeRuntimeInput, type ConfigApplyOptions, type ConfigCoverage, type ConfigDiffDocument, type ConfigDifference, type ConfigDigest, type ConfigDrift, type ConfigInspectOptions, ConfigOperationCommandError, type ConfigOperationInspectOptions, type ConfigOperationResult, type ConfigPlanAction, type ConfigPlanDocument, type ConfigReconciliation, type ConfigRisk, type ConfigSource, type ConnectGitHubSecuritySourceOptions, type DesiredRegistryState, type DisconnectGitHubSecuritySourceOptions, type FollowHostedSecurityJobOptions, GOOGLE_CALENDAR_EVENTS_SCOPE, type GetHostedSecurityIntentOptions, type GetHostedSecurityJobOptions, type GoogleCalendarConfig, type HarnessInstallResult, type HostedSecurityProfile, type HostedSecurityResult, type HostedSecurityTokenRequest, type IntegrationProbe, type IntegrationSeed, type InvocationProblem, type ListGitHubSecuritySourcesOptions, type ListHostedSecurityJobsOptions, type LoadedProjectConfig, type LocalCredentials, type OdlaIntegration, type OdlaProjectConfig, type ProvisionOptions, type ProvisionPlan, type ReconciliationInput, type RunHostedSecurityOptions, SYSTEM_AI_PURPOSES, type ScopedPlatformTokenOptions, type SecretsPushOptions, type SecretsSetOptions, type SkillInstallOptions, type SkillInstallResult, type SmokeOptions, type StartHostedSecurityJobOptions, type SurfaceNode, type SystemAiPurpose, acceptedAfter, adminAi, calendarBookingPageUrl, calendarCalendars, calendarConnect, calendarDisconnect, calendarServiceConfig, calendarStatus, codeConnect, configApply, configDiff, configOperationGet, configOperationWait, configPlan, connectGitHubSecuritySource, describeProblem, desiredRegistryState, disconnectGitHubSecuritySource, doctor, exitCodeFor, followHostedSecurityJob, getHostedSecurityIntent, getHostedSecurityJob, getHostedSecurityPlan, getHostedSecurityReport, getScopedPlatformToken, inferGitHubRepository, initProject, installSkill, invocationPath, isTerminalHostedSecurityStatus, listGitHubSecuritySources, listHostedSecurityJobs, prepareCodeImages, printCapabilities, provision, reconcileConfig, redactSecrets, repositoryFromGitRemote, runCli, runCodeRuntime, runHostedSecurity, secretsPush, secretsSet, secretsSetClerkKey, smoke, startHostedSecurityJob, surfacePaths, validateInvocation };
|
package/dist/index.js
CHANGED
|
@@ -5,6 +5,7 @@ import {
|
|
|
5
5
|
CODE_BUILD_RECIPES,
|
|
6
6
|
CODE_PI_IMAGE,
|
|
7
7
|
COMMAND_SURFACE,
|
|
8
|
+
ConfigOperationCommandError,
|
|
8
9
|
GOOGLE_CALENDAR_EVENTS_SCOPE,
|
|
9
10
|
SYSTEM_AI_PURPOSES,
|
|
10
11
|
acceptedAfter,
|
|
@@ -16,7 +17,10 @@ import {
|
|
|
16
17
|
calendarServiceConfig,
|
|
17
18
|
calendarStatus,
|
|
18
19
|
codeConnect,
|
|
20
|
+
configApply,
|
|
19
21
|
configDiff,
|
|
22
|
+
configOperationGet,
|
|
23
|
+
configOperationWait,
|
|
20
24
|
configPlan,
|
|
21
25
|
connectGitHubSecuritySource,
|
|
22
26
|
describeProblem,
|
|
@@ -53,13 +57,14 @@ import {
|
|
|
53
57
|
startHostedSecurityJob,
|
|
54
58
|
surfacePaths,
|
|
55
59
|
validateInvocation
|
|
56
|
-
} from "./chunk-
|
|
60
|
+
} from "./chunk-ZAZBUURZ.js";
|
|
57
61
|
export {
|
|
58
62
|
AGENT_HARNESSES,
|
|
59
63
|
CAPABILITIES,
|
|
60
64
|
CODE_BUILD_RECIPES,
|
|
61
65
|
CODE_PI_IMAGE,
|
|
62
66
|
COMMAND_SURFACE,
|
|
67
|
+
ConfigOperationCommandError,
|
|
63
68
|
GOOGLE_CALENDAR_EVENTS_SCOPE,
|
|
64
69
|
SYSTEM_AI_PURPOSES,
|
|
65
70
|
acceptedAfter,
|
|
@@ -71,7 +76,10 @@ export {
|
|
|
71
76
|
calendarServiceConfig,
|
|
72
77
|
calendarStatus,
|
|
73
78
|
codeConnect,
|
|
79
|
+
configApply,
|
|
74
80
|
configDiff,
|
|
81
|
+
configOperationGet,
|
|
82
|
+
configOperationWait,
|
|
75
83
|
configPlan,
|
|
76
84
|
connectGitHubSecuritySource,
|
|
77
85
|
describeProblem,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@odla-ai/cli",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.26.1",
|
|
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",
|
|
@@ -58,7 +58,7 @@
|
|
|
58
58
|
},
|
|
59
59
|
"dependencies": {
|
|
60
60
|
"@odla-ai/ai": ">=0.5.0 <1.0.0",
|
|
61
|
-
"@odla-ai/apps": ">=0.
|
|
61
|
+
"@odla-ai/apps": ">=0.9.0 <1.0.0",
|
|
62
62
|
"@odla-ai/db": ">=0.6.7 <1.0.0",
|
|
63
63
|
"@odla-ai/security": ">=0.3.1 <1.0.0"
|
|
64
64
|
},
|
|
@@ -40,8 +40,8 @@ block (`availabilityCalendars` per env, optional `bookingCalendar`). Normal
|
|
|
40
40
|
provision opens a second, state-bound Google checkpoint issued by the
|
|
41
41
|
platform; the human grants the booking scopes in a browser. Google tokens
|
|
42
42
|
stay platform-side and never become app/CLI secrets. Google Calendar is the
|
|
43
|
-
single source of truth — odla stores no
|
|
44
|
-
nothing syncs.
|
|
43
|
+
single source of truth — odla stores no event mirror, bounded exact-lifetime
|
|
44
|
+
mutation receipts are purged with the app, and nothing syncs.
|
|
45
45
|
|
|
46
46
|
```ts
|
|
47
47
|
// Trusted Worker only — the admin key must never enter browser code.
|
|
@@ -61,7 +61,9 @@ const { booking } = await cal.actions.create(
|
|
|
61
61
|
```
|
|
62
62
|
|
|
63
63
|
Store the returned `eventId`/`meetUrl` on the app's own record;
|
|
64
|
-
`actions.reschedule(eventId, …)` and
|
|
64
|
+
`actions.reschedule(eventId, { idempotencyKey, … })` and
|
|
65
|
+
`actions.cancel(eventId, { idempotencyKey })` use it. Derive each key from the
|
|
66
|
+
record and exact intended action; reuse it only for an exact retry. A
|
|
65
67
|
taken slot rejects with non-retryable `calendar_slot_unavailable` — refetch
|
|
66
68
|
slots, don't retry. Browser code never calls `initCalendar` or the platform
|
|
67
69
|
calendar routes; it hits the app's own endpoints and may import pure helpers
|
|
@@ -3,7 +3,8 @@
|
|
|
3
3
|
Use this phase when the site should offer real scheduling: visitors pick a
|
|
4
4
|
bookable slot and the app creates a live Google Calendar event — with a Meet
|
|
5
5
|
link and an invitation email that Google itself sends. Google Calendar is the
|
|
6
|
-
single source of truth; odla stores no calendar
|
|
6
|
+
single source of truth; odla stores no calendar mirror. Bounded exact-lifetime
|
|
7
|
+
mutation receipts make retries safe and are removed on app purge. There is no
|
|
7
8
|
sync, no mirror, and no `$bookings` namespace.
|
|
8
9
|
|
|
9
10
|
Human obligations: complete the server-issued Google consent page in a
|
|
@@ -95,14 +96,17 @@ this app's own Worker endpoints and may import pure helpers from
|
|
|
95
96
|
```
|
|
96
97
|
|
|
97
98
|
Store the returned `booking.eventId` and `booking.meetUrl` on the app's
|
|
98
|
-
own record (its odla-db row) — that
|
|
99
|
-
|
|
99
|
+
own record (its odla-db row) — that is the app's product record. Attendee
|
|
100
|
+
source data lives in Google; the platform may retain the bounded create
|
|
101
|
+
response in the exact app lifetime for replay. On `calendar_slot_unavailable` (409,
|
|
100
102
|
non-retryable) return a "slot taken" response; the client refetches
|
|
101
103
|
`/api/booking/slots` and re-picks. On retryable
|
|
102
104
|
`calendar_booking_in_progress`, retry once after a short delay.
|
|
103
|
-
6. Reschedule/cancel go through the stored id
|
|
104
|
-
`cal.actions.reschedule(eventId, {
|
|
105
|
-
|
|
105
|
+
6. Reschedule/cancel go through the stored id and require stable exact-action
|
|
106
|
+
keys: `cal.actions.reschedule(eventId, { idempotencyKey:
|
|
107
|
+
\`booking:${applicationId}:move:${startAt}:${endAt}\`, startAt, endAt })`
|
|
108
|
+
and `cal.actions.cancel(eventId, { idempotencyKey:
|
|
109
|
+
\`booking:${applicationId}:cancel\` })` — expose them as app endpoints
|
|
106
110
|
gated to the record's owner. Attendees can also act through Google's own
|
|
107
111
|
invitation flows; treat Google as authoritative.
|
|
108
112
|
7. Frontend. Two supported shapes:
|
|
@@ -125,7 +129,8 @@ UI creates the event on the booking calendar with a Meet link; the Google
|
|
|
125
129
|
invitation email arrives in the test attendee's inbox; a repeat POST with the
|
|
126
130
|
same idempotency key returns `duplicate: true` (no second event); a taken
|
|
127
131
|
slot returns 409 and the UI refetches slots; reschedule and cancel work via
|
|
128
|
-
the stored `eventId`;
|
|
129
|
-
app
|
|
132
|
+
the stored `eventId`; no event mirror exists and retry receipts are purged
|
|
133
|
+
with the app; attendee source data remains in Google and the app stores only
|
|
134
|
+
its own product record; no Google credential exists in local files; and
|
|
130
135
|
PM records the booking-flow decision and the active task comment links this
|
|
131
136
|
evidence.
|