@astryxdesign/cli 0.7.2 → 0.7.3-canary.06872b4
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 +99 -66
- 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 +16 -2
- package/api/component/component.test.mjs +15 -0
- package/api/discover/_adapter.mjs +36 -9
- package/api/discover/_adapter.test.mjs +42 -0
- package/api/docs/_adapter.mjs +17 -5
- package/api/docs/docs.test.mjs +7 -1
- package/api/doctor/doctor.mjs +86 -12
- package/api/doctor/doctor.test.mjs +28 -3
- 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/authoring-checks.mjs +83 -9
- 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 +226 -32
- package/api/integration/validate-integration.type.d.mts +58 -1
- package/api/integration/validate-integration.type.mjs +45 -2
- package/api/integration/validateIntegration.doc.mjs +1 -1
- package/api/search/ORDERING.md +28 -0
- package/api/search/_adapter.d.mts +66 -2
- package/api/search/_adapter.mjs +118 -10
- 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 +158 -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 +7 -5
- package/api/search/search.mjs +53 -2483
- 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/is-my-code-good.doc.mjs +287 -0
- package/assets/docs/tree/api.doc.mjs +6 -0
- package/assets/docs/tree/host-entry.doc.mjs +128 -0
- package/assets/docs/tree/template-grading-rubric.doc.mjs +16 -37
- package/assets/docs/tree/tokens-data.doc.mjs +2 -2
- 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/clients/cli/bin/astryx.mjs +7 -78
- package/clients/cli/commands/doctor.mjs +30 -0
- package/clients/cli/commands/doctor.test.mjs +65 -0
- 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/outside-project.test.mjs +2 -1
- package/clients/cli/commands/setup-nudge.test.mjs +61 -0
- 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 +19 -1
- 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 +1010 -99
- package/foundation/agent-docs/agent-docs.path-safety.test.mjs +1239 -17
- package/foundation/agent-docs/agent-docs.test.mjs +678 -35
- package/foundation/config/project.mjs +20 -22
- package/foundation/config/project.test.mjs +56 -0
- 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/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 +8 -0
- package/foundation/doc-compiler/read.mjs +59 -1
- package/foundation/doc-compiler/read.test.mjs +11 -2
- 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/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
|
@@ -23,7 +23,55 @@
|
|
|
23
23
|
* @property {boolean} [registry]
|
|
24
24
|
*/
|
|
25
25
|
/**
|
|
26
|
-
*
|
|
26
|
+
* Where an upgrade runs: the root of the Astryx project `cwd` belongs to, the
|
|
27
|
+
* nearest folder at or above it whose package.json declares an Astryx
|
|
28
|
+
* package or that an Astryx workspace lists as a member, so a run from any
|
|
29
|
+
* folder inside a project upgrades that project exactly as a run from its
|
|
30
|
+
* root does. Its source, config, agent docs and
|
|
31
|
+
* protection declarations all live there. The search stops at a repository
|
|
32
|
+
* root and ends at the home folder without counting it (see
|
|
33
|
+
* `findAstryxProject`). A `path` the caller names, in any spelling (`./src`,
|
|
34
|
+
* `src`, `src/`), is read from `cwd`, where they typed it. With no `path`,
|
|
35
|
+
* the upgrade scans `./src` at the project root. With no Astryx project, the
|
|
36
|
+
* upgrade runs in `cwd` as released versions did.
|
|
37
|
+
* @param {UpgradeOptions} options
|
|
38
|
+
* @param {string} cwd
|
|
39
|
+
* @returns {{options: UpgradeOptions, cwd: string, origin?: string}} `origin`
|
|
40
|
+
* is the folder the command ran in, when the project root is above it
|
|
41
|
+
*/
|
|
42
|
+
export function scopeToProject(options: UpgradeOptions, cwd: string): {
|
|
43
|
+
options: UpgradeOptions;
|
|
44
|
+
cwd: string;
|
|
45
|
+
origin?: string;
|
|
46
|
+
};
|
|
47
|
+
/**
|
|
48
|
+
* The result of an upgrade that ran at a project root above the folder the
|
|
49
|
+
* command ran in, with its file paths made relative to that folder, so each
|
|
50
|
+
* resolves from where the command ran: `modifiedFiles`, `agentDocs.files`, and
|
|
51
|
+
* the `file` of each `protectedFiles`, `declinedCandidates` and `errors`
|
|
52
|
+
* entry. The registry step names copied-composition paths from that folder
|
|
53
|
+
* itself (see `reconcileRegistryCompositions`), so they pass through. A
|
|
54
|
+
* result of a run at the project root is returned as it is.
|
|
55
|
+
* @template {{type: string, data: object}} T
|
|
56
|
+
* @param {T} result
|
|
57
|
+
* @param {{cwd: string, origin?: string}} scope from `scopeToProject`
|
|
58
|
+
* @returns {T}
|
|
59
|
+
*/
|
|
60
|
+
export function relativeToOrigin<T extends {
|
|
61
|
+
type: string;
|
|
62
|
+
data: object;
|
|
63
|
+
}>(result: T, { cwd: root, origin }: {
|
|
64
|
+
cwd: string;
|
|
65
|
+
origin?: string;
|
|
66
|
+
}): T;
|
|
67
|
+
/**
|
|
68
|
+
* Detect the installed target version: the Core the Astryx project of `cwd`
|
|
69
|
+
* installed, in its own node_modules or, for a member its workspace lists, in
|
|
70
|
+
* a folder up to the workspace root. The nearest folder wins, the current
|
|
71
|
+
* name before the legacy one, then Yarn Plug'n'Play. A Core above a project
|
|
72
|
+
* no workspace lists does not count, so a nested project that has not
|
|
73
|
+
* installed its own reports nothing installed. With no Astryx project, only
|
|
74
|
+
* the node_modules of `cwd` itself is read, as released versions did.
|
|
27
75
|
* @param {string} cwd
|
|
28
76
|
* @returns {{version: string, packageName: string}|null}
|
|
29
77
|
*/
|
|
@@ -84,25 +132,20 @@ export function runPostCodemodHooks(hooks: import("../../authoring/config/type")
|
|
|
84
132
|
files: string[];
|
|
85
133
|
apply: boolean;
|
|
86
134
|
}): Promise<void>;
|
|
87
|
-
/**
|
|
88
|
-
* @typedef {object} AgentDocsRefreshPlan
|
|
89
|
-
* @property {string} cwd
|
|
90
|
-
* @property {string|null} renderedBlock
|
|
91
|
-
* @property {import('./upgrade.type.mjs').AgentDocsSummary} summary
|
|
92
|
-
*/
|
|
93
135
|
/**
|
|
94
136
|
* Compute the expected managed block and report staleness without writing.
|
|
95
137
|
* Apply-mode callers commit the prepared bytes only after codemods and hooks
|
|
96
138
|
* succeed.
|
|
97
139
|
*
|
|
98
|
-
* @param {{cwd: string, installedVersion: string, apply: boolean, fresh?: boolean}} ctx
|
|
140
|
+
* @param {{cwd: string, installedVersion: string, apply: boolean, fresh?: boolean, origin?: string}} ctx
|
|
99
141
|
* @returns {Promise<AgentDocsRefreshPlan>}
|
|
100
142
|
*/
|
|
101
|
-
export function prepareAgentDocsRefresh({ cwd, installedVersion, apply, fresh, }: {
|
|
143
|
+
export function prepareAgentDocsRefresh({ cwd, installedVersion, apply, fresh, origin, }: {
|
|
102
144
|
cwd: string;
|
|
103
145
|
installedVersion: string;
|
|
104
146
|
apply: boolean;
|
|
105
147
|
fresh?: boolean;
|
|
148
|
+
origin?: string;
|
|
106
149
|
}): Promise<AgentDocsRefreshPlan>;
|
|
107
150
|
/**
|
|
108
151
|
* Commit a prepared agent-doc refresh.
|
|
@@ -288,6 +331,11 @@ export type UpgradeOptions = {
|
|
|
288
331
|
};
|
|
289
332
|
export type AgentDocsRefreshPlan = {
|
|
290
333
|
cwd: string;
|
|
334
|
+
/**
|
|
335
|
+
* the folder the command ran in, when the upgrade
|
|
336
|
+
* runs at a project root above it
|
|
337
|
+
*/
|
|
338
|
+
origin?: string | undefined;
|
|
291
339
|
renderedBlock: string | null;
|
|
292
340
|
summary: import("./upgrade.type.mjs").AgentDocsSummary;
|
|
293
341
|
};
|
package/api/upgrade/_adapter.mjs
CHANGED
|
@@ -30,6 +30,8 @@ import {
|
|
|
30
30
|
} from '../../assets/codemods/integration-discovery.mjs';
|
|
31
31
|
import {runIntegrationCodemods} from '../../assets/codemods/integration-runner.mjs';
|
|
32
32
|
import {
|
|
33
|
+
AgentDocsHomeError,
|
|
34
|
+
assertAgentDocsTarget,
|
|
33
35
|
installAgentDocs,
|
|
34
36
|
inspectAgentDocs,
|
|
35
37
|
renderAgentDocsBlock,
|
|
@@ -42,7 +44,11 @@ import {
|
|
|
42
44
|
quoteCommandArgument,
|
|
43
45
|
} from '../../foundation/env/package-manager.mjs';
|
|
44
46
|
import {isValidSemver, semverGt} from '../../foundation/env/semver.mjs';
|
|
45
|
-
import {
|
|
47
|
+
import {
|
|
48
|
+
CLI_ROOT,
|
|
49
|
+
findAstryxProject,
|
|
50
|
+
findProjectPackageOf,
|
|
51
|
+
} from '../../foundation/fs/paths.mjs';
|
|
46
52
|
import {Project, providerLedgerOf} from '../../foundation/config/project.mjs';
|
|
47
53
|
import {loadIntegrations} from '../../foundation/integrations/integrations.mjs';
|
|
48
54
|
import {resolveProviders} from '../../foundation/integrations/provider-resolution.mjs';
|
|
@@ -82,26 +88,125 @@ const execFileAsync = promisify(execFile);
|
|
|
82
88
|
*/
|
|
83
89
|
|
|
84
90
|
/**
|
|
85
|
-
*
|
|
91
|
+
* Where an upgrade runs: the root of the Astryx project `cwd` belongs to, the
|
|
92
|
+
* nearest folder at or above it whose package.json declares an Astryx
|
|
93
|
+
* package or that an Astryx workspace lists as a member, so a run from any
|
|
94
|
+
* folder inside a project upgrades that project exactly as a run from its
|
|
95
|
+
* root does. Its source, config, agent docs and
|
|
96
|
+
* protection declarations all live there. The search stops at a repository
|
|
97
|
+
* root and ends at the home folder without counting it (see
|
|
98
|
+
* `findAstryxProject`). A `path` the caller names, in any spelling (`./src`,
|
|
99
|
+
* `src`, `src/`), is read from `cwd`, where they typed it. With no `path`,
|
|
100
|
+
* the upgrade scans `./src` at the project root. With no Astryx project, the
|
|
101
|
+
* upgrade runs in `cwd` as released versions did.
|
|
102
|
+
* @param {UpgradeOptions} options
|
|
103
|
+
* @param {string} cwd
|
|
104
|
+
* @returns {{options: UpgradeOptions, cwd: string, origin?: string}} `origin`
|
|
105
|
+
* is the folder the command ran in, when the project root is above it
|
|
106
|
+
*/
|
|
107
|
+
export function scopeToProject(options, cwd) {
|
|
108
|
+
const here = path.resolve(cwd);
|
|
109
|
+
const root = findAstryxProject(here) ?? here;
|
|
110
|
+
if (root === here) return {options, cwd};
|
|
111
|
+
const namedPath =
|
|
112
|
+
options.path == null ? {} : {path: path.resolve(here, options.path)};
|
|
113
|
+
return {options: {...options, ...namedPath}, cwd: root, origin: here};
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
/**
|
|
117
|
+
* The result of an upgrade that ran at a project root above the folder the
|
|
118
|
+
* command ran in, with its file paths made relative to that folder, so each
|
|
119
|
+
* resolves from where the command ran: `modifiedFiles`, `agentDocs.files`, and
|
|
120
|
+
* the `file` of each `protectedFiles`, `declinedCandidates` and `errors`
|
|
121
|
+
* entry. The registry step names copied-composition paths from that folder
|
|
122
|
+
* itself (see `reconcileRegistryCompositions`), so they pass through. A
|
|
123
|
+
* result of a run at the project root is returned as it is.
|
|
124
|
+
* @template {{type: string, data: object}} T
|
|
125
|
+
* @param {T} result
|
|
126
|
+
* @param {{cwd: string, origin?: string}} scope from `scopeToProject`
|
|
127
|
+
* @returns {T}
|
|
128
|
+
*/
|
|
129
|
+
export function relativeToOrigin(result, {cwd: root, origin}) {
|
|
130
|
+
if (origin == null) return result;
|
|
131
|
+
/** @param {string} file */
|
|
132
|
+
const rebase = file =>
|
|
133
|
+
path.relative(origin, path.resolve(root, file)).split(path.sep).join('/') ||
|
|
134
|
+
'.';
|
|
135
|
+
/** @type {Record<string, any>} */
|
|
136
|
+
const data = {...result.data};
|
|
137
|
+
if (data.agentDocs) {
|
|
138
|
+
data.agentDocs = {
|
|
139
|
+
...data.agentDocs,
|
|
140
|
+
files: data.agentDocs.files.map(rebase),
|
|
141
|
+
};
|
|
142
|
+
}
|
|
143
|
+
if (data.modifiedFiles) data.modifiedFiles = data.modifiedFiles.map(rebase);
|
|
144
|
+
for (const key of ['protectedFiles', 'declinedCandidates', 'errors']) {
|
|
145
|
+
if (data[key]) {
|
|
146
|
+
data[key] = data[key].map(
|
|
147
|
+
(/** @type {{file: string, declarations?: string[]}} */ entry) => ({
|
|
148
|
+
...entry,
|
|
149
|
+
file: rebase(entry.file),
|
|
150
|
+
...(Array.isArray(entry.declarations)
|
|
151
|
+
? {declarations: entry.declarations.map(rebaseDeclaration(rebase))}
|
|
152
|
+
: {}),
|
|
153
|
+
}),
|
|
154
|
+
);
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
return /** @type {T} */ ({...result, data});
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
/**
|
|
161
|
+
* The project-relative file a protection declaration names, and the text
|
|
162
|
+
* around it: the ignore or attributes file that protects a file (and its
|
|
163
|
+
* line), or the symbolic link on its path. Other declarations name no file.
|
|
164
|
+
*/
|
|
165
|
+
const DECLARATION_PATHS = [
|
|
166
|
+
/^(excluded by )(.+?)(:\d+)?$/u,
|
|
167
|
+
/^(linguist-(?:generated|vendored) in )(.+?)(:\d+)$/u,
|
|
168
|
+
/^(symbolic link at )(.+)()$/u,
|
|
169
|
+
];
|
|
170
|
+
|
|
171
|
+
/**
|
|
172
|
+
* A protection declaration with the file it names rebased, as `rebase` does
|
|
173
|
+
* for result paths.
|
|
174
|
+
* @param {(file: string) => string} rebase
|
|
175
|
+
* @returns {(declaration: string) => string}
|
|
176
|
+
*/
|
|
177
|
+
function rebaseDeclaration(rebase) {
|
|
178
|
+
return declaration => {
|
|
179
|
+
for (const pattern of DECLARATION_PATHS) {
|
|
180
|
+
const match = pattern.exec(declaration);
|
|
181
|
+
if (match) return `${match[1]}${rebase(match[2])}${match[3] ?? ''}`;
|
|
182
|
+
}
|
|
183
|
+
return declaration;
|
|
184
|
+
};
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
/**
|
|
188
|
+
* Detect the installed target version: the Core the Astryx project of `cwd`
|
|
189
|
+
* installed, in its own node_modules or, for a member its workspace lists, in
|
|
190
|
+
* a folder up to the workspace root. The nearest folder wins, the current
|
|
191
|
+
* name before the legacy one, then Yarn Plug'n'Play. A Core above a project
|
|
192
|
+
* no workspace lists does not count, so a nested project that has not
|
|
193
|
+
* installed its own reports nothing installed. With no Astryx project, only
|
|
194
|
+
* the node_modules of `cwd` itself is read, as released versions did.
|
|
86
195
|
* @param {string} cwd
|
|
87
196
|
* @returns {{version: string, packageName: string}|null}
|
|
88
197
|
*/
|
|
89
198
|
export function detectInstalledTargetVersion(cwd) {
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
'package.json',
|
|
199
|
+
const found = findProjectPackageOf(cwd, ['@astryxdesign/core', '@xds/core']);
|
|
200
|
+
if (!found) return null;
|
|
201
|
+
try {
|
|
202
|
+
const pkg = JSON.parse(
|
|
203
|
+
fs.readFileSync(path.join(found.packageDir, 'package.json'), 'utf-8'),
|
|
96
204
|
);
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
// Missing/unreadable — try the next supported package name.
|
|
102
|
-
}
|
|
205
|
+
return pkg.version ? {version: pkg.version, packageName: found.name} : null;
|
|
206
|
+
} catch {
|
|
207
|
+
// Unreadable package.json: no version to target.
|
|
208
|
+
return null;
|
|
103
209
|
}
|
|
104
|
-
return null;
|
|
105
210
|
}
|
|
106
211
|
|
|
107
212
|
/**
|
|
@@ -282,16 +387,47 @@ export async function runPostCodemodHooks(hooks, context) {
|
|
|
282
387
|
/**
|
|
283
388
|
* @typedef {object} AgentDocsRefreshPlan
|
|
284
389
|
* @property {string} cwd
|
|
390
|
+
* @property {string} [origin] the folder the command ran in, when the upgrade
|
|
391
|
+
* runs at a project root above it
|
|
285
392
|
* @property {string|null} renderedBlock
|
|
286
393
|
* @property {import('./upgrade.type.mjs').AgentDocsSummary} summary
|
|
287
394
|
*/
|
|
288
395
|
|
|
396
|
+
/**
|
|
397
|
+
* The advice to run `init`, phrased for where the command ran: when the
|
|
398
|
+
* upgrade runs at a project root above that folder, it names the root, so the
|
|
399
|
+
* agent docs are installed beside the project's package.json.
|
|
400
|
+
* @param {string} cwd the folder the upgrade runs at
|
|
401
|
+
* @param {string} [origin] the folder the command ran in
|
|
402
|
+
* @returns {string}
|
|
403
|
+
*/
|
|
404
|
+
function initAdvice(cwd, origin) {
|
|
405
|
+
const command = `\`${formatCliCommand('astryx init --features agents')}\``;
|
|
406
|
+
if (origin == null) return command;
|
|
407
|
+
return `${command} in ${path.relative(origin, cwd) || '.'} (the project root)`;
|
|
408
|
+
}
|
|
409
|
+
|
|
410
|
+
/**
|
|
411
|
+
* Why upgrade leaves the agent docs of a project at the home folder or the
|
|
412
|
+
* top of a settings folder, and what to do instead. init refuses the same
|
|
413
|
+
* folder, so the line never points at it.
|
|
414
|
+
* @param {AgentDocsHomeError} err
|
|
415
|
+
* @param {'stale' | 'missing'} [state] whether a block is there to refresh
|
|
416
|
+
* @returns {string}
|
|
417
|
+
*/
|
|
418
|
+
function homeRefusalLine(err, state = 'stale') {
|
|
419
|
+
const where = `${err.dir} is the home folder or a settings folder in it, which every project's agents read.`;
|
|
420
|
+
return state === 'missing'
|
|
421
|
+
? `Agent docs not installed: ${where} To have agent docs, move the project into a folder of its own, or add the Astryx block to its agent file by hand.`
|
|
422
|
+
: `Agent docs not refreshed: ${where} To keep agent docs, move the project into a folder of its own; otherwise update or remove the Astryx block there by hand.`;
|
|
423
|
+
}
|
|
424
|
+
|
|
289
425
|
/**
|
|
290
426
|
* Compute the expected managed block and report staleness without writing.
|
|
291
427
|
* Apply-mode callers commit the prepared bytes only after codemods and hooks
|
|
292
428
|
* succeed.
|
|
293
429
|
*
|
|
294
|
-
* @param {{cwd: string, installedVersion: string, apply: boolean, fresh?: boolean}} ctx
|
|
430
|
+
* @param {{cwd: string, installedVersion: string, apply: boolean, fresh?: boolean, origin?: string}} ctx
|
|
295
431
|
* @returns {Promise<AgentDocsRefreshPlan>}
|
|
296
432
|
*/
|
|
297
433
|
export async function prepareAgentDocsRefresh({
|
|
@@ -299,6 +435,7 @@ export async function prepareAgentDocsRefresh({
|
|
|
299
435
|
installedVersion,
|
|
300
436
|
apply,
|
|
301
437
|
fresh = false,
|
|
438
|
+
origin,
|
|
302
439
|
}) {
|
|
303
440
|
const initial = inspectAgentDocs(cwd, installedVersion);
|
|
304
441
|
/** @type {import('./upgrade.type.mjs').AgentDocsSummary} */
|
|
@@ -312,11 +449,21 @@ export async function prepareAgentDocsRefresh({
|
|
|
312
449
|
};
|
|
313
450
|
|
|
314
451
|
if (initial.status === 'missing') {
|
|
452
|
+
// init writes nothing in a project at the home folder or the top of a
|
|
453
|
+
// settings folder, so it is not the remedy there (INV31).
|
|
454
|
+
try {
|
|
455
|
+
assertAgentDocsTarget(cwd);
|
|
456
|
+
} catch (err) {
|
|
457
|
+
if (!(err instanceof AgentDocsHomeError)) throw err;
|
|
458
|
+
summary.action = 'error';
|
|
459
|
+
logger.warn(homeRefusalLine(err, 'missing'));
|
|
460
|
+
return {cwd, origin, renderedBlock: null, summary};
|
|
461
|
+
}
|
|
315
462
|
summary.action = 'nudge-init';
|
|
316
463
|
logger.warn(
|
|
317
|
-
`No Astryx agent-docs block found - AI agents have no component index. Run
|
|
464
|
+
`No Astryx agent-docs block found - AI agents have no component index. Run ${initAdvice(cwd, origin)} to install it.`,
|
|
318
465
|
);
|
|
319
|
-
return {cwd, renderedBlock: null, summary};
|
|
466
|
+
return {cwd, origin, renderedBlock: null, summary};
|
|
320
467
|
}
|
|
321
468
|
|
|
322
469
|
let renderedBlock;
|
|
@@ -329,16 +476,30 @@ export async function prepareAgentDocsRefresh({
|
|
|
329
476
|
summary.action = 'error';
|
|
330
477
|
summary.files = initial.files.map(file => file.path);
|
|
331
478
|
logger.warn(
|
|
332
|
-
`Could not render the expected agent docs. Run
|
|
479
|
+
`Could not render the expected agent docs. Run ${initAdvice(cwd, origin)} to update them manually.`,
|
|
333
480
|
);
|
|
334
|
-
return {cwd, renderedBlock: null, summary};
|
|
481
|
+
return {cwd, origin, renderedBlock: null, summary};
|
|
335
482
|
}
|
|
336
483
|
|
|
337
484
|
const inspection = inspectAgentDocs(cwd, installedVersion, renderedBlock);
|
|
338
485
|
summary.status = inspection.status;
|
|
339
486
|
summary.fromVersions = inspection.blockVersions;
|
|
340
487
|
summary.files = inspection.staleFiles;
|
|
341
|
-
if (inspection.status === 'current')
|
|
488
|
+
if (inspection.status === 'current') {
|
|
489
|
+
return {cwd, origin, renderedBlock, summary};
|
|
490
|
+
}
|
|
491
|
+
|
|
492
|
+
// A project at the home folder or the top of a settings folder is never
|
|
493
|
+
// refreshed (INV31): the dry run says so, as --apply does, rather than
|
|
494
|
+
// offering a refresh that would be refused.
|
|
495
|
+
try {
|
|
496
|
+
assertAgentDocsTarget(cwd);
|
|
497
|
+
} catch (err) {
|
|
498
|
+
if (!(err instanceof AgentDocsHomeError)) throw err;
|
|
499
|
+
summary.action = 'error';
|
|
500
|
+
logger.warn(homeRefusalLine(err));
|
|
501
|
+
return {cwd, origin, renderedBlock: null, summary};
|
|
502
|
+
}
|
|
342
503
|
|
|
343
504
|
summary.action = 'would-refresh';
|
|
344
505
|
if (!apply) {
|
|
@@ -346,7 +507,7 @@ export async function prepareAgentDocsRefresh({
|
|
|
346
507
|
`Agent docs differ from the installed Astryx and integration configuration. Re-run with --apply to refresh (${summary.files.join(', ')}).`,
|
|
347
508
|
);
|
|
348
509
|
}
|
|
349
|
-
return {cwd, renderedBlock, summary};
|
|
510
|
+
return {cwd, origin, renderedBlock, summary};
|
|
350
511
|
}
|
|
351
512
|
|
|
352
513
|
/**
|
|
@@ -355,7 +516,7 @@ export async function prepareAgentDocsRefresh({
|
|
|
355
516
|
* @returns {import('./upgrade.type.mjs').AgentDocsSummary}
|
|
356
517
|
*/
|
|
357
518
|
export function applyAgentDocsRefresh(plan) {
|
|
358
|
-
const {cwd, renderedBlock, summary} = plan;
|
|
519
|
+
const {cwd, origin, renderedBlock, summary} = plan;
|
|
359
520
|
if (summary.action !== 'would-refresh' || renderedBlock == null)
|
|
360
521
|
return summary;
|
|
361
522
|
|
|
@@ -363,6 +524,9 @@ export function applyAgentDocsRefresh(plan) {
|
|
|
363
524
|
const written = installAgentDocs(cwd, {
|
|
364
525
|
onlyReplace: true,
|
|
365
526
|
renderedBlock,
|
|
527
|
+
// A GEMINI.md that resolves outside the project is left as it is.
|
|
528
|
+
onSkipped: (file, reason) =>
|
|
529
|
+
logger.warn(`Note: ${file} left as it is (${reason}).`),
|
|
366
530
|
});
|
|
367
531
|
summary.refreshed = written.length > 0;
|
|
368
532
|
summary.files = written;
|
|
@@ -371,15 +535,21 @@ export function applyAgentDocsRefresh(plan) {
|
|
|
371
535
|
logger.log(`[ok] Agent docs refreshed -> ${written.join(', ')}`);
|
|
372
536
|
} else {
|
|
373
537
|
logger.warn(
|
|
374
|
-
`Agent docs look stale but couldn't be refreshed. Run
|
|
538
|
+
`Agent docs look stale but couldn't be refreshed. Run ${initAdvice(cwd, origin)} to reinstall the block.`,
|
|
375
539
|
);
|
|
376
540
|
}
|
|
377
|
-
} catch {
|
|
541
|
+
} catch (err) {
|
|
378
542
|
summary.action = 'error';
|
|
379
543
|
summary.refreshed = false;
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
544
|
+
if (err instanceof AgentDocsHomeError) {
|
|
545
|
+
// init refuses this folder too, so pointing at it would loop: say why,
|
|
546
|
+
// and what to do instead.
|
|
547
|
+
logger.warn(homeRefusalLine(err));
|
|
548
|
+
} else {
|
|
549
|
+
logger.warn(
|
|
550
|
+
`Could not refresh agent docs. Run ${initAdvice(cwd, origin)} to update them manually.`,
|
|
551
|
+
);
|
|
552
|
+
}
|
|
383
553
|
}
|
|
384
554
|
return summary;
|
|
385
555
|
}
|
|
@@ -4,14 +4,18 @@
|
|
|
4
4
|
/** @param {string} root */
|
|
5
5
|
export function discoverRegistryReceipts(root: string): string[];
|
|
6
6
|
/**
|
|
7
|
+
* Reported paths are relative to the scanned source folder, or, when `origin`
|
|
8
|
+
* names the folder the command ran in below the project root `cwd`, to that
|
|
9
|
+
* folder, so they resolve from where the command ran.
|
|
7
10
|
* @param {{apply?: boolean, path?: string}} options
|
|
8
|
-
* @param {{cwd?: string, fetchImpl?: typeof fetch, registryOrigin?: string, expectedVersion?: string, requireExpectedVersion?: boolean}} [ctx]
|
|
11
|
+
* @param {{cwd?: string, origin?: string, fetchImpl?: typeof fetch, registryOrigin?: string, expectedVersion?: string, requireExpectedVersion?: boolean}} [ctx]
|
|
9
12
|
*/
|
|
10
13
|
export function reconcileRegistryCompositions(options?: {
|
|
11
14
|
apply?: boolean;
|
|
12
15
|
path?: string;
|
|
13
|
-
}, { cwd, fetchImpl, registryOrigin, expectedVersion, requireExpectedVersion, }?: {
|
|
16
|
+
}, { cwd, origin, fetchImpl, registryOrigin, expectedVersion, requireExpectedVersion, }?: {
|
|
14
17
|
cwd?: string;
|
|
18
|
+
origin?: string;
|
|
15
19
|
fetchImpl?: typeof fetch;
|
|
16
20
|
registryOrigin?: string;
|
|
17
21
|
expectedVersion?: string;
|
|
@@ -23,9 +27,10 @@ export function reconcileRegistryCompositions(options?: {
|
|
|
23
27
|
/** @param {import('../upgrade.type.mjs').RegistryCompositionSummary} summary */
|
|
24
28
|
export function logRegistryCompositionSummary(summary: import("../upgrade.type.mjs").RegistryCompositionSummary): void;
|
|
25
29
|
/**
|
|
26
|
-
* Standalone `astryx upgrade --registry` leaf.
|
|
30
|
+
* Standalone `astryx upgrade --registry` leaf. `ctx.origin` is the folder the
|
|
31
|
+
* command ran in, when `ctx.cwd` is the project root above it.
|
|
27
32
|
* @param {{apply?: boolean, path?: string}} options
|
|
28
|
-
* @param {{cwd?: string, fetchImpl?: typeof fetch, registryOrigin?: string, expectedVersion?: string, requireExpectedVersion?: boolean}} [ctx]
|
|
33
|
+
* @param {{cwd?: string, origin?: string, fetchImpl?: typeof fetch, registryOrigin?: string, expectedVersion?: string, requireExpectedVersion?: boolean}} [ctx]
|
|
29
34
|
* @returns {Promise<import('../upgrade.type.mjs').UpgradeRegistryResponse>}
|
|
30
35
|
*/
|
|
31
36
|
export function registryUpgrade(options?: {
|
|
@@ -33,6 +38,7 @@ export function registryUpgrade(options?: {
|
|
|
33
38
|
path?: string;
|
|
34
39
|
}, ctx?: {
|
|
35
40
|
cwd?: string;
|
|
41
|
+
origin?: string;
|
|
36
42
|
fetchImpl?: typeof fetch;
|
|
37
43
|
registryOrigin?: string;
|
|
38
44
|
expectedVersion?: string;
|
|
@@ -414,8 +414,9 @@ async function fetchLatestReceipt(
|
|
|
414
414
|
/**
|
|
415
415
|
* @param {string} receiptPath
|
|
416
416
|
* @param {string} root
|
|
417
|
+
* @param {string} [display] the folder reported paths are relative to
|
|
417
418
|
*/
|
|
418
|
-
function loadInstalledReceipt(receiptPath, root) {
|
|
419
|
+
function loadInstalledReceipt(receiptPath, root, display = root) {
|
|
419
420
|
let receipt;
|
|
420
421
|
let receiptText;
|
|
421
422
|
try {
|
|
@@ -436,7 +437,7 @@ function loadInstalledReceipt(receiptPath, root) {
|
|
|
436
437
|
}
|
|
437
438
|
} catch (error) {
|
|
438
439
|
throw new Error(
|
|
439
|
-
`Invalid receipt ${relativePath(receiptPath,
|
|
440
|
+
`Invalid receipt ${relativePath(receiptPath, display)}: ${error instanceof Error ? error.message : String(error)}`,
|
|
440
441
|
{cause: error},
|
|
441
442
|
);
|
|
442
443
|
}
|
|
@@ -445,7 +446,7 @@ function loadInstalledReceipt(receiptPath, root) {
|
|
|
445
446
|
const candidates = receiptFileCandidates(receipt, file).map(candidate => {
|
|
446
447
|
if (registryContentHash(candidate.content) !== candidate.sha256) {
|
|
447
448
|
throw new Error(
|
|
448
|
-
`Invalid receipt ${relativePath(receiptPath,
|
|
449
|
+
`Invalid receipt ${relativePath(receiptPath, display)}: stored hash does not match ${file.registryPath} (${candidate.format})`,
|
|
449
450
|
);
|
|
450
451
|
}
|
|
451
452
|
let sourcePath;
|
|
@@ -458,7 +459,7 @@ function loadInstalledReceipt(receiptPath, root) {
|
|
|
458
459
|
} catch (error) {
|
|
459
460
|
if (error instanceof PathSafetyError) {
|
|
460
461
|
throw new Error(
|
|
461
|
-
`Invalid receipt ${relativePath(receiptPath,
|
|
462
|
+
`Invalid receipt ${relativePath(receiptPath, display)}: ${error.message}`,
|
|
462
463
|
{cause: error},
|
|
463
464
|
);
|
|
464
465
|
}
|
|
@@ -471,7 +472,7 @@ function loadInstalledReceipt(receiptPath, root) {
|
|
|
471
472
|
);
|
|
472
473
|
if (existing.length > 1) {
|
|
473
474
|
throw new Error(
|
|
474
|
-
`Invalid receipt ${relativePath(receiptPath,
|
|
475
|
+
`Invalid receipt ${relativePath(receiptPath, display)}: multiple install variants exist for ${file.registryPath}`,
|
|
475
476
|
);
|
|
476
477
|
}
|
|
477
478
|
return existing[0] ?? candidates[0];
|
|
@@ -483,12 +484,14 @@ function loadInstalledReceipt(receiptPath, root) {
|
|
|
483
484
|
/**
|
|
484
485
|
* @param {string} receiptPath
|
|
485
486
|
* @param {string} root
|
|
486
|
-
* @param {{fetchImpl: typeof fetch, registryOrigin: string, expectedVersion?: string}} options
|
|
487
|
+
* @param {{fetchImpl: typeof fetch, registryOrigin: string, expectedVersion?: string, display?: string}} options
|
|
488
|
+
* `display` is the folder reported paths are relative to, `root` by default
|
|
487
489
|
*/
|
|
488
490
|
async function planReceipt(receiptPath, root, options) {
|
|
491
|
+
const display = options.display ?? root;
|
|
489
492
|
let installed;
|
|
490
493
|
try {
|
|
491
|
-
installed = loadInstalledReceipt(receiptPath, root);
|
|
494
|
+
installed = loadInstalledReceipt(receiptPath, root, display);
|
|
492
495
|
} catch (error) {
|
|
493
496
|
return {
|
|
494
497
|
receiptPath,
|
|
@@ -584,7 +587,7 @@ async function planReceipt(receiptPath, root, options) {
|
|
|
584
587
|
oldReceiptText,
|
|
585
588
|
};
|
|
586
589
|
}
|
|
587
|
-
const displayPath = relativePath(sourcePath,
|
|
590
|
+
const displayPath = relativePath(sourcePath, display);
|
|
588
591
|
try {
|
|
589
592
|
if (!fs.existsSync(sourcePath)) {
|
|
590
593
|
plannedFiles.push({
|
|
@@ -636,7 +639,7 @@ async function planReceipt(receiptPath, root, options) {
|
|
|
636
639
|
const newFile = newReceiptFile
|
|
637
640
|
? receiptFileForFormat(newReceipt, newReceiptFile, oldFile.format)
|
|
638
641
|
: null;
|
|
639
|
-
const displayPath = relativePath(oldFile.sourcePath,
|
|
642
|
+
const displayPath = relativePath(oldFile.sourcePath, display);
|
|
640
643
|
if (!newReceiptFile) {
|
|
641
644
|
plannedFiles.push({
|
|
642
645
|
id: oldFile.id,
|
|
@@ -856,8 +859,12 @@ function publicAction(action, apply) {
|
|
|
856
859
|
return action;
|
|
857
860
|
}
|
|
858
861
|
|
|
859
|
-
/**
|
|
860
|
-
|
|
862
|
+
/**
|
|
863
|
+
* @param {any} item
|
|
864
|
+
* @param {string} display the folder reported paths are relative to
|
|
865
|
+
* @param {boolean} apply
|
|
866
|
+
*/
|
|
867
|
+
function publicItem(item, display, apply) {
|
|
861
868
|
return {
|
|
862
869
|
item: item.item,
|
|
863
870
|
path: item.itemPath,
|
|
@@ -870,7 +877,7 @@ function publicItem(item, root, apply) {
|
|
|
870
877
|
action: publicAction(file.action, apply),
|
|
871
878
|
...(file.message ? {message: file.message} : {}),
|
|
872
879
|
...(file.action === 'conflict' && file.conflictPath
|
|
873
|
-
? {conflictFile: relativePath(file.conflictPath,
|
|
880
|
+
? {conflictFile: relativePath(file.conflictPath, display)}
|
|
874
881
|
: {}),
|
|
875
882
|
}),
|
|
876
883
|
),
|
|
@@ -968,13 +975,17 @@ function applyPlan(plan) {
|
|
|
968
975
|
}
|
|
969
976
|
|
|
970
977
|
/**
|
|
978
|
+
* Reported paths are relative to the scanned source folder, or, when `origin`
|
|
979
|
+
* names the folder the command ran in below the project root `cwd`, to that
|
|
980
|
+
* folder, so they resolve from where the command ran.
|
|
971
981
|
* @param {{apply?: boolean, path?: string}} options
|
|
972
|
-
* @param {{cwd?: string, fetchImpl?: typeof fetch, registryOrigin?: string, expectedVersion?: string, requireExpectedVersion?: boolean}} [ctx]
|
|
982
|
+
* @param {{cwd?: string, origin?: string, fetchImpl?: typeof fetch, registryOrigin?: string, expectedVersion?: string, requireExpectedVersion?: boolean}} [ctx]
|
|
973
983
|
*/
|
|
974
984
|
export async function reconcileRegistryCompositions(
|
|
975
985
|
options = {},
|
|
976
986
|
{
|
|
977
987
|
cwd = process.cwd(),
|
|
988
|
+
origin,
|
|
978
989
|
fetchImpl = globalThis.fetch,
|
|
979
990
|
registryOrigin = PUBLIC_SHADCN_REGISTRY_ORIGIN,
|
|
980
991
|
expectedVersion,
|
|
@@ -998,6 +1009,7 @@ export async function reconcileRegistryCompositions(
|
|
|
998
1009
|
throw error;
|
|
999
1010
|
}
|
|
1000
1011
|
|
|
1012
|
+
const display = origin ?? root;
|
|
1001
1013
|
const apply = options.apply ?? false;
|
|
1002
1014
|
const receipts = discoverRegistryReceipts(root);
|
|
1003
1015
|
const summary = emptySummary(apply);
|
|
@@ -1019,6 +1031,7 @@ export async function reconcileRegistryCompositions(
|
|
|
1019
1031
|
fetchImpl,
|
|
1020
1032
|
registryOrigin,
|
|
1021
1033
|
expectedVersion,
|
|
1034
|
+
display,
|
|
1022
1035
|
}),
|
|
1023
1036
|
);
|
|
1024
1037
|
|
|
@@ -1031,7 +1044,7 @@ export async function reconcileRegistryCompositions(
|
|
|
1031
1044
|
summary.invalid++;
|
|
1032
1045
|
}
|
|
1033
1046
|
}
|
|
1034
|
-
recordItem(summary, publicItem(plan,
|
|
1047
|
+
recordItem(summary, publicItem(plan, display, apply), plan.action, apply);
|
|
1035
1048
|
if (!apply) continue;
|
|
1036
1049
|
|
|
1037
1050
|
try {
|
|
@@ -1119,13 +1132,17 @@ export function logRegistryCompositionSummary(summary) {
|
|
|
1119
1132
|
}
|
|
1120
1133
|
|
|
1121
1134
|
/**
|
|
1122
|
-
* Standalone `astryx upgrade --registry` leaf.
|
|
1135
|
+
* Standalone `astryx upgrade --registry` leaf. `ctx.origin` is the folder the
|
|
1136
|
+
* command ran in, when `ctx.cwd` is the project root above it.
|
|
1123
1137
|
* @param {{apply?: boolean, path?: string}} options
|
|
1124
|
-
* @param {{cwd?: string, fetchImpl?: typeof fetch, registryOrigin?: string, expectedVersion?: string, requireExpectedVersion?: boolean}} [ctx]
|
|
1138
|
+
* @param {{cwd?: string, origin?: string, fetchImpl?: typeof fetch, registryOrigin?: string, expectedVersion?: string, requireExpectedVersion?: boolean}} [ctx]
|
|
1125
1139
|
* @returns {Promise<import('../upgrade.type.mjs').UpgradeRegistryResponse>}
|
|
1126
1140
|
*/
|
|
1127
1141
|
export async function registryUpgrade(options = {}, ctx = {}) {
|
|
1128
1142
|
const cwd = ctx.cwd ?? process.cwd();
|
|
1143
|
+
if (ctx.origin != null) {
|
|
1144
|
+
logger.log(`Project root: ${path.relative(ctx.origin, cwd) || '.'}`);
|
|
1145
|
+
}
|
|
1129
1146
|
const installed = detectInstalledTargetVersion(cwd);
|
|
1130
1147
|
const expectedVersion =
|
|
1131
1148
|
ctx.expectedVersion ??
|