anymorph 0.12.0 → 0.13.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 +3 -3
  2. package/dist/index.js +245 -37
  3. package/package.json +1 -1
package/README.md CHANGED
@@ -189,9 +189,9 @@ anymorph validate 20260517T074200Z
189
189
  ```
190
190
 
191
191
  Validation does not update the backend. Backend sync happens from the tenant
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.
192
+ repo GitHub webhook after `agent/runs/{runId}/{channel}/actions.json` is pushed
193
+ to `main`. Any generated `content/*.mdx` files are materialized as CMS pages
194
+ from the same webhook path.
195
195
 
196
196
  ## How It Works
197
197
 
package/dist/index.js CHANGED
@@ -12541,6 +12541,26 @@ var require_src = __commonJS({
12541
12541
  policy: GeoStrategyPolicyVersionSchema2,
12542
12542
  actions: z.array(GeoStrategyActionSchema2).max(20)
12543
12543
  }).strict();
12544
+ var GeoStrategyActionChannelSchema2 = z.enum(["brand_owned", "geo_pages", "third_party"]);
12545
+ var GEO_STRATEGY_CHANNEL_ASSET_TYPE2 = Object.freeze({
12546
+ brand_owned: "brand_owned",
12547
+ geo_pages: "geo_page",
12548
+ third_party: "third_party"
12549
+ });
12550
+ var GeoStrategyChannelActionsArtifactSchema2 = GeoStrategyActionsArtifactSchema2.extend({
12551
+ channel: GeoStrategyActionChannelSchema2
12552
+ }).strict().superRefine((artifact, ctx) => {
12553
+ const expectedAssetType = GEO_STRATEGY_CHANNEL_ASSET_TYPE2[artifact.channel];
12554
+ artifact.actions.forEach((action, index2) => {
12555
+ if (action.assetType !== expectedAssetType) {
12556
+ ctx.addIssue({
12557
+ code: z.ZodIssueCode.custom,
12558
+ path: ["actions", index2, "assetType"],
12559
+ message: `assetType must be ${expectedAssetType} for ${artifact.channel} channel artifacts`
12560
+ });
12561
+ }
12562
+ });
12563
+ });
12544
12564
  var GeoStrategyActionsArtifactJsonSchema2 = {
12545
12565
  $schema: "https://json-schema.org/draft/2020-12/schema",
12546
12566
  title: "GeoStrategyActions",
@@ -12665,6 +12685,71 @@ var require_src = __commonJS({
12665
12685
  }
12666
12686
  }
12667
12687
  };
12688
+ function geoStrategyChannelActionsArtifactJsonSchema(channel) {
12689
+ const assetType = GEO_STRATEGY_CHANNEL_ASSET_TYPE2[channel];
12690
+ return {
12691
+ ...GeoStrategyActionsArtifactJsonSchema2,
12692
+ title: `GeoStrategy${channel}Actions`,
12693
+ required: ["schemaVersion", "runId", "channel", "policy", "actions"],
12694
+ properties: {
12695
+ ...GeoStrategyActionsArtifactJsonSchema2.properties,
12696
+ channel: { const: channel },
12697
+ actions: {
12698
+ ...GeoStrategyActionsArtifactJsonSchema2.properties.actions,
12699
+ items: {
12700
+ ...GeoStrategyActionsArtifactJsonSchema2.properties.actions.items,
12701
+ properties: {
12702
+ ...GeoStrategyActionsArtifactJsonSchema2.properties.actions.items.properties,
12703
+ assetType: { const: assetType }
12704
+ }
12705
+ }
12706
+ }
12707
+ }
12708
+ };
12709
+ }
12710
+ var GeoStrategyChannelActionsArtifactJsonSchemas2 = Object.freeze({
12711
+ brand_owned: geoStrategyChannelActionsArtifactJsonSchema("brand_owned"),
12712
+ geo_pages: geoStrategyChannelActionsArtifactJsonSchema("geo_pages"),
12713
+ third_party: geoStrategyChannelActionsArtifactJsonSchema("third_party")
12714
+ });
12715
+ var GeoStrategyMemoryItemJsonSchema2 = {
12716
+ $schema: "https://json-schema.org/draft/2020-12/schema",
12717
+ title: "GeoStrategyMemoryItem",
12718
+ type: "object",
12719
+ required: ["id", "runId", "type", "title", "content", "createdAt"],
12720
+ additionalProperties: false,
12721
+ properties: {
12722
+ id: { type: "string", pattern: "^[0-9a-z]{5}-[a-z0-9][a-z0-9-]*$" },
12723
+ runId: { type: "string", minLength: 1 },
12724
+ type: {
12725
+ type: "string",
12726
+ enum: ["observation", "evidence", "competitor", "query", "hypothesis"]
12727
+ },
12728
+ title: { type: "string", minLength: 1 },
12729
+ content: { type: "string", minLength: 1 },
12730
+ sources: { type: "array", items: { type: "string" }, default: [] },
12731
+ tags: { type: "array", items: { type: "string" }, default: [] },
12732
+ createdAt: { type: "string", format: "date-time" }
12733
+ }
12734
+ };
12735
+ var GeoStrategyRunContextJsonSchema2 = {
12736
+ $schema: "https://json-schema.org/draft/2020-12/schema",
12737
+ title: "GeoStrategyRunContext",
12738
+ type: "object",
12739
+ required: ["runId", "mode", "workspaceDomain", "workspaceId", "signals"],
12740
+ additionalProperties: true,
12741
+ properties: {
12742
+ runId: { type: "string", minLength: 1 },
12743
+ mode: { type: "string", enum: ["bootstrap", "normal"] },
12744
+ workspaceDomain: { type: "string", minLength: 1 },
12745
+ workspaceId: { type: "string", minLength: 1 },
12746
+ tenantRepo: { type: "object" },
12747
+ branch: { type: "string" },
12748
+ signals: { type: "object" },
12749
+ systemContext: { type: "object" },
12750
+ intentsPath: { type: "string" }
12751
+ }
12752
+ };
12668
12753
  var LegacyGeoStrategyActionsArtifactSchema = z.union([
12669
12754
  z.array(GeoStrategyActionSchema2),
12670
12755
  z.object({
@@ -13074,6 +13159,14 @@ var require_src = __commonJS({
13074
13159
  policy: null
13075
13160
  };
13076
13161
  }
13162
+ function parseGeoStrategyChannelActionsArtifactWithMetadata2(raw) {
13163
+ const parsed = GeoStrategyChannelActionsArtifactSchema2.parse(raw);
13164
+ return {
13165
+ channel: parsed.channel,
13166
+ actions: parsed.actions,
13167
+ policy: parsed.policy
13168
+ };
13169
+ }
13077
13170
  function allowedGeoStrategyArtifactPaths2(runId) {
13078
13171
  return [
13079
13172
  `agent/runs/${runId}/context.json`,
@@ -13081,12 +13174,13 @@ var require_src = __commonJS({
13081
13174
  `agent/runs/${runId}/policy.json`,
13082
13175
  `agent/runs/${runId}/intents.json`,
13083
13176
  `agent/runs/${runId}/crawl_logs.json`,
13084
- `agent/runs/${runId}/subagents/brand_owned.json`,
13085
- `agent/runs/${runId}/subagents/brand_owned.rationale.md`,
13086
- `agent/runs/${runId}/subagents/geo_pages.json`,
13087
- `agent/runs/${runId}/subagents/geo_pages.rationale.md`,
13088
- `agent/runs/${runId}/subagents/third_party.json`,
13089
- `agent/runs/${runId}/subagents/third_party.rationale.md`,
13177
+ `agent/runs/${runId}/brand_owned/actions.json`,
13178
+ `agent/runs/${runId}/brand_owned/rationale.md`,
13179
+ `agent/runs/${runId}/geo_pages/actions.json`,
13180
+ `agent/runs/${runId}/geo_pages/rationale.md`,
13181
+ `agent/runs/${runId}/third_party/actions.json`,
13182
+ `agent/runs/${runId}/third_party/actions_enriched.json`,
13183
+ `agent/runs/${runId}/third_party/rationale.md`,
13090
13184
  `agent/runs/${runId}/actions.json`,
13091
13185
  `agent/runs/${runId}/rationale.md`,
13092
13186
  `agent/runs/${runId}/status.json`,
@@ -13424,6 +13518,12 @@ var require_src = __commonJS({
13424
13518
  GeoStrategyPolicyVersionSchema: GeoStrategyPolicyVersionSchema2,
13425
13519
  GeoStrategyActionsArtifactSchema: GeoStrategyActionsArtifactSchema2,
13426
13520
  GeoStrategyActionsArtifactJsonSchema: GeoStrategyActionsArtifactJsonSchema2,
13521
+ GeoStrategyActionChannelSchema: GeoStrategyActionChannelSchema2,
13522
+ GEO_STRATEGY_CHANNEL_ASSET_TYPE: GEO_STRATEGY_CHANNEL_ASSET_TYPE2,
13523
+ GeoStrategyChannelActionsArtifactSchema: GeoStrategyChannelActionsArtifactSchema2,
13524
+ GeoStrategyChannelActionsArtifactJsonSchemas: GeoStrategyChannelActionsArtifactJsonSchemas2,
13525
+ GeoStrategyMemoryItemJsonSchema: GeoStrategyMemoryItemJsonSchema2,
13526
+ GeoStrategyRunContextJsonSchema: GeoStrategyRunContextJsonSchema2,
13427
13527
  GeoStrategyAgentOutputSchema: GeoStrategyAgentOutputSchema2,
13428
13528
  GeoStrategySubagentArtifactSchema: GeoStrategySubagentArtifactSchema2,
13429
13529
  GeoStrategyActionsArtifactSubmitSchema: GeoStrategyActionsArtifactSubmitSchema2,
@@ -13450,6 +13550,7 @@ var require_src = __commonJS({
13450
13550
  StrategyMapEvidenceSchema: StrategyMapEvidenceSchema2,
13451
13551
  parseGeoStrategyActionsArtifact: parseGeoStrategyActionsArtifact2,
13452
13552
  parseGeoStrategyActionsArtifactWithMetadata: parseGeoStrategyActionsArtifactWithMetadata2,
13553
+ parseGeoStrategyChannelActionsArtifactWithMetadata: parseGeoStrategyChannelActionsArtifactWithMetadata2,
13453
13554
  allowedGeoStrategyArtifactPaths: allowedGeoStrategyArtifactPaths2,
13454
13555
  allowedStrategyMapArtifactPaths: allowedStrategyMapArtifactPaths2,
13455
13556
  formatGeoStrategyActionsArtifactContract: formatGeoStrategyActionsArtifactContract2,
@@ -22437,6 +22538,12 @@ var GeoStrategyActionSchema = import_index2.default.GeoStrategyActionSchema;
22437
22538
  var GeoStrategyPolicyVersionSchema = import_index2.default.GeoStrategyPolicyVersionSchema;
22438
22539
  var GeoStrategyActionsArtifactSchema = import_index2.default.GeoStrategyActionsArtifactSchema;
22439
22540
  var GeoStrategyActionsArtifactJsonSchema = import_index2.default.GeoStrategyActionsArtifactJsonSchema;
22541
+ var GeoStrategyActionChannelSchema = import_index2.default.GeoStrategyActionChannelSchema;
22542
+ var GEO_STRATEGY_CHANNEL_ASSET_TYPE = import_index2.default.GEO_STRATEGY_CHANNEL_ASSET_TYPE;
22543
+ var GeoStrategyChannelActionsArtifactSchema = import_index2.default.GeoStrategyChannelActionsArtifactSchema;
22544
+ var GeoStrategyChannelActionsArtifactJsonSchemas = import_index2.default.GeoStrategyChannelActionsArtifactJsonSchemas;
22545
+ var GeoStrategyMemoryItemJsonSchema = import_index2.default.GeoStrategyMemoryItemJsonSchema;
22546
+ var GeoStrategyRunContextJsonSchema = import_index2.default.GeoStrategyRunContextJsonSchema;
22440
22547
  var GeoStrategyAgentOutputSchema = import_index2.default.GeoStrategyAgentOutputSchema;
22441
22548
  var GeoStrategySubagentArtifactSchema = import_index2.default.GeoStrategySubagentArtifactSchema;
22442
22549
  var GeoStrategyActionsArtifactSubmitSchema = import_index2.default.GeoStrategyActionsArtifactSubmitSchema;
@@ -22463,6 +22570,7 @@ var StrategyMapStrategySchema = import_index2.default.StrategyMapStrategySchema;
22463
22570
  var StrategyMapEvidenceSchema = import_index2.default.StrategyMapEvidenceSchema;
22464
22571
  var parseGeoStrategyActionsArtifact = import_index2.default.parseGeoStrategyActionsArtifact;
22465
22572
  var parseGeoStrategyActionsArtifactWithMetadata = import_index2.default.parseGeoStrategyActionsArtifactWithMetadata;
22573
+ var parseGeoStrategyChannelActionsArtifactWithMetadata = import_index2.default.parseGeoStrategyChannelActionsArtifactWithMetadata;
22466
22574
  var allowedGeoStrategyArtifactPaths = import_index2.default.allowedGeoStrategyArtifactPaths;
22467
22575
  var allowedStrategyMapArtifactPaths = import_index2.default.allowedStrategyMapArtifactPaths;
22468
22576
  var formatGeoStrategyActionsArtifactContract = import_index2.default.formatGeoStrategyActionsArtifactContract;
@@ -45588,13 +45696,27 @@ async function syncContracts(repoPath, changed) {
45588
45696
  await mkdir3(contractsDir, { recursive: true });
45589
45697
  await writeIfChanged(
45590
45698
  join4(contractsDir, "actions.schema.json"),
45591
- `${JSON.stringify(ACTIONS_SCHEMA, null, 2)}
45699
+ `${JSON.stringify(GeoStrategyActionsArtifactJsonSchema, null, 2)}
45592
45700
  `,
45593
45701
  changed
45594
45702
  );
45703
+ for (const [channel, schema] of Object.entries(GeoStrategyChannelActionsArtifactJsonSchemas)) {
45704
+ await writeIfChanged(
45705
+ join4(contractsDir, `${channel}.actions.schema.json`),
45706
+ `${JSON.stringify(schema, null, 2)}
45707
+ `,
45708
+ changed
45709
+ );
45710
+ }
45595
45711
  await writeIfChanged(
45596
45712
  join4(contractsDir, "memory-item.schema.json"),
45597
- `${JSON.stringify(MEMORY_ITEM_SCHEMA, null, 2)}
45713
+ `${JSON.stringify(GeoStrategyMemoryItemJsonSchema, null, 2)}
45714
+ `,
45715
+ changed
45716
+ );
45717
+ await writeIfChanged(
45718
+ join4(contractsDir, "run-context.schema.json"),
45719
+ `${JSON.stringify(GeoStrategyRunContextJsonSchema, null, 2)}
45598
45720
  `,
45599
45721
  changed
45600
45722
  );
@@ -45844,31 +45966,11 @@ async function isDirectory(path2) {
45844
45966
  async function exists2(path2) {
45845
45967
  return stat2(path2).then(() => true).catch(() => false);
45846
45968
  }
45847
- var ACTIONS_SCHEMA = {
45848
- $schema: "https://json-schema.org/draft/2020-12/schema",
45849
- title: "Anymorph GEO actions artifact",
45850
- type: "object",
45851
- required: ["runId", "actions"],
45852
- properties: {
45853
- runId: { type: "string" },
45854
- actions: { type: "array", items: { type: "object" } },
45855
- artifactPaths: { type: "array", items: { type: "string" } }
45856
- }
45857
- };
45858
- var MEMORY_ITEM_SCHEMA = {
45859
- $schema: "https://json-schema.org/draft/2020-12/schema",
45860
- title: "Anymorph GEO memory item",
45861
- type: "object",
45862
- required: ["summary"],
45863
- properties: {
45864
- summary: { type: "string" },
45865
- evidence: { type: "array", items: { type: "string" } }
45866
- }
45867
- };
45868
45969
 
45869
45970
  // src/geo/validate.ts
45870
45971
  import { readFile as readFile2, stat as stat3 } from "node:fs/promises";
45871
45972
  import { join as join5 } from "node:path";
45973
+ var CHANNELS = ["brand_owned", "geo_pages", "third_party"];
45872
45974
  async function validateGeoRunArtifacts(input) {
45873
45975
  const runDir = join5(input.repoPath, "agent", "runs", input.runId);
45874
45976
  const errors = [];
@@ -45886,8 +45988,15 @@ async function validateGeoRunArtifacts(input) {
45886
45988
  errors.push(`Missing agent/runs/${input.runId}/${file}`);
45887
45989
  }
45888
45990
  }
45889
- if (!await exists3(join5(runDir, "actions.json"))) {
45890
- errors.push(`Missing agent/runs/${input.runId}/actions.json`);
45991
+ const hasRootActions = await exists3(join5(runDir, "actions.json"));
45992
+ const presentChannels = [];
45993
+ for (const channel of CHANNELS) {
45994
+ if (await exists3(join5(runDir, channel, "actions.json"))) presentChannels.push(channel);
45995
+ }
45996
+ if (!hasRootActions && presentChannels.length === 0) {
45997
+ errors.push(
45998
+ `Missing GEO actions artifact. Write agent/runs/${input.runId}/{brand_owned|geo_pages|third_party}/actions.json`
45999
+ );
45891
46000
  }
45892
46001
  if (!await exists3(join5(runDir, "rationale.md"))) {
45893
46002
  errors.push(`Missing agent/runs/${input.runId}/rationale.md`);
@@ -45897,7 +46006,7 @@ async function validateGeoRunArtifacts(input) {
45897
46006
  const policy = await readJson2(join5(runDir, "policy.json"), errors);
45898
46007
  const products = await readJson2(join5(runDir, "products.json"), errors);
45899
46008
  const status = await readJson2(join5(runDir, "status.json"), errors);
45900
- const actions = await readJson2(join5(runDir, "actions.json"), errors);
46009
+ const actions = hasRootActions ? await readJson2(join5(runDir, "actions.json"), errors) : null;
45901
46010
  if (isRecord2(manifest)) validateManifest(manifest, input.runId, errors);
45902
46011
  if (isRecord2(status)) validateStatus(status, errors);
45903
46012
  if (isRecord2(actions)) {
@@ -45912,6 +46021,56 @@ async function validateGeoRunArtifacts(input) {
45912
46021
  errors
45913
46022
  );
45914
46023
  }
46024
+ for (const channel of presentChannels) {
46025
+ const channelActions = await readJson2(join5(runDir, channel, "actions.json"), errors);
46026
+ if (isRecord2(channelActions)) {
46027
+ validateActionsArtifact(
46028
+ channelActions,
46029
+ {
46030
+ runId: input.runId,
46031
+ policy,
46032
+ isCommerce: isCommerceRun(context, products),
46033
+ productIds: collectProductIds(products),
46034
+ channel
46035
+ },
46036
+ errors
46037
+ );
46038
+ }
46039
+ if (!await exists3(join5(runDir, channel, "rationale.md"))) {
46040
+ errors.push(`Missing agent/runs/${input.runId}/${channel}/rationale.md`);
46041
+ }
46042
+ }
46043
+ return {
46044
+ ok: errors.length === 0,
46045
+ errors,
46046
+ warnings: [],
46047
+ runDir
46048
+ };
46049
+ }
46050
+ async function validateGeoChannelArtifacts(input) {
46051
+ const runDir = join5(input.repoPath, "agent", "runs", input.runId);
46052
+ const errors = [];
46053
+ const context = await readJson2(join5(runDir, "context.json"), errors);
46054
+ const policy = await readJson2(join5(runDir, "policy.json"), errors);
46055
+ const products = await readJson2(join5(runDir, "products.json"), errors);
46056
+ const actionsPath = join5(runDir, input.channel, "actions.json");
46057
+ const actions = await readJson2(actionsPath, errors);
46058
+ if (!await exists3(join5(runDir, input.channel, "rationale.md"))) {
46059
+ errors.push(`Missing agent/runs/${input.runId}/${input.channel}/rationale.md`);
46060
+ }
46061
+ if (isRecord2(actions)) {
46062
+ validateActionsArtifact(
46063
+ actions,
46064
+ {
46065
+ runId: input.runId,
46066
+ policy,
46067
+ isCommerce: isCommerceRun(context, products),
46068
+ productIds: collectProductIds(products),
46069
+ channel: input.channel
46070
+ },
46071
+ errors
46072
+ );
46073
+ }
45915
46074
  return {
45916
46075
  ok: errors.length === 0,
45917
46076
  errors,
@@ -45944,7 +46103,7 @@ function validateManifest(value, runId, errors) {
45944
46103
  }
45945
46104
  }
45946
46105
  function validateActionsArtifact(artifact, context, errors) {
45947
- const parsed = GeoStrategyActionsArtifactSchema.safeParse(artifact);
46106
+ const parsed = context.channel ? GeoStrategyChannelActionsArtifactSchema.safeParse(artifact) : GeoStrategyActionsArtifactSchema.safeParse(artifact);
45948
46107
  if (!parsed.success) {
45949
46108
  for (const issue of parsed.error.issues) {
45950
46109
  errors.push(
@@ -45955,10 +46114,13 @@ function validateActionsArtifact(artifact, context, errors) {
45955
46114
  }
45956
46115
  rejectExtraKeys(
45957
46116
  artifact,
45958
- ["schemaVersion", "runId", "policy", "actions"],
46117
+ context.channel ? ["schemaVersion", "runId", "channel", "policy", "actions"] : ["schemaVersion", "runId", "policy", "actions"],
45959
46118
  "actions.json",
45960
46119
  errors
45961
46120
  );
46121
+ if (context.channel && artifact.channel !== context.channel) {
46122
+ errors.push(`actions.json channel must be ${context.channel}`);
46123
+ }
45962
46124
  if (artifact.schemaVersion !== 1) errors.push("actions.json schemaVersion must be 1");
45963
46125
  if (artifact.runId !== context.runId) {
45964
46126
  errors.push(`actions.json runId must match ${context.runId}`);
@@ -46023,6 +46185,12 @@ function validateActionItem(action, index2, context, seen, errors) {
46023
46185
  if (!["brand_owned", "geo_page", "third_party"].includes(String(action.assetType))) {
46024
46186
  errors.push(`${path2}.assetType must be brand_owned, geo_page, or third_party`);
46025
46187
  }
46188
+ if (context.channel) {
46189
+ const expectedAssetType = context.channel === "geo_pages" ? "geo_page" : context.channel;
46190
+ if (action.assetType !== expectedAssetType) {
46191
+ errors.push(`${path2}.assetType must be ${expectedAssetType} for ${context.channel}`);
46192
+ }
46193
+ }
46026
46194
  validateIntentRef(action, path2, errors);
46027
46195
  validateActionFields(action, path2, errors);
46028
46196
  validateActionByType(action, path2, context, errors);
@@ -46271,11 +46439,14 @@ Examples:
46271
46439
  $ anymorph validate 20260517T074200Z
46272
46440
  $ anymorph validate run 20260517T074200Z
46273
46441
  $ anymorph validate actions 20260517T074200Z
46442
+ $ anymorph validate brand-owned 20260517T074200Z
46443
+ $ anymorph validate geo-pages 20260517T074200Z
46444
+ $ anymorph validate third-party 20260517T074200Z
46274
46445
  $ anymorph validate mdx content/guide/page.mdx
46275
46446
  $ anymorph validate mdx "content/**/*.mdx"
