@odla-ai/cli 0.25.19 → 0.25.20

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 CHANGED
@@ -746,6 +746,12 @@ export default {
746
746
  `db.schema` and `db.rules` may be inline objects, JSON files, or JS modules
747
747
  exporting `default`, `schema` / `SCHEMA`, or `rules` / `RULES`.
748
748
 
749
+ `services` accepts only ids from `@odla-ai/apps`'
750
+ `APP_SERVICE_CATALOG`. The CLI validates the same-environment dependencies
751
+ from that catalog before authentication or mutation; currently `calendar`,
752
+ `chat`, and `kg` require `db`. Application npm integrations remain under
753
+ `integrations`, not `services`.
754
+
749
755
  If schema is present and rules are omitted, `defaultRules: "deny"` generates
750
756
  deny-all rules for every schema entity. That is the safe default for Workers
751
757
  that mediate reads and writes with an app key.
package/dist/bin.cjs CHANGED
@@ -968,6 +968,7 @@ var import_node_process8 = __toESM(require("process"), 1);
968
968
  var import_node_fs4 = require("fs");
969
969
  var import_node_path4 = require("path");
970
970
  var import_node_url = require("url");
971
+ var import_apps = require("@odla-ai/apps");
971
972
 
972
973
  // src/integration-validation.ts
973
974
  function validateIntegrations(cfg, path, defaultServices) {
@@ -1055,6 +1056,7 @@ async function loadProjectConfig(configPath = "odla.config.mjs") {
1055
1056
  const dbEndpoint = trimSlash(process.env.ODLA_DB_ENDPOINT || raw.dbEndpoint || platformUrl);
1056
1057
  const envs = unique2(raw.envs?.length ? raw.envs : DEFAULT_ENVS);
1057
1058
  const services = unique2(raw.services?.length ? raw.services : DEFAULT_SERVICES);
1059
+ validateServices(services, resolved);
1058
1060
  validateCalendarConfig(raw, envs, services, resolved);
1059
1061
  const local = {
1060
1062
  tokenFile: (0, import_node_path4.resolve)(rootDir, raw.local?.tokenFile ?? ".odla/dev-token.json"),
@@ -1210,7 +1212,19 @@ function validateCalendarConfig(cfg, envs, services, path) {
1210
1212
  }
1211
1213
  }
1212
1214
  }
1213
- if (enabled && !services.includes("db")) throw new Error(`${path}: calendar service requires the db service`);
1215
+ }
1216
+ function validateServices(services, path) {
1217
+ for (const service of services) {
1218
+ const definition = (0, import_apps.appServiceDefinition)(service);
1219
+ if (!definition) {
1220
+ throw new Error(`${path}: unknown service "${service}" (known: ${(0, import_apps.appServiceIds)().join(", ")})`);
1221
+ }
1222
+ for (const dependency of definition.requires) {
1223
+ if (!services.includes(dependency)) {
1224
+ throw new Error(`${path}: ${service} service requires the ${dependency} service`);
1225
+ }
1226
+ }
1227
+ }
1214
1228
  }
1215
1229
  function assertOnly(value, allowed, label) {
1216
1230
  const extra = Object.keys(value).find((key) => !allowed.includes(key));
@@ -1534,7 +1548,7 @@ async function adminCommand(parsed, deps = {}) {
1534
1548
  }
1535
1549
 
1536
1550
  // src/tenant.ts
1537
- var import_apps = require("@odla-ai/apps");
1551
+ var import_apps2 = require("@odla-ai/apps");
1538
1552
  function resolveEnv(cfg, requested) {
1539
1553
  const env = requested ?? (cfg.envs.includes("dev") ? "dev" : cfg.envs[0]);
1540
1554
  if (!env || !cfg.envs.includes(env)) {
@@ -1544,7 +1558,7 @@ function resolveEnv(cfg, requested) {
1544
1558
  }
1545
1559
  function resolveTenant(cfg, requested) {
1546
1560
  const env = resolveEnv(cfg, requested);
1547
- return { env, tenant: (0, import_apps.tenantIdFor)(cfg.app.id, env) };
1561
+ return { env, tenant: (0, import_apps2.tenantIdFor)(cfg.app.id, env) };
1548
1562
  }
1549
1563
  function bothTenants(cfg) {
1550
1564
  for (const env of ["dev", "prod"]) {
@@ -1554,7 +1568,7 @@ function bothTenants(cfg) {
1554
1568
  );
1555
1569
  }
1556
1570
  }
1557
- return { sandbox: (0, import_apps.tenantIdFor)(cfg.app.id, "dev"), live: (0, import_apps.tenantIdFor)(cfg.app.id, "prod") };
1571
+ return { sandbox: (0, import_apps2.tenantIdFor)(cfg.app.id, "dev"), live: (0, import_apps2.tenantIdFor)(cfg.app.id, "prod") };
1558
1572
  }
1559
1573
 
1560
1574
  // src/agent-command.ts
@@ -3090,6 +3104,7 @@ function harnessOption(value, flag) {
3090
3104
  // src/init.ts
3091
3105
  var import_node_fs11 = require("fs");
3092
3106
  var import_node_path9 = require("path");
3107
+ var import_apps3 = require("@odla-ai/apps");
3093
3108
  function initProject(options) {
3094
3109
  const out = options.stdout ?? console;
3095
3110
  const rootDir = (0, import_node_path9.resolve)(options.rootDir ?? process.cwd());
@@ -3102,7 +3117,13 @@ function initProject(options) {
3102
3117
  }
3103
3118
  const envs = options.envs?.length ? options.envs : ["dev"];
3104
3119
  const services = options.services?.length ? options.services : ["db", "ai"];
3105
- if (services.includes("calendar") && !services.includes("db")) throw new Error("--services calendar requires db");
3120
+ for (const service of services) {
3121
+ const definition = (0, import_apps3.appServiceDefinition)(service);
3122
+ if (!definition) throw new Error(`--services contains unknown service "${service}" (known: ${(0, import_apps3.appServiceIds)().join(", ")})`);
3123
+ for (const dependency of definition.requires) {
3124
+ if (!services.includes(dependency)) throw new Error(`--services ${service} requires ${dependency}`);
3125
+ }
3126
+ }
3106
3127
  const aiProvider = options.aiProvider ?? "anthropic";
3107
3128
  (0, import_node_fs11.mkdirSync)((0, import_node_path9.dirname)(configPath), { recursive: true });
3108
3129
  (0, import_node_fs11.mkdirSync)((0, import_node_path9.resolve)(rootDir, "src/odla"), { recursive: true });
@@ -3292,7 +3313,7 @@ function assertWranglerConfig(cfg) {
3292
3313
 
3293
3314
  // src/secrets-set.ts
3294
3315
  var import_ai = require("@odla-ai/ai");
3295
- var import_apps2 = require("@odla-ai/apps");
3316
+ var import_apps4 = require("@odla-ai/apps");
3296
3317
  var PROD_ENV_NAMES2 = /* @__PURE__ */ new Set(["prod", "production"]);
3297
3318
  async function secretsSet(options) {
3298
3319
  const name = (options.name ?? "").trim();
@@ -3344,7 +3365,7 @@ async function resolveVaultWrite(options) {
3344
3365
  throw new Error(`refusing to store a secret for "${options.env}" without --yes`);
3345
3366
  }
3346
3367
  const value = await secretInputValue(options, "secret");
3347
- return { cfg, tenantId: (0, import_apps2.tenantIdFor)(cfg.app.id, options.env), value, doFetch, out };
3368
+ return { cfg, tenantId: (0, import_apps4.tenantIdFor)(cfg.app.id, options.env), value, doFetch, out };
3348
3369
  }
3349
3370
 
3350
3371
  // src/skill.ts
@@ -8972,7 +8993,7 @@ async function read2(url, headers, doFetch) {
8972
8993
  }
8973
8994
 
8974
8995
  // src/provision.ts
8975
- var import_apps5 = require("@odla-ai/apps");
8996
+ var import_apps7 = require("@odla-ai/apps");
8976
8997
  var import_ai3 = require("@odla-ai/ai");
8977
8998
  var import_node_process10 = __toESM(require("process"), 1);
8978
8999
 
@@ -9029,9 +9050,9 @@ async function responseText(res) {
9029
9050
  }
9030
9051
 
9031
9052
  // src/provision-credentials.ts
9032
- var import_apps3 = require("@odla-ai/apps");
9053
+ var import_apps5 = require("@odla-ai/apps");
9033
9054
  async function provisionEnvCredentials(opts) {
9034
- const tenantId = (0, import_apps3.tenantIdFor)(opts.cfg.app.id, opts.env);
9055
+ const tenantId = (0, import_apps5.tenantIdFor)(opts.cfg.app.id, opts.env);
9035
9056
  const prior = opts.credentials?.envs[opts.env];
9036
9057
  let credentials = opts.credentials;
9037
9058
  let dbKey = opts.cfg.services.includes("db") && !opts.rotateDb ? prior?.dbKey : void 0;
@@ -9125,18 +9146,13 @@ async function safeText4(res) {
9125
9146
 
9126
9147
  // src/provision-helpers.ts
9127
9148
  var import_ai2 = require("@odla-ai/ai");
9128
- var import_apps4 = require("@odla-ai/apps");
9129
- function serviceRank(service) {
9130
- if (service === "db") return 0;
9131
- if (service === "calendar") return 2;
9132
- return 1;
9133
- }
9149
+ var import_apps6 = require("@odla-ai/apps");
9134
9150
  function defaultSecretName(provider) {
9135
9151
  const names = import_ai2.DEFAULT_SECRET_NAMES;
9136
9152
  return names[provider] ?? `${provider}_api_key`;
9137
9153
  }
9138
9154
  async function assertTenantAdminAccess(doFetch, cfg, env, token) {
9139
- const tenantId = (0, import_apps4.tenantIdFor)(cfg.app.id, env);
9155
+ const tenantId = (0, import_apps6.tenantIdFor)(cfg.app.id, env);
9140
9156
  const res = await doFetch(`${cfg.dbEndpoint}/admin/apps/${encodeURIComponent(tenantId)}/entitlements`, {
9141
9157
  headers: { authorization: `Bearer ${token}` }
9142
9158
  });
@@ -9245,7 +9261,7 @@ async function provision(options) {
9245
9261
  }
9246
9262
  const doFetch = options.fetch ?? fetch;
9247
9263
  const token = await getDeveloperToken(cfg, options, doFetch, out);
9248
- const apps = (0, import_apps5.createAppsClient)({ endpoint: cfg.platformUrl, token, fetcher: { fetch: doFetch } });
9264
+ const apps = (0, import_apps7.createAppsClient)({ endpoint: cfg.platformUrl, token, fetcher: { fetch: doFetch } });
9249
9265
  const existing = await apps.resolveApp(cfg.app.id);
9250
9266
  if (existing) {
9251
9267
  out.log(`app: ${cfg.app.id} already exists`);
@@ -9256,7 +9272,7 @@ async function provision(options) {
9256
9272
  for (const env of cfg.envs) {
9257
9273
  await assertTenantAdminAccess(doFetch, cfg, env, token);
9258
9274
  }
9259
- const serviceOrder = [...cfg.services].sort((a, b) => serviceRank(a) - serviceRank(b));
9275
+ const serviceOrder = (0, import_apps7.orderAppServices)(cfg.services);
9260
9276
  for (const env of cfg.envs) {
9261
9277
  for (const service of serviceOrder) {
9262
9278
  if (service === "ai") {
@@ -9289,7 +9305,7 @@ async function provision(options) {
9289
9305
  }
9290
9306
  }
9291
9307
  for (const env of cfg.envs) {
9292
- const tenantId = (0, import_apps5.tenantIdFor)(cfg.app.id, env);
9308
+ const tenantId = (0, import_apps7.tenantIdFor)(cfg.app.id, env);
9293
9309
  credentials = await provisionEnvCredentials({
9294
9310
  cfg,
9295
9311
  env,