anymorph 0.5.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.
- package/README.md +6 -16
- package/dist/index.js +218 -113
- 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
|
-
|
|
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
|
-
|
|
191
|
-
|
|
192
|
-
|
|
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("..")) {
|
|
@@ -12254,6 +12336,7 @@ var require_src = __commonJS({
|
|
|
12254
12336
|
generationMode: z.enum(["full", "lite"]).optional(),
|
|
12255
12337
|
tierMix: PromptGenTierMixSchema.optional(),
|
|
12256
12338
|
realizationMode: z.enum(["auto", "llm", "deterministic"]).optional(),
|
|
12339
|
+
brandProfile: z.record(z.string(), z.unknown()).optional(),
|
|
12257
12340
|
additionalContext: z.string().trim().min(1).max(2e4).optional(),
|
|
12258
12341
|
userRequest: z.string().trim().min(1).max(2e4).optional(),
|
|
12259
12342
|
async: z.boolean().optional(),
|
|
@@ -13342,7 +13425,9 @@ var require_src = __commonJS({
|
|
|
13342
13425
|
CMS_THEME_CONTRACT_TOKEN_KEYS: cmsThemeTokens.CMS_THEME_CONTRACT_TOKEN_KEYS,
|
|
13343
13426
|
CMS_THEME_STATUS_DEFAULTS: cmsThemeTokens.CMS_THEME_STATUS_DEFAULTS,
|
|
13344
13427
|
normalizeCmsThemeTokens: cmsThemeTokens.normalizeCmsThemeTokens,
|
|
13345
|
-
validateCmsThemeTokens: cmsThemeTokens.validateCmsThemeTokens
|
|
13428
|
+
validateCmsThemeTokens: cmsThemeTokens.validateCmsThemeTokens,
|
|
13429
|
+
CMS_MDX_COMPONENT_CONTRACTS: CMS_MDX_COMPONENT_CONTRACTS2,
|
|
13430
|
+
validateCmsMdxComponentContracts: validateCmsMdxComponentContracts2
|
|
13346
13431
|
};
|
|
13347
13432
|
}
|
|
13348
13433
|
});
|
|
@@ -13797,14 +13882,14 @@ var baseOpen = async (options) => {
|
|
|
13797
13882
|
}
|
|
13798
13883
|
const subprocess = childProcess.spawn(command, cliArguments, childProcessOptions);
|
|
13799
13884
|
if (options.wait) {
|
|
13800
|
-
return new Promise((
|
|
13885
|
+
return new Promise((resolve4, reject) => {
|
|
13801
13886
|
subprocess.once("error", reject);
|
|
13802
13887
|
subprocess.once("close", (exitCode) => {
|
|
13803
13888
|
if (!options.allowNonzeroExitCode && exitCode > 0) {
|
|
13804
13889
|
reject(new Error(`Exited with code ${exitCode}`));
|
|
13805
13890
|
return;
|
|
13806
13891
|
}
|
|
13807
|
-
|
|
13892
|
+
resolve4(subprocess);
|
|
13808
13893
|
});
|
|
13809
13894
|
});
|
|
13810
13895
|
}
|
|
@@ -15418,7 +15503,7 @@ async function loginCommand() {
|
|
|
15418
15503
|
process.exit(1);
|
|
15419
15504
|
}
|
|
15420
15505
|
function sleep(ms) {
|
|
15421
|
-
return new Promise((
|
|
15506
|
+
return new Promise((resolve4) => setTimeout(resolve4, ms));
|
|
15422
15507
|
}
|
|
15423
15508
|
|
|
15424
15509
|
// src/lib/display.ts
|
|
@@ -15548,7 +15633,7 @@ async function checkCommand(domain, opts) {
|
|
|
15548
15633
|
process.exit(1);
|
|
15549
15634
|
}
|
|
15550
15635
|
function sleep2(ms) {
|
|
15551
|
-
return new Promise((
|
|
15636
|
+
return new Promise((resolve4) => setTimeout(resolve4, ms));
|
|
15552
15637
|
}
|
|
15553
15638
|
|
|
15554
15639
|
// src/commands/status.ts
|
|
@@ -15674,6 +15759,8 @@ var CMS_THEME_CONTRACT_TOKEN_KEYS = import_index2.default.CMS_THEME_CONTRACT_TOK
|
|
|
15674
15759
|
var CMS_THEME_STATUS_DEFAULTS = import_index2.default.CMS_THEME_STATUS_DEFAULTS;
|
|
15675
15760
|
var normalizeCmsThemeTokens = import_index2.default.normalizeCmsThemeTokens;
|
|
15676
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;
|
|
15677
15764
|
var reasonTagSchema = import_index2.default.reasonTagSchema;
|
|
15678
15765
|
var reasonClassSchema = import_index2.default.reasonClassSchema;
|
|
15679
15766
|
var REASON_TAG_CLASS = import_index2.default.REASON_TAG_CLASS;
|
|
@@ -15683,8 +15770,8 @@ var priorDecisionSchema = import_index2.default.priorDecisionSchema;
|
|
|
15683
15770
|
var geoStrategyDecisionInputSchema = import_index2.default.geoStrategyDecisionInputSchema;
|
|
15684
15771
|
|
|
15685
15772
|
// src/commands/geo.ts
|
|
15686
|
-
import { readFile as readFile3 } from "node:fs/promises";
|
|
15687
|
-
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";
|
|
15688
15775
|
|
|
15689
15776
|
// src/geo/package-writer.ts
|
|
15690
15777
|
import { mkdir, writeFile } from "node:fs/promises";
|
|
@@ -16377,15 +16464,6 @@ async function validateGeoRunArtifacts(input) {
|
|
|
16377
16464
|
runDir
|
|
16378
16465
|
};
|
|
16379
16466
|
}
|
|
16380
|
-
function normalizeSubmitArtifactPaths(runId, paths) {
|
|
16381
|
-
const required = [
|
|
16382
|
-
`agent/runs/${runId}/actions.json`,
|
|
16383
|
-
`agent/runs/${runId}/rationale.md`,
|
|
16384
|
-
`agent/runs/${runId}/status.json`
|
|
16385
|
-
];
|
|
16386
|
-
const clean = Array.isArray(paths) ? paths.filter((path2) => hasText(path2)) : [];
|
|
16387
|
-
return Array.from(/* @__PURE__ */ new Set([...clean, ...required]));
|
|
16388
|
-
}
|
|
16389
16467
|
function validateManifest(value, runId, errors) {
|
|
16390
16468
|
if (value.schemaVersion !== 1) errors.push("manifest.json schemaVersion must be 1");
|
|
16391
16469
|
if (value.runId !== runId) errors.push(`manifest.json runId must match ${runId}`);
|
|
@@ -16731,30 +16809,47 @@ Run from the tenant repo root. Writes agent/runs/{runId}/ with manifest,
|
|
|
16731
16809
|
context, policy, intents, product catalog, crawl logs, and status files.`
|
|
16732
16810
|
).action(geoPrepareCommand)
|
|
16733
16811
|
);
|
|
16734
|
-
|
|
16735
|
-
|
|
16736
|
-
|
|
16737
|
-
`
|
|
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
|
+
`
|
|
16738
16815
|
Examples:
|
|
16739
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"
|
|
16740
16821
|
$ anymorph validate 20260517T074200Z --json
|
|
16741
16822
|
|
|
16742
16823
|
Checks required run files, the shared actions.json contract, policy hash,
|
|
16743
|
-
per-asset target rules,
|
|
16744
|
-
|
|
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)
|
|
16745
16834
|
);
|
|
16746
|
-
|
|
16747
|
-
new Command("
|
|
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(
|
|
16748
16840
|
"after",
|
|
16749
16841
|
`
|
|
16750
16842
|
Examples:
|
|
16751
|
-
$ anymorph
|
|
16752
|
-
$ anymorph
|
|
16753
|
-
|
|
16754
|
-
|
|
16755
|
-
|
|
16756
|
-
|
|
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
|
+
)
|
|
16757
16851
|
);
|
|
16852
|
+
commands.push(validateCommand);
|
|
16758
16853
|
commands.push(
|
|
16759
16854
|
new Command("intents").argument("<runId>").description("Show the pre-fetched intents for a local GEO strategy run").option("--json", "Output as JSON").addHelpText(
|
|
16760
16855
|
"after",
|
|
@@ -16881,7 +16976,9 @@ async function geoPrepareCommand(workspaceId, opts) {
|
|
|
16881
16976
|
console.log(source_default.bold(" Next:"));
|
|
16882
16977
|
console.log(source_default.dim(" codex"));
|
|
16883
16978
|
console.log(source_default.dim(` anymorph validate ${pkg.runId}`));
|
|
16884
|
-
console.log(source_default.dim(
|
|
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"));
|
|
16885
16982
|
console.log();
|
|
16886
16983
|
}
|
|
16887
16984
|
async function geoValidateCommand(runId, opts) {
|
|
@@ -16908,80 +17005,96 @@ async function geoValidateCommand(runId, opts) {
|
|
|
16908
17005
|
console.error();
|
|
16909
17006
|
process.exit(1);
|
|
16910
17007
|
}
|
|
16911
|
-
async function
|
|
17008
|
+
async function geoValidateMdxCommand(paths, opts) {
|
|
17009
|
+
const json = opts.json || paths.includes("--json");
|
|
17010
|
+
const cleanPaths = paths.filter((path2) => path2 !== "--json");
|
|
16912
17011
|
const repoPath = await resolveCurrentRepoRoot();
|
|
16913
|
-
const
|
|
16914
|
-
|
|
16915
|
-
|
|
16916
|
-
|
|
16917
|
-
|
|
16918
|
-
|
|
16919
|
-
|
|
16920
|
-
|
|
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.
|
|
16921
17032
|
`));
|
|
16922
|
-
|
|
16923
|
-
console.error();
|
|
16924
|
-
process.exit(1);
|
|
17033
|
+
return;
|
|
16925
17034
|
}
|
|
16926
|
-
|
|
16927
|
-
const
|
|
16928
|
-
|
|
16929
|
-
|
|
16930
|
-
]);
|
|
16931
|
-
const workspace = opts.workspace ?? stringValue(context.workspaceId) ?? stringValue(manifest.workspaceId) ?? stringValue(context.workspaceDomain) ?? stringValue(manifest.workspaceDomain);
|
|
16932
|
-
if (!workspace) {
|
|
16933
|
-
console.error(source_default.red("Could not infer workspace. Pass --workspace <workspaceId>."));
|
|
16934
|
-
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}`);
|
|
16935
17039
|
}
|
|
16936
|
-
|
|
16937
|
-
|
|
16938
|
-
|
|
16939
|
-
|
|
16940
|
-
);
|
|
16941
|
-
const
|
|
16942
|
-
|
|
16943
|
-
|
|
16944
|
-
workspace,
|
|
16945
|
-
commitSha: git.headSha,
|
|
16946
|
-
artifactPaths,
|
|
16947
|
-
mode: context.mode ?? manifest.mode,
|
|
16948
|
-
signalsSnapshot: {
|
|
16949
|
-
runId,
|
|
16950
|
-
source: "local-skillpack",
|
|
16951
|
-
mode: context.mode ?? manifest.mode ?? null,
|
|
16952
|
-
signals: context.signals ?? null
|
|
16953
|
-
},
|
|
16954
|
-
systemContext: context.systemContext ?? null
|
|
16955
|
-
},
|
|
16956
|
-
"Invalid GEO submit request"
|
|
16957
|
-
);
|
|
16958
|
-
const res = await apiRequest(
|
|
16959
|
-
"POST",
|
|
16960
|
-
`/api/cli/geo-strategy/runs/${encodeURIComponent(runId)}/submit`,
|
|
16961
|
-
body
|
|
16962
|
-
);
|
|
16963
|
-
if (!res.ok) {
|
|
16964
|
-
await printApiFailure(res, "Couldn't submit GEO strategy run", {
|
|
16965
|
-
method: "POST",
|
|
16966
|
-
path: `/api/cli/geo-strategy/runs/${encodeURIComponent(runId)}/submit`
|
|
16967
|
-
});
|
|
16968
|
-
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);
|
|
16969
17048
|
}
|
|
16970
|
-
|
|
16971
|
-
|
|
16972
|
-
await res.json(),
|
|
16973
|
-
"Invalid GEO submit response from backend"
|
|
16974
|
-
);
|
|
16975
|
-
if (opts.json) {
|
|
16976
|
-
console.log(JSON.stringify({ ...payload, repoPath }, null, 2));
|
|
16977
|
-
return;
|
|
17049
|
+
if (files.size === 0) {
|
|
17050
|
+
throw new Error("No MDX files matched.");
|
|
16978
17051
|
}
|
|
16979
|
-
|
|
16980
|
-
|
|
16981
|
-
|
|
16982
|
-
|
|
16983
|
-
|
|
16984
|
-
|
|
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}$`);
|
|
16985
17098
|
}
|
|
16986
17099
|
async function geoIntentsCommand(runId, opts) {
|
|
16987
17100
|
const repoPath = await resolveCurrentRepoRoot();
|
|
@@ -17080,14 +17193,6 @@ async function readGeoIntentList(runDir) {
|
|
|
17080
17193
|
};
|
|
17081
17194
|
}
|
|
17082
17195
|
}
|
|
17083
|
-
async function readJsonRecord(path2) {
|
|
17084
|
-
const raw = await readFile3(path2, "utf8");
|
|
17085
|
-
const parsed = JSON.parse(raw);
|
|
17086
|
-
if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) {
|
|
17087
|
-
throw new Error(`${path2} must contain a JSON object`);
|
|
17088
|
-
}
|
|
17089
|
-
return parsed;
|
|
17090
|
-
}
|
|
17091
17196
|
function stringValue(value) {
|
|
17092
17197
|
return typeof value === "string" && value.length > 0 ? value : null;
|
|
17093
17198
|
}
|
|
@@ -17148,14 +17253,14 @@ function printScaffoldError(prefix, err) {
|
|
|
17148
17253
|
|
|
17149
17254
|
// src/index.ts
|
|
17150
17255
|
var program2 = new Command();
|
|
17151
|
-
program2.name("anymorph").description("Check AI visibility and run local GEO strategy workflows").version("0.
|
|
17256
|
+
program2.name("anymorph").description("Check AI visibility and run local GEO strategy workflows").version("0.7.0");
|
|
17152
17257
|
program2.command("login").description("Sign in to your Anymorph account").addHelpText(
|
|
17153
17258
|
"after",
|
|
17154
17259
|
`
|
|
17155
17260
|
Examples:
|
|
17156
17261
|
$ anymorph login
|
|
17157
17262
|
|
|
17158
|
-
Use this before authenticated commands such as workspaces
|
|
17263
|
+
Use this before authenticated commands such as workspaces and prepare.`
|
|
17159
17264
|
).action(loginCommand);
|
|
17160
17265
|
program2.command("check <domain>").description("Run an AI visibility check for a domain").option("--json", "Output as JSON").addHelpText(
|
|
17161
17266
|
"after",
|
|
@@ -17225,15 +17330,15 @@ Command usage:
|
|
|
17225
17330
|
Must be run from the tenant repo root.
|
|
17226
17331
|
|
|
17227
17332
|
anymorph validate <runId> [--json]
|
|
17228
|
-
Validate local run files and actions.json before
|
|
17333
|
+
Validate local run files and actions.json before pushing.
|
|
17229
17334
|
Must be run from the tenant repo root.
|
|
17230
17335
|
|
|
17231
|
-
anymorph
|
|
17232
|
-
|
|
17336
|
+
anymorph validate mdx <paths...> [--json]
|
|
17337
|
+
Validate CMS MDX component contracts such as Callout tone values.
|
|
17233
17338
|
Must be run from the tenant repo root.
|
|
17234
17339
|
|
|
17235
17340
|
anymorph run-status <runId> [--json]
|
|
17236
|
-
Show backend status for a
|
|
17341
|
+
Show backend sync status for a pushed GEO run.
|
|
17237
17342
|
|
|
17238
17343
|
Use "anymorph <command> --help" for examples and option details.`
|
|
17239
17344
|
);
|