aios-lite 0.1.3 → 0.1.4

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,18 @@
2
2
 
3
3
  All notable changes to this project will be documented in this file.
4
4
 
5
+ ## [0.1.4] - Unreleased
6
+ ### Added
7
+ - New command:
8
+ - `aios-lite test:smoke [workspace-path] [--lang=en|pt-BR] [--keep]`
9
+ - New smoke test suite: `tests/smoke.test.js`.
10
+
11
+ ### Changed
12
+ - `doctor` now supports safe remediation mode:
13
+ - `aios-lite doctor --fix`
14
+ - `aios-lite doctor --fix --dry-run`
15
+ - `setup:context` and setup templates now default `aios_lite_version` to `0.1.4`.
16
+
5
17
  ## [0.1.3] - 2026-03-01
6
18
  ### Added
7
19
  - 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]`
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
23
  - `aios-lite context:validate [path]`
24
24
  - `aios-lite locale:apply [path] [--lang=en|pt-BR]`
25
+ - `aios-lite test:smoke [workspace-path] [--lang=en|pt-BR] [--keep]`
25
26
 
26
27
  ## Agent usage helper
27
28
  If your AI CLI does not show a visual agent picker, use:
@@ -30,6 +31,8 @@ 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
33
36
  ```
34
37
 
35
38
  ## i18n
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "aios-lite",
3
- "version": "0.1.3",
3
+ "version": "0.1.4",
4
4
  "description": "Lightweight AI agent framework for software projects.",
