@openlife/cli 1.7.13 → 1.8.2

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.
Files changed (35) hide show
  1. package/INSTALL.md +29 -1
  2. package/dist/cli/ChatTui.js +32 -0
  3. package/dist/cli/InstallModules.js +17 -2
  4. package/dist/cli/InstallWizardV2.js +110 -0
  5. package/dist/cli/install/Multiselect.js +285 -0
  6. package/dist/cli/install/OAuthRunner.js +170 -0
  7. package/dist/cli/install/Phases.js +864 -0
  8. package/dist/cli/install/ProvidersCatalog.js +320 -0
  9. package/dist/cli/install/WizardIO.js +271 -0
  10. package/dist/cli/install/types.js +17 -0
  11. package/dist/index.js +170 -35
  12. package/dist/orchestrator/ConsequenceForecaster.js +24 -1
  13. package/dist/orchestrator/DreamGoalStore.js +130 -0
  14. package/dist/orchestrator/Gatekeeper.js +14 -0
  15. package/dist/orchestrator/Gateway.js +194 -15
  16. package/dist/orchestrator/ModelManager.js +7 -1
  17. package/dist/orchestrator/OrchestrationLoop.js +12 -0
  18. package/dist/orchestrator/ParallelOrchestrationLoop.js +12 -2
  19. package/dist/orchestrator/RuntimePolicy.js +4 -1
  20. package/dist/orchestrator/ServiceCompletionPolicy.js +15 -0
  21. package/dist/orchestrator/SynthesizerAgent.js +20 -1
  22. package/dist/orchestrator/TaskExecutor.js +53 -0
  23. package/dist/orchestrator/capability/CapabilityGenesisEngine.js +66 -11
  24. package/dist/test_capability_genesis_engine.js +1 -1
  25. package/dist/test_chat_smoke_command.js +59 -0
  26. package/dist/test_dream_goal_commands.js +76 -0
  27. package/dist/test_gateway_telegram_formatting.js +74 -0
  28. package/dist/test_install_wizard_v2.js +193 -0
  29. package/dist/test_on_demand_voice_reply.js +65 -0
  30. package/dist/test_remaining_sprints_contracts.js +103 -0
  31. package/dist/test_runtime_policy.js +25 -6
  32. package/dist/test_service_completion_policy.js +7 -0
  33. package/dist/test_subsystems_routing_governance.js +13 -3
  34. package/dist/test_task_executor_gemini_api.js +68 -0
  35. package/package.json +5 -3
