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 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`
@@ -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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "aios-lite",
3
- "version": "0.1.3",
3
+ "version": "0.1.7",
4
4
  "description": "Lightweight AI agent framework for software projects.",
5
5
  "keywords": [
6
6
  "ai",
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: {}, logger, t });
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
- return;
52
- }
53
- if (command === 'install') {
54
- await runInstall({ args, options, logger, t });
55
- return;
56
- }
57
- if (command === 'update') {
58
- await runUpdate({ args, options, logger, t });
59
- return;
60
- }
61
- if (command === 'info') {
62
- await runInfo({ args, options, logger, t });
63
- return;
64
- }
65
- if (command === 'doctor') {
66
- await runDoctorCommand({ args, options, logger, t });
67
- return;
68
- }
69
- if (command === 'i18n:add' || command === 'i18n-add') {
70
- await runI18nAdd({ args, options, logger, t });
71
- return;
72
- }
73
- if (command === 'agents') {
74
- await runAgentsList({ args, options, logger, t });
75
- return;
76
- }
77
- if (command === 'agent:prompt' || command === 'agent-prompt') {
78
- await runAgentPrompt({ args, options, logger, t });
79
- return;
80
- }
81
- if (command === 'context:validate' || command === 'context-validate') {
82
- await runContextValidate({ args, options, logger, t });
83
- return;
84
- }
85
- if (command === 'setup:context' || command === 'setup-context') {
86
- await runSetupContext({ args, options, logger, t });
87
- return;
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
- logger.error(`${t('cli.unknown_command', { command })}\n`);
95
- printHelp(t);
96
- process.exitCode = 1;
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
- logger.error(t('cli.error_prefix', { message: error.message }));
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
- logger.log(t('context_validate.missing_file', { path: result.filePath }));
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
- logger.log(t('context_validate.valid'));
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
-
@@ -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 report;
90
+ return output;
25
91
  }
26
92
 
27
93
  module.exports = {
@@ -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 = {