anymorph 0.6.0 → 0.7.0

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 (3) hide show
  1. package/README.md +6 -16
  2. package/dist/index.js +217 -113
  3. package/package.json +1 -1
package/README.md CHANGED
@@ -30,7 +30,9 @@ anymorph workspaces
30
30
  anymorph init
31
31
  anymorph prepare ws_abc123
32
32
  anymorph validate 20260517T074200Z
33
- anymorph submit 20260517T074200Z
33
+ git add agent/runs content
34
+ git commit -m "chore(geo): publish run 20260517T074200Z"
35
+ git push
34
36
  ```
35
37
 
36
38
  ## Commands
@@ -187,21 +189,9 @@ anymorph validate 20260517T074200Z
187
189
  ```
188
190
 
189
191
  Validation does not update the backend. Backend sync happens from the tenant
190
- submission command after local artifacts pass validation.
191
-
192
- ### `anymorph submit <runId>`
193
-
194
- Submit validated local GEO run artifacts to Anymorph.
195
-
196
- ```bash
197
- anymorph submit 20260517T074200Z
198
- anymorph submit 20260517T074200Z --json
199
- ```
200
-
201
- The CLI reads `agent/runs/{runId}/manifest.json`, submits the manifest-declared
202
- artifact paths, and includes the current git commit SHA when available. Use
203
- `--workspace <workspaceId>` only when the workspace cannot be inferred from the
204
- run package.
192
+ repo GitHub webhook after `agent/runs/{runId}/actions.json` is pushed to
193
+ `main`. Any generated `content/*.mdx` files are materialized as CMS pages from
194
+ the same webhook path.
205
195
 
206
196
  ## How It Works
207
197
 
