@kodus/cli 0.1.10 → 0.1.12

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 (81) hide show
  1. package/dist/commands/__tests__/auth.login-logout.test.d.ts +2 -0
  2. package/dist/commands/__tests__/auth.login-logout.test.d.ts.map +1 -0
  3. package/dist/commands/__tests__/auth.login-logout.test.js +125 -0
  4. package/dist/commands/__tests__/auth.login-logout.test.js.map +1 -0
  5. package/dist/commands/__tests__/auth.team-key.test.d.ts +2 -0
  6. package/dist/commands/__tests__/auth.team-key.test.d.ts.map +1 -0
  7. package/dist/commands/__tests__/auth.team-key.test.js +129 -0
  8. package/dist/commands/__tests__/auth.team-key.test.js.map +1 -0
  9. package/dist/commands/__tests__/hook.test.js +1 -1
  10. package/dist/commands/__tests__/hook.test.js.map +1 -1
  11. package/dist/commands/auth/index.js +1 -1
  12. package/dist/commands/auth/index.js.map +1 -1
  13. package/dist/commands/auth/login.d.ts.map +1 -1
  14. package/dist/commands/auth/login.js +5 -2
  15. package/dist/commands/auth/login.js.map +1 -1
  16. package/dist/commands/auth/logout.js +1 -1
  17. package/dist/commands/auth/logout.js.map +1 -1
  18. package/dist/commands/auth/team-key.d.ts.map +1 -1
  19. package/dist/commands/auth/team-key.js +37 -4
  20. package/dist/commands/auth/team-key.js.map +1 -1
  21. package/dist/commands/hook/index.d.ts.map +1 -1
  22. package/dist/commands/hook/index.js +5 -5
  23. package/dist/commands/hook/index.js.map +1 -1
  24. package/dist/commands/hook/install.d.ts.map +1 -1
  25. package/dist/commands/hook/install.js +35 -8
  26. package/dist/commands/hook/install.js.map +1 -1
  27. package/dist/commands/hook/status.js +4 -4
  28. package/dist/commands/hook/status.js.map +1 -1
  29. package/dist/commands/hook/uninstall.js +4 -4
  30. package/dist/commands/hook/uninstall.js.map +1 -1
  31. package/dist/services/__tests__/auth.service.test.js +36 -2
  32. package/dist/services/__tests__/auth.service.test.js.map +1 -1
  33. package/dist/services/__tests__/review.service.auth-fallback.test.d.ts +2 -0
  34. package/dist/services/__tests__/review.service.auth-fallback.test.d.ts.map +1 -0
  35. package/dist/services/__tests__/review.service.auth-fallback.test.js +63 -0
  36. package/dist/services/__tests__/review.service.auth-fallback.test.js.map +1 -0
  37. package/dist/services/__tests__/review.suggestions-auth.test.d.ts +2 -0
  38. package/dist/services/__tests__/review.suggestions-auth.test.d.ts.map +1 -0
  39. package/dist/services/__tests__/review.suggestions-auth.test.js +81 -0
  40. package/dist/services/__tests__/review.suggestions-auth.test.js.map +1 -0
  41. package/dist/services/api/__tests__/api.real.test.d.ts +2 -0
  42. package/dist/services/api/__tests__/api.real.test.d.ts.map +1 -0
  43. package/dist/services/api/__tests__/api.real.test.js +171 -0
  44. package/dist/services/api/__tests__/api.real.test.js.map +1 -0
  45. package/dist/services/api/api.real.d.ts.map +1 -1
  46. package/dist/services/api/api.real.js +94 -9
  47. package/dist/services/api/api.real.js.map +1 -1
  48. package/dist/services/auth.service.d.ts +2 -0
  49. package/dist/services/auth.service.d.ts.map +1 -1
  50. package/dist/services/auth.service.js +45 -20
  51. package/dist/services/auth.service.js.map +1 -1
  52. package/dist/services/git.service.d.ts.map +1 -1
  53. package/dist/services/git.service.js +18 -15
  54. package/dist/services/git.service.js.map +1 -1
  55. package/dist/services/review.service.d.ts +1 -0
  56. package/dist/services/review.service.d.ts.map +1 -1
  57. package/dist/services/review.service.js +54 -2
  58. package/dist/services/review.service.js.map +1 -1
  59. package/dist/utils/__tests__/config.test.d.ts +2 -0
  60. package/dist/utils/__tests__/config.test.d.ts.map +1 -0
  61. package/dist/utils/__tests__/config.test.js +79 -0
  62. package/dist/utils/__tests__/config.test.js.map +1 -0
  63. package/dist/utils/__tests__/credentials.test.d.ts +2 -0
  64. package/dist/utils/__tests__/credentials.test.d.ts.map +1 -0
  65. package/dist/utils/__tests__/credentials.test.js +89 -0
  66. package/dist/utils/__tests__/credentials.test.js.map +1 -0
  67. package/dist/utils/__tests__/device.test.d.ts +2 -0
  68. package/dist/utils/__tests__/device.test.d.ts.map +1 -0
  69. package/dist/utils/__tests__/device.test.js +108 -0
  70. package/dist/utils/__tests__/device.test.js.map +1 -0
  71. package/dist/utils/config.d.ts.map +1 -1
  72. package/dist/utils/config.js +15 -5
  73. package/dist/utils/config.js.map +1 -1
  74. package/dist/utils/credentials.d.ts.map +1 -1
  75. package/dist/utils/credentials.js +15 -5
  76. package/dist/utils/credentials.js.map +1 -1
  77. package/dist/utils/device.d.ts +7 -0
  78. package/dist/utils/device.d.ts.map +1 -0
  79. package/dist/utils/device.js +118 -0
  80. package/dist/utils/device.js.map +1 -0
  81. package/package.json +1 -1
