@topolo/cli 0.6.5 → 0.6.6

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.
@@ -483,7 +483,9 @@ function emitBindings(lines, bindings, env) {
483
483
  lines.push(`binding = ${tomlString(d.binding)}`);
484
484
  lines.push(`database_name = ${tomlString(cfg.databaseName)}`);
485
485
  if (cfg.databaseId) lines.push(`database_id = ${tomlString(cfg.databaseId)}`);
486
- if (d.migrationsDir) lines.push(`migrations_dir = ${tomlString(d.migrationsDir)}`);
486
+ if (d.manageMigrations !== false && d.migrationsDir) {
487
+ lines.push(`migrations_dir = ${tomlString(d.migrationsDir)}`);
488
+ }
487
489
  lines.push('');
488
490
  }
489
491
  for (const r of bindings.r2 || []) {
@@ -656,7 +658,11 @@ function emitCloudcontrol() {
656
658
  const reportedHost = host || publicUrlHost(t, env);
657
659
  const reportedRoutes = routes.length ? routes : (host ? [host] : []);
658
660
  const d1Migrations = (t.bindings?.d1 || [])
659
- .filter((binding) => bindingAppliesToEnv(binding, env) && binding[env])
661
+ .filter((binding) => (
662
+ bindingAppliesToEnv(binding, env)
663
+ && binding[env]
664
+ && binding.manageMigrations !== false
665
+ ))
660
666
  .map((binding) => ({
661
667
  binding: binding.binding,
662
668
  ...(binding.migrationsDir || binding.migrations_dir
@@ -687,7 +693,7 @@ function emitCloudcontrol() {
687
693
  ...(Array.isArray(t.requiredSecrets) && t.requiredSecrets.length
688
694
  ? { required_secrets: t.requiredSecrets }
689
695
  : {}),
690
- ...(d1Migrations.length ? { migrations: { d1: d1Migrations } } : {}),
696
+ ...(t.bindings?.d1?.length ? { migrations: { d1: d1Migrations } } : {}),
691
697
  ...preservedCloudControlFields,
692
698
  });
693
699
  }
package/dist/index.js CHANGED
@@ -98,13 +98,13 @@ var TopoloHttpError = class extends TopoloSdkError {
98
98
  path;
99
99
  requestId;
100
100
  retryAfter;
101
- constructor(service, path8, status, body, message, options = {}) {
102
- super(extractHttpErrorCode(body), message ?? `HTTP ${status} from ${service}${path8}`);
101
+ constructor(service, path9, status, body, message, options = {}) {
102
+ super(extractHttpErrorCode(body), message ?? `HTTP ${status} from ${service}${path9}`);
103
103
  this.name = "TopoloHttpError";
104
104
  this.status = status;
105
105
  this.body = body;
106
106
  this.service = service;
107
- this.path = path8;
107
+ this.path = path9;
108
108
  this.requestId = options.requestId;
109
109
  this.retryAfter = options.retryAfter;
110
110
  }
@@ -113,6 +113,7 @@ var APP_API_URLS = {
113
113
  agent: "https://agent.topolo.app",
114
114
  auth: "https://auth.topolo.app",
115
115
  backup: "https://backup.topolo.app",
116
+ blog: "https://blog.topolo.app",
116
117
  books: "https://books.topolo.app",
117
118
  brand: "https://brand.topolo.app",
118
119
  bugfix: "https://bugfix.topolo.app",
@@ -125,6 +126,7 @@ var APP_API_URLS = {
125
126
  compose: "https://compose.topolo.app",
126
127
  consent: "https://consent.topolo.app",
127
128
  crm: "https://crm.topolo.app",
129
+ design: "https://design.topolo.app",
128
130
  developers: "https://developers.topolo.app",
129
131
  director: "https://director.topolo.app",
130
132
  feed: "https://feed.topolo.app",
@@ -208,7 +210,9 @@ var APPLICATIONS = {
208
210
  "domains": [
209
211
  "agent.topolo.app"
210
212
  ],
211
- "routes": [],
213
+ "routes": [
214
+ "agent.topolo.app"
215
+ ],
212
216
  "appId": "agent"
213
217
  },
214
218
  {
@@ -269,6 +273,38 @@ var APPLICATIONS = {
269
273
  }
270
274
  ]
271
275
  },
276
+ "blog": {
277
+ "id": "blog",
278
+ "appDir": "TopoloBlog",
279
+ "name": "topolo-blog",
280
+ "packageName": "topolo-blog",
281
+ "productionUrl": "https://blog.topolo.app",
282
+ "services": [
283
+ "blog"
284
+ ],
285
+ "deployTargets": [
286
+ {
287
+ "name": "topolo-blog",
288
+ "kind": "worker",
289
+ "apiUrl": "https://blog.topolo.app",
290
+ "domains": [
291
+ "blog.topolo.app"
292
+ ],
293
+ "routes": [
294
+ "blog.topolo.app"
295
+ ],
296
+ "appId": "blog"
297
+ },
298
+ {
299
+ "name": "topolo-blog-api",
300
+ "kind": "worker",
301
+ "apiUrl": null,
302
+ "domains": [],
303
+ "routes": [],
304
+ "appId": null
305
+ }
306
+ ]
307
+ },
272
308
  "books": {
273
309
  "id": "books",
274
310
  "appDir": "TopoloBooks",
@@ -286,7 +322,9 @@ var APPLICATIONS = {
286
322
  "domains": [
287
323
  "books.topolo.app"
288
324
  ],
289
- "routes": [],
325
+ "routes": [
326
+ "books.topolo.app"
327
+ ],
290
328
  "appId": "books"
291
329
  },
292
330
  {
@@ -436,7 +474,9 @@ var APPLICATIONS = {
436
474
  "domains": [
437
475
  "campaigns.topolo.app"
438
476
  ],
439
- "routes": [],
477
+ "routes": [
478
+ "campaigns.topolo.app"
479
+ ],
440
480
  "appId": "campaigns"
441
481
  },
442
482
  {
@@ -646,11 +686,45 @@ var APPLICATIONS = {
646
686
  "domains": [
647
687
  "crm.topolo.app"
648
688
  ],
649
- "routes": [],
689
+ "routes": [
690
+ "crm.topolo.app"
691
+ ],
650
692
  "appId": "crm"
651
693
  }
652
694
  ]
653
695
  },
696
+ "design": {
697
+ "id": "design",
698
+ "appDir": "TopoloDesign",
699
+ "name": "topolo-design",
700
+ "packageName": "@topolo-io/design",
701
+ "productionUrl": "https://design.topolo.app",
702
+ "services": [
703
+ "design"
704
+ ],
705
+ "deployTargets": [
706
+ {
707
+ "name": "topolo-design",
708
+ "kind": "worker",
709
+ "apiUrl": "https://design.topolo.app",
710
+ "domains": [
711
+ "design.topolo.app"
712
+ ],
713
+ "routes": [
714
+ "design.topolo.app"
715
+ ],
716
+ "appId": "design"
717
+ },
718
+ {
719
+ "name": "topolo-design-api",
720
+ "kind": "worker",
721
+ "apiUrl": null,
722
+ "domains": [],
723
+ "routes": [],
724
+ "appId": null
725
+ }
726
+ ]
727
+ },
654
728
  "developers": {
655
729
  "id": "developers",
656
730
  "appDir": "TopoloDevelopers",
@@ -938,7 +1012,9 @@ var APPLICATIONS = {
938
1012
  "domains": [
939
1013
  "insights.topolo.app"
940
1014
  ],
941
- "routes": [],
1015
+ "routes": [
1016
+ "insights.topolo.app"
1017
+ ],
942
1018
  "appId": "insights"
943
1019
  },
944
1020
  {
@@ -1322,7 +1398,9 @@ var APPLICATIONS = {
1322
1398
  "domains": [
1323
1399
  "pay.topolo.app"
1324
1400
  ],
1325
- "routes": [],
1401
+ "routes": [
1402
+ "pay.topolo.app"
1403
+ ],
1326
1404
  "appId": "pay"
1327
1405
  },
1328
1406
  {
@@ -2277,17 +2355,17 @@ function validateTopoloActionInput(schema, input3) {
2277
2355
  validateNode(schema, input3, "$", schema, errors, 0);
2278
2356
  return { valid: errors.length === 0, errors };
2279
2357
  }
2280
- function inspectSchema(schema, path8, root, depth) {
2281
- if (depth > 128) return { path: path8, code: "schema_depth", message: "Schema recursion exceeded 128 levels." };
2358
+ function inspectSchema(schema, path9, root, depth) {
2359
+ if (depth > 128) return { path: path9, code: "schema_depth", message: "Schema recursion exceeded 128 levels." };
2282
2360
  const unsupportedKeyword = Object.keys(schema).find((keyword) => !SUPPORTED_SCHEMA_KEYWORDS.has(keyword));
2283
2361
  if (unsupportedKeyword) {
2284
- return { path: path8, code: "unsupported_schema_keyword", message: `Action schema uses unsupported keyword ${unsupportedKeyword}.` };
2362
+ return { path: path9, code: "unsupported_schema_keyword", message: `Action schema uses unsupported keyword ${unsupportedKeyword}.` };
2285
2363
  }
2286
2364
  if (typeof schema.format === "string" && !["uri", "email", "date-time"].includes(schema.format)) {
2287
- return { path: path8, code: "unsupported_schema_format", message: `Action schema uses unsupported format ${schema.format}.` };
2365
+ return { path: path9, code: "unsupported_schema_format", message: `Action schema uses unsupported format ${schema.format}.` };
2288
2366
  }
2289
2367
  if (typeof schema.$ref === "string" && !resolveLocalReference(root, schema.$ref)) {
2290
- return { path: path8, code: "unsupported_schema_ref", message: `Cannot resolve schema reference ${schema.$ref}.` };
2368
+ return { path: path9, code: "unsupported_schema_ref", message: `Cannot resolve schema reference ${schema.$ref}.` };
2291
2369
  }
2292
2370
  const children = [];
2293
2371
  if (isRecord(schema.properties)) children.push(...Object.entries(schema.properties));
@@ -2303,7 +2381,7 @@ function inspectSchema(schema, path8, root, depth) {
2303
2381
  );
2304
2382
  for (const [key, child] of children) {
2305
2383
  if (!isRecord(child)) continue;
2306
- const issue = inspectSchema(child, `${path8}.${key}`, root, depth + 1);
2384
+ const issue = inspectSchema(child, `${path9}.${key}`, root, depth + 1);
2307
2385
  if (issue) return issue;
2308
2386
  }
2309
2387
  return null;
@@ -2311,129 +2389,129 @@ function inspectSchema(schema, path8, root, depth) {
2311
2389
  function arraySchemaEntries(keyword, value) {
2312
2390
  return Array.isArray(value) ? value.map((candidate, index) => [`${keyword}[${index}]`, candidate]) : [];
2313
2391
  }
2314
- function validateNode(schema, value, path8, root, errors, depth) {
2392
+ function validateNode(schema, value, path9, root, errors, depth) {
2315
2393
  if (depth > 128) {
2316
- errors.push({ path: path8, code: "schema_depth", message: "Schema recursion exceeded 128 levels." });
2394
+ errors.push({ path: path9, code: "schema_depth", message: "Schema recursion exceeded 128 levels." });
2317
2395
  return;
2318
2396
  }
2319
2397
  if (typeof schema.$ref === "string") {
2320
2398
  const resolved = resolveLocalReference(root, schema.$ref);
2321
2399
  if (!resolved) {
2322
- errors.push({ path: path8, code: "unsupported_schema_ref", message: `Cannot resolve schema reference ${schema.$ref}.` });
2400
+ errors.push({ path: path9, code: "unsupported_schema_ref", message: `Cannot resolve schema reference ${schema.$ref}.` });
2323
2401
  return;
2324
2402
  }
2325
- validateNode(resolved, value, path8, root, errors, depth + 1);
2403
+ validateNode(resolved, value, path9, root, errors, depth + 1);
2326
2404
  }
2327
2405
  if (Array.isArray(schema.allOf)) {
2328
2406
  for (const candidate of schema.allOf) {
2329
- if (isRecord(candidate)) validateNode(candidate, value, path8, root, errors, depth + 1);
2407
+ if (isRecord(candidate)) validateNode(candidate, value, path9, root, errors, depth + 1);
2330
2408
  }
2331
2409
  }
2332
2410
  if (Array.isArray(schema.anyOf) && !schema.anyOf.some((candidate) => candidateMatches(candidate, value, root, depth))) {
2333
- errors.push({ path: path8, code: "any_of", message: "Value does not match any allowed schema." });
2411
+ errors.push({ path: path9, code: "any_of", message: "Value does not match any allowed schema." });
2334
2412
  return;
2335
2413
  }
2336
2414
  if (Array.isArray(schema.oneOf)) {
2337
2415
  const matches = schema.oneOf.filter((candidate) => candidateMatches(candidate, value, root, depth)).length;
2338
2416
  if (matches !== 1) {
2339
- errors.push({ path: path8, code: "one_of", message: "Value must match exactly one allowed schema." });
2417
+ errors.push({ path: path9, code: "one_of", message: "Value must match exactly one allowed schema." });
2340
2418
  return;
2341
2419
  }
2342
2420
  }
2343
2421
  if (value === null && schema.nullable === true) return;
2344
2422
  if (Object.prototype.hasOwnProperty.call(schema, "const") && !sameJsonValue(value, schema.const)) {
2345
- errors.push({ path: path8, code: "const", message: `Value must equal ${JSON.stringify(schema.const)}.` });
2423
+ errors.push({ path: path9, code: "const", message: `Value must equal ${JSON.stringify(schema.const)}.` });
2346
2424
  return;
2347
2425
  }
2348
2426
  if (Array.isArray(schema.enum) && !schema.enum.some((candidate) => sameJsonValue(value, candidate))) {
2349
- errors.push({ path: path8, code: "enum", message: `Value must be one of ${schema.enum.map((item) => JSON.stringify(item)).join(", ")}.` });
2427
+ errors.push({ path: path9, code: "enum", message: `Value must be one of ${schema.enum.map((item) => JSON.stringify(item)).join(", ")}.` });
2350
2428
  return;
2351
2429
  }
2352
2430
  if (!matchesType(schema.type, value)) {
2353
- errors.push({ path: path8, code: "type", message: `Expected ${String(schema.type)}.` });
2431
+ errors.push({ path: path9, code: "type", message: `Expected ${String(schema.type)}.` });
2354
2432
  return;
2355
2433
  }
2356
- if (typeof value === "string") validateString(schema, value, path8, errors);
2357
- if (typeof value === "number") validateNumber(schema, value, path8, errors);
2358
- if (Array.isArray(value)) validateArray(schema, value, path8, root, errors, depth);
2359
- if (isRecord(value)) validateObject(schema, value, path8, root, errors, depth);
2434
+ if (typeof value === "string") validateString(schema, value, path9, errors);
2435
+ if (typeof value === "number") validateNumber(schema, value, path9, errors);
2436
+ if (Array.isArray(value)) validateArray(schema, value, path9, root, errors, depth);
2437
+ if (isRecord(value)) validateObject(schema, value, path9, root, errors, depth);
2360
2438
  }
2361
- function validateObject(schema, value, path8, root, errors, depth) {
2439
+ function validateObject(schema, value, path9, root, errors, depth) {
2362
2440
  if (typeof schema.minProperties === "number" && Object.keys(value).length < schema.minProperties) {
2363
- errors.push({ path: path8, code: "min_properties", message: `Expected at least ${schema.minProperties} properties.` });
2441
+ errors.push({ path: path9, code: "min_properties", message: `Expected at least ${schema.minProperties} properties.` });
2364
2442
  }
2365
2443
  if (typeof schema.maxProperties === "number" && Object.keys(value).length > schema.maxProperties) {
2366
- errors.push({ path: path8, code: "max_properties", message: `Expected at most ${schema.maxProperties} properties.` });
2444
+ errors.push({ path: path9, code: "max_properties", message: `Expected at most ${schema.maxProperties} properties.` });
2367
2445
  }
2368
2446
  const properties = isRecord(schema.properties) ? schema.properties : {};
2369
2447
  const required = Array.isArray(schema.required) ? schema.required.map(String) : [];
2370
2448
  for (const key of required) {
2371
2449
  if (!Object.prototype.hasOwnProperty.call(value, key)) {
2372
- errors.push({ path: `${path8}.${key}`, code: "required", message: "Required property is missing." });
2450
+ errors.push({ path: `${path9}.${key}`, code: "required", message: "Required property is missing." });
2373
2451
  }
2374
2452
  }
2375
2453
  if (isRecord(schema.propertyNames)) {
2376
2454
  for (const key of Object.keys(value)) {
2377
- validateNode(schema.propertyNames, key, `${path8}.${key}`, root, errors, depth + 1);
2455
+ validateNode(schema.propertyNames, key, `${path9}.${key}`, root, errors, depth + 1);
2378
2456
  }
2379
2457
  }
2380
2458
  for (const [key, child] of Object.entries(value)) {
2381
2459
  const childSchema = properties[key];
2382
2460
  if (isRecord(childSchema)) {
2383
- validateNode(childSchema, child, `${path8}.${key}`, root, errors, depth + 1);
2461
+ validateNode(childSchema, child, `${path9}.${key}`, root, errors, depth + 1);
2384
2462
  } else if (schema.additionalProperties === false) {
2385
- errors.push({ path: `${path8}.${key}`, code: "additional_property", message: "Property is not declared by the action schema." });
2463
+ errors.push({ path: `${path9}.${key}`, code: "additional_property", message: "Property is not declared by the action schema." });
2386
2464
  } else if (isRecord(schema.additionalProperties)) {
2387
- validateNode(schema.additionalProperties, child, `${path8}.${key}`, root, errors, depth + 1);
2465
+ validateNode(schema.additionalProperties, child, `${path9}.${key}`, root, errors, depth + 1);
2388
2466
  }
2389
2467
  }
2390
2468
  }
2391
- function validateArray(schema, value, path8, root, errors, depth) {
2469
+ function validateArray(schema, value, path9, root, errors, depth) {
2392
2470
  if (typeof schema.minItems === "number" && value.length < schema.minItems) {
2393
- errors.push({ path: path8, code: "min_items", message: `Expected at least ${schema.minItems} items.` });
2471
+ errors.push({ path: path9, code: "min_items", message: `Expected at least ${schema.minItems} items.` });
2394
2472
  }
2395
2473
  if (typeof schema.maxItems === "number" && value.length > schema.maxItems) {
2396
- errors.push({ path: path8, code: "max_items", message: `Expected at most ${schema.maxItems} items.` });
2474
+ errors.push({ path: path9, code: "max_items", message: `Expected at most ${schema.maxItems} items.` });
2397
2475
  }
2398
2476
  if (schema.uniqueItems === true) {
2399
2477
  const unique4 = new Set(value.map((item) => JSON.stringify(item)));
2400
- if (unique4.size !== value.length) errors.push({ path: path8, code: "unique_items", message: "Expected every item to be unique." });
2478
+ if (unique4.size !== value.length) errors.push({ path: path9, code: "unique_items", message: "Expected every item to be unique." });
2401
2479
  }
2402
2480
  if (isRecord(schema.items)) {
2403
- value.forEach((item, index) => validateNode(schema.items, item, `${path8}[${index}]`, root, errors, depth + 1));
2481
+ value.forEach((item, index) => validateNode(schema.items, item, `${path9}[${index}]`, root, errors, depth + 1));
2404
2482
  }
2405
2483
  }
2406
- function validateString(schema, value, path8, errors) {
2484
+ function validateString(schema, value, path9, errors) {
2407
2485
  if (typeof schema.minLength === "number" && value.length < schema.minLength) {
2408
- errors.push({ path: path8, code: "min_length", message: `Expected at least ${schema.minLength} characters.` });
2486
+ errors.push({ path: path9, code: "min_length", message: `Expected at least ${schema.minLength} characters.` });
2409
2487
  }
2410
2488
  if (typeof schema.maxLength === "number" && value.length > schema.maxLength) {
2411
- errors.push({ path: path8, code: "max_length", message: `Expected at most ${schema.maxLength} characters.` });
2489
+ errors.push({ path: path9, code: "max_length", message: `Expected at most ${schema.maxLength} characters.` });
2412
2490
  }
2413
2491
  if (typeof schema.pattern === "string") {
2414
2492
  try {
2415
- if (!new RegExp(schema.pattern).test(value)) errors.push({ path: path8, code: "pattern", message: "Value does not match the required pattern." });
2493
+ if (!new RegExp(schema.pattern).test(value)) errors.push({ path: path9, code: "pattern", message: "Value does not match the required pattern." });
2416
2494
  } catch {
2417
- errors.push({ path: path8, code: "invalid_schema_pattern", message: "Action schema contains an invalid pattern." });
2495
+ errors.push({ path: path9, code: "invalid_schema_pattern", message: "Action schema contains an invalid pattern." });
2418
2496
  }
2419
2497
  }
2420
- if (schema.format === "uri" && !isUrl(value)) errors.push({ path: path8, code: "format_uri", message: "Expected an absolute URL." });
2421
- if (schema.format === "email" && !/^[^@\s]+@[^@\s]+\.[^@\s]+$/.test(value)) errors.push({ path: path8, code: "format_email", message: "Expected an email address." });
2422
- if (schema.format === "date-time" && !isDateTime(value)) errors.push({ path: path8, code: "format_date_time", message: "Expected an ISO-8601 date-time." });
2498
+ if (schema.format === "uri" && !isUrl(value)) errors.push({ path: path9, code: "format_uri", message: "Expected an absolute URL." });
2499
+ if (schema.format === "email" && !/^[^@\s]+@[^@\s]+\.[^@\s]+$/.test(value)) errors.push({ path: path9, code: "format_email", message: "Expected an email address." });
2500
+ if (schema.format === "date-time" && !isDateTime(value)) errors.push({ path: path9, code: "format_date_time", message: "Expected an ISO-8601 date-time." });
2423
2501
  }
2424
- function validateNumber(schema, value, path8, errors) {
2425
- if (typeof schema.minimum === "number" && value < schema.minimum) errors.push({ path: path8, code: "minimum", message: `Expected a value of at least ${schema.minimum}.` });
2426
- if (typeof schema.maximum === "number" && value > schema.maximum) errors.push({ path: path8, code: "maximum", message: `Expected a value of at most ${schema.maximum}.` });
2502
+ function validateNumber(schema, value, path9, errors) {
2503
+ if (typeof schema.minimum === "number" && value < schema.minimum) errors.push({ path: path9, code: "minimum", message: `Expected a value of at least ${schema.minimum}.` });
2504
+ if (typeof schema.maximum === "number" && value > schema.maximum) errors.push({ path: path9, code: "maximum", message: `Expected a value of at most ${schema.maximum}.` });
2427
2505
  const exclusiveMinimum = typeof schema.exclusiveMinimum === "number" ? schema.exclusiveMinimum : schema.exclusiveMinimum === true && typeof schema.minimum === "number" ? schema.minimum : null;
2428
2506
  const exclusiveMaximum = typeof schema.exclusiveMaximum === "number" ? schema.exclusiveMaximum : schema.exclusiveMaximum === true && typeof schema.maximum === "number" ? schema.maximum : null;
2429
2507
  if (exclusiveMinimum !== null && value <= exclusiveMinimum) {
2430
- errors.push({ path: path8, code: "exclusive_minimum", message: `Expected a value greater than ${exclusiveMinimum}.` });
2508
+ errors.push({ path: path9, code: "exclusive_minimum", message: `Expected a value greater than ${exclusiveMinimum}.` });
2431
2509
  }
2432
2510
  if (exclusiveMaximum !== null && value >= exclusiveMaximum) {
2433
- errors.push({ path: path8, code: "exclusive_maximum", message: `Expected a value less than ${exclusiveMaximum}.` });
2511
+ errors.push({ path: path9, code: "exclusive_maximum", message: `Expected a value less than ${exclusiveMaximum}.` });
2434
2512
  }
2435
2513
  if (typeof schema.multipleOf === "number" && !isMultipleOf(value, schema.multipleOf)) {
2436
- errors.push({ path: path8, code: "multiple_of", message: `Expected a multiple of ${schema.multipleOf}.` });
2514
+ errors.push({ path: path9, code: "multiple_of", message: `Expected a multiple of ${schema.multipleOf}.` });
2437
2515
  }
2438
2516
  }
2439
2517
  function candidateMatches(candidate, value, root, depth) {
@@ -2565,8 +2643,8 @@ function prepareTopoloUrlSessionUploadInput(contractValue, byteLength, input3, o
2565
2643
  }
2566
2644
  };
2567
2645
  }
2568
- function topoloUploadResponseValue(response, path8) {
2569
- return path8.split(".").reduce((value, segment) => isRecord2(value) ? value[segment] : void 0, response);
2646
+ function topoloUploadResponseValue(response, path9) {
2647
+ return path9.split(".").reduce((value, segment) => isRecord2(value) ? value[segment] : void 0, response);
2570
2648
  }
2571
2649
  function decodeTopoloActionBase64(contentBase64) {
2572
2650
  if (!isCanonicalBase64(contentBase64)) {
@@ -2613,11 +2691,11 @@ function parseCompleteContract(value) {
2613
2691
  };
2614
2692
  }
2615
2693
  function requiredPath(value, name) {
2616
- const path8 = typeof value === "string" ? value.trim() : "";
2617
- if (!/^[A-Za-z_][A-Za-z0-9_]*(?:\.[A-Za-z_][A-Za-z0-9_]*)*$/.test(path8)) {
2694
+ const path9 = typeof value === "string" ? value.trim() : "";
2695
+ if (!/^[A-Za-z_][A-Za-z0-9_]*(?:\.[A-Za-z_][A-Za-z0-9_]*)*$/.test(path9)) {
2618
2696
  throw new TopoloSdkError("invalid_upload_contract", `The action upload contract has an invalid ${name}.`);
2619
2697
  }
2620
- return path8;
2698
+ return path9;
2621
2699
  }
2622
2700
  function unsupportedInlineProfile() {
2623
2701
  return new TopoloSdkError("invalid_upload_contract", "This action does not publish an inline-base64 upload contract.");
@@ -3572,8 +3650,8 @@ function normalizeActionCatalogEntry(item) {
3572
3650
  const name = pickActionString(a.name);
3573
3651
  const appId = pickActionString(a.app_id) ?? pickActionString(a.appId);
3574
3652
  const method = pickActionString(a.method)?.toUpperCase();
3575
- const path8 = pickActionString(a.path);
3576
- if (!actionId || !name || !appId || !method || !path8 || !isHttpMethod(method)) {
3653
+ const path9 = pickActionString(a.path);
3654
+ if (!actionId || !name || !appId || !method || !path9 || !isHttpMethod(method)) {
3577
3655
  return null;
3578
3656
  }
3579
3657
  return {
@@ -3588,7 +3666,7 @@ function normalizeActionCatalogEntry(item) {
3588
3666
  appSlug: pickActionString(a.app_slug) ?? pickActionString(a.appSlug) ?? null,
3589
3667
  appName: pickActionString(a.app_name) ?? pickActionString(a.appName) ?? null,
3590
3668
  method,
3591
- path: path8,
3669
+ path: path9,
3592
3670
  permissionName: pickActionString(a.permission_name) ?? pickActionString(a.permissionName) ?? "",
3593
3671
  requiredPermission: pickActionString(a.required_permission) ?? pickActionString(a.requiredPermission) ?? "",
3594
3672
  authorizationMode: pickAuthorizationMode(a.authorization_mode ?? a.authorizationMode),
@@ -3624,7 +3702,7 @@ function stringArray(value) {
3624
3702
  }
3625
3703
  function mapActionInput(action, input3) {
3626
3704
  const remaining = { ...input3 || {} };
3627
- const path8 = action.path.replace(/\{([a-zA-Z0-9_]+)\}/g, (_match, key) => {
3705
+ const path9 = action.path.replace(/\{([a-zA-Z0-9_]+)\}/g, (_match, key) => {
3628
3706
  const value = remaining[key];
3629
3707
  if (value === void 0 || value === null || value === "") {
3630
3708
  throw new TopoloSdkError(
@@ -3641,14 +3719,14 @@ function mapActionInput(action, input3) {
3641
3719
  delete remaining.body;
3642
3720
  if (action.method === "GET") {
3643
3721
  return {
3644
- path: path8,
3722
+ path: path9,
3645
3723
  query: objectToQuery({ ...remaining, ...explicitQuery })
3646
3724
  };
3647
3725
  }
3648
3726
  const query = objectToQuery(explicitQuery);
3649
3727
  const body = explicitBody !== void 0 ? explicitBody : remaining;
3650
3728
  return {
3651
- path: path8,
3729
+ path: path9,
3652
3730
  ...query ? { query } : {},
3653
3731
  body
3654
3732
  };
@@ -3818,8 +3896,8 @@ var TopoloOAuth = class {
3818
3896
  if (params.clientSecret) body.set("client_secret", params.clientSecret);
3819
3897
  return this.#postForm("/api/developer-oauth/token", body);
3820
3898
  }
3821
- async #postForm(path8, body) {
3822
- const url = new URL(path8, this.baseUrl.endsWith("/") ? this.baseUrl : `${this.baseUrl}/`);
3899
+ async #postForm(path9, body) {
3900
+ const url = new URL(path9, this.baseUrl.endsWith("/") ? this.baseUrl : `${this.baseUrl}/`);
3823
3901
  const res = await this.fetchImpl(url.toString(), {
3824
3902
  method: "POST",
3825
3903
  headers: {
@@ -3835,7 +3913,7 @@ var TopoloOAuth = class {
3835
3913
  const err = parsed;
3836
3914
  throw new TopoloAuthError(err.error_description || err.error, err.error);
3837
3915
  }
3838
- throw new TopoloHttpError("auth", path8, res.status, parsed);
3916
+ throw new TopoloHttpError("auth", path9, res.status, parsed);
3839
3917
  }
3840
3918
  return parsed;
3841
3919
  }
@@ -3898,13 +3976,13 @@ var TopoloHttpError2 = class extends TopoloSdkError2 {
3898
3976
  path;
3899
3977
  requestId;
3900
3978
  retryAfter;
3901
- constructor(service, path8, status, body, message, options = {}) {
3902
- super(extractHttpErrorCode2(body), message ?? `HTTP ${status} from ${service}${path8}`);
3979
+ constructor(service, path9, status, body, message, options = {}) {
3980
+ super(extractHttpErrorCode2(body), message ?? `HTTP ${status} from ${service}${path9}`);
3903
3981
  this.name = "TopoloHttpError";
3904
3982
  this.status = status;
3905
3983
  this.body = body;
3906
3984
  this.service = service;
3907
- this.path = path8;
3985
+ this.path = path9;
3908
3986
  this.requestId = options.requestId;
3909
3987
  this.retryAfter = options.retryAfter;
3910
3988
  }
@@ -3913,6 +3991,7 @@ var APP_API_URLS2 = {
3913
3991
  agent: "https://agent.topolo.app",
3914
3992
  auth: "https://auth.topolo.app",
3915
3993
  backup: "https://backup.topolo.app",
3994
+ blog: "https://blog.topolo.app",
3916
3995
  books: "https://books.topolo.app",
3917
3996
  brand: "https://brand.topolo.app",
3918
3997
  bugfix: "https://bugfix.topolo.app",
@@ -3925,6 +4004,7 @@ var APP_API_URLS2 = {
3925
4004
  compose: "https://compose.topolo.app",
3926
4005
  consent: "https://consent.topolo.app",
3927
4006
  crm: "https://crm.topolo.app",
4007
+ design: "https://design.topolo.app",
3928
4008
  developers: "https://developers.topolo.app",
3929
4009
  director: "https://director.topolo.app",
3930
4010
  feed: "https://feed.topolo.app",
@@ -4037,8 +4117,8 @@ var TopoloOAuth2 = class {
4037
4117
  if (params.clientSecret) body.set("client_secret", params.clientSecret);
4038
4118
  return this.#postForm("/api/developer-oauth/token", body);
4039
4119
  }
4040
- async #postForm(path8, body) {
4041
- const url = new URL(path8, this.baseUrl.endsWith("/") ? this.baseUrl : `${this.baseUrl}/`);
4120
+ async #postForm(path9, body) {
4121
+ const url = new URL(path9, this.baseUrl.endsWith("/") ? this.baseUrl : `${this.baseUrl}/`);
4042
4122
  const res = await this.fetchImpl(url.toString(), {
4043
4123
  method: "POST",
4044
4124
  headers: {
@@ -4054,7 +4134,7 @@ var TopoloOAuth2 = class {
4054
4134
  const err = parsed;
4055
4135
  throw new TopoloAuthError2(err.error_description || err.error, err.error);
4056
4136
  }
4057
- throw new TopoloHttpError2("auth", path8, res.status, parsed);
4137
+ throw new TopoloHttpError2("auth", path9, res.status, parsed);
4058
4138
  }
4059
4139
  return parsed;
4060
4140
  }
@@ -4084,22 +4164,22 @@ function configPath() {
4084
4164
  return join(base, "topolo", "config.json");
4085
4165
  }
4086
4166
  async function readConfig() {
4087
- const path8 = configPath();
4088
- if (!existsSync(path8)) return {};
4167
+ const path9 = configPath();
4168
+ if (!existsSync(path9)) return {};
4089
4169
  try {
4090
- const raw = await readFile(path8, "utf8");
4170
+ const raw = await readFile(path9, "utf8");
4091
4171
  return JSON.parse(raw);
4092
4172
  } catch {
4093
4173
  return {};
4094
4174
  }
4095
4175
  }
4096
4176
  async function writeConfig(config) {
4097
- const path8 = configPath();
4098
- await mkdir(dirname(path8), { recursive: true });
4099
- await writeFile(path8, JSON.stringify(config, null, 2) + "\n", "utf8");
4177
+ const path9 = configPath();
4178
+ await mkdir(dirname(path9), { recursive: true });
4179
+ await writeFile(path9, JSON.stringify(config, null, 2) + "\n", "utf8");
4100
4180
  if (platform() !== "win32") {
4101
4181
  try {
4102
- await chmod(path8, 384);
4182
+ await chmod(path9, 384);
4103
4183
  } catch {
4104
4184
  }
4105
4185
  }
@@ -4429,9 +4509,9 @@ function readCliVersion() {
4429
4509
  join2(here, "package.json"),
4430
4510
  join2(here, "..", "package.json")
4431
4511
  ];
4432
- for (const path8 of candidates) {
4512
+ for (const path9 of candidates) {
4433
4513
  try {
4434
- const pkg = JSON.parse(readFileSync(path8, "utf8"));
4514
+ const pkg = JSON.parse(readFileSync(path9, "utf8"));
4435
4515
  if (typeof pkg.version === "string" && pkg.version) return pkg.version;
4436
4516
  } catch {
4437
4517
  }
@@ -4791,7 +4871,7 @@ function registerApiCommand(program2) {
4791
4871
  "-q, --query <kv...>",
4792
4872
  "Query params as key=value (repeatable), e.g. --query source=cli page=2"
4793
4873
  ).option("--resource-type <type>", "Cataloged app-local workspace resource alias for resource-scoped API keys").option("--resource-id <id>", "Workspace resource id for resource-scoped API keys").option("--confirm", "Acknowledge a mutating request").option("--json", "Output JSON", true).option("--no-json", "Output human-readable text").action(
4794
- async (service, method, path8, opts) => {
4874
+ async (service, method, path9, opts) => {
4795
4875
  const mode = resolveOutputMode(opts.json);
4796
4876
  try {
4797
4877
  const upperMethod = method.toUpperCase();
@@ -4830,7 +4910,7 @@ function registerApiCommand(program2) {
4830
4910
  const result = await topolo.client.request({
4831
4911
  service,
4832
4912
  method: httpMethod,
4833
- path: path8,
4913
+ path: path9,
4834
4914
  body,
4835
4915
  ...query ? { query } : {},
4836
4916
  ...resource ? { resource } : {},
@@ -5018,13 +5098,13 @@ async function requiredClient() {
5018
5098
  function parseJsonObject(value) {
5019
5099
  let source = value;
5020
5100
  if (value.startsWith("@")) {
5021
- const path8 = value.slice(1);
5022
- if (!path8) throw new Error("--data @file path must not be empty");
5101
+ const path9 = value.slice(1);
5102
+ if (!path9) throw new Error("--data @file path must not be empty");
5023
5103
  try {
5024
- source = readFileSync2(path8, "utf8");
5104
+ source = readFileSync2(path9, "utf8");
5025
5105
  } catch (err) {
5026
5106
  const detail = err instanceof Error ? err.message : String(err);
5027
- throw new Error(`Could not read --data file ${path8}: ${detail}`);
5107
+ throw new Error(`Could not read --data file ${path9}: ${detail}`);
5028
5108
  }
5029
5109
  }
5030
5110
  let parsed;
@@ -5038,7 +5118,7 @@ function parseJsonObject(value) {
5038
5118
  }
5039
5119
  return parsed;
5040
5120
  }
5041
- function inferContentType(path8) {
5121
+ function inferContentType(path9) {
5042
5122
  return {
5043
5123
  ".avif": "image/avif",
5044
5124
  ".gif": "image/gif",
@@ -5051,7 +5131,7 @@ function inferContentType(path8) {
5051
5131
  ".png": "image/png",
5052
5132
  ".svg": "image/svg+xml",
5053
5133
  ".webp": "image/webp"
5054
- }[extname(path8).toLowerCase()] ?? null;
5134
+ }[extname(path9).toLowerCase()] ?? null;
5055
5135
  }
5056
5136
  function formatActionRows(rows, nextCursor = null) {
5057
5137
  if (rows.length === 0) return "No actions available for this credential.";
@@ -5113,8 +5193,8 @@ function formatActionPlan(plan) {
5113
5193
 
5114
5194
  // src/commands/apps.ts
5115
5195
  import { execSync } from "child_process";
5116
- import { existsSync as existsSync4, mkdirSync as mkdirSync2, readFileSync as readFileSync5, writeFileSync as writeFileSync2 } from "fs";
5117
- import path5 from "path";
5196
+ import { existsSync as existsSync4, mkdirSync as mkdirSync2, readFileSync as readFileSync6, writeFileSync as writeFileSync2 } from "fs";
5197
+ import path6 from "path";
5118
5198
 
5119
5199
  // src/commands/app-audit-local.ts
5120
5200
  import {
@@ -6251,14 +6331,14 @@ import { constants } from "fs";
6251
6331
  import { access } from "fs/promises";
6252
6332
  import { relative, resolve } from "path";
6253
6333
  function normalizeHomePath(value) {
6254
- const path8 = String(value || "/dashboard").trim();
6255
- if (!path8.startsWith("/") || path8.startsWith("//") || /[?#]/.test(path8)) {
6334
+ const path9 = String(value || "/dashboard").trim();
6335
+ if (!path9.startsWith("/") || path9.startsWith("//") || /[?#]/.test(path9)) {
6256
6336
  throw new Error("Invalid home path. Use an absolute application path such as /dashboard.");
6257
6337
  }
6258
- if (["/", "/login", "/auth/callback", "/getting-started"].includes(path8)) {
6338
+ if (["/", "/login", "/auth/callback", "/getting-started"].includes(path9)) {
6259
6339
  throw new Error("Home path must be a protected product route, not a reserved entry route.");
6260
6340
  }
6261
- return path8.replace(/\/$/, "") || "/dashboard";
6341
+ return path9.replace(/\/$/, "") || "/dashboard";
6262
6342
  }
6263
6343
  function normalizeHomeLabel(value) {
6264
6344
  const label = String(value || "Dashboard").trim();
@@ -6389,9 +6469,9 @@ function toTitle(value) {
6389
6469
  function json(value) {
6390
6470
  return JSON.stringify(value, null, 2);
6391
6471
  }
6392
- async function pathExists(path8) {
6472
+ async function pathExists(path9) {
6393
6473
  try {
6394
- await access(path8, constants.F_OK);
6474
+ await access(path9, constants.F_OK);
6395
6475
  return true;
6396
6476
  } catch {
6397
6477
  return false;
@@ -6421,6 +6501,54 @@ function firstPartyAppPath(appDir, _audience) {
6421
6501
  return `apps/${appDir}`;
6422
6502
  }
6423
6503
 
6504
+ // src/commands/app-scaffold-platform-versions.ts
6505
+ import { readdirSync as readdirSync2, readFileSync as readFileSync4 } from "fs";
6506
+ import path2 from "path";
6507
+ var versionCache = /* @__PURE__ */ new Map();
6508
+ function platformPackagePin(packageName, options = {}) {
6509
+ const workspaceRoot = resolveTopoloRepoRoot(
6510
+ options.repoRoot ?? process.env.TOPOLO_WORKSPACE_ROOT ?? void 0,
6511
+ options.cwd ?? process.cwd()
6512
+ );
6513
+ if (!workspaceRoot) {
6514
+ throw new Error(
6515
+ `Cannot resolve a concrete version for ${packageName}: platform-target scaffolds must run inside the Topolo workspace checkout (a directory containing apps/ and system-apps/), or receive --repo-root. The fleet pinning policy requires exact ^<latest> pins, never "latest".`
6516
+ );
6517
+ }
6518
+ const version = platformPackageVersions(workspaceRoot).get(packageName);
6519
+ if (!version) {
6520
+ throw new Error(
6521
+ `Unknown Topolo platform package: ${packageName} \u2014 no published package with that name under ${path2.join(workspaceRoot, "topolo-platform", "packages")}.`
6522
+ );
6523
+ }
6524
+ return `^${version}`;
6525
+ }
6526
+ function platformPackageVersions(workspaceRoot) {
6527
+ const packagesRoot = path2.join(workspaceRoot, "topolo-platform", "packages");
6528
+ const cached = versionCache.get(packagesRoot);
6529
+ if (cached) return cached;
6530
+ const versions = /* @__PURE__ */ new Map();
6531
+ let entries = [];
6532
+ try {
6533
+ entries = readdirSync2(packagesRoot);
6534
+ } catch {
6535
+ }
6536
+ for (const entry of entries) {
6537
+ let packageJson2;
6538
+ try {
6539
+ packageJson2 = JSON.parse(readFileSync4(path2.join(packagesRoot, entry, "package.json"), "utf8"));
6540
+ } catch {
6541
+ continue;
6542
+ }
6543
+ const version = packageJson2.topoloPublishedVersion || packageJson2.version;
6544
+ if (packageJson2.name && /^@topolo(-io)?\//.test(packageJson2.name) && !packageJson2.private && version) {
6545
+ versions.set(packageJson2.name, version);
6546
+ }
6547
+ }
6548
+ versionCache.set(packagesRoot, versions);
6549
+ return versions;
6550
+ }
6551
+
6424
6552
  // src/commands/app-scaffold-cloudflare-constants.ts
6425
6553
  var CLOUDFLARE_ACCOUNT_ID = "49ef1ba682ad8cfd720c86699ae17521";
6426
6554
  var STAGING_CLOUDFLARE_ACCOUNT_ID = "4f4e1c69a3830946f9fea7b1eb7531ac";
@@ -6453,7 +6581,7 @@ function packageJson(application, target, options) {
6453
6581
  devDependencies.tailwindcss = "3.4.19";
6454
6582
  dependencies["react-router-dom"] = "^7.6.2";
6455
6583
  } else {
6456
- dependencies["@topolo/login"] = topoloPackageVersion("@topolo/login", target);
6584
+ dependencies["@topolo/login"] = topoloPackageVersion("@topolo/login", target, options.repoRoot);
6457
6585
  }
6458
6586
  }
6459
6587
  if (options.api) {
@@ -6465,13 +6593,13 @@ function packageJson(application, target, options) {
6465
6593
  scripts["deploy:staging"] = `DEPLOY_ENVIRONMENT=staging CLOUDFLARE_ACCOUNT_ID=${STAGING_CLOUDFLARE_ACCOUNT_ID} python3 .github/scripts/standard_deploy.py local-deploy`;
6466
6594
  scripts["deploy:production"] = `DEPLOY_ENVIRONMENT=production CLOUDFLARE_ACCOUNT_ID=${CLOUDFLARE_ACCOUNT_ID} python3 .github/scripts/standard_deploy.py local-deploy`;
6467
6595
  } else {
6468
- dependencies["@topolo/sdk"] = topoloPackageVersion("@topolo/sdk", target);
6596
+ dependencies["@topolo/sdk"] = topoloPackageVersion("@topolo/sdk", target, options.repoRoot);
6469
6597
  scripts.deploy = "npm run build && wrangler deploy";
6470
6598
  }
6471
6599
  devDependencies.wrangler = "^4.91.0";
6472
6600
  }
6473
6601
  for (const packageName of options.packages) {
6474
- dependencies[packageName] = topoloPackageVersion(packageName, target);
6602
+ dependencies[packageName] = topoloPackageVersion(packageName, target, options.repoRoot);
6475
6603
  }
6476
6604
  if (target === "platform") {
6477
6605
  const testDirs = [];
@@ -6513,14 +6641,16 @@ function packageJson(application, target, options) {
6513
6641
  })}
6514
6642
  `;
6515
6643
  }
6516
- function topoloPackageVersion(packageName, target) {
6644
+ function topoloPackageVersion(packageName, target, repoRoot) {
6517
6645
  if (target === "developer") {
6518
6646
  if (packageName === "@topolo/login") return "^0.1.0";
6519
6647
  if (packageName === "@topolo-io/auth-client") return "^1.0.0";
6520
6648
  if (packageName === "@topolo/sdk") return "^0.8.1";
6521
6649
  return "^0.1.0";
6522
6650
  }
6523
- if (packageName.startsWith("@topolo/") || packageName.startsWith("@topolo-io/")) return "latest";
6651
+ if (packageName.startsWith("@topolo/") || packageName.startsWith("@topolo-io/")) {
6652
+ return platformPackagePin(packageName, { repoRoot });
6653
+ }
6524
6654
  throw new Error(`Unknown Topolo platform package: ${packageName}`);
6525
6655
  }
6526
6656
  function hasScaffoldResources(resources) {
@@ -8489,10 +8619,10 @@ function developerWorkerTs(application) {
8489
8619
  }
8490
8620
 
8491
8621
  // src/commands/app-scaffold-generate.ts
8492
- import { existsSync as existsSync3, mkdirSync, mkdtempSync, readFileSync as readFileSync4, rmSync, writeFileSync } from "fs";
8622
+ import { existsSync as existsSync3, mkdirSync, mkdtempSync, readFileSync as readFileSync5, rmSync, writeFileSync } from "fs";
8493
8623
  import { spawnSync } from "child_process";
8494
8624
  import { tmpdir } from "os";
8495
- import path2 from "path";
8625
+ import path3 from "path";
8496
8626
  function resolveGeneratorPath() {
8497
8627
  const candidates = [
8498
8628
  // Published CLI: vendored alongside dist/index.js at build time.
@@ -8519,18 +8649,18 @@ var GENERATED = {
8519
8649
  };
8520
8650
  function deriveGeneratedConfigs(files, base) {
8521
8651
  const generator = resolveGeneratorPath();
8522
- const root = mkdtempSync(path2.join(tmpdir(), "topolo-scaffold-generate-"));
8652
+ const root = mkdtempSync(path3.join(tmpdir(), "topolo-scaffold-generate-"));
8523
8653
  try {
8524
8654
  const prefix = `${base}/`;
8525
8655
  for (const file of files) {
8526
8656
  if (!file.path.startsWith(prefix)) continue;
8527
- const abs = path2.join(root, file.path.slice(prefix.length));
8528
- mkdirSync(path2.dirname(abs), { recursive: true });
8657
+ const abs = path3.join(root, file.path.slice(prefix.length));
8658
+ mkdirSync(path3.dirname(abs), { recursive: true });
8529
8659
  writeFileSync(abs, file.content, "utf8");
8530
8660
  }
8531
8661
  const result = spawnSync(
8532
8662
  process.execPath,
8533
- [generator, `--manifest=${path2.join(root, "topolo.app.json")}`],
8663
+ [generator, `--manifest=${path3.join(root, "topolo.app.json")}`],
8534
8664
  { cwd: root, encoding: "utf8" }
8535
8665
  );
8536
8666
  if (result.status !== 0) {
@@ -8547,7 +8677,7 @@ ${result.stdout ?? ""}`);
8547
8677
  return written.map((rel) => ({
8548
8678
  path: `${base}/${rel}`,
8549
8679
  ...GENERATED,
8550
- content: readFileSync4(path2.join(root, rel), "utf8")
8680
+ content: readFileSync5(path3.join(root, rel), "utf8")
8551
8681
  }));
8552
8682
  } finally {
8553
8683
  rmSync(root, { recursive: true, force: true });
@@ -9781,7 +9911,8 @@ function applicationScaffoldPayload(application, options = {}) {
9781
9911
  target,
9782
9912
  browser,
9783
9913
  api,
9784
- ciWorkflow
9914
+ ciWorkflow,
9915
+ repoRoot: options.repoRoot
9785
9916
  }),
9786
9917
  commands: scaffoldCommands({
9787
9918
  id,
@@ -9869,7 +10000,8 @@ function scaffoldFiles(options) {
9869
10000
  browser: options.browser,
9870
10001
  api: options.api,
9871
10002
  resources: options.payload.resources,
9872
- packages: options.payload.capabilityComposition.packages
10003
+ packages: options.payload.capabilityComposition.packages,
10004
+ repoRoot: options.repoRoot
9873
10005
  })
9874
10006
  },
9875
10007
  {
@@ -10680,18 +10812,18 @@ import { join as join3 } from "path";
10680
10812
 
10681
10813
  // src/commands/app-reconcile.ts
10682
10814
  import { readFile as readFile4, writeFile as writeFile5 } from "fs/promises";
10683
- import path4 from "path";
10815
+ import path5 from "path";
10684
10816
  import { createInterface as createInterface2 } from "readline/promises";
10685
10817
  import { stdin as input2, stdout as output } from "process";
10686
10818
 
10687
10819
  // src/commands/app-capability-composition.ts
10688
10820
  import { mkdir as mkdir3, readFile as readFile3, writeFile as writeFile4 } from "fs/promises";
10689
- import path3 from "path";
10821
+ import path4 from "path";
10690
10822
  async function reconcileApplicationCapabilitySource(options) {
10691
- const manifestPath = path3.resolve(options.manifestPath || "topolo.app.json");
10692
- const root = path3.dirname(manifestPath);
10693
- const packagePath = path3.join(root, "package.json");
10694
- const contractPath = path3.join(root, "topolo.capability-contract.json");
10823
+ const manifestPath = path4.resolve(options.manifestPath || "topolo.app.json");
10824
+ const root = path4.dirname(manifestPath);
10825
+ const packagePath = path4.join(root, "package.json");
10826
+ const contractPath = path4.join(root, "topolo.capability-contract.json");
10695
10827
  const manifest = parseRecord(await readFile3(manifestPath, "utf8"), manifestPath);
10696
10828
  const registration = record(manifest.registration);
10697
10829
  if (!registration) throw new Error("topolo.app.json must declare registration before capability composition.");
@@ -10736,7 +10868,7 @@ async function reconcileApplicationCapabilitySource(options) {
10736
10868
  const nextDependencies = { ...dependencies };
10737
10869
  for (const packageName of capabilities.packages) {
10738
10870
  if (typeof nextDependencies[packageName] !== "string") {
10739
- nextDependencies[packageName] = packageVersion(packageName, target);
10871
+ nextDependencies[packageName] = packageVersion(packageName, target, { repoRoot: options.repoRoot, cwd: root });
10740
10872
  }
10741
10873
  }
10742
10874
  const sortedDependencies = sortRecord(nextDependencies);
@@ -10746,9 +10878,9 @@ async function reconcileApplicationCapabilitySource(options) {
10746
10878
  compareChange(changes, "topolo.capability-contract.json", existingContract, expectedContract);
10747
10879
  const adapter = target === "platform" ? managedCapabilityAdapter(capabilities.selected) : null;
10748
10880
  const apiDirectory = resolveApiDirectory(root, manifest, target);
10749
- const adapterPath = path3.join(apiDirectory, "src", "topolo-capabilities.ts");
10881
+ const adapterPath = path4.join(apiDirectory, "src", "topolo-capabilities.ts");
10750
10882
  if (adapter) compareChange(changes, relativePath(root, adapterPath), await readOptionalText(adapterPath), adapter);
10751
- const pricingPath = path3.join(root, "pricing-manifest.json");
10883
+ const pricingPath = path4.join(root, "pricing-manifest.json");
10752
10884
  const pricingManifest = capabilities.selected.includes("billing") ? defaultPricingManifest({
10753
10885
  appId: String(manifest.appId || manifest.app_id || "").trim(),
10754
10886
  displayName: String(registration.displayName || manifest.name || "Application"),
@@ -10760,7 +10892,7 @@ async function reconcileApplicationCapabilitySource(options) {
10760
10892
  const missingResources = capabilities.resources.filter((resource) => !manifestProvidesResource(manifest, resource));
10761
10893
  const verticalConfiguration = [];
10762
10894
  for (const [capability2, fileName, description] of VERTICAL_CAPABILITY_FILES) {
10763
- if (capabilities.selected.includes(capability2) && !await fileExists(path3.join(root, fileName))) {
10895
+ if (capabilities.selected.includes(capability2) && !await fileExists(path4.join(root, fileName))) {
10764
10896
  verticalConfiguration.push(`${fileName}: ${description}`);
10765
10897
  }
10766
10898
  }
@@ -10775,7 +10907,7 @@ async function reconcileApplicationCapabilitySource(options) {
10775
10907
  await writeJson(contractPath, expectedContract);
10776
10908
  if (pricingManifest) await writeJson(pricingPath, pricingManifest);
10777
10909
  if (adapter) {
10778
- await mkdir3(path3.dirname(adapterPath), { recursive: true });
10910
+ await mkdir3(path4.dirname(adapterPath), { recursive: true });
10779
10911
  await writeFile4(adapterPath, adapter, "utf8");
10780
10912
  }
10781
10913
  }
@@ -10878,11 +11010,8 @@ function manifestProvidesResource(manifest, resource) {
10878
11010
  }
10879
11011
  return false;
10880
11012
  }
10881
- function packageVersion(packageName, target) {
10882
- if (target === "platform") {
10883
- if (packageName === "@topolo-io/notifications") return "^0.6.8";
10884
- return "latest";
10885
- }
11013
+ function packageVersion(packageName, target, resolution) {
11014
+ if (target === "platform") return platformPackagePin(packageName, resolution);
10886
11015
  if (packageName === "@topolo/login") return "^0.1.0";
10887
11016
  if (packageName === "@topolo/sdk") return "^0.8.1";
10888
11017
  throw new Error(`Capability registry exposed private package ${packageName} to a third-party application.`);
@@ -10959,13 +11088,13 @@ function resolveApiDirectory(root, manifest, target) {
10959
11088
  for (const value of Object.values(record(manifest.targets) ?? {})) {
10960
11089
  const targetRecord = record(value);
10961
11090
  if (targetRecord?.kind === "worker" && !targetRecord.assets && typeof targetRecord.dir === "string") {
10962
- return path3.resolve(root, targetRecord.dir);
11091
+ return path4.resolve(root, targetRecord.dir);
10963
11092
  }
10964
11093
  }
10965
- return path3.join(root, "apps", "api");
11094
+ return path4.join(root, "apps", "api");
10966
11095
  }
10967
11096
  function relativePath(root, filePath) {
10968
- return path3.relative(root, filePath).split(path3.sep).join("/");
11097
+ return path4.relative(root, filePath).split(path4.sep).join("/");
10969
11098
  }
10970
11099
 
10971
11100
  // src/commands/app-reconcile.ts
@@ -11035,7 +11164,7 @@ function titleFromSlug(value) {
11035
11164
  return value.replace(/^topolo[-_]/, "").split(/[-_]+/).filter(Boolean).map((part) => part.charAt(0).toUpperCase() + part.slice(1)).join(" ");
11036
11165
  }
11037
11166
  async function completeApplicationRegistrationInteractively(options) {
11038
- const manifestPath = path4.resolve(options.manifestPath || "topolo.app.json");
11167
+ const manifestPath = path5.resolve(options.manifestPath || "topolo.app.json");
11039
11168
  const manifest = JSON.parse(await readFile4(manifestPath, "utf8"));
11040
11169
  const existing = record2(manifest.registration) || {};
11041
11170
  const appId = String(manifest.appId || manifest.app_id || "").trim();
@@ -11115,7 +11244,7 @@ async function completeApplicationRegistrationInteractively(options) {
11115
11244
  }
11116
11245
  }
11117
11246
  async function loadApplicationReconcileRequest(options) {
11118
- const manifestPath = path4.resolve(options.manifestPath || "topolo.app.json");
11247
+ const manifestPath = path5.resolve(options.manifestPath || "topolo.app.json");
11119
11248
  const raw = await readFile4(manifestPath, "utf8");
11120
11249
  const manifest = JSON.parse(raw);
11121
11250
  assertRegistration(manifest.registration);
@@ -11519,7 +11648,7 @@ function applicationAuditPayload(application, options = {}) {
11519
11648
  }
11520
11649
  function recordApplicationEvidence(application, options = {}) {
11521
11650
  const appId = resolveApplication(application).id;
11522
- const root = path5.resolve(options.appRoot ?? process.cwd());
11651
+ const root = path6.resolve(options.appRoot ?? process.cwd());
11523
11652
  if (!existsSync4(root)) {
11524
11653
  throw new Error(`Application root does not exist: ${root}`);
11525
11654
  }
@@ -11531,12 +11660,12 @@ function recordApplicationEvidence(application, options = {}) {
11531
11660
  commit = void 0;
11532
11661
  }
11533
11662
  }
11534
- const evidenceDir = path5.join(root, ".topolo");
11535
- const evidencePath = path5.join(evidenceDir, "evidence.json");
11663
+ const evidenceDir = path6.join(root, ".topolo");
11664
+ const evidencePath = path6.join(evidenceDir, "evidence.json");
11536
11665
  let before = null;
11537
11666
  if (existsSync4(evidencePath)) {
11538
11667
  try {
11539
- const raw = JSON.parse(readFileSync5(evidencePath, "utf8"));
11668
+ const raw = JSON.parse(readFileSync6(evidencePath, "utf8"));
11540
11669
  if (raw && typeof raw === "object" && raw.version === 1) {
11541
11670
  before = raw;
11542
11671
  }
@@ -11831,14 +11960,14 @@ function statusesAtOrWorse(threshold) {
11831
11960
  }
11832
11961
 
11833
11962
  // src/commands/platform.ts
11834
- import { readdirSync as readdirSync2, readFileSync as readFileSync6, statSync as statSync2 } from "fs";
11835
- import path7 from "path";
11963
+ import { readdirSync as readdirSync3, readFileSync as readFileSync7, statSync as statSync2 } from "fs";
11964
+ import path8 from "path";
11836
11965
 
11837
11966
  // src/commands/app-capability-provision.ts
11838
11967
  import { readFile as readFile5, writeFile as writeFile6 } from "fs/promises";
11839
- import path6 from "path";
11968
+ import path7 from "path";
11840
11969
  async function provisionApplicationResources(options) {
11841
- const manifestPath = path6.resolve(options.manifestPath || "topolo.app.json");
11970
+ const manifestPath = path7.resolve(options.manifestPath || "topolo.app.json");
11842
11971
  const manifest = parseRecord2(await readFile5(manifestPath, "utf8"), manifestPath);
11843
11972
  const environments = requiredRecord(manifest.environments, "topolo.app.json#environments");
11844
11973
  const environment = requiredRecord(environments[options.environment], `topolo.app.json#environments.${options.environment}`);
@@ -12043,7 +12172,8 @@ function registerPlatformCommand(program2) {
12043
12172
  navigationMode: opts.navigationMode,
12044
12173
  workspaceSwitcher: opts.workspaceSwitcher,
12045
12174
  uiTemplate: opts.uiTemplate,
12046
- tagline: opts.tagline
12175
+ tagline: opts.tagline,
12176
+ repoRoot: opts.repoRoot
12047
12177
  });
12048
12178
  if (opts.workflowOnly && !payload.ciWorkflow) {
12049
12179
  throw new Error("--workflow-only is only available for first-party scaffolds.");
@@ -12110,12 +12240,12 @@ var SKIPPED_SCAN_DIRS = /* @__PURE__ */ new Set([
12110
12240
  "output"
12111
12241
  ]);
12112
12242
  function scanStagingProductionUrls(rootInput, allowPatterns) {
12113
- const root = path7.resolve(rootInput);
12243
+ const root = path8.resolve(rootInput);
12114
12244
  const allowlist = allowPatterns.map((pattern) => new RegExp(pattern));
12115
12245
  const violations = [];
12116
12246
  function shouldSkipFile(filePath) {
12117
- const basename2 = path7.basename(filePath);
12118
- const relativePath2 = path7.relative(root, filePath);
12247
+ const basename2 = path8.basename(filePath);
12248
+ const relativePath2 = path8.relative(root, filePath);
12119
12249
  if (basename2 === "package-lock.json" || basename2 === "pnpm-lock.yaml" || basename2 === "yarn.lock") return true;
12120
12250
  if (basename2 === "topolo.cloudcontrol.json") return true;
12121
12251
  if (basename2 === "wrangler.toml" || basename2 === "wrangler.jsonc") return true;
@@ -12124,15 +12254,15 @@ function scanStagingProductionUrls(rootInput, allowPatterns) {
12124
12254
  if (basename2.endsWith(".generated.ts")) return true;
12125
12255
  if (basename2.endsWith(".test.ts") || basename2.endsWith(".test.tsx") || basename2.endsWith(".spec.ts")) return true;
12126
12256
  if (basename2 === ".env.production") return true;
12127
- if (relativePath2 === path7.join("src", "environment.ts") || relativePath2 === path7.join("src", "environmentUrls.ts") || relativePath2.endsWith(path7.join("src", "environment.ts")) || relativePath2.endsWith(path7.join("src", "lib", "environment.ts")) || relativePath2 === path7.join("packages", "topolo-ui-kit", "src", "environmentUrls.ts")) return true;
12128
- if (relativePath2.includes(`${path7.sep}test${path7.sep}`) || relativePath2.includes(`${path7.sep}tests${path7.sep}`) || relativePath2.includes(`${path7.sep}e2e${path7.sep}`)) return true;
12129
- if (relativePath2.startsWith(`scripts${path7.sep}`) || relativePath2.includes(`${path7.sep}scripts${path7.sep}`)) return true;
12130
- return !RUNTIME_EXTENSIONS.has(path7.extname(filePath));
12257
+ if (relativePath2 === path8.join("src", "environment.ts") || relativePath2 === path8.join("src", "environmentUrls.ts") || relativePath2.endsWith(path8.join("src", "environment.ts")) || relativePath2.endsWith(path8.join("src", "lib", "environment.ts")) || relativePath2 === path8.join("packages", "topolo-ui-kit", "src", "environmentUrls.ts")) return true;
12258
+ if (relativePath2.includes(`${path8.sep}test${path8.sep}`) || relativePath2.includes(`${path8.sep}tests${path8.sep}`) || relativePath2.includes(`${path8.sep}e2e${path8.sep}`)) return true;
12259
+ if (relativePath2.startsWith(`scripts${path8.sep}`) || relativePath2.includes(`${path8.sep}scripts${path8.sep}`)) return true;
12260
+ return !RUNTIME_EXTENSIONS.has(path8.extname(filePath));
12131
12261
  }
12132
12262
  function scanFile(filePath) {
12133
12263
  if (shouldSkipFile(filePath)) return;
12134
- const relativePath2 = path7.relative(root, filePath);
12135
- const content = readFileSync6(filePath, "utf8");
12264
+ const relativePath2 = path8.relative(root, filePath);
12265
+ const content = readFileSync7(filePath, "utf8");
12136
12266
  const lines = content.split(/\r?\n/);
12137
12267
  lines.forEach((line, index) => {
12138
12268
  const matches = [...line.matchAll(PRODUCTION_TOPOLO_URL_PATTERN)].map((match) => match[0]);
@@ -12145,8 +12275,8 @@ function scanStagingProductionUrls(rootInput, allowPatterns) {
12145
12275
  });
12146
12276
  }
12147
12277
  function walk(dir) {
12148
- for (const entry of readdirSync2(dir, { withFileTypes: true })) {
12149
- const fullPath = path7.join(dir, entry.name);
12278
+ for (const entry of readdirSync3(dir, { withFileTypes: true })) {
12279
+ const fullPath = path8.join(dir, entry.name);
12150
12280
  if (entry.isDirectory()) {
12151
12281
  if (!SKIPPED_SCAN_DIRS.has(entry.name)) walk(fullPath);
12152
12282
  continue;
@@ -12314,7 +12444,7 @@ var DEFAULT_SEED_BASE_URL = "https://seed.stg.topolo.us";
12314
12444
  function seedBaseUrl() {
12315
12445
  return process.env.TOPOLO_SEED_URL || DEFAULT_SEED_BASE_URL;
12316
12446
  }
12317
- async function authedFetch(path8, init = {}) {
12447
+ async function authedFetch(path9, init = {}) {
12318
12448
  const credential = await refreshCredentialIfNeeded("staging");
12319
12449
  if (!credential) {
12320
12450
  throw new Error("No staging credential configured. Run `topolo auth login --env staging` or set TOPOLO_STAGING_API_KEY.");
@@ -12324,7 +12454,7 @@ async function authedFetch(path8, init = {}) {
12324
12454
  else headers.set("Authorization", `Bearer ${credential.accessToken}`);
12325
12455
  headers.set("X-Topolo-Client", `topolo-cli/${CLI_VERSION}`);
12326
12456
  if (init.body && !headers.has("Content-Type")) headers.set("Content-Type", "application/json");
12327
- const response = await fetch(`${seedBaseUrl()}${path8}`, { ...init, headers });
12457
+ const response = await fetch(`${seedBaseUrl()}${path9}`, { ...init, headers });
12328
12458
  const text = await response.text();
12329
12459
  let body;
12330
12460
  try {
@@ -12601,7 +12731,7 @@ function createOAuthClientPayload(options) {
12601
12731
  logo_url: options.logoUrl
12602
12732
  };
12603
12733
  }
12604
- async function authFetchJson(path8, init = {}) {
12734
+ async function authFetchJson(path9, init = {}) {
12605
12735
  const environment = selectedEnvironment();
12606
12736
  const credential = await refreshCredentialIfNeeded(environment);
12607
12737
  if (!credential) {
@@ -12623,7 +12753,7 @@ async function authFetchJson(path8, init = {}) {
12623
12753
  throw err;
12624
12754
  }
12625
12755
  headers.set("Authorization", `Bearer ${credential.accessToken}`);
12626
- const response = await fetch(`${authBaseUrl}${path8}`, { ...init, headers });
12756
+ const response = await fetch(`${authBaseUrl}${path9}`, { ...init, headers });
12627
12757
  const text = await response.text();
12628
12758
  const payload = text ? JSON.parse(text) : {};
12629
12759
  if (!response.ok || payload.success === false) {
@@ -12878,11 +13008,11 @@ function registerViaOfficialCli(cli, mcp, agentName) {
12878
13008
  return result.status === 0;
12879
13009
  }
12880
13010
  async function registerClaudeViaConfig(mcp) {
12881
- const path8 = join5(homedir2(), ".claude.json");
13011
+ const path9 = join5(homedir2(), ".claude.json");
12882
13012
  let config = {};
12883
- if (existsSync5(path8)) {
13013
+ if (existsSync5(path9)) {
12884
13014
  try {
12885
- config = JSON.parse(await readFile7(path8, "utf8"));
13015
+ config = JSON.parse(await readFile7(path9, "utf8"));
12886
13016
  } catch {
12887
13017
  config = {};
12888
13018
  }
@@ -12895,13 +13025,13 @@ async function registerClaudeViaConfig(mcp) {
12895
13025
  env: { TOPOLO_AGENT_NAME: AGENT_NAME_FOR.claude }
12896
13026
  };
12897
13027
  config.mcpServers = servers;
12898
- await writeFile7(path8, `${JSON.stringify(config, null, 2)}
13028
+ await writeFile7(path9, `${JSON.stringify(config, null, 2)}
12899
13029
  `, "utf8");
12900
13030
  }
12901
13031
  async function registerCodexViaConfig(mcp) {
12902
- const path8 = join5(homedir2(), ".codex", "config.toml");
13032
+ const path9 = join5(homedir2(), ".codex", "config.toml");
12903
13033
  let text = "";
12904
- if (existsSync5(path8)) text = await readFile7(path8, "utf8");
13034
+ if (existsSync5(path9)) text = await readFile7(path9, "utf8");
12905
13035
  text = text.replace(
12906
13036
  /(^|\n)\[mcp_servers\.topolo(?:\.[a-z]+)?\][^\[]*/g,
12907
13037
  (match) => match.startsWith("\n") ? "\n" : ""
@@ -12917,8 +13047,8 @@ command = "${mcp.command}"${argsToml}
12917
13047
  [mcp_servers.topolo.env]
12918
13048
  TOPOLO_AGENT_NAME = "${AGENT_NAME_FOR.codex}"
12919
13049
  `;
12920
- await mkdir4(dirname4(path8), { recursive: true });
12921
- await writeFile7(path8, `${text}${block}`, "utf8");
13050
+ await mkdir4(dirname4(path9), { recursive: true });
13051
+ await writeFile7(path9, `${text}${block}`, "utf8");
12922
13052
  }
12923
13053
  async function installForAgent(agent, sourceDir, mcp, opts) {
12924
13054
  const skillDir = agent === "claude" ? claudeSkillDir(opts.projectDir) : codexSkillDir();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@topolo/cli",
3
- "version": "0.6.5",
3
+ "version": "0.6.6",
4
4
  "topoloPublishedVersion": "0.6.5",
5
5
  "description": "Command-line interface for Topolo developers, operators, and agents, with internal first-party scaffolding available under the topolo platform namespace.",
6
6
  "type": "module",
@@ -11,20 +11,6 @@
11
11
  "dist",
12
12
  "skills"
13
13
  ],
14
- "scripts": {
15
- "build:sdk": "python3 ../../tooling/with-resource-lock.py ../topolo-sdk -- pnpm --dir ../topolo-sdk build",
16
- "prebuild": "pnpm run build:sdk",
17
- "build": "tsup && node scripts/vendor-generator.mjs",
18
- "dev": "tsup --watch",
19
- "pretypecheck": "pnpm run build:sdk",
20
- "typecheck": "tsc --noEmit",
21
- "start": "node dist/index.js",
22
- "pretest": "pnpm run build:sdk",
23
- "test": "vitest run",
24
- "test:watch": "vitest",
25
- "precoverage": "pnpm run build:sdk",
26
- "coverage": "vitest run --coverage"
27
- },
28
14
  "dependencies": {
29
15
  "commander": "^12.1.0"
30
16
  },
@@ -38,5 +24,19 @@
38
24
  },
39
25
  "engines": {
40
26
  "node": ">=20"
27
+ },
28
+ "scripts": {
29
+ "build:sdk": "python3 ../../tooling/with-resource-lock.py ../topolo-sdk -- pnpm --dir ../topolo-sdk build",
30
+ "prebuild": "pnpm run build:sdk",
31
+ "build": "tsup && node scripts/vendor-generator.mjs",
32
+ "dev": "tsup --watch",
33
+ "pretypecheck": "pnpm run build:sdk",
34
+ "typecheck": "tsc --noEmit",
35
+ "start": "node dist/index.js",
36
+ "pretest": "pnpm run build:sdk",
37
+ "test": "vitest run",
38
+ "test:watch": "vitest",
39
+ "precoverage": "pnpm run build:sdk",
40
+ "coverage": "vitest run --coverage"
41
41
  }
42
- }
42
+ }