tsic-ainode 1.0.0 → 1.1.0
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/index.js +59 -61
- package/package.json +1 -1
package/bin/index.js
CHANGED
|
@@ -54,36 +54,36 @@ function detectLocale() {
|
|
|
54
54
|
// ---------------------------------------------------------------------------
|
|
55
55
|
const TOOLS = [
|
|
56
56
|
{
|
|
57
|
-
id:
|
|
58
|
-
nameKey:
|
|
59
|
-
detect:
|
|
60
|
-
install:
|
|
57
|
+
id: 'claude',
|
|
58
|
+
nameKey: 'tool_claude',
|
|
59
|
+
detect: () => fs.existsSync(path.join(HOME, '.claude')),
|
|
60
|
+
install: installClaude,
|
|
61
61
|
},
|
|
62
62
|
{
|
|
63
|
-
id:
|
|
64
|
-
nameKey:
|
|
65
|
-
detect:
|
|
66
|
-
|
|
67
|
-
|
|
63
|
+
id: 'cursor',
|
|
64
|
+
nameKey: 'tool_cursor',
|
|
65
|
+
detect: () => cmdExists('cursor') ||
|
|
66
|
+
fs.existsSync(path.join(HOME, '.cursor')) ||
|
|
67
|
+
fs.existsSync(path.join(CWD, '.cursor')),
|
|
68
|
+
install: installCursor,
|
|
68
69
|
},
|
|
69
70
|
{
|
|
70
|
-
id:
|
|
71
|
-
nameKey:
|
|
72
|
-
detect:
|
|
73
|
-
install:
|
|
71
|
+
id: 'codex',
|
|
72
|
+
nameKey: 'tool_codex',
|
|
73
|
+
detect: () => cmdExists('codex'),
|
|
74
|
+
install: installCodex,
|
|
74
75
|
},
|
|
75
76
|
{
|
|
76
|
-
id:
|
|
77
|
-
nameKey:
|
|
78
|
-
detect:
|
|
79
|
-
install:
|
|
77
|
+
id: 'gemini',
|
|
78
|
+
nameKey: 'tool_gemini',
|
|
79
|
+
detect: () => cmdExists('gemini') || cmdExists('gemini-cli'),
|
|
80
|
+
install: installGemini,
|
|
80
81
|
},
|
|
81
82
|
{
|
|
82
|
-
id:
|
|
83
|
-
nameKey:
|
|
84
|
-
detect:
|
|
85
|
-
|
|
86
|
-
install: installAntigravity,
|
|
83
|
+
id: 'antigravity',
|
|
84
|
+
nameKey: 'tool_antigravity',
|
|
85
|
+
detect: () => cmdExists('antigravity'),
|
|
86
|
+
install: installAntigravity,
|
|
87
87
|
},
|
|
88
88
|
];
|
|
89
89
|
|
|
@@ -105,7 +105,7 @@ function copyTemplate(src, dest) {
|
|
|
105
105
|
}
|
|
106
106
|
|
|
107
107
|
function appendToFile(src, dest) {
|
|
108
|
-
const tag
|
|
108
|
+
const tag = '<!-- tsic-ainode -->';
|
|
109
109
|
const content = fs.readFileSync(src, 'utf8');
|
|
110
110
|
if (fs.existsSync(dest)) {
|
|
111
111
|
const existing = fs.readFileSync(dest, 'utf8');
|
|
@@ -164,47 +164,48 @@ function createRL() {
|
|
|
164
164
|
}
|
|
165
165
|
|
|
166
166
|
function ask(rl, question) {
|
|
167
|
-
return new Promise(resolve => rl.question(question, resolve));
|
|
167
|
+
return new Promise(resolve => rl.question(question, ans => resolve(ans.trim())));
|
|
168
168
|
}
|
|
169
169
|
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
});
|
|
170
|
+
// Single-prompt choice: shows numbered list, returns chosen item (default: first)
|
|
171
|
+
async function askChoice(rl, question, choices) {
|
|
172
|
+
const opts = choices.map((c, i) => ` ${i + 1}. ${c}`).join('\n');
|
|
173
|
+
const ans = await ask(rl, `${question}\n${opts}\n> `);
|
|
174
|
+
const idx = parseInt(ans, 10) - 1;
|
|
175
|
+
if (isNaN(idx) || idx < 0 || idx >= choices.length) return choices[0];
|
|
176
|
+
return choices[idx];
|
|
178
177
|
}
|
|
179
178
|
|
|
179
|
+
// Single-prompt checkbox: shows numbered list with detected pre-selected.
|
|
180
|
+
// User types space-separated numbers to select, or Enter to accept detected defaults.
|
|
180
181
|
async function askCheckbox(rl, question, items) {
|
|
182
|
+
const defaultNums = items
|
|
183
|
+
.map((item, i) => (item.detected ? String(i + 1) : null))
|
|
184
|
+
.filter(Boolean);
|
|
185
|
+
|
|
181
186
|
console.log(`\n${question}`);
|
|
182
|
-
const selected = new Set(items.filter(i => i.detected).map(i => i.id));
|
|
183
187
|
items.forEach((item, i) => {
|
|
184
|
-
const
|
|
185
|
-
|
|
186
|
-
console.log(` ${i + 1}. ${check} ${item.label}${hint}`);
|
|
188
|
+
const mark = item.detected ? '[✓]' : '[ ]';
|
|
189
|
+
console.log(` ${i + 1}. ${mark} ${item.label}`);
|
|
187
190
|
});
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
}
|
|
199
|
-
});
|
|
200
|
-
// redraw
|
|
201
|
-
items.forEach((item, i) => {
|
|
202
|
-
const check = selected.has(item.id) ? '◉' : '○';
|
|
203
|
-
process.stdout.write(` ${i + 1}. ${check} ${item.label}\n`);
|
|
204
|
-
});
|
|
205
|
-
console.log(' (Enter to confirm, or toggle more)');
|
|
191
|
+
|
|
192
|
+
const hint = defaultNums.length > 0
|
|
193
|
+
? `(Enter 確認選取 ${defaultNums.join(' ')},或輸入編號如 "1 3")`
|
|
194
|
+
: '(輸入編號如 "1 3",多選用空白分隔)';
|
|
195
|
+
console.log(` ${hint}`);
|
|
196
|
+
|
|
197
|
+
const ans = await ask(rl, '> ');
|
|
198
|
+
|
|
199
|
+
if (ans === '' && defaultNums.length > 0) {
|
|
200
|
+
return items.filter(item => item.detected);
|
|
206
201
|
}
|
|
207
|
-
|
|
202
|
+
|
|
203
|
+
const selected = ans.split(/\s+/)
|
|
204
|
+
.map(n => parseInt(n, 10) - 1)
|
|
205
|
+
.filter(i => i >= 0 && i < items.length)
|
|
206
|
+
.map(i => items[i]);
|
|
207
|
+
|
|
208
|
+
return selected;
|
|
208
209
|
}
|
|
209
210
|
|
|
210
211
|
// ---------------------------------------------------------------------------
|
|
@@ -232,11 +233,11 @@ async function main() {
|
|
|
232
233
|
loadLocale(locale);
|
|
233
234
|
|
|
234
235
|
// Detect tools
|
|
235
|
-
const detectedIds = TOOLS.filter(
|
|
236
|
+
const detectedIds = TOOLS.filter(tool => tool.detect()).map(tool => tool.id);
|
|
236
237
|
if (detectedIds.length > 0) {
|
|
237
238
|
console.log(`\n${T.detect_title}`);
|
|
238
239
|
detectedIds.forEach(id => {
|
|
239
|
-
const tool = TOOLS.find(
|
|
240
|
+
const tool = TOOLS.find(tool => tool.id === id);
|
|
240
241
|
console.log(` ✓ ${T[tool.nameKey] || tool.id}`);
|
|
241
242
|
});
|
|
242
243
|
} else {
|
|
@@ -267,16 +268,13 @@ async function main() {
|
|
|
267
268
|
|
|
268
269
|
// Install
|
|
269
270
|
console.log(`\n${T.installing}`);
|
|
270
|
-
const results = [];
|
|
271
271
|
for (const tool of chosen) {
|
|
272
272
|
try {
|
|
273
273
|
const dest = tool.install(scope);
|
|
274
|
-
console.log(` ${T.installed_ok}: ${tool.label}`);
|
|
274
|
+
console.log(` ✓ ${T.installed_ok}: ${tool.label}`);
|
|
275
275
|
console.log(` → ${dest}`);
|
|
276
|
-
results.push({ tool, dest, ok: true });
|
|
277
276
|
} catch (err) {
|
|
278
277
|
console.error(` ✗ ${T.err_write}: ${tool.label} — ${err.message}`);
|
|
279
|
-
results.push({ tool, ok: false });
|
|
280
278
|
}
|
|
281
279
|
}
|
|
282
280
|
|
package/package.json
CHANGED