@apso/cli 0.38.4 → 0.39.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 CHANGED
@@ -57,6 +57,17 @@ Add to your MCP configuration:
57
57
  | `start_dev_server` | Start local dev environment via Docker Compose |
58
58
  | `deploy_api` | Deploy to the Apso platform |
59
59
 
60
+ **Schema edit tools** (from `@apso/schema-tools`) change the project's `.apsorc` one step at a time. Each write is linted with the rules `apso generate` enforces; a change that would add a lint error is rejected and the file is left as it was.
61
+
62
+ | Tool | Description |
63
+ |------|-------------|
64
+ | `get_schema`, `describe_entity` | Read the schema outline, or one entity and its relationships |
65
+ | `add_entity`, `rename_entity`, `remove_entity` | Entities (relationships and foreign key indexes follow renames and removals) |
66
+ | `add_field`, `update_field`, `rename_field`, `remove_field` | Fields (indexes and uniques follow renames and removals) |
67
+ | `add_relationship`, `remove_relationship` | Relationships |
68
+ | `add_index` | Index or unique index |
69
+ | `lint_schema` | Lint report |
70
+
60
71
  **Available resources:**
61
72
 
62
73
  | Resource | URI | Description |
@@ -16,6 +16,7 @@ const lib_1 = require("../../lib");
16
16
  const runner_1 = require("../../lib/doctor/runner");
17
17
  const file_system_1 = require("../../lib/utils/file-system");
18
18
  const schema_convert_1 = require("../../lib/utils/schema-convert");
19
+ const mcp_schema_tools_1 = require("../../lib/mcp-schema-tools");
19
20
  const perf_hooks_1 = require("perf_hooks");
