@dmsdc-ai/aterm 0.1.13 → 0.1.15

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/bin/aterm.js CHANGED
@@ -4,12 +4,8 @@ import path from 'node:path';
4
4
  import { spawn } from 'node:child_process';
5
5
  import { fileURLToPath } from 'node:url';
6
6
  import {
7
- detectAiCliStatus,
8
7
  ensureUserLayout,
9
- getUserAtermConfigPath,
10
8
  resolveAigentryConfig,
11
- resolveInstallHomeDir,
12
- updateConfigFile,
13
9
  } from '../lib/aigentry.js';
14
10
 
15
11
  const __filename = fileURLToPath(import.meta.url);
@@ -22,125 +18,12 @@ const packageJson = JSON.parse(
22
18
  fs.readFileSync(path.join(packageRoot, 'package.json'), 'utf8'),
23
19
  );
24
20
 
25
- function printVersionAndExit() {
21
+ if (process.argv.includes('--version') || process.argv.includes('-v')) {
26
22
  console.log(packageJson.version);
27
23
  process.exit(0);
28
24
  }
29
25
 
30
- function readUserSetupState() {
31
- const configPath = getUserAtermConfigPath();
32
- if (!fs.existsSync(configPath)) {
33
- return {
34
- configPath,
35
- setupCompleted: false,
36
- };
37
- }
38
-
39
- try {
40
- const config = JSON.parse(fs.readFileSync(configPath, 'utf8'));
41
- return {
42
- configPath,
43
- setupCompleted: config.setupCompleted === true,
44
- };
45
- } catch (error) {
46
- console.warn(`[aterm] invalid user config, rerunning setup: ${error.message}`);
47
- return {
48
- configPath,
49
- setupCompleted: false,
50
- };
51
- }
52
- }
53
-
54
- async function maybeRunFirstRunWizard() {
55
- ensureUserLayout({ version: packageJson.version });
56
- const setupState = readUserSetupState();
57
- if (setupState.setupCompleted) {
58
- return;
59
- }
60
-
61
- let wizardModule;
62
- try {
63
- wizardModule = await import('../scripts/tui-installer.js');
64
- } catch (error) {
65
- console.warn(`[aterm] setup wizard unavailable, launching with defaults (${error.message})`);
66
- return;
67
- }
68
-
69
- if (!wizardModule.shouldRunFirstRunWizard()) {
70
- return;
71
- }
72
-
73
- const context = wizardModule.buildFirstRunWizardContext(packageJson.version, process.cwd());
74
- const wizardResult = await wizardModule.runFirstRunWizard(context);
75
- if (!wizardResult) {
76
- process.exit(0);
77
- }
78
-
79
- await wizardModule.completeFirstRunWizard(context, wizardResult);
80
- }
81
-
82
- async function maybeRunConfigMigration() {
83
- const configPath = getUserAtermConfigPath();
84
- if (!fs.existsSync(configPath)) return;
85
-
86
- let config;
87
- try {
88
- config = JSON.parse(fs.readFileSync(configPath, 'utf8'));
89
- } catch { return; }
90
-
91
- if (!config.setupCompleted) return;
92
-
93
- const isTTY = process.stdin.isTTY && process.stdout.isTTY;
94
- const cliStatus = detectAiCliStatus(resolveInstallHomeDir());
95
- const patch = {};
96
- const questions = [];
97
-
98
- // Check each field individually — users from any version get prompted only for THEIR missing fields
99
- if (!config.ai?.defaultCLI) {
100
- questions.push({
101
- type: 'select',
102
- name: 'defaultCLI',
103
- message: 'Default AI CLI for orchestrator workspace',
104
- choices: [
105
- { title: 'claude', value: 'claude', disabled: !cliStatus.claude },
106
- { title: 'codex', value: 'codex', disabled: !cliStatus.codex },
107
- { title: 'gemini', value: 'gemini', disabled: !cliStatus.gemini },
108
- { title: 'none (plain zsh)', value: 'none' },
109
- ],
110
- initial: cliStatus.claude ? 0 : cliStatus.codex ? 1 : cliStatus.gemini ? 2 : 3,
111
- });
112
- }
113
-
114
- if (questions.length === 0) return;
115
-
116
- if (isTTY) {
117
- try {
118
- const prompts = (await import('prompts')).default;
119
- const responses = await prompts(questions);
120
- if (responses.defaultCLI) {
121
- patch.ai = { ...config.ai, defaultCLI: responses.defaultCLI };
122
- }
123
- } catch { /* fall through to auto-detect */ }
124
- }
125
-
126
- // Auto-fill any fields not answered via prompt
127
- if (!patch.ai?.defaultCLI && !config.ai?.defaultCLI) {
128
- const auto = cliStatus.claude ? 'claude' : cliStatus.codex ? 'codex' : cliStatus.gemini ? 'gemini' : 'none';
129
- patch.ai = { ...config.ai, ...patch.ai, defaultCLI: auto };
130
- }
131
-
132
- if (Object.keys(patch).length > 0) {
133
- updateConfigFile(configPath, patch);
134
- }
135
- }
136
-
137
- if (process.argv.includes('--version') || process.argv.includes('-v')) {
138
- printVersionAndExit();
139
- }
140
-
141
- await maybeRunFirstRunWizard();
142
- await maybeRunConfigMigration();
143
- const resolvedConfig = resolveAigentryConfig({ cwd: process.cwd() });
26
+ ensureUserLayout({ version: packageJson.version });
144
27
 
145
28
  if (!fs.existsSync(executable)) {
146
29
  console.error('[aterm] native app bundle is not installed');
@@ -148,6 +31,7 @@ if (!fs.existsSync(executable)) {
148
31
  process.exit(1);
149
32
  }
150
33
 
34
+ const resolvedConfig = resolveAigentryConfig({ cwd: process.cwd() });
151
35
  for (const warning of resolvedConfig.warnings) {
152
36
  console.warn(warning);
153
37
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dmsdc-ai/aterm",
3
- "version": "0.1.13",
3
+ "version": "0.1.15",
4
4
  "description": "Native aterm launcher package",
5
5
  "type": "module",
6
6
  "main": "./bin/aterm.js",
@@ -17,15 +17,13 @@
17
17
  "package.json"
18
18
  ],
19
19
  "optionalDependencies": {
20
- "@dmsdc-ai/aterm-darwin-arm64": "0.1.13"
20
+ "@dmsdc-ai/aterm-darwin-arm64": "0.1.15"
21
21
  },
22
22
  "dependencies": {
23
23
  "@dmsdc-ai/aigentry-brain": "latest",
24
24
  "@dmsdc-ai/aigentry-deliberation": "latest",
25
25
  "@dmsdc-ai/aigentry-devkit": "latest",
26
- "@dmsdc-ai/aigentry-telepty": "latest",
27
- "blessed": "^0.1.81",
28
- "prompts": "^2.4.2"
26
+ "@dmsdc-ai/aigentry-telepty": "latest"
29
27
  },
30
28
  "license": "UNLICENSED",
31
29
  "publishConfig": {
@@ -1,311 +0,0 @@
1
- import path from 'node:path';
2
- import { createRequire } from 'node:module';
3
- import {
4
- detectAiCliStatus,
5
- resolveInstallHomeDir,
6
- resolveProjectRoot,
7
- updateConfigFile,
8
- } from '../lib/aigentry.js';
9
-
10
- const require = createRequire(import.meta.url);
11
-
12
- function waitForKeypress(screen, keys = ['enter', 'space', 'escape']) {
13
- return new Promise((resolve) => {
14
- const handler = (_, key) => {
15
- if (!key || !keys.includes(key.name)) {
16
- return;
17
- }
18
- screen.off('keypress', handler);
19
- resolve();
20
- };
21
- screen.on('keypress', handler);
22
- });
23
- }
24
-
25
- async function showInfoScreen(blessed, title, lines, footer) {
26
- const screen = blessed.screen({
27
- smartCSR: true,
28
- title: 'aterm installer',
29
- fullUnicode: true,
30
- });
31
-
32
- blessed.box({
33
- parent: screen,
34
- top: 'center',
35
- left: 'center',
36
- width: '78%',
37
- height: Math.max(12, lines.length + 6),
38
- border: { type: 'line' },
39
- tags: true,
40
- label: ` ${title} `,
41
- style: {
42
- border: { fg: 'cyan' },
43
- fg: 'white',
44
- },
45
- content: `${lines.join('\n')}\n\n${footer}`,
46
- });
47
-
48
- screen.render();
49
- await waitForKeypress(screen);
50
- screen.destroy();
51
- // Reset terminal modes that blessed may leave set (DECCKM, keypad)
52
- // so that subsequent prompts receive normal arrow key sequences.
53
- process.stdout.write('\x1b[?1l\x1b>');
54
- }
55
-
56
- function buildWorkspaceChoices(context) {
57
- const choices = [];
58
- if (context.orchestratorAvailable) {
59
- choices.push({
60
- title: 'aigentry-orchestrator',
61
- value: 'orchestrator',
62
- description: context.orchestratorPath,
63
- });
64
- }
65
-
66
- if (context.projectRoot) {
67
- choices.push({
68
- title: 'current project',
69
- value: 'project',
70
- description: context.projectRoot,
71
- });
72
- }
73
-
74
- choices.push({
75
- title: 'home directory',
76
- value: 'home',
77
- description: resolveInstallHomeDir(),
78
- });
79
-
80
- return choices;
81
- }
82
-
83
- function buildConfigPatch(context, answers) {
84
- const workspacePathMap = {
85
- orchestrator: context.orchestratorPath,
86
- project: context.projectRoot,
87
- home: resolveInstallHomeDir(),
88
- };
89
-
90
- return {
91
- shell: {
92
- default: answers.defaultShell,
93
- },
94
- workspace: {
95
- default: answers.defaultWorkspace,
96
- path: workspacePathMap[answers.defaultWorkspace] ?? resolveInstallHomeDir(),
97
- },
98
- orchestrator: {
99
- enabled: answers.defaultWorkspace === 'orchestrator',
100
- path: context.orchestratorPath,
101
- },
102
- tailscale: {
103
- connect_on_launch: answers.tailscaleConnect,
104
- },
105
- ai: {
106
- defaultCLI: answers.defaultCLI,
107
- detected_clis: context.cliStatus,
108
- },
109
- };
110
- }
111
-
112
- export async function runFirstRunWizard(context) {
113
- const blessed = require('blessed');
114
- const prompts = (await import('prompts')).default;
115
-
116
- await showInfoScreen(
117
- blessed,
118
- ' aterm Installer ',
119
- [
120
- '{center}{bold}Aigentry Terminal Installer{/bold}{/center}',
121
- '',
122
- 'This wizard finishes your aterm setup before the native app launches.',
123
- 'It will save your preferred shell, workspace, and Tailscale defaults.',
124
- '',
125
- `Package version: ${context.version}`,
126
- ],
127
- '{gray-fg}Press Enter to continue{/}',
128
- );
129
-
130
- const cliLines = [
131
- '{bold}AI CLI detection{/bold}',
132
- '',
133
- `claude ${context.cliStatus.claude ? '✅' : '❌'}`,
134
- `codex ${context.cliStatus.codex ? '✅' : '❌'}`,
135
- `gemini ${context.cliStatus.gemini ? '✅' : '❌'}`,
136
- ];
137
-
138
- await showInfoScreen(
139
- blessed,
140
- ' CLI Status ',
141
- cliLines,
142
- '{gray-fg}Press Enter to continue{/}',
143
- );
144
-
145
- const workspaceChoices = buildWorkspaceChoices(context);
146
- const defaultResponses = {
147
- defaultShell: 'zsh',
148
- defaultWorkspace: workspaceChoices[0]?.value ?? 'home',
149
- defaultCLI: context.cliStatus.claude ? 'claude' : context.cliStatus.codex ? 'codex' : context.cliStatus.gemini ? 'gemini' : 'none',
150
- tailscaleConnect: false,
151
- };
152
- let cancelled = false;
153
-
154
- const responses = await prompts(
155
- [
156
- {
157
- type: 'select',
158
- name: 'defaultShell',
159
- message: 'Default shell',
160
- choices: [
161
- { title: 'zsh', value: 'zsh' },
162
- { title: 'bash', value: 'bash' },
163
- { title: 'fish', value: 'fish' },
164
- ],
165
- initial: 0,
166
- },
167
- {
168
- type: 'select',
169
- name: 'defaultWorkspace',
170
- message: 'Default workspace / orchestrator target',
171
- choices: workspaceChoices,
172
- initial: 0,
173
- },
174
- {
175
- type: 'select',
176
- name: 'defaultCLI',
177
- message: 'Default AI CLI for orchestrator workspace',
178
- choices: [
179
- { title: 'claude', value: 'claude', disabled: !context.cliStatus.claude },
180
- { title: 'codex', value: 'codex', disabled: !context.cliStatus.codex },
181
- { title: 'gemini', value: 'gemini', disabled: !context.cliStatus.gemini },
182
- { title: 'none (plain zsh)', value: 'none' },
183
- ],
184
- initial: context.cliStatus.claude ? 0 : context.cliStatus.codex ? 1 : context.cliStatus.gemini ? 2 : 3,
185
- },
186
- {
187
- type: 'toggle',
188
- name: 'tailscaleConnect',
189
- message: 'Enable Tailscale connect on launch?',
190
- initial: false,
191
- active: 'yes',
192
- inactive: 'no',
193
- },
194
- ],
195
- {
196
- onCancel: () => {
197
- cancelled = true;
198
- return false;
199
- },
200
- },
201
- );
202
-
203
- if (cancelled) {
204
- return null;
205
- }
206
-
207
- const mergedAnswers = {
208
- ...defaultResponses,
209
- ...responses,
210
- };
211
-
212
- return {
213
- configPatch: buildConfigPatch(context, mergedAnswers),
214
- summary: mergedAnswers,
215
- };
216
- }
217
-
218
- export function shouldRunFirstRunWizard() {
219
- if (process.env.CI) {
220
- return false;
221
- }
222
- if (process.env.npm_config_yes === 'true') {
223
- return false;
224
- }
225
- return Boolean(process.stdin.isTTY && process.stdout.isTTY);
226
- }
227
-
228
- export function buildFirstRunWizardContext(version, cwd = process.cwd()) {
229
- const installHome = resolveInstallHomeDir();
230
- const projectRoot = resolveProjectRoot(cwd);
231
- const orchestratorPath = path.join(installHome, 'projects', 'aigentry-orchestrator');
232
- const cliStatus = detectAiCliStatus(installHome);
233
-
234
- return {
235
- version,
236
- projectRoot,
237
- cliStatus,
238
- orchestratorPath,
239
- orchestratorAvailable: require('node:fs').existsSync(orchestratorPath),
240
- userConfigPath: path.join(installHome, '.aigentry', 'config', 'aterm.json'),
241
- };
242
- }
243
-
244
- export async function showProgressScreen(runSteps) {
245
- const blessed = require('blessed');
246
- const screen = blessed.screen({
247
- smartCSR: true,
248
- title: 'aterm installer',
249
- fullUnicode: true,
250
- });
251
-
252
- const box = blessed.log({
253
- parent: screen,
254
- top: 'center',
255
- left: 'center',
256
- width: '84%',
257
- height: '70%',
258
- border: { type: 'line' },
259
- tags: true,
260
- label: ' Installation Progress ',
261
- style: {
262
- border: { fg: 'green' },
263
- fg: 'white',
264
- },
265
- scrollable: true,
266
- alwaysScroll: true,
267
- scrollbar: { ch: ' ', inverse: true },
268
- });
269
-
270
- const report = (line) => {
271
- box.add(line);
272
- screen.render();
273
- };
274
-
275
- screen.render();
276
- await runSteps(report);
277
- await new Promise(resolve => setTimeout(resolve, 250));
278
- screen.destroy();
279
- process.stdout.write('\x1b[?1l\x1b>');
280
- }
281
-
282
- export async function showDoneScreen(summaryLines) {
283
- const blessed = require('blessed');
284
- await showInfoScreen(
285
- blessed,
286
- ' Install Complete ',
287
- summaryLines,
288
- '{green-fg}Run: aterm{/}',
289
- );
290
- }
291
-
292
- export async function completeFirstRunWizard(context, wizardResult) {
293
- const blessed = require('blessed');
294
- await showProgressScreen(async (progress) => {
295
- progress('{bold}Saving setup{/bold}');
296
- updateConfigFile(context.userConfigPath, {
297
- ...wizardResult.configPatch,
298
- setupCompleted: true,
299
- });
300
- progress(`{green-fg}ok{/} ${context.userConfigPath}`);
301
- });
302
-
303
- await showDoneScreen([
304
- 'aterm setup is complete.',
305
- '',
306
- `Shell: ${wizardResult.summary.defaultShell}`,
307
- `AI CLI: ${wizardResult.summary.defaultCLI}`,
308
- `Workspace: ${wizardResult.summary.defaultWorkspace}`,
309
- `Tailscale connect: ${wizardResult.summary.tailscaleConnect ? 'yes' : 'no'}`,
310
- ]);
311
- }