@dmsdc-ai/aterm 0.1.2 → 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/bin/aterm.js +71 -1
- package/lib/aigentry.js +4 -0
- package/package.json +2 -2
- package/scripts/postinstall.js +5 -53
- package/scripts/tui-installer.js +45 -43
package/bin/aterm.js
CHANGED
|
@@ -3,7 +3,11 @@ import fs from 'node:fs';
|
|
|
3
3
|
import path from 'node:path';
|
|
4
4
|
import { spawn } from 'node:child_process';
|
|
5
5
|
import { fileURLToPath } from 'node:url';
|
|
6
|
-
import {
|
|
6
|
+
import {
|
|
7
|
+
ensureUserLayout,
|
|
8
|
+
getUserAtermConfigPath,
|
|
9
|
+
resolveAigentryConfig,
|
|
10
|
+
} from '../lib/aigentry.js';
|
|
7
11
|
|
|
8
12
|
const __filename = fileURLToPath(import.meta.url);
|
|
9
13
|
const __dirname = path.dirname(__filename);
|
|
@@ -11,6 +15,72 @@ const packageRoot = path.resolve(__dirname, '..');
|
|
|
11
15
|
const appRoot = path.join(packageRoot, 'dist', 'aterm.app');
|
|
12
16
|
const executable = path.join(appRoot, 'Contents', 'MacOS', 'aterm');
|
|
13
17
|
const frameworksDir = path.join(appRoot, 'Contents', 'Frameworks');
|
|
18
|
+
const packageJson = JSON.parse(
|
|
19
|
+
fs.readFileSync(path.join(packageRoot, 'package.json'), 'utf8'),
|
|
20
|
+
);
|
|
21
|
+
|
|
22
|
+
function printVersionAndExit() {
|
|
23
|
+
console.log(packageJson.version);
|
|
24
|
+
process.exit(0);
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
function readUserSetupState() {
|
|
28
|
+
const configPath = getUserAtermConfigPath();
|
|
29
|
+
if (!fs.existsSync(configPath)) {
|
|
30
|
+
return {
|
|
31
|
+
configPath,
|
|
32
|
+
setupCompleted: false,
|
|
33
|
+
};
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
try {
|
|
37
|
+
const config = JSON.parse(fs.readFileSync(configPath, 'utf8'));
|
|
38
|
+
return {
|
|
39
|
+
configPath,
|
|
40
|
+
setupCompleted: config.setupCompleted === true,
|
|
41
|
+
};
|
|
42
|
+
} catch (error) {
|
|
43
|
+
console.warn(`[aterm] invalid user config, rerunning setup: ${error.message}`);
|
|
44
|
+
return {
|
|
45
|
+
configPath,
|
|
46
|
+
setupCompleted: false,
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
async function maybeRunFirstRunWizard() {
|
|
52
|
+
ensureUserLayout({ version: packageJson.version });
|
|
53
|
+
const setupState = readUserSetupState();
|
|
54
|
+
if (setupState.setupCompleted) {
|
|
55
|
+
return;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
let wizardModule;
|
|
59
|
+
try {
|
|
60
|
+
wizardModule = await import('../scripts/tui-installer.js');
|
|
61
|
+
} catch (error) {
|
|
62
|
+
console.warn(`[aterm] setup wizard unavailable, launching with defaults (${error.message})`);
|
|
63
|
+
return;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
if (!wizardModule.shouldRunFirstRunWizard()) {
|
|
67
|
+
return;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
const context = wizardModule.buildFirstRunWizardContext(packageJson.version, process.cwd());
|
|
71
|
+
const wizardResult = await wizardModule.runFirstRunWizard(context);
|
|
72
|
+
if (!wizardResult) {
|
|
73
|
+
process.exit(0);
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
await wizardModule.completeFirstRunWizard(context, wizardResult);
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
if (process.argv.includes('--version') || process.argv.includes('-v')) {
|
|
80
|
+
printVersionAndExit();
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
await maybeRunFirstRunWizard();
|
|
14
84
|
const resolvedConfig = resolveAigentryConfig({ cwd: process.cwd() });
|
|
15
85
|
|
|
16
86
|
if (!fs.existsSync(executable)) {
|
package/lib/aigentry.js
CHANGED
|
@@ -246,6 +246,10 @@ export function getLegacyTeleptyShared(homeDir = os.homedir()) {
|
|
|
246
246
|
return path.join(homeDir, '.telepty', 'shared');
|
|
247
247
|
}
|
|
248
248
|
|
|
249
|
+
export function getUserAtermConfigPath(homeDir = os.homedir()) {
|
|
250
|
+
return path.join(getUserAigentryRoot(homeDir), 'config', 'aterm.json');
|
|
251
|
+
}
|
|
252
|
+
|
|
249
253
|
export function resolveInstallHomeDir() {
|
|
250
254
|
return resolveUserHomeFromSudoUser() ?? os.homedir();
|
|
251
255
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@dmsdc-ai/aterm",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.4",
|
|
4
4
|
"description": "Native aterm launcher package",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./bin/aterm.js",
|
|
@@ -17,7 +17,7 @@
|
|
|
17
17
|
"package.json"
|
|
18
18
|
],
|
|
19
19
|
"optionalDependencies": {
|
|
20
|
-
"@dmsdc-ai/aterm-darwin-arm64": "0.1.
|
|
20
|
+
"@dmsdc-ai/aterm-darwin-arm64": "0.1.4"
|
|
21
21
|
},
|
|
22
22
|
"dependencies": {
|
|
23
23
|
"@dmsdc-ai/aigentry-brain": "latest",
|
package/scripts/postinstall.js
CHANGED
|
@@ -31,12 +31,12 @@ function resolvePlatformPackage() {
|
|
|
31
31
|
return PLATFORM_PACKAGES[process.platform]?.[process.arch] ?? null;
|
|
32
32
|
}
|
|
33
33
|
|
|
34
|
-
|
|
34
|
+
function buildDefaultPlan() {
|
|
35
35
|
const mode = isGlobalInstall() ? 'global' : 'local';
|
|
36
36
|
const installRoot = process.env.INIT_CWD ? path.resolve(process.env.INIT_CWD) : process.cwd();
|
|
37
37
|
const projectRoot = mode === 'local' ? resolveProjectRoot(installRoot) : null;
|
|
38
38
|
|
|
39
|
-
|
|
39
|
+
return {
|
|
40
40
|
installLevels: mode === 'global' ? ['system', 'user'] : ['project'],
|
|
41
41
|
configPatch: {
|
|
42
42
|
shell: { default: 'zsh' },
|
|
@@ -58,25 +58,6 @@ async function collectInstallerPlan() {
|
|
|
58
58
|
mode,
|
|
59
59
|
projectRoot,
|
|
60
60
|
};
|
|
61
|
-
|
|
62
|
-
let tuiModule;
|
|
63
|
-
try {
|
|
64
|
-
tuiModule = await import('./tui-installer.js');
|
|
65
|
-
} catch (error) {
|
|
66
|
-
console.warn(`[aterm] installer TUI unavailable, falling back to defaults (${error.message})`);
|
|
67
|
-
return defaultPlan;
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
if (!tuiModule.shouldRunInstallerTui()) {
|
|
71
|
-
return defaultPlan;
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
const context = tuiModule.buildInstallerContext(mode, projectRoot);
|
|
75
|
-
const plan = await tuiModule.runInstallerTui(context);
|
|
76
|
-
return {
|
|
77
|
-
...defaultPlan,
|
|
78
|
-
...plan,
|
|
79
|
-
};
|
|
80
61
|
}
|
|
81
62
|
|
|
82
63
|
function applyInstallPlan(plan, progress) {
|
|
@@ -163,41 +144,12 @@ function installNativeBundle() {
|
|
|
163
144
|
fs.mkdirSync(path.dirname(targetApp), { recursive: true });
|
|
164
145
|
fs.cpSync(sourceApp, targetApp, { recursive: true });
|
|
165
146
|
|
|
166
|
-
console.log(`[aterm] installed native bundle from ${platformPackage}`);
|
|
167
147
|
}
|
|
168
148
|
|
|
169
|
-
|
|
170
|
-
const plan =
|
|
171
|
-
|
|
172
|
-
let tuiModule = null;
|
|
173
|
-
try {
|
|
174
|
-
tuiModule = await import('./tui-installer.js');
|
|
175
|
-
} catch {
|
|
176
|
-
tuiModule = null;
|
|
177
|
-
}
|
|
178
|
-
|
|
179
|
-
if (tuiModule?.shouldRunInstallerTui()) {
|
|
180
|
-
await tuiModule.showProgressScreen(async (progress) => {
|
|
181
|
-
applyInstallPlan(plan, progress);
|
|
182
|
-
progress('{bold}Staging native bundle{/bold}');
|
|
183
|
-
installNativeBundle();
|
|
184
|
-
progress('{green-fg}ok{/} native bundle ready');
|
|
185
|
-
});
|
|
186
|
-
|
|
187
|
-
await tuiModule.showDoneScreen([
|
|
188
|
-
'aterm setup is complete.',
|
|
189
|
-
'',
|
|
190
|
-
`Mode: ${plan.mode}`,
|
|
191
|
-
`Levels: ${plan.installLevels.join(', ')}`,
|
|
192
|
-
`Shell: ${plan.configPatch.shell?.default ?? 'zsh'}`,
|
|
193
|
-
`Workspace: ${plan.configPatch.workspace?.default ?? 'home'}`,
|
|
194
|
-
`Tailscale connect: ${plan.configPatch.tailscale?.connect_on_launch ? 'yes' : 'no'}`,
|
|
195
|
-
]);
|
|
196
|
-
return;
|
|
197
|
-
}
|
|
198
|
-
|
|
149
|
+
function main() {
|
|
150
|
+
const plan = buildDefaultPlan();
|
|
199
151
|
applyInstallPlan(plan);
|
|
200
152
|
installNativeBundle();
|
|
201
153
|
}
|
|
202
154
|
|
|
203
|
-
|
|
155
|
+
main();
|
package/scripts/tui-installer.js
CHANGED
|
@@ -1,7 +1,11 @@
|
|
|
1
|
-
import os from 'node:os';
|
|
2
1
|
import path from 'node:path';
|
|
3
2
|
import { createRequire } from 'node:module';
|
|
4
|
-
import {
|
|
3
|
+
import {
|
|
4
|
+
detectAiCliStatus,
|
|
5
|
+
resolveInstallHomeDir,
|
|
6
|
+
resolveProjectRoot,
|
|
7
|
+
updateConfigFile,
|
|
8
|
+
} from '../lib/aigentry.js';
|
|
5
9
|
|
|
6
10
|
const require = createRequire(import.meta.url);
|
|
7
11
|
|
|
@@ -56,7 +60,7 @@ function buildWorkspaceChoices(context) {
|
|
|
56
60
|
});
|
|
57
61
|
}
|
|
58
62
|
|
|
59
|
-
if (context.
|
|
63
|
+
if (context.projectRoot) {
|
|
60
64
|
choices.push({
|
|
61
65
|
title: 'current project',
|
|
62
66
|
value: 'project',
|
|
@@ -101,7 +105,7 @@ function buildConfigPatch(context, answers) {
|
|
|
101
105
|
};
|
|
102
106
|
}
|
|
103
107
|
|
|
104
|
-
export async function
|
|
108
|
+
export async function runFirstRunWizard(context) {
|
|
105
109
|
const blessed = require('blessed');
|
|
106
110
|
const prompts = (await import('prompts')).default;
|
|
107
111
|
|
|
@@ -111,10 +115,10 @@ export async function runInstallerTui(context) {
|
|
|
111
115
|
[
|
|
112
116
|
'{center}{bold}Aigentry Terminal Installer{/bold}{/center}',
|
|
113
117
|
'',
|
|
114
|
-
'This
|
|
115
|
-
'
|
|
118
|
+
'This wizard finishes your aterm setup before the native app launches.',
|
|
119
|
+
'It will save your preferred shell, workspace, and Tailscale defaults.',
|
|
116
120
|
'',
|
|
117
|
-
`
|
|
121
|
+
`Package version: ${context.version}`,
|
|
118
122
|
],
|
|
119
123
|
'{gray-fg}Press Enter to continue{/}',
|
|
120
124
|
);
|
|
@@ -136,23 +140,14 @@ export async function runInstallerTui(context) {
|
|
|
136
140
|
|
|
137
141
|
const workspaceChoices = buildWorkspaceChoices(context);
|
|
138
142
|
const defaultResponses = {
|
|
139
|
-
installLevels: context.availableLevels.map(level => level.value),
|
|
140
143
|
defaultShell: 'zsh',
|
|
141
144
|
defaultWorkspace: workspaceChoices[0]?.value ?? 'home',
|
|
142
145
|
tailscaleConnect: false,
|
|
143
146
|
};
|
|
147
|
+
let cancelled = false;
|
|
144
148
|
|
|
145
149
|
const responses = await prompts(
|
|
146
150
|
[
|
|
147
|
-
{
|
|
148
|
-
type: 'multiselect',
|
|
149
|
-
name: 'installLevels',
|
|
150
|
-
message: 'Install level selection',
|
|
151
|
-
choices: context.availableLevels,
|
|
152
|
-
initial: 0,
|
|
153
|
-
instructions: false,
|
|
154
|
-
min: 1,
|
|
155
|
-
},
|
|
156
151
|
{
|
|
157
152
|
type: 'select',
|
|
158
153
|
name: 'defaultShell',
|
|
@@ -181,23 +176,29 @@ export async function runInstallerTui(context) {
|
|
|
181
176
|
},
|
|
182
177
|
],
|
|
183
178
|
{
|
|
184
|
-
onCancel: () =>
|
|
179
|
+
onCancel: () => {
|
|
180
|
+
cancelled = true;
|
|
181
|
+
return false;
|
|
182
|
+
},
|
|
185
183
|
},
|
|
186
184
|
);
|
|
187
185
|
|
|
186
|
+
if (cancelled) {
|
|
187
|
+
return null;
|
|
188
|
+
}
|
|
189
|
+
|
|
188
190
|
const mergedAnswers = {
|
|
189
191
|
...defaultResponses,
|
|
190
192
|
...responses,
|
|
191
193
|
};
|
|
192
194
|
|
|
193
195
|
return {
|
|
194
|
-
installLevels: mergedAnswers.installLevels,
|
|
195
196
|
configPatch: buildConfigPatch(context, mergedAnswers),
|
|
196
197
|
summary: mergedAnswers,
|
|
197
198
|
};
|
|
198
199
|
}
|
|
199
200
|
|
|
200
|
-
export function
|
|
201
|
+
export function shouldRunFirstRunWizard() {
|
|
201
202
|
if (process.env.CI) {
|
|
202
203
|
return false;
|
|
203
204
|
}
|
|
@@ -207,38 +208,19 @@ export function shouldRunInstallerTui() {
|
|
|
207
208
|
return Boolean(process.stdin.isTTY && process.stdout.isTTY);
|
|
208
209
|
}
|
|
209
210
|
|
|
210
|
-
export function
|
|
211
|
+
export function buildFirstRunWizardContext(version, cwd = process.cwd()) {
|
|
211
212
|
const installHome = resolveInstallHomeDir();
|
|
213
|
+
const projectRoot = resolveProjectRoot(cwd);
|
|
212
214
|
const orchestratorPath = path.join(installHome, 'projects', 'aigentry-orchestrator');
|
|
213
215
|
const cliStatus = detectAiCliStatus(installHome);
|
|
214
|
-
const availableLevels = mode === 'global'
|
|
215
|
-
? [
|
|
216
|
-
{
|
|
217
|
-
title: 'system',
|
|
218
|
-
value: 'system',
|
|
219
|
-
description: 'Create /etc/aigentry/config/aterm.json when writable',
|
|
220
|
-
},
|
|
221
|
-
{
|
|
222
|
-
title: 'user',
|
|
223
|
-
value: 'user',
|
|
224
|
-
description: `Create ${path.join(installHome, '.aigentry')}`,
|
|
225
|
-
},
|
|
226
|
-
]
|
|
227
|
-
: [
|
|
228
|
-
{
|
|
229
|
-
title: 'project',
|
|
230
|
-
value: 'project',
|
|
231
|
-
description: `Create ${path.join(projectRoot ?? process.cwd(), '.aigentry')}`,
|
|
232
|
-
},
|
|
233
|
-
];
|
|
234
216
|
|
|
235
217
|
return {
|
|
236
|
-
|
|
218
|
+
version,
|
|
237
219
|
projectRoot,
|
|
238
220
|
cliStatus,
|
|
239
221
|
orchestratorPath,
|
|
240
222
|
orchestratorAvailable: require('node:fs').existsSync(orchestratorPath),
|
|
241
|
-
|
|
223
|
+
userConfigPath: path.join(installHome, '.aigentry', 'config', 'aterm.json'),
|
|
242
224
|
};
|
|
243
225
|
}
|
|
244
226
|
|
|
@@ -288,3 +270,23 @@ export async function showDoneScreen(summaryLines) {
|
|
|
288
270
|
'{green-fg}Run: aterm{/}',
|
|
289
271
|
);
|
|
290
272
|
}
|
|
273
|
+
|
|
274
|
+
export async function completeFirstRunWizard(context, wizardResult) {
|
|
275
|
+
const blessed = require('blessed');
|
|
276
|
+
await showProgressScreen(async (progress) => {
|
|
277
|
+
progress('{bold}Saving setup{/bold}');
|
|
278
|
+
updateConfigFile(context.userConfigPath, {
|
|
279
|
+
...wizardResult.configPatch,
|
|
280
|
+
setupCompleted: true,
|
|
281
|
+
});
|
|
282
|
+
progress(`{green-fg}ok{/} ${context.userConfigPath}`);
|
|
283
|
+
});
|
|
284
|
+
|
|
285
|
+
await showDoneScreen([
|
|
286
|
+
'aterm setup is complete.',
|
|
287
|
+
'',
|
|
288
|
+
`Shell: ${wizardResult.summary.defaultShell}`,
|
|
289
|
+
`Workspace: ${wizardResult.summary.defaultWorkspace}`,
|
|
290
|
+
`Tailscale connect: ${wizardResult.summary.tailscaleConnect ? 'yes' : 'no'}`,
|
|
291
|
+
]);
|
|
292
|
+
}
|