@devness/useai-cli 0.8.8 → 0.8.10

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/dist/index.js +130 -32
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -30,7 +30,7 @@ var SYSTEMD_SERVICE_PATH = join(homedir(), ".config", "systemd", "user", "useai-
30
30
  var WINDOWS_STARTUP_SCRIPT_PATH = join(process.env["APPDATA"] ?? join(homedir(), "AppData", "Roaming"), "Microsoft", "Windows", "Start Menu", "Programs", "Startup", "useai-daemon.vbs");
31
31
 
32
32
  // ../shared/dist/constants/version.js
33
- var VERSION = "0.8.8";
33
+ var VERSION = "0.8.10";
34
34
 
35
35
  // ../shared/dist/constants/defaults.js
36
36
  var DEFAULT_CAPTURE_CONFIG = {
@@ -41,7 +41,7 @@ var DEFAULT_CAPTURE_CONFIG = {
41
41
  milestones: true
42
42
  };
43
43
  var DEFAULT_SYNC_CONFIG = {
44
- enabled: true,
44
+ enabled: false,
45
45
  interval_hours: 1
46
46
  };
47
47
  var DEFAULT_CONFIG = {
@@ -234,6 +234,9 @@ function migrateConfig(raw) {
234
234
  };
235
235
  }
236
236
  delete config.sync.include;
237
+ if (config.sync.enabled && !config.auth?.token) {
238
+ config.sync.enabled = false;
239
+ }
237
240
  if (!config.evaluation_framework) {
238
241
  config.evaluation_framework = "space";
239
242
  }
@@ -360,6 +363,11 @@ import { Command as Command2 } from "commander";
360
363
  import { existsSync as existsSync2, statSync, readdirSync } from "fs";
361
364
  import pc3 from "picocolors";
362
365
 
366
+ // ../shared/dist/types/config.js
367
+ function getUserMode(config) {
368
+ return config.auth?.token ? "cloud" : "local";
369
+ }
370
+
363
371
  // src/services/config.service.ts
364
372
  function getConfig() {
365
373
  const raw = readJson(CONFIG_FILE, {});
@@ -418,15 +426,17 @@ var statusCommand = new Command2("status").description("Full transparency dashbo
418
426
  ])
419
427
  );
420
428
  console.log(header("Settings"));
429
+ const mode = getUserMode(config);
430
+ const modeDisplay = mode === "cloud" ? pc3.green("Cloud") + pc3.dim(` \xB7 @${config.auth.user.username ?? config.auth.user.email}`) : pc3.cyan("Local");
421
431
  console.log(
422
432
  table([
433
+ ["Mode", modeDisplay],
423
434
  ["Milestone tracking", config.capture.milestones ? pc3.green("on") : pc3.red("off")],
424
435
  ["Prompt capture", config.capture.prompt ? pc3.green("on") : pc3.red("off")],
425
436
  ["Eval reasons", config.capture.evaluation_reasons],
426
437
  ["Cloud sync", config.sync.enabled ? pc3.green("on") : pc3.red("off")],
427
438
  ["Sync interval", `${config.sync.interval_hours}h`],
428
- ["Last sync", config.last_sync_at ?? pc3.dim("never")],
429
- ["Logged in", config.auth ? pc3.green(config.auth.user.email) : pc3.dim("no")]
439
+ ["Last sync", config.last_sync_at ?? pc3.dim("never")]
430
440
  ])
431
441
  );
432
442
  console.log(header("Privacy"));
@@ -6245,17 +6255,19 @@ var configCommand = new Command4("config").description("View or update settings"
6245
6255
  }
6246
6256
  const config = getConfig();
6247
6257
  if (!changed) {
6258
+ const mode = getUserMode(config);
6259
+ const modeDisplay = mode === "cloud" ? pc5.green("Cloud") + pc5.dim(` \xB7 @${config.auth.user.username ?? config.auth.user.email}`) : pc5.cyan("Local");
6248
6260
  console.log(header("Current Settings"));
6249
6261
  console.log(
6250
6262
  table([
6263
+ ["Mode", modeDisplay],
6251
6264
  ["Milestone tracking", config.capture.milestones ? pc5.green("on") : pc5.red("off")],
6252
6265
  ["Prompt capture", config.capture.prompt ? pc5.green("on") : pc5.red("off")],
6253
6266
  ["Eval reasons", config.capture.evaluation_reasons],
6254
6267
  ["Cloud sync", config.sync.enabled ? pc5.green("on") : pc5.red("off")],
6255
6268
  ["Eval framework", pc5.cyan(config.evaluation_framework ?? "space")],
6256
6269
  ["Sync interval", `${config.sync.interval_hours}h`],
6257
- ["Last sync", config.last_sync_at ?? pc5.dim("never")],
6258
- ["Logged in", config.auth ? pc5.green(config.auth.user.email) : pc5.dim("no")]
6270
+ ["Last sync", config.last_sync_at ?? pc5.dim("never")]
6259
6271
  ])
6260
6272
  );
6261
6273
  console.log("");
@@ -6820,11 +6832,80 @@ async function apiCall(endpoint, body) {
6820
6832
  }
6821
6833
  return data;
6822
6834
  }
6823
- var loginCommand = new Command10("login").description("Login to useai.dev").action(async () => {
6835
+ async function apiGet(endpoint, token) {
6836
+ const res = await fetch(`${API_URL}${endpoint}`, {
6837
+ headers: { Authorization: `Bearer ${token}` }
6838
+ });
6839
+ const data = await res.json();
6840
+ if (!res.ok) {
6841
+ throw new Error(data.message ?? `Request failed (${res.status})`);
6842
+ }
6843
+ return data;
6844
+ }
6845
+ async function apiPatch(endpoint, token, body) {
6846
+ const res = await fetch(`${API_URL}${endpoint}`, {
6847
+ method: "PATCH",
6848
+ headers: {
6849
+ "Content-Type": "application/json",
6850
+ Authorization: `Bearer ${token}`
6851
+ },
6852
+ body: JSON.stringify(body)
6853
+ });
6854
+ const data = await res.json();
6855
+ if (!res.ok) {
6856
+ throw new Error(data.message ?? `Request failed (${res.status})`);
6857
+ }
6858
+ return data;
6859
+ }
6860
+ function validateUsernameFormat(username) {
6861
+ if (username.length < 3) return "Username must be at least 3 characters";
6862
+ if (username.length > 20) return "Username must be at most 20 characters";
6863
+ if (!/^[a-z0-9][a-z0-9-]*[a-z0-9]$/.test(username) && username.length >= 3) {
6864
+ return "Only lowercase letters, numbers, and hyphens (not at start/end)";
6865
+ }
6866
+ if (/--/.test(username)) return "No consecutive hyphens";
6867
+ return void 0;
6868
+ }
6869
+ async function claimUsername(token) {
6870
+ while (true) {
6871
+ const usernameResult = await p2.text({
6872
+ message: "Choose a username:",
6873
+ placeholder: "e.g. fastdev",
6874
+ validate: (v) => {
6875
+ if (!v) return "Username is required";
6876
+ return validateUsernameFormat(v);
6877
+ }
6878
+ });
6879
+ if (p2.isCancel(usernameResult)) {
6880
+ return void 0;
6881
+ }
6882
+ const username = usernameResult.toLowerCase();
6883
+ try {
6884
+ const check = await apiGet(`/api/users/check-username/${encodeURIComponent(username)}`, token);
6885
+ if (!check.available) {
6886
+ console.log(pc9.yellow(` "${username}" is not available${check.reason ? `: ${check.reason}` : ""}. Try another.`));
6887
+ continue;
6888
+ }
6889
+ } catch {
6890
+ console.log(pc9.yellow(" Could not verify availability. Try again."));
6891
+ continue;
6892
+ }
6893
+ try {
6894
+ await apiPatch("/api/users/me", token, { username });
6895
+ return username;
6896
+ } catch (err) {
6897
+ console.log(pc9.yellow(` Could not claim "${username}": ${err.message}. Try another.`));
6898
+ continue;
6899
+ }
6900
+ }
6901
+ }
6902
+ var loginCommand = new Command10("login").description("Login to useai.dev and enable Cloud Mode").action(async () => {
6824
6903
  try {
6825
6904
  const config = getConfig();
6826
6905
  if (config.auth?.token) {
6827
- console.log(pc9.dim(` Already logged in as ${pc9.bold(config.auth.user.email)}`));
6906
+ const mode = pc9.green("Cloud Mode");
6907
+ const user = config.auth.user.username ? `@${config.auth.user.username}` : config.auth.user.email;
6908
+ console.log(pc9.dim(` Already logged in as ${pc9.bold(user)} (${mode})`));
6828
6909
  console.log(pc9.dim(" Run `useai logout` to switch accounts."));
6829
6910
  return;
6830
6911
  }
@@ -6851,8 +6932,8 @@ var loginCommand = new Command10("login").description("Login to useai.dev").acti
6851
6932
  console.log("");
6852
6933
  let attempts = 0;
6853
6934
  const maxAttempts = 3;
6854
- let success2 = false;
6855
- while (attempts < maxAttempts && !success2) {
6935
+ let verifyResult = null;
6936
+ while (attempts < maxAttempts && !verifyResult) {
6856
6937
  const codeResult = await p2.text({
6857
6938
  message: 'Enter 6-digit code (or "resend"):',
6858
6939
  validate: (v) => {
@@ -6884,24 +6965,7 @@ var loginCommand = new Command10("login").description("Login to useai.dev").acti
6884
6965
  try {
6885
6966
  const result = await apiCall("/api/auth/verify-otp", { email, code });
6886
6967
  if (result?.token) {
6887
- updateConfig({
6888
- auth: {
6889
- token: result.token,
6890
- user: {
6891
- id: result.user.id,
6892
- email: result.user.email,
6893
- username: result.user.username
6894
- }
6895
- }
6896
- });
6897
- console.log("");
6898
- console.log(pc9.green(` \u2713 Logged in as ${pc9.bold(result.user.email)}`));
6899
- if (result.user.username) {
6900
- console.log(pc9.dim(` username: ${result.user.username}`));
6901
- }
6902
- console.log("");
6903
- console.log(pc9.dim(" Your sessions and milestones will sync to useai.dev"));
6904
- success2 = true;
6968
+ verifyResult = result;
6905
6969
  }
6906
6970
  } catch (err) {
6907
6971
  attempts++;
@@ -6928,9 +6992,39 @@ var loginCommand = new Command10("login").description("Login to useai.dev").acti
6928
6992
  }
6929
6993
  }
6930
6994
  }
6931
- if (!success2) {
6995
+ if (!verifyResult) {
6932
6996
  console.log(pc9.red(" Login failed. Please try again."));
6997
+ return;
6933
6998
  }
6999
+ let username = verifyResult.user.username;
7000
+ if (!username) {
7001
+ console.log("");
7002
+ console.log(pc9.green(` \u2713 Authenticated as ${pc9.bold(email)}`));
7003
+ console.log("");
7004
+ username = await claimUsername(verifyResult.token);
7005
+ if (!username) {
7006
+ console.log(pc9.dim("\n Login cancelled \u2014 username is required for Cloud Mode."));
7007
+ return;
7008
+ }
7009
+ console.log(pc9.green(` \u2713 Username claimed: @${username}`));
7010
+ }
7011
+ updateConfig({
7012
+ auth: {
7013
+ token: verifyResult.token,
7014
+ user: {
7015
+ id: verifyResult.user.id,
7016
+ email: verifyResult.user.email,
7017
+ username
7018
+ }
7019
+ },
7020
+ sync: { enabled: true, interval_hours: config.sync.interval_hours }
7021
+ });
7022
+ console.log("");
7023
+ console.log(pc9.green(` \u2713 Cloud Mode enabled`));
7024
+ console.log(pc9.dim(` Logged in as ${pc9.bold(`@${username}`)} (${email})`));
7025
+ console.log(pc9.dim(` Sessions sync hourly \u2014 prompts stay local`));
7026
+ console.log(pc9.dim(` Profile: useai.dev/@${username}`));
7027
+ console.log("");
6934
7028
  } catch (err) {
6935
7029
  if (err.name === "ExitPromptError" || err.message?.includes("force closed")) {
6936
7030
  console.log("");
@@ -6940,15 +7034,19 @@ var loginCommand = new Command10("login").description("Login to useai.dev").acti
6940
7034
  console.log(pc9.red(` Login failed: ${err.message}`));
6941
7035
  }
6942
7036
  });
6943
- var logoutCommand = new Command10("logout").description("Logout from useai.dev").action(() => {
7037
+ var logoutCommand = new Command10("logout").description("Logout and return to Local Mode").action(() => {
6944
7038
  const config = getConfig();
6945
7039
  if (!config.auth) {
6946
- console.log(pc9.dim(" Not logged in."));
7040
+ console.log(pc9.dim(" Not logged in \u2014 already in Local Mode."));
6947
7041
  return;
6948
7042
  }
6949
7043
  const email = config.auth.user.email;
6950
- updateConfig({ auth: void 0 });
7044
+ updateConfig({
7045
+ auth: void 0,
7046
+ sync: { enabled: false, interval_hours: config.sync.interval_hours }
7047
+ });
6951
7048
  console.log(pc9.green(` \u2713 Logged out from ${email}`));
7049
+ console.log(pc9.dim(" Local Mode \u2014 your data stays on this device."));
6952
7050
  });
6953
7051
 
6954
7052
  // src/commands/update.ts
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@devness/useai-cli",
3
- "version": "0.8.8",
3
+ "version": "0.8.10",
4
4
  "description": "CLI tool for useai.dev — stats, sync, publish your AI development workflow",
5
5
  "author": "nabeelkausari",
6
6
  "license": "AGPL-3.0-only",