46276
46447
  $ anymorph validate 20260517T074200Z --json
46277
46448
 
46278
- Checks required run files, the shared actions.json contract, policy hash,
46449
+ Checks required run files, shared root/channel actions.json contracts, policy hash,
46279
46450
  per-asset target rules, commerce targetProductIds, or CMS renderer MDX validation.`
46280
46451
  ).action(async (runId, opts) => {
46281
46452
  if (!runId) {
@@ -46290,6 +46461,21 @@ per-asset target rules, commerce targetProductIds, or CMS renderer MDX validatio
46290
46461
  validateCommand.addCommand(
46291
46462
  new Command("actions").argument("<runId>").description("Validate actions.json and related local GEO run artifacts").option("--json", "Output as JSON").action(geoValidateCommand)
46292
46463
  );
46464
+ validateCommand.addCommand(
46465
+ new Command("brand-owned").argument("<runId>").description("Validate brand_owned/actions.json for a local GEO run").option("--json", "Output as JSON").action(
46466
+ (runId, opts) => geoValidateChannelCommand(runId, "brand_owned", opts)
46467
+ )
46468
+ );
46469
+ validateCommand.addCommand(
46470
+ new Command("geo-pages").argument("<runId>").description("Validate geo_pages/actions.json for a local GEO run").option("--json", "Output as JSON").action(
46471
+ (runId, opts) => geoValidateChannelCommand(runId, "geo_pages", opts)
46472
+ )
46473
+ );
46474
+ validateCommand.addCommand(
46475
+ new Command("third-party").argument("<runId>").description("Validate third_party/actions.json for a local GEO run").option("--json", "Output as JSON").action(
46476
+ (runId, opts) => geoValidateChannelCommand(runId, "third_party", opts)
46477
+ )
46478
+ );
46293
46479
  validateCommand.addCommand(
46294
46480
  new Command("mdx").argument("<paths...>").description("Validate CMS MDX with the renderer publish gate").option("--json", "Output as JSON").addHelpText(
46295
46481
  "after",
@@ -46460,6 +46646,24 @@ async function geoValidateCommand(runId, opts) {
46460
46646
  console.error();
46461
46647
  process.exit(1);
46462
46648
  }
46649
+ async function geoValidateChannelCommand(runId, channel, opts) {
46650
+ const repoPath = await resolveCurrentRepoRoot();
46651
+ const result = await validateGeoChannelArtifacts({ repoPath, runId, channel });
46652
+ if (opts.json) {
46653
+ console.log(JSON.stringify({ ...result, repoPath, channel }, null, 2));
46654
+ process.exit(result.ok ? 0 : 1);
46655
+ }
46656
+ if (result.ok) {
46657
+ console.log(source_default.green(`
46658
+ GEO ${channel} actions for ${runId} are valid.
46659
+ `));
46660
+ return;
46661
+ }
46662
+ console.error(source_default.red("\n Validation failed\n"));
46663
+ for (const error of result.errors) console.error(` - ${error}`);
46664
+ console.error();
46665
+ process.exit(1);
46666
+ }
46463
46667
  async function geoValidateMdxCommand(paths, opts) {
46464
46668
  const json = opts.json || paths.includes("--json");
46465
46669
  const cleanPaths = paths.filter((path2) => path2 !== "--json");
@@ -46719,7 +46923,7 @@ function printScaffoldError(prefix, err) {
46719
46923
 
46720
46924
  // src/index.ts
46721
46925
  var program2 = new Command();
46722
- program2.name("anymorph").description("Check AI visibility and run local GEO strategy workflows").version("0.12.0");
46926
+ program2.name("anymorph").description("Check AI visibility and run local GEO strategy workflows").version("0.13.0");
46723
46927
  program2.command("login").description("Sign in to your Anymorph account").addHelpText(
46724
46928
  "after",
46725
46929
  `
@@ -46796,7 +47000,11 @@ Command usage:
46796
47000
  Must be run from the tenant repo root.
46797
47001
 
46798
47002
  anymorph validate <runId> [--json]
46799
- Validate local run files and actions.json before pushing.
47003
+ Validate local run files and channel actions before pushing.
47004
+ Must be run from the tenant repo root.
47005
+
47006
+ anymorph validate brand-owned|geo-pages|third-party <runId> [--json]
47007
+ Validate one channel actions artifact before pushing.
46800
47008
  Must be run from the tenant repo root.
46801
47009
 
46802
47010
  anymorph validate mdx <paths...> [--json]
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "anymorph",
3
- "version": "0.12.0",
3
+ "version": "0.13.0",
4
4
  "description": "Check your brand's AI visibility across ChatGPT, Perplexity, Gemini, and more",
5
5
  "type": "module",
6
6
  "private": false,