5
5
  "keywords": [
6
6
  "ai",
package/src/cli.js CHANGED
@@ -12,6 +12,7 @@ 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');
15
16
 
16
17
  function printHelp(t) {
17
18
  console.log(`${t('cli.title')}\n`);
@@ -27,6 +28,7 @@ function printHelp(t) {
27
28
  console.log(` ${t('cli.help_context_validate')}`);
28
29
  console.log(` ${t('cli.help_setup_context')}`);
29
30
  console.log(` ${t('cli.help_locale_apply')}`);
31
+ console.log(` ${t('cli.help_test_smoke')}`);
30
32
  }
31
33
 
32
34
  async function main() {
@@ -90,6 +92,10 @@ async function main() {
90
92
  await runLocaleApply({ args, options, logger, t });
91
93
  return;
92
94
  }
95
+ if (command === 'test:smoke' || command === 'test-smoke') {
96
+ await runSmokeTest({ args, options, logger, t });
97
+ return;
98
+ }
93
99
 
94
100
  logger.error(`${t('cli.unknown_command', { command })}\n`);
95
101
  printHelp(t);
@@ -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,49 @@ 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
+
38
+ let report = await runDoctor(targetDir);
39
+
40
+ if (fix) {
41
+ logger.log(dryRun ? t('doctor.fix_start_dry_run') : t('doctor.fix_start'));
42
+ const fixResult = await applyDoctorFixes(targetDir, report, { dryRun });
43
+ for (const action of fixResult.actions) {
44
+ printFixAction(action, logger, t, dryRun);
45
+ }
46
+
47
+ logger.log(
48
+ dryRun
49
+ ? t('doctor.fix_summary_dry_run', { count: fixResult.changedCount })
50
+ : t('doctor.fix_summary', { count: fixResult.changedCount })
51
+ );
52
+ logger.log('');
53
+ report = await runDoctor(targetDir);
54
+ }
55
+
56
+ printDoctorChecks(report, logger, t);
17
57
 
18
58
  if (!report.ok) {
19
59
  logger.log(`\n${t('doctor.diagnosis_fail', { count: report.failedCount })}`);
@@ -53,7 +53,7 @@ async function runSetupContext({ args, options, logger, t }) {
53
53
  email: resolveOption(options, 'email', ''),
54
54
  payments: resolveOption(options, 'payments', ''),
55
55
  installCommands: resolveOption(options, 'install-commands', ''),
56
- aiosLiteVersion: resolveOption(options, 'aios-lite-version', '0.1.3')
56
+ aiosLiteVersion: resolveOption(options, 'aios-lite-version', '0.1.4')
57
57
  };
58
58
 
59
59
  let userTypesCount = Number(options['user-types'] || 1);
@@ -0,0 +1,151 @@
1
+ 'use strict';
2
+
3
+ const fs = require('node:fs/promises');
4
+ const os = require('node:os');
5
+ const path = require('node:path');
6
+ const { ensureDir } = require('../utils');
7
+ const { runInstall } = require('./install');
8
+ const { runSetupContext } = require('./setup-context');
9
+ const { runLocaleApply } = require('./locale-apply');
10
+ const { runAgentsList, runAgentPrompt } = require('./agents');
11
+ const { runContextValidate } = require('./context-validate');
12
+ const { runDoctor } = require('../doctor');
13
+ const { runUpdate } = require('./update');
14
+
15
+ function createQuietLogger() {
16
+ return {
17
+ log() {},
18
+ error() {}
19
+ };
20
+ }
21
+
22
+ function assertStep(condition, message) {
23
+ if (!condition) {
24
+ throw new Error(message);
25
+ }
26
+ }
27
+
28
+ async function runSmokeTest({ args, options, logger, t }) {
29
+ const language = String(options.language || options.lang || 'en');
30
+ const keep = Boolean(options.keep);
31
+ const baseDir = path.resolve(process.cwd(), args[0] || os.tmpdir());
32
+ await ensureDir(baseDir);
33
+
34
+ const workspaceRoot = await fs.mkdtemp(path.join(baseDir, 'aios-lite-smoke-'));
35
+ const projectDir = path.join(workspaceRoot, 'demo');
36
+ await ensureDir(projectDir);
37
+
38
+ const steps = [];
39
+ const quietLogger = createQuietLogger();
40
+
41
+ try {
42
+ logger.log(t('smoke.start', { projectDir }));
43
+
44
+ const installResult = await runInstall({
45
+ args: [projectDir],
46
+ options: {},
47
+ logger: quietLogger,
48
+ t
49
+ });
50
+ assertStep(installResult.copied.length > 0, 'install copied zero files');
51
+ steps.push('install');
52
+ logger.log(t('smoke.step_ok', { step: 'install' }));
53
+
54
+ const setupResult = await runSetupContext({
55
+ args: [projectDir],
56
+ options: {
57
+ defaults: true,
58
+ 'project-name': 'demo',
59
+ 'project-type': 'web_app',
60
+ profile: 'developer',
61
+ framework: 'Node',
62
+ 'framework-installed': true,
63
+ language
64
+ },
65
+ logger: quietLogger,
66
+ t
67
+ });
68
+ assertStep(Boolean(setupResult.filePath), 'setup:context did not write context file');
69
+ steps.push('setup:context');
70
+ logger.log(t('smoke.step_ok', { step: 'setup:context' }));
71
+
72
+ const localeResult = await runLocaleApply({
73
+ args: [projectDir],
74
+ options: { lang: language },
75
+ logger: quietLogger,
76
+ t
77
+ });
78
+ assertStep(localeResult.copied.length > 0, 'locale:apply copied zero files');
79
+ steps.push('locale:apply');
80
+ logger.log(t('smoke.step_ok', { step: 'locale:apply' }));
81
+
82
+ const agentsResult = await runAgentsList({
83
+ args: [projectDir],
84
+ options: { lang: language },
85
+ logger: quietLogger,
86
+ t
87
+ });
88
+ assertStep(agentsResult.count >= 7, 'agents command returned unexpected agent count');
89
+ steps.push('agents');
90
+ logger.log(t('smoke.step_ok', { step: 'agents' }));
91
+
92
+ const promptResult = await runAgentPrompt({
93
+ args: ['setup', projectDir],
94
+ options: { tool: 'codex', lang: language },
95
+ logger: quietLogger,
96
+ t
97
+ });
98
+ assertStep(
99
+ promptResult.prompt.includes('.aios-lite'),
100
+ 'agent:prompt did not include expected path information'
101
+ );
102
+ steps.push('agent:prompt');
103
+ logger.log(t('smoke.step_ok', { step: 'agent:prompt' }));
104
+
105
+ const contextResult = await runContextValidate({
106
+ args: [projectDir],
107
+ options: {},
108
+ logger: quietLogger,
109
+ t
110
+ });
111
+ assertStep(contextResult.ok, 'context:validate failed');
112
+ steps.push('context:validate');
113
+ logger.log(t('smoke.step_ok', { step: 'context:validate' }));
114
+
115
+ const doctorResult = await runDoctor(projectDir);
116
+ assertStep(doctorResult.ok, 'doctor check failed');
117
+ steps.push('doctor');
118
+ logger.log(t('smoke.step_ok', { step: 'doctor' }));
119
+
120
+ await runUpdate({
121
+ args: [projectDir],
122
+ options: {},
123
+ logger: quietLogger,
124
+ t
125
+ });
126
+ steps.push('update');
127
+ logger.log(t('smoke.step_ok', { step: 'update' }));
128
+
129
+ logger.log(t('smoke.completed'));
130
+ logger.log(t('smoke.steps_count', { count: steps.length }));
131
+
132
+ return {
133
+ ok: true,
134
+ steps,
135
+ workspaceRoot,
136
+ projectDir,
137
+ kept: keep
138
+ };
139
+ } finally {
140
+ if (!keep) {
141
+ await fs.rm(workspaceRoot, { recursive: true, force: true });
142
+ logger.log(t('smoke.workspace_removed', { path: workspaceRoot }));
143
+ } else {
144
+ logger.log(t('smoke.workspace_kept', { path: workspaceRoot }));
145
+ }
146
+ }
147
+ }
148
+
149
+ module.exports = {
150
+ runSmokeTest
151
+ };
package/src/doctor.js CHANGED
@@ -2,8 +2,10 @@
2
2
 
3
3
  const path = require('node:path');
4
4
  const { REQUIRED_FILES } = require('./constants');
5
+ const { installTemplate } = require('./installer');
5
6
  const { exists } = require('./utils');
6
7
  const { validateProjectContextFile } = require('./context');
8
+ const { applyAgentLocale, resolveAgentLocale } = require('./locales');
7
9
 
8
10
  function parseMajor(version) {
9
11
  const cleaned = String(version || '').replace(/^v/, '');
@@ -72,7 +74,73 @@ async function runDoctor(targetDir) {
72
74
  };
73
75
  }
74
76
 
77
+ async function applyDoctorFixes(targetDir, report, options = {}) {
78
+ const dryRun = Boolean(options.dryRun);
79
+ const actions = [];
80
+ let changedCount = 0;
81
+
82
+ const missingRequiredFiles = report.checks
83
+ .filter((check) => !check.ok && check.id.startsWith('file:'))
84
+ .map((check) => check.params.rel);
85
+
86
+ if (missingRequiredFiles.length > 0) {
87
+ const installResult = await installTemplate(targetDir, {
88
+ overwrite: false,
89
+ dryRun,
90
+ mode: 'install'
91
+ });
92
+ const copiedRequired = installResult.copied.filter((rel) => missingRequiredFiles.includes(rel));
93
+ if (copiedRequired.length > 0) changedCount += copiedRequired.length;
94
+ actions.push({
95
+ id: 'required_files',
96
+ applied: copiedRequired.length > 0,
97
+ count: copiedRequired.length,
98
+ missingCount: missingRequiredFiles.length
99
+ });
100
+ } else {
101
+ actions.push({
102
+ id: 'required_files',
103
+ applied: false,
104
+ skipped: true,
105
+ count: 0,
106
+ missingCount: 0
107
+ });
108
+ }
109
+
110
+ if (
111
+ report.contextValidation &&
112
+ report.contextValidation.parsed &&
113
+ report.contextValidation.valid &&
114
+ report.contextValidation.data &&
115
+ report.contextValidation.data.conversation_language
116
+ ) {
117
+ const locale = resolveAgentLocale(report.contextValidation.data.conversation_language);
118
+ const localeResult = await applyAgentLocale(targetDir, locale, { dryRun });
119
+ if (localeResult.copied.length > 0) changedCount += localeResult.copied.length;
120
+ actions.push({
121
+ id: 'locale_sync',
122
+ applied: localeResult.copied.length > 0,
123
+ count: localeResult.copied.length,
124
+ locale: localeResult.locale
125
+ });
126
+ } else {
127
+ actions.push({
128
+ id: 'locale_sync',
129
+ applied: false,
130
+ skipped: true,
131
+ count: 0
132
+ });
133
+ }
134
+
135
+ return {
136
+ dryRun,
137
+ actions,
138
+ changedCount
139
+ };
140
+ }
141
+
75
142
  module.exports = {
76
143
  runDoctor,
77
- parseMajor
144
+ parseMajor,
145
+ applyDoctorFixes
78
146
  };
@@ -8,13 +8,14 @@ module.exports = {
8
8
  help_install: 'aios-lite install [path] [--force] [--dry-run] [--locale=en]',
9
9
  help_update: 'aios-lite update [path] [--dry-run] [--locale=en]',
10
10
  help_info: 'aios-lite info [path] [--locale=en]',
11
- help_doctor: 'aios-lite doctor [path] [--locale=en]',
11
+ help_doctor: 'aios-lite doctor [path] [--fix] [--dry-run] [--locale=en]',
12
12
  help_i18n_add: 'aios-lite i18n:add <locale> [--force] [--dry-run] [--locale=en]',
13
13
  help_agents: 'aios-lite agents [path] [--lang=en|pt-BR] [--locale=en]',
14
14
  help_agent_prompt: 'aios-lite agent:prompt <agent> [path] [--tool=codex|claude|gemini|opencode] [--lang=en|pt-BR] [--locale=en]',
15
15
  help_context_validate: 'aios-lite context:validate [path] [--locale=en]',
16
16
  help_setup_context: 'aios-lite setup:context [path] [--defaults] [--project-name=...] [--language=en] [--locale=en]',
17
17
  help_locale_apply: 'aios-lite locale:apply [path] [--lang=en|pt-BR] [--dry-run] [--locale=en]',
18
+ help_test_smoke: 'aios-lite test:smoke [workspace-path] [--lang=en|pt-BR] [--keep] [--locale=en]',
18
19
  unknown_command: 'Unknown command: {command}',
19
20
  error_prefix: 'Error: {message}'
20
21
  },
@@ -76,7 +77,18 @@ module.exports = {
76
77
  context_profile_value_hint: 'Use developer, beginner, or team exactly.',
77
78
  context_conversation_language_format: '`conversation_language` is not a valid BCP-47 tag',
78
79
  context_conversation_language_format_hint: 'Use values like en, en-US, pt-BR.',
79
- node_version: 'Node.js >= 18 (current: {version})'
80
+ node_version: 'Node.js >= 18 (current: {version})',
81
+ fix_start: 'Safe fix mode enabled.',
82
+ fix_start_dry_run: 'Safe fix mode enabled (dry-run).',
83
+ fix_action_required_files: 'Restore missing managed files from template',
84
+ fix_action_locale_sync: 'Synchronize active agent prompts with context language',
85
+ fix_not_applicable: 'Not applicable for current state.',
86
+ fix_target_count: 'Targets identified: {count}',
87
+ fix_applied_count: 'Changes applied: {count}',
88
+ fix_planned_count: 'Changes planned: {count}',
89
+ fix_locale: 'Resolved locale: {locale}',
90
+ fix_summary: 'Safe fix changes applied: {count}',
91
+ fix_summary_dry_run: '[dry-run] Safe fix changes planned: {count}'
80
92
  },
81
93
  i18n_add: {
82
94
  usage_error: 'Usage: aios-lite i18n:add <locale> [--force] [--dry-run] [--locale=en]',
@@ -133,5 +145,13 @@ module.exports = {
133
145
  dry_run_applied: '[dry-run] Locale pack would be applied: {locale}',
134
146
  copied_count: 'Files copied: {count}',
135
147
  missing_count: 'Missing locale files: {count}'
148
+ },
149
+ smoke: {
150
+ start: 'Running smoke test in: {projectDir}',
151
+ step_ok: 'OK: {step}',
152
+ completed: 'Smoke test completed successfully.',
153
+ steps_count: 'Validated steps: {count}',
154
+ workspace_kept: 'Workspace kept: {path}',
155
+ workspace_removed: 'Workspace removed: {path}'
136
156
  }
137
157
  };
@@ -37,7 +37,7 @@ framework: "Laravel|Rails|Django|Next.js|Nuxt|Node|..."
37
37
  framework_installed: true
38
38
  classification: "MICRO|SMALL|MEDIUM"
39
39
  conversation_language: "en"
40
- aios_lite_version: "0.1.3"
40
+ aios_lite_version: "0.1.4"
41
41
  generated_at: "ISO-8601"
42
42
  ---
43
43
 
@@ -37,7 +37,7 @@ framework: "Laravel|Rails|Django|Next.js|Nuxt|Node|..."
37
37
  framework_installed: true
38
38
  classification: "MICRO|SMALL|MEDIUM"
39
39
  conversation_language: "en"
40
- aios_lite_version: "0.1.3"
40
+ aios_lite_version: "0.1.4"
41
41
  generated_at: "ISO-8601"
42
42
  ---
43
43