package/dist/index.js CHANGED
@@ -12216,6 +12216,88 @@ var require_src = __commonJS({
12216
12216
  var cmsFrontmatter = require_cms_frontmatter();
12217
12217
  var cmsThemeTokens = require_cms_theme_tokens();
12218
12218
  var HOSTNAME_LABEL_RE = /^[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?$/i;
12219
+ var CMS_MDX_COMPONENT_CONTRACTS2 = Object.freeze({
12220
+ Callout: Object.freeze({
12221
+ props: Object.freeze({
12222
+ tone: Object.freeze({
12223
+ allowedValues: Object.freeze(["info", "success", "definition"]),
12224
+ defaultValue: "info"
12225
+ })
12226
+ })
12227
+ }),
12228
+ CTA: Object.freeze({
12229
+ requiredProps: Object.freeze(["title", "description"]),
12230
+ reason: "CTA renders title + description side-by-side with the button; missing description leaves the column empty."
12231
+ })
12232
+ });
12233
+ function validateCmsMdxComponentContracts2(mdx) {
12234
+ const issues = [];
12235
+ checkRequiredComponentProps(mdx, issues);
12236
+ checkEnumComponentProps(mdx, issues);
12237
+ return issues;
12238
+ }
12239
+ function checkRequiredComponentProps(mdx, issues) {
12240
+ for (const [component, contract] of Object.entries(CMS_MDX_COMPONENT_CONTRACTS2)) {
12241
+ if (!Array.isArray(contract.requiredProps) || contract.requiredProps.length === 0) continue;
12242
+ for (const attrs of findComponentAttrs(mdx, component)) {
12243
+ for (const prop of contract.requiredProps) {
12244
+ if (!new RegExp(`\\b${escapeRegExp(prop)}\\s*=`).test(attrs)) {
12245
+ const trailer = contract.reason ? ` ${contract.reason}` : "";
12246
+ issues.push({
12247
+ code: "missing_required_prop",
12248
+ component,
12249
+ prop,
12250
+ message: `<${component}> is missing required prop "${prop}".${trailer}`
12251
+ });
12252
+ }
12253
+ }
12254
+ }
12255
+ }
12256
+ }
12257
+ function checkEnumComponentProps(mdx, issues) {
12258
+ for (const [component, contract] of Object.entries(CMS_MDX_COMPONENT_CONTRACTS2)) {
12259
+ if (!contract.props) continue;
12260
+ for (const attrs of findComponentAttrs(mdx, component)) {
12261
+ for (const [prop, propContract] of Object.entries(contract.props)) {
12262
+ if (!Array.isArray(propContract.allowedValues)) continue;
12263
+ const value = readStaticJsxStringProp(attrs, prop);
12264
+ if (value === null) continue;
12265
+ if (!propContract.allowedValues.includes(value)) {
12266
+ issues.push({
12267
+ code: "invalid_prop_value",
12268
+ component,
12269
+ prop,
12270
+ value,
12271
+ allowedValues: propContract.allowedValues,
12272
+ message: `<${component}> prop "${prop}" must be one of ${propContract.allowedValues.map((v) => `"${v}"`).join(", ")}; received "${value}".`
12273
+ });
12274
+ }
12275
+ }
12276
+ }
12277
+ }
12278
+ }
12279
+ function findComponentAttrs(mdx, component) {
12280
+ const tagPattern = new RegExp(`<${escapeRegExp(component)}\\b([^>]*?)\\s*/?>`, "gs");
12281
+ const attrs = [];
12282
+ let match = tagPattern.exec(mdx);
12283
+ while (match !== null) {
12284
+ attrs.push(match[1] ?? "");
12285
+ match = tagPattern.exec(mdx);
12286
+ }
12287
+ return attrs;
12288
+ }
12289
+ function readStaticJsxStringProp(attrs, prop) {
12290
+ const propPattern = new RegExp(
12291
+ `\\b${escapeRegExp(prop)}\\s*=\\s*(?:"([^"]*)"|'([^']*)'|\\{\\s*["']([^"']*)["']\\s*\\})`,
12292
+ "s"
12293
+ );
12294
+ const match = propPattern.exec(attrs);
12295
+ if (!match) return null;
12296
+ return match[1] ?? match[2] ?? match[3] ?? null;
12297
+ }
12298
+ function escapeRegExp(value) {
12299
+ return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
12300
+ }
12219
12301
  function normalizePromptGenDomain2(value) {
12220
12302
  const domain = value.trim().toLowerCase();
12221
12303
  if (domain.length === 0 || domain.length > 253 || domain.includes("/") || domain.includes("\\") || domain.includes("?") || domain.includes("#") || domain.includes(":") || domain.includes("@") || domain.startsWith(".") || domain.endsWith(".") || domain.includes("..")) {
@@ -13343,7 +13425,9 @@ var require_src = __commonJS({
13343
13425
  CMS_THEME_CONTRACT_TOKEN_KEYS: cmsThemeTokens.CMS_THEME_CONTRACT_TOKEN_KEYS,
13344
13426
  CMS_THEME_STATUS_DEFAULTS: cmsThemeTokens.CMS_THEME_STATUS_DEFAULTS,
13345
13427
  normalizeCmsThemeTokens: cmsThemeTokens.normalizeCmsThemeTokens,
13346
- validateCmsThemeTokens: cmsThemeTokens.validateCmsThemeTokens
13428
+ validateCmsThemeTokens: cmsThemeTokens.validateCmsThemeTokens,
13429
+ CMS_MDX_COMPONENT_CONTRACTS: CMS_MDX_COMPONENT_CONTRACTS2,
13430
+ validateCmsMdxComponentContracts: validateCmsMdxComponentContracts2
13347
13431
  };
13348
13432
  }
13349
13433
  });
@@ -13798,14 +13882,14 @@ var baseOpen = async (options) => {
13798
13882
  }
13799
13883
  const subprocess = childProcess.spawn(command, cliArguments, childProcessOptions);
13800
13884
  if (options.wait) {
13801
- return new Promise((resolve3, reject) => {
13885
+ return new Promise((resolve4, reject) => {
13802
13886
  subprocess.once("error", reject);
13803
13887
  subprocess.once("close", (exitCode) => {
13804
13888
  if (!options.allowNonzeroExitCode && exitCode > 0) {
13805
13889
  reject(new Error(`Exited with code ${exitCode}`));
13806
13890
  return;
13807
13891
  }
13808
- resolve3(subprocess);
13892
+ resolve4(subprocess);
13809
13893
  });
13810
13894
  });
13811
13895
  }
@@ -15419,7 +15503,7 @@ async function loginCommand() {
15419
15503
  process.exit(1);
15420
15504
  }
15421
15505
  function sleep(ms) {
15422
- return new Promise((resolve3) => setTimeout(resolve3, ms));
15506
+ return new Promise((resolve4) => setTimeout(resolve4, ms));
15423
15507
  }
15424
15508
 
15425
15509
  // src/lib/display.ts
@@ -15549,7 +15633,7 @@ async function checkCommand(domain, opts) {
15549
15633
  process.exit(1);
15550
15634
  }
15551
15635
  function sleep2(ms) {
15552
- return new Promise((resolve3) => setTimeout(resolve3, ms));
15636
+ return new Promise((resolve4) => setTimeout(resolve4, ms));
15553
15637
  }
15554
15638
 
15555
15639
  // src/commands/status.ts
@@ -15675,6 +15759,8 @@ var CMS_THEME_CONTRACT_TOKEN_KEYS = import_index2.default.CMS_THEME_CONTRACT_TOK
15675
15759
  var CMS_THEME_STATUS_DEFAULTS = import_index2.default.CMS_THEME_STATUS_DEFAULTS;
15676
15760
  var normalizeCmsThemeTokens = import_index2.default.normalizeCmsThemeTokens;
15677
15761
  var validateCmsThemeTokens = import_index2.default.validateCmsThemeTokens;
15762
+ var CMS_MDX_COMPONENT_CONTRACTS = import_index2.default.CMS_MDX_COMPONENT_CONTRACTS;
15763
+ var validateCmsMdxComponentContracts = import_index2.default.validateCmsMdxComponentContracts;
15678
15764
  var reasonTagSchema = import_index2.default.reasonTagSchema;
15679
15765
  var reasonClassSchema = import_index2.default.reasonClassSchema;
15680
15766
  var REASON_TAG_CLASS = import_index2.default.REASON_TAG_CLASS;
@@ -15684,8 +15770,8 @@ var priorDecisionSchema = import_index2.default.priorDecisionSchema;
15684
15770
  var geoStrategyDecisionInputSchema = import_index2.default.geoStrategyDecisionInputSchema;
15685
15771
 
15686
15772
  // src/commands/geo.ts
15687
- import { readFile as readFile3 } from "node:fs/promises";
15688
- import { join as join6 } from "node:path";
15773
+ import { readFile as readFile3, readdir as readdir3, stat as stat4 } from "node:fs/promises";
15774
+ import { join as join6, relative as relative2, resolve as resolve3 } from "node:path";
15689
15775
 
15690
15776
  // src/geo/package-writer.ts
15691
15777
  import { mkdir, writeFile } from "node:fs/promises";
@@ -16378,15 +16464,6 @@ async function validateGeoRunArtifacts(input) {
16378
16464
  runDir
16379
16465
  };
16380
16466
  }
16381
- function normalizeSubmitArtifactPaths(runId, paths) {
16382
- const required = [
16383
- `agent/runs/${runId}/actions.json`,
16384
- `agent/runs/${runId}/rationale.md`,
16385
- `agent/runs/${runId}/status.json`
16386
- ];
16387
- const clean = Array.isArray(paths) ? paths.filter((path2) => hasText(path2)) : [];
16388
- return Array.from(/* @__PURE__ */ new Set([...clean, ...required]));
16389
- }
16390
16467
  function validateManifest(value, runId, errors) {
16391
16468
  if (value.schemaVersion !== 1) errors.push("manifest.json schemaVersion must be 1");
16392
16469
  if (value.runId !== runId) errors.push(`manifest.json runId must match ${runId}`);
@@ -16732,30 +16809,47 @@ Run from the tenant repo root. Writes agent/runs/{runId}/ with manifest,
16732
16809
  context, policy, intents, product catalog, crawl logs, and status files.`
16733
16810
  ).action(geoPrepareCommand)
16734
16811
  );
16735
- commands.push(
16736
- new Command("validate").argument("<runId>").description("Validate local GEO strategy run artifacts before pushing").option("--json", "Output as JSON").addHelpText(
16737
- "after",
16738
- `
16812
+ const validateCommand = new Command("validate").argument("[runId]").description("Validate local GEO strategy artifacts or CMS MDX").option("--json", "Output as JSON").addHelpText(
16813
+ "after",
16814
+ `
16739
16815
  Examples:
16740
16816
  $ anymorph validate 20260517T074200Z
16817
+ $ anymorph validate run 20260517T074200Z
16818
+ $ anymorph validate actions 20260517T074200Z
16819
+ $ anymorph validate mdx content/guide/page.mdx
16820
+ $ anymorph validate mdx "content/**/*.mdx"
16741
16821
  $ anymorph validate 20260517T074200Z --json
16742
16822
 
16743
16823
  Checks required run files, the shared actions.json contract, policy hash,
16744
- per-asset target rules, and commerce targetProductIds.`
16745
- ).action(geoValidateCommand)
16824
+ per-asset target rules, commerce targetProductIds, or CMS MDX component contracts.`
16825
+ ).action(async (runId, opts) => {
16826
+ if (!runId) {
16827
+ console.error(source_default.red("Missing runId. Use anymorph validate <runId> or anymorph validate mdx <file>."));
16828
+ process.exit(1);
16829
+ }
16830
+ await geoValidateCommand(runId, opts);
16831
+ });
16832
+ validateCommand.addCommand(
16833
+ new Command("run").argument("<runId>").description("Validate a local GEO run package").option("--json", "Output as JSON").action(geoValidateCommand)
16746
16834
  );
16747
- commands.push(
16748
- new Command("submit").argument("<runId>").description("Submit validated local GEO strategy artifacts to Anymorph").option("--workspace <workspaceId>", "Override workspace id for this submission").option("--json", "Output as JSON").addHelpText(
16835
+ validateCommand.addCommand(
16836
+ new Command("actions").argument("<runId>").description("Validate actions.json and related local GEO run artifacts").option("--json", "Output as JSON").action(geoValidateCommand)
16837
+ );
16838
+ validateCommand.addCommand(
16839
+ new Command("mdx").argument("<paths...>").description("Validate CMS MDX component contracts").option("--json", "Output as JSON").addHelpText(
16749
16840
  "after",
16750
16841
  `
16751
16842
  Examples:
16752
- $ anymorph submit 20260517T074200Z
16753
- $ anymorph submit 20260517T074200Z --workspace ws_abc123
16754
-
16755
- Submit after committing and pushing tenant repo artifacts. Backend reads the
16756
- pushed actions.json from the tenant repo and materializes the run.`
16757
- ).action(geoSubmitCommand)
16843
+ $ anymorph validate mdx content/guide/page.mdx
16844
+ $ anymorph validate mdx "content/**/*.mdx"
16845
+ $ anymorph validate mdx content --json`
16846
+ ).action(
16847
+ (paths, opts, command) => geoValidateMdxCommand(paths, {
16848
+ json: opts.json || Boolean(command.parent?.opts().json)
16849
+ })
16850
+ )
16758
16851
  );
16852
+ commands.push(validateCommand);
16759
16853
  commands.push(
16760
16854
  new Command("intents").argument("<runId>").description("Show the pre-fetched intents for a local GEO strategy run").option("--json", "Output as JSON").addHelpText(
16761
16855
  "after",
@@ -16882,7 +16976,9 @@ async function geoPrepareCommand(workspaceId, opts) {
16882
16976
  console.log(source_default.bold(" Next:"));
16883
16977
  console.log(source_default.dim(" codex"));
16884
16978
  console.log(source_default.dim(` anymorph validate ${pkg.runId}`));
16885
- console.log(source_default.dim(` anymorph submit ${pkg.runId}`));
16979
+ console.log(source_default.dim(" git add agent/runs content"));
16980
+ console.log(source_default.dim(` git commit -m "chore(geo): publish run ${pkg.runId}"`));
16981
+ console.log(source_default.dim(" git push"));
16886
16982
  console.log();
16887
16983
  }
16888
16984
  async function geoValidateCommand(runId, opts) {
@@ -16909,80 +17005,96 @@ async function geoValidateCommand(runId, opts) {
16909
17005
  console.error();
16910
17006
  process.exit(1);
16911
17007
  }
16912
- async function geoSubmitCommand(runId, opts) {
17008
+ async function geoValidateMdxCommand(paths, opts) {
17009
+ const json = opts.json || paths.includes("--json");
17010
+ const cleanPaths = paths.filter((path2) => path2 !== "--json");
16913
17011
  const repoPath = await resolveCurrentRepoRoot();
16914
- const validation = await validateGeoRunArtifacts({ repoPath, runId });
16915
- if (!validation.ok) {
16916
- if (opts.json) {
16917
- console.log(JSON.stringify({ ...validation, repoPath }, null, 2));
16918
- process.exit(1);
16919
- }
16920
- console.error(source_default.red(`
16921
- GEO run ${runId} is not valid
17012
+ const files = await resolveMdxInputFiles(repoPath, cleanPaths);
17013
+ const results = await Promise.all(
17014
+ files.map(async (file) => {
17015
+ const mdx = await readFile3(file, "utf8");
17016
+ const issues = validateCmsMdxComponentContracts(mdx);
17017
+ return {
17018
+ file: relative2(repoPath, file),
17019
+ ok: issues.length === 0,
17020
+ issues
17021
+ };
17022
+ })
17023
+ );
17024
+ const ok = results.every((result) => result.ok);
17025
+ if (json) {
17026
+ console.log(JSON.stringify({ ok, repoPath, files: results }, null, 2));
17027
+ process.exit(ok ? 0 : 1);
17028
+ }
17029
+ if (ok) {
17030
+ console.log(source_default.green(`
17031
+ ${results.length} CMS MDX file${results.length === 1 ? "" : "s"} valid.
16922
17032
  `));
16923
- for (const error of validation.errors) console.error(` - ${error}`);
16924
- console.error();
16925
- process.exit(1);
17033
+ return;
16926
17034
  }
16927
- const runDir = join6(repoPath, "agent", "runs", runId);
16928
- const [context, manifest] = await Promise.all([
16929
- readJsonRecord(join6(runDir, "context.json")),
16930
- readJsonRecord(join6(runDir, "manifest.json"))
16931
- ]);
16932
- const workspace = opts.workspace ?? stringValue(context.workspaceId) ?? stringValue(manifest.workspaceId) ?? stringValue(context.workspaceDomain) ?? stringValue(manifest.workspaceDomain);
16933
- if (!workspace) {
16934
- console.error(source_default.red("Could not infer workspace. Pass --workspace <workspaceId>."));
16935
- process.exit(1);
17035
+ console.error(source_default.red("\n MDX validation failed\n"));
17036
+ for (const result of results.filter((item) => !item.ok)) {
17037
+ console.error(` ${source_default.bold(result.file)}`);
17038
+ for (const issue of result.issues) console.error(` - ${issue.message}`);
16936
17039
  }
16937
- const git = await gitInfo(repoPath);
16938
- const artifactPaths = normalizeSubmitArtifactPaths(
16939
- runId,
16940
- manifest.allowedArtifactPaths
16941
- );
16942
- const body = parseCliRequest(
16943
- CliGeoSubmitRequestSchema,
16944
- {
16945
- workspace,
16946
- commitSha: git.headSha,
16947
- artifactPaths,
16948
- mode: context.mode ?? manifest.mode,
16949
- signalsSnapshot: {
16950
- runId,
16951
- source: "local-skillpack",
16952
- mode: context.mode ?? manifest.mode ?? null,
16953
- signals: context.signals ?? null
16954
- },
16955
- systemContext: context.systemContext ?? null
16956
- },
16957
- "Invalid GEO submit request"
16958
- );
16959
- const res = await apiRequest(
16960
- "POST",
16961
- `/api/cli/geo-strategy/runs/${encodeURIComponent(runId)}/submit`,
16962
- body
16963
- );
16964
- if (!res.ok) {
16965
- await printApiFailure(res, "Couldn't submit GEO strategy run", {
16966
- method: "POST",
16967
- path: `/api/cli/geo-strategy/runs/${encodeURIComponent(runId)}/submit`
16968
- });
16969
- process.exit(1);
17040
+ console.error();
17041
+ process.exit(1);
17042
+ }
17043
+ async function resolveMdxInputFiles(repoPath, inputs) {
17044
+ const files = /* @__PURE__ */ new Set();
17045
+ for (const input of inputs) {
17046
+ const matches = await expandMdxInput(repoPath, input);
17047
+ for (const file of matches) files.add(file);
16970
17048
  }
16971
- const payload = parseCliResponse(
16972
- CliGeoSubmitResponseSchema,
16973
- await res.json(),
16974
- "Invalid GEO submit response from backend"
16975
- );
16976
- if (opts.json) {
16977
- console.log(JSON.stringify({ ...payload, repoPath }, null, 2));
16978
- return;
17049
+ if (files.size === 0) {
17050
+ throw new Error("No MDX files matched.");
16979
17051
  }
16980
- console.log();
16981
- console.log(source_default.green.bold(` Submitted GEO run ${runId}`));
16982
- console.log(` ${source_default.bold("Workspace:")} ${workspace}`);
16983
- console.log(` ${source_default.bold("Status:")} ${payload.status}`);
16984
- if (payload.commitSha) console.log(` ${source_default.bold("Commit:")} ${payload.commitSha}`);
16985
- console.log();
17052
+ return [...files].sort();
17053
+ }
17054
+ async function expandMdxInput(repoPath, input) {
17055
+ if (input.includes("*")) return expandSimpleMdxGlob(repoPath, input);
17056
+ const absolute = resolve3(repoPath, input);
17057
+ const info = await stat4(absolute);
17058
+ if (info.isDirectory()) return walkMdxFiles(absolute);
17059
+ if (info.isFile() && absolute.endsWith(".mdx")) return [absolute];
17060
+ return [];
17061
+ }
17062
+ async function expandSimpleMdxGlob(repoPath, pattern) {
17063
+ const normalized = pattern.replaceAll("\\", "/");
17064
+ const prefix = normalized.split("*", 1)[0].replace(/[^/]*$/, "");
17065
+ const base = resolve3(repoPath, prefix || ".");
17066
+ const candidates = await walkMdxFiles(base);
17067
+ const regex2 = globToRegExp(normalized);
17068
+ return candidates.filter((file) => regex2.test(relative2(repoPath, file).replaceAll("\\", "/")));
17069
+ }
17070
+ async function walkMdxFiles(dir) {
17071
+ const entries = await readdir3(dir, { withFileTypes: true });
17072
+ const files = [];
17073
+ for (const entry of entries) {
17074
+ const path2 = join6(dir, entry.name);
17075
+ if (entry.isDirectory()) {
17076
+ files.push(...await walkMdxFiles(path2));
17077
+ } else if (entry.isFile() && entry.name.endsWith(".mdx")) {
17078
+ files.push(path2);
17079
+ }
17080
+ }
17081
+ return files;
17082
+ }
17083
+ function globToRegExp(pattern) {
17084
+ let source = "";
17085
+ for (let i = 0; i < pattern.length; i += 1) {
17086
+ const char = pattern[i];
17087
+ const next = pattern[i + 1];
17088
+ if (char === "*" && next === "*") {
17089
+ source += ".*";
17090
+ i += 1;
17091
+ } else if (char === "*") {
17092
+ source += "[^/]*";
17093
+ } else {
17094
+ source += char.replace(/[.+?^${}()|[\]\\]/g, "\\$&");
17095
+ }
17096
+ }
17097
+ return new RegExp(`^${source}$`);
16986
17098
  }
16987
17099
  async function geoIntentsCommand(runId, opts) {
16988
17100
  const repoPath = await resolveCurrentRepoRoot();
@@ -17081,14 +17193,6 @@ async function readGeoIntentList(runDir) {
17081
17193
  };
17082
17194
  }
17083
17195
  }
17084
- async function readJsonRecord(path2) {
17085
- const raw = await readFile3(path2, "utf8");
17086
- const parsed = JSON.parse(raw);
17087
- if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) {
17088
- throw new Error(`${path2} must contain a JSON object`);
17089
- }
17090
- return parsed;
17091
- }
17092
17196
  function stringValue(value) {
17093
17197
  return typeof value === "string" && value.length > 0 ? value : null;
17094
17198
  }
@@ -17149,14 +17253,14 @@ function printScaffoldError(prefix, err) {
17149
17253
 
17150
17254
  // src/index.ts
17151
17255
  var program2 = new Command();
17152
- program2.name("anymorph").description("Check AI visibility and run local GEO strategy workflows").version("0.6.0");
17256
+ program2.name("anymorph").description("Check AI visibility and run local GEO strategy workflows").version("0.7.0");
17153
17257
  program2.command("login").description("Sign in to your Anymorph account").addHelpText(
17154
17258
  "after",
17155
17259
  `
17156
17260
  Examples:
17157
17261
  $ anymorph login
17158
17262
 
17159
- Use this before authenticated commands such as workspaces, prepare, and submit.`
17263
+ Use this before authenticated commands such as workspaces and prepare.`
17160
17264
  ).action(loginCommand);
17161
17265
  program2.command("check <domain>").description("Run an AI visibility check for a domain").option("--json", "Output as JSON").addHelpText(
17162
17266
  "after",
@@ -17226,15 +17330,15 @@ Command usage:
17226
17330
  Must be run from the tenant repo root.
17227
17331
 
17228
17332
  anymorph validate <runId> [--json]
17229
- Validate local run files and actions.json before submit.
17333
+ Validate local run files and actions.json before pushing.
17230
17334
  Must be run from the tenant repo root.
17231
17335
 
17232
- anymorph submit <runId> [--workspace <workspaceId>] [--json]
17233
- Submit a validated, pushed local GEO run to Anymorph.
17336
+ anymorph validate mdx <paths...> [--json]
17337
+ Validate CMS MDX component contracts such as Callout tone values.
17234
17338
  Must be run from the tenant repo root.
17235
17339
 
17236
17340
  anymorph run-status <runId> [--json]
17237
- Show backend status for a submitted GEO run.
17341
+ Show backend sync status for a pushed GEO run.
17238
17342
 
17239
17343
  Use "anymorph <command> --help" for examples and option details.`
17240
17344
  );
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "anymorph",
3
- "version": "0.6.0",
3
+ "version": "0.7.0",
4
4
  "description": "Check your brand's AI visibility across ChatGPT, Perplexity, Gemini, and more",
5
5
  "type": "module",
6
6
  "private": false,