20
21
  class McpServe extends base_command_1.default {
21
22
  async run() {
@@ -69,6 +70,10 @@ class McpServe extends base_command_1.default {
69
70
  };
70
71
  }
71
72
  registerTools(server) {
73
+ // ── granular schema edits (@apso/schema-tools) ─────────────────
74
+ // get_schema, describe_entity, add_entity, add_field, rename_field, ...
75
+ // on the project's .apsorc, each linted before it is written.
76
+ (0, mcp_schema_tools_1.registerSchemaTools)(server);
72
77
  // ── design_schema ──────────────────────────────────────────────
73
78
  server.tool("design_schema", "Design a database schema from application requirements. Takes a description of entities, relationships, and business rules. Returns a validated .apsorc schema definition ready for code generation.", {
74
79
  requirements: zod_1.z
@@ -0,0 +1,18 @@
1
+ import { LintIssue, LintResult } from "@apso/schema-tools";
2
+ import BaseCommand from "../../lib/base-command";
3
+ import { ApsorcType } from "../../lib/apsorc-parser";
4
+ /** Lints (and with `fix`, repairs and saves) an .apsorc file. */
5
+ export declare function lintApsorc(configPath: string, apsorc: ApsorcType, fix: boolean): {
6
+ result: LintResult;
7
+ fixed: LintIssue[];
8
+ backupPath?: string;
9
+ };
10
+ export default class SchemaLint extends BaseCommand {
11
+ static description: string;
12
+ static examples: string[];
13
+ static flags: {
14
+ fix: import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
15
+ json: import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
16
+ };
17
+ run(): Promise<void>;
18
+ }
@@ -0,0 +1,74 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.lintApsorc = void 0;
4
+ const tslib_1 = require("tslib");
5
+ const core_1 = require("@oclif/core");
6
+ const fs = tslib_1.__importStar(require("fs"));
7
+ const path = tslib_1.__importStar(require("path"));
8
+ const schema_tools_1 = require("@apso/schema-tools");
9
+ const base_command_1 = tslib_1.__importDefault(require("../../lib/base-command"));
10
+ const config_1 = require("../../lib/config");
11
+ const apsorc_parser_1 = require("../../lib/apsorc-parser");
12
+ /** Lints (and with `fix`, repairs and saves) an .apsorc file. */
13
+ function lintApsorc(configPath, apsorc, fix) {
14
+ if (!fix)
15
+ return { result: (0, schema_tools_1.lintSchema)(apsorc), fixed: [] };
16
+ const { schema, applied } = (0, schema_tools_1.fixSchema)(apsorc);
17
+ let backupPath;
18
+ if (applied.length > 0) {
19
+ backupPath = (0, config_1.createBackup)(configPath, path.dirname(configPath));
20
+ fs.writeFileSync(configPath, `${JSON.stringify(schema, null, 2)}\n`, "utf-8");
21
+ }
22
+ return { result: (0, schema_tools_1.lintSchema)(schema), fixed: applied, backupPath };
23
+ }
24
+ exports.lintApsorc = lintApsorc;
25
+ class SchemaLint extends base_command_1.default {
26
+ async run() {
27
+ const { flags } = await this.parse(SchemaLint);
28
+ let file;
29
+ try {
30
+ file = (0, apsorc_parser_1.readApsorcFile)();
31
+ }
32
+ catch (error) {
33
+ this.error(`Failed to read .apsorc: ${error instanceof Error ? error.message : String(error)}`);
34
+ }
35
+ if (file.apsorc.version !== 2) {
36
+ this.error("apso schema lint supports version 2 .apsorc files only.");
37
+ }
38
+ const { result, fixed, backupPath } = lintApsorc(file.configPath, file.apsorc, flags.fix);
39
+ if (flags.json) {
40
+ this.log(JSON.stringify({ ...result, fixed }, null, 2));
41
+ }
42
+ else {
43
+ if (fixed.length > 0) {
44
+ this.log(`Fixed ${fixed.length} issue(s) in ${file.configPath} (backup: ${backupPath}):`);
45
+ for (const issue of fixed)
46
+ this.log(` - ${issue.rule}: ${issue.message}`);
47
+ this.log("");
48
+ }
49
+ this.log((0, schema_tools_1.formatLintReport)(result));
50
+ if (!flags.fix && result.issues.some((issue) => issue.fixable)) {
51
+ this.log('\nRun "apso schema lint --fix" to apply the auto-fixable changes.');
52
+ }
53
+ }
54
+ if (result.errorCount > 0)
55
+ this.exit(1);
56
+ }
57
+ }
58
+ SchemaLint.description = "Check the local .apsorc for names and settings that would break the generated code";
59
+ SchemaLint.examples = [
60
+ "$ apso schema lint",
61
+ "$ apso schema lint --fix",
62
+ "$ apso schema lint --json",
63
+ ];
64
+ SchemaLint.flags = {
65
+ fix: core_1.Flags.boolean({
66
+ description: "Apply the safe automatic fixes and save .apsorc (a backup is kept)",
67
+ default: false,
68
+ }),
69
+ json: core_1.Flags.boolean({
70
+ description: "Print the result as JSON",
71
+ default: false,
72
+ }),
73
+ };
74
+ exports.default = SchemaLint;
@@ -5,12 +5,32 @@ const core_1 = require("@oclif/core");
5
5
  const base_command_1 = tslib_1.__importDefault(require("../../lib/base-command"));
6
6
  const config_1 = require("../../lib/config");
7
7
  const services_1 = require("../../lib/api/services");
8
+ const schema_tools_1 = require("@apso/schema-tools");
8
9
  const apsorc_parser_1 = require("../../lib/apsorc-parser");
9
10
  const schema_convert_1 = require("../../lib/utils/schema-convert");
10
11
  class SchemaValidate extends base_command_1.default {
11
12
  async run() {
12
13
  var _a;
13
14
  const { flags } = await this.parse(SchemaValidate);
15
+ // Lint first so every issue is listed, not just the first one parseApsorc throws on
16
+ let file;
17
+ try {
18
+ file = (0, apsorc_parser_1.readApsorcFile)();
19
+ }
20
+ catch (error) {
21
+ const msg = error instanceof Error ? error.message : String(error);
22
+ this.error(`Failed to read .apsorc: ${msg}`);
23
+ }
24
+ if (file.apsorc.version === 2) {
25
+ const lint = (0, schema_tools_1.lintSchema)(file.apsorc);
26
+ if (lint.issues.length > 0) {
27
+ this.log((0, schema_tools_1.formatLintReport)(lint));
28
+ this.log("");
29
+ }
30
+ if (lint.errorCount > 0) {
31
+ this.error(`Validation failed with ${lint.errorCount} lint error(s). Run "apso schema lint --fix" to apply the safe fixes.`);
32
+ }
33
+ }
14
34
  // Parse .apsorc
15
35
  let parsed;
16
36
  try {
@@ -52,8 +52,9 @@ type ParsedApsorc = {
52
52
  };
53
53
  export declare const parseApsorcV1: (apsorc: ApsorcType) => ParsedApsorcData;
54
54
  /**
55
- * A name in .apsorc that would generate code that does not compile. `code`
56
- * matches the apso-client-v2 schema validator (src/lib/ai/validation.ts).
55
+ * A schema problem that would make `apso generate` emit code that does not
56
+ * compile. `code` is the @apso/schema-tools rule id (FIELD_RELATIONSHIP_COLLISION,
57
+ * DUPLICATE_FIELD_NAME, ...), the same codes the apso-client-v2 validator used.
57
58
  */
58
59
  export declare class ApsorcNamingError extends Error {
59
60
  code: string;
@@ -62,13 +63,12 @@ export declare class ApsorcNamingError extends Error {
62
63
  constructor(message: string, code: string, entity: string, field?: string | undefined);
63
64
  }
64
65
  /**
65
- * Throws an ApsorcNamingError when .apsorc names would generate code that does
66
- * not compile, e.g. a text field `notes` on Contact plus Note ManyToOne
67
- * Contact, whose inverse side is `notes: Note[]` on Contact (TS2300 Duplicate
68
- * identifier). The client schema validator enforces the same rules; both repos
69
- * run test/fixtures/codegen-naming-cases.json, so change them together.
66
+ * Throws an ApsorcNamingError for the first @apso/schema-tools error, e.g. a
67
+ * text field `notes` on Contact plus Note ManyToOne Contact, whose inverse
68
+ * side is `notes: Note[]` on Contact (TS2300 Duplicate identifier). The client
69
+ * schema builder runs the same rules, so a schema that passes there passes here.
70
70
  */
71
- export declare const assertCodegenSafeNames: (entities: Entity[], relationshipMap: RelationshipMap) => void;
71
+ export declare const assertCodegenSafeNames: (apsorc: Pick<ApsorcType, "entities" | "relationships">) => void;
72
72
  export declare const parseApsorcV2: (apsorc: ApsorcType) => ParsedApsorcData;
73
73
  export declare const parseApsorc: () => ParsedApsorc;
74
74
  /**
@@ -76,5 +76,10 @@ export declare const parseApsorc: () => ParsedApsorc;
76
76
  * Searches upwards from the current working directory.
77
77
  * @returns The absolute path to the .apsorc file, or null if not found.
78
78
  */
79
+ /** Reads the .apsorc file itself (not rc-merged), for commands that rewrite it. */
80
+ export declare const readApsorcFile: () => {
81
+ configPath: string;
82
+ apsorc: ApsorcType;
83
+ };
79
84
  export declare const findConfigPath: () => string | null;
80
85
  export {};
@@ -1,14 +1,14 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.findConfigPath = exports.parseApsorc = exports.parseApsorcV2 = exports.assertCodegenSafeNames = exports.ApsorcNamingError = exports.parseApsorcV1 = exports.ApiType = void 0;
3
+ exports.findConfigPath = exports.readApsorcFile = exports.parseApsorc = exports.parseApsorcV2 = exports.assertCodegenSafeNames = exports.ApsorcNamingError = exports.parseApsorcV1 = exports.ApiType = void 0;
4
4
  const tslib_1 = require("tslib");
5
5
  const fs = tslib_1.__importStar(require("fs"));
6
6
  const path = tslib_1.__importStar(require("path"));
7
7
  const rc_1 = tslib_1.__importDefault(require("rc"));
8
8
  const relationships_1 = require("./utils/relationships");
9
9
  const perf_hooks_1 = require("perf_hooks");
10
- const pluralize_1 = tslib_1.__importDefault(require("pluralize"));
11
- const casing_1 = require("./utils/casing");
10
+ // @apso/schema-tools is published on npm (apsoai/apso-packages).
11
+ const schema_tools_1 = require("@apso/schema-tools");
12
12
  var ApiType;
13
13
  (function (ApiType) {
14
14
  ApiType["Graphql"] = "graphql";
@@ -23,11 +23,10 @@ const parseApsorcV1 = (apsorc) => {
23
23
  return { entities, relationshipMap };
24
24
  };
25
25
  exports.parseApsorcV1 = parseApsorcV1;
26
- /** Valid in TypeScript, Python and Go, so every target language compiles it. */
27
- const IDENTIFIER = /^[A-Z_a-z]\w*$/;
28
26
  /**
29
- * A name in .apsorc that would generate code that does not compile. `code`
30
- * matches the apso-client-v2 schema validator (src/lib/ai/validation.ts).
27
+ * A schema problem that would make `apso generate` emit code that does not
28
+ * compile. `code` is the @apso/schema-tools rule id (FIELD_RELATIONSHIP_COLLISION,
29
+ * DUPLICATE_FIELD_NAME, ...), the same codes the apso-client-v2 validator used.
31
30
  */
32
31
  class ApsorcNamingError extends Error {
33
32
  constructor(message, code, entity, field) {
@@ -40,57 +39,24 @@ class ApsorcNamingError extends Error {
40
39
  }
41
40
  exports.ApsorcNamingError = ApsorcNamingError;
42
41
  /**
43
- * Throws an ApsorcNamingError when .apsorc names would generate code that does
44
- * not compile, e.g. a text field `notes` on Contact plus Note ManyToOne
45
- * Contact, whose inverse side is `notes: Note[]` on Contact (TS2300 Duplicate
46
- * identifier). The client schema validator enforces the same rules; both repos
47
- * run test/fixtures/codegen-naming-cases.json, so change them together.
42
+ * Throws an ApsorcNamingError for the first @apso/schema-tools error, e.g. a
43
+ * text field `notes` on Contact plus Note ManyToOne Contact, whose inverse
44
+ * side is `notes: Note[]` on Contact (TS2300 Duplicate identifier). The client
45
+ * schema builder runs the same rules, so a schema that passes there passes here.
48
46
  */
49
- const assertCodegenSafeNames = (entities, relationshipMap) => {
50
- const seenEntities = new Set();
51
- for (const entity of entities) {
52
- if (seenEntities.has(entity.name)) {
53
- throw new ApsorcNamingError(`Entity "${entity.name}" is defined more than once. Merge or rename one of them in .apsorc.`, "DUPLICATE_ENTITY_NAME", entity.name);
54
- }
55
- seenEntities.add(entity.name);
56
- if (!IDENTIFIER.test(entity.name)) {
57
- throw new ApsorcNamingError(`Entity "${entity.name}" is not a valid name. Use letters, digits and underscores, starting with a letter.`, "INVALID_ENTITY_NAME", entity.name);
58
- }
59
- const fieldNames = new Set();
60
- for (const { name } of entity.fields || []) {
61
- if (!IDENTIFIER.test(name)) {
62
- throw new ApsorcNamingError(`Field "${name}" on entity "${entity.name}" is not a valid name. Use letters, digits and underscores.`, "INVALID_FIELD_NAME", entity.name, name);
63
- }
64
- if (fieldNames.has(name)) {
65
- throw new ApsorcNamingError(`Entity "${entity.name}" has more than one field named "${name}". Remove or rename one in .apsorc.`, "DUPLICATE_FIELD_NAME", entity.name, name);
66
- }
67
- fieldNames.add(name);
68
- }
69
- // Same property names and dedupe key as getRelationshipForTemplate + entity.eta.
70
- const generated = new Map();
71
- for (const rel of relationshipMap[entity.name] || []) {
72
- const base = rel.referenceName || rel.name;
73
- const property = (0, casing_1.camelCase)(rel.type === "OneToMany" || rel.type === "ManyToMany"
74
- ? (0, pluralize_1.default)(base)
75
- : base);
76
- const key = `${rel.name}:${rel.referenceName || "default"}`;
77
- const desc = `${rel.type} relationship to "${rel.name}"`;
78
- if (fieldNames.has(property)) {
79
- throw new ApsorcNamingError(`Entity "${entity.name}" has a field "${property}" with the same name as the property generated by its ${desc}. Rename the field in .apsorc.`, "FIELD_RELATIONSHIP_COLLISION", entity.name, property);
80
- }
81
- const existing = generated.get(property);
82
- if (existing && existing.key !== key) {
83
- throw new ApsorcNamingError(`Entity "${entity.name}" gets the property "${property}" from both its ${existing.rel} and its ${desc}. Give one of them a different "to_name" in .apsorc.`, "RELATIONSHIP_PROPERTY_CLASH", entity.name, property);
84
- }
85
- generated.set(property, { key, rel: desc });
86
- }
87
- }
47
+ const assertCodegenSafeNames = (apsorc) => {
48
+ const { issues } = (0, schema_tools_1.lintSchema)(apsorc);
49
+ const error = issues.find((issue) => issue.severity === "error");
50
+ if (!error)
51
+ return;
52
+ const more = issues.filter((issue) => issue.severity === "error").length - 1;
53
+ throw new ApsorcNamingError(`${error.message}${more > 0 ? ` (${more} more error${more === 1 ? "" : "s"})` : ""} Run "apso schema lint" to see every issue, or "apso schema lint --fix" to apply the safe fixes.`, error.rule, error.entity || "", error.field);
88
54
  };
89
55
  exports.assertCodegenSafeNames = assertCodegenSafeNames;
90
56
  const parseApsorcV2 = (apsorc) => {
91
57
  const { entities, relationships: apsoRelationships } = apsorc;
58
+ (0, exports.assertCodegenSafeNames)(apsorc);
92
59
  const relationshipMap = (0, relationships_1.parseRelationships)(apsoRelationships);
93
- (0, exports.assertCodegenSafeNames)(entities, relationshipMap);
94
60
  return { entities, relationshipMap };
95
61
  };
96
62
  exports.parseApsorcV2 = parseApsorcV2;
@@ -182,6 +148,15 @@ exports.parseApsorc = parseApsorc;
182
148
  * Searches upwards from the current working directory.
183
149
  * @returns The absolute path to the .apsorc file, or null if not found.
184
150
  */
151
+ /** Reads the .apsorc file itself (not rc-merged), for commands that rewrite it. */
152
+ const readApsorcFile = () => {
153
+ const configPath = (0, exports.findConfigPath)();
154
+ if (!configPath) {
155
+ throw new Error("No .apsorc found in this directory or any parent.");
156
+ }
157
+ return { configPath, apsorc: JSON.parse(fs.readFileSync(configPath).toString()) };
158
+ };
159
+ exports.readApsorcFile = readApsorcFile;
185
160
  const findConfigPath = () => {
186
161
  let currentDir = process.cwd();
187
162
  while (currentDir !== path.parse(currentDir).root) {
@@ -0,0 +1,31 @@
1
+ export interface SchemaToolFileResult {
2
+ ok: boolean;
3
+ message: string;
4
+ data?: unknown;
5
+ configPath: string;
6
+ /** True when the operation changed the schema and .apsorc was rewritten. */
7
+ saved: boolean;
8
+ lint: {
9
+ errorCount: number;
10
+ warningCount: number;
11
+ report: string;
12
+ };
13
+ }
14
+ /**
15
+ * Run one @apso/schema-tools operation on an .apsorc file: read it, apply the
16
+ * operation, write it back when the operation changed the schema, and return
17
+ * the lint result. An operation that would add a lint error is rejected by
18
+ * the tool and the file is left untouched.
19
+ */
20
+ export declare function applySchemaToolToFile(configPath: string, name: string, input: unknown): SchemaToolFileResult;
21
+ type ToolServer = {
22
+ tool: (...args: any[]) => unknown;
23
+ };
24
+ /**
25
+ * Register every @apso/schema-tools operation as a granular MCP tool on the
26
+ * project's .apsorc (found from the current directory up), next to the coarse
27
+ * design/validate/scaffold tools. The JSON Schema inputs from the package are
28
+ * converted to zod for the MCP SDK.
29
+ */
30
+ export declare function registerSchemaTools(server: ToolServer): void;
31
+ export {};
@@ -0,0 +1,69 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.registerSchemaTools = exports.applySchemaToolToFile = void 0;
4
+ const tslib_1 = require("tslib");
5
+ const fs = tslib_1.__importStar(require("fs"));
6
+ const zod_1 = require("zod");
7
+ const schema_tools_1 = require("@apso/schema-tools");
8
+ const apsorc_parser_1 = require("./apsorc-parser");
9
+ /**
10
+ * Run one @apso/schema-tools operation on an .apsorc file: read it, apply the
11
+ * operation, write it back when the operation changed the schema, and return
12
+ * the lint result. An operation that would add a lint error is rejected by
13
+ * the tool and the file is left untouched.
14
+ */
15
+ function applySchemaToolToFile(configPath, name, input) {
16
+ // eslint-disable-next-line unicorn/prefer-json-parse-buffer -- JSON.parse's TS type requires a string
17
+ const apsorc = JSON.parse(fs.readFileSync(configPath, "utf-8"));
18
+ if (apsorc.version !== 2) {
19
+ throw new Error("The schema tools support version 2 .apsorc files only.");
20
+ }
21
+ const result = (0, schema_tools_1.runSchemaTool)(apsorc, name, input);
22
+ const saved = result.ok && result.schema !== apsorc;
23
+ if (saved)
24
+ fs.writeFileSync(configPath, `${JSON.stringify(result.schema, null, 2)}\n`, "utf-8");
25
+ const lint = (0, schema_tools_1.lintSchema)(result.schema);
26
+ return {
27
+ ok: result.ok,
28
+ message: result.message,
29
+ ...(result.data === undefined ? {} : { data: result.data }),
30
+ configPath,
31
+ saved,
32
+ lint: { errorCount: lint.errorCount, warningCount: lint.warningCount, report: (0, schema_tools_1.formatLintReport)(lint) },
33
+ };
34
+ }
35
+ exports.applySchemaToolToFile = applySchemaToolToFile;
36
+ /**
37
+ * Register every @apso/schema-tools operation as a granular MCP tool on the
38
+ * project's .apsorc (found from the current directory up), next to the coarse
39
+ * design/validate/scaffold tools. The JSON Schema inputs from the package are
40
+ * converted to zod for the MCP SDK.
41
+ */
42
+ function registerSchemaTools(server) {
43
+ for (const t of schema_tools_1.schemaTools) {
44
+ const shape = zod_1.z.fromJSONSchema(t.inputSchema).shape;
45
+ server.tool(t.name, `${t.description} Operates on the .apsorc in the current project.${t.readOnly ? "" : " Writes the file only when the change lints clean of new errors."}`, shape, { readOnlyHint: t.readOnly }, async (input) => {
46
+ const configPath = (0, apsorc_parser_1.findConfigPath)();
47
+ if (!configPath) {
48
+ return {
49
+ content: [{ type: "text", text: "No .apsorc found in this directory or its parents. Run `apso init` first." }],
50
+ isError: true,
51
+ };
52
+ }
53
+ try {
54
+ const result = applySchemaToolToFile(configPath, t.name, input);
55
+ return {
56
+ content: [{ type: "text", text: JSON.stringify(result, null, 2) }],
57
+ isError: !result.ok,
58
+ };
59
+ }
60
+ catch (error) {
61
+ return {
62
+ content: [{ type: "text", text: error instanceof Error ? error.message : String(error) }],
63
+ isError: true,
64
+ };
65
+ }
66
+ });
67
+ }
68
+ }
69
+ exports.registerSchemaTools = registerSchemaTools;
@@ -1,14 +1,15 @@
1
1
  {
2
2
  "name": "@apso/cli",
3
- "version": "0.38.4",
3
+ "version": "0.39.1",
4
4
  "lockfileVersion": 3,
5
5
  "requires": true,
6
6
  "packages": {
7
7
  "": {
8
8
  "name": "@apso/cli",
9
- "version": "0.38.4",
9
+ "version": "0.39.1",
10
10
  "license": "Apache-2.0",
11
11
  "dependencies": {
12
+ "@apso/schema-tools": "^0.2.0",
12
13
  "@biomejs/biome": "^1.9.4",
13
14
  "@electric-sql/pglite": "^0.2.17",
14
15
  "@modelcontextprotocol/sdk": "^1.29.0",
@@ -147,6 +148,15 @@
147
148
  "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==",
148
149
  "license": "MIT"
149
150
  },
151
+ "node_modules/@apso/schema-tools": {
152
+ "version": "0.2.0",
153
+ "resolved": "https://registry.npmjs.org/@apso/schema-tools/-/schema-tools-0.2.0.tgz",
154
+ "integrity": "sha512-EulC5vj7ErDkMhnfFyQdEO1k9LuELpg0FsBtkfgf/AaISiJPWvr6ZbJcvhzlqUisLq+G9AJO41egmN11A+tRrA==",
155
+ "license": "Apache-2.0",
156
+ "dependencies": {
157
+ "pluralize": "^8.0.0"
158
+ }
159
+ },
150
160
  "node_modules/@babel/code-frame": {
151
161
  "version": "7.21.4",
152
162
  "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.21.4.tgz",
@@ -1,5 +1,5 @@
1
1
  {
2
- "version": "0.38.4",
2
+ "version": "0.39.1",
3
3
  "commands": {
4
4
  "config": {
5
5
  "id": "config",
@@ -784,6 +784,36 @@
784
784
  "flags": {},
785
785
  "args": {}
786
786
  },
787
+ "schema:lint": {
788
+ "id": "schema:lint",
789
+ "description": "Check the local .apsorc for names and settings that would break the generated code",
790
+ "strict": true,
791
+ "pluginName": "@apso/cli",
792
+ "pluginAlias": "@apso/cli",
793
+ "pluginType": "core",
794
+ "aliases": [],
795
+ "hiddenAliases": [],
796
+ "examples": [
797
+ "$ apso schema lint",
798
+ "$ apso schema lint --fix",
799
+ "$ apso schema lint --json"
800
+ ],
801
+ "flags": {
802
+ "fix": {
803
+ "name": "fix",
804
+ "type": "boolean",
805
+ "description": "Apply the safe automatic fixes and save .apsorc (a backup is kept)",
806
+ "allowNo": false
807
+ },
808
+ "json": {
809
+ "name": "json",
810
+ "type": "boolean",
811
+ "description": "Print the result as JSON",
812
+ "allowNo": false
813
+ }
814
+ },
815
+ "args": {}
816
+ },
787
817
  "schema:pull": {
788
818
  "id": "schema:pull",
789
819
  "description": "Pull remote schema to local .apsorc",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@apso/cli",
3
- "version": "0.38.4",
3
+ "version": "0.39.1",
4
4
  "mcpName": "io.github.apsoai/apso",
5
5
  "description": "Apso CLI",
6
6
  "author": "Apso by Mavric - @mavric",
@@ -24,6 +24,7 @@
24
24
  "/oclif.manifest.json"
25
25
  ],
26
26
  "dependencies": {
27
+ "@apso/schema-tools": "^0.2.0",
27
28
  "@biomejs/biome": "^1.9.4",
28
29
  "@electric-sql/pglite": "^0.2.17",
29
30
  "@modelcontextprotocol/sdk": "^1.29.0",