aios-core 4.1.0 → 4.2.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/.aios-core/.session/current-session.json +14 -0
- package/.aios-core/core/registry/registry-schema.json +166 -166
- package/.aios-core/core/registry/service-registry.json +6585 -6585
- package/.aios-core/data/entity-registry.yaml +208 -8
- package/.aios-core/data/registry-update-log.jsonl +165 -0
- package/.aios-core/development/scripts/approval-workflow.js +642 -642
- package/.aios-core/development/scripts/backup-manager.js +606 -606
- package/.aios-core/development/scripts/branch-manager.js +389 -389
- package/.aios-core/development/scripts/code-quality-improver.js +1311 -1311
- package/.aios-core/development/scripts/commit-message-generator.js +849 -849
- package/.aios-core/development/scripts/conflict-resolver.js +674 -674
- package/.aios-core/development/scripts/dependency-analyzer.js +637 -637
- package/.aios-core/development/scripts/diff-generator.js +351 -351
- package/.aios-core/development/scripts/elicitation-engine.js +384 -384
- package/.aios-core/development/scripts/elicitation-session-manager.js +299 -299
- package/.aios-core/development/scripts/git-wrapper.js +461 -461
- package/.aios-core/development/scripts/manifest-preview.js +244 -244
- package/.aios-core/development/scripts/metrics-tracker.js +775 -775
- package/.aios-core/development/scripts/modification-validator.js +554 -554
- package/.aios-core/development/scripts/pattern-learner.js +1224 -1224
- package/.aios-core/development/scripts/performance-analyzer.js +757 -757
- package/.aios-core/development/scripts/refactoring-suggester.js +1138 -1138
- package/.aios-core/development/scripts/rollback-handler.js +530 -530
- package/.aios-core/development/scripts/security-checker.js +358 -358
- package/.aios-core/development/scripts/template-engine.js +239 -239
- package/.aios-core/development/scripts/template-validator.js +278 -278
- package/.aios-core/development/scripts/test-generator.js +843 -843
- package/.aios-core/development/scripts/transaction-manager.js +589 -589
- package/.aios-core/development/scripts/usage-tracker.js +673 -673
- package/.aios-core/development/scripts/validate-filenames.js +226 -226
- package/.aios-core/development/scripts/version-tracker.js +526 -526
- package/.aios-core/development/scripts/yaml-validator.js +396 -396
- package/.aios-core/development/tasks/validate-next-story.md +99 -2
- package/.aios-core/development/templates/service-template/README.md.hbs +158 -158
- package/.aios-core/development/templates/service-template/__tests__/index.test.ts.hbs +237 -237
- package/.aios-core/development/templates/service-template/client.ts.hbs +403 -403
- package/.aios-core/development/templates/service-template/errors.ts.hbs +182 -182
- package/.aios-core/development/templates/service-template/index.ts.hbs +120 -120
- package/.aios-core/development/templates/service-template/package.json.hbs +87 -87
- package/.aios-core/development/templates/service-template/types.ts.hbs +145 -145
- package/.aios-core/development/templates/squad-template/LICENSE +21 -21
- package/.aios-core/docs/SHARD-TRANSLATION-GUIDE.md +335 -0
- package/.aios-core/docs/component-creation-guide.md +458 -0
- package/.aios-core/docs/session-update-pattern.md +307 -0
- package/.aios-core/docs/standards/AIOS-FRAMEWORK-MASTER.md +1963 -0
- package/.aios-core/docs/standards/AIOS-LIVRO-DE-OURO-V2.1-SUMMARY.md +1190 -0
- package/.aios-core/docs/standards/AIOS-LIVRO-DE-OURO-V2.1.md +439 -0
- package/.aios-core/docs/standards/AIOS-LIVRO-DE-OURO.md +5398 -0
- package/.aios-core/docs/standards/V3-ARCHITECTURAL-DECISIONS.md +523 -0
- package/.aios-core/docs/template-syntax.md +267 -0
- package/.aios-core/docs/troubleshooting-guide.md +625 -0
- package/.aios-core/infrastructure/templates/aios-sync.yaml.template +193 -193
- package/.aios-core/infrastructure/templates/coderabbit.yaml.template +279 -279
- package/.aios-core/infrastructure/templates/github-workflows/ci.yml.template +169 -169
- package/.aios-core/infrastructure/templates/github-workflows/pr-automation.yml.template +330 -330
- package/.aios-core/infrastructure/templates/github-workflows/release.yml.template +196 -196
- package/.aios-core/infrastructure/templates/gitignore/gitignore-aios-base.tmpl +63 -63
- package/.aios-core/infrastructure/templates/gitignore/gitignore-brownfield-merge.tmpl +18 -18
- package/.aios-core/infrastructure/templates/gitignore/gitignore-node.tmpl +85 -85
- package/.aios-core/infrastructure/templates/gitignore/gitignore-python.tmpl +145 -145
- package/.aios-core/infrastructure/tests/utilities-audit-results.json +501 -0
- package/.aios-core/install-manifest.yaml +101 -101
- package/.aios-core/local-config.yaml.template +70 -70
- package/.aios-core/manifests/agents.csv +29 -0
- package/.aios-core/manifests/schema/manifest-schema.json +190 -190
- package/.aios-core/manifests/tasks.csv +198 -0
- package/.aios-core/manifests/workers.csv +204 -0
- package/.aios-core/monitor/hooks/lib/__init__.py +1 -1
- package/.aios-core/monitor/hooks/lib/enrich.py +58 -58
- package/.aios-core/monitor/hooks/lib/send_event.py +47 -47
- package/.aios-core/monitor/hooks/notification.py +29 -29
- package/.aios-core/monitor/hooks/post_tool_use.py +45 -45
- package/.aios-core/monitor/hooks/pre_compact.py +29 -29
- package/.aios-core/monitor/hooks/pre_tool_use.py +40 -40
- package/.aios-core/monitor/hooks/stop.py +29 -29
- package/.aios-core/monitor/hooks/subagent_stop.py +29 -29
- package/.aios-core/monitor/hooks/user_prompt_submit.py +38 -38
- package/.aios-core/product/templates/adr.hbs +125 -125
- package/.aios-core/product/templates/component-react-tmpl.tsx +98 -98
- package/.aios-core/product/templates/dbdr.hbs +241 -241
- package/.aios-core/product/templates/engine/schemas/adr.schema.json +102 -102
- package/.aios-core/product/templates/engine/schemas/dbdr.schema.json +205 -205
- package/.aios-core/product/templates/engine/schemas/epic.schema.json +175 -175
- package/.aios-core/product/templates/engine/schemas/pmdr.schema.json +175 -175
- package/.aios-core/product/templates/engine/schemas/prd-v2.schema.json +300 -300
- package/.aios-core/product/templates/engine/schemas/prd.schema.json +152 -152
- package/.aios-core/product/templates/engine/schemas/story.schema.json +222 -222
- package/.aios-core/product/templates/engine/schemas/task.schema.json +154 -154
- package/.aios-core/product/templates/epic.hbs +212 -212
- package/.aios-core/product/templates/eslintrc-security.json +32 -32
- package/.aios-core/product/templates/github-actions-cd.yml +212 -212
- package/.aios-core/product/templates/github-actions-ci.yml +172 -172
- package/.aios-core/product/templates/pmdr.hbs +186 -186
- package/.aios-core/product/templates/prd-v2.0.hbs +216 -216
- package/.aios-core/product/templates/prd.hbs +201 -201
- package/.aios-core/product/templates/shock-report-tmpl.html +502 -502
- package/.aios-core/product/templates/story.hbs +263 -263
- package/.aios-core/product/templates/task.hbs +170 -170
- package/.aios-core/product/templates/tmpl-comment-on-examples.sql +158 -158
- package/.aios-core/product/templates/tmpl-migration-script.sql +91 -91
- package/.aios-core/product/templates/tmpl-rls-granular-policies.sql +104 -104
- package/.aios-core/product/templates/tmpl-rls-kiss-policy.sql +10 -10
- package/.aios-core/product/templates/tmpl-rls-roles.sql +135 -135
- package/.aios-core/product/templates/tmpl-rls-simple.sql +77 -77
- package/.aios-core/product/templates/tmpl-rls-tenant.sql +152 -152
- package/.aios-core/product/templates/tmpl-rollback-script.sql +77 -77
- package/.aios-core/product/templates/tmpl-seed-data.sql +140 -140
- package/.aios-core/product/templates/tmpl-smoke-test.sql +16 -16
- package/.aios-core/product/templates/tmpl-staging-copy-merge.sql +139 -139
- package/.aios-core/product/templates/tmpl-stored-proc.sql +140 -140
- package/.aios-core/product/templates/tmpl-trigger.sql +152 -152
- package/.aios-core/product/templates/tmpl-view-materialized.sql +133 -133
- package/.aios-core/product/templates/tmpl-view.sql +177 -177
- package/.aios-core/product/templates/token-exports-css-tmpl.css +240 -240
- package/.aios-core/quality/schemas/quality-metrics.schema.json +233 -233
- package/.aios-core/scripts/migrate-framework-docs.sh +300 -300
- package/.aios-core/scripts/pm.sh +0 -0
- package/.claude/hooks/enforce-architecture-first.py +196 -196
- package/.claude/hooks/mind-clone-governance.py +192 -192
- package/.claude/hooks/read-protection.py +151 -151
- package/.claude/hooks/slug-validation.py +176 -176
- package/.claude/hooks/sql-governance.py +182 -182
- package/.claude/hooks/write-path-validation.py +194 -194
- package/.claude/rules/agent-authority.md +105 -0
- package/.claude/rules/coderabbit-integration.md +93 -0
- package/.claude/rules/ids-principles.md +112 -0
- package/.claude/rules/story-lifecycle.md +139 -0
- package/.claude/rules/workflow-execution.md +150 -0
- package/LICENSE +48 -48
- package/bin/aios-minimal.js +0 -0
- package/bin/aios.js +0 -0
- package/package.json +1 -1
- package/packages/aios-install/bin/aios-install.js +0 -0
- package/packages/aios-install/bin/edmcp.js +0 -0
- package/packages/aios-pro-cli/bin/aios-pro.js +0 -0
- package/packages/installer/src/wizard/pro-setup.js +433 -49
- package/scripts/check-markdown-links.py +352 -352
- package/scripts/code-intel-health-check.js +343 -0
- package/scripts/dashboard-parallel-dev.sh +0 -0
- package/scripts/dashboard-parallel-phase3.sh +0 -0
- package/scripts/dashboard-parallel-phase4.sh +0 -0
- package/scripts/glue/README.md +355 -0
- package/scripts/glue/compose-agent-prompt.cjs +362 -0
- package/scripts/install-monitor-hooks.sh +0 -0
- package/.aios-core/lib/build.json +0 -1
|
@@ -2,10 +2,15 @@
|
|
|
2
2
|
* Pro Installation Wizard with License Gate
|
|
3
3
|
*
|
|
4
4
|
* 3-step wizard: (1) License Gate, (2) Install/Scaffold, (3) Verify
|
|
5
|
-
* Supports interactive mode, CI mode (AIOS_PRO_KEY env
|
|
5
|
+
* Supports interactive mode, CI mode (AIOS_PRO_KEY/AIOS_PRO_EMAIL env vars), and lazy import.
|
|
6
|
+
*
|
|
7
|
+
* License Gate supports two activation methods:
|
|
8
|
+
* - Email + Password authentication (recommended, PRO-11)
|
|
9
|
+
* - License key (legacy, PRO-6)
|
|
6
10
|
*
|
|
7
11
|
* @module wizard/pro-setup
|
|
8
12
|
* @story INS-3.2 — Implement Pro Installation Wizard with License Gate
|
|
13
|
+
* @story PRO-11 — Email Authentication & Buyer-Based Pro Activation
|
|
9
14
|
*/
|
|
10
15
|
|
|
11
16
|
'use strict';
|
|
@@ -35,6 +40,26 @@ const LICENSE_KEY_PATTERN = /^PRO-[A-Z0-9]{4}-[A-Z0-9]{4}-[A-Z0-9]{4}-[A-Z0-9]{4
|
|
|
35
40
|
*/
|
|
36
41
|
const MAX_RETRIES = 3;
|
|
37
42
|
|
|
43
|
+
/**
|
|
44
|
+
* Email verification polling interval in milliseconds.
|
|
45
|
+
*/
|
|
46
|
+
const VERIFY_POLL_INTERVAL_MS = 5000;
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* Email verification polling timeout in milliseconds (10 minutes).
|
|
50
|
+
*/
|
|
51
|
+
const VERIFY_POLL_TIMEOUT_MS = 10 * 60 * 1000;
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* Minimum password length.
|
|
55
|
+
*/
|
|
56
|
+
const MIN_PASSWORD_LENGTH = 8;
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* Email format regex.
|
|
60
|
+
*/
|
|
61
|
+
const EMAIL_PATTERN = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
|
|
62
|
+
|
|
38
63
|
/**
|
|
39
64
|
* Detect CI environment.
|
|
40
65
|
*
|
|
@@ -145,78 +170,425 @@ function loadProScaffolder() {
|
|
|
145
170
|
}
|
|
146
171
|
|
|
147
172
|
/**
|
|
148
|
-
* Step 1: License Gate — validate license
|
|
173
|
+
* Step 1: License Gate — authenticate and validate license.
|
|
174
|
+
*
|
|
175
|
+
* Supports two activation methods:
|
|
176
|
+
* 1. Email + Password authentication (recommended, PRO-11)
|
|
177
|
+
* 2. License key (legacy, PRO-6)
|
|
149
178
|
*
|
|
150
|
-
* In CI mode, reads from AIOS_PRO_KEY env
|
|
151
|
-
* In interactive mode, prompts
|
|
179
|
+
* In CI mode, reads from AIOS_PRO_EMAIL + AIOS_PRO_PASSWORD or AIOS_PRO_KEY env vars.
|
|
180
|
+
* In interactive mode, prompts user to choose method.
|
|
152
181
|
*
|
|
153
182
|
* @param {Object} [options={}] - Options
|
|
154
183
|
* @param {string} [options.key] - Pre-provided key (from CLI args or env)
|
|
184
|
+
* @param {string} [options.email] - Pre-provided email (from CLI args or env)
|
|
185
|
+
* @param {string} [options.password] - Pre-provided password (from CLI args or env)
|
|
155
186
|
* @returns {Promise<Object>} Result with { success, key, activationResult }
|
|
156
187
|
*/
|
|
157
188
|
async function stepLicenseGate(options = {}) {
|
|
158
|
-
showStep(1, 3, 'License
|
|
189
|
+
showStep(1, 3, 'License Activation');
|
|
159
190
|
|
|
160
191
|
const isCI = isCIEnvironment();
|
|
161
|
-
let key = options.key || null;
|
|
162
192
|
|
|
163
|
-
// CI mode:
|
|
164
|
-
if (
|
|
165
|
-
|
|
193
|
+
// CI mode: check env vars
|
|
194
|
+
if (isCI) {
|
|
195
|
+
return stepLicenseGateCI(options);
|
|
196
|
+
}
|
|
166
197
|
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
198
|
+
// Pre-provided key (from CLI args)
|
|
199
|
+
if (options.key) {
|
|
200
|
+
return stepLicenseGateWithKey(options.key);
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
// Pre-provided email credentials (from CLI args)
|
|
204
|
+
if (options.email && options.password) {
|
|
205
|
+
return authenticateWithEmail(options.email, options.password);
|
|
173
206
|
}
|
|
174
207
|
|
|
175
|
-
// Interactive mode: prompt for
|
|
176
|
-
|
|
177
|
-
const inquirer = require('inquirer');
|
|
208
|
+
// Interactive mode: prompt for method
|
|
209
|
+
const inquirer = require('inquirer');
|
|
178
210
|
|
|
179
|
-
|
|
180
|
-
|
|
211
|
+
const { method } = await inquirer.prompt([
|
|
212
|
+
{
|
|
213
|
+
type: 'list',
|
|
214
|
+
name: 'method',
|
|
215
|
+
message: colors.primary('How would you like to activate Pro?'),
|
|
216
|
+
choices: [
|
|
181
217
|
{
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
message: colors.primary('Enter your Pro license key:'),
|
|
185
|
-
mask: '*',
|
|
186
|
-
validate: (input) => {
|
|
187
|
-
if (!input || !input.trim()) {
|
|
188
|
-
return 'License key is required';
|
|
189
|
-
}
|
|
190
|
-
if (!validateKeyFormat(input)) {
|
|
191
|
-
return 'Invalid format. Expected: PRO-XXXX-XXXX-XXXX-XXXX';
|
|
192
|
-
}
|
|
193
|
-
return true;
|
|
194
|
-
},
|
|
218
|
+
name: 'Login with email and password (Recommended)',
|
|
219
|
+
value: 'email',
|
|
195
220
|
},
|
|
196
|
-
|
|
221
|
+
{
|
|
222
|
+
name: 'Enter license key',
|
|
223
|
+
value: 'key',
|
|
224
|
+
},
|
|
225
|
+
],
|
|
226
|
+
},
|
|
227
|
+
]);
|
|
228
|
+
|
|
229
|
+
if (method === 'email') {
|
|
230
|
+
return stepLicenseGateWithEmail();
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
return stepLicenseGateWithKeyInteractive();
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
/**
|
|
237
|
+
* CI mode license gate — reads from env vars.
|
|
238
|
+
*
|
|
239
|
+
* Priority: AIOS_PRO_EMAIL + AIOS_PRO_PASSWORD > AIOS_PRO_KEY
|
|
240
|
+
*
|
|
241
|
+
* @param {Object} options - Options with possible pre-provided credentials
|
|
242
|
+
* @returns {Promise<Object>} Result with { success, key, activationResult }
|
|
243
|
+
*/
|
|
244
|
+
async function stepLicenseGateCI(options) {
|
|
245
|
+
const email = options.email || process.env.AIOS_PRO_EMAIL;
|
|
246
|
+
const password = options.password || process.env.AIOS_PRO_PASSWORD;
|
|
247
|
+
const key = options.key || process.env.AIOS_PRO_KEY;
|
|
248
|
+
|
|
249
|
+
// Prefer email auth over key
|
|
250
|
+
if (email && password) {
|
|
251
|
+
return authenticateWithEmail(email, password);
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
if (key) {
|
|
255
|
+
return stepLicenseGateWithKey(key);
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
return {
|
|
259
|
+
success: false,
|
|
260
|
+
error: 'CI mode: Set AIOS_PRO_EMAIL + AIOS_PRO_PASSWORD or AIOS_PRO_KEY environment variables.',
|
|
261
|
+
};
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
/**
|
|
265
|
+
* Interactive email/password license gate flow.
|
|
266
|
+
*
|
|
267
|
+
* Prompts for email, then checks if account exists to determine signup vs login.
|
|
268
|
+
*
|
|
269
|
+
* @returns {Promise<Object>} Result with { success, key, activationResult }
|
|
270
|
+
*/
|
|
271
|
+
async function stepLicenseGateWithEmail() {
|
|
272
|
+
const inquirer = require('inquirer');
|
|
273
|
+
|
|
274
|
+
const { email } = await inquirer.prompt([
|
|
275
|
+
{
|
|
276
|
+
type: 'input',
|
|
277
|
+
name: 'email',
|
|
278
|
+
message: colors.primary('Email:'),
|
|
279
|
+
validate: (input) => {
|
|
280
|
+
if (!input || !input.trim()) {
|
|
281
|
+
return 'Email is required';
|
|
282
|
+
}
|
|
283
|
+
if (!EMAIL_PATTERN.test(input.trim())) {
|
|
284
|
+
return 'Please enter a valid email address';
|
|
285
|
+
}
|
|
286
|
+
return true;
|
|
287
|
+
},
|
|
288
|
+
},
|
|
289
|
+
]);
|
|
290
|
+
|
|
291
|
+
const { password } = await inquirer.prompt([
|
|
292
|
+
{
|
|
293
|
+
type: 'password',
|
|
294
|
+
name: 'password',
|
|
295
|
+
message: colors.primary('Password:'),
|
|
296
|
+
mask: '*',
|
|
297
|
+
validate: (input) => {
|
|
298
|
+
if (!input || input.length < MIN_PASSWORD_LENGTH) {
|
|
299
|
+
return `Password must be at least ${MIN_PASSWORD_LENGTH} characters`;
|
|
300
|
+
}
|
|
301
|
+
return true;
|
|
302
|
+
},
|
|
303
|
+
},
|
|
304
|
+
]);
|
|
305
|
+
|
|
306
|
+
return authenticateWithEmail(email.trim(), password);
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
/**
|
|
310
|
+
* Authenticate with email and password.
|
|
311
|
+
*
|
|
312
|
+
* Tries login first. If user doesn't exist, offers to create account.
|
|
313
|
+
* Handles email verification polling for new signups.
|
|
314
|
+
*
|
|
315
|
+
* @param {string} email - User email
|
|
316
|
+
* @param {string} password - User password
|
|
317
|
+
* @returns {Promise<Object>} Result with { success, key, activationResult }
|
|
318
|
+
*/
|
|
319
|
+
async function authenticateWithEmail(email, password) {
|
|
320
|
+
const loader = module.exports._testing ? module.exports._testing.loadLicenseApi : loadLicenseApi;
|
|
321
|
+
const licenseModule = loader();
|
|
322
|
+
|
|
323
|
+
if (!licenseModule) {
|
|
324
|
+
return {
|
|
325
|
+
success: false,
|
|
326
|
+
error: 'Pro license module not available. Ensure @aios-fullstack/pro is installed.',
|
|
327
|
+
};
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
const { LicenseApiClient } = licenseModule;
|
|
331
|
+
const client = new LicenseApiClient();
|
|
332
|
+
|
|
333
|
+
// Check connectivity
|
|
334
|
+
const online = await client.isOnline();
|
|
335
|
+
if (!online) {
|
|
336
|
+
return {
|
|
337
|
+
success: false,
|
|
338
|
+
error: 'License server is unreachable. Check your internet connection and try again.',
|
|
339
|
+
};
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
// Try login first
|
|
343
|
+
const spinner = createSpinner('Authenticating...');
|
|
344
|
+
spinner.start();
|
|
345
|
+
|
|
346
|
+
let sessionToken;
|
|
347
|
+
let emailVerified;
|
|
348
|
+
|
|
349
|
+
try {
|
|
350
|
+
const loginResult = await client.login(email, password);
|
|
351
|
+
sessionToken = loginResult.sessionToken;
|
|
352
|
+
emailVerified = loginResult.emailVerified;
|
|
353
|
+
spinner.succeed('Authenticated successfully.');
|
|
354
|
+
} catch (loginError) {
|
|
355
|
+
// If invalid credentials, try signup for new users
|
|
356
|
+
if (loginError.code === 'INVALID_CREDENTIALS') {
|
|
357
|
+
spinner.info('No account found. Creating a new account...');
|
|
358
|
+
|
|
359
|
+
try {
|
|
360
|
+
await client.signup(email, password);
|
|
361
|
+
showSuccess('Account created. Verification email sent!');
|
|
362
|
+
emailVerified = false;
|
|
363
|
+
|
|
364
|
+
// Login after signup to get session token
|
|
365
|
+
const loginAfterSignup = await client.login(email, password);
|
|
366
|
+
sessionToken = loginAfterSignup.sessionToken;
|
|
367
|
+
} catch (signupError) {
|
|
368
|
+
if (signupError.code === 'EMAIL_ALREADY_REGISTERED') {
|
|
369
|
+
showError('An account exists with this email but the password is incorrect.');
|
|
370
|
+
showInfo('Forgot your password? Visit https://pro.synkra.ai/reset-password or contact support@synkra.ai');
|
|
371
|
+
return { success: false, error: signupError.message };
|
|
372
|
+
}
|
|
373
|
+
return { success: false, error: signupError.message };
|
|
374
|
+
}
|
|
375
|
+
} else if (loginError.code === 'AUTH_RATE_LIMITED') {
|
|
376
|
+
spinner.fail(loginError.message);
|
|
377
|
+
return { success: false, error: loginError.message };
|
|
378
|
+
} else {
|
|
379
|
+
spinner.fail(`Authentication failed: ${loginError.message}`);
|
|
380
|
+
return { success: false, error: loginError.message };
|
|
381
|
+
}
|
|
382
|
+
}
|
|
383
|
+
|
|
384
|
+
// Wait for email verification if needed
|
|
385
|
+
if (!emailVerified) {
|
|
386
|
+
const verifyResult = await waitForEmailVerification(client, sessionToken);
|
|
387
|
+
if (!verifyResult.success) {
|
|
388
|
+
return verifyResult;
|
|
389
|
+
}
|
|
390
|
+
}
|
|
391
|
+
|
|
392
|
+
// Activate Pro
|
|
393
|
+
return activateProByAuth(client, sessionToken);
|
|
394
|
+
}
|
|
197
395
|
|
|
198
|
-
|
|
396
|
+
/**
|
|
397
|
+
* Wait for email verification with polling.
|
|
398
|
+
*
|
|
399
|
+
* Polls the server every 5 seconds for up to 10 minutes.
|
|
400
|
+
* User can press R to resend verification email.
|
|
401
|
+
*
|
|
402
|
+
* @param {object} client - LicenseApiClient instance
|
|
403
|
+
* @param {string} sessionToken - Session token
|
|
404
|
+
* @returns {Promise<Object>} Result with { success }
|
|
405
|
+
*/
|
|
406
|
+
async function waitForEmailVerification(client, sessionToken) {
|
|
407
|
+
console.log('');
|
|
408
|
+
showInfo('Waiting for email verification...');
|
|
409
|
+
showInfo('Open your email and click the verification link.');
|
|
410
|
+
console.log(colors.dim(' (Checking every 5 seconds... timeout in 10 minutes)'));
|
|
199
411
|
|
|
200
|
-
|
|
201
|
-
|
|
412
|
+
if (!isCIEnvironment()) {
|
|
413
|
+
console.log(colors.dim(' [Press R to resend verification email]'));
|
|
414
|
+
}
|
|
415
|
+
|
|
416
|
+
const startTime = Date.now();
|
|
417
|
+
let resendHint = false;
|
|
418
|
+
|
|
419
|
+
// Set up keyboard listener for resend (non-CI only)
|
|
420
|
+
let keyListener;
|
|
421
|
+
if (!isCIEnvironment() && process.stdin.setRawMode) {
|
|
422
|
+
process.stdin.setRawMode(true);
|
|
423
|
+
process.stdin.resume();
|
|
424
|
+
keyListener = (key) => {
|
|
425
|
+
if (key.toString().toLowerCase() === 'r') {
|
|
426
|
+
resendHint = true;
|
|
427
|
+
}
|
|
428
|
+
// Ctrl+C
|
|
429
|
+
if (key.toString() === '\u0003') {
|
|
430
|
+
cleanupKeyListener();
|
|
431
|
+
process.exit(0);
|
|
432
|
+
}
|
|
433
|
+
};
|
|
434
|
+
process.stdin.on('data', keyListener);
|
|
435
|
+
}
|
|
436
|
+
|
|
437
|
+
function cleanupKeyListener() {
|
|
438
|
+
if (keyListener) {
|
|
439
|
+
process.stdin.removeListener('data', keyListener);
|
|
440
|
+
if (process.stdin.setRawMode) {
|
|
441
|
+
process.stdin.setRawMode(false);
|
|
442
|
+
}
|
|
443
|
+
process.stdin.pause();
|
|
444
|
+
}
|
|
445
|
+
}
|
|
202
446
|
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
447
|
+
try {
|
|
448
|
+
while (Date.now() - startTime < VERIFY_POLL_TIMEOUT_MS) {
|
|
449
|
+
// Handle resend request
|
|
450
|
+
if (resendHint) {
|
|
451
|
+
resendHint = false;
|
|
452
|
+
try {
|
|
453
|
+
await client.resendVerification(sessionToken);
|
|
454
|
+
showInfo('Verification email resent.');
|
|
455
|
+
} catch (error) {
|
|
456
|
+
showWarning(`Could not resend: ${error.message}`);
|
|
457
|
+
}
|
|
206
458
|
}
|
|
207
459
|
|
|
208
|
-
//
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
460
|
+
// Poll verification status
|
|
461
|
+
try {
|
|
462
|
+
const status = await client.checkEmailVerified(sessionToken);
|
|
463
|
+
if (status.verified) {
|
|
464
|
+
showSuccess('Email verified!');
|
|
465
|
+
return { success: true };
|
|
466
|
+
}
|
|
467
|
+
} catch {
|
|
468
|
+
// Polling failure is non-fatal, continue
|
|
215
469
|
}
|
|
470
|
+
|
|
471
|
+
// Wait before next poll
|
|
472
|
+
await new Promise((resolve) => setTimeout(resolve, VERIFY_POLL_INTERVAL_MS));
|
|
473
|
+
}
|
|
474
|
+
|
|
475
|
+
// Timeout
|
|
476
|
+
showError('Email verification timed out after 10 minutes.');
|
|
477
|
+
showInfo('Run the installer again to retry verification.');
|
|
478
|
+
return { success: false, error: 'Email verification timed out.' };
|
|
479
|
+
} finally {
|
|
480
|
+
cleanupKeyListener();
|
|
481
|
+
}
|
|
482
|
+
}
|
|
483
|
+
|
|
484
|
+
/**
|
|
485
|
+
* Activate Pro using an authenticated session.
|
|
486
|
+
*
|
|
487
|
+
* @param {object} client - LicenseApiClient instance
|
|
488
|
+
* @param {string} sessionToken - Authenticated session token
|
|
489
|
+
* @returns {Promise<Object>} Result with { success, key, activationResult }
|
|
490
|
+
*/
|
|
491
|
+
async function activateProByAuth(client, sessionToken) {
|
|
492
|
+
const spinner = createSpinner('Validating Pro subscription...');
|
|
493
|
+
spinner.start();
|
|
494
|
+
|
|
495
|
+
try {
|
|
496
|
+
// Generate machine fingerprint
|
|
497
|
+
const os = require('os');
|
|
498
|
+
const crypto = require('crypto');
|
|
499
|
+
const machineId = crypto
|
|
500
|
+
.createHash('sha256')
|
|
501
|
+
.update(`${os.hostname()}-${os.platform()}-${os.arch()}`)
|
|
502
|
+
.digest('hex')
|
|
503
|
+
.substring(0, 32);
|
|
504
|
+
|
|
505
|
+
// Read aios-core version
|
|
506
|
+
let aiosCoreVersion = 'unknown';
|
|
507
|
+
try {
|
|
508
|
+
const path = require('path');
|
|
509
|
+
const fs = require('fs');
|
|
510
|
+
const pkgPath = path.join(__dirname, '..', '..', '..', '..', 'package.json');
|
|
511
|
+
const pkg = JSON.parse(fs.readFileSync(pkgPath, 'utf8'));
|
|
512
|
+
aiosCoreVersion = pkg.version || 'unknown';
|
|
513
|
+
} catch {
|
|
514
|
+
// Keep 'unknown'
|
|
515
|
+
}
|
|
516
|
+
|
|
517
|
+
const activationResult = await client.activateByAuth(sessionToken, machineId, aiosCoreVersion);
|
|
518
|
+
|
|
519
|
+
spinner.succeed(`Pro subscription confirmed! License: ${maskLicenseKey(activationResult.key)}`);
|
|
520
|
+
return { success: true, key: activationResult.key, activationResult };
|
|
521
|
+
} catch (error) {
|
|
522
|
+
if (error.code === 'NOT_A_BUYER') {
|
|
523
|
+
spinner.fail('No active Pro subscription found for this email.');
|
|
524
|
+
showInfo('Purchase Pro at https://pro.synkra.ai');
|
|
525
|
+
return { success: false, error: error.message };
|
|
526
|
+
}
|
|
527
|
+
if (error.code === 'SEAT_LIMIT_EXCEEDED') {
|
|
528
|
+
spinner.fail(error.message);
|
|
529
|
+
showInfo('Deactivate another device or upgrade your license.');
|
|
530
|
+
return { success: false, error: error.message };
|
|
531
|
+
}
|
|
532
|
+
|
|
533
|
+
spinner.fail(`Activation failed: ${error.message}`);
|
|
534
|
+
return { success: false, error: error.message };
|
|
535
|
+
}
|
|
536
|
+
}
|
|
537
|
+
|
|
538
|
+
/**
|
|
539
|
+
* Interactive license key gate (legacy flow).
|
|
540
|
+
*
|
|
541
|
+
* @returns {Promise<Object>} Result with { success, key, activationResult }
|
|
542
|
+
*/
|
|
543
|
+
async function stepLicenseGateWithKeyInteractive() {
|
|
544
|
+
const inquirer = require('inquirer');
|
|
545
|
+
|
|
546
|
+
for (let attempt = 1; attempt <= MAX_RETRIES; attempt++) {
|
|
547
|
+
const { licenseKey } = await inquirer.prompt([
|
|
548
|
+
{
|
|
549
|
+
type: 'password',
|
|
550
|
+
name: 'licenseKey',
|
|
551
|
+
message: colors.primary('Enter your Pro license key:'),
|
|
552
|
+
mask: '*',
|
|
553
|
+
validate: (input) => {
|
|
554
|
+
if (!input || !input.trim()) {
|
|
555
|
+
return 'License key is required';
|
|
556
|
+
}
|
|
557
|
+
if (!validateKeyFormat(input)) {
|
|
558
|
+
return 'Invalid format. Expected: PRO-XXXX-XXXX-XXXX-XXXX';
|
|
559
|
+
}
|
|
560
|
+
return true;
|
|
561
|
+
},
|
|
562
|
+
},
|
|
563
|
+
]);
|
|
564
|
+
|
|
565
|
+
const key = licenseKey.trim().toUpperCase();
|
|
566
|
+
const result = await validateKeyWithApi(key);
|
|
567
|
+
|
|
568
|
+
if (result.success) {
|
|
569
|
+
showSuccess(`License validated: ${maskLicenseKey(key)}`);
|
|
570
|
+
return { success: true, key, activationResult: result.data };
|
|
571
|
+
}
|
|
572
|
+
|
|
573
|
+
const remaining = MAX_RETRIES - attempt;
|
|
574
|
+
if (remaining > 0) {
|
|
575
|
+
showError(`${result.error} (${remaining} attempt${remaining > 1 ? 's' : ''} remaining)`);
|
|
576
|
+
} else {
|
|
577
|
+
showError(`${result.error} — no attempts remaining.`);
|
|
578
|
+
return { success: false, error: result.error };
|
|
216
579
|
}
|
|
217
580
|
}
|
|
218
581
|
|
|
219
|
-
|
|
582
|
+
return { success: false, error: 'Maximum attempts reached.' };
|
|
583
|
+
}
|
|
584
|
+
|
|
585
|
+
/**
|
|
586
|
+
* Validate with pre-provided license key (CI or CLI arg).
|
|
587
|
+
*
|
|
588
|
+
* @param {string} key - License key
|
|
589
|
+
* @returns {Promise<Object>} Result with { success, key, activationResult }
|
|
590
|
+
*/
|
|
591
|
+
async function stepLicenseGateWithKey(key) {
|
|
220
592
|
if (!validateKeyFormat(key)) {
|
|
221
593
|
return {
|
|
222
594
|
success: false,
|
|
@@ -224,7 +596,6 @@ async function stepLicenseGate(options = {}) {
|
|
|
224
596
|
};
|
|
225
597
|
}
|
|
226
598
|
|
|
227
|
-
// Validate with API
|
|
228
599
|
const spinner = createSpinner(`Validating license ${maskLicenseKey(key)}...`);
|
|
229
600
|
spinner.start();
|
|
230
601
|
|
|
@@ -489,6 +860,8 @@ async function runProWizard(options = {}) {
|
|
|
489
860
|
// Step 1: License Gate
|
|
490
861
|
const licenseResult = await stepLicenseGate({
|
|
491
862
|
key: options.key || process.env.AIOS_PRO_KEY,
|
|
863
|
+
email: options.email || process.env.AIOS_PRO_EMAIL,
|
|
864
|
+
password: options.password || process.env.AIOS_PRO_PASSWORD,
|
|
492
865
|
});
|
|
493
866
|
|
|
494
867
|
if (!licenseResult.success) {
|
|
@@ -538,10 +911,21 @@ module.exports = {
|
|
|
538
911
|
// Internal helpers exported for testing
|
|
539
912
|
_testing: {
|
|
540
913
|
validateKeyWithApi,
|
|
914
|
+
authenticateWithEmail,
|
|
915
|
+
waitForEmailVerification,
|
|
916
|
+
activateProByAuth,
|
|
917
|
+
stepLicenseGateCI,
|
|
918
|
+
stepLicenseGateWithKey,
|
|
919
|
+
stepLicenseGateWithKeyInteractive,
|
|
920
|
+
stepLicenseGateWithEmail,
|
|
541
921
|
loadLicenseApi,
|
|
542
922
|
loadFeatureGate,
|
|
543
923
|
loadProScaffolder,
|
|
544
924
|
MAX_RETRIES,
|
|
545
925
|
LICENSE_KEY_PATTERN,
|
|
926
|
+
EMAIL_PATTERN,
|
|
927
|
+
MIN_PASSWORD_LENGTH,
|
|
928
|
+
VERIFY_POLL_INTERVAL_MS,
|
|
929
|
+
VERIFY_POLL_TIMEOUT_MS,
|
|
546
930
|
},
|
|
547
931
|
};
|