@@ -3,6 +3,9 @@ import path from 'path';
3
3
  import os from 'os';
4
4
  const CONFIG_DIR = path.join(os.homedir(), '.kodus');
5
5
  const CONFIG_FILE = path.join(CONFIG_DIR, 'config.json');
6
+ function isJsonParseError(error) {
7
+ return error instanceof SyntaxError;
8
+ }
6
9
  async function ensureConfigDir() {
7
10
  try {
8
11
  await fs.mkdir(CONFIG_DIR, { recursive: true, mode: 0o700 });
@@ -15,10 +18,10 @@ async function ensureConfigDir() {
15
18
  }
16
19
  export async function saveConfig(config) {
17
20
  await ensureConfigDir();
18
- await fs.writeFile(CONFIG_FILE, JSON.stringify(config, null, 2), {
19
- encoding: 'utf-8',
20
- mode: 0o600,
21
- });
21
+ const tmpFile = `${CONFIG_FILE}.${process.pid}.${Date.now()}.tmp`;
22
+ const content = JSON.stringify(config, null, 2);
23
+ await fs.writeFile(tmpFile, content, { encoding: 'utf-8', mode: 0o600 });
24
+ await fs.rename(tmpFile, CONFIG_FILE);
22
25
  }
23
26
  export async function loadConfig() {
24
27
  try {
@@ -26,7 +29,14 @@ export async function loadConfig() {
26
29
  return JSON.parse(content);
27
30
  }
28
31
  catch (error) {
29
- if (error.code === 'ENOENT') {
32
+ const code = error.code;
33
+ if (code === 'ENOENT') {
34
+ return null;
35
+ }
36
+ // Self-heal malformed JSON by isolating the broken file and treating as no config.
37
+ if (isJsonParseError(error)) {
38
+ const brokenFile = `${CONFIG_FILE}.corrupted.${Date.now()}`;
39
+ await fs.rename(CONFIG_FILE, brokenFile).catch(() => { });
30
40
  return null;
31
41
  }
32
42
  throw error;
@@ -1 +1 @@
1
- {"version":3,"file":"config.js","sourceRoot":"","sources":["../../src/utils/config.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,aAAa,CAAC;AAC7B,OAAO,IAAI,MAAM,MAAM,CAAC;AACxB,OAAO,EAAE,MAAM,IAAI,CAAC;AAEpB,MAAM,UAAU,GAAG,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,OAAO,EAAE,EAAE,QAAQ,CAAC,CAAC;AACrD,MAAM,WAAW,GAAG,IAAI,CAAC,IAAI,CAAC,UAAU,EAAE,aAAa,CAAC,CAAC;AAQzD,KAAK,UAAU,eAAe;IAC5B,IAAI,CAAC;QACH,MAAM,EAAE,CAAC,KAAK,CAAC,UAAU,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC;IAC/D,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,IAAK,KAA+B,CAAC,IAAI,KAAK,QAAQ,EAAE,CAAC;YACvD,MAAM,KAAK,CAAC;QACd,CAAC;IACH,CAAC;AACH,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,UAAU,CAAC,MAAiB;IAChD,MAAM,eAAe,EAAE,CAAC;IACxB,MAAM,EAAE,CAAC,SAAS,CAAC,WAAW,EAAE,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE;QAC/D,QAAQ,EAAE,OAAO;QACjB,IAAI,EAAE,KAAK;KACZ,CAAC,CAAC;AACL,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,UAAU;IAC9B,IAAI,CAAC;QACH,MAAM,OAAO,GAAG,MAAM,EAAE,CAAC,QAAQ,CAAC,WAAW,EAAE,OAAO,CAAC,CAAC;QACxD,OAAO,IAAI,CAAC,KAAK,CAAC,OAAO,CAAc,CAAC;IAC1C,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,IAAK,KAA+B,CAAC,IAAI,KAAK,QAAQ,EAAE,CAAC;YACvD,OAAO,IAAI,CAAC;QACd,CAAC;QACD,MAAM,KAAK,CAAC;IACd,CAAC;AACH,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,WAAW;IAC/B,IAAI,CAAC;QACH,MAAM,EAAE,CAAC,MAAM,CAAC,WAAW,CAAC,CAAC;IAC/B,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,IAAK,KAA+B,CAAC,IAAI,KAAK,QAAQ,EAAE,CAAC;YACvD,MAAM,KAAK,CAAC;QACd,CAAC;IACH,CAAC;AACH,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,YAAY;IAChC,IAAI,CAAC;QACH,MAAM,EAAE,CAAC,MAAM,CAAC,WAAW,CAAC,CAAC;QAC7B,OAAO,IAAI,CAAC;IACd,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,KAAK,CAAC;IACf,CAAC;AACH,CAAC"}
1
+ {"version":3,"file":"config.js","sourceRoot":"","sources":["../../src/utils/config.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,aAAa,CAAC;AAC7B,OAAO,IAAI,MAAM,MAAM,CAAC;AACxB,OAAO,EAAE,MAAM,IAAI,CAAC;AAEpB,MAAM,UAAU,GAAG,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,OAAO,EAAE,EAAE,QAAQ,CAAC,CAAC;AACrD,MAAM,WAAW,GAAG,IAAI,CAAC,IAAI,CAAC,UAAU,EAAE,aAAa,CAAC,CAAC;AAQzD,SAAS,gBAAgB,CAAC,KAAc;IACtC,OAAO,KAAK,YAAY,WAAW,CAAC;AACtC,CAAC;AAED,KAAK,UAAU,eAAe;IAC5B,IAAI,CAAC;QACH,MAAM,EAAE,CAAC,KAAK,CAAC,UAAU,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC;IAC/D,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,IAAK,KAA+B,CAAC,IAAI,KAAK,QAAQ,EAAE,CAAC;YACvD,MAAM,KAAK,CAAC;QACd,CAAC;IACH,CAAC;AACH,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,UAAU,CAAC,MAAiB;IAChD,MAAM,eAAe,EAAE,CAAC;IACxB,MAAM,OAAO,GAAG,GAAG,WAAW,IAAI,OAAO,CAAC,GAAG,IAAI,IAAI,CAAC,GAAG,EAAE,MAAM,CAAC;IAClE,MAAM,OAAO,GAAG,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC;IAEhD,MAAM,EAAE,CAAC,SAAS,CAAC,OAAO,EAAE,OAAO,EAAE,EAAE,QAAQ,EAAE,OAAO,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC;IACzE,MAAM,EAAE,CAAC,MAAM,CAAC,OAAO,EAAE,WAAW,CAAC,CAAC;AACxC,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,UAAU;IAC9B,IAAI,CAAC;QACH,MAAM,OAAO,GAAG,MAAM,EAAE,CAAC,QAAQ,CAAC,WAAW,EAAE,OAAO,CAAC,CAAC;QACxD,OAAO,IAAI,CAAC,KAAK,CAAC,OAAO,CAAc,CAAC;IAC1C,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,MAAM,IAAI,GAAI,KAA+B,CAAC,IAAI,CAAC;QACnD,IAAI,IAAI,KAAK,QAAQ,EAAE,CAAC;YACtB,OAAO,IAAI,CAAC;QACd,CAAC;QAED,mFAAmF;QACnF,IAAI,gBAAgB,CAAC,KAAK,CAAC,EAAE,CAAC;YAC5B,MAAM,UAAU,GAAG,GAAG,WAAW,cAAc,IAAI,CAAC,GAAG,EAAE,EAAE,CAAC;YAC5D,MAAM,EAAE,CAAC,MAAM,CAAC,WAAW,EAAE,UAAU,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE,GAAE,CAAC,CAAC,CAAC;YACzD,OAAO,IAAI,CAAC;QACd,CAAC;QAED,MAAM,KAAK,CAAC;IACd,CAAC;AACH,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,WAAW;IAC/B,IAAI,CAAC;QACH,MAAM,EAAE,CAAC,MAAM,CAAC,WAAW,CAAC,CAAC;IAC/B,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,IAAK,KAA+B,CAAC,IAAI,KAAK,QAAQ,EAAE,CAAC;YACvD,MAAM,KAAK,CAAC;QACd,CAAC;IACH,CAAC;AACH,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,YAAY;IAChC,IAAI,CAAC;QACH,MAAM,EAAE,CAAC,MAAM,CAAC,WAAW,CAAC,CAAC;QAC7B,OAAO,IAAI,CAAC;IACd,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,KAAK,CAAC;IACf,CAAC;AACH,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"credentials.d.ts","sourceRoot":"","sources":["../../src/utils/credentials.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,iBAAiB,EAAyB,MAAM,mBAAmB,CAAC;AAelF,wBAAsB,eAAe,IAAI,OAAO,CAAC,iBAAiB,GAAG,IAAI,CAAC,CAUzE;AAED,wBAAsB,eAAe,CAAC,WAAW,EAAE,iBAAiB,GAAG,OAAO,CAAC,IAAI,CAAC,CAMnF;AAED,wBAAsB,gBAAgB,IAAI,OAAO,CAAC,IAAI,CAAC,CAQtD;AAED,wBAAsB,gBAAgB,IAAI,OAAO,CAAC,OAAO,CAAC,CAOzD"}
1
+ {"version":3,"file":"credentials.d.ts","sourceRoot":"","sources":["../../src/utils/credentials.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,iBAAiB,EAAyB,MAAM,mBAAmB,CAAC;AAmBlF,wBAAsB,eAAe,IAAI,OAAO,CAAC,iBAAiB,GAAG,IAAI,CAAC,CAmBzE;AAED,wBAAsB,eAAe,CAAC,WAAW,EAAE,iBAAiB,GAAG,OAAO,CAAC,IAAI,CAAC,CAOnF;AAED,wBAAsB,gBAAgB,IAAI,OAAO,CAAC,IAAI,CAAC,CAQtD;AAED,wBAAsB,gBAAgB,IAAI,OAAO,CAAC,OAAO,CAAC,CAOzD"}
@@ -3,6 +3,9 @@ import path from 'path';
3
3
  import os from 'os';
4
4
  const KODUS_DIR = path.join(os.homedir(), '.kodus');
5
5
  const CREDENTIALS_FILE = path.join(KODUS_DIR, 'credentials.json');
6
+ function isJsonParseError(error) {
7
+ return error instanceof SyntaxError;
8
+ }
6
9
  async function ensureKodusDir() {
7
10
  try {
8
11
  await fs.mkdir(KODUS_DIR, { recursive: true, mode: 0o700 });
@@ -19,7 +22,14 @@ export async function loadCredentials() {
19
22
  return JSON.parse(content);
20
23
  }
21
24
  catch (error) {
22
- if (error.code === 'ENOENT') {
25
+ const code = error.code;
26
+ if (code === 'ENOENT') {
27
+ return null;
28
+ }
29
+ // Self-heal malformed JSON by isolating the broken file and treating as no credentials.
30
+ if (isJsonParseError(error)) {
31
+ const brokenFile = `${CREDENTIALS_FILE}.corrupted.${Date.now()}`;
32
+ await fs.rename(CREDENTIALS_FILE, brokenFile).catch(() => { });
23
33
  return null;
24
34
  }
25
35
  throw error;
@@ -27,10 +37,10 @@ export async function loadCredentials() {
27
37
  }
28
38
  export async function saveCredentials(credentials) {
29
39
  await ensureKodusDir();
30
- await fs.writeFile(CREDENTIALS_FILE, JSON.stringify(credentials, null, 2), {
31
- encoding: 'utf-8',
32
- mode: 0o600,
33
- });
40
+ const tmpFile = `${CREDENTIALS_FILE}.${process.pid}.${Date.now()}.tmp`;
41
+ const content = JSON.stringify(credentials, null, 2);
42
+ await fs.writeFile(tmpFile, content, { encoding: 'utf-8', mode: 0o600 });
43
+ await fs.rename(tmpFile, CREDENTIALS_FILE);
34
44
  }
35
45
  export async function clearCredentials() {
36
46
  try {
@@ -1 +1 @@
1
- {"version":3,"file":"credentials.js","sourceRoot":"","sources":["../../src/utils/credentials.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,aAAa,CAAC;AAC7B,OAAO,IAAI,MAAM,MAAM,CAAC;AACxB,OAAO,EAAE,MAAM,IAAI,CAAC;AAGpB,MAAM,SAAS,GAAG,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,OAAO,EAAE,EAAE,QAAQ,CAAC,CAAC;AACpD,MAAM,gBAAgB,GAAG,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,kBAAkB,CAAC,CAAC;AAElE,KAAK,UAAU,cAAc;IAC3B,IAAI,CAAC;QACH,MAAM,EAAE,CAAC,KAAK,CAAC,SAAS,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC;IAC9D,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,IAAK,KAA+B,CAAC,IAAI,KAAK,QAAQ,EAAE,CAAC;YACvD,MAAM,KAAK,CAAC;QACd,CAAC;IACH,CAAC;AACH,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,eAAe;IACnC,IAAI,CAAC;QACH,MAAM,OAAO,GAAG,MAAM,EAAE,CAAC,QAAQ,CAAC,gBAAgB,EAAE,OAAO,CAAC,CAAC;QAC7D,OAAO,IAAI,CAAC,KAAK,CAAC,OAAO,CAAsB,CAAC;IAClD,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,IAAK,KAA+B,CAAC,IAAI,KAAK,QAAQ,EAAE,CAAC;YACvD,OAAO,IAAI,CAAC;QACd,CAAC;QACD,MAAM,KAAK,CAAC;IACd,CAAC;AACH,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,eAAe,CAAC,WAA8B;IAClE,MAAM,cAAc,EAAE,CAAC;IACvB,MAAM,EAAE,CAAC,SAAS,CAAC,gBAAgB,EAAE,IAAI,CAAC,SAAS,CAAC,WAAW,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE;QACzE,QAAQ,EAAE,OAAO;QACjB,IAAI,EAAE,KAAK;KACZ,CAAC,CAAC;AACL,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,gBAAgB;IACpC,IAAI,CAAC;QACH,MAAM,EAAE,CAAC,MAAM,CAAC,gBAAgB,CAAC,CAAC;IACpC,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,IAAK,KAA+B,CAAC,IAAI,KAAK,QAAQ,EAAE,CAAC;YACvD,MAAM,KAAK,CAAC;QACd,CAAC;IACH,CAAC;AACH,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,gBAAgB;IACpC,IAAI,CAAC;QACH,MAAM,EAAE,CAAC,MAAM,CAAC,gBAAgB,CAAC,CAAC;QAClC,OAAO,IAAI,CAAC;IACd,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,KAAK,CAAC;IACf,CAAC;AACH,CAAC"}
1
+ {"version":3,"file":"credentials.js","sourceRoot":"","sources":["../../src/utils/credentials.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,aAAa,CAAC;AAC7B,OAAO,IAAI,MAAM,MAAM,CAAC;AACxB,OAAO,EAAE,MAAM,IAAI,CAAC;AAGpB,MAAM,SAAS,GAAG,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,OAAO,EAAE,EAAE,QAAQ,CAAC,CAAC;AACpD,MAAM,gBAAgB,GAAG,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,kBAAkB,CAAC,CAAC;AAElE,SAAS,gBAAgB,CAAC,KAAc;IACtC,OAAO,KAAK,YAAY,WAAW,CAAC;AACtC,CAAC;AAED,KAAK,UAAU,cAAc;IAC3B,IAAI,CAAC;QACH,MAAM,EAAE,CAAC,KAAK,CAAC,SAAS,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC;IAC9D,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,IAAK,KAA+B,CAAC,IAAI,KAAK,QAAQ,EAAE,CAAC;YACvD,MAAM,KAAK,CAAC;QACd,CAAC;IACH,CAAC;AACH,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,eAAe;IACnC,IAAI,CAAC;QACH,MAAM,OAAO,GAAG,MAAM,EAAE,CAAC,QAAQ,CAAC,gBAAgB,EAAE,OAAO,CAAC,CAAC;QAC7D,OAAO,IAAI,CAAC,KAAK,CAAC,OAAO,CAAsB,CAAC;IAClD,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,MAAM,IAAI,GAAI,KAA+B,CAAC,IAAI,CAAC;QACnD,IAAI,IAAI,KAAK,QAAQ,EAAE,CAAC;YACtB,OAAO,IAAI,CAAC;QACd,CAAC;QAED,wFAAwF;QACxF,IAAI,gBAAgB,CAAC,KAAK,CAAC,EAAE,CAAC;YAC5B,MAAM,UAAU,GAAG,GAAG,gBAAgB,cAAc,IAAI,CAAC,GAAG,EAAE,EAAE,CAAC;YACjE,MAAM,EAAE,CAAC,MAAM,CAAC,gBAAgB,EAAE,UAAU,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE,GAAE,CAAC,CAAC,CAAC;YAC9D,OAAO,IAAI,CAAC;QACd,CAAC;QAED,MAAM,KAAK,CAAC;IACd,CAAC;AACH,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,eAAe,CAAC,WAA8B;IAClE,MAAM,cAAc,EAAE,CAAC;IACvB,MAAM,OAAO,GAAG,GAAG,gBAAgB,IAAI,OAAO,CAAC,GAAG,IAAI,IAAI,CAAC,GAAG,EAAE,MAAM,CAAC;IACvE,MAAM,OAAO,GAAG,IAAI,CAAC,SAAS,CAAC,WAAW,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC;IAErD,MAAM,EAAE,CAAC,SAAS,CAAC,OAAO,EAAE,OAAO,EAAE,EAAE,QAAQ,EAAE,OAAO,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC;IACzE,MAAM,EAAE,CAAC,MAAM,CAAC,OAAO,EAAE,gBAAgB,CAAC,CAAC;AAC7C,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,gBAAgB;IACpC,IAAI,CAAC;QACH,MAAM,EAAE,CAAC,MAAM,CAAC,gBAAgB,CAAC,CAAC;IACpC,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,IAAK,KAA+B,CAAC,IAAI,KAAK,QAAQ,EAAE,CAAC;YACvD,MAAM,KAAK,CAAC;QACd,CAAC;IACH,CAAC;AACH,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,gBAAgB;IACpC,IAAI,CAAC;QACH,MAAM,EAAE,CAAC,MAAM,CAAC,gBAAgB,CAAC,CAAC;QAClC,OAAO,IAAI,CAAC;IACd,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,KAAK,CAAC;IACf,CAAC;AACH,CAAC"}
@@ -0,0 +1,7 @@
1
+ export declare function getDeviceIdentity(): Promise<{
2
+ deviceId: string;
3
+ deviceToken?: string;
4
+ }>;
5
+ export declare function getOrCreateDeviceId(): Promise<string>;
6
+ export declare function updateDeviceToken(deviceToken: string): Promise<void>;
7
+ //# sourceMappingURL=device.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"device.d.ts","sourceRoot":"","sources":["../../src/utils/device.ts"],"names":[],"mappings":"AAqEA,wBAAsB,iBAAiB,IAAI,OAAO,CAAC;IAAE,QAAQ,EAAE,MAAM,CAAC;IAAC,WAAW,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC,CAsC7F;AAED,wBAAsB,mBAAmB,IAAI,OAAO,CAAC,MAAM,CAAC,CAG3D;AAED,wBAAsB,iBAAiB,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CA0B1E"}
@@ -0,0 +1,118 @@
1
+ import fs from 'fs/promises';
2
+ import os from 'os';
3
+ import path from 'path';
4
+ import { randomUUID } from 'crypto';
5
+ const KODUS_DIR = path.join(os.homedir(), '.kodus');
6
+ const DEVICE_FILE = path.join(KODUS_DIR, 'device.json');
7
+ const UUID_REGEX = /^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i;
8
+ let cachedDevice = null;
9
+ let initializationPromise = null;
10
+ function isValidDeviceId(value) {
11
+ return typeof value === 'string' && UUID_REGEX.test(value);
12
+ }
13
+ function isValidDeviceToken(value) {
14
+ return typeof value === 'string' && value.trim().length > 0;
15
+ }
16
+ async function ensureKodusDir() {
17
+ try {
18
+ await fs.mkdir(KODUS_DIR, { recursive: true, mode: 0o700 });
19
+ }
20
+ catch (error) {
21
+ if (error.code !== 'EEXIST') {
22
+ throw error;
23
+ }
24
+ }
25
+ }
26
+ async function writeDeviceData(data) {
27
+ await ensureKodusDir();
28
+ const tmpFile = `${DEVICE_FILE}.${process.pid}.${Date.now()}.tmp`;
29
+ await fs.writeFile(tmpFile, JSON.stringify(data, null, 2), {
30
+ encoding: 'utf-8',
31
+ mode: 0o600,
32
+ });
33
+ await fs.rename(tmpFile, DEVICE_FILE);
34
+ }
35
+ async function readStoredDeviceData() {
36
+ try {
37
+ const content = await fs.readFile(DEVICE_FILE, 'utf-8');
38
+ const parsed = JSON.parse(content);
39
+ if (!isValidDeviceId(parsed.deviceId)) {
40
+ return null;
41
+ }
42
+ return {
43
+ deviceId: parsed.deviceId,
44
+ createdAt: typeof parsed.createdAt === 'string' ? parsed.createdAt : new Date().toISOString(),
45
+ ...(isValidDeviceToken(parsed.deviceToken) ? { deviceToken: parsed.deviceToken } : {}),
46
+ ...(typeof parsed.tokenUpdatedAt === 'string' ? { tokenUpdatedAt: parsed.tokenUpdatedAt } : {}),
47
+ };
48
+ }
49
+ catch (error) {
50
+ if (error.code === 'ENOENT') {
51
+ return null;
52
+ }
53
+ return null;
54
+ }
55
+ }
56
+ export async function getDeviceIdentity() {
57
+ if (cachedDevice) {
58
+ return {
59
+ deviceId: cachedDevice.deviceId,
60
+ ...(cachedDevice.deviceToken ? { deviceToken: cachedDevice.deviceToken } : {}),
61
+ };
62
+ }
63
+ if (initializationPromise) {
64
+ return initializationPromise;
65
+ }
66
+ initializationPromise = (async () => {
67
+ const existing = await readStoredDeviceData();
68
+ if (existing) {
69
+ cachedDevice = existing;
70
+ return {
71
+ deviceId: existing.deviceId,
72
+ ...(existing.deviceToken ? { deviceToken: existing.deviceToken } : {}),
73
+ };
74
+ }
75
+ const created = {
76
+ deviceId: randomUUID(),
77
+ createdAt: new Date().toISOString(),
78
+ };
79
+ cachedDevice = created;
80
+ try {
81
+ await writeDeviceData(created);
82
+ }
83
+ catch {
84
+ // If persistence fails, still return a process-stable identity.
85
+ }
86
+ return { deviceId: created.deviceId };
87
+ })();
88
+ return initializationPromise;
89
+ }
90
+ export async function getOrCreateDeviceId() {
91
+ const identity = await getDeviceIdentity();
92
+ return identity.deviceId;
93
+ }
94
+ export async function updateDeviceToken(deviceToken) {
95
+ if (!isValidDeviceToken(deviceToken)) {
96
+ return;
97
+ }
98
+ const current = cachedDevice ?? await readStoredDeviceData() ?? {
99
+ deviceId: randomUUID(),
100
+ createdAt: new Date().toISOString(),
101
+ };
102
+ if (current.deviceToken === deviceToken && cachedDevice) {
103
+ return;
104
+ }
105
+ const next = {
106
+ ...current,
107
+ deviceToken,
108
+ tokenUpdatedAt: new Date().toISOString(),
109
+ };
110
+ cachedDevice = next;
111
+ try {
112
+ await writeDeviceData(next);
113
+ }
114
+ catch {
115
+ // Keep in-memory token even if disk persistence fails.
116
+ }
117
+ }
118
+ //# sourceMappingURL=device.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"device.js","sourceRoot":"","sources":["../../src/utils/device.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kodus/cli",
3
- "version": "0.1.10",
3
+ "version": "0.1.12",
4
4
  "description": "Kodus CLI - AI-powered code review from your terminal",
5
5
  "type": "module",
6
6
  "bin": {