@nepopsx/cli 0.0.23 → 0.0.25
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/commands/guard.d.ts +10 -0
- package/dist/commands/guard.d.ts.map +1 -0
- package/dist/commands/guard.js +63 -0
- package/dist/commands/guard.js.map +1 -0
- package/dist/commands/import-agents.d.ts +17 -0
- package/dist/commands/import-agents.d.ts.map +1 -0
- package/dist/commands/import-agents.js +166 -0
- package/dist/commands/import-agents.js.map +1 -0
- package/dist/commands/import.d.ts +19 -0
- package/dist/commands/import.d.ts.map +1 -0
- package/dist/commands/import.js +175 -0
- package/dist/commands/import.js.map +1 -0
- package/dist/commands/init.d.ts.map +1 -1
- package/dist/commands/init.js +22 -14
- package/dist/commands/init.js.map +1 -1
- package/dist/commands/install.js +4 -4
- package/dist/commands/install.js.map +1 -1
- package/dist/commands/login.d.ts +3 -3
- package/dist/commands/login.d.ts.map +1 -1
- package/dist/commands/login.js +26 -70
- package/dist/commands/login.js.map +1 -1
- package/dist/commands/push-learnings.js +1 -1
- package/dist/commands/push-learnings.js.map +1 -1
- package/dist/commands/sync.d.ts.map +1 -1
- package/dist/commands/sync.js +7 -2
- package/dist/commands/sync.js.map +1 -1
- package/dist/commands/up.js +2 -2
- package/dist/commands/up.js.map +1 -1
- package/dist/config/api-config.d.ts +7 -0
- package/dist/config/api-config.d.ts.map +1 -1
- package/dist/config/api-config.js +9 -1
- package/dist/config/api-config.js.map +1 -1
- package/dist/config/global-config.d.ts +52 -0
- package/dist/config/global-config.d.ts.map +1 -0
- package/dist/config/global-config.js +161 -0
- package/dist/config/global-config.js.map +1 -0
- package/dist/config/global-config.test.d.ts +2 -0
- package/dist/config/global-config.test.d.ts.map +1 -0
- package/dist/config/global-config.test.js +62 -0
- package/dist/config/global-config.test.js.map +1 -0
- package/dist/guard/policy.d.ts +38 -0
- package/dist/guard/policy.d.ts.map +1 -0
- package/dist/guard/policy.js +62 -0
- package/dist/guard/policy.js.map +1 -0
- package/dist/guard/policy.test.d.ts +2 -0
- package/dist/guard/policy.test.d.ts.map +1 -0
- package/dist/guard/policy.test.js +47 -0
- package/dist/guard/policy.test.js.map +1 -0
- package/dist/hooks/capture-hooks.d.ts.map +1 -1
- package/dist/hooks/capture-hooks.js +36 -1
- package/dist/hooks/capture-hooks.js.map +1 -1
- package/dist/import/adapter.d.ts +82 -0
- package/dist/import/adapter.d.ts.map +1 -0
- package/dist/import/adapter.js +111 -0
- package/dist/import/adapter.js.map +1 -0
- package/dist/import/adapter.test.d.ts +2 -0
- package/dist/import/adapter.test.d.ts.map +1 -0
- package/dist/import/adapter.test.js +100 -0
- package/dist/import/adapter.test.js.map +1 -0
- package/dist/import/agents/agent-adapter.d.ts +83 -0
- package/dist/import/agents/agent-adapter.d.ts.map +1 -0
- package/dist/import/agents/agent-adapter.js +66 -0
- package/dist/import/agents/agent-adapter.js.map +1 -0
- package/dist/import/agents/agent-adapter.test.d.ts +2 -0
- package/dist/import/agents/agent-adapter.test.d.ts.map +1 -0
- package/dist/import/agents/agent-adapter.test.js +99 -0
- package/dist/import/agents/agent-adapter.test.js.map +1 -0
- package/dist/import/agents/artifact-parser.d.ts +26 -0
- package/dist/import/agents/artifact-parser.d.ts.map +1 -0
- package/dist/import/agents/artifact-parser.js +40 -0
- package/dist/import/agents/artifact-parser.js.map +1 -0
- package/dist/import/agents/assembler.d.ts +32 -0
- package/dist/import/agents/assembler.d.ts.map +1 -0
- package/dist/import/agents/assembler.js +62 -0
- package/dist/import/agents/assembler.js.map +1 -0
- package/dist/import/agents/assembler.test.d.ts +2 -0
- package/dist/import/agents/assembler.test.d.ts.map +1 -0
- package/dist/import/agents/assembler.test.js +115 -0
- package/dist/import/agents/assembler.test.js.map +1 -0
- package/dist/import/agents/claude-code-adapter.d.ts +11 -0
- package/dist/import/agents/claude-code-adapter.d.ts.map +1 -0
- package/dist/import/agents/claude-code-adapter.js +67 -0
- package/dist/import/agents/claude-code-adapter.js.map +1 -0
- package/dist/import/agents/copilot-agent-adapter.d.ts +12 -0
- package/dist/import/agents/copilot-agent-adapter.d.ts.map +1 -0
- package/dist/import/agents/copilot-agent-adapter.js +89 -0
- package/dist/import/agents/copilot-agent-adapter.js.map +1 -0
- package/dist/import/agents/scanner.d.ts +15 -0
- package/dist/import/agents/scanner.d.ts.map +1 -0
- package/dist/import/agents/scanner.js +87 -0
- package/dist/import/agents/scanner.js.map +1 -0
- package/dist/import/agents/secret-scan.d.ts +14 -0
- package/dist/import/agents/secret-scan.d.ts.map +1 -0
- package/dist/import/agents/secret-scan.js +64 -0
- package/dist/import/agents/secret-scan.js.map +1 -0
- package/dist/import/agents/secret-scan.test.d.ts +2 -0
- package/dist/import/agents/secret-scan.test.d.ts.map +1 -0
- package/dist/import/agents/secret-scan.test.js +41 -0
- package/dist/import/agents/secret-scan.test.js.map +1 -0
- package/dist/import/claude-memory-adapter.d.ts +20 -0
- package/dist/import/claude-memory-adapter.d.ts.map +1 -0
- package/dist/import/claude-memory-adapter.js +87 -0
- package/dist/import/claude-memory-adapter.js.map +1 -0
- package/dist/import/copilot-adapter.d.ts +13 -0
- package/dist/import/copilot-adapter.d.ts.map +1 -0
- package/dist/import/copilot-adapter.js +75 -0
- package/dist/import/copilot-adapter.js.map +1 -0
- package/dist/index.js +28 -7
- package/dist/index.js.map +1 -1
- package/dist/learnings/memory-index.d.ts +17 -0
- package/dist/learnings/memory-index.d.ts.map +1 -0
- package/dist/learnings/memory-index.js +73 -0
- package/dist/learnings/memory-index.js.map +1 -0
- package/dist/licensing/index.d.ts +1 -1
- package/dist/licensing/index.d.ts.map +1 -1
- package/dist/licensing/index.js +1 -1
- package/dist/licensing/index.js.map +1 -1
- package/dist/licensing/installer.d.ts +7 -8
- package/dist/licensing/installer.d.ts.map +1 -1
- package/dist/licensing/installer.js +9 -17
- package/dist/licensing/installer.js.map +1 -1
- package/dist/licensing/license-manager.d.ts +25 -51
- package/dist/licensing/license-manager.d.ts.map +1 -1
- package/dist/licensing/license-manager.js +54 -275
- package/dist/licensing/license-manager.js.map +1 -1
- package/dist/licensing/workspace-name.d.ts +1 -1
- package/dist/licensing/workspace-name.js +1 -1
- package/dist/mcp/config-generator.d.ts +6 -6
- package/dist/mcp/config-generator.d.ts.map +1 -1
- package/dist/mcp/config-generator.js +4 -4
- package/dist/mcp/config-generator.js.map +1 -1
- package/package.json +1 -1
|
@@ -1,134 +1,56 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
3
|
-
*
|
|
2
|
+
* Auth/session helpers. Post-migration the CLI has ONE credential: the opaque
|
|
3
|
+
* device token from `nepopsx login`, stored in the GLOBAL `~/.nepopsx/config.json`
|
|
4
|
+
* (never in the repo — see {@link readAuth}). The `License` shape is kept as a thin
|
|
5
|
+
* compatibility view — `.key` IS the device token — so existing commands send the
|
|
6
|
+
* right Bearer credential unchanged. Auth and entitlement are server-authoritative
|
|
7
|
+
* now (the backend 401/402s); there is no license.json, no machine binding, and no
|
|
8
|
+
* online validate/refresh.
|
|
4
9
|
*/
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
7
|
-
import { TIER_LIMITS, generateMachineId, generateFingerprint, checkExpiry, } from '@nepopsx/core';
|
|
8
|
-
import { resolveApiBase } from '../config/api-config.js';
|
|
9
|
-
import { fetchWithTimeout } from '../utils/fetch.js';
|
|
10
|
+
import { TIER_LIMITS, generateMachineId, generateFingerprint, } from '@nepopsx/core';
|
|
11
|
+
import { readAuth, resolveOrgForPath } from '../config/global-config.js';
|
|
10
12
|
import { fetchPlanManifest } from '../utils/fetch-plan-manifest.js';
|
|
11
|
-
import { API_TIMEOUT_MS } from '../constants.js';
|
|
12
13
|
import { readWorkspaceNameFromDisk } from './workspace-name.js';
|
|
13
|
-
import { getCachedEntitlement
|
|
14
|
-
|
|
15
|
-
const LICENSE_FILE = 'license.json';
|
|
16
|
-
// ─── License file operations ────────────────────────────────
|
|
14
|
+
import { getCachedEntitlement } from './entitlement-cache.js';
|
|
15
|
+
// ─── Session (device token) ─────────────────────────────────
|
|
17
16
|
/**
|
|
18
|
-
*
|
|
17
|
+
* Build a `License`-shaped view from the stored device token. `.key` IS the opaque
|
|
18
|
+
* `opsx_dvc_…` token sent as a Bearer credential; `org`/`tier` come from the plan
|
|
19
|
+
* captured at login; `workspace` is the live local name. Returns null if not
|
|
20
|
+
* logged in. (No license.json — the device token in config.json is the credential.)
|
|
19
21
|
*/
|
|
20
22
|
export function readLicense(rootDir) {
|
|
21
|
-
const
|
|
22
|
-
if (!
|
|
23
|
+
const auth = readAuth(rootDir);
|
|
24
|
+
if (!auth?.token)
|
|
23
25
|
return null;
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
}
|
|
26
|
+
return {
|
|
27
|
+
key: auth.token,
|
|
28
|
+
// Project-specific org (registry) wins over the machine default from login.
|
|
29
|
+
org: resolveOrgForPath(rootDir, auth.org),
|
|
30
|
+
tier: auth.plan ?? 'free',
|
|
31
|
+
valid_until: '',
|
|
32
|
+
refresh_token: '',
|
|
33
|
+
machine_id: generateMachineId(),
|
|
34
|
+
workspace: readWorkspaceNameFromDisk(rootDir) ?? 'unknown',
|
|
35
|
+
activated_at: '',
|
|
36
|
+
last_refreshed: '',
|
|
37
|
+
};
|
|
36
38
|
}
|
|
37
|
-
/**
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
export function writeLicense(rootDir, license) {
|
|
41
|
-
const dir = join(rootDir, LICENSE_DIR);
|
|
42
|
-
if (!existsSync(dir)) {
|
|
43
|
-
mkdirSync(dir, { recursive: true });
|
|
44
|
-
}
|
|
45
|
-
writeFileSync(join(dir, LICENSE_FILE), JSON.stringify(license, null, 2) + '\n', 'utf-8');
|
|
39
|
+
/** No-op: the workspace is sourced live from disk in `readLicense` now. */
|
|
40
|
+
export function reconcileLicenseWorkspace(_rootDir, license) {
|
|
41
|
+
return license;
|
|
46
42
|
}
|
|
47
|
-
/**
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
* The license is activated before `workspace.yaml` exists, so it is born with
|
|
51
|
-
* `workspace: "unknown"`. Once the real config exists, reconcile the in-memory
|
|
52
|
-
* license (and persist it) so every downstream `license.workspace` read — and
|
|
53
|
-
* every backend call derived from it — uses the live workspace name instead of
|
|
54
|
-
* the stale snapshot. Best-effort: returns the license unchanged when the config
|
|
55
|
-
* is absent or already matches. Accepts/returns `null` for the no-license path.
|
|
56
|
-
*/
|
|
57
|
-
export function reconcileLicenseWorkspace(rootDir, license) {
|
|
58
|
-
if (!license)
|
|
59
|
-
return license;
|
|
60
|
-
const liveName = readWorkspaceNameFromDisk(rootDir);
|
|
61
|
-
if (!liveName || liveName === license.workspace)
|
|
62
|
-
return license;
|
|
63
|
-
const reconciled = { ...license, workspace: liveName };
|
|
64
|
-
try {
|
|
65
|
-
writeLicense(rootDir, reconciled);
|
|
66
|
-
}
|
|
67
|
-
catch {
|
|
68
|
-
// Persisting is best-effort — the in-memory heal is what callers rely on.
|
|
69
|
-
}
|
|
70
|
-
return reconciled;
|
|
43
|
+
/** No-op kept for callers: there is no license.json to write any more. */
|
|
44
|
+
export function writeLicense(_rootDir, _license) {
|
|
45
|
+
/* the device token is written to config.json by `nepopsx login` */
|
|
71
46
|
}
|
|
47
|
+
// ─── Validation (local, advisory) ───────────────────────────
|
|
72
48
|
/**
|
|
73
|
-
*
|
|
74
|
-
*
|
|
49
|
+
* Confirm a device token is present. Auth + entitlement are enforced by the
|
|
50
|
+
* backend (401/402) — this no longer calls the server.
|
|
75
51
|
*/
|
|
76
|
-
export async function
|
|
77
|
-
const
|
|
78
|
-
const apiBase = resolveApiBase(rootDir);
|
|
79
|
-
try {
|
|
80
|
-
const response = await fetchWithTimeout(`${apiBase}/license/activate`, {
|
|
81
|
-
method: 'POST',
|
|
82
|
-
headers: { 'Content-Type': 'application/json' },
|
|
83
|
-
body: JSON.stringify({
|
|
84
|
-
key: licenseKey,
|
|
85
|
-
machine_id: machineId,
|
|
86
|
-
workspace: workspaceName,
|
|
87
|
-
}),
|
|
88
|
-
}, API_TIMEOUT_MS);
|
|
89
|
-
if (!response.ok) {
|
|
90
|
-
const body = await response.text();
|
|
91
|
-
return {
|
|
92
|
-
success: false,
|
|
93
|
-
error: `Activation failed (${response.status}): ${body}`,
|
|
94
|
-
};
|
|
95
|
-
}
|
|
96
|
-
const data = await response.json();
|
|
97
|
-
const license = {
|
|
98
|
-
key: licenseKey,
|
|
99
|
-
org: data.org,
|
|
100
|
-
tier: data.tier,
|
|
101
|
-
valid_until: data.valid_until,
|
|
102
|
-
refresh_token: data.refresh_token,
|
|
103
|
-
machine_id: machineId,
|
|
104
|
-
workspace: workspaceName,
|
|
105
|
-
activated_at: new Date().toISOString(),
|
|
106
|
-
last_refreshed: new Date().toISOString(),
|
|
107
|
-
};
|
|
108
|
-
writeLicense(rootDir, license);
|
|
109
|
-
return { success: true, license };
|
|
110
|
-
}
|
|
111
|
-
catch (err) {
|
|
112
|
-
// Network failure — might be offline
|
|
113
|
-
return {
|
|
114
|
-
success: false,
|
|
115
|
-
error: `Cannot reach NEPOPSX API: ${err instanceof Error ? err.message : String(err)}. Check your internet connection.`,
|
|
116
|
-
};
|
|
117
|
-
}
|
|
118
|
-
}
|
|
119
|
-
// ─── Validation ─────────────────────────────────────────────
|
|
120
|
-
/**
|
|
121
|
-
* Validate the current license. Attempts online refresh if expired.
|
|
122
|
-
* Returns detailed status.
|
|
123
|
-
*/
|
|
124
|
-
export async function validateLicense(rootDir, config) {
|
|
125
|
-
// Heal a stale `workspace: "unknown"` against the live config before any
|
|
126
|
-
// backend call uses it. validateLicense always runs with a loaded config, so
|
|
127
|
-
// this self-heals license.json and every later readLicense() returns the
|
|
128
|
-
// correct workspace.
|
|
129
|
-
const license = reconcileLicenseWorkspace(rootDir, readLicense(rootDir));
|
|
130
|
-
const apiBase = resolveApiBase(rootDir);
|
|
131
|
-
// No license file
|
|
52
|
+
export async function validateLicense(rootDir, _config) {
|
|
53
|
+
const license = readLicense(rootDir);
|
|
132
54
|
if (!license) {
|
|
133
55
|
return {
|
|
134
56
|
valid: false,
|
|
@@ -137,159 +59,24 @@ export async function validateLicense(rootDir, config) {
|
|
|
137
59
|
tier: 'free',
|
|
138
60
|
org: '',
|
|
139
61
|
fingerprint: '',
|
|
140
|
-
message: '
|
|
141
|
-
};
|
|
142
|
-
}
|
|
143
|
-
// Machine binding check
|
|
144
|
-
const currentMachineId = generateMachineId();
|
|
145
|
-
if (license.machine_id !== currentMachineId) {
|
|
146
|
-
return {
|
|
147
|
-
valid: false,
|
|
148
|
-
expired: false,
|
|
149
|
-
days_remaining: 0,
|
|
150
|
-
tier: license.tier,
|
|
151
|
-
org: license.org,
|
|
152
|
-
fingerprint: '',
|
|
153
|
-
message: 'License is bound to a different machine. Run `nepopsx activate <key>` to re-activate.',
|
|
154
|
-
};
|
|
155
|
-
}
|
|
156
|
-
const { expired, daysRemaining } = checkExpiry(license.valid_until);
|
|
157
|
-
const fingerprint = generateFingerprint(license.org, license.key, license.workspace);
|
|
158
|
-
// Still valid — return immediately
|
|
159
|
-
if (!expired) {
|
|
160
|
-
try {
|
|
161
|
-
const response = await fetchWithTimeout(`${apiBase}/license/validate`, {
|
|
162
|
-
method: 'POST',
|
|
163
|
-
headers: { 'Content-Type': 'application/json' },
|
|
164
|
-
body: JSON.stringify({
|
|
165
|
-
key: license.key,
|
|
166
|
-
machine_id: license.machine_id,
|
|
167
|
-
workspace: license.workspace,
|
|
168
|
-
}),
|
|
169
|
-
}, API_TIMEOUT_MS);
|
|
170
|
-
if (response.ok) {
|
|
171
|
-
const data = await response.json();
|
|
172
|
-
if (data.valid) {
|
|
173
|
-
const updatedLicense = {
|
|
174
|
-
...license,
|
|
175
|
-
org: data.org,
|
|
176
|
-
tier: data.tier,
|
|
177
|
-
valid_until: data.valid_until,
|
|
178
|
-
last_refreshed: new Date().toISOString(),
|
|
179
|
-
};
|
|
180
|
-
writeLicense(rootDir, updatedLicense);
|
|
181
|
-
if (data.entitlement) {
|
|
182
|
-
setCachedEntitlement(rootDir, updatedLicense.key, data.entitlement);
|
|
183
|
-
}
|
|
184
|
-
const onlineExpiry = checkExpiry(updatedLicense.valid_until);
|
|
185
|
-
return {
|
|
186
|
-
valid: true,
|
|
187
|
-
expired: false,
|
|
188
|
-
days_remaining: onlineExpiry.daysRemaining,
|
|
189
|
-
tier: updatedLicense.tier,
|
|
190
|
-
org: updatedLicense.org,
|
|
191
|
-
fingerprint,
|
|
192
|
-
message: data.message,
|
|
193
|
-
entitlement: data.entitlement,
|
|
194
|
-
};
|
|
195
|
-
}
|
|
196
|
-
return {
|
|
197
|
-
valid: false,
|
|
198
|
-
expired: false,
|
|
199
|
-
days_remaining: daysRemaining,
|
|
200
|
-
tier: license.tier,
|
|
201
|
-
org: license.org,
|
|
202
|
-
fingerprint,
|
|
203
|
-
message: data.message,
|
|
204
|
-
};
|
|
205
|
-
}
|
|
206
|
-
}
|
|
207
|
-
catch {
|
|
208
|
-
// Fall back to local validation when offline or backend is unavailable.
|
|
209
|
-
}
|
|
210
|
-
return {
|
|
211
|
-
valid: true,
|
|
212
|
-
expired: false,
|
|
213
|
-
days_remaining: daysRemaining,
|
|
214
|
-
tier: license.tier,
|
|
215
|
-
org: license.org,
|
|
216
|
-
fingerprint,
|
|
217
|
-
message: daysRemaining <= 7
|
|
218
|
-
? `License expires in ${daysRemaining} day(s). Renew at nepopsx.dev.`
|
|
219
|
-
: `Licensed to ${license.org} (${license.tier}).`,
|
|
62
|
+
message: 'Not logged in. Run `nepopsx login` to authorize this machine.',
|
|
220
63
|
};
|
|
221
64
|
}
|
|
222
|
-
// Expired — attempt online refresh
|
|
223
|
-
const refreshed = await refreshLicense(rootDir, license);
|
|
224
|
-
if (refreshed) {
|
|
225
|
-
const { license: refreshedLicense, entitlement } = refreshed;
|
|
226
|
-
const newExpiry = checkExpiry(refreshedLicense.valid_until);
|
|
227
|
-
return {
|
|
228
|
-
valid: true,
|
|
229
|
-
expired: false,
|
|
230
|
-
days_remaining: newExpiry.daysRemaining,
|
|
231
|
-
tier: refreshedLicense.tier,
|
|
232
|
-
org: refreshedLicense.org,
|
|
233
|
-
fingerprint,
|
|
234
|
-
message: `License refreshed. Valid until ${refreshedLicense.valid_until}.`,
|
|
235
|
-
entitlement,
|
|
236
|
-
};
|
|
237
|
-
}
|
|
238
|
-
// Refresh failed — license is truly expired
|
|
239
65
|
return {
|
|
240
|
-
valid:
|
|
241
|
-
expired:
|
|
242
|
-
days_remaining:
|
|
66
|
+
valid: true,
|
|
67
|
+
expired: false,
|
|
68
|
+
days_remaining: 365,
|
|
243
69
|
tier: license.tier,
|
|
244
70
|
org: license.org,
|
|
245
|
-
fingerprint,
|
|
246
|
-
message: `
|
|
71
|
+
fingerprint: generateFingerprint(license.org, license.key, license.workspace),
|
|
72
|
+
message: `Logged in to ${license.org || 'your org'} (${license.tier}).`,
|
|
247
73
|
};
|
|
248
74
|
}
|
|
249
|
-
/**
|
|
250
|
-
* Attempt to refresh the license via the remote API.
|
|
251
|
-
* Returns the updated license (+ entitlement when the backend provides it) on success,
|
|
252
|
-
* null on failure.
|
|
253
|
-
*/
|
|
254
|
-
async function refreshLicense(rootDir, license) {
|
|
255
|
-
const apiBase = resolveApiBase(rootDir);
|
|
256
|
-
try {
|
|
257
|
-
const response = await fetchWithTimeout(`${apiBase}/license/refresh`, {
|
|
258
|
-
method: 'POST',
|
|
259
|
-
headers: { 'Content-Type': 'application/json' },
|
|
260
|
-
body: JSON.stringify({
|
|
261
|
-
refresh_token: license.refresh_token,
|
|
262
|
-
machine_id: license.machine_id,
|
|
263
|
-
}),
|
|
264
|
-
}, API_TIMEOUT_MS);
|
|
265
|
-
if (!response.ok)
|
|
266
|
-
return null;
|
|
267
|
-
const data = await response.json();
|
|
268
|
-
const updated = {
|
|
269
|
-
...license,
|
|
270
|
-
tier: data.tier,
|
|
271
|
-
valid_until: data.valid_until,
|
|
272
|
-
refresh_token: data.refresh_token,
|
|
273
|
-
last_refreshed: new Date().toISOString(),
|
|
274
|
-
};
|
|
275
|
-
writeLicense(rootDir, updated);
|
|
276
|
-
if (data.entitlement) {
|
|
277
|
-
setCachedEntitlement(rootDir, updated.key, data.entitlement);
|
|
278
|
-
}
|
|
279
|
-
return { license: updated, entitlement: data.entitlement };
|
|
280
|
-
}
|
|
281
|
-
catch {
|
|
282
|
-
// Network failure — can't refresh
|
|
283
|
-
return null;
|
|
284
|
-
}
|
|
285
|
-
}
|
|
286
75
|
// ─── Resolved entitlement (display / advisory) ──────────────
|
|
287
76
|
/**
|
|
288
|
-
* Resolve the org's entitlement for DISPLAY: cache → synthesized from the plan
|
|
289
|
-
* the
|
|
290
|
-
*
|
|
291
|
-
* This is advisory only — the backend's 402 responses are the single hard authority. Use it
|
|
292
|
-
* to show the user their current plan/limits, not to allow/deny an operation locally.
|
|
77
|
+
* Resolve the org's entitlement for DISPLAY: cache → synthesized from the plan
|
|
78
|
+
* manifest + the session's plan. Advisory only — the backend's 402s are the hard
|
|
79
|
+
* authority. Never throws.
|
|
293
80
|
*/
|
|
294
81
|
export async function resolveEntitlement(rootDir, license) {
|
|
295
82
|
const cached = getCachedEntitlement(rootDir, license.key);
|
|
@@ -302,22 +89,18 @@ export async function resolveEntitlement(rootDir, license) {
|
|
|
302
89
|
status: license.tier === 'free' ? 'free' : 'active',
|
|
303
90
|
limits: spec.limits,
|
|
304
91
|
features: spec.features,
|
|
305
|
-
validUntil:
|
|
92
|
+
validUntil: null,
|
|
306
93
|
trialEndsAt: null,
|
|
307
94
|
};
|
|
308
95
|
}
|
|
309
96
|
/**
|
|
310
|
-
* Check whether the workspace config exceeds the
|
|
311
|
-
*
|
|
312
|
-
*
|
|
313
|
-
* surface violations as a *warning* + upgrade hint and proceed; they must not hard-block on
|
|
314
|
-
* this result. Agent quality (customs, philosophy, prompts) is identical across all tiers —
|
|
315
|
-
* the differentiators are scale (services / agent packages) and tooling access (LLM scan).
|
|
97
|
+
* Check whether the workspace config exceeds the tier's scale limits.
|
|
98
|
+
* **Advisory only** — the server is the enforcement authority (402). Surface as a
|
|
99
|
+
* warning + upgrade hint and proceed; never hard-block on this result.
|
|
316
100
|
*/
|
|
317
101
|
export function enforceTierLimits(config, tier) {
|
|
318
102
|
const limits = TIER_LIMITS[tier];
|
|
319
103
|
const violations = [];
|
|
320
|
-
// Service count
|
|
321
104
|
if (config.services.length > limits.max_services) {
|
|
322
105
|
violations.push({
|
|
323
106
|
feature: 'services',
|
|
@@ -326,7 +109,6 @@ export function enforceTierLimits(config, tier) {
|
|
|
326
109
|
required_tier: tier === 'free' ? 'team' : 'enterprise',
|
|
327
110
|
});
|
|
328
111
|
}
|
|
329
|
-
// Agent count
|
|
330
112
|
if (config.agents) {
|
|
331
113
|
const enabledAgents = Object.values(config.agents).filter((a) => a.enabled).length;
|
|
332
114
|
if (enabledAgents > limits.max_agents) {
|
|
@@ -341,10 +123,7 @@ export function enforceTierLimits(config, tier) {
|
|
|
341
123
|
return violations;
|
|
342
124
|
}
|
|
343
125
|
// ─── Dev mode bypass ────────────────────────────────────────
|
|
344
|
-
/**
|
|
345
|
-
* Check if the CLI is running in dev mode (for NEPOPSX agent developers).
|
|
346
|
-
* Set NEPOPSX_DEV=1 to bypass license checks.
|
|
347
|
-
*/
|
|
126
|
+
/** Set NEPOPSX_DEV=1 to bypass auth checks (for NEPOPSX agent developers). */
|
|
348
127
|
export function isDevMode() {
|
|
349
128
|
return process.env.NEPOPSX_DEV === '1';
|
|
350
129
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"license-manager.js","sourceRoot":"","sources":["../../src/licensing/license-manager.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"license-manager.js","sourceRoot":"","sources":["../../src/licensing/license-manager.ts"],"names":[],"mappings":"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"}
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
* Workspace-name resolution.
|
|
3
3
|
*
|
|
4
4
|
* The license file (`.nepopsx/license.json`) carries a `workspace` field that is
|
|
5
|
-
* written ONCE at `nepopsx login`
|
|
5
|
+
* written ONCE at `nepopsx login` time. At first run the
|
|
6
6
|
* workspace config doesn't exist yet, so it is stored as the literal `"unknown"`.
|
|
7
7
|
* `nepopsx up` later creates `.nepopsx/workspace.yaml` with the real name, but the
|
|
8
8
|
* license file is not rewritten — so any command that sends `license.workspace`
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
* Workspace-name resolution.
|
|
3
3
|
*
|
|
4
4
|
* The license file (`.nepopsx/license.json`) carries a `workspace` field that is
|
|
5
|
-
* written ONCE at `nepopsx login`
|
|
5
|
+
* written ONCE at `nepopsx login` time. At first run the
|
|
6
6
|
* workspace config doesn't exist yet, so it is stored as the literal `"unknown"`.
|
|
7
7
|
* `nepopsx up` later creates `.nepopsx/workspace.yaml` with the real name, but the
|
|
8
8
|
* license file is not rewritten — so any command that sends `license.workspace`
|
|
@@ -4,12 +4,12 @@
|
|
|
4
4
|
* `learning_search` / `learning_store` for governed team recall.
|
|
5
5
|
*
|
|
6
6
|
* Claude Code's remote HTTP MCP form is `{ type: "http", url, headers }`, and it
|
|
7
|
-
* expands `${VAR}` in the config — so we embed the
|
|
8
|
-
* placeholder (`${
|
|
9
|
-
* committed `.mcp.json` shareable across the team without leaking the
|
|
7
|
+
* expands `${VAR}` in the config — so we embed the device token as an env
|
|
8
|
+
* placeholder (`${NEPOPSX_DEVICE_TOKEN}`) rather than the raw secret, keeping the
|
|
9
|
+
* committed `.mcp.json` shareable across the team without leaking the token.
|
|
10
10
|
*/
|
|
11
11
|
export declare const MEMORY_SERVER_NAME = "nepopsx-memory";
|
|
12
|
-
export declare const LICENSE_ENV_VAR = "
|
|
12
|
+
export declare const LICENSE_ENV_VAR = "NEPOPSX_DEVICE_TOKEN";
|
|
13
13
|
export interface McpHttpServer {
|
|
14
14
|
type: 'http';
|
|
15
15
|
url: string;
|
|
@@ -23,9 +23,9 @@ export interface McpSetupOptions {
|
|
|
23
23
|
rootDir: string;
|
|
24
24
|
/** Backend API base, including `/v1` (e.g. http://localhost:3100/v1). */
|
|
25
25
|
apiUrl: string;
|
|
26
|
-
/** Raw
|
|
26
|
+
/** Raw device token — only embedded when `inlineKey` is true (dev convenience). */
|
|
27
27
|
licenseKey?: string;
|
|
28
|
-
/** Embed the raw
|
|
28
|
+
/** Embed the raw token instead of the `${NEPOPSX_DEVICE_TOKEN}` placeholder. */
|
|
29
29
|
inlineKey?: boolean;
|
|
30
30
|
}
|
|
31
31
|
/** Build the `nepopsx-memory` HTTP server entry for `.mcp.json`. */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"config-generator.d.ts","sourceRoot":"","sources":["../../src/mcp/config-generator.ts"],"names":[],"mappings":"AAGA;;;;;;;;;GASG;AAEH,eAAO,MAAM,kBAAkB,mBAAmB,CAAC;AACnD,eAAO,MAAM,eAAe,
|
|
1
|
+
{"version":3,"file":"config-generator.d.ts","sourceRoot":"","sources":["../../src/mcp/config-generator.ts"],"names":[],"mappings":"AAGA;;;;;;;;;GASG;AAEH,eAAO,MAAM,kBAAkB,mBAAmB,CAAC;AACnD,eAAO,MAAM,eAAe,yBAAyB,CAAC;AAEtD,MAAM,WAAW,aAAa;IAC5B,IAAI,EAAE,MAAM,CAAC;IACb,GAAG,EAAE,MAAM,CAAC;IACZ,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CACjC;AAED,MAAM,WAAW,aAAa;IAC5B,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,aAAa,CAAC,CAAC;IAC1C,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;CACxB;AAED,MAAM,WAAW,eAAe;IAC9B,OAAO,EAAE,MAAM,CAAC;IAChB,yEAAyE;IACzE,MAAM,EAAE,MAAM,CAAC;IACf,mFAAmF;IACnF,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,gFAAgF;IAChF,SAAS,CAAC,EAAE,OAAO,CAAC;CACrB;AAED,oEAAoE;AACpE,wBAAgB,sBAAsB,CACpC,MAAM,EAAE,MAAM,EACd,IAAI,GAAE;IAAE,UAAU,CAAC,EAAE,MAAM,CAAC;IAAC,SAAS,CAAC,EAAE,OAAO,CAAA;CAAO,GACtD,aAAa,CAWf;AAED;;;;GAIG;AACH,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,eAAe,GAAG,MAAM,EAAE,CA4BpE"}
|
|
@@ -6,12 +6,12 @@ import { join } from 'node:path';
|
|
|
6
6
|
* `learning_search` / `learning_store` for governed team recall.
|
|
7
7
|
*
|
|
8
8
|
* Claude Code's remote HTTP MCP form is `{ type: "http", url, headers }`, and it
|
|
9
|
-
* expands `${VAR}` in the config — so we embed the
|
|
10
|
-
* placeholder (`${
|
|
11
|
-
* committed `.mcp.json` shareable across the team without leaking the
|
|
9
|
+
* expands `${VAR}` in the config — so we embed the device token as an env
|
|
10
|
+
* placeholder (`${NEPOPSX_DEVICE_TOKEN}`) rather than the raw secret, keeping the
|
|
11
|
+
* committed `.mcp.json` shareable across the team without leaking the token.
|
|
12
12
|
*/
|
|
13
13
|
export const MEMORY_SERVER_NAME = 'nepopsx-memory';
|
|
14
|
-
export const LICENSE_ENV_VAR = '
|
|
14
|
+
export const LICENSE_ENV_VAR = 'NEPOPSX_DEVICE_TOKEN';
|
|
15
15
|
/** Build the `nepopsx-memory` HTTP server entry for `.mcp.json`. */
|
|
16
16
|
export function buildMemoryServerEntry(apiUrl, opts = {}) {
|
|
17
17
|
const base = apiUrl.replace(/\/+$/, '');
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"config-generator.js","sourceRoot":"","sources":["../../src/mcp/config-generator.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AAClE,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAEjC;;;;;;;;;GASG;AAEH,MAAM,CAAC,MAAM,kBAAkB,GAAG,gBAAgB,CAAC;AACnD,MAAM,CAAC,MAAM,eAAe,GAAG,
|
|
1
|
+
{"version":3,"file":"config-generator.js","sourceRoot":"","sources":["../../src/mcp/config-generator.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AAClE,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAEjC;;;;;;;;;GASG;AAEH,MAAM,CAAC,MAAM,kBAAkB,GAAG,gBAAgB,CAAC;AACnD,MAAM,CAAC,MAAM,eAAe,GAAG,sBAAsB,CAAC;AAuBtD,oEAAoE;AACpE,MAAM,UAAU,sBAAsB,CACpC,MAAc,EACd,OAAqD,EAAE;IAEvD,MAAM,IAAI,GAAG,MAAM,CAAC,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC;IACxC,MAAM,KAAK,GACT,IAAI,CAAC,SAAS,IAAI,IAAI,CAAC,UAAU;QAC/B,CAAC,CAAC,IAAI,CAAC,UAAU;QACjB,CAAC,CAAC,IAAI,GAAG,eAAe,GAAG,GAAG,CAAC;IACnC,OAAO;QACL,IAAI,EAAE,MAAM;QACZ,GAAG,EAAE,GAAG,IAAI,MAAM;QAClB,OAAO,EAAE,EAAE,aAAa,EAAE,UAAU,KAAK,EAAE,EAAE;KAC9C,CAAC;AACJ,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,iBAAiB,CAAC,OAAwB;IACxD,MAAM,UAAU,GAAG,IAAI,CAAC,OAAO,CAAC,OAAO,EAAE,WAAW,CAAC,CAAC;IAEtD,IAAI,QAAQ,GAAkB,EAAE,UAAU,EAAE,EAAE,EAAE,CAAC;IACjD,IAAI,UAAU,CAAC,UAAU,CAAC,EAAE,CAAC;QAC3B,IAAI,CAAC;YACH,MAAM,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,UAAU,EAAE,OAAO,CAAC,CAAY,CAAC;YACrE,IAAI,GAAG,IAAI,OAAO,GAAG,KAAK,QAAQ,EAAE,CAAC;gBACnC,MAAM,GAAG,GAAG,GAA8B,CAAC;gBAC3C,MAAM,OAAO,GACX,GAAG,CAAC,UAAU,IAAI,OAAO,GAAG,CAAC,UAAU,KAAK,QAAQ;oBAClD,CAAC,CAAE,GAAG,CAAC,UAA4C;oBACnD,CAAC,CAAC,EAAE,CAAC;gBACT,QAAQ,GAAG,EAAE,GAAG,GAAG,EAAE,UAAU,EAAE,EAAE,GAAG,OAAO,EAAE,EAAE,CAAC;YACpD,CAAC;QACH,CAAC;QAAC,MAAM,CAAC;YACP,mEAAmE;YACnE,QAAQ,GAAG,EAAE,UAAU,EAAE,EAAE,EAAE,CAAC;QAChC,CAAC;IACH,CAAC;IAED,QAAQ,CAAC,UAAU,CAAC,kBAAkB,CAAC,GAAG,sBAAsB,CAC9D,OAAO,CAAC,MAAM,EACd,EAAE,UAAU,EAAE,OAAO,CAAC,UAAU,EAAE,SAAS,EAAE,OAAO,CAAC,SAAS,EAAE,CACjE,CAAC;IAEF,aAAa,CAAC,UAAU,EAAE,IAAI,CAAC,SAAS,CAAC,QAAQ,EAAE,IAAI,EAAE,CAAC,CAAC,GAAG,IAAI,EAAE,OAAO,CAAC,CAAC;IAC7E,OAAO,CAAC,WAAW,CAAC,CAAC;AACvB,CAAC"}
|