aios-lite 0.1.3 → 0.1.7
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/CHANGELOG.md +55 -0
- package/README.md +28 -2
- package/docs/en/web3.md +54 -0
- package/package.json +1 -1
- package/src/cli.js +95 -46
- package/src/commands/context-validate.js +44 -16
- package/src/commands/doctor.js +72 -6
- package/src/commands/info.js +15 -6
- package/src/commands/setup-context.js +79 -2
- package/src/commands/smoke.js +277 -0
- package/src/constants.js +9 -1
- package/src/context-writer.js +20 -1
- package/src/detector.js +81 -2
- package/src/doctor.js +69 -1
- package/src/i18n/messages/en.js +40 -7
- package/src/parser.js +1 -0
- package/template/.aios-lite/agents/setup.md +17 -3
- package/template/.aios-lite/config.md +15 -0
- package/template/.aios-lite/locales/en/agents/setup.md +17 -3
- package/template/.aios-lite/locales/pt-BR/agents/setup.md +7 -0
- package/template/.aios-lite/skills/dynamic/cardano-docs.md +3 -0
- package/template/.aios-lite/skills/dynamic/ethereum-docs.md +3 -0
- package/template/.aios-lite/skills/dynamic/solana-docs.md +3 -0
- package/template/.aios-lite/skills/static/node-typescript-patterns.md +6 -0
- package/template/.aios-lite/skills/static/web3-cardano-patterns.md +6 -0
- package/template/.aios-lite/skills/static/web3-ethereum-patterns.md +6 -0
- package/template/.aios-lite/skills/static/web3-security-checklist.md +7 -0
- package/template/.aios-lite/skills/static/web3-solana-patterns.md +6 -0
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,61 @@
|
|
|
2
2
|
|
|
3
3
|
All notable changes to this project will be documented in this file.
|
|
4
4
|
|
|
5
|
+
## [0.1.7] - Unreleased
|
|
6
|
+
### Added
|
|
7
|
+
- JSON output mode (`--json`) for:
|
|
8
|
+
- `aios-lite info`
|
|
9
|
+
- `aios-lite doctor`
|
|
10
|
+
- `aios-lite context:validate`
|
|
11
|
+
- `aios-lite test:smoke`
|
|
12
|
+
- New JSON output test suite: `tests/json-output.test.js`.
|
|
13
|
+
|
|
14
|
+
### Changed
|
|
15
|
+
- CLI now returns structured JSON errors for unknown commands and runtime failures when `--json` is enabled.
|
|
16
|
+
- `setup:context` and setup templates now default `aios_lite_version` to `0.1.7`.
|
|
17
|
+
|
|
18
|
+
## [0.1.6] - 2026-03-01
|
|
19
|
+
### Added
|
|
20
|
+
- `test:smoke` now supports chain-specific Web3 profiles:
|
|
21
|
+
- `--web3=ethereum`
|
|
22
|
+
- `--web3=solana`
|
|
23
|
+
- `--web3=cardano`
|
|
24
|
+
- Web3 smoke workflow now verifies:
|
|
25
|
+
- framework detection per chain profile
|
|
26
|
+
- `project.context.md` dApp/Web3 frontmatter consistency.
|
|
27
|
+
|
|
28
|
+
### Changed
|
|
29
|
+
- CLI help and docs updated for `test:smoke --web3`.
|
|
30
|
+
- `setup:context` and setup templates now default `aios_lite_version` to `0.1.6`.
|
|
31
|
+
|
|
32
|
+
## [0.1.5] - 2026-03-01
|
|
33
|
+
### Added
|
|
34
|
+
- Web3 framework detection:
|
|
35
|
+
- Ethereum: `Hardhat`, `Foundry`, `Truffle`
|
|
36
|
+
- Solana: `Anchor`, `Solana Web3`
|
|
37
|
+
- Cardano: `Cardano` (Aiken/Cardano SDK signals)
|
|
38
|
+
- New Web3 skill templates:
|
|
39
|
+
- static: `web3-ethereum-patterns`, `web3-solana-patterns`, `web3-cardano-patterns`, `web3-security-checklist`, `node-typescript-patterns`
|
|
40
|
+
- dynamic: `ethereum-docs`, `solana-docs`, `cardano-docs`
|
|
41
|
+
- New documentation page: `docs/en/web3.md`.
|
|
42
|
+
|
|
43
|
+
### Changed
|
|
44
|
+
- `project_type` now accepts `dapp`.
|
|
45
|
+
- `setup:context` now supports Web3 context fields (`web3_enabled`, `web3_networks`, `contract_framework`, `wallet_provider`, `indexer`, `rpc_provider`).
|
|
46
|
+
- `setup:context` and setup templates now default `aios_lite_version` to `0.1.5`.
|
|
47
|
+
|
|
48
|
+
## [0.1.4] - 2026-03-01
|
|
49
|
+
### Added
|
|
50
|
+
- New command:
|
|
51
|
+
- `aios-lite test:smoke [workspace-path] [--lang=en|pt-BR] [--keep]`
|
|
52
|
+
- New smoke test suite: `tests/smoke.test.js`.
|
|
53
|
+
|
|
54
|
+
### Changed
|
|
55
|
+
- `doctor` now supports safe remediation mode:
|
|
56
|
+
- `aios-lite doctor --fix`
|
|
57
|
+
- `aios-lite doctor --fix --dry-run`
|
|
58
|
+
- `setup:context` and setup templates now default `aios_lite_version` to `0.1.4`.
|
|
59
|
+
|
|
5
60
|
## [0.1.3] - 2026-03-01
|
|
6
61
|
### Added
|
|
7
62
|
- Localized agent prompt packs:
|
package/README.md
CHANGED
|
@@ -15,13 +15,14 @@ npx aios-lite install
|
|
|
15
15
|
- `aios-lite install [path]`
|
|
16
16
|
- `aios-lite update [path]`
|
|
17
17
|
- `aios-lite info [path]`
|
|
18
|
-
- `aios-lite doctor [path]`
|
|
18
|
+
- `aios-lite doctor [path] [--fix] [--dry-run] [--json]`
|
|
19
19
|
- `aios-lite i18n:add <locale>`
|
|
20
20
|
- `aios-lite setup:context [path]`
|
|
21
21
|
- `aios-lite agents`
|
|
22
22
|
- `aios-lite agent:prompt <agent> [--tool=codex|claude|gemini|opencode]`
|
|
23
|
-
- `aios-lite context:validate [path]`
|
|
23
|
+
- `aios-lite context:validate [path] [--json]`
|
|
24
24
|
- `aios-lite locale:apply [path] [--lang=en|pt-BR]`
|
|
25
|
+
- `aios-lite test:smoke [workspace-path] [--lang=en|pt-BR] [--web3=ethereum|solana|cardano] [--keep] [--json]`
|
|
25
26
|
|
|
26
27
|
## Agent usage helper
|
|
27
28
|
If your AI CLI does not show a visual agent picker, use:
|
|
@@ -30,8 +31,18 @@ If your AI CLI does not show a visual agent picker, use:
|
|
|
30
31
|
aios-lite agents
|
|
31
32
|
aios-lite agent:prompt setup --tool=codex
|
|
32
33
|
aios-lite locale:apply --lang=pt-BR
|
|
34
|
+
aios-lite doctor --fix
|
|
35
|
+
aios-lite test:smoke --lang=pt-BR
|
|
36
|
+
aios-lite test:smoke --web3=ethereum
|
|
33
37
|
```
|
|
34
38
|
|
|
39
|
+
## JSON output for CI
|
|
40
|
+
Use `--json` on selected commands:
|
|
41
|
+
- `aios-lite info --json`
|
|
42
|
+
- `aios-lite doctor --json`
|
|
43
|
+
- `aios-lite context:validate --json`
|
|
44
|
+
- `aios-lite test:smoke --json`
|
|
45
|
+
|
|
35
46
|
## i18n
|
|
36
47
|
CLI localization is supported with:
|
|
37
48
|
- `--locale=<code>`
|
|
@@ -51,8 +62,23 @@ aios-lite i18n:add fr
|
|
|
51
62
|
- Gemini CLI (`.gemini/GEMINI.md`)
|
|
52
63
|
- OpenCode (`OPENCODE.md`)
|
|
53
64
|
|
|
65
|
+
## Web3 support
|
|
66
|
+
- `project_type=dapp` is supported in context validation and setup.
|
|
67
|
+
- Framework detection now includes:
|
|
68
|
+
- Ethereum: `Hardhat`, `Foundry`, `Truffle`
|
|
69
|
+
- Solana: `Anchor`, `Solana Web3`
|
|
70
|
+
- Cardano: `Cardano` (Aiken/Cardano SDK signals)
|
|
71
|
+
- `setup:context` supports Web3 fields:
|
|
72
|
+
- `--web3-enabled=true|false`
|
|
73
|
+
- `--web3-networks=ethereum,solana`
|
|
74
|
+
- `--contract-framework=Hardhat`
|
|
75
|
+
- `--wallet-provider=wagmi`
|
|
76
|
+
- `--indexer=The Graph`
|
|
77
|
+
- `--rpc-provider=Alchemy`
|
|
78
|
+
|
|
54
79
|
## Docs
|
|
55
80
|
- i18n guide: `docs/en/i18n.md`
|
|
81
|
+
- web3 guide: `docs/en/web3.md`
|
|
56
82
|
- release guide: `docs/en/release.md`
|
|
57
83
|
- release flow: `docs/en/release-flow.md`
|
|
58
84
|
- release notes template: `docs/en/release-notes-template.md`
|
package/docs/en/web3.md
ADDED
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
# Web3 Support
|
|
2
|
+
|
|
3
|
+
AIOS Lite includes lightweight Web3 support for small and medium teams using JavaScript/TypeScript workflows.
|
|
4
|
+
|
|
5
|
+
## Supported framework detection
|
|
6
|
+
- Ethereum: `Hardhat`, `Foundry`, `Truffle`
|
|
7
|
+
- Solana: `Anchor`, `Solana Web3`
|
|
8
|
+
- Cardano: `Cardano` (Aiken and Cardano SDK dependency signals)
|
|
9
|
+
|
|
10
|
+
## Context contract for dApps
|
|
11
|
+
`project_type` accepts `dapp`, and setup can include:
|
|
12
|
+
- `web3_enabled`
|
|
13
|
+
- `web3_networks`
|
|
14
|
+
- `contract_framework`
|
|
15
|
+
- `wallet_provider`
|
|
16
|
+
- `indexer`
|
|
17
|
+
- `rpc_provider`
|
|
18
|
+
|
|
19
|
+
## Setup examples
|
|
20
|
+
```bash
|
|
21
|
+
# Interactive
|
|
22
|
+
aios-lite setup:context
|
|
23
|
+
|
|
24
|
+
# Defaults with explicit Web3 options
|
|
25
|
+
aios-lite setup:context . \
|
|
26
|
+
--defaults \
|
|
27
|
+
--project-type=dapp \
|
|
28
|
+
--framework=Hardhat \
|
|
29
|
+
--web3-enabled=true \
|
|
30
|
+
--web3-networks=ethereum \
|
|
31
|
+
--contract-framework=Hardhat \
|
|
32
|
+
--wallet-provider=wagmi \
|
|
33
|
+
--indexer="The Graph" \
|
|
34
|
+
--rpc-provider=Alchemy
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
## Web3 smoke checks
|
|
38
|
+
```bash
|
|
39
|
+
aios-lite test:smoke --web3=ethereum
|
|
40
|
+
aios-lite test:smoke --web3=solana
|
|
41
|
+
aios-lite test:smoke --web3=cardano
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
## Skills bundled in templates
|
|
45
|
+
- Static:
|
|
46
|
+
- `web3-ethereum-patterns.md`
|
|
47
|
+
- `web3-solana-patterns.md`
|
|
48
|
+
- `web3-cardano-patterns.md`
|
|
49
|
+
- `web3-security-checklist.md`
|
|
50
|
+
- `node-typescript-patterns.md`
|
|
51
|
+
- Dynamic:
|
|
52
|
+
- `ethereum-docs.md`
|
|
53
|
+
- `solana-docs.md`
|
|
54
|
+
- `cardano-docs.md`
|
package/package.json
CHANGED
package/src/cli.js
CHANGED
|
@@ -12,6 +12,19 @@ const { runAgentsList, runAgentPrompt } = require('./commands/agents');
|
|
|
12
12
|
const { runContextValidate } = require('./commands/context-validate');
|
|
13
13
|
const { runSetupContext } = require('./commands/setup-context');
|
|
14
14
|
const { runLocaleApply } = require('./commands/locale-apply');
|
|
15
|
+
const { runSmokeTest } = require('./commands/smoke');
|
|
16
|
+
|
|
17
|
+
const JSON_SUPPORTED_COMMANDS = new Set([
|
|
18
|
+
'info',
|
|
19
|
+
'doctor',
|
|
20
|
+
'context:validate',
|
|
21
|
+
'context-validate',
|
|
22
|
+
'test:smoke',
|
|
23
|
+
'test-smoke',
|
|
24
|
+
'version',
|
|
25
|
+
'--version',
|
|
26
|
+
'-v'
|
|
27
|
+
]);
|
|
15
28
|
|
|
16
29
|
function printHelp(t) {
|
|
17
30
|
console.log(`${t('cli.title')}\n`);
|
|
@@ -27,11 +40,30 @@ function printHelp(t) {
|
|
|
27
40
|
console.log(` ${t('cli.help_context_validate')}`);
|
|
28
41
|
console.log(` ${t('cli.help_setup_context')}`);
|
|
29
42
|
console.log(` ${t('cli.help_locale_apply')}`);
|
|
43
|
+
console.log(` ${t('cli.help_test_smoke')}`);
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
function commandSupportsJson(command) {
|
|
47
|
+
return JSON_SUPPORTED_COMMANDS.has(command);
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
async function writeJson(payload) {
|
|
51
|
+
const text = `${JSON.stringify(payload, null, 2)}\n`;
|
|
52
|
+
await new Promise((resolve, reject) => {
|
|
53
|
+
process.stdout.write(text, (error) => {
|
|
54
|
+
if (error) {
|
|
55
|
+
reject(error);
|
|
56
|
+
return;
|
|
57
|
+
}
|
|
58
|
+
resolve();
|
|
59
|
+
});
|
|
60
|
+
});
|
|
30
61
|
}
|
|
31
62
|
|
|
32
63
|
async function main() {
|
|
33
64
|
const { command, args, options } = parseArgv(process.argv);
|
|
34
65
|
const locale = normalizeLocale(options.locale || process.env.AIOS_LITE_LOCALE || 'en');
|
|
66
|
+
const jsonMode = Boolean(options.json);
|
|
35
67
|
const { t } = createTranslator(locale);
|
|
36
68
|
const logger = console;
|
|
37
69
|
|
|
@@ -41,61 +73,78 @@ async function main() {
|
|
|
41
73
|
}
|
|
42
74
|
|
|
43
75
|
if (command === '--version' || command === '-v' || command === 'version' || options.version) {
|
|
44
|
-
await runInfo({ args: ['.'], options
|
|
76
|
+
const result = await runInfo({ args: ['.'], options, logger, t });
|
|
77
|
+
if (jsonMode) {
|
|
78
|
+
await writeJson(result);
|
|
79
|
+
}
|
|
45
80
|
return;
|
|
46
81
|
}
|
|
47
82
|
|
|
48
83
|
try {
|
|
84
|
+
let result = null;
|
|
85
|
+
|
|
49
86
|
if (command === 'init') {
|
|
50
|
-
await runInit({ args, options, logger, t });
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
if (command === '
|
|
54
|
-
await
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
if (command === '
|
|
58
|
-
await
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
if (command === '
|
|
62
|
-
await
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
if (command === '
|
|
66
|
-
await
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
if (command === '
|
|
70
|
-
await
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
if (command === 'locale:apply' || command === 'locale-apply') {
|
|
90
|
-
await runLocaleApply({ args, options, logger, t });
|
|
87
|
+
result = await runInit({ args, options, logger, t });
|
|
88
|
+
} else if (command === 'install') {
|
|
89
|
+
result = await runInstall({ args, options, logger, t });
|
|
90
|
+
} else if (command === 'update') {
|
|
91
|
+
result = await runUpdate({ args, options, logger, t });
|
|
92
|
+
} else if (command === 'info') {
|
|
93
|
+
result = await runInfo({ args, options, logger, t });
|
|
94
|
+
} else if (command === 'doctor') {
|
|
95
|
+
result = await runDoctorCommand({ args, options, logger, t });
|
|
96
|
+
} else if (command === 'i18n:add' || command === 'i18n-add') {
|
|
97
|
+
result = await runI18nAdd({ args, options, logger, t });
|
|
98
|
+
} else if (command === 'agents') {
|
|
99
|
+
result = await runAgentsList({ args, options, logger, t });
|
|
100
|
+
} else if (command === 'agent:prompt' || command === 'agent-prompt') {
|
|
101
|
+
result = await runAgentPrompt({ args, options, logger, t });
|
|
102
|
+
} else if (command === 'context:validate' || command === 'context-validate') {
|
|
103
|
+
result = await runContextValidate({ args, options, logger, t });
|
|
104
|
+
} else if (command === 'setup:context' || command === 'setup-context') {
|
|
105
|
+
result = await runSetupContext({ args, options, logger, t });
|
|
106
|
+
} else if (command === 'locale:apply' || command === 'locale-apply') {
|
|
107
|
+
result = await runLocaleApply({ args, options, logger, t });
|
|
108
|
+
} else if (command === 'test:smoke' || command === 'test-smoke') {
|
|
109
|
+
result = await runSmokeTest({ args, options, logger, t });
|
|
110
|
+
} else {
|
|
111
|
+
const message = t('cli.unknown_command', { command });
|
|
112
|
+
if (jsonMode) {
|
|
113
|
+
await writeJson({
|
|
114
|
+
ok: false,
|
|
115
|
+
error: {
|
|
116
|
+
code: 'unknown_command',
|
|
117
|
+
message,
|
|
118
|
+
command
|
|
119
|
+
}
|
|
120
|
+
});
|
|
121
|
+
} else {
|
|
122
|
+
logger.error(`${message}\n`);
|
|
123
|
+
printHelp(t);
|
|
124
|
+
}
|
|
125
|
+
process.exitCode = 1;
|
|
91
126
|
return;
|
|
92
127
|
}
|
|
93
128
|
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
129
|
+
if (jsonMode && commandSupportsJson(command)) {
|
|
130
|
+
await writeJson(result || { ok: true });
|
|
131
|
+
if (result && Object.prototype.hasOwnProperty.call(result, 'ok') && !result.ok) {
|
|
132
|
+
process.exitCode = 1;
|
|
133
|
+
}
|
|
134
|
+
}
|
|
97
135
|
} catch (error) {
|
|
98
|
-
|
|
136
|
+
if (jsonMode) {
|
|
137
|
+
await writeJson({
|
|
138
|
+
ok: false,
|
|
139
|
+
error: {
|
|
140
|
+
code: 'command_error',
|
|
141
|
+
message: error.message,
|
|
142
|
+
command
|
|
143
|
+
}
|
|
144
|
+
});
|
|
145
|
+
} else {
|
|
146
|
+
logger.error(t('cli.error_prefix', { message: error.message }));
|
|
147
|
+
}
|
|
99
148
|
process.exitCode = 1;
|
|
100
149
|
}
|
|
101
150
|
}
|
|
@@ -3,51 +3,79 @@
|
|
|
3
3
|
const path = require('node:path');
|
|
4
4
|
const { validateProjectContextFile } = require('../context');
|
|
5
5
|
|
|
6
|
-
async function runContextValidate({ args, logger, t }) {
|
|
6
|
+
async function runContextValidate({ args, options = {}, logger, t }) {
|
|
7
7
|
const targetDir = path.resolve(process.cwd(), args[0] || '.');
|
|
8
|
+
const jsonMode = Boolean(options.json);
|
|
8
9
|
const result = await validateProjectContextFile(targetDir);
|
|
9
10
|
|
|
11
|
+
const base = {
|
|
12
|
+
targetDir
|
|
13
|
+
};
|
|
14
|
+
|
|
10
15
|
if (!result.exists) {
|
|
11
|
-
|
|
12
|
-
logger.log(t('context_validate.hint_setup'));
|
|
13
|
-
return {
|
|
16
|
+
const output = {
|
|
14
17
|
ok: false,
|
|
18
|
+
reason: 'missing_file',
|
|
19
|
+
...base,
|
|
15
20
|
...result
|
|
16
21
|
};
|
|
22
|
+
if (jsonMode) {
|
|
23
|
+
return output;
|
|
24
|
+
}
|
|
25
|
+
logger.log(t('context_validate.missing_file', { path: result.filePath }));
|
|
26
|
+
logger.log(t('context_validate.hint_setup'));
|
|
27
|
+
return output;
|
|
17
28
|
}
|
|
18
29
|
|
|
19
30
|
if (!result.parsed) {
|
|
31
|
+
const output = {
|
|
32
|
+
ok: false,
|
|
33
|
+
reason: 'invalid_frontmatter',
|
|
34
|
+
...base,
|
|
35
|
+
...result
|
|
36
|
+
};
|
|
37
|
+
if (jsonMode) {
|
|
38
|
+
return output;
|
|
39
|
+
}
|
|
20
40
|
logger.log(t('context_validate.invalid_frontmatter'));
|
|
21
41
|
logger.log(t('context_validate.file_path', { path: result.filePath }));
|
|
22
42
|
logger.log(t('context_validate.parse_reason', { reason: result.parseError || 'unknown' }));
|
|
23
43
|
logger.log(t('context_validate.hint_fix_frontmatter'));
|
|
24
|
-
return
|
|
25
|
-
ok: false,
|
|
26
|
-
...result
|
|
27
|
-
};
|
|
44
|
+
return output;
|
|
28
45
|
}
|
|
29
46
|
|
|
30
47
|
if (!result.valid) {
|
|
48
|
+
const output = {
|
|
49
|
+
ok: false,
|
|
50
|
+
reason: 'invalid_fields',
|
|
51
|
+
...base,
|
|
52
|
+
...result
|
|
53
|
+
};
|
|
54
|
+
if (jsonMode) {
|
|
55
|
+
return output;
|
|
56
|
+
}
|
|
31
57
|
logger.log(t('context_validate.invalid_fields'));
|
|
32
58
|
logger.log(t('context_validate.file_path', { path: result.filePath }));
|
|
33
59
|
for (const issue of result.issues) {
|
|
34
60
|
logger.log(`- ${t(issue.key, issue.params || {})}`);
|
|
35
61
|
}
|
|
36
|
-
return
|
|
37
|
-
ok: false,
|
|
38
|
-
...result
|
|
39
|
-
};
|
|
62
|
+
return output;
|
|
40
63
|
}
|
|
41
64
|
|
|
42
|
-
|
|
43
|
-
logger.log(t('context_validate.file_path', { path: result.filePath }));
|
|
44
|
-
return {
|
|
65
|
+
const output = {
|
|
45
66
|
ok: true,
|
|
67
|
+
reason: 'valid',
|
|
68
|
+
...base,
|
|
46
69
|
...result
|
|
47
70
|
};
|
|
71
|
+
if (jsonMode) {
|
|
72
|
+
return output;
|
|
73
|
+
}
|
|
74
|
+
logger.log(t('context_validate.valid'));
|
|
75
|
+
logger.log(t('context_validate.file_path', { path: result.filePath }));
|
|
76
|
+
return output;
|
|
48
77
|
}
|
|
49
78
|
|
|
50
79
|
module.exports = {
|
|
51
80
|
runContextValidate
|
|
52
81
|
};
|
|
53
|
-
|
package/src/commands/doctor.js
CHANGED
|
@@ -1,12 +1,9 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
3
|
const path = require('node:path');
|
|
4
|
-
const { runDoctor } = require('../doctor');
|
|
5
|
-
|
|
6
|
-
async function runDoctorCommand({ args, logger, t }) {
|
|
7
|
-
const targetDir = path.resolve(process.cwd(), args[0] || '.');
|
|
8
|
-
const report = await runDoctor(targetDir);
|
|
4
|
+
const { runDoctor, applyDoctorFixes } = require('../doctor');
|
|
9
5
|
|
|
6
|
+
function printDoctorChecks(report, logger, t) {
|
|
10
7
|
for (const check of report.checks) {
|
|
11
8
|
const icon = check.ok ? t('doctor.ok') : t('doctor.fail');
|
|
12
9
|
logger.log(`[${icon}] ${t(check.key, check.params)}`);
|
|
@@ -14,6 +11,75 @@ async function runDoctorCommand({ args, logger, t }) {
|
|
|
14
11
|
logger.log(` ${t('doctor.hint_prefix', { hint: t(check.hintKey) })}`);
|
|
15
12
|
}
|
|
16
13
|
}
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
function printFixAction(action, logger, t, dryRun) {
|
|
17
|
+
logger.log(`- ${t(`doctor.fix_action_${action.id}`)}`);
|
|
18
|
+
if (action.skipped) {
|
|
19
|
+
logger.log(` ${t('doctor.fix_not_applicable')}`);
|
|
20
|
+
return;
|
|
21
|
+
}
|
|
22
|
+
logger.log(` ${t('doctor.fix_target_count', { count: action.missingCount || action.count || 0 })}`);
|
|
23
|
+
logger.log(
|
|
24
|
+
` ${t(dryRun ? 'doctor.fix_planned_count' : 'doctor.fix_applied_count', {
|
|
25
|
+
count: action.count || 0
|
|
26
|
+
})}`
|
|
27
|
+
);
|
|
28
|
+
if (action.locale) {
|
|
29
|
+
logger.log(` ${t('doctor.fix_locale', { locale: action.locale })}`);
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
async function runDoctorCommand({ args, options = {}, logger, t }) {
|
|
34
|
+
const targetDir = path.resolve(process.cwd(), args[0] || '.');
|
|
35
|
+
const fix = Boolean(options.fix);
|
|
36
|
+
const dryRun = Boolean(options['dry-run']);
|
|
37
|
+
const jsonMode = Boolean(options.json);
|
|
38
|
+
|
|
39
|
+
let report = await runDoctor(targetDir);
|
|
40
|
+
let fixResult = null;
|
|
41
|
+
|
|
42
|
+
if (fix) {
|
|
43
|
+
if (!jsonMode) {
|
|
44
|
+
logger.log(dryRun ? t('doctor.fix_start_dry_run') : t('doctor.fix_start'));
|
|
45
|
+
}
|
|
46
|
+
fixResult = await applyDoctorFixes(targetDir, report, { dryRun });
|
|
47
|
+
if (!jsonMode) {
|
|
48
|
+
for (const action of fixResult.actions) {
|
|
49
|
+
printFixAction(action, logger, t, dryRun);
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
logger.log(
|
|
53
|
+
dryRun
|
|
54
|
+
? t('doctor.fix_summary_dry_run', { count: fixResult.changedCount })
|
|
55
|
+
: t('doctor.fix_summary', { count: fixResult.changedCount })
|
|
56
|
+
);
|
|
57
|
+
logger.log('');
|
|
58
|
+
}
|
|
59
|
+
report = await runDoctor(targetDir);
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
const output = {
|
|
63
|
+
ok: report.ok,
|
|
64
|
+
targetDir,
|
|
65
|
+
fix: {
|
|
66
|
+
enabled: fix,
|
|
67
|
+
dryRun,
|
|
68
|
+
...(fixResult
|
|
69
|
+
? {
|
|
70
|
+
changedCount: fixResult.changedCount,
|
|
71
|
+
actions: fixResult.actions
|
|
72
|
+
}
|
|
73
|
+
: {})
|
|
74
|
+
},
|
|
75
|
+
report
|
|
76
|
+
};
|
|
77
|
+
|
|
78
|
+
if (jsonMode) {
|
|
79
|
+
return output;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
printDoctorChecks(report, logger, t);
|
|
17
83
|
|
|
18
84
|
if (!report.ok) {
|
|
19
85
|
logger.log(`\n${t('doctor.diagnosis_fail', { count: report.failedCount })}`);
|
|
@@ -21,7 +87,7 @@ async function runDoctorCommand({ args, logger, t }) {
|
|
|
21
87
|
logger.log(`\n${t('doctor.diagnosis_ok')}`);
|
|
22
88
|
}
|
|
23
89
|
|
|
24
|
-
return
|
|
90
|
+
return output;
|
|
25
91
|
}
|
|
26
92
|
|
|
27
93
|
module.exports = {
|
package/src/commands/info.js
CHANGED
|
@@ -5,14 +5,27 @@ const path = require('node:path');
|
|
|
5
5
|
const { detectFramework } = require('../detector');
|
|
6
6
|
const { detectExistingInstall } = require('../installer');
|
|
7
7
|
|
|
8
|
-
async function runInfo({ args, logger, t }) {
|
|
8
|
+
async function runInfo({ args, options = {}, logger, t }) {
|
|
9
9
|
const targetDir = path.resolve(process.cwd(), args[0] || '.');
|
|
10
|
+
const jsonMode = Boolean(options.json);
|
|
10
11
|
const pkgPath = path.join(__dirname, '../../package.json');
|
|
11
12
|
const pkg = JSON.parse(await fs.readFile(pkgPath, 'utf8'));
|
|
12
13
|
|
|
13
14
|
const installed = await detectExistingInstall(targetDir);
|
|
14
15
|
const detection = await detectFramework(targetDir);
|
|
15
16
|
|
|
17
|
+
const result = {
|
|
18
|
+
ok: true,
|
|
19
|
+
version: pkg.version,
|
|
20
|
+
targetDir,
|
|
21
|
+
installed,
|
|
22
|
+
detection
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
if (jsonMode) {
|
|
26
|
+
return result;
|
|
27
|
+
}
|
|
28
|
+
|
|
16
29
|
logger.log(t('info.cli_version', { version: pkg.version }));
|
|
17
30
|
logger.log(t('info.directory', { targetDir }));
|
|
18
31
|
logger.log(t('info.installed_here', { value: installed ? t('info.yes') : t('info.no') }));
|
|
@@ -21,11 +34,7 @@ async function runInfo({ args, logger, t }) {
|
|
|
21
34
|
logger.log(t('info.evidence', { evidence: detection.evidence }));
|
|
22
35
|
}
|
|
23
36
|
|
|
24
|
-
return
|
|
25
|
-
version: pkg.version,
|
|
26
|
-
installed,
|
|
27
|
-
detection
|
|
28
|
-
};
|
|
37
|
+
return result;
|
|
29
38
|
}
|
|
30
39
|
|
|
31
40
|
module.exports = {
|