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.
- package/README.md +6 -16
- package/dist/index.js +217 -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("..")) {
|
|
@@ -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((
|
|
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
|
-
|
|
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((
|
|
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((
|
|
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
|
-
|
|
16736
|
-
|
|
16737
|
-
|
|
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,
|
|
16745
|
-
|
|
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
|
-
|
|
16748
|
-
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(
|
|
16749
16840
|
"after",
|
|
16750
16841
|
`
|
|
16751
16842
|
Examples:
|
|
16752
|
-
$ anymorph
|
|
16753
|
-
$ anymorph
|
|
16754
|
-
|
|
16755
|
-
|
|
16756
|
-
|
|
16757
|
-
|
|
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(
|
|
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
|
|
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
|
|
16915
|
-
|
|
16916
|
-
|
|
16917
|
-
|
|
16918
|
-
|
|
16919
|
-
|
|
16920
|
-
|
|
16921
|
-
|
|
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
|
-
|
|
16924
|
-
console.error();
|
|
16925
|
-
process.exit(1);
|
|
17033
|
+
return;
|
|
16926
17034
|
}
|
|
16927
|
-
|
|
16928
|
-
const
|
|
16929
|
-
|
|
16930
|
-
|
|
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
|
-
|
|
16938
|
-
|
|
16939
|
-
|
|
16940
|
-
|
|
16941
|
-
);
|
|
16942
|
-
const
|
|
16943
|
-
|
|
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
|
-
|
|
16972
|
-
|
|
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
|
-
|
|
16981
|
-
|
|
16982
|
-
|
|
16983
|
-
|
|
16984
|
-
|
|
16985
|
-
|
|
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.
|
|
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
|
|
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
|
|
17333
|
+
Validate local run files and actions.json before pushing.
|
|
17230
17334
|
Must be run from the tenant repo root.
|
|
17231
17335
|
|
|
17232
|
-
anymorph
|
|
17233
|
-
|
|
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
|
|
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
|
);
|