@@ -0,0 +1,320 @@
1
+ "use strict";
2
+ // src/cli/install/ProvidersCatalog.ts
3
+ // Hermes-parity provider catalog — ~30 providers organized in 5 tiers.
4
+ //
5
+ // Each row carries:
6
+ // - id (machine-readable, matches ProviderId in types.ts)
7
+ // - label (display name)
8
+ // - description (1-liner shown in the multiselect)
9
+ // - envVar (which .env var holds the credential, when api-key strategy)
10
+ // - oauthCli (which CLI binary handles `<cli> login`, when oauth strategy)
11
+ // - tier (organizational grouping for the multiselect header)
12
+ // - tags (filter chips: 'cloud' | 'local' | 'router' | 'oauth' | 'oss')
13
+ //
14
+ // To add a new provider: append the row here, add the ProviderId to types.ts,
15
+ // and (if it collects API keys) wire the env var in InstallModules.API_KEY_ENV_MAP.
16
+ Object.defineProperty(exports, "__esModule", { value: true });
17
+ exports.TIER_LABELS = exports.PROVIDERS_CATALOG = void 0;
18
+ exports.getProvider = getProvider;
19
+ exports.providersByTier = providersByTier;
20
+ exports.oauthProviders = oauthProviders;
21
+ exports.PROVIDERS_CATALOG = Object.freeze([
22
+ // ── Tier 1: first-class, ship-it-now providers ────────────────────────
23
+ {
24
+ id: 'openai-api',
25
+ label: 'OpenAI API',
26
+ description: 'GPT-5.5, GPT-5.4-mini, embeddings (api.openai.com)',
27
+ envVar: 'OPENAI_API_KEY',
28
+ oauthCli: '',
29
+ tier: 'tier-1',
30
+ tags: ['cloud'],
31
+ blurb: 'Direct API — fastest setup, paid per-token',
32
+ },
33
+ {
34
+ id: 'anthropic',
35
+ label: 'Anthropic',
36
+ description: 'Claude Opus 4.7, Sonnet 4.6, Haiku 4.5 (api.anthropic.com)',
37
+ envVar: 'ANTHROPIC_API_KEY',
38
+ oauthCli: '',
39
+ tier: 'tier-1',
40
+ tags: ['cloud'],
41
+ blurb: 'Direct API — Claude family. OAuth NOT supported (use API key only)',
42
+ },
43
+ {
44
+ id: 'gemini-api',
45
+ label: 'Google Gemini API',
46
+ description: 'Gemini 3.1 Pro/Flash (generativelanguage.googleapis.com)',
47
+ envVar: 'GEMINI_API_KEY',
48
+ oauthCli: '',
49
+ tier: 'tier-1',
50
+ tags: ['cloud'],
51
+ blurb: 'Direct API — generous free tier, multimodal',
52
+ },
53
+ {
54
+ id: 'openrouter',
55
+ label: 'OpenRouter',
56
+ description: 'Unified gateway to 200+ models (openrouter.ai)',
57
+ envVar: 'OPENROUTER_API_KEY',
58
+ oauthCli: '',
59
+ tier: 'tier-1',
60
+ tags: ['cloud', 'router'],
61
+ blurb: 'Single key, every model — pay-as-you-go aggregation',
62
+ },
63
+ {
64
+ id: 'ollama',
65
+ label: 'Ollama (local)',
66
+ description: 'Run llama, qwen, mistral, etc. locally (localhost:11434)',
67
+ envVar: '',
68
+ oauthCli: '',
69
+ tier: 'tier-1',
70
+ tags: ['local', 'oss'],
71
+ blurb: 'Local inference — no API key needed, GPU/CPU on your machine',
72
+ },
73
+ // ── Tier 2: CLI-based and popular alternatives ────────────────────────
74
+ {
75
+ id: 'openai-cli',
76
+ label: 'OpenAI Codex (OAuth)',
77
+ description: 'OAuth login via @openai/codex CLI — uses Plus/Pro subscription',
78
+ envVar: '',
79
+ oauthCli: 'codex',
80
+ tier: 'tier-2',
81
+ tags: ['cloud', 'oauth'],
82
+ blurb: 'Browser OAuth — reuses your ChatGPT Plus/Pro session, no API costs',
83
+ },
84
+ {
85
+ id: 'gemini-cli',
86
+ label: 'Google Gemini CLI (OAuth)',
87
+ description: 'OAuth login via gemini-cli — uses Google account quota',
88
+ envVar: '',
89
+ oauthCli: 'gemini',
90
+ tier: 'tier-2',
91
+ tags: ['cloud', 'oauth'],
92
+ blurb: 'Browser OAuth — uses your Google account, generous free tier',
93
+ },
94
+ {
95
+ id: 'xai',
96
+ label: 'xAI Grok',
97
+ description: 'Grok 4, Grok-vision (api.x.ai) — API key OR device-auth OAuth',
98
+ envVar: 'XAI_API_KEY',
99
+ oauthCli: 'grok',
100
+ tier: 'tier-2',
101
+ tags: ['cloud', 'oauth'],
102
+ blurb: 'Direct API or browser OAuth — Grok models, X integration',
103
+ },
104
+ {
105
+ id: 'deepseek',
106
+ label: 'DeepSeek',
107
+ description: 'DeepSeek-V3, DeepSeek-Coder (api.deepseek.com)',
108
+ envVar: 'DEEPSEEK_API_KEY',
109
+ oauthCli: '',
110
+ tier: 'tier-2',
111
+ tags: ['cloud'],
112
+ blurb: 'Strong coder models, competitive pricing',
113
+ },
114
+ {
115
+ id: 'groq',
116
+ label: 'Groq',
117
+ description: 'Ultra-fast inference on LPUs (api.groq.com)',
118
+ envVar: 'GROQ_API_KEY',
119
+ oauthCli: '',
120
+ tier: 'tier-2',
121
+ tags: ['cloud'],
122
+ blurb: 'Lowest-latency inference, llama/mixtral on LPU hardware',
123
+ },
124
+ {
125
+ id: 'together',
126
+ label: 'Together AI',
127
+ description: 'Open-source models at scale (api.together.xyz)',
128
+ envVar: 'TOGETHER_API_KEY',
129
+ oauthCli: '',
130
+ tier: 'tier-2',
131
+ tags: ['cloud', 'oss'],
132
+ blurb: 'Hosted OSS models — llama, mixtral, deepseek, qwen, etc.',
133
+ },
134
+ {
135
+ id: 'mistral',
136
+ label: 'Mistral AI',
137
+ description: 'Mistral Large, Codestral (api.mistral.ai)',
138
+ envVar: 'MISTRAL_API_KEY',
139
+ oauthCli: '',
140
+ tier: 'tier-2',
141
+ tags: ['cloud'],
142
+ blurb: 'European AI lab — strong general + coder models',
143
+ },
144
+ // ── Tier 3: enterprise / specialty / regional ─────────────────────────
145
+ {
146
+ id: 'bedrock',
147
+ label: 'AWS Bedrock',
148
+ description: 'Claude, Llama, Titan via AWS (bedrock.amazonaws.com)',
149
+ envVar: 'AWS_ACCESS_KEY_ID',
150
+ oauthCli: '',
151
+ tier: 'tier-3',
152
+ tags: ['cloud', 'enterprise'],
153
+ blurb: 'Enterprise — AWS billing, VPC integration, multi-model',
154
+ },
155
+ {
156
+ id: 'qwen',
157
+ label: 'Alibaba Qwen',
158
+ description: 'Qwen2.5, Qwen-VL (dashscope.aliyuncs.com)',
159
+ envVar: 'DASHSCOPE_API_KEY',
160
+ oauthCli: '',
161
+ tier: 'tier-3',
162
+ tags: ['cloud'],
163
+ blurb: 'Alibaba models — strong multilingual + Chinese performance',
164
+ },
165
+ {
166
+ id: 'kimi',
167
+ label: 'Moonshot Kimi',
168
+ description: 'Kimi-k2, long-context (api.moonshot.cn)',
169
+ envVar: 'MOONSHOT_API_KEY',
170
+ oauthCli: '',
171
+ tier: 'tier-3',
172
+ tags: ['cloud'],
173
+ blurb: 'Moonshot — 2M context window, Chinese-strong',
174
+ },
175
+ {
176
+ id: 'minimax',
177
+ label: 'MiniMax',
178
+ description: 'abab6.5 (api.minimax.chat)',
179
+ envVar: 'MINIMAX_API_KEY',
180
+ oauthCli: '',
181
+ tier: 'tier-3',
182
+ tags: ['cloud'],
183
+ blurb: 'MiniMax — multimodal, agent-friendly',
184
+ },
185
+ {
186
+ id: 'glm',
187
+ label: 'Zhipu GLM',
188
+ description: 'GLM-4, ChatGLM (open.bigmodel.cn)',
189
+ envVar: 'ZHIPU_API_KEY',
190
+ oauthCli: '',
191
+ tier: 'tier-3',
192
+ tags: ['cloud'],
193
+ blurb: 'Zhipu AI — GLM family, multilingual',
194
+ },
195
+ {
196
+ id: 'huggingface',
197
+ label: 'Hugging Face',
198
+ description: 'Inference API + Endpoints (api-inference.huggingface.co)',
199
+ envVar: 'HF_TOKEN',
200
+ oauthCli: '',
201
+ tier: 'tier-3',
202
+ tags: ['cloud', 'oss'],
203
+ blurb: 'Any HF model via serverless inference or dedicated endpoints',
204
+ },
205
+ {
206
+ id: 'nvidia-nim',
207
+ label: 'NVIDIA NIM',
208
+ description: 'NVIDIA-hosted optimized inference (integrate.api.nvidia.com)',
209
+ envVar: 'NVIDIA_API_KEY',
210
+ oauthCli: '',
211
+ tier: 'tier-3',
212
+ tags: ['cloud', 'enterprise'],
213
+ blurb: 'NVIDIA Inference Microservices — optimized for NVIDIA stack',
214
+ },
215
+ {
216
+ id: 'perplexity',
217
+ label: 'Perplexity',
218
+ description: 'Sonar models w/ real-time web search (api.perplexity.ai)',
219
+ envVar: 'PERPLEXITY_API_KEY',
220
+ oauthCli: '',
221
+ tier: 'tier-3',
222
+ tags: ['cloud'],
223
+ blurb: 'Web-grounded models — search-augmented responses',
224
+ },
225
+ // ── Tier 4: local / self-hosted / DIY ─────────────────────────────────
226
+ {
227
+ id: 'vllm',
228
+ label: 'vLLM (self-hosted)',
229
+ description: 'OpenAI-compatible server, self-hosted (vllm.ai)',
230
+ envVar: 'VLLM_BASE_URL',
231
+ oauthCli: '',
232
+ tier: 'tier-4',
233
+ tags: ['local', 'oss'],
234
+ blurb: 'High-throughput inference server — bring your own GPUs',
235
+ },
236
+ {
237
+ id: 'sglang',
238
+ label: 'SGLang (self-hosted)',
239
+ description: 'Fast structured-generation server (sgl-project.github.io)',
240
+ envVar: 'SGLANG_BASE_URL',
241
+ oauthCli: '',
242
+ tier: 'tier-4',
243
+ tags: ['local', 'oss'],
244
+ blurb: 'Structured output + RadixAttention — self-hosted',
245
+ },
246
+ {
247
+ id: 'llamacpp',
248
+ label: 'llama.cpp server',
249
+ description: 'GGUF inference w/ OpenAI-compat endpoint (github.com/ggml-org/llama.cpp)',
250
+ envVar: 'LLAMACPP_BASE_URL',
251
+ oauthCli: '',
252
+ tier: 'tier-4',
253
+ tags: ['local', 'oss'],
254
+ blurb: 'CPU/GPU GGUF inference — tiny footprint',
255
+ },
256
+ {
257
+ id: 'lmstudio',
258
+ label: 'LM Studio',
259
+ description: 'Desktop local-LLM app w/ OpenAI server (lmstudio.ai)',
260
+ envVar: 'LMSTUDIO_BASE_URL',
261
+ oauthCli: '',
262
+ tier: 'tier-4',
263
+ tags: ['local'],
264
+ blurb: 'Desktop app — easiest local LLM setup',
265
+ },
266
+ // ── Tier 5: routers / gateways / custom ───────────────────────────────
267
+ {
268
+ id: 'litellm',
269
+ label: 'LiteLLM Proxy',
270
+ description: 'Unified proxy for 100+ providers (litellm.ai)',
271
+ envVar: 'LITELLM_BASE_URL',
272
+ oauthCli: '',
273
+ tier: 'tier-5',
274
+ tags: ['router', 'oss'],
275
+ blurb: 'Self-hosted proxy — one endpoint, every provider',
276
+ },
277
+ {
278
+ id: 'clawrouter',
279
+ label: 'ClawRouter',
280
+ description: 'OpenAI-compatible router (clawrouter.ai)',
281
+ envVar: 'CLAWROUTER_API_KEY',
282
+ oauthCli: '',
283
+ tier: 'tier-5',
284
+ tags: ['cloud', 'router'],
285
+ blurb: 'Cloud router — multi-provider failover',
286
+ },
287
+ {
288
+ id: 'custom-openai',
289
+ label: 'Custom OpenAI-compatible',
290
+ description: 'Any provider exposing the /v1/chat/completions API',
291
+ envVar: 'CUSTOM_OPENAI_BASE_URL',
292
+ oauthCli: '',
293
+ tier: 'tier-5',
294
+ tags: ['custom'],
295
+ blurb: 'Bring your own endpoint — any OpenAI-API-compatible server',
296
+ },
297
+ ]);
298
+ exports.TIER_LABELS = Object.freeze({
299
+ 'tier-1': '⭐ Tier 1 — First-class (start here)',
300
+ 'tier-2': '🔥 Tier 2 — Popular alternatives',
301
+ 'tier-3': '🏢 Tier 3 — Enterprise & regional',
302
+ 'tier-4': '💻 Tier 4 — Local & self-hosted',
303
+ 'tier-5': '🔀 Tier 5 — Routers & custom',
304
+ });
305
+ /** Lookup by id — throws on unknown id (catches catalog desync at runtime). */
306
+ function getProvider(id) {
307
+ const found = exports.PROVIDERS_CATALOG.find(p => p.id === id);
308
+ if (!found) {
309
+ throw new Error(`PROVIDER_NOT_IN_CATALOG: ${id} — add a row to ProvidersCatalog.ts`);
310
+ }
311
+ return found;
312
+ }
313
+ /** All providers belonging to a tier — used to render the multiselect. */
314
+ function providersByTier(tier) {
315
+ return exports.PROVIDERS_CATALOG.filter(p => p.tier === tier);
316
+ }
317
+ /** OAuth-capable providers — used in the agent profile auth-strategy phase. */
318
+ function oauthProviders() {
319
+ return exports.PROVIDERS_CATALOG.filter(p => !!p.oauthCli);
320
+ }
@@ -0,0 +1,271 @@
1
+ "use strict";
2
+ // src/cli/install/WizardIO.ts
3
+ // Sequential I/O surface for the Install Wizard 2.0.
4
+ //
5
+ // Core principle: every prompt waits for an explicit Enter. No batching, no
6
+ // silent defaults. Tests inject a CannedIO; production uses the readline-based
7
+ // implementation.
8
+ //
9
+ // Reuses MatrixTheme for visual consistency with ChatTui / ConfigTui.
10
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
11
+ if (k2 === undefined) k2 = k;
12
+ var desc = Object.getOwnPropertyDescriptor(m, k);
13
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
14
+ desc = { enumerable: true, get: function() { return m[k]; } };
15
+ }
16
+ Object.defineProperty(o, k2, desc);
17
+ }) : (function(o, m, k, k2) {
18
+ if (k2 === undefined) k2 = k;
19
+ o[k2] = m[k];
20
+ }));
21
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
22
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
23
+ }) : function(o, v) {
24
+ o["default"] = v;
25
+ });
26
+ var __importStar = (this && this.__importStar) || (function () {
27
+ var ownKeys = function(o) {
28
+ ownKeys = Object.getOwnPropertyNames || function (o) {
29
+ var ar = [];
30
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
31
+ return ar;
32
+ };
33
+ return ownKeys(o);
34
+ };
35
+ return function (mod) {
36
+ if (mod && mod.__esModule) return mod;
37
+ var result = {};
38
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
39
+ __setModuleDefault(result, mod);
40
+ return result;
41
+ };
42
+ })();
43
+ Object.defineProperty(exports, "__esModule", { value: true });
44
+ exports.CannedIO = exports.ReadlineWizardIO = void 0;
45
+ const readline = __importStar(require("readline"));
46
+ const MatrixTheme_1 = require("../MatrixTheme");
47
+ /**
48
+ * Production IO — wraps node:readline. Renders with Matrix theme when stdout
49
+ * supports color; otherwise plain text.
50
+ */
51
+ class ReadlineWizardIO {
52
+ rl;
53
+ ownsInterface;
54
+ constructor(rl) {
55
+ if (rl) {
56
+ this.rl = rl;
57
+ this.ownsInterface = false;
58
+ }
59
+ else {
60
+ this.rl = readline.createInterface({ input: process.stdin, output: process.stdout });
61
+ this.ownsInterface = true;
62
+ }
63
+ }
64
+ close() {
65
+ if (this.ownsInterface)
66
+ this.rl.close();
67
+ }
68
+ header(line) {
69
+ const color = (0, MatrixTheme_1.supportsColor)() ? MatrixTheme_1.MATRIX.head : '';
70
+ const reset = (0, MatrixTheme_1.supportsColor)() ? MatrixTheme_1.ANSI.reset : '';
71
+ process.stdout.write(`\n${color}━━━ ${line} ━━━${reset}\n\n`);
72
+ }
73
+ print(line) {
74
+ const color = (0, MatrixTheme_1.supportsColor)() ? MatrixTheme_1.MATRIX.body : '';
75
+ const reset = (0, MatrixTheme_1.supportsColor)() ? MatrixTheme_1.ANSI.reset : '';
76
+ process.stdout.write(`${color}${line}${reset}\n`);
77
+ }
78
+ hint(line) {
79
+ process.stdout.write(`${(0, MatrixTheme_1.paint)(line, MatrixTheme_1.MATRIX.tail)}\n`);
80
+ }
81
+ warn(line) {
82
+ process.stdout.write(`${(0, MatrixTheme_1.paint)('⚠ ' + line, MatrixTheme_1.MATRIX.warn)}\n`);
83
+ }
84
+ err(line) {
85
+ process.stdout.write(`${(0, MatrixTheme_1.paint)('✗ ' + line, MatrixTheme_1.MATRIX.err)}\n`);
86
+ }
87
+ divider() {
88
+ const w = Math.min(process.stdout.columns || 60, 60);
89
+ process.stdout.write(`${(0, MatrixTheme_1.paint)('─'.repeat(w), MatrixTheme_1.MATRIX.tail)}\n`);
90
+ }
91
+ ask(prompt) {
92
+ return new Promise((resolve) => {
93
+ this.rl.question(prompt, (answer) => resolve(answer));
94
+ });
95
+ }
96
+ async text(prompt, defaultValue) {
97
+ const suffix = defaultValue !== undefined && defaultValue !== ''
98
+ ? (0, MatrixTheme_1.paint)(` [${defaultValue}]`, MatrixTheme_1.MATRIX.tail)
99
+ : '';
100
+ const promptStr = `${(0, MatrixTheme_1.paint)(prompt, MatrixTheme_1.MATRIX.body)}${suffix}${(0, MatrixTheme_1.paint)(': ', MatrixTheme_1.MATRIX.head)}`;
101
+ const raw = (await this.ask(promptStr)).trim();
102
+ if (!raw && defaultValue !== undefined)
103
+ return defaultValue;
104
+ return raw;
105
+ }
106
+ /**
107
+ * Masked input — disables echo, accumulates chars manually, prints * per
108
+ * character. Falls back to plain text() when stdin is not a TTY (CI/piped).
109
+ */
110
+ async secret(prompt) {
111
+ if (!process.stdin.isTTY) {
112
+ // CI / piped — accept the pasted value as-is.
113
+ return this.text(prompt);
114
+ }
115
+ return new Promise((resolve) => {
116
+ const promptStr = `${(0, MatrixTheme_1.paint)(prompt, MatrixTheme_1.MATRIX.body)}${(0, MatrixTheme_1.paint)(': ', MatrixTheme_1.MATRIX.head)}`;
117
+ process.stdout.write(promptStr);
118
+ let value = '';
119
+ const previousRaw = process.stdin.isRaw === true;
120
+ try {
121
+ process.stdin.setRawMode(true);
122
+ }
123
+ catch { /* ignore */ }
124
+ process.stdin.resume();
125
+ process.stdin.setEncoding('utf-8');
126
+ const onData = (chunk) => {
127
+ for (const ch of chunk) {
128
+ const code = ch.charCodeAt(0);
129
+ // Enter (13 or 10)
130
+ if (code === 13 || code === 10) {
131
+ process.stdin.removeListener('data', onData);
132
+ try {
133
+ process.stdin.setRawMode(previousRaw);
134
+ }
135
+ catch { /* ignore */ }
136
+ process.stdin.pause();
137
+ process.stdout.write('\n');
138
+ resolve(value.trim());
139
+ return;
140
+ }
141
+ // Ctrl-C
142
+ if (code === 3) {
143
+ process.stdin.removeListener('data', onData);
144
+ try {
145
+ process.stdin.setRawMode(previousRaw);
146
+ }
147
+ catch { /* ignore */ }
148
+ process.stdin.pause();
149
+ process.stdout.write('\n');
150
+ process.exit(130);
151
+ return;
152
+ }
153
+ // Backspace
154
+ if (code === 127 || code === 8) {
155
+ if (value.length > 0) {
156
+ value = value.slice(0, -1);
157
+ process.stdout.write('\b \b');
158
+ }
159
+ continue;
160
+ }
161
+ // Printable char — append and echo asterisk
162
+ if (code >= 32) {
163
+ value += ch;
164
+ process.stdout.write('*');
165
+ }
166
+ }
167
+ };
168
+ process.stdin.on('data', onData);
169
+ });
170
+ }
171
+ async yesNo(prompt, defaultYes = false) {
172
+ const hint = defaultYes ? '[Y/n]' : '[y/N]';
173
+ const promptStr = `${(0, MatrixTheme_1.paint)(prompt, MatrixTheme_1.MATRIX.body)} ${(0, MatrixTheme_1.paint)(hint, MatrixTheme_1.MATRIX.tail)}${(0, MatrixTheme_1.paint)(': ', MatrixTheme_1.MATRIX.head)}`;
174
+ const raw = (await this.ask(promptStr)).trim().toLowerCase();
175
+ if (!raw)
176
+ return defaultYes;
177
+ if (raw === 'y' || raw === 'yes' || raw === 's' || raw === 'sim')
178
+ return true;
179
+ if (raw === 'n' || raw === 'no' || raw === 'não' || raw === 'nao')
180
+ return false;
181
+ return defaultYes;
182
+ }
183
+ async choice(prompt, options, defaultIndex = 0) {
184
+ this.print(prompt);
185
+ for (let i = 0; i < options.length; i++) {
186
+ const marker = i === defaultIndex ? (0, MatrixTheme_1.paint)('▶', MatrixTheme_1.MATRIX.head) : ' ';
187
+ const num = (0, MatrixTheme_1.paint)(`${i + 1})`, MatrixTheme_1.MATRIX.body);
188
+ this.print(` ${marker} ${num} ${options[i]}`);
189
+ }
190
+ const promptStr = `${(0, MatrixTheme_1.paint)(`Choice [${defaultIndex + 1}]`, MatrixTheme_1.MATRIX.body)}${(0, MatrixTheme_1.paint)(': ', MatrixTheme_1.MATRIX.head)}`;
191
+ const raw = (await this.ask(promptStr)).trim();
192
+ if (!raw)
193
+ return defaultIndex;
194
+ const parsed = Number.parseInt(raw, 10);
195
+ if (Number.isNaN(parsed) || parsed < 1 || parsed > options.length) {
196
+ this.warn(`Invalid choice — must be 1..${options.length}. Using default (${defaultIndex + 1}).`);
197
+ return defaultIndex;
198
+ }
199
+ return parsed - 1;
200
+ }
201
+ async pause(prompt = 'Press Enter to continue') {
202
+ const promptStr = `${(0, MatrixTheme_1.paint)(`▸ ${prompt}…`, MatrixTheme_1.MATRIX.tail)}`;
203
+ await this.ask(promptStr);
204
+ }
205
+ }
206
+ exports.ReadlineWizardIO = ReadlineWizardIO;
207
+ /**
208
+ * Test seam — feeds canned answers from a FIFO queue. Each prompt method
209
+ * shifts one answer off. Empty queue throws so tests fail loudly on
210
+ * forgotten answers.
211
+ */
212
+ class CannedIO {
213
+ queue;
214
+ transcript = [];
215
+ constructor(answers) {
216
+ this.queue = [...answers];
217
+ }
218
+ header(line) { this.transcript.push(`[header] ${line}`); }
219
+ print(line) { this.transcript.push(`[print] ${(0, MatrixTheme_1.stripAnsi)(line)}`); }
220
+ hint(line) { this.transcript.push(`[hint] ${line}`); }
221
+ warn(line) { this.transcript.push(`[warn] ${line}`); }
222
+ err(line) { this.transcript.push(`[err] ${line}`); }
223
+ divider() { this.transcript.push(`[divider]`); }
224
+ close() { }
225
+ next(kind) {
226
+ if (this.queue.length === 0) {
227
+ throw new Error(`CANNED_IO_EXHAUSTED: wizard asked for "${kind}" but the queue is empty`);
228
+ }
229
+ return this.queue.shift();
230
+ }
231
+ async text(prompt, _defaultValue) {
232
+ this.transcript.push(`[text] ${prompt}`);
233
+ const v = this.next('text');
234
+ if (typeof v !== 'string')
235
+ throw new Error(`CANNED_IO_TYPE: expected string for text, got ${typeof v}`);
236
+ return v;
237
+ }
238
+ async secret(prompt) {
239
+ this.transcript.push(`[secret] ${prompt}`);
240
+ const v = this.next('secret');
241
+ if (typeof v !== 'string')
242
+ throw new Error(`CANNED_IO_TYPE: expected string for secret, got ${typeof v}`);
243
+ return v;
244
+ }
245
+ async yesNo(prompt, _defaultYes) {
246
+ this.transcript.push(`[yesNo] ${prompt}`);
247
+ const v = this.next('yesNo');
248
+ if (typeof v !== 'boolean')
249
+ throw new Error(`CANNED_IO_TYPE: expected boolean for yesNo, got ${typeof v}`);
250
+ return v;
251
+ }
252
+ async choice(prompt, _options, _defaultIndex) {
253
+ this.transcript.push(`[choice] ${prompt}`);
254
+ const v = this.next('choice');
255
+ if (typeof v !== 'number')
256
+ throw new Error(`CANNED_IO_TYPE: expected number for choice, got ${typeof v}`);
257
+ return v;
258
+ }
259
+ async pause(_prompt) {
260
+ this.transcript.push(`[pause]`);
261
+ // Pause consumes one boolean from the queue — usually `true` to continue.
262
+ // This makes test queues predictable: every Enter in the wizard = one entry.
263
+ const v = this.next('pause');
264
+ if (typeof v !== 'boolean')
265
+ throw new Error(`CANNED_IO_TYPE: expected boolean for pause, got ${typeof v}`);
266
+ }
267
+ remaining() {
268
+ return this.queue.length;
269
+ }
270
+ }
271
+ exports.CannedIO = CannedIO;
@@ -0,0 +1,17 @@
1
+ "use strict";
2
+ // src/cli/install/types.ts
3
+ // Shared types for the Install Wizard 2.0 (phase-based, sequential, multi-host).
4
+ //
5
+ // Replaces the old single-host, batched-Q&A model in InstallWizard.ts with:
6
+ // - 2 install profiles (openlife-core | openlife-agent) installable separately or sequentially
7
+ // - Multi-host selection (claude-code | gemini-cli | codex — pick 1..N)
8
+ // - Per-provider auth strategy in agent profile (api-key | oauth | skip)
9
+ // - ~30 providers in tier-organized catalog
10
+ Object.defineProperty(exports, "__esModule", { value: true });
11
+ exports.OAUTH_ENABLED_PROVIDERS = void 0;
12
+ /** Providers where OAuth is permitted as an auth strategy. */
13
+ exports.OAUTH_ENABLED_PROVIDERS = Object.freeze([
14
+ 'openai-cli', // Codex
15
+ 'gemini-cli', // Gemini CLI
16
+ 'xai', // Grok device-auth
17
+ ]);