| ... | ... | @@ -9,6 +9,10 @@ const CodexAuthJsonSchema = Schema.Struct({ |
| 9 | 9 | }), |
| 10 | 10 | }); |
| 11 | 11 | |
| 12 | const ClaudeJsonSchema = Schema.Struct({ |
| 13 | userID: Schema.String, |
| 14 | }); |
| 15 | |
| 12 | 16 | class IdentifyUserError extends Schema.TaggedErrorClass<IdentifyUserError>()("IdentifyUserError", { |
| 13 | 17 | message: Schema.String, |
| 14 | 18 | cause: Schema.optional(Schema.Defect), |
| ... | ... | @@ -37,6 +41,19 @@ const getCodexAccountId = Effect.gen(function* () { |
| 37 | 41 | return authJson.tokens.account_id; |
| 38 | 42 | }); |
| 39 | 43 | |
| 44 | const getClaudeUserId = Effect.gen(function* () { |
| 45 | const fileSystem = yield* FileSystem.FileSystem; |
| 46 | const path = yield* Path.Path; |
| 47 | |
| 48 | const claudeJsonPath = path.join(homedir(), ".claude.json"); |
| 49 | const claudeJson = yield* Effect.flatMap( |
| 50 | fileSystem.readFileString(claudeJsonPath), |
| 51 | Schema.decodeEffect(Schema.fromJsonString(ClaudeJsonSchema)), |
| 52 | ); |
| 53 | |
| 54 | return claudeJson.userID; |
| 55 | }); |
| 56 | |
| 40 | 57 | const upsertAnonymousId = Effect.gen(function* () { |
| 41 | 58 | const fileSystem = yield* FileSystem.FileSystem; |
| 42 | 59 | const path = yield* Path.Path; |
| ... | ... | @@ -59,7 +76,8 @@ const upsertAnonymousId = Effect.gen(function* () { |
| 59 | 76 | /** |
| 60 | 77 | * getTelemetryIdentifier - Users are "identified" by finding the first match of the following, then hashing the value. |
| 61 | 78 | * 1. ~/.codex/auth.json tokens.account_id |
| 62 | | * 2. ~/.t3/telemetry/anonymous-id |
| 79 | * 2. ~/.claude.json userID |
| 80 | * 3. ~/.t3/telemetry/anonymous-id |
| 63 | 81 | */ |
| 64 | 82 | export const getTelemetryIdentifier = Effect.gen(function* () { |
| 65 | 83 | const codexAccountId = yield* Effect.result(getCodexAccountId); |
| ... | ... | @@ -67,6 +85,11 @@ export const getTelemetryIdentifier = Effect.gen(function* () { |
| 67 | 85 | return yield* hash(codexAccountId.success); |
| 68 | 86 | } |
| 69 | 87 | |
| 88 | const claudeUserId = yield* Effect.result(getClaudeUserId); |
| 89 | if (claudeUserId._tag === "Success") { |
| 90 | return yield* hash(claudeUserId.success); |
| 91 | } |
| 92 | |
| 70 | 93 | const anonymousId = yield* Effect.result(upsertAnonymousId); |
| 71 | 94 | if (anonymousId._tag === "Success") { |
| 72 | 95 | return yield* hash(anonymousId.success); |