@topolo/cli 0.1.18 → 0.1.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.
Files changed (2) hide show
  1. package/dist/index.js +126 -23
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -2699,7 +2699,28 @@ function sleep(ms) {
2699
2699
  }
2700
2700
 
2701
2701
  // src/version.ts
2702
- var CLI_VERSION = "0.1.17";
2702
+ import { readFileSync } from "fs";
2703
+ import { dirname as dirname2, join as join2 } from "path";
2704
+ import { fileURLToPath } from "url";
2705
+ function readCliVersion() {
2706
+ try {
2707
+ const here = dirname2(fileURLToPath(import.meta.url));
2708
+ const candidates = [
2709
+ join2(here, "package.json"),
2710
+ join2(here, "..", "package.json")
2711
+ ];
2712
+ for (const path4 of candidates) {
2713
+ try {
2714
+ const pkg = JSON.parse(readFileSync(path4, "utf8"));
2715
+ if (typeof pkg.version === "string" && pkg.version) return pkg.version;
2716
+ } catch {
2717
+ }
2718
+ }
2719
+ } catch {
2720
+ }
2721
+ return "0.0.0";
2722
+ }
2723
+ var CLI_VERSION = readCliVersion();
2703
2724
 
2704
2725
  // src/client.ts
2705
2726
  async function buildClient(options) {
@@ -2938,14 +2959,14 @@ function parseQueryPairs(pairs) {
2938
2959
 
2939
2960
  // src/commands/apps.ts
2940
2961
  import { execSync } from "child_process";
2941
- import { existsSync as existsSync3, mkdirSync, readFileSync as readFileSync2, writeFileSync } from "fs";
2962
+ import { existsSync as existsSync3, mkdirSync, readFileSync as readFileSync3, writeFileSync } from "fs";
2942
2963
  import path2 from "path";
2943
2964
 
2944
2965
  // src/commands/app-audit-local.ts
2945
2966
  import {
2946
2967
  existsSync as existsSync2,
2947
2968
  readdirSync,
2948
- readFileSync,
2969
+ readFileSync as readFileSync2,
2949
2970
  statSync
2950
2971
  } from "fs";
2951
2972
  import path from "path";
@@ -2954,7 +2975,7 @@ function readEvidenceFile(appRoot) {
2954
2975
  const candidate = path.join(appRoot, ".topolo", "evidence.json");
2955
2976
  if (!isFile(candidate)) return null;
2956
2977
  try {
2957
- const raw = JSON.parse(readFileSync(candidate, "utf8"));
2978
+ const raw = JSON.parse(readFileSync2(candidate, "utf8"));
2958
2979
  if (raw && typeof raw === "object" && raw.version === 1) {
2959
2980
  return raw;
2960
2981
  }
@@ -3737,7 +3758,7 @@ function readSourceIndex(root) {
3737
3758
  const files = collectSourceFiles(root, 4e3);
3738
3759
  const chunks = files.map((file) => {
3739
3760
  try {
3740
- return readFileSync(file, "utf8");
3761
+ return readFileSync2(file, "utf8");
3741
3762
  } catch {
3742
3763
  return "";
3743
3764
  }
@@ -3797,7 +3818,7 @@ function sortedDirEntries(dir) {
3797
3818
  function readJson(filePath) {
3798
3819
  if (!isFile(filePath)) return null;
3799
3820
  try {
3800
- return JSON.parse(readFileSync(filePath, "utf8"));
3821
+ return JSON.parse(readFileSync2(filePath, "utf8"));
3801
3822
  } catch {
3802
3823
  return null;
3803
3824
  }
@@ -3870,7 +3891,7 @@ function isFile(filePath) {
3870
3891
  // src/commands/app-scaffold.ts
3871
3892
  import { constants } from "fs";
3872
3893
  import { access, mkdir as mkdir2, writeFile as writeFile2 } from "fs/promises";
3873
- import { dirname as dirname2, relative, resolve } from "path";
3894
+ import { dirname as dirname3, relative, resolve } from "path";
3874
3895
  var CLOUDFLARE_ACCOUNT_ID = "49ef1ba682ad8cfd720c86699ae17521";
3875
3896
  var STAGING_CLOUDFLARE_ACCOUNT_ID = "4f4e1c69a3830946f9fea7b1eb7531ac";
3876
3897
  var CLOUDFLARE_COMPATIBILITY_DATE = "2026-05-05";
@@ -3977,7 +3998,7 @@ async function writeApplicationScaffold(payload, options = {}) {
3977
3998
  const files = [];
3978
3999
  for (const planned of plannedFiles) {
3979
4000
  const existed = await pathExists(planned.absolutePath);
3980
- await mkdir2(dirname2(planned.absolutePath), { recursive: true });
4001
+ await mkdir2(dirname3(planned.absolutePath), { recursive: true });
3981
4002
  await writeFile2(planned.absolutePath, planned.file.content, "utf8");
3982
4003
  files.push({
3983
4004
  path: planned.file.path,
@@ -4168,18 +4189,32 @@ function scaffoldFiles(options) {
4168
4189
  }
4169
4190
  );
4170
4191
  if (options.api && application.serviceId) {
4171
- files.push({
4172
- path: `PlatformApplications/TopoloAuth/catalog/service-manifests/${application.serviceId}.json`,
4173
- purpose: "Auth service manifest for first-party permissions, role bundles, and API-key scopes.",
4174
- requiredSignals: [
4175
- "serviceId matches the generated Worker service id",
4176
- "permissions, role bundles, and API-key scopes exist before the app is catalog-visible",
4177
- "systems metadata maps the service back to the generated TopoloDocs entries"
4178
- ],
4179
- content: serviceManifestJson(application, {
4180
- tenancy: options.payload.tenancy
4181
- })
4182
- });
4192
+ files.push(
4193
+ {
4194
+ path: `PlatformApplications/TopoloAuth/catalog/service-manifests/${application.serviceId}.json`,
4195
+ purpose: "Auth service manifest for first-party permissions, role bundles, and API-key scopes.",
4196
+ requiredSignals: [
4197
+ "serviceId matches the generated Worker service id",
4198
+ "permissions, role bundles, and API-key scopes exist before the app is catalog-visible",
4199
+ "systems metadata maps the service back to the generated TopoloDocs entries"
4200
+ ],
4201
+ content: serviceManifestJson(application, {
4202
+ tenancy: options.payload.tenancy
4203
+ })
4204
+ },
4205
+ {
4206
+ path: `PlatformApplications/TopoloAuth/scripts/add-topolo-${slug}-service-production.sql`,
4207
+ purpose: "Auth service catalog registration for embedded first-party login, launcher visibility, and callback origins.",
4208
+ requiredSignals: [
4209
+ "services.id matches the generated Worker service id",
4210
+ "settings.launcher.category is first_party so embedded password login is allowed",
4211
+ "base_url and auth_domain define the production callback origin"
4212
+ ],
4213
+ content: serviceRegistrationSql(application, {
4214
+ tenancy: options.payload.tenancy
4215
+ })
4216
+ }
4217
+ );
4183
4218
  }
4184
4219
  } else {
4185
4220
  files.push(
@@ -5574,6 +5609,7 @@ function internalDocs(application, options) {
5574
5609
  ...options.api ? [`- \`PlatformApplications/${application.appDir}/src/worker.ts\``] : [],
5575
5610
  `- \`PlatformApplications/${application.appDir}/topolo.cloudcontrol.json\``,
5576
5611
  ...options.api && application.serviceId ? [`- \`PlatformApplications/TopoloAuth/catalog/service-manifests/${application.serviceId}.json\``] : [],
5612
+ ...options.api && application.serviceId ? [`- \`PlatformApplications/TopoloAuth/scripts/add-topolo-${slug}-service-production.sql\``] : [],
5577
5613
  "",
5578
5614
  "## API Reference",
5579
5615
  "",
@@ -5604,6 +5640,7 @@ function internalDocs(application, options) {
5604
5640
  "- run `topolo apps audit <app> --local --repo-root /Users/ashes/Projects/topolo --fail-on needs_review --json` after SDK catalog registration",
5605
5641
  "- inspect `topolo.cloudcontrol.json` before deployment changes",
5606
5642
  ...options.api && application.serviceId ? [`- inspect \`PlatformApplications/TopoloAuth/catalog/service-manifests/${application.serviceId}.json\` when permission grants fail`] : [],
5643
+ ...options.api && application.serviceId ? [`- inspect \`PlatformApplications/TopoloAuth/scripts/add-topolo-${slug}-service-production.sql\` when embedded app login fails`] : [],
5607
5644
  "",
5608
5645
  "## Change Log / Verification",
5609
5646
  "",
@@ -5747,6 +5784,62 @@ function serviceManifestJson(application, options) {
5747
5784
  })}
5748
5785
  `;
5749
5786
  }
5787
+ function serviceRegistrationSql(application, options) {
5788
+ const slug = toSlug(application.id);
5789
+ const title = toTitle(application.name);
5790
+ const serviceId = application.serviceId ?? application.id;
5791
+ const productionUrl = application.productionUrl ?? `https://${slug}.topolo.app`;
5792
+ const authDomain = hostnameFromUrl(productionUrl);
5793
+ const surface = options.tenancy === "household" ? "personal-workspace" : "workspace";
5794
+ const settings = JSON.stringify({
5795
+ app_slug: `topolo-${slug}`,
5796
+ surface,
5797
+ auth_domain: authDomain,
5798
+ launcher: {
5799
+ category: "first_party",
5800
+ app_id: slug
5801
+ }
5802
+ });
5803
+ return [
5804
+ `-- Register ${title} in the Topolo Auth service catalog.`,
5805
+ "-- Safe to rerun.",
5806
+ "",
5807
+ "INSERT INTO services (",
5808
+ " id,",
5809
+ " name,",
5810
+ " description,",
5811
+ " base_url,",
5812
+ " version,",
5813
+ " status,",
5814
+ " settings,",
5815
+ " created_at,",
5816
+ " updated_at,",
5817
+ " show_in_app_switcher",
5818
+ ")",
5819
+ "VALUES (",
5820
+ ` '${sqlString(serviceId)}',`,
5821
+ ` '${sqlString(title)}',`,
5822
+ ` 'First-party ${sqlString(title)} ${sqlString(surface)} application.',`,
5823
+ ` '${sqlString(productionUrl)}',`,
5824
+ " '1.0.0',",
5825
+ " 'active',",
5826
+ ` '${sqlString(settings)}',`,
5827
+ " strftime('%s', 'now'),",
5828
+ " strftime('%s', 'now'),",
5829
+ " 1",
5830
+ ")",
5831
+ "ON CONFLICT(id) DO UPDATE SET",
5832
+ " name = excluded.name,",
5833
+ " description = excluded.description,",
5834
+ " base_url = excluded.base_url,",
5835
+ " version = excluded.version,",
5836
+ " status = excluded.status,",
5837
+ " settings = excluded.settings,",
5838
+ " updated_at = strftime('%s', 'now'),",
5839
+ " show_in_app_switcher = excluded.show_in_app_switcher;",
5840
+ ""
5841
+ ].join("\n");
5842
+ }
5750
5843
  function developerManifest(application, options) {
5751
5844
  return `${json({
5752
5845
  schema: "https://topolo.app/schemas/topolo-app-manifest.v1.json",
@@ -5870,6 +5963,13 @@ function toTitle(value) {
5870
5963
  function json(value) {
5871
5964
  return JSON.stringify(value, null, 2);
5872
5965
  }
5966
+ function hostnameFromUrl(value) {
5967
+ try {
5968
+ return new URL(value).hostname;
5969
+ } catch {
5970
+ return value.replace(/^https?:\/\//, "").replace(/\/.*$/, "");
5971
+ }
5972
+ }
5873
5973
  async function pathExists(path4) {
5874
5974
  try {
5875
5975
  await access(path4, constants.F_OK);
@@ -5892,6 +5992,9 @@ function escapeHtml(value) {
5892
5992
  function escapeSingleQuoted(value) {
5893
5993
  return value.replace(/\\/g, "\\\\").replace(/'/g, "\\'");
5894
5994
  }
5995
+ function sqlString(value) {
5996
+ return value.replace(/'/g, "''");
5997
+ }
5895
5998
  function escapeDoubleQuoted(value) {
5896
5999
  return value.replace(/\\/g, "\\\\").replace(/"/g, '\\"');
5897
6000
  }
@@ -6223,7 +6326,7 @@ function recordApplicationEvidence(application, options = {}) {
6223
6326
  let before = null;
6224
6327
  if (existsSync3(evidencePath)) {
6225
6328
  try {
6226
- const raw = JSON.parse(readFileSync2(evidencePath, "utf8"));
6329
+ const raw = JSON.parse(readFileSync3(evidencePath, "utf8"));
6227
6330
  if (raw && typeof raw === "object" && raw.version === 1) {
6228
6331
  before = raw;
6229
6332
  }
@@ -6499,7 +6602,7 @@ function statusesAtOrWorse(threshold) {
6499
6602
  }
6500
6603
 
6501
6604
  // src/commands/platform.ts
6502
- import { readdirSync as readdirSync2, readFileSync as readFileSync3, statSync as statSync2 } from "fs";
6605
+ import { readdirSync as readdirSync2, readFileSync as readFileSync4, statSync as statSync2 } from "fs";
6503
6606
  import path3 from "path";
6504
6607
  function registerPlatformCommand(program2) {
6505
6608
  const platform3 = program2.command("platform").description("Internal Topolo first-party platform and personal app commands");
@@ -6625,7 +6728,7 @@ function scanStagingProductionUrls(rootInput, allowPatterns) {
6625
6728
  function scanFile(filePath) {
6626
6729
  if (shouldSkipFile(filePath)) return;
6627
6730
  const relativePath = path3.relative(root, filePath);
6628
- const content = readFileSync3(filePath, "utf8");
6731
+ const content = readFileSync4(filePath, "utf8");
6629
6732
  const lines = content.split(/\r?\n/);
6630
6733
  lines.forEach((line, index) => {
6631
6734
  const matches = [...line.matchAll(PRODUCTION_TOPOLO_URL_PATTERN)].map((match) => match[0]);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@topolo/cli",
3
- "version": "0.1.18",
3
+ "version": "0.1.20",
4
4
  "description": "Command-line interface for Topolo developers, operators, and agents, with internal first-party scaffolding available under the topolo platform namespace.",
5
5
  "type": "module",
6
6
  "bin": {