@ornexus/neocortex 4.60.66 → 4.60.68
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/dist/release-source.json +1 -1
- package/dist/sbom.cdx.json +1598 -1640
- package/install.ps1 +1 -1
- package/install.sh +2 -1
- package/package.json +10 -7
- package/packages/client/dist/adapters/adapter-registry.js +108 -1
- package/packages/client/dist/adapters/antigravity-adapter.js +77 -2
- package/packages/client/dist/adapters/claude-code-adapter.js +79 -3
- package/packages/client/dist/adapters/codex-adapter.js +80 -2
- package/packages/client/dist/adapters/cursor-adapter.js +115 -4
- package/packages/client/dist/adapters/gemini-adapter.js +71 -2
- package/packages/client/dist/adapters/grok-adapter.js +42 -2
- package/packages/client/dist/adapters/index.js +22 -1
- package/packages/client/dist/adapters/platform-detector.js +212 -1
- package/packages/client/dist/adapters/target-adapter.js +12 -0
- package/packages/client/dist/adapters/vscode-adapter.js +72 -2
- package/packages/client/dist/agent/refresh-stubs.js +417 -2
- package/packages/client/dist/agent/update-agent-yaml.js +102 -1
- package/packages/client/dist/agent/update-description.js +251 -1
- package/packages/client/dist/cache/crypto-utils.js +78 -1
- package/packages/client/dist/cache/encrypted-cache.js +108 -1
- package/packages/client/dist/cache/in-memory-asset-cache.js +73 -1
- package/packages/client/dist/cache/index.js +13 -1
- package/packages/client/dist/cache/protected-pi-boundary.js +44 -1
- package/packages/client/dist/checkpoint/checkpoint-client-reader.js +127 -2
- package/packages/client/dist/checkpoint/index.js +11 -1
- package/packages/client/dist/checkpoint/shared-checkpoint-types.js +32 -1
- package/packages/client/dist/cli.js +303 -3
- package/packages/client/dist/commands/activate.js +394 -8
- package/packages/client/dist/commands/architecture-answers.js +274 -7
- package/packages/client/dist/commands/architecture-memory-terminal.js +253 -4
- package/packages/client/dist/commands/architecture-non-ui-continuation.js +100 -1
- package/packages/client/dist/commands/architecture-root-binding.js +51 -1
- package/packages/client/dist/commands/cache-status.js +112 -2
- package/packages/client/dist/commands/config.js +88 -1
- package/packages/client/dist/commands/doctor.d.ts +135 -0
- package/packages/client/dist/commands/doctor.js +635 -0
- package/packages/client/dist/commands/invoke.d.ts +18 -0
- package/packages/client/dist/commands/invoke.js +7140 -142
- package/packages/client/dist/commands/legacy-epic-terminal.js +71 -1
- package/packages/client/dist/commands/legacy-story-branch.js +96 -1
- package/packages/client/dist/commands/legacy-story-pr.js +276 -1
- package/packages/client/dist/commands/mutation-qa-checkpoint.js +285 -5
- package/packages/client/dist/commands/mutation-qa-gate.js +54 -1
- package/packages/client/dist/commands/mutation-qa-git.js +41 -1
- package/packages/client/dist/commands/mutation-qa-policy.js +102 -1
- package/packages/client/dist/commands/mutation-qa-run.js +219 -3
- package/packages/client/dist/commands/mutation-qa-verdict.js +149 -1
- package/packages/client/dist/commands/mutation-qa.js +220 -1
- package/packages/client/dist/commands/native-agent.js +136 -2
- package/packages/client/dist/commands/planning-diagnosis.js +43 -1
- package/packages/client/dist/commands/planning-generation.js +53 -1
- package/packages/client/dist/commands/planning-memory.js +40 -1
- package/packages/client/dist/commands/planning-research.js +42 -1
- package/packages/client/dist/commands/private-session.js +75 -1
- package/packages/client/dist/commands/property-qa.js +139 -1
- package/packages/client/dist/commands/qa-control.js +16 -1
- package/packages/client/dist/commands/qa-scan-browser-launch.js +55 -1
- package/packages/client/dist/commands/qa-scan-browser-route.js +28 -1
- package/packages/client/dist/commands/qa-scan-capture.js +663 -5
- package/packages/client/dist/commands/qa-scan-discovery.js +376 -3
- package/packages/client/dist/commands/qa-scan-review.js +826 -5
- package/packages/client/dist/commands/qa-synthetic-backend-capture.js +266 -1
- package/packages/client/dist/commands/qa-synthetic-backend-review.js +297 -1
- package/packages/client/dist/commands/qa-synthetic-backend.js +340 -2
- package/packages/client/dist/commands/qa-synthetic-broker-port.js +85 -1
- package/packages/client/dist/commands/qa-synthetic-browser.js +39 -1
- package/packages/client/dist/commands/refactor-characterization.js +671 -21
- package/packages/client/dist/commands/refactor-commit.js +399 -13
- package/packages/client/dist/commands/refactor-control.js +142 -3
- package/packages/client/dist/commands/refactor-cpp-assertions.js +93 -3
- package/packages/client/dist/commands/refactor-review.js +283 -5
- package/packages/client/dist/commands/refactor-root.js +588 -7
- package/packages/client/dist/commands/refresh-memory.js +156 -3
- package/packages/client/dist/commands/shared-architecture-non-ui.js +24 -1
- package/packages/client/dist/commands/story-checkpoint.js +171 -1
- package/packages/client/dist/config/profile-directory.js +13 -1
- package/packages/client/dist/config/resolver-selection.js +278 -1
- package/packages/client/dist/config/secure-config.js +281 -12
- package/packages/client/dist/config.js +223 -2
- package/packages/client/dist/constants.js +25 -1
- package/packages/client/dist/context/context-collector.js +222 -2
- package/packages/client/dist/context/context-sanitizer.js +145 -1
- package/packages/client/dist/continuity/autonomous-governance.js +285 -1
- package/packages/client/dist/continuity/continuity-client-state-store.js +1587 -1
- package/packages/client/dist/continuity/invoke-hooks.js +129 -1
- package/packages/client/dist/continuity/migrations/001-initial-schema.js +12 -2
- package/packages/client/dist/continuity/migrations/002-processing-output-summary-indexes.js +12 -2
- package/packages/client/dist/continuity/migrations/003-headless-execution-attempts.js +12 -2
- package/packages/client/dist/continuity/migrations/004-outbox-delivery-state.js +12 -2
- package/packages/client/dist/continuity/migrations/005-bounded-headless-queue.js +12 -2
- package/packages/client/dist/continuity/migrations/006-native-agent-dispatches.js +10 -2
- package/packages/client/dist/continuity/native-agent-store.js +69 -1
- package/packages/client/dist/continuity/native-agent-types.js +90 -1
- package/packages/client/dist/continuity/outbox.js +117 -1
- package/packages/client/dist/continuity/runner-bootstrap-policy.js +172 -1
- package/packages/client/dist/continuity/sqlite-store.js +2536 -81
- package/packages/client/dist/effects/invoke-effect-gateways.js +62 -1
- package/packages/client/dist/errors/error-messages.js +228 -2
- package/packages/client/dist/errors/frontmatter-diagnostics.js +125 -1
- package/packages/client/dist/evidence/collector.js +347 -1
- package/packages/client/dist/evidence/index.js +1 -1
- package/packages/client/dist/evidence/types.js +2 -0
- package/packages/client/dist/fs/atomic-state-replace.js +152 -1
- package/packages/client/dist/generated/command-registry.generated.js +4076 -1
- package/packages/client/dist/generated/public-projections.generated.js +149 -1
- package/packages/client/dist/git/direct-yolo-c01-retry.js +138 -4
- package/packages/client/dist/git/direct-yolo-checkpoint.js +1234 -4
- package/packages/client/dist/git/git-lifecycle-step-ids.js +14 -1
- package/packages/client/dist/git/git-lifecycle-store.js +1938 -9
- package/packages/client/dist/git/legacy-story-branch-checkpoint.js +259 -9
- package/packages/client/dist/git/legacy-story-branch-setup.js +348 -4
- package/packages/client/dist/git/legacy-story-pr.js +3538 -70
- package/packages/client/dist/git/secure-filesystem-boundary.js +182 -5
- package/packages/client/dist/graph-retrieval/pre-command-hook.js +284 -1
- package/packages/client/dist/graph-retrieval/shared-graph-retrieval-contract.js +237 -1
- package/packages/client/dist/i18n/first-run.js +60 -2
- package/packages/client/dist/index.js +47 -1
- package/packages/client/dist/invocation/invoke-input.js +24 -1
- package/packages/client/dist/license/index.js +5 -1
- package/packages/client/dist/license/license-client.js +304 -1
- package/packages/client/dist/machine/fingerprint.js +163 -2
- package/packages/client/dist/machine/index.js +5 -1
- package/packages/client/dist/memory/project-memory-path-scope.js +62 -1
- package/packages/client/dist/memory/project-memory-writer.js +1007 -40
- package/packages/client/dist/memory/shared-project-memory-types.js +253 -2
- package/packages/client/dist/migrations/project-identity-capability.js +50 -1
- package/packages/client/dist/migrations/project-identity.js +493 -7
- package/packages/client/dist/migrations/state-json.js +344 -4
- package/packages/client/dist/policy/architecture-policy.js +184 -2
- package/packages/client/dist/policy/index.js +7 -1
- package/packages/client/dist/policy/shared-policy-types.js +38 -0
- package/packages/client/dist/policy/subagent-approval-policy.js +55 -1
- package/packages/client/dist/private-execution/clean-baseline.js +279 -2
- package/packages/client/dist/private-execution/codex-executor.js +574 -4
- package/packages/client/dist/private-execution/codex-host-runtime.js +137 -1
- package/packages/client/dist/private-execution/codex-lifecycle-guard.js +97 -1
- package/packages/client/dist/private-execution/codex-scoped-permissions.js +128 -1
- package/packages/client/dist/private-execution/delivery.js +410 -13
- package/packages/client/dist/private-execution/diagnosis-root-review.js +294 -2
- package/packages/client/dist/private-execution/frozen-handoff.js +19 -6
- package/packages/client/dist/private-execution/implementation-validation.js +106 -2
- package/packages/client/dist/private-execution/isolated-admission.js +1432 -23
- package/packages/client/dist/private-execution/isolated-session.js +725 -5
- package/packages/client/dist/private-execution/isolated-workspace.js +122 -1
- package/packages/client/dist/private-execution/pact-consumer-runtime.js +409 -3
- package/packages/client/dist/private-execution/pact-test-source.js +258 -1
- package/packages/client/dist/private-execution/pact-toolchain.js +290 -3
- package/packages/client/dist/private-execution/pact-write-set.js +172 -1
- package/packages/client/dist/private-execution/planning-diagnosis-checkpoint.js +406 -5
- package/packages/client/dist/private-execution/planning-generation-checkpoint.js +462 -5
- package/packages/client/dist/private-execution/planning-memory-checkpoint.js +139 -3
- package/packages/client/dist/private-execution/planning-research-checkpoint.js +325 -4
- package/packages/client/dist/private-execution/private-report-store.js +42 -1
- package/packages/client/dist/private-execution/property-test-candidate.js +103 -1
- package/packages/client/dist/private-execution/property-test-choices.js +147 -3
- package/packages/client/dist/private-execution/property-test-plan.js +271 -7
- package/packages/client/dist/private-execution/property-test-review.js +258 -4
- package/packages/client/dist/private-execution/property-test-runtime.js +372 -9
- package/packages/client/dist/private-execution/property-test-source.js +139 -1
- package/packages/client/dist/private-execution/root-checkpoint.js +80 -1
- package/packages/client/dist/private-execution/root-memory-git-evidence.js +135 -3
- package/packages/client/dist/private-execution/root-memory-recovery.js +93 -1
- package/packages/client/dist/private-execution/root-memory-request.js +29 -1
- package/packages/client/dist/private-execution/root-memory-scope.js +178 -1
- package/packages/client/dist/private-execution/root-memory-writer.js +102 -1
- package/packages/client/dist/private-execution/session-lease.js +63 -1
- package/packages/client/dist/private-execution/shared-private-admission-types.js +50 -1
- package/packages/client/dist/private-execution/shared-project-validation.js +66 -1
- package/packages/client/dist/private-execution/shared-root-memory-types.js +61 -1
- package/packages/client/dist/private-execution/ux-source-validation.js +372 -1
- package/packages/client/dist/private-execution/ux-write-set.js +191 -2
- package/packages/client/dist/resilience/circuit-breaker.js +170 -1
- package/packages/client/dist/resilience/degradation-manager.js +164 -1
- package/packages/client/dist/resilience/freshness-indicator.js +100 -1
- package/packages/client/dist/resilience/index.js +8 -1
- package/packages/client/dist/resilience/recovery-detector.js +74 -1
- package/packages/client/dist/resolvers/asset-resolver.js +13 -0
- package/packages/client/dist/resolvers/local-resolver.js +255 -8
- package/packages/client/dist/resolvers/remote-resolver.js +233 -1
- package/packages/client/dist/runner/binary.js +404 -1
- package/packages/client/dist/runner/cli.js +1571 -17
- package/packages/client/dist/runner/headless/adapters.js +49 -1
- package/packages/client/dist/runner/headless/claude-code-adapter.js +79 -1
- package/packages/client/dist/runner/headless/continuous-story-workspace.js +1628 -11
- package/packages/client/dist/runner/headless/epic-git-reconciliation-inventory.js +69 -1
- package/packages/client/dist/runner/headless/epic-merge-candidate-qa.js +110 -2
- package/packages/client/dist/runner/headless/epic-terminal-git-cli-adapter.js +1236 -8
- package/packages/client/dist/runner/headless/epic-terminal-git-runner.js +318 -2
- package/packages/client/dist/runner/headless/fake-adapter.js +62 -1
- package/packages/client/dist/runner/headless/managed-profile.js +132 -1
- package/packages/client/dist/runner/headless/opencode-adapter.js +145 -2
- package/packages/client/dist/runner/headless/prepared-story-bundle.js +43 -1
- package/packages/client/dist/runner/headless/resolver.js +231 -1
- package/packages/client/dist/runner/headless/run-yolo.js +885 -1
- package/packages/client/dist/runner/headless/run-yoloop.d.ts +4 -1
- package/packages/client/dist/runner/headless/run-yoloop.js +2574 -2
- package/packages/client/dist/runner/headless/types.js +574 -2
- package/packages/client/dist/runner/local-console.js +396 -13
- package/packages/client/dist/runner/portal-sync-worker.js +1487 -1
- package/packages/client/dist/runner/project-identity.js +106 -1
- package/packages/client/dist/runner/scheduler.js +995 -7
- package/packages/client/dist/runner-cli.js +18 -2
- package/packages/client/dist/state/invocation-shape.js +13 -1
- package/packages/client/dist/state/project-state-snapshot.js +1677 -1
- package/packages/client/dist/state/state-json-repair.js +785 -3
- package/packages/client/dist/state/structural-dag-projection.js +118 -1
- package/packages/client/dist/telemetry/index.js +5 -1
- package/packages/client/dist/telemetry/offline-queue.js +131 -1
- package/packages/client/dist/tier/index.js +5 -1
- package/packages/client/dist/tier/tier-aware-client.js +405 -1
- package/packages/client/dist/types/index.js +38 -1
- package/packages/client/dist/version.js +27 -1
- package/packages/client/dist/yolo/change-evidence-collector.js +126 -1
- package/packages/client/dist/yolo/invoke-envelope-capability.js +62 -1
- package/packages/client/dist/yolo/spec-envelope-collector.js +185 -5
- package/packages/client/dist/yoloop/discovery-hook.js +300 -2
- package/packages/client/dist/yoloop/index.js +8 -1
- package/packages/client/dist/yoloop/invoke-hooks.js +669 -12
- package/packages/client/dist/yoloop/shared-discover-epics.js +1007 -1
- package/packages/client/dist/yoloop/shared-yoloop-types.js +33 -1
- package/packages/client/dist/yoloop/target-normalization.js +180 -1
- package/packages/client/dist/yoloop/yoloop-client-state-store.js +1723 -1
- package/packages/shared/dist/compatibility/index.js +476 -0
- package/packages/shared/dist/yoloop/release-blocked.js +653 -0
- package/targets-stubs/antigravity/gemini.md +1 -1
- package/targets-stubs/antigravity/skill/SKILL.md +3 -2
- package/targets-stubs/claude-code/neocortex-root.agent.yaml +1 -1
- package/targets-stubs/claude-code/neocortex-root.md +5 -5
- package/targets-stubs/claude-code/neocortex.agent.yaml +1 -1
- package/targets-stubs/claude-code/neocortex.md +8 -9
- package/targets-stubs/codex/AGENTS.md +3 -3
- package/targets-stubs/cursor/agent.md +4 -3
- package/targets-stubs/gemini-cli/agent.md +5 -4
- package/targets-stubs/opencode/neocortex-root.md +3 -3
- package/targets-stubs/vscode/neocortex.agent.md +5 -4
|
@@ -1,8 +1,394 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
1
|
+
/**
|
|
2
|
+
* @license FSL-1.1
|
|
3
|
+
* Copyright (c) 2026 OrNexus AI
|
|
4
|
+
*
|
|
5
|
+
* This file is part of Neocortex CLI, licensed under the
|
|
6
|
+
* Functional Source License, Version 1.1 (FSL-1.1).
|
|
7
|
+
*
|
|
8
|
+
* Change Date: February 20, 2029
|
|
9
|
+
* Change License: MIT
|
|
10
|
+
*
|
|
11
|
+
* See the LICENSE file in the project root for full license text.
|
|
12
|
+
*/
|
|
13
|
+
/**
|
|
14
|
+
* @neocortex/client - Activate Command
|
|
15
|
+
*
|
|
16
|
+
* Manages license activation for the Neocortex CLI.
|
|
17
|
+
* Validates license key with the IP Protection Server,
|
|
18
|
+
* caches JWT token, and creates user config file.
|
|
19
|
+
*
|
|
20
|
+
* Story 43.3 - AC1, AC3, AC4, AC5
|
|
21
|
+
*/
|
|
22
|
+
import { existsSync, mkdirSync, writeFileSync, readFileSync } from 'node:fs';
|
|
23
|
+
import { join, dirname } from 'node:path';
|
|
24
|
+
import { homedir } from 'node:os';
|
|
25
|
+
import { fileURLToPath } from 'node:url';
|
|
26
|
+
import { LicenseClient } from '../license/license-client.js';
|
|
27
|
+
import { EncryptedCache } from '../cache/encrypted-cache.js';
|
|
28
|
+
import { getMachineFingerprint } from '../machine/fingerprint.js';
|
|
29
|
+
import { updateAgentDescription } from '../agent/update-description.js';
|
|
30
|
+
import { refreshStubs } from '../agent/refresh-stubs.js';
|
|
31
|
+
import { updateAgentYaml } from '../agent/update-agent-yaml.js';
|
|
32
|
+
import { saveSecureConfig, setSecureDirPermissions } from '../config/secure-config.js';
|
|
33
|
+
import { DEFAULT_SERVER_URL } from '../constants.js';
|
|
34
|
+
// ── Version Resolution ────────────────────────────────────────────────────
|
|
35
|
+
function getInstalledVersion() {
|
|
36
|
+
try {
|
|
37
|
+
const thisFile = fileURLToPath(import.meta.url);
|
|
38
|
+
let dir = dirname(thisFile);
|
|
39
|
+
for (let i = 0; i < 5; i++) {
|
|
40
|
+
try {
|
|
41
|
+
const pkg = JSON.parse(readFileSync(join(dir, 'package.json'), 'utf-8'));
|
|
42
|
+
if (pkg.name === '@ornexus/neocortex' || pkg.name === '@neocortex/client') {
|
|
43
|
+
return pkg.version ?? '0.0.0';
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
catch { /* no package.json at this level */ }
|
|
47
|
+
dir = dirname(dir);
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
catch { /* fallback */ }
|
|
51
|
+
return '0.0.0';
|
|
52
|
+
}
|
|
53
|
+
// ── Constants ─────────────────────────────────────────────────────────────
|
|
54
|
+
const CONFIG_DIR = join(homedir(), '.neocortex');
|
|
55
|
+
const CONFIG_FILE = join(CONFIG_DIR, 'config.json');
|
|
56
|
+
// License key format: NX-{F|P|E}-{24 hex}-{4 hex checksum}
|
|
57
|
+
const LICENSE_KEY_PATTERN = /^NX-(F|P|E)-[a-f0-9]+-[a-f0-9]+$/i;
|
|
58
|
+
// API key format: nxk_{24hex}_{4check} (new, P32) or nxk_{tier}_{24hex}_{4check} (legacy)
|
|
59
|
+
const API_KEY_PATTERN = /^nxk_(?:[a-z]+_)?[a-f0-9]+_[a-f0-9]+$/;
|
|
60
|
+
// ── Validation ────────────────────────────────────────────────────────────
|
|
61
|
+
/**
|
|
62
|
+
* Validate license key format.
|
|
63
|
+
* Format: NX-{TIER}-{random}-{random}
|
|
64
|
+
* Tiers: FREE, PRO, ENT
|
|
65
|
+
*/
|
|
66
|
+
export function validateLicenseKeyFormat(key) {
|
|
67
|
+
if (!key || key.trim().length === 0) {
|
|
68
|
+
return { valid: false, error: 'License key cannot be empty' };
|
|
69
|
+
}
|
|
70
|
+
const trimmed = key.trim().toUpperCase();
|
|
71
|
+
if (!trimmed.startsWith('NX-')) {
|
|
72
|
+
return { valid: false, error: 'License key must start with "NX-"' };
|
|
73
|
+
}
|
|
74
|
+
if (!LICENSE_KEY_PATTERN.test(trimmed)) {
|
|
75
|
+
return {
|
|
76
|
+
valid: false,
|
|
77
|
+
error: 'Invalid license key format. Expected: NX-{TIER}-{ID} (e.g., NX-PRO-ABC-123)',
|
|
78
|
+
};
|
|
79
|
+
}
|
|
80
|
+
return { valid: true };
|
|
81
|
+
}
|
|
82
|
+
/**
|
|
83
|
+
* Validate API key format.
|
|
84
|
+
* Format: nxk_{tier}_{random}_{check}
|
|
85
|
+
*/
|
|
86
|
+
export function validateApiKeyFormat(key) {
|
|
87
|
+
if (!key || key.trim().length === 0) {
|
|
88
|
+
return { valid: false, error: 'API key cannot be empty' };
|
|
89
|
+
}
|
|
90
|
+
const trimmed = key.trim();
|
|
91
|
+
if (!trimmed.startsWith('nxk_')) {
|
|
92
|
+
return { valid: false, error: 'API key must start with "nxk_"' };
|
|
93
|
+
}
|
|
94
|
+
if (trimmed.length < 20) {
|
|
95
|
+
return { valid: false, error: 'API key is too short' };
|
|
96
|
+
}
|
|
97
|
+
if (!API_KEY_PATTERN.test(trimmed)) {
|
|
98
|
+
return {
|
|
99
|
+
valid: false,
|
|
100
|
+
error: 'Invalid API key format. Expected: nxk_{id}_{check} (e.g., nxk_abc123def456...)',
|
|
101
|
+
};
|
|
102
|
+
}
|
|
103
|
+
return { valid: true };
|
|
104
|
+
}
|
|
105
|
+
// ── Config Management ─────────────────────────────────────────────────────
|
|
106
|
+
/**
|
|
107
|
+
* Load existing user config, if any.
|
|
108
|
+
*/
|
|
109
|
+
function loadExistingConfig() {
|
|
110
|
+
try {
|
|
111
|
+
if (existsSync(CONFIG_FILE)) {
|
|
112
|
+
const raw = readFileSync(CONFIG_FILE, 'utf-8');
|
|
113
|
+
return JSON.parse(raw);
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
catch {
|
|
117
|
+
// Corrupted config - will be overwritten
|
|
118
|
+
}
|
|
119
|
+
return null;
|
|
120
|
+
}
|
|
121
|
+
/**
|
|
122
|
+
* Save user config after successful activation.
|
|
123
|
+
* License key is encrypted using machine fingerprint (Story 61.2).
|
|
124
|
+
* File permissions set to 600 (Story 61.4).
|
|
125
|
+
*/
|
|
126
|
+
function saveConfig(config) {
|
|
127
|
+
// Ensure directories exist with secure permissions
|
|
128
|
+
mkdirSync(CONFIG_DIR, { recursive: true });
|
|
129
|
+
setSecureDirPermissions(CONFIG_DIR);
|
|
130
|
+
const cacheDir = join(CONFIG_DIR, 'cache');
|
|
131
|
+
mkdirSync(cacheDir, { recursive: true });
|
|
132
|
+
setSecureDirPermissions(cacheDir);
|
|
133
|
+
if (config.licenseKey || config.apiKey) {
|
|
134
|
+
// Use secure config writer which encrypts the key
|
|
135
|
+
saveSecureConfig({
|
|
136
|
+
serverUrl: config.serverUrl,
|
|
137
|
+
mode: config.mode,
|
|
138
|
+
machineId: config.machineId,
|
|
139
|
+
activatedAt: config.activatedAt,
|
|
140
|
+
tier: config.tier,
|
|
141
|
+
licenseKey: (config.licenseKey ?? config.apiKey),
|
|
142
|
+
});
|
|
143
|
+
}
|
|
144
|
+
else {
|
|
145
|
+
// Fallback: write without key (should not happen in normal flow)
|
|
146
|
+
const fallbackConfig = { configVersion: 1, ...config };
|
|
147
|
+
writeFileSync(CONFIG_FILE, JSON.stringify(fallbackConfig, null, 2) + '\n', 'utf-8');
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
// ── Activate Command ──────────────────────────────────────────────────────
|
|
151
|
+
/**
|
|
152
|
+
* Activate a Neocortex license.
|
|
153
|
+
*
|
|
154
|
+
* Flow:
|
|
155
|
+
* 1. Validate license key format
|
|
156
|
+
* 2. Call IP Protection Server to activate
|
|
157
|
+
* 3. Cache JWT token via LicenseClient
|
|
158
|
+
* 4. Create/update ~/.neocortex/config.json
|
|
159
|
+
* 5. Return result with feedback
|
|
160
|
+
*/
|
|
161
|
+
export async function activate(options) {
|
|
162
|
+
const { licenseKey, serverUrl = DEFAULT_SERVER_URL } = options;
|
|
163
|
+
// 1. Check if key is provided
|
|
164
|
+
if (!licenseKey) {
|
|
165
|
+
return {
|
|
166
|
+
success: false,
|
|
167
|
+
message: [
|
|
168
|
+
'No key provided.',
|
|
169
|
+
'',
|
|
170
|
+
'Get your license key at https://neocortex.sh/portal/login',
|
|
171
|
+
'',
|
|
172
|
+
'Usage:',
|
|
173
|
+
' neocortex activate YOUR-LICENSE-KEY',
|
|
174
|
+
' neocortex activate YOUR-API-KEY',
|
|
175
|
+
].join('\n'),
|
|
176
|
+
};
|
|
177
|
+
}
|
|
178
|
+
const trimmedKey = licenseKey.trim();
|
|
179
|
+
// 2. Detect key type: API key (nxk_) or license key (NX-)
|
|
180
|
+
const isApiKey = trimmedKey.startsWith('nxk_');
|
|
181
|
+
if (isApiKey) {
|
|
182
|
+
// ── API Key Activation Flow (Story 22.04) ──────────────────────────
|
|
183
|
+
const apiValidation = validateApiKeyFormat(trimmedKey);
|
|
184
|
+
if (!apiValidation.valid) {
|
|
185
|
+
return {
|
|
186
|
+
success: false,
|
|
187
|
+
message: `Invalid API key: ${apiValidation.error}`,
|
|
188
|
+
};
|
|
189
|
+
}
|
|
190
|
+
// Extract tier from API key -- new format has no tier prefix, server returns tier in response
|
|
191
|
+
const tierMatch = trimmedKey.match(/^nxk_(free|pro|ent)_/);
|
|
192
|
+
const apiTierMap = { free: 'free', pro: 'pro', ent: 'enterprise' };
|
|
193
|
+
const tier = tierMatch?.[1] ? (apiTierMap[tierMatch[1]] ?? 'unknown') : 'unknown'; // will be overridden by server response
|
|
194
|
+
const machineId = getMachineFingerprint();
|
|
195
|
+
const cliVersion = getInstalledVersion();
|
|
196
|
+
// Call /api/v1/license/activate-key
|
|
197
|
+
let response;
|
|
198
|
+
try {
|
|
199
|
+
const res = await fetch(`${serverUrl}/api/v1/license/activate-key`, {
|
|
200
|
+
method: 'POST',
|
|
201
|
+
headers: { 'Content-Type': 'application/json' },
|
|
202
|
+
body: JSON.stringify({
|
|
203
|
+
api_key: trimmedKey,
|
|
204
|
+
machine_id: machineId,
|
|
205
|
+
client_version: cliVersion,
|
|
206
|
+
}),
|
|
207
|
+
});
|
|
208
|
+
if (!res.ok) {
|
|
209
|
+
const body = await res.json().catch(() => ({}));
|
|
210
|
+
const errorBody = body;
|
|
211
|
+
return {
|
|
212
|
+
success: false,
|
|
213
|
+
message: `API key activation failed: ${errorBody.message ?? `HTTP ${res.status}`}`,
|
|
214
|
+
};
|
|
215
|
+
}
|
|
216
|
+
response = await res.json();
|
|
217
|
+
}
|
|
218
|
+
catch {
|
|
219
|
+
return {
|
|
220
|
+
success: false,
|
|
221
|
+
message: [
|
|
222
|
+
'Failed to connect to IP Protection Server.',
|
|
223
|
+
'',
|
|
224
|
+
'Possible causes:',
|
|
225
|
+
` - Server at ${serverUrl} is unreachable`,
|
|
226
|
+
' - Network connectivity issue',
|
|
227
|
+
'',
|
|
228
|
+
'Workaround: Use --local flag to run in local mode',
|
|
229
|
+
].join('\n'),
|
|
230
|
+
};
|
|
231
|
+
}
|
|
232
|
+
const activatedTier = response.tier ?? tier;
|
|
233
|
+
// Cache JWT token via EncryptedCache
|
|
234
|
+
const cacheDir = join(CONFIG_DIR, 'cache');
|
|
235
|
+
try {
|
|
236
|
+
const encryptedCache = new EncryptedCache({
|
|
237
|
+
cacheDir,
|
|
238
|
+
passphrase: trimmedKey,
|
|
239
|
+
});
|
|
240
|
+
await encryptedCache.set('neocortex:jwt:token', response.token, response.expires_in * 1000);
|
|
241
|
+
}
|
|
242
|
+
catch {
|
|
243
|
+
// Cache is non-critical (fail-open)
|
|
244
|
+
}
|
|
245
|
+
// Save config with API key
|
|
246
|
+
const config = {
|
|
247
|
+
serverUrl,
|
|
248
|
+
mode: 'remote',
|
|
249
|
+
machineId,
|
|
250
|
+
activatedAt: new Date().toISOString(),
|
|
251
|
+
tier: activatedTier,
|
|
252
|
+
apiKey: trimmedKey,
|
|
253
|
+
};
|
|
254
|
+
try {
|
|
255
|
+
saveConfig(config);
|
|
256
|
+
}
|
|
257
|
+
catch (err) {
|
|
258
|
+
return {
|
|
259
|
+
success: false,
|
|
260
|
+
message: `Failed to save configuration: ${err instanceof Error ? err.message : 'unknown error'}`,
|
|
261
|
+
};
|
|
262
|
+
}
|
|
263
|
+
// Refresh stubs and agent description
|
|
264
|
+
const stubsRefreshed = refreshStubs(cliVersion, { forceCreate: true, targetFilter: 'claude-code' })
|
|
265
|
+
+ refreshStubs(cliVersion);
|
|
266
|
+
updateAgentDescription(cliVersion, activatedTier);
|
|
267
|
+
updateAgentYaml(cliVersion, activatedTier);
|
|
268
|
+
return {
|
|
269
|
+
success: true,
|
|
270
|
+
message: [
|
|
271
|
+
'Neocortex activated successfully.',
|
|
272
|
+
'',
|
|
273
|
+
'Open your preferred platform (Claude Code, Cursor, VS Code, etc.)',
|
|
274
|
+
'and reference the Neocortex agent.',
|
|
275
|
+
...(stubsRefreshed > 0
|
|
276
|
+
? ['', 'Managed agent wrappers were refreshed while preserving existing Markdown frontmatter and unrelated platform files.']
|
|
277
|
+
: []),
|
|
278
|
+
'',
|
|
279
|
+
'Use *menu to see available commands or check the Docs in your Dashboard.',
|
|
280
|
+
].join('\n'),
|
|
281
|
+
tier: activatedTier,
|
|
282
|
+
serverUrl,
|
|
283
|
+
configPath: CONFIG_FILE,
|
|
284
|
+
};
|
|
285
|
+
}
|
|
286
|
+
// ── License Key Activation Flow (existing) ──────────────────────────────
|
|
287
|
+
const validation = validateLicenseKeyFormat(trimmedKey);
|
|
288
|
+
if (!validation.valid) {
|
|
289
|
+
return {
|
|
290
|
+
success: false,
|
|
291
|
+
message: `Invalid license key: ${validation.error}`,
|
|
292
|
+
};
|
|
293
|
+
}
|
|
294
|
+
const normalizedKey = trimmedKey;
|
|
295
|
+
// Extract tier from key
|
|
296
|
+
const tierMatch = normalizedKey.match(/^NX-(F|P|E)-/i);
|
|
297
|
+
const tierMap = { F: 'free', P: 'pro', E: 'enterprise' };
|
|
298
|
+
const tier = tierMatch?.[1] ? (tierMap[tierMatch[1].toUpperCase()] ?? 'unknown') : 'unknown';
|
|
299
|
+
// Attempt activation via LicenseClient with EncryptedCache
|
|
300
|
+
const cacheDir = join(CONFIG_DIR, 'cache');
|
|
301
|
+
const encryptedCache = new EncryptedCache({
|
|
302
|
+
cacheDir,
|
|
303
|
+
passphrase: normalizedKey,
|
|
304
|
+
});
|
|
305
|
+
const client = new LicenseClient({
|
|
306
|
+
serverUrl,
|
|
307
|
+
licenseKey: normalizedKey,
|
|
308
|
+
cacheProvider: encryptedCache,
|
|
309
|
+
});
|
|
310
|
+
let activationResult;
|
|
311
|
+
try {
|
|
312
|
+
activationResult = await client.activate();
|
|
313
|
+
}
|
|
314
|
+
catch {
|
|
315
|
+
return {
|
|
316
|
+
success: false,
|
|
317
|
+
message: [
|
|
318
|
+
'Failed to connect to IP Protection Server.',
|
|
319
|
+
'',
|
|
320
|
+
'Possible causes:',
|
|
321
|
+
` - Server at ${serverUrl} is unreachable`,
|
|
322
|
+
' - Network connectivity issue',
|
|
323
|
+
' - Server is still being deployed',
|
|
324
|
+
'',
|
|
325
|
+
'Workaround: Use --local flag to run in local mode',
|
|
326
|
+
].join('\n'),
|
|
327
|
+
};
|
|
328
|
+
}
|
|
329
|
+
if (!activationResult) {
|
|
330
|
+
return {
|
|
331
|
+
success: false,
|
|
332
|
+
message: [
|
|
333
|
+
'License activation failed.',
|
|
334
|
+
'',
|
|
335
|
+
'Possible causes:',
|
|
336
|
+
' - Invalid or expired license key',
|
|
337
|
+
' - License already activated on another machine',
|
|
338
|
+
' - Server rejected the activation request',
|
|
339
|
+
'',
|
|
340
|
+
'Check your license key and try again.',
|
|
341
|
+
'Contact support if the problem persists.',
|
|
342
|
+
].join('\n'),
|
|
343
|
+
};
|
|
344
|
+
}
|
|
345
|
+
// An admin upgrade changes the server license tier without rotating the
|
|
346
|
+
// original NX-F/NX-P key. The validated activation response is authoritative;
|
|
347
|
+
// the prefix remains only a compatibility fallback for older servers.
|
|
348
|
+
const activatedTier = activationResult.tier ?? tier;
|
|
349
|
+
// Save config with license key for invoke re-authentication
|
|
350
|
+
const config = {
|
|
351
|
+
serverUrl,
|
|
352
|
+
mode: 'remote',
|
|
353
|
+
machineId: getMachineFingerprint(),
|
|
354
|
+
activatedAt: new Date().toISOString(),
|
|
355
|
+
tier: activatedTier,
|
|
356
|
+
licenseKey: normalizedKey,
|
|
357
|
+
};
|
|
358
|
+
try {
|
|
359
|
+
saveConfig(config);
|
|
360
|
+
}
|
|
361
|
+
catch (err) {
|
|
362
|
+
return {
|
|
363
|
+
success: false,
|
|
364
|
+
message: `Failed to save config to ${CONFIG_FILE}: ${err instanceof Error ? err.message : String(err)}`,
|
|
365
|
+
};
|
|
366
|
+
}
|
|
367
|
+
// Refresh Claude plus any other existing targets when versions differ.
|
|
368
|
+
const cliVersion = getInstalledVersion();
|
|
369
|
+
const stubsRefreshed = refreshStubs(cliVersion, {
|
|
370
|
+
forceCreate: true,
|
|
371
|
+
targetFilter: 'claude-code',
|
|
372
|
+
}) + refreshStubs(cliVersion);
|
|
373
|
+
// Update agent description with activated tier and version
|
|
374
|
+
updateAgentDescription(cliVersion, activatedTier);
|
|
375
|
+
// Update agent YAML with version and tier (Story 55.2)
|
|
376
|
+
updateAgentYaml(cliVersion, activatedTier);
|
|
377
|
+
return {
|
|
378
|
+
success: true,
|
|
379
|
+
message: [
|
|
380
|
+
'Neocortex activated successfully.',
|
|
381
|
+
'',
|
|
382
|
+
'Open your preferred platform (Claude Code, Cursor, VS Code, etc.)',
|
|
383
|
+
'and reference the Neocortex agent.',
|
|
384
|
+
...(stubsRefreshed > 0
|
|
385
|
+
? ['', 'Managed agent wrappers were refreshed while preserving existing Markdown frontmatter and unrelated platform files.']
|
|
386
|
+
: []),
|
|
387
|
+
'',
|
|
388
|
+
'Use *menu to see available commands or check the Docs in your Dashboard.',
|
|
389
|
+
].join('\n'),
|
|
390
|
+
tier: activatedTier,
|
|
391
|
+
serverUrl,
|
|
392
|
+
configPath: CONFIG_FILE,
|
|
393
|
+
};
|
|
394
|
+
}
|