@astryxdesign/cli 0.7.2 → 0.7.3-canary.0bf23bd
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 +104 -71
- package/api/build/_adapter.d.mts +58 -0
- package/api/build/_adapter.mjs +115 -3
- package/api/build/blocks/blocks.d.mts +42 -0
- package/api/build/blocks/blocks.mjs +169 -0
- package/api/build/blocks/blocks.test.mjs +108 -0
- package/api/build/blocks/blocks.weights.json +1 -0
- package/api/build/build.mjs +25 -6
- package/api/build/kit/answer.d.mts +14 -0
- package/api/build/kit/answer.mjs +85 -0
- package/api/build/kit/answer.test.mjs +38 -0
- package/api/build/kit/kind.d.mts +25 -0
- package/api/build/kit/kind.mjs +170 -0
- package/api/build/kit/kit.d.mts +2 -4
- package/api/build/kit/kit.mjs +8 -398
- package/api/build/kit/rank.d.mts +3 -32
- package/api/build/kit/rank.mjs +25 -342
- package/api/build/kit/rank.test.mjs +2 -1
- package/api/build/kit/signals.d.mts +60 -0
- package/api/build/kit/signals.mjs +284 -0
- package/api/build/kit/start.d.mts +32 -0
- package/api/build/kit/start.mjs +163 -0
- package/api/build/kit/words.d.mts +72 -0
- package/api/build/kit/words.mjs +202 -0
- package/api/build/tree.d.mts +20 -0
- package/api/build/tree.mjs +52 -0
- package/api/build/tree.test.mjs +177 -0
- package/api/build/tree.weights.json +1 -0
- package/api/component/component.mjs +17 -3
- package/api/component/component.test.mjs +15 -0
- package/api/component/doc-links.test.mjs +2 -2
- package/api/discover/_adapter.mjs +36 -9
- package/api/discover/_adapter.test.mjs +42 -0
- package/api/docs/_adapter.d.mts +2 -2
- package/api/docs/_adapter.mjs +78 -23
- package/api/docs/docs-homes.test.mjs +127 -0
- package/api/docs/docs.doc.mjs +3 -3
- package/api/docs/docs.test.mjs +35 -19
- package/api/docs/integration-tree.test.mjs +20 -20
- package/api/docs/integrationDocs.test.mjs +1 -1
- package/api/docs/namespace-section.test.mjs +6 -6
- package/api/docs/reference-blocks.test.mjs +2 -2
- package/api/doctor/doctor.mjs +102 -24
- package/api/doctor/doctor.test.mjs +37 -12
- package/api/hook/hook.mjs +1 -1
- package/api/init/init.doc.mjs +20 -6
- package/api/init/init.test.mjs +18 -2
- package/api/init/init.type.d.mts +3 -3
- package/api/init/init.type.mjs +3 -3
- package/api/init/remove/remove.mjs +17 -4
- package/api/init/remove/remove.test.mjs +114 -2
- package/api/init/run/run.mjs +69 -6
- package/api/integration/_adapter.d.mts +8 -0
- package/api/integration/_adapter.mjs +21 -1
- package/api/integration/authoring-checks.mjs +83 -9
- package/api/integration/authoring-checks.test.mjs +220 -0
- package/api/integration/pack-check.mjs +123 -4
- package/api/integration/pack-check.test.mjs +87 -0
- package/api/integration/validate-integration-case-disk.test.mjs +111 -0
- package/api/integration/validate-integration-gaps.test.mjs +1964 -0
- package/api/integration/validate-integration.d.mts +11 -2
- package/api/integration/validate-integration.mjs +250 -32
- package/api/integration/validate-integration.type.d.mts +59 -1
- package/api/integration/validate-integration.type.mjs +46 -2
- package/api/integration/validateIntegration.doc.mjs +1 -1
- package/api/search/ORDERING.md +28 -0
- package/api/search/_adapter.d.mts +82 -2
- package/api/search/_adapter.mjs +157 -10
- package/api/search/_adapter.test.mjs +173 -0
- package/api/search/_candidate-score.d.mts +40 -0
- package/api/search/_candidate-score.mjs +238 -0
- package/api/search/_cards.json +6098 -0
- package/api/search/_compound.d.mts +50 -0
- package/api/search/_compound.mjs +170 -0
- package/api/search/_doc-searcher.d.mts +4 -0
- package/api/search/_doc-searcher.mjs +23 -0
- package/api/search/_doc-searcher.test.mjs +36 -0
- package/api/search/_doc-searcher.weights.json +1 -0
- package/api/search/_doc-text.d.mts +30 -0
- package/api/search/_doc-text.mjs +87 -0
- package/api/search/_entries.d.mts +52 -0
- package/api/search/_entries.mjs +214 -0
- package/api/search/_features.d.mts +35 -0
- package/api/search/_features.mjs +155 -0
- package/api/search/_gather-components.d.mts +26 -0
- package/api/search/_gather-components.mjs +284 -0
- package/api/search/_gather-docs.d.mts +20 -0
- package/api/search/_gather-docs.mjs +254 -0
- package/api/search/_gather-hooks.d.mts +12 -0
- package/api/search/_gather-hooks.mjs +52 -0
- package/api/search/_gather-templates.d.mts +25 -0
- package/api/search/_gather-templates.mjs +107 -0
- package/api/search/_lexical.d.mts +135 -0
- package/api/search/_lexical.mjs +351 -0
- package/api/search/_main-searcher.d.mts +19 -0
- package/api/search/_main-searcher.mjs +115 -0
- package/api/search/_main-searcher.test.mjs +106 -0
- package/api/search/_main-searcher.weights.json +1 -0
- package/api/search/_module-doc.d.mts +32 -0
- package/api/search/_module-doc.mjs +78 -0
- package/api/search/_order.d.mts +32 -0
- package/api/search/_order.mjs +162 -0
- package/api/search/_order.test.mjs +72 -0
- package/api/search/_priority.d.mts +50 -0
- package/api/search/_priority.mjs +139 -0
- package/api/search/_query-words.d.mts +25 -0
- package/api/search/_query-words.mjs +92 -0
- package/api/search/_query.d.mts +65 -0
- package/api/search/_query.mjs +176 -0
- package/api/search/_result.d.mts +97 -0
- package/api/search/_result.mjs +150 -0
- package/api/search/_score.d.mts +60 -0
- package/api/search/_score.mjs +283 -0
- package/api/search/_synonyms.d.mts +21 -0
- package/api/search/_synonyms.mjs +67 -0
- package/api/search/_template-searcher.d.mts +4 -0
- package/api/search/_template-searcher.mjs +23 -0
- package/api/search/_template-searcher.test.mjs +40 -0
- package/api/search/_template-searcher.weights.json +1 -0
- package/api/search/_titles.d.mts +33 -0
- package/api/search/_titles.mjs +65 -0
- package/api/search/_words.d.mts +64 -0
- package/api/search/_words.mjs +157 -0
- package/api/search/search.d.mts +22 -305
- package/api/search/search.doc.mjs +8 -6
- package/api/search/search.mjs +56 -2482
- package/api/search/search.test.mjs +14 -14
- package/api/search/search.type.d.mts +6 -1
- package/api/search/search.type.mjs +6 -1
- package/api/search/tree.d.mts +15 -0
- package/api/search/tree.mjs +40 -0
- package/api/search/tree.test.mjs +66 -0
- package/api/search/tree.weights.json +1 -0
- package/api/theme/build/build.packed-old-core.test.mjs +1 -0
- package/api/upgrade/_adapter.d.mts +57 -9
- package/api/upgrade/_adapter.mjs +198 -28
- package/api/upgrade/registry/registry.d.mts +10 -4
- package/api/upgrade/registry/registry.mjs +33 -16
- package/api/upgrade/registry/registry.test.mjs +85 -0
- package/api/upgrade/run/run.d.mts +4 -2
- package/api/upgrade/run/run.mjs +13 -2
- package/api/upgrade/run/run.test.mjs +417 -3
- package/api/upgrade/upgrade.doc.mjs +10 -5
- package/api/upgrade/upgrade.mjs +13 -2
- package/api/upgrade/upgrade.test.mjs +194 -0
- package/api/upgrade/upgrade.type.d.mts +5 -3
- package/api/upgrade/upgrade.type.mjs +8 -6
- package/assets/codemods/transforms/v0.7.0/__tests__/validate-data-token-ownership.test.mjs +11 -0
- package/assets/codemods/transforms/v0.7.0/validate-data-token-ownership.mjs +3 -3
- package/assets/docs/author-a-theme.doc.mjs +2 -2
- package/assets/docs/is-my-code-good.doc.mjs +287 -0
- package/assets/docs/tree/add-a-component.doc.mjs +1 -1
- package/assets/docs/tree/add-a-theme.doc.mjs +1 -1
- package/assets/docs/tree/add-a-topic.doc.mjs +2 -2
- package/assets/docs/tree/agent-guidance.doc.mjs +1 -1
- package/assets/docs/tree/api.doc.mjs +6 -0
- package/assets/docs/tree/{integrations.doc.mjs → authoring.doc.mjs} +15 -6
- package/assets/docs/tree/block-template.doc.mjs +1 -1
- package/assets/docs/tree/build-the-template.doc.mjs +1 -1
- package/assets/docs/tree/building-blocks.doc.mjs +2 -2
- package/assets/docs/tree/check-the-props.doc.mjs +1 -1
- package/assets/docs/tree/check-your-docs.doc.mjs +2 -2
- package/assets/docs/tree/checks.doc.mjs +2 -2
- package/assets/docs/tree/cli-command.doc.mjs +1 -1
- package/assets/docs/tree/cli.doc.mjs +1 -1
- package/assets/docs/tree/codemods.doc.mjs +1 -1
- package/assets/docs/tree/component-family.doc.mjs +1 -1
- package/assets/docs/tree/component-imports.doc.mjs +1 -1
- package/assets/docs/tree/components.doc.mjs +1 -1
- package/assets/docs/tree/configuration.doc.mjs +1 -1
- package/assets/docs/tree/debug-and-gap-reports.doc.mjs +1 -1
- package/assets/docs/tree/define-the-theme.doc.mjs +1 -1
- package/assets/docs/tree/describe-the-component.doc.mjs +1 -1
- package/assets/docs/tree/docs.doc.mjs +1 -1
- package/assets/docs/tree/document-the-template.doc.mjs +1 -1
- package/assets/docs/tree/document-the-theme.doc.mjs +1 -1
- package/assets/docs/tree/export-template-assets.doc.mjs +1 -1
- package/assets/docs/tree/extend-or-replace.doc.mjs +1 -1
- package/assets/docs/{authoring.doc.mjs → tree/field-reference.doc.mjs} +4 -3
- package/assets/docs/tree/fonts-and-assets.doc.mjs +1 -1
- package/assets/docs/tree/generate-a-palette.doc.mjs +1 -1
- package/assets/docs/tree/global-integrations.doc.mjs +2 -2
- package/assets/docs/tree/grade-template-with-agent.doc.mjs +4 -4
- package/assets/docs/tree/help.doc.mjs +2 -2
- package/assets/docs/tree/host-entry.doc.mjs +128 -0
- package/assets/docs/tree/links.doc.mjs +1 -1
- package/assets/docs/tree/package-and-test.doc.mjs +1 -1
- package/assets/docs/tree/page-template.doc.mjs +1 -1
- package/assets/docs/tree/publishing.doc.mjs +1 -1
- package/assets/docs/tree/quick-start.doc.mjs +1 -1
- package/assets/docs/tree/replace-a-core-component.doc.mjs +1 -1
- package/assets/docs/tree/replace-a-core-template.doc.mjs +1 -1
- package/assets/docs/tree/sections-and-placement.doc.mjs +1 -1
- package/assets/docs/tree/see-it-in-an-app.doc.mjs +1 -1
- package/assets/docs/tree/ship.doc.mjs +2 -2
- package/assets/docs/tree/short-and-findable.doc.mjs +1 -1
- package/assets/docs/tree/single-component.doc.mjs +1 -1
- package/assets/docs/tree/start-a-template.doc.mjs +1 -1
- package/assets/docs/tree/subcomponent.doc.mjs +1 -1
- package/assets/docs/tree/template-assets.doc.mjs +1 -1
- package/assets/docs/tree/template-doc-overview.doc.mjs +2 -2
- package/assets/docs/tree/template-fonts.doc.mjs +1 -1
- package/assets/docs/tree/template-grading-rubric.doc.mjs +17 -38
- package/assets/docs/tree/template-icons.doc.mjs +1 -1
- package/assets/docs/tree/template-images-media.doc.mjs +1 -1
- package/assets/docs/tree/template-styles.doc.mjs +1 -1
- package/assets/docs/tree/templates.doc.mjs +1 -1
- package/assets/docs/tree/test-in-an-app.doc.mjs +1 -1
- package/assets/docs/tree/test-template-in-app.doc.mjs +1 -1
- package/assets/docs/tree/themes.doc.mjs +1 -1
- package/assets/docs/tree/tokens-data.doc.mjs +2 -2
- package/assets/docs/tree/troubleshooting.doc.mjs +1 -1
- package/assets/docs/tree/upgrading.doc.mjs +1 -1
- package/assets/docs/tree/use-a-theme-in-an-app.doc.mjs +1 -1
- package/assets/docs/tree/verify-packed-template.doc.mjs +1 -1
- package/assets/docs/tree/versioning.doc.mjs +1 -1
- package/assets/docs/tree/write-good-templates.doc.mjs +1 -1
- package/assets/docs/tree/write-the-template-file.doc.mjs +1 -1
- package/assets/docs/use-integrations.doc.mjs +120 -0
- package/assets/docs/working-with-ai.doc.mjs +6 -2
- package/assets/templates/themes/butter/butterTheme.ts +4 -2
- package/assets/templates/themes/stone/stoneTheme.ts +4 -2
- package/assets/templates/themes/y2k/y2kTheme.ts +4 -2
- package/authoring/debug/parse.d.mts +1 -1
- package/authoring/doctypes/schema/schema.doc.mjs +1 -1
- package/authoring/integration/integration.doc.mjs +1 -1
- package/authoring/integration/type.ts +1 -1
- package/clients/cli/bin/astryx.mjs +7 -78
- package/clients/cli/command-result-coverage.test.mjs +6 -5
- package/clients/cli/commands/build-theme.color-scheme.test.mjs +1 -1
- package/clients/cli/commands/{component/index.mjs → component.mjs} +37 -37
- package/clients/cli/commands/component.test.mjs +6 -6
- package/clients/cli/commands/docs.doc.mjs +2 -2
- package/clients/cli/commands/docs.mjs +1 -1
- package/clients/cli/commands/docs.test.mjs +14 -14
- package/clients/cli/commands/doctor.mjs +30 -0
- package/clients/cli/commands/doctor.test.mjs +65 -0
- package/clients/cli/commands/{hook/index.mjs → hook.mjs} +22 -22
- package/clients/cli/commands/import-hint-correctness.test.mjs +1 -1
- package/clients/cli/commands/init.behavior.test.mjs +230 -1
- package/clients/cli/commands/init.doc.mjs +28 -9
- package/clients/cli/commands/init.flag-help.test.mjs +1 -0
- package/clients/cli/commands/init.mjs +2 -2
- package/clients/cli/commands/integration-check.test.mjs +48 -0
- package/clients/cli/commands/integration.doc.mjs +1 -1
- package/clients/cli/commands/manifest.doc.mjs +1 -1
- package/clients/cli/commands/manifest.mjs +67 -0
- package/clients/cli/commands/outside-project.test.mjs +2 -1
- package/clients/cli/commands/postinstall.doc.mjs +23 -0
- package/clients/cli/commands/postinstall.mjs +31 -0
- package/clients/cli/commands/setup-nudge.test.mjs +61 -0
- package/clients/cli/commands/{build-theme.mjs → theme.mjs} +1 -1
- package/clients/cli/commands/upgrade.doc.mjs +4 -2
- package/clients/cli/commands/upgrade.mjs +9 -2
- package/clients/cli/commands/upgrade.subfolder-path.test.mjs +97 -0
- package/clients/cli/index.mjs +29 -86
- package/clients/cli/lib/component-format.mjs +1 -1
- package/clients/cli/lib/define-command.mjs +12 -7
- package/clients/cli/lib/exit-codes.test.mjs +5 -0
- package/clients/cli/lib/manifest.test.mjs +12 -0
- package/clients/cli/lib/welcome-box.mjs +50 -0
- package/clients/cli/run.mjs +108 -0
- package/foundation/agent-docs/agent-doc-state.d.mts +20 -7
- package/foundation/agent-docs/agent-doc-state.mjs +35 -8
- package/foundation/agent-docs/agent-docs.d.mts +100 -12
- package/foundation/agent-docs/agent-docs.mjs +1012 -100
- package/foundation/agent-docs/agent-docs.path-safety.test.mjs +1239 -17
- package/foundation/agent-docs/agent-docs.test.mjs +683 -39
- package/foundation/config/project.mjs +20 -22
- package/foundation/config/project.test.mjs +56 -0
- package/foundation/discovery/authoring-self-docs.d.mts +7 -0
- package/foundation/discovery/authoring-self-docs.mjs +16 -4
- package/foundation/discovery/authoring-self-docs.test.mjs +15 -3
- package/foundation/discovery/authoring-surface.d.mts +1 -1
- package/foundation/discovery/authoring-surface.mjs +2 -2
- package/foundation/discovery/authoring-surface.test.mjs +1 -1
- package/foundation/discovery/cli-self-docs.d.mts +2 -1
- package/foundation/discovery/cli-self-docs.mjs +4 -3
- package/foundation/discovery/cli-self-docs.test.mjs +2 -2
- package/foundation/discovery/component-discovery.d.mts +37 -0
- package/foundation/discovery/component-discovery.mjs +80 -5
- package/foundation/discovery/component-loader.d.mts +1 -1
- package/foundation/discovery/docs-discovery.mjs +14 -1
- package/foundation/discovery/module-exports.d.mts +41 -0
- package/foundation/discovery/module-exports.mjs +253 -0
- package/foundation/discovery/runner-allowlist.d.mts +2 -4
- package/foundation/discovery/runner-allowlist.mjs +2 -4
- package/foundation/discovery/runner-commands.d.mts +77 -0
- package/foundation/discovery/runner-commands.mjs +294 -0
- package/foundation/discovery/runner-commands.test.mjs +128 -0
- package/foundation/discovery/stray-pointers.test.mjs +1 -1
- package/foundation/discovery/template-adapter.mjs +18 -1
- package/foundation/discovery/template-needs.mjs +1 -44
- package/foundation/discovery/theme-discovery.mjs +147 -3
- package/foundation/doc-compiler/doc-loads.test.mjs +33 -9
- package/foundation/doc-compiler/read.mjs +59 -1
- package/foundation/doc-compiler/read.test.mjs +11 -2
- package/foundation/doc-compiler/split-topic-keywords.test.mjs +3 -2
- package/foundation/doc-compiler/tree.d.mts +32 -6
- package/foundation/doc-compiler/tree.mjs +77 -43
- package/foundation/doc-compiler/tree.test.mjs +7 -7
- package/foundation/fs/paths.d.mts +70 -8
- package/foundation/fs/paths.mjs +556 -38
- package/foundation/fs/paths.test.mjs +430 -54
- package/foundation/fs/read-record.d.mts +18 -0
- package/foundation/fs/read-record.mjs +131 -0
- package/foundation/fs/read-record.test.mjs +77 -0
- package/foundation/integrations/autolink.d.mts +2 -1
- package/foundation/integrations/autolink.mjs +4 -13
- package/foundation/integrations/computer-integrations.d.mts +6 -3
- package/foundation/integrations/computer-integrations.mjs +38 -9
- package/foundation/integrations/contribution-inventory.d.mts +15 -20
- package/foundation/integrations/contribution-inventory.mjs +41 -5
- package/foundation/integrations/integrations.d.mts +27 -1
- package/foundation/integrations/integrations.mjs +61 -2
- package/foundation/integrations/validate-contributions.d.mts +115 -0
- package/foundation/integrations/validate-contributions.mjs +1168 -13
- package/foundation/release/handoff.d.mts +23 -4
- package/foundation/release/handoff.mjs +175 -8
- package/foundation/release/run-context.mjs +14 -0
- package/foundation/response/response-types.doc.mjs +1 -1
- package/foundation/route/route.d.mts +285 -0
- package/foundation/route/route.mjs +324 -0
- package/foundation/route/route.test.mjs +153 -0
- package/foundation/runtime/hosted-runtime.test.mjs +403 -0
- package/foundation/runtime/locked-versions.d.mts +32 -0
- package/foundation/runtime/locked-versions.mjs +65 -0
- package/foundation/runtime/package-root.d.mts +91 -0
- package/foundation/runtime/package-root.mjs +174 -0
- package/foundation/runtime/package-set.d.mts +62 -0
- package/foundation/runtime/package-set.mjs +130 -0
- package/foundation/runtime/package-set.test.mjs +432 -0
- package/host/door-conformance.test.mjs +274 -0
- package/host/index.d.ts +116 -0
- package/host/index.mjs +295 -0
- package/host/index.test.mjs +302 -0
- package/package.json +14 -9
|
@@ -246,7 +246,7 @@ describe('integration docs in the docs tree', () => {
|
|
|
246
246
|
});
|
|
247
247
|
scaffold({
|
|
248
248
|
...kit(),
|
|
249
|
-
'
|
|
249
|
+
'guides.doc.mjs': {...NAMESPACE, name: 'guides', title: 'Mine', summary: 'Mine.'},
|
|
250
250
|
'use-a-theme.doc.mjs': {...NAMESPACE, name: 'use-a-theme', title: 'Acme use-a-theme', summary: 'Acme use-a-theme.'},
|
|
251
251
|
'cli.doc.mjs': flat('cli'),
|
|
252
252
|
});
|
|
@@ -254,26 +254,26 @@ describe('integration docs in the docs tree', () => {
|
|
|
254
254
|
expect(listed.meta.namespaces).toEqual(
|
|
255
255
|
expect.arrayContaining([
|
|
256
256
|
expect.objectContaining({topic: 'cli', package: '@astryxdesign/cli'}),
|
|
257
|
-
expect.objectContaining({topic: '
|
|
257
|
+
expect.objectContaining({topic: 'guides', package: '@astryxdesign/cli'}),
|
|
258
258
|
]),
|
|
259
259
|
);
|
|
260
|
-
expect(listed.meta.namespaces.filter(n => ['use-a-theme', '
|
|
260
|
+
expect(listed.meta.namespaces.filter(n => ['use-a-theme', 'guides'].includes(n.topic) && n.package === '@acme/kit')).toEqual([]);
|
|
261
261
|
expect(listed.data.map(entry => entry.topic)).not.toContain('cli');
|
|
262
262
|
// Each name opens the CLI's doc, and a CLI topic keeps its home.
|
|
263
263
|
expect((await docs('cli', undefined, {cwd: tmpDir})).data).toMatchObject({route: 'cli', package: '@astryxdesign/cli'});
|
|
264
|
-
expect((await docs('
|
|
264
|
+
expect((await docs('guides', undefined, {cwd: tmpDir})).data).toMatchObject({route: 'guides', package: '@astryxdesign/cli'});
|
|
265
265
|
const tokens = await docs('use-a-theme', undefined, {cwd: tmpDir});
|
|
266
266
|
expect(tokens.type).toBe('docs.detail');
|
|
267
|
-
expect(tokens.data.links.up).toBe('astryx docs
|
|
267
|
+
expect(tokens.data.links.up).toBe('astryx docs guides');
|
|
268
268
|
// The project doctor and the package doctor both name the claims.
|
|
269
269
|
const check = await checkDocsTree({docsCatalog: await loadDocsCatalog(tmpDir)});
|
|
270
270
|
expect(check.status).toBe('warn');
|
|
271
|
-
expect(check.message).toContain('takes the route "
|
|
271
|
+
expect(check.message).toContain('takes the route "guides", which the CLI\'s own docs keep');
|
|
272
272
|
expect(check.message).toContain('takes the route "use-a-theme"');
|
|
273
273
|
expect(check.message).toContain('both have the route "cli"');
|
|
274
274
|
const result = await integrationDocConflicts('@acme/kit', {cwd: tmpDir});
|
|
275
275
|
const graph = result.data.issues.filter(issue => issue.code === 'invalid_doc_graph').map(issue => issue.message).join('\n');
|
|
276
|
-
expect(graph).toContain('takes the route "
|
|
276
|
+
expect(graph).toContain('takes the route "guides"');
|
|
277
277
|
expect(graph).toContain('takes the route "use-a-theme"');
|
|
278
278
|
expect(graph).toContain('route "cli"');
|
|
279
279
|
}, SLOW);
|
|
@@ -294,16 +294,16 @@ describe('integration docs in the docs tree', () => {
|
|
|
294
294
|
const nested = path.join(tmpDir, 'node_modules', '@acme', 'kit', 'docs', 'nested');
|
|
295
295
|
fs.mkdirSync(nested, {recursive: true});
|
|
296
296
|
fs.writeFileSync(
|
|
297
|
-
path.join(nested, 'caps-
|
|
298
|
-
`export const docs = ${JSON.stringify(flat('
|
|
297
|
+
path.join(nested, 'caps-guides.doc.mjs'),
|
|
298
|
+
`export const docs = ${JSON.stringify(flat('Guides'), null, 2)};\n`,
|
|
299
299
|
);
|
|
300
300
|
fs.writeFileSync(
|
|
301
301
|
path.join(nested, 'caps-use-a-theme.doc.mjs'),
|
|
302
302
|
`export const docs = ${JSON.stringify(flat('USE-A-THEME'), null, 2)};\n`,
|
|
303
303
|
);
|
|
304
304
|
expect((await docs('cli', undefined, {cwd: tmpDir})).data).toMatchObject({route: 'cli', package: '@astryxdesign/cli'});
|
|
305
|
-
expect((await docs('
|
|
306
|
-
expect((await docs('theme', undefined, {cwd: tmpDir, index: true})).data.links.up).toBe('astryx docs
|
|
305
|
+
expect((await docs('guides', undefined, {cwd: tmpDir})).data).toMatchObject({route: 'guides', package: '@astryxdesign/cli'});
|
|
306
|
+
expect((await docs('theme', undefined, {cwd: tmpDir, index: true})).data.links.up).toBe('astryx docs guides');
|
|
307
307
|
const listed = await docs(undefined, undefined, {cwd: tmpDir});
|
|
308
308
|
expect(listed.data.map(entry => entry.topic.toLowerCase())).not.toContain('cli');
|
|
309
309
|
// Search does not offer a topic whose route another doc owns.
|
|
@@ -314,10 +314,10 @@ describe('integration docs in the docs tree', () => {
|
|
|
314
314
|
const check = await checkDocsTree({docsCatalog: await loadDocsCatalog(tmpDir)});
|
|
315
315
|
expect(check.status).toBe('warn');
|
|
316
316
|
expect(check.message).toContain('route "CLI"');
|
|
317
|
-
expect(check.message).toContain('takes the route "
|
|
317
|
+
expect(check.message).toContain('takes the route "Guides"');
|
|
318
318
|
// `USE-A-THEME` is the CLI's topic `use-a-theme` in another spelling: the CLI's wins.
|
|
319
319
|
const tokens = await docs('USE-A-THEME', undefined, {cwd: tmpDir, index: true});
|
|
320
|
-
expect(tokens.data).toMatchObject({name: 'use-a-theme', links: {up: 'astryx docs
|
|
320
|
+
expect(tokens.data).toMatchObject({name: 'use-a-theme', links: {up: 'astryx docs guides'}});
|
|
321
321
|
expect(tokens.data.title).not.toBe('Acme USE-A-THEME');
|
|
322
322
|
const result = await integrationDocConflicts('@acme/kit', {cwd: tmpDir});
|
|
323
323
|
const graph = result.data.issues
|
|
@@ -325,7 +325,7 @@ describe('integration docs in the docs tree', () => {
|
|
|
325
325
|
.map(issue => issue.message)
|
|
326
326
|
.join('\n');
|
|
327
327
|
expect(graph).toContain('route "CLI"');
|
|
328
|
-
expect(graph).toContain('takes the route "
|
|
328
|
+
expect(graph).toContain('takes the route "Guides"');
|
|
329
329
|
}, SLOW);
|
|
330
330
|
|
|
331
331
|
it("keeps a replaced name for the topic that replaces it, over another integration's namespace", async () => {
|
|
@@ -420,9 +420,9 @@ describe('integration docs in the docs tree', () => {
|
|
|
420
420
|
scaffold({
|
|
421
421
|
...kit(),
|
|
422
422
|
'a-cli.doc.mjs': flat('cli'),
|
|
423
|
-
'a-
|
|
423
|
+
'a-guides.doc.mjs': flat('Guides'),
|
|
424
424
|
'z-b2.doc.mjs': flat('b2', {replaces: 'cli'}),
|
|
425
|
-
'z-u2.doc.mjs': flat('u2', {replaces: '
|
|
425
|
+
'z-u2.doc.mjs': flat('u2', {replaces: 'Guides'}),
|
|
426
426
|
});
|
|
427
427
|
// Another package carries the chain on: c3 replaces b2, which replaced cli.
|
|
428
428
|
const three = path.join(tmpDir, 'node_modules', '@acme', 'three');
|
|
@@ -440,8 +440,8 @@ describe('integration docs in the docs tree', () => {
|
|
|
440
440
|
for (const name of ['cli', 'CLI']) {
|
|
441
441
|
expect((await docs(name, undefined, {cwd: tmpDir})).data).toMatchObject({route: 'cli', package: '@astryxdesign/cli'});
|
|
442
442
|
}
|
|
443
|
-
for (const name of ['
|
|
444
|
-
expect((await docs(name, undefined, {cwd: tmpDir})).data).toMatchObject({route: '
|
|
443
|
+
for (const name of ['guides', 'GUIDES']) {
|
|
444
|
+
expect((await docs(name, undefined, {cwd: tmpDir})).data).toMatchObject({route: 'guides', package: '@astryxdesign/cli'});
|
|
445
445
|
}
|
|
446
446
|
// The replacement still answers to its own names.
|
|
447
447
|
for (const name of ['b2', 'c3']) {
|
|
@@ -456,7 +456,7 @@ describe('integration docs in the docs tree', () => {
|
|
|
456
456
|
const check = await checkDocsTree({docsCatalog: await loadDocsCatalog(tmpDir)});
|
|
457
457
|
expect(check.status).toBe('warn');
|
|
458
458
|
expect(check.message).toContain('The topic "c3" answers to "cli" through replaces');
|
|
459
|
-
expect(check.message).toContain('The topic "u2" answers to "
|
|
459
|
+
expect(check.message).toContain('The topic "u2" answers to "guides" through replaces');
|
|
460
460
|
const inPackage = await integrationDocConflicts('@acme/kit', {cwd: tmpDir});
|
|
461
461
|
const graph = inPackage.data.issues
|
|
462
462
|
.filter(issue => issue.code === 'invalid_doc_graph')
|
|
@@ -519,7 +519,7 @@ describe('integration docs in the docs tree', () => {
|
|
|
519
519
|
});
|
|
520
520
|
const {data} = await docs('theme', 'acme-theming-notes', {cwd: tmpDir});
|
|
521
521
|
// `generic:integrations` is the extension's own guide, never the CLI's
|
|
522
|
-
// `
|
|
522
|
+
// `authoring`; a provider-qualified link reaches the CLI's topic.
|
|
523
523
|
expect(data.content[0].text).toBe(
|
|
524
524
|
'See `astryx docs acme/integrations`, and `astryx docs tokens` for the tokens.',
|
|
525
525
|
);
|
|
@@ -447,7 +447,7 @@ describe('integration-contributed topics', () => {
|
|
|
447
447
|
// places it.
|
|
448
448
|
expect(top).toContain('troubleshooting');
|
|
449
449
|
expect(
|
|
450
|
-
top.some(name => /^
|
|
450
|
+
top.some(name => /^authoring\/(?:.+\/)?troubleshooting$/.test(name)),
|
|
451
451
|
top.join(', '),
|
|
452
452
|
).toBe(true);
|
|
453
453
|
}, SLOW);
|
|
@@ -157,13 +157,13 @@ describe('a section read on a namespace', () => {
|
|
|
157
157
|
expect(names).toContain('layout/side-panels');
|
|
158
158
|
expect(names.every(name => name.startsWith('layout/'))).toBe(true);
|
|
159
159
|
// At any depth: guides under nested namespaces are named, namespaces are not.
|
|
160
|
-
const
|
|
161
|
-
expect(
|
|
162
|
-
expect(
|
|
163
|
-
'
|
|
160
|
+
const authoring = await docs('authoring', 'zzzz-nope').catch(e => e);
|
|
161
|
+
expect(authoring.code).toBe('ERR_UNKNOWN_SECTION');
|
|
162
|
+
expect(authoring.suggestions.map(s => s.name)).toContain(
|
|
163
|
+
'authoring/building-blocks/components/add-a-component',
|
|
164
164
|
);
|
|
165
|
-
expect(
|
|
166
|
-
'
|
|
165
|
+
expect(authoring.suggestions.map(s => s.name)).not.toContain(
|
|
166
|
+
'authoring/building-blocks',
|
|
167
167
|
);
|
|
168
168
|
},
|
|
169
169
|
SLOW,
|
|
@@ -300,11 +300,11 @@ describe('a reference block that includes what it names', () => {
|
|
|
300
300
|
});
|
|
301
301
|
|
|
302
302
|
describe('what a reference block names', () => {
|
|
303
|
-
it('resolves a CLI authoring schema by identity, to its section of
|
|
303
|
+
it('resolves a CLI authoring schema by identity, to its section of the field reference', async () => {
|
|
304
304
|
const resolve = await linkResolver(builtinCatalog(), CLI_PROVIDER_ID);
|
|
305
305
|
expect(await resolve('schema:integration')).toMatchObject({
|
|
306
306
|
id: createDocId(CLI_PROVIDER_ID, 'schema', 'integration'),
|
|
307
|
-
route: 'authoring',
|
|
307
|
+
route: 'authoring/field-reference',
|
|
308
308
|
title: 'Astryx Integration',
|
|
309
309
|
command: 'astryx docs authoring integration',
|
|
310
310
|
});
|
package/api/doctor/doctor.mjs
CHANGED
|
@@ -28,7 +28,15 @@ import * as fs from 'node:fs';
|
|
|
28
28
|
import * as path from 'node:path';
|
|
29
29
|
|
|
30
30
|
import {MIN_NODE_VERSION, isNodeVersionSupported} from '../../foundation/env/node-version.mjs';
|
|
31
|
-
import {
|
|
31
|
+
import {
|
|
32
|
+
AGENT_DOC_PATHS,
|
|
33
|
+
holdsAstryxBlock,
|
|
34
|
+
} from '../../foundation/agent-docs/agent-doc-state.mjs';
|
|
35
|
+
import {
|
|
36
|
+
agentDocsTargetDir,
|
|
37
|
+
assertAgentDocsTarget,
|
|
38
|
+
resolveAgentDocsRoot,
|
|
39
|
+
} from '../../foundation/agent-docs/agent-docs.mjs';
|
|
32
40
|
import {CLI_ROOT, findProjectCoreDir, findInstalledPackage} from '../../foundation/fs/paths.mjs';
|
|
33
41
|
import {explainPackageManager, formatCliCommand, getCliInvocation, guessCliInvocation} from '../../foundation/env/package-manager.mjs';
|
|
34
42
|
import {chooseDeclaredCliCommand, declaredCliCommandsOf} from '../../foundation/env/cli-command.mjs';
|
|
@@ -610,6 +618,21 @@ export function checkConfiguredIntegrations(ctx) {
|
|
|
610
618
|
};
|
|
611
619
|
}
|
|
612
620
|
|
|
621
|
+
/**
|
|
622
|
+
* Why init writes no agent docs for `cwd`, or null when it does: the folder
|
|
623
|
+
* it would write to is the home folder or the top of a settings folder in it.
|
|
624
|
+
* @param {string} cwd
|
|
625
|
+
* @returns {string | null}
|
|
626
|
+
*/
|
|
627
|
+
function agentDocsRefusal(cwd) {
|
|
628
|
+
try {
|
|
629
|
+
assertAgentDocsTarget(agentDocsTargetDir(cwd));
|
|
630
|
+
return null;
|
|
631
|
+
} catch (err) {
|
|
632
|
+
return err instanceof Error && err.name === 'AgentDocsHomeError' ? err.message : null;
|
|
633
|
+
}
|
|
634
|
+
}
|
|
635
|
+
|
|
613
636
|
/**
|
|
614
637
|
* Check 7 — agent docs exist and contain the Astryx section markers.
|
|
615
638
|
* @param {DoctorContext} ctx
|
|
@@ -617,8 +640,15 @@ export function checkConfiguredIntegrations(ctx) {
|
|
|
617
640
|
*/
|
|
618
641
|
export function checkAgentDocs(ctx) {
|
|
619
642
|
// Every file init can write (one shared list), looked for in the working
|
|
620
|
-
// directory
|
|
621
|
-
|
|
643
|
+
// directory, the project root, and the folder init writes them to: run from
|
|
644
|
+
// src/ or a nested package, the docs sit at the root.
|
|
645
|
+
const dirs = [
|
|
646
|
+
...new Set(
|
|
647
|
+
[ctx.cwd, projectRootOf(ctx), resolveAgentDocsRoot(ctx.cwd) ?? ctx.cwd].map(dir =>
|
|
648
|
+
path.resolve(dir),
|
|
649
|
+
),
|
|
650
|
+
),
|
|
651
|
+
];
|
|
622
652
|
const present = dirs.flatMap(dir =>
|
|
623
653
|
AGENT_DOC_PATHS.map(rel => path.join(dir, rel)).filter(abs =>
|
|
624
654
|
fs.existsSync(abs),
|
|
@@ -626,6 +656,15 @@ export function checkAgentDocs(ctx) {
|
|
|
626
656
|
);
|
|
627
657
|
/** @param {string} abs */
|
|
628
658
|
const shown = abs => path.relative(ctx.cwd, abs) || path.basename(abs);
|
|
659
|
+
// In the home folder, or at the top of a settings folder in it, init
|
|
660
|
+
// writes no agent docs (INV31), so the fix is moving the project or a hand
|
|
661
|
+
// edit, never init.
|
|
662
|
+
const refusal = agentDocsRefusal(ctx.cwd);
|
|
663
|
+
/** @param {string} initFix */
|
|
664
|
+
const fixFor = initFix =>
|
|
665
|
+
refusal
|
|
666
|
+
? `${refusal} Move the project into a folder of its own, or edit the Astryx block in its agent file by hand.`
|
|
667
|
+
: initFix;
|
|
629
668
|
|
|
630
669
|
if (present.length === 0) {
|
|
631
670
|
return {
|
|
@@ -633,29 +672,64 @@ export function checkAgentDocs(ctx) {
|
|
|
633
672
|
label: 'AI agent docs',
|
|
634
673
|
status: 'info',
|
|
635
674
|
message: `No agent docs found: looked for ${AGENT_DOC_PATHS.join(', ')} in ${dirs.map(dir => path.relative(ctx.cwd, dir) || '.').join(' and ')}.`,
|
|
636
|
-
fix:
|
|
675
|
+
fix: fixFor(
|
|
676
|
+
`Generate agent docs with \`${getCliInvocation(ctx.cwd)} init --features agents\`.`,
|
|
677
|
+
),
|
|
637
678
|
};
|
|
638
679
|
}
|
|
639
680
|
|
|
640
|
-
|
|
681
|
+
/** @param {string} abs */
|
|
682
|
+
const read = abs => {
|
|
641
683
|
try {
|
|
642
|
-
|
|
643
|
-
return (
|
|
644
|
-
(content.includes('<!-- ASTRYX:START -->') || content.includes('<!-- XDS:START -->')) &&
|
|
645
|
-
(content.includes('<!-- ASTRYX:END -->') || content.includes('<!-- XDS:END -->'))
|
|
646
|
-
);
|
|
684
|
+
return fs.readFileSync(abs, 'utf-8');
|
|
647
685
|
} catch {
|
|
648
|
-
return
|
|
686
|
+
return '';
|
|
649
687
|
}
|
|
688
|
+
};
|
|
689
|
+
const withMarkers = present.filter(abs => {
|
|
690
|
+
const content = read(abs);
|
|
691
|
+
return (
|
|
692
|
+
(content.includes('<!-- ASTRYX:START -->') || content.includes('<!-- XDS:START -->')) &&
|
|
693
|
+
(content.includes('<!-- ASTRYX:END -->') || content.includes('<!-- XDS:END -->')) &&
|
|
694
|
+
holdsAstryxBlock(content)
|
|
695
|
+
);
|
|
650
696
|
});
|
|
651
697
|
|
|
698
|
+
// A managed block that only imports another file (init's GEMINI.md import
|
|
699
|
+
// of AGENTS.md) is broken when that file holds no block: the agents that
|
|
700
|
+
// read either file get no Astryx docs.
|
|
701
|
+
const dangling = present.flatMap(abs => {
|
|
702
|
+
const match = /<!-- ASTRYX:START -->\s*@(\S+)\s*<!-- ASTRYX:END -->/.exec(read(abs));
|
|
703
|
+
if (match == null) return [];
|
|
704
|
+
const target = path.resolve(path.dirname(abs), match[1]);
|
|
705
|
+
return holdsAstryxBlock(read(target)) ? [] : [{abs, target}];
|
|
706
|
+
});
|
|
707
|
+
if (dangling.length > 0) {
|
|
708
|
+
return {
|
|
709
|
+
id: 'agent-docs',
|
|
710
|
+
label: 'AI agent docs',
|
|
711
|
+
status: 'fail',
|
|
712
|
+
message: dangling
|
|
713
|
+
.map(
|
|
714
|
+
({abs, target}) =>
|
|
715
|
+
`${shown(abs)} imports ${shown(target)}, which holds no Astryx block, so agents that read them get no Astryx docs.`,
|
|
716
|
+
)
|
|
717
|
+
.join(' '),
|
|
718
|
+
fix: fixFor(
|
|
719
|
+
`Write the block again with \`${getCliInvocation(ctx.cwd)} init --features agents\`.`,
|
|
720
|
+
),
|
|
721
|
+
};
|
|
722
|
+
}
|
|
723
|
+
|
|
652
724
|
if (withMarkers.length === 0) {
|
|
653
725
|
return {
|
|
654
726
|
id: 'agent-docs',
|
|
655
727
|
label: 'AI agent docs',
|
|
656
728
|
status: 'warn',
|
|
657
729
|
message: `Agent docs present (${present.map(shown).join(', ')}) but no Astryx section markers found.`,
|
|
658
|
-
fix:
|
|
730
|
+
fix: fixFor(
|
|
731
|
+
`Add the Astryx section to your agent docs with \`${getCliInvocation(ctx.cwd)} init --features agents\`.`,
|
|
732
|
+
),
|
|
659
733
|
};
|
|
660
734
|
}
|
|
661
735
|
|
|
@@ -974,16 +1048,20 @@ function nameTypes(names) {
|
|
|
974
1048
|
}
|
|
975
1049
|
|
|
976
1050
|
/**
|
|
977
|
-
* The section keys
|
|
978
|
-
* command reads them.
|
|
1051
|
+
* The section keys the field reference lists (`astryx docs
|
|
1052
|
+
* authoring/field-reference --index`), read the way that command reads them.
|
|
979
1053
|
* @returns {Promise<{keys: Set<string>} | {keys: null, error: string}>}
|
|
980
1054
|
*/
|
|
981
1055
|
async function authoringTopicKeys() {
|
|
982
1056
|
try {
|
|
1057
|
+
const {AUTHORING_REFERENCE_ROUTE} =
|
|
1058
|
+
await import('../../foundation/discovery/authoring-self-docs.mjs');
|
|
983
1059
|
const catalog = DocsCatalog.fromBuiltins();
|
|
984
|
-
const
|
|
985
|
-
if (!
|
|
986
|
-
|
|
1060
|
+
const node = (await projectTree(catalog)).get(AUTHORING_REFERENCE_ROUTE);
|
|
1061
|
+
if (!node?.ref?.topicFile) {
|
|
1062
|
+
return {keys: null, error: 'the docs tree has no field reference'};
|
|
1063
|
+
}
|
|
1064
|
+
const index = indexView(await lowerTopic(catalog, guideEntry(node)));
|
|
987
1065
|
return {keys: new Set(index.sections.map(section => section.id))};
|
|
988
1066
|
} catch (err) {
|
|
989
1067
|
return {
|
|
@@ -1002,7 +1080,7 @@ function surfaceProblems(surface) {
|
|
|
1002
1080
|
const problems = [];
|
|
1003
1081
|
if (surface.types === 0 && surface.untraced.length === 0) {
|
|
1004
1082
|
problems.push(
|
|
1005
|
-
`@astryxdesign/cli/authoring exports no types, so nothing was compared with \`${formatCliCommand('docs authoring')}\``,
|
|
1083
|
+
`@astryxdesign/cli/authoring exports no types, so nothing was compared with \`${formatCliCommand('docs authoring/field-reference')}\``,
|
|
1006
1084
|
);
|
|
1007
1085
|
}
|
|
1008
1086
|
for (const {module, names, reason, source, key} of surface.unreadable) {
|
|
@@ -1015,7 +1093,7 @@ function surfaceProblems(surface) {
|
|
|
1015
1093
|
? `${source} does not load`
|
|
1016
1094
|
: `${source} renders section "${key}", which the topic's index does not list`;
|
|
1017
1095
|
problems.push(
|
|
1018
|
-
`${nameTypes(names)} from ${module} ${names.length === 1 ? 'has' : 'have'} no doc in \`${formatCliCommand('docs authoring')}\`: ${why}`,
|
|
1096
|
+
`${nameTypes(names)} from ${module} ${names.length === 1 ? 'has' : 'have'} no doc in \`${formatCliCommand('docs authoring/field-reference')}\`: ${why}`,
|
|
1019
1097
|
);
|
|
1020
1098
|
}
|
|
1021
1099
|
for (const {name, reason} of surface.untraced) {
|
|
@@ -1056,7 +1134,7 @@ export async function checkAuthoringDocs(_ctx, options = {}) {
|
|
|
1056
1134
|
const audit = await auditAuthoringSelfDocs({root, sources});
|
|
1057
1135
|
const problems = [
|
|
1058
1136
|
...audit.unreachable.map(
|
|
1059
|
-
source => `${source} is not in \`${formatCliCommand('docs authoring')}\``,
|
|
1137
|
+
source => `${source} is not in \`${formatCliCommand('docs authoring/field-reference')}\``,
|
|
1060
1138
|
),
|
|
1061
1139
|
...audit.failed.map(
|
|
1062
1140
|
({source, error}) => `${source} failed to load: ${error}`,
|
|
@@ -1072,7 +1150,7 @@ export async function checkAuthoringDocs(_ctx, options = {}) {
|
|
|
1072
1150
|
: {keys: options.topicKeys};
|
|
1073
1151
|
const surface = [
|
|
1074
1152
|
...('error' in topic
|
|
1075
|
-
? [`\`${formatCliCommand('docs authoring')}\` could not be read: ${topic.error}`]
|
|
1153
|
+
? [`\`${formatCliCommand('docs authoring/field-reference')}\` could not be read: ${topic.error}`]
|
|
1076
1154
|
: []),
|
|
1077
1155
|
...surfaceProblems(
|
|
1078
1156
|
await auditAuthoringSurface({root, sources, topicKeys: topic.keys}),
|
|
@@ -1096,7 +1174,7 @@ export async function checkAuthoringDocs(_ctx, options = {}) {
|
|
|
1096
1174
|
id,
|
|
1097
1175
|
label,
|
|
1098
1176
|
status: 'pass',
|
|
1099
|
-
message: `All ${audit.sections} authoring schemas are readable in \`${formatCliCommand('docs authoring')}\`.`,
|
|
1177
|
+
message: `All ${audit.sections} authoring schemas are readable in \`${formatCliCommand('docs authoring/field-reference')}\`.`,
|
|
1100
1178
|
};
|
|
1101
1179
|
} catch (err) {
|
|
1102
1180
|
return {
|
|
@@ -1164,7 +1242,7 @@ export async function checkCliDocs(_ctx, options = {}) {
|
|
|
1164
1242
|
id,
|
|
1165
1243
|
label,
|
|
1166
1244
|
status: 'pass',
|
|
1167
|
-
message: `All ${audit.docs} CLI docs are readable: ${audit.tree} in the \`${formatCliCommand('docs cli')}\` tree and ${audit.authoring} in \`${formatCliCommand('docs authoring')}\`.`,
|
|
1245
|
+
message: `All ${audit.docs} CLI docs are readable: ${audit.tree} in the \`${formatCliCommand('docs cli')}\` tree and ${audit.authoring} in \`${formatCliCommand('docs authoring/field-reference')}\`.`,
|
|
1168
1246
|
};
|
|
1169
1247
|
} catch (err) {
|
|
1170
1248
|
return {
|
|
@@ -1281,7 +1359,7 @@ export async function checkDocsProgressiveDisclosure(ctx) {
|
|
|
1281
1359
|
// A guide the docs tree places is a topic read by its route; it is held
|
|
1282
1360
|
// to the same budget as every flat topic.
|
|
1283
1361
|
const guides = [...(await projectTree(catalog)).nodes.values()]
|
|
1284
|
-
// A flat topic in
|
|
1362
|
+
// A flat topic in a topic level is checked above, as a topic.
|
|
1285
1363
|
.filter(node => node.kind === 'generic' && !node.ref?.flatTopic)
|
|
1286
1364
|
.map(guideEntry);
|
|
1287
1365
|
for (const entry of [...catalog.entries(), ...guides]) {
|
|
@@ -652,7 +652,7 @@ describe('checkAuthoringDocs', () => {
|
|
|
652
652
|
it('passes when every authoring self-doc is reachable and fits one read', async () => {
|
|
653
653
|
const c = await checkAuthoringDocs();
|
|
654
654
|
expect(c).toMatchObject({id: 'authoring-docs', status: 'pass'});
|
|
655
|
-
expect(c.message).toContain(formatCliCommand('docs authoring'));
|
|
655
|
+
expect(c.message).toContain(formatCliCommand('docs authoring/field-reference'));
|
|
656
656
|
}, SLOW);
|
|
657
657
|
});
|
|
658
658
|
|
|
@@ -680,7 +680,7 @@ describe('checkCliDocs', () => {
|
|
|
680
680
|
id: 'cli-docs',
|
|
681
681
|
label: 'CLI docs',
|
|
682
682
|
status: 'pass',
|
|
683
|
-
message: `All ${audit.docs} CLI docs are readable: ${audit.tree} in the \`${formatCliCommand('docs cli')}\` tree and ${audit.authoring} in \`${formatCliCommand('docs authoring')}\`.`,
|
|
683
|
+
message: `All ${audit.docs} CLI docs are readable: ${audit.tree} in the \`${formatCliCommand('docs cli')}\` tree and ${audit.authoring} in \`${formatCliCommand('docs authoring/field-reference')}\`.`,
|
|
684
684
|
});
|
|
685
685
|
},
|
|
686
686
|
SLOW,
|
|
@@ -790,7 +790,7 @@ describe('checkDocsTree', () => {
|
|
|
790
790
|
describe('checkAuthoringDocs against the public authoring surface', () => {
|
|
791
791
|
const NAMESPACE = 'doctypes/namespace/namespace.doc.mjs';
|
|
792
792
|
const NAMESPACE_TYPES =
|
|
793
|
-
`NamespaceDoc, NamespaceProviderScope, NamespaceSlotAcceptance, NamespaceSlot, NamespaceAdoptionSource, NamespaceAdoptionRule from doctypes/namespace/type.ts have no doc in \`${formatCliCommand('docs authoring')}\``;
|
|
793
|
+
`NamespaceDoc, NamespaceProviderScope, NamespaceSlotAcceptance, NamespaceSlot, NamespaceAdoptionSource, NamespaceAdoptionRule from doctypes/namespace/type.ts have no doc in \`${formatCliCommand('docs authoring/field-reference')}\``;
|
|
794
794
|
const SURFACE_FIX =
|
|
795
795
|
'Put a self-doc beside each module whose types @astryxdesign/cli/authoring exports and list it in AUTHORING_SELF_DOCS; export what each listed self-doc documents, or remove that self-doc.';
|
|
796
796
|
|
|
@@ -820,7 +820,7 @@ describe('checkAuthoringDocs against the public authoring surface', () => {
|
|
|
820
820
|
id: 'authoring-docs',
|
|
821
821
|
label: 'Authoring docs',
|
|
822
822
|
status: 'pass',
|
|
823
|
-
message: `All ${AUTHORING_SELF_DOCS.length} authoring schemas are readable in \`${formatCliCommand('docs authoring')}\`.`,
|
|
823
|
+
message: `All ${AUTHORING_SELF_DOCS.length} authoring schemas are readable in \`${formatCliCommand('docs authoring/field-reference')}\`.`,
|
|
824
824
|
});
|
|
825
825
|
},
|
|
826
826
|
SLOW,
|
|
@@ -849,7 +849,7 @@ describe('checkAuthoringDocs against the public authoring surface', () => {
|
|
|
849
849
|
});
|
|
850
850
|
expect(c.status).toBe('fail');
|
|
851
851
|
expect(c.message).toBe(
|
|
852
|
-
`2 problems: ${NAMESPACE} is not in \`${formatCliCommand('docs authoring')}\`; ${NAMESPACE_TYPES}: ${NAMESPACE} is not listed in AUTHORING_SELF_DOCS`,
|
|
852
|
+
`2 problems: ${NAMESPACE} is not in \`${formatCliCommand('docs authoring/field-reference')}\`; ${NAMESPACE_TYPES}: ${NAMESPACE} is not listed in AUTHORING_SELF_DOCS`,
|
|
853
853
|
);
|
|
854
854
|
},
|
|
855
855
|
SLOW,
|
|
@@ -858,7 +858,7 @@ describe('checkAuthoringDocs against the public authoring surface', () => {
|
|
|
858
858
|
it(
|
|
859
859
|
"fails when the topic's index no longer exposes the NamespaceDoc section",
|
|
860
860
|
async () => {
|
|
861
|
-
const index = await docs('authoring', undefined, {index: true});
|
|
861
|
+
const index = await docs('authoring/field-reference', undefined, {index: true});
|
|
862
862
|
const topicKeys = new Set(
|
|
863
863
|
index.data.sections
|
|
864
864
|
.map((/** @type {any} */ s) => s.id)
|
|
@@ -947,7 +947,7 @@ describe('checkAuthoringDocs against the public authoring surface', () => {
|
|
|
947
947
|
expect(c.fix).toBe(SURFACE_FIX);
|
|
948
948
|
expect(c.message).toMatch(
|
|
949
949
|
new RegExp(
|
|
950
|
-
`^[A-Za-z, ]+ from ${escape(module)} have no doc in \`${escape(formatCliCommand('docs authoring'))}\`: no self-doc sits beside ${escape(module)}$`,
|
|
950
|
+
`^[A-Za-z, ]+ from ${escape(module)} have no doc in \`${escape(formatCliCommand('docs authoring/field-reference'))}\`: no self-doc sits beside ${escape(module)}$`,
|
|
951
951
|
),
|
|
952
952
|
);
|
|
953
953
|
for (const name of names) {
|
|
@@ -990,7 +990,7 @@ describe('checkAuthoringDocs against the public authoring surface', () => {
|
|
|
990
990
|
expect(await checkAuthoringDocs()).toMatchObject({
|
|
991
991
|
status: 'fail',
|
|
992
992
|
message:
|
|
993
|
-
`\`${formatCliCommand('docs authoring')}\` could not be read: no built-in docs`,
|
|
993
|
+
`\`${formatCliCommand('docs authoring/field-reference')}\` could not be read: no built-in docs`,
|
|
994
994
|
fix: SURFACE_FIX,
|
|
995
995
|
});
|
|
996
996
|
} finally {
|
|
@@ -1011,7 +1011,7 @@ describe('checkAuthoringDocs against the public authoring surface', () => {
|
|
|
1011
1011
|
const c = await checkAuthoringDocs(undefined, {root});
|
|
1012
1012
|
expect(c.status).toBe('fail');
|
|
1013
1013
|
expect(c.message).toContain(
|
|
1014
|
-
`@astryxdesign/cli/authoring exports no types, so nothing was compared with \`${formatCliCommand('docs authoring')}\``,
|
|
1014
|
+
`@astryxdesign/cli/authoring exports no types, so nothing was compared with \`${formatCliCommand('docs authoring/field-reference')}\``,
|
|
1015
1015
|
);
|
|
1016
1016
|
},
|
|
1017
1017
|
SLOW,
|
|
@@ -1317,8 +1317,12 @@ describe('a configured integration that cannot load fails the gate', () => {
|
|
|
1317
1317
|
'astryx.config.mjs': "export default { integrations: ['@acme/widgets'] };\n",
|
|
1318
1318
|
};
|
|
1319
1319
|
|
|
1320
|
-
/**
|
|
1321
|
-
|
|
1320
|
+
/**
|
|
1321
|
+
* Run doctor on a project under the working directory, in its folder `at`.
|
|
1322
|
+
* @param {Record<string, string>} files
|
|
1323
|
+
* @param {string} [at]
|
|
1324
|
+
*/
|
|
1325
|
+
async function report(files, at = '.') {
|
|
1322
1326
|
const dir = fs.mkdtempSync(path.join(process.cwd(), '.astryx-doctor-gate-'));
|
|
1323
1327
|
tmpDirs.push(dir);
|
|
1324
1328
|
for (const [rel, content] of Object.entries(files)) {
|
|
@@ -1326,7 +1330,7 @@ describe('a configured integration that cannot load fails the gate', () => {
|
|
|
1326
1330
|
fs.mkdirSync(path.dirname(abs), {recursive: true});
|
|
1327
1331
|
fs.writeFileSync(abs, content);
|
|
1328
1332
|
}
|
|
1329
|
-
const {checks, summary} = (await doctor({cwd: dir})).data;
|
|
1333
|
+
const {checks, summary} = (await doctor({cwd: path.join(dir, at)})).data;
|
|
1330
1334
|
return {by: Object.fromEntries(checks.map(c => [c.id, c])), summary};
|
|
1331
1335
|
}
|
|
1332
1336
|
|
|
@@ -1354,6 +1358,27 @@ describe('a configured integration that cannot load fails the gate', () => {
|
|
|
1354
1358
|
SLOW,
|
|
1355
1359
|
);
|
|
1356
1360
|
|
|
1361
|
+
it(
|
|
1362
|
+
'passes in a workspace member whose configured integration is hoisted to the root',
|
|
1363
|
+
async () => {
|
|
1364
|
+
const {by} = await report(
|
|
1365
|
+
{
|
|
1366
|
+
'package.json': JSON.stringify({name: 'root', private: true, workspaces: ['apps/*']}),
|
|
1367
|
+
...CORE_STUB,
|
|
1368
|
+
...widgets(),
|
|
1369
|
+
'apps/web/package.json': '{"name":"web"}',
|
|
1370
|
+
'apps/web/astryx.config.mjs': "export default { integrations: ['@acme/widgets'] };\n",
|
|
1371
|
+
},
|
|
1372
|
+
'apps/web',
|
|
1373
|
+
);
|
|
1374
|
+
expect(by['configured-integrations'].status).toBe('pass');
|
|
1375
|
+
expect(by['configured-integrations'].message).toBe(
|
|
1376
|
+
'1 integration named in astryx.config loaded: @acme/widgets.',
|
|
1377
|
+
);
|
|
1378
|
+
},
|
|
1379
|
+
SLOW,
|
|
1380
|
+
);
|
|
1381
|
+
|
|
1357
1382
|
it(
|
|
1358
1383
|
'counts the package being authored when its own config names it',
|
|
1359
1384
|
async () => {
|
package/api/hook/hook.mjs
CHANGED
|
@@ -43,7 +43,7 @@ export async function hook(name, options = {}) {
|
|
|
43
43
|
zh = false,
|
|
44
44
|
} = options;
|
|
45
45
|
|
|
46
|
-
// Default detail level mirrors the CLI (see commands/hook
|
|
46
|
+
// Default detail level mirrors the CLI (see commands/hook.mjs):
|
|
47
47
|
// single-hook views default to 'full', list-style views (--list,
|
|
48
48
|
// --category, or no name) default to 'brief' (scannable name lists).
|
|
49
49
|
// Keeping this in sync with the CLI is what the API↔CLI parity test checks.
|
package/api/init/init.doc.mjs
CHANGED
|
@@ -17,11 +17,22 @@ export const doc = {
|
|
|
17
17
|
'Non-interactive project setup: install agent docs and point at the theme + build workflows.',
|
|
18
18
|
description:
|
|
19
19
|
'Sets a project up with NO prompts, so it behaves identically for humans, ' +
|
|
20
|
-
'agents, CI, and piped I/O. By default it
|
|
21
|
-
'
|
|
20
|
+
'agents, CI, and piped I/O. By default it writes the agent-docs cheat sheet, ' +
|
|
21
|
+
'including guidance from configured integrations, at the project root (the nearest ' +
|
|
22
|
+
'package.json that declares an @astryxdesign package, else the nearest package.json, ' +
|
|
23
|
+
'searching no higher than the repository root): to AGENTS.md, ' +
|
|
24
|
+
"to the project's Claude Code file (CLAUDE.md, else .claude/CLAUDE.md; when CLAUDE.md " +
|
|
25
|
+
'exists, a block in .claude/CLAUDE.md is removed, unless the project ignores CLAUDE.md, in which case a ' +
|
|
26
|
+
'.claude/CLAUDE.md the project commits keeps a copy), and as a ' +
|
|
27
|
+
'one-line import of AGENTS.md in GEMINI.md unless GEMINI.md already imports it. ' +
|
|
28
|
+
'In the home folder, or in a settings folder in it outside a project, it writes none: every ' +
|
|
29
|
+
'folder of the home folder whose name starts with a dot is a settings folder, and such a folder itself never ' +
|
|
30
|
+
'counts as a project, even with a package.json; a folder below it with a package.json does. ' +
|
|
31
|
+
'The managed block is Astryx-owned: it is written, refreshed, and removed whatever ignore rules ' +
|
|
32
|
+
'or generated markers say, and the text around it is never changed. It then ' +
|
|
22
33
|
"prints getting-started guidance; `features` / `all` print only the chosen features' " +
|
|
23
34
|
'guidance instead (the theme feature also writes the annotated theme template). ' +
|
|
24
|
-
'With `removeAgents` it removes the managed agent-docs block instead of installing. ' +
|
|
35
|
+
'With `removeAgents` it removes the managed agent-docs block, at the project root and in `ctx.cwd`, instead of installing. ' +
|
|
25
36
|
'Outside a project it writes the same files but prints no getting-started steps and no step that adds a theme to an app, since those set up a project the folder does not have. ' +
|
|
26
37
|
"With `user` it sets up the computer instead of the folder: it writes the computer-level agent text, one skill file at `~/.agents/skills/astryx/SKILL.md`, linked into the skill folders of agents that read only their own (`~/.claude/skills` always; Kiro, Windsurf, Letta, Xcode's coding assistant, and `~/.config/agents/skills` when that folder exists), with a managed copy for Continue, whose scanner skips links,, telling agents anywhere on the computer that Astryx is there and when to use it; with `user` and `removeAgents` it removes the file and the links it made and records that the text is turned off. " +
|
|
27
38
|
'The CLI installed for the computer refreshes the file in the background after each upgrade; package install scripts, project setup, and upgrade never write it.' +
|
|
@@ -46,7 +57,7 @@ export const doc = {
|
|
|
46
57
|
name: 'options.removeAgents',
|
|
47
58
|
type: 'boolean',
|
|
48
59
|
description:
|
|
49
|
-
'Remove the managed agent-docs block instead of installing. With `user`, remove the computer-level agent text instead.',
|
|
60
|
+
'Remove the managed agent-docs block, at the project root and in `ctx.cwd`, instead of installing. With `user`, remove the computer-level agent text instead.',
|
|
50
61
|
},
|
|
51
62
|
{
|
|
52
63
|
name: 'options.user',
|
|
@@ -62,7 +73,10 @@ export const doc = {
|
|
|
62
73
|
name: 'options.agent',
|
|
63
74
|
type: 'string',
|
|
64
75
|
description:
|
|
65
|
-
'Agent preset: claude, cursor, codex, hermes, muse, all.
|
|
76
|
+
'Agent preset: claude, cursor, codex, hermes, muse, all. `all` writes every existing agent doc except GEMINI.md, ' +
|
|
77
|
+
'which keeps its one-line import of AGENTS.md. With claude and all, when CLAUDE.md gets the block, a block in ' +
|
|
78
|
+
'.claude/CLAUDE.md is removed, unless the project ignores CLAUDE.md, in which case a .claude/CLAUDE.md the ' +
|
|
79
|
+
'project commits gets a copy too. Used only when the agents feature runs. Refused with `user`.',
|
|
66
80
|
},
|
|
67
81
|
{
|
|
68
82
|
name: 'options.agentDocsPath',
|
|
@@ -122,7 +136,7 @@ export const doc = {
|
|
|
122
136
|
},
|
|
123
137
|
{
|
|
124
138
|
code: 'ERR_PATH_TRAVERSAL',
|
|
125
|
-
when: 'the template output path resolves outside cwd (for example through a symlinked src directory), or, with removeAgents, a managed agent-docs file resolves outside
|
|
139
|
+
when: 'the template output path resolves outside cwd (for example through a symlinked src directory), or, with removeAgents, a managed agent-docs file in cwd, or at the project root when run there, resolves outside that folder through a symlink (run below the root, a project-root file is left as it is with a note)',
|
|
126
140
|
},
|
|
127
141
|
],
|
|
128
142
|
examples: [
|