charness 3.4.0 → 3.5.0

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 (146) hide show
  1. package/CHANGELOG.md +27 -0
  2. package/README.md +73 -5
  3. package/dist/adapters/claudeCliAdapter.js +2 -2
  4. package/dist/adapters/claudeCliAdapter.js.map +1 -1
  5. package/dist/adapters/claudeConfigDir.d.ts +18 -0
  6. package/dist/adapters/claudeConfigDir.d.ts.map +1 -1
  7. package/dist/adapters/claudeJsonStreamAdapter.d.ts +8 -1
  8. package/dist/adapters/claudeJsonStreamAdapter.d.ts.map +1 -1
  9. package/dist/adapters/claudeJsonStreamAdapter.js +24 -6
  10. package/dist/adapters/claudeJsonStreamAdapter.js.map +1 -1
  11. package/dist/adapters/createAdapter.d.ts +2 -1
  12. package/dist/adapters/createAdapter.d.ts.map +1 -1
  13. package/dist/adapters/createAdapter.js +16 -0
  14. package/dist/adapters/createAdapter.js.map +1 -1
  15. package/dist/agentLogin/agentLogin.d.ts +18 -1
  16. package/dist/agentLogin/agentLogin.d.ts.map +1 -1
  17. package/dist/agentLogin/agentLogin.js +59 -18
  18. package/dist/agentLogin/agentLogin.js.map +1 -1
  19. package/dist/apiErrorRetry.d.ts +3 -1
  20. package/dist/apiErrorRetry.d.ts.map +1 -1
  21. package/dist/apiErrorRetry.js +11 -1
  22. package/dist/apiErrorRetry.js.map +1 -1
  23. package/dist/bot.d.ts.map +1 -1
  24. package/dist/bot.js +176 -23
  25. package/dist/bot.js.map +1 -1
  26. package/dist/cli/claudeProfiles.d.ts +1 -1
  27. package/dist/cli/claudeProfiles.d.ts.map +1 -1
  28. package/dist/cli/claudeProfiles.js +11 -6
  29. package/dist/cli/claudeProfiles.js.map +1 -1
  30. package/dist/connectors/telegram/commands/claudeAccounts.d.ts +6 -2
  31. package/dist/connectors/telegram/commands/claudeAccounts.d.ts.map +1 -1
  32. package/dist/connectors/telegram/commands/claudeAccounts.js +127 -28
  33. package/dist/connectors/telegram/commands/claudeAccounts.js.map +1 -1
  34. package/dist/connectors/telegram/commands/fallbackChain.d.ts.map +1 -1
  35. package/dist/connectors/telegram/commands/fallbackChain.js +6 -2
  36. package/dist/connectors/telegram/commands/fallbackChain.js.map +1 -1
  37. package/dist/i18n/de.d.ts.map +1 -1
  38. package/dist/i18n/de.js +28 -1
  39. package/dist/i18n/de.js.map +1 -1
  40. package/dist/i18n/en.d.ts.map +1 -1
  41. package/dist/i18n/en.js +28 -1
  42. package/dist/i18n/en.js.map +1 -1
  43. package/dist/i18n/es.d.ts.map +1 -1
  44. package/dist/i18n/es.js +28 -1
  45. package/dist/i18n/es.js.map +1 -1
  46. package/dist/i18n/fr.d.ts.map +1 -1
  47. package/dist/i18n/fr.js +28 -1
  48. package/dist/i18n/fr.js.map +1 -1
  49. package/dist/i18n/hi.d.ts.map +1 -1
  50. package/dist/i18n/hi.js +28 -1
  51. package/dist/i18n/hi.js.map +1 -1
  52. package/dist/i18n/ja.d.ts.map +1 -1
  53. package/dist/i18n/ja.js +28 -1
  54. package/dist/i18n/ja.js.map +1 -1
  55. package/dist/i18n/ka.d.ts.map +1 -1
  56. package/dist/i18n/ka.js +28 -1
  57. package/dist/i18n/ka.js.map +1 -1
  58. package/dist/i18n/pt.d.ts.map +1 -1
  59. package/dist/i18n/pt.js +28 -1
  60. package/dist/i18n/pt.js.map +1 -1
  61. package/dist/i18n/ru.d.ts.map +1 -1
  62. package/dist/i18n/ru.js +28 -1
  63. package/dist/i18n/ru.js.map +1 -1
  64. package/dist/i18n/uk.d.ts.map +1 -1
  65. package/dist/i18n/uk.js +28 -1
  66. package/dist/i18n/uk.js.map +1 -1
  67. package/dist/i18n/uz.d.ts.map +1 -1
  68. package/dist/i18n/uz.js +28 -1
  69. package/dist/i18n/uz.js.map +1 -1
  70. package/dist/i18n/zh.d.ts.map +1 -1
  71. package/dist/i18n/zh.js +28 -1
  72. package/dist/i18n/zh.js.map +1 -1
  73. package/dist/scheduler/mcpSurface.d.ts.map +1 -1
  74. package/dist/scheduler/mcpSurface.js +4 -2
  75. package/dist/scheduler/mcpSurface.js.map +1 -1
  76. package/dist/state.d.ts +31 -0
  77. package/dist/state.d.ts.map +1 -1
  78. package/dist/state.js +36 -0
  79. package/dist/state.js.map +1 -1
  80. package/dist/types.d.ts +6 -0
  81. package/dist/types.d.ts.map +1 -1
  82. package/dist/utils/anthropicApiKeyCheck.d.ts +19 -0
  83. package/dist/utils/anthropicApiKeyCheck.d.ts.map +1 -0
  84. package/dist/utils/anthropicApiKeyCheck.js +41 -0
  85. package/dist/utils/anthropicApiKeyCheck.js.map +1 -0
  86. package/dist/utils/claudeAccountPickerPlan.d.ts +6 -1
  87. package/dist/utils/claudeAccountPickerPlan.d.ts.map +1 -1
  88. package/dist/utils/claudeAccountPickerPlan.js +5 -1
  89. package/dist/utils/claudeAccountPickerPlan.js.map +1 -1
  90. package/dist/utils/claudeApiKeyHelper.d.ts +19 -0
  91. package/dist/utils/claudeApiKeyHelper.d.ts.map +1 -0
  92. package/dist/utils/claudeApiKeyHelper.js +32 -0
  93. package/dist/utils/claudeApiKeyHelper.js.map +1 -0
  94. package/dist/utils/claudeApiSpend.d.ts +73 -0
  95. package/dist/utils/claudeApiSpend.d.ts.map +1 -0
  96. package/dist/utils/claudeApiSpend.js +82 -0
  97. package/dist/utils/claudeApiSpend.js.map +1 -0
  98. package/dist/utils/claudeCompactHook.d.ts +11 -6
  99. package/dist/utils/claudeCompactHook.d.ts.map +1 -1
  100. package/dist/utils/claudeCompactHook.js +28 -11
  101. package/dist/utils/claudeCompactHook.js.map +1 -1
  102. package/dist/utils/claudeLimitSwitch.d.ts +2 -1
  103. package/dist/utils/claudeLimitSwitch.d.ts.map +1 -1
  104. package/dist/utils/claudeLimitSwitch.js +3 -2
  105. package/dist/utils/claudeLimitSwitch.js.map +1 -1
  106. package/dist/utils/claudeProfileUsageLines.d.ts +18 -3
  107. package/dist/utils/claudeProfileUsageLines.d.ts.map +1 -1
  108. package/dist/utils/claudeProfileUsageLines.js +23 -2
  109. package/dist/utils/claudeProfileUsageLines.js.map +1 -1
  110. package/dist/utils/claudeProfiles.d.ts +57 -2
  111. package/dist/utils/claudeProfiles.d.ts.map +1 -1
  112. package/dist/utils/claudeProfiles.js +96 -3
  113. package/dist/utils/claudeProfiles.js.map +1 -1
  114. package/dist/utils/claudeStreamJson.d.ts +4 -1
  115. package/dist/utils/claudeStreamJson.d.ts.map +1 -1
  116. package/dist/utils/claudeStreamJson.js +6 -0
  117. package/dist/utils/claudeStreamJson.js.map +1 -1
  118. package/dist/utils/claudeTranscriptContent.d.ts +8 -0
  119. package/dist/utils/claudeTranscriptContent.d.ts.map +1 -1
  120. package/dist/utils/claudeTranscriptContent.js +44 -0
  121. package/dist/utils/claudeTranscriptContent.js.map +1 -1
  122. package/dist/utils/claudeUsage.d.ts +22 -6
  123. package/dist/utils/claudeUsage.d.ts.map +1 -1
  124. package/dist/utils/claudeUsage.js +12 -5
  125. package/dist/utils/claudeUsage.js.map +1 -1
  126. package/dist/utils/claudeUsageRefresher.d.ts +6 -0
  127. package/dist/utils/claudeUsageRefresher.d.ts.map +1 -1
  128. package/dist/utils/claudeUsageRefresher.js +2 -2
  129. package/dist/utils/claudeUsageRefresher.js.map +1 -1
  130. package/dist/utils/fallbackChain.d.ts +15 -8
  131. package/dist/utils/fallbackChain.d.ts.map +1 -1
  132. package/dist/utils/fallbackChain.js +30 -13
  133. package/dist/utils/fallbackChain.js.map +1 -1
  134. package/dist/utils/limitsBoardPlan.d.ts +4 -2
  135. package/dist/utils/limitsBoardPlan.d.ts.map +1 -1
  136. package/dist/utils/limitsBoardPlan.js +12 -5
  137. package/dist/utils/limitsBoardPlan.js.map +1 -1
  138. package/dist/utils/recvPreviewRedaction.d.ts +7 -2
  139. package/dist/utils/recvPreviewRedaction.d.ts.map +1 -1
  140. package/dist/utils/recvPreviewRedaction.js +10 -4
  141. package/dist/utils/recvPreviewRedaction.js.map +1 -1
  142. package/dist/utils/threadStatusReport.d.ts +12 -1
  143. package/dist/utils/threadStatusReport.d.ts.map +1 -1
  144. package/dist/utils/threadStatusReport.js +13 -4
  145. package/dist/utils/threadStatusReport.js.map +1 -1
  146. package/package.json +1 -1
@@ -0,0 +1,73 @@
1
+ /**
2
+ * @description What an account billed to API credits (`utils/claudeProfiles.ts`, `billing: 'api'`) has spent through
3
+ * the bot, from the `total_cost_usd` of Claude's stream `result` frames (the json-stream backend; the tmux backend
4
+ * reports no figure).
5
+ *
6
+ * That figure is the CONVERSATION's running cost, not the turn's: Claude Code writes it into the transcript when its
7
+ * process exits and restores it on `--resume`, so a resumed process starts from the conversation's last saved total,
8
+ * and a subscription turn of the same conversation counts in it too (a notional figure). The turn's spend is therefore
9
+ * a DELTA, and only a turn on an API account adds to that account's spend. The first turn of a process the bot
10
+ * started is measured against the total that process restored (the adapter reads it from the transcript before the
11
+ * launch: `0` for a new conversation) — never against the last total the bot saw, which a turn the bot did not see
12
+ * (the tmux backend's, which reports none) or a process that died without its exit flush (the next one restores an
13
+ * OLDER total) makes wrong. Every later turn is measured against the last total the bot saw for that conversation (a
14
+ * per-topic baseline it keeps for every account, persisted, so an adopted process after a restart goes on from it).
15
+ *
16
+ * It is what the bot OBSERVED, not the organization's balance: reading that needs an Admin API key.
17
+ *
18
+ * Pure: the clock and the zone come from the caller.
19
+ */
20
+ import type { ClaudeProfileBilling } from './claudeProfiles';
21
+ /** The last `total_cost_usd` the bot saw for a topic's conversation (`state.json` `claudeCostBaselines`). */
22
+ export interface ClaudeCostBaseline {
23
+ sessionId: string;
24
+ totalCostUsd: number;
25
+ }
26
+ /** An API account's spend through the bot (`ClaudeProfileRecord.apiSpend`). */
27
+ export interface ClaudeApiSpend {
28
+ totalUsd: number;
29
+ /** ISO instant of the first turn counted. */
30
+ since: string;
31
+ lastTurnUsd: number;
32
+ /** ISO instant of the last turn counted. */
33
+ lastTurnAt: string;
34
+ }
35
+ /**
36
+ * @description The spend of the turn whose `result` reported `totalCostUsd` for `sessionId` (see the module). The first
37
+ * turn of a process the bot started (`startCostUsd` known) counts from the total that process restored; any other turn
38
+ * is the delta against the baseline of the same conversation, `null` (unknown) without one. A total BELOW the figure it
39
+ * is measured against means the CLI counted from zero (it restored nothing), so the total is the turn's.
40
+ */
41
+ export declare function computeClaudeTurnCostUsd(input: {
42
+ previous: ClaudeCostBaseline | undefined;
43
+ sessionId: string;
44
+ totalCostUsd: number;
45
+ startCostUsd: number | null;
46
+ }): number | null;
47
+ /** What one turn's cost report does to the account it ran on. */
48
+ export interface ClaudeTurnCostOutcome {
49
+ /** What to add to the account's spend: the turn's cost on an account billed to API credits; `null` for nothing. */
50
+ spendUsd: number | null;
51
+ /** A billed turn went through on an account marked out of credits: the balance is back, the mark ends. */
52
+ isCreditMarkCleared: boolean;
53
+ }
54
+ /**
55
+ * @description The effect of a turn's cost on its account: only an account billed to API credits has spend (a
56
+ * subscription's figure is notional), and only a positive, known cost adds to it. A turn that did not end on an error
57
+ * AND was billed proves the account works again, so it ends a used-up-credits mark on ANY account (the refusal marks
58
+ * whichever account it came from) — a result that made no request (a compaction with nothing to compact, a local
59
+ * command) costs nothing and proves nothing.
60
+ */
61
+ export declare function getClaudeTurnCostOutcome(input: {
62
+ billing: ClaudeProfileBilling | null;
63
+ isCreditExhausted: boolean;
64
+ isError: boolean;
65
+ turnCostUsd: number | null;
66
+ }): ClaudeTurnCostOutcome;
67
+ /** The account's spend after a turn that cost `turnCostUsd` at `atIso` (the first counted turn opens `since`). */
68
+ export declare function addClaudeApiSpend(previous: ClaudeApiSpend | undefined, turnCostUsd: number, atIso: string): ClaudeApiSpend;
69
+ /** `$12.34`; `<$0.01` for a positive amount under a cent; `$0.00` for none. */
70
+ export declare function formatUsd(amount: number): string;
71
+ /** The day a spend is counted since, in the instance zone: `23.10` (the year when it is not this one: `23.10.2025`). */
72
+ export declare function formatSpendSinceDay(sinceIso: string, timezone: string, nowMs: number): string;
73
+ //# sourceMappingURL=claudeApiSpend.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"claudeApiSpend.d.ts","sourceRoot":"","sources":["../../src/utils/claudeApiSpend.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAEH,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,kBAAkB,CAAC;AAE7D,6GAA6G;AAC7G,MAAM,WAAW,kBAAkB;IACjC,SAAS,EAAE,MAAM,CAAC;IAClB,YAAY,EAAE,MAAM,CAAC;CACtB;AAED,+EAA+E;AAC/E,MAAM,WAAW,cAAc;IAC7B,QAAQ,EAAE,MAAM,CAAC;IACjB,6CAA6C;IAC7C,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,EAAE,MAAM,CAAC;IACpB,4CAA4C;IAC5C,UAAU,EAAE,MAAM,CAAC;CACpB;AAED;;;;;GAKG;AACH,wBAAgB,wBAAwB,CAAC,KAAK,EAAE;IAC9C,QAAQ,EAAE,kBAAkB,GAAG,SAAS,CAAC;IACzC,SAAS,EAAE,MAAM,CAAC;IAClB,YAAY,EAAE,MAAM,CAAC;IACrB,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;CAC7B,GAAG,MAAM,GAAG,IAAI,CAMhB;AAED,iEAAiE;AACjE,MAAM,WAAW,qBAAqB;IACpC,mHAAmH;IACnH,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,0GAA0G;IAC1G,mBAAmB,EAAE,OAAO,CAAC;CAC9B;AAED;;;;;;GAMG;AACH,wBAAgB,wBAAwB,CAAC,KAAK,EAAE;IAC9C,OAAO,EAAE,oBAAoB,GAAG,IAAI,CAAC;IACrC,iBAAiB,EAAE,OAAO,CAAC;IAC3B,OAAO,EAAE,OAAO,CAAC;IACjB,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;CAC5B,GAAG,qBAAqB,CAMxB;AAED,kHAAkH;AAClH,wBAAgB,iBAAiB,CAAC,QAAQ,EAAE,cAAc,GAAG,SAAS,EAAE,WAAW,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,cAAc,CAO1H;AAKD,+EAA+E;AAC/E,wBAAgB,SAAS,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAGhD;AAED,wHAAwH;AACxH,wBAAgB,mBAAmB,CAAC,QAAQ,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,CAQ7F"}
@@ -0,0 +1,82 @@
1
+ "use strict";
2
+ /**
3
+ * @description What an account billed to API credits (`utils/claudeProfiles.ts`, `billing: 'api'`) has spent through
4
+ * the bot, from the `total_cost_usd` of Claude's stream `result` frames (the json-stream backend; the tmux backend
5
+ * reports no figure).
6
+ *
7
+ * That figure is the CONVERSATION's running cost, not the turn's: Claude Code writes it into the transcript when its
8
+ * process exits and restores it on `--resume`, so a resumed process starts from the conversation's last saved total,
9
+ * and a subscription turn of the same conversation counts in it too (a notional figure). The turn's spend is therefore
10
+ * a DELTA, and only a turn on an API account adds to that account's spend. The first turn of a process the bot
11
+ * started is measured against the total that process restored (the adapter reads it from the transcript before the
12
+ * launch: `0` for a new conversation) — never against the last total the bot saw, which a turn the bot did not see
13
+ * (the tmux backend's, which reports none) or a process that died without its exit flush (the next one restores an
14
+ * OLDER total) makes wrong. Every later turn is measured against the last total the bot saw for that conversation (a
15
+ * per-topic baseline it keeps for every account, persisted, so an adopted process after a restart goes on from it).
16
+ *
17
+ * It is what the bot OBSERVED, not the organization's balance: reading that needs an Admin API key.
18
+ *
19
+ * Pure: the clock and the zone come from the caller.
20
+ */
21
+ Object.defineProperty(exports, "__esModule", { value: true });
22
+ exports.computeClaudeTurnCostUsd = computeClaudeTurnCostUsd;
23
+ exports.getClaudeTurnCostOutcome = getClaudeTurnCostOutcome;
24
+ exports.addClaudeApiSpend = addClaudeApiSpend;
25
+ exports.formatUsd = formatUsd;
26
+ exports.formatSpendSinceDay = formatSpendSinceDay;
27
+ /**
28
+ * @description The spend of the turn whose `result` reported `totalCostUsd` for `sessionId` (see the module). The first
29
+ * turn of a process the bot started (`startCostUsd` known) counts from the total that process restored; any other turn
30
+ * is the delta against the baseline of the same conversation, `null` (unknown) without one. A total BELOW the figure it
31
+ * is measured against means the CLI counted from zero (it restored nothing), so the total is the turn's.
32
+ */
33
+ function computeClaudeTurnCostUsd(input) {
34
+ const { previous, totalCostUsd } = input;
35
+ const measuredFromUsd = input.startCostUsd ?? (previous?.sessionId === input.sessionId ? previous.totalCostUsd : null);
36
+ if (measuredFromUsd === null)
37
+ return null;
38
+ const delta = totalCostUsd - measuredFromUsd;
39
+ return delta >= 0 ? delta : totalCostUsd;
40
+ }
41
+ /**
42
+ * @description The effect of a turn's cost on its account: only an account billed to API credits has spend (a
43
+ * subscription's figure is notional), and only a positive, known cost adds to it. A turn that did not end on an error
44
+ * AND was billed proves the account works again, so it ends a used-up-credits mark on ANY account (the refusal marks
45
+ * whichever account it came from) — a result that made no request (a compaction with nothing to compact, a local
46
+ * command) costs nothing and proves nothing.
47
+ */
48
+ function getClaudeTurnCostOutcome(input) {
49
+ const billedUsd = input.turnCostUsd !== null && input.turnCostUsd > 0 ? input.turnCostUsd : null;
50
+ return {
51
+ spendUsd: input.billing === 'api' ? billedUsd : null,
52
+ isCreditMarkCleared: input.isCreditExhausted && !input.isError && billedUsd !== null,
53
+ };
54
+ }
55
+ /** The account's spend after a turn that cost `turnCostUsd` at `atIso` (the first counted turn opens `since`). */
56
+ function addClaudeApiSpend(previous, turnCostUsd, atIso) {
57
+ return {
58
+ totalUsd: (previous?.totalUsd ?? 0) + turnCostUsd,
59
+ since: previous?.since ?? atIso,
60
+ lastTurnUsd: turnCostUsd,
61
+ lastTurnAt: atIso,
62
+ };
63
+ }
64
+ /** Below a cent a figure reads as `<$0.01` rather than a misleading `$0.00`. */
65
+ const smallestShownUsd = 0.01;
66
+ /** `$12.34`; `<$0.01` for a positive amount under a cent; `$0.00` for none. */
67
+ function formatUsd(amount) {
68
+ if (amount > 0 && amount < smallestShownUsd)
69
+ return `<$${smallestShownUsd.toFixed(2)}`;
70
+ return `$${amount.toFixed(2)}`;
71
+ }
72
+ /** The day a spend is counted since, in the instance zone: `23.10` (the year when it is not this one: `23.10.2025`). */
73
+ function formatSpendSinceDay(sinceIso, timezone, nowMs) {
74
+ const at = Date.parse(sinceIso);
75
+ if (Number.isNaN(at))
76
+ return '?';
77
+ const read = (options, instant) => new Intl.DateTimeFormat('en-GB', { timeZone: timezone, ...options }).format(instant);
78
+ const day = `${read({ day: '2-digit' }, at)}.${read({ month: '2-digit' }, at)}`;
79
+ const year = read({ year: 'numeric' }, at);
80
+ return year === read({ year: 'numeric' }, nowMs) ? day : `${day}.${year}`;
81
+ }
82
+ //# sourceMappingURL=claudeApiSpend.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"claudeApiSpend.js","sourceRoot":"","sources":["../../src/utils/claudeApiSpend.ts"],"names":[],"mappings":"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"}
@@ -54,11 +54,16 @@ export declare function buildClaudeCompactHookSettings(command: string): {
54
54
  };
55
55
  };
56
56
  /**
57
- * @description Write the hook settings file and return the `--settings <path>`
58
- * argument pair for a Claude launch. Rewritten on every launch (atomic rename, so
59
- * a concurrently starting session never reads a half-written file) so a changed
60
- * guidance reaches the next session. A write failure returns `[]` and only logs:
61
- * the hook improves a summary, it must never stop an agent from starting.
57
+ * @description Write the launch settings file and return the `--settings <path>` argument pair for a Claude
58
+ * launch under `configDir` (the account profile's directory, `null` = `~/.claude`). Rewritten on every launch
59
+ * (atomic rename, so a concurrently starting session never reads a half-written file) so a changed guidance
60
+ * reaches the next session.
61
+ *
62
+ * Only the LAST `--settings` a launch carries counts (probed on 2.1.304), so a profile that holds a pasted API key
63
+ * (`utils/claudeProfiles.ts`) gets ONE file of its own, in its directory: the hook plus the `apiKeyHelper` that
64
+ * reads the key. Every other launch shares the hook file in `dataDir`. A write failure of the shared file returns
65
+ * `[]` and only logs (the hook improves a summary, it must never stop an agent from starting); for a key profile
66
+ * the same settings go inline instead, so the account never loses its key to a full disk.
62
67
  */
63
- export declare function prepareClaudeCompactHookFlags(dataDir: string): string[];
68
+ export declare function prepareClaudeCompactHookFlags(dataDir: string, configDir?: string | null): string[];
64
69
  //# sourceMappingURL=claudeCompactHook.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"claudeCompactHook.d.ts","sourceRoot":"","sources":["../../src/utils/claudeCompactHook.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AAWH;;;;GAIG;AACH,eAAO,MAAM,iCAAiC,6BAA6B,CAAC;AAE5E;;;;GAIG;AACH,wBAAgB,4BAA4B,IAAI,MAAM,CAOrD;AAED;;;;;;GAMG;AACH,wBAAgB,0BAA0B,CAAC,KAAK,EAAE;IAChD,WAAW,EAAE,MAAM,CAAC;IACpB,iBAAiB,EAAE,MAAM,CAAC;CAC3B,GAAG,MAAM,CAET;AAED,6FAA6F;AAC7F,wBAAgB,8BAA8B,CAAC,OAAO,EAAE,MAAM,GAAG;IAC/D,KAAK,EAAE;QAAE,UAAU,EAAE,KAAK,CAAC;YAAE,KAAK,EAAE,KAAK,CAAC;gBAAE,IAAI,EAAE,SAAS,CAAC;gBAAC,OAAO,EAAE,MAAM,CAAA;aAAE,CAAC,CAAA;SAAE,CAAC,CAAA;KAAE,CAAC;CACtF,CAEA;AAED;;;;;;GAMG;AACH,wBAAgB,6BAA6B,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,EAAE,CAiBvE"}
1
+ {"version":3,"file":"claudeCompactHook.d.ts","sourceRoot":"","sources":["../../src/utils/claudeCompactHook.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AAaH;;;;GAIG;AACH,eAAO,MAAM,iCAAiC,6BAA6B,CAAC;AAE5E;;;;GAIG;AACH,wBAAgB,4BAA4B,IAAI,MAAM,CAOrD;AAED;;;;;;GAMG;AACH,wBAAgB,0BAA0B,CAAC,KAAK,EAAE;IAChD,WAAW,EAAE,MAAM,CAAC;IACpB,iBAAiB,EAAE,MAAM,CAAC;CAC3B,GAAG,MAAM,CAET;AAED,6FAA6F;AAC7F,wBAAgB,8BAA8B,CAAC,OAAO,EAAE,MAAM,GAAG;IAC/D,KAAK,EAAE;QAAE,UAAU,EAAE,KAAK,CAAC;YAAE,KAAK,EAAE,KAAK,CAAC;gBAAE,IAAI,EAAE,SAAS,CAAC;gBAAC,OAAO,EAAE,MAAM,CAAA;aAAE,CAAC,CAAA;SAAE,CAAC,CAAA;KAAE,CAAC;CACtF,CAEA;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,6BAA6B,CAAC,OAAO,EAAE,MAAM,EAAE,SAAS,GAAE,MAAM,GAAG,IAAW,GAAG,MAAM,EAAE,CAaxG"}
@@ -33,6 +33,8 @@ const fs_1 = __importDefault(require("fs"));
33
33
  const path_1 = __importDefault(require("path"));
34
34
  const compactOnIdle_1 = require("./compactOnIdle");
35
35
  const tmuxExec_1 = require("./tmuxExec");
36
+ const claudeProfiles_1 = require("./claudeProfiles");
37
+ const claudeApiKeyHelper_1 = require("./claudeApiKeyHelper");
36
38
  /**
37
39
  * Name of the hook settings file inside `DATA_DIR`. ONE file shared by every
38
40
  * session: its content is the same for all of them, and a session that outlives
@@ -67,22 +69,37 @@ function buildClaudeCompactHookSettings(command) {
67
69
  return { hooks: { PreCompact: [{ hooks: [{ type: 'command', command }] }] } };
68
70
  }
69
71
  /**
70
- * @description Write the hook settings file and return the `--settings <path>`
71
- * argument pair for a Claude launch. Rewritten on every launch (atomic rename, so
72
- * a concurrently starting session never reads a half-written file) so a changed
73
- * guidance reaches the next session. A write failure returns `[]` and only logs:
74
- * the hook improves a summary, it must never stop an agent from starting.
72
+ * @description Write the launch settings file and return the `--settings <path>` argument pair for a Claude
73
+ * launch under `configDir` (the account profile's directory, `null` = `~/.claude`). Rewritten on every launch
74
+ * (atomic rename, so a concurrently starting session never reads a half-written file) so a changed guidance
75
+ * reaches the next session.
76
+ *
77
+ * Only the LAST `--settings` a launch carries counts (probed on 2.1.304), so a profile that holds a pasted API key
78
+ * (`utils/claudeProfiles.ts`) gets ONE file of its own, in its directory: the hook plus the `apiKeyHelper` that
79
+ * reads the key. Every other launch shares the hook file in `dataDir`. A write failure of the shared file returns
80
+ * `[]` and only logs (the hook improves a summary, it must never stop an agent from starting); for a key profile
81
+ * the same settings go inline instead, so the account never loses its key to a full disk.
75
82
  */
76
- function prepareClaudeCompactHookFlags(dataDir) {
77
- const settingsPath = path_1.default.join(dataDir, exports.claudeCompactHookSettingsFileName);
83
+ function prepareClaudeCompactHookFlags(dataDir, configDir = null) {
78
84
  const command = buildPreCompactHookCommand({
79
85
  instruction: getHookCompactionInstruction(),
80
86
  alreadySentMarker: compactOnIdle_1.compactionSkillsGuidance,
81
87
  });
88
+ const hookSettings = buildClaudeCompactHookSettings(command);
89
+ if (configDir !== null && (0, claudeProfiles_1.checkHasClaudeProfileApiKey)(configDir)) {
90
+ const settings = { ...hookSettings, ...(0, claudeApiKeyHelper_1.buildClaudeApiKeyHelperSettings)(configDir) };
91
+ const written = writeLaunchSettingsFile(configDir, path_1.default.join(configDir, claudeProfiles_1.claudeProfileLaunchSettingsFileName), settings);
92
+ return ['--settings', written ?? JSON.stringify(settings)];
93
+ }
94
+ const written = writeLaunchSettingsFile(dataDir, path_1.default.join(dataDir, exports.claudeCompactHookSettingsFileName), hookSettings);
95
+ return written === null ? [] : ['--settings', written];
96
+ }
97
+ /** Write `settings` to `settingsPath` atomically (`0600`); the path, or `null` when the write failed (logged). */
98
+ function writeLaunchSettingsFile(dir, settingsPath, settings) {
82
99
  const tmpPath = `${settingsPath}.${process.pid}.${Date.now()}.tmp`;
83
100
  try {
84
- fs_1.default.mkdirSync(dataDir, { recursive: true });
85
- fs_1.default.writeFileSync(tmpPath, JSON.stringify(buildClaudeCompactHookSettings(command)));
101
+ fs_1.default.mkdirSync(dir, { recursive: true });
102
+ fs_1.default.writeFileSync(tmpPath, JSON.stringify(settings), { mode: 0o600 });
86
103
  fs_1.default.renameSync(tmpPath, settingsPath);
87
104
  }
88
105
  catch (e) {
@@ -91,8 +108,8 @@ function prepareClaudeCompactHookFlags(dataDir) {
91
108
  fs_1.default.unlinkSync(tmpPath);
92
109
  }
93
110
  catch { /* never written */ }
94
- return [];
111
+ return null;
95
112
  }
96
- return ['--settings', settingsPath];
113
+ return settingsPath;
97
114
  }
98
115
  //# sourceMappingURL=claudeCompactHook.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"claudeCompactHook.js","sourceRoot":"","sources":["../../src/utils/claudeCompactHook.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;;;;;;AAuBH,oEAOC;AASD,gEAKC;AAGD,wEAIC;AASD,sEAiBC;AA3ED,4CAAoB;AACpB,gDAAwB;AACxB,mDAIyB;AACzB,yCAA8C;AAE9C;;;;GAIG;AACU,QAAA,iCAAiC,GAAG,0BAA0B,CAAC;AAE5E;;;;GAIG;AACH,SAAgB,4BAA4B;IAC1C,OAAO,IAAA,0CAA0B,EAAC;QAChC,oBAAoB,EAAE,KAAK;QAC3B,eAAe,EAAE,yCAAyB;QAC1C,mBAAmB,EAAE,KAAK;QAC1B,cAAc,EAAE,wCAAwB;KACzC,CAAC,IAAI,EAAE,CAAC;AACX,CAAC;AAED;;;;;;GAMG;AACH,SAAgB,0BAA0B,CAAC,KAG1C;IACC,OAAO,eAAe,IAAA,2BAAgB,EAAC,KAAK,CAAC,iBAAiB,CAAC,sBAAsB,IAAA,2BAAgB,EAAC,KAAK,CAAC,WAAW,CAAC,EAAE,CAAC;AAC7H,CAAC;AAED,6FAA6F;AAC7F,SAAgB,8BAA8B,CAAC,OAAe;IAG5D,OAAO,EAAE,KAAK,EAAE,EAAE,UAAU,EAAE,CAAC,EAAE,KAAK,EAAE,CAAC,EAAE,IAAI,EAAE,SAAS,EAAE,OAAO,EAAE,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC;AAChF,CAAC;AAED;;;;;;GAMG;AACH,SAAgB,6BAA6B,CAAC,OAAe;IAC3D,MAAM,YAAY,GAAG,cAAI,CAAC,IAAI,CAAC,OAAO,EAAE,yCAAiC,CAAC,CAAC;IAC3E,MAAM,OAAO,GAAG,0BAA0B,CAAC;QACzC,WAAW,EAAE,4BAA4B,EAAE;QAC3C,iBAAiB,EAAE,wCAAwB;KAC5C,CAAC,CAAC;IACH,MAAM,OAAO,GAAG,GAAG,YAAY,IAAI,OAAO,CAAC,GAAG,IAAI,IAAI,CAAC,GAAG,EAAE,MAAM,CAAC;IACnE,IAAI,CAAC;QACH,YAAE,CAAC,SAAS,CAAC,OAAO,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;QAC3C,YAAE,CAAC,aAAa,CAAC,OAAO,EAAE,IAAI,CAAC,SAAS,CAAC,8BAA8B,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC;QACnF,YAAE,CAAC,UAAU,CAAC,OAAO,EAAE,YAAY,CAAC,CAAC;IACvC,CAAC;IAAC,OAAO,CAAC,EAAE,CAAC;QACX,OAAO,CAAC,IAAI,CAAC,+BAA+B,YAAY,GAAG,EAAE,CAAC,CAAC,CAAC;QAChE,IAAI,CAAC;YAAC,YAAE,CAAC,UAAU,CAAC,OAAO,CAAC,CAAC;QAAC,CAAC;QAAC,MAAM,CAAC,CAAC,mBAAmB,CAAC,CAAC;QAC7D,OAAO,EAAE,CAAC;IACZ,CAAC;IACD,OAAO,CAAC,YAAY,EAAE,YAAY,CAAC,CAAC;AACtC,CAAC"}
1
+ {"version":3,"file":"claudeCompactHook.js","sourceRoot":"","sources":["../../src/utils/claudeCompactHook.ts"],"names":[],"mappings":"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"}
@@ -16,7 +16,8 @@ export { resolveClaudeAutoSwitchOnLimitEnabled } from './autoContinueOnLimit';
16
16
  * @description The profiles that may take a topic's work over, best first: signed in, not marked limited, with
17
17
  * KNOWN and fresh usage that leaves headroom on the windows `model` drains, and not the profile that just hit
18
18
  * the limit. A profile whose usage is unknown or stale is left out on purpose — the switch is sold as "this
19
- * one has room", and a guess could land the topic in a second limit.
19
+ * one has room", and a guess could land the topic in a second limit. An account billed to API credits is never
20
+ * one of them: it has no windows to have room on, and only the operator decides to spend money (the chain's rung).
20
21
  */
21
22
  export declare function pickClaudeLimitSwitchCandidates(input: {
22
23
  profiles: readonly ClaudeProfileUsageView[];
@@ -1 +1 @@
1
- {"version":3,"file":"claudeLimitSwitch.d.ts","sourceRoot":"","sources":["../../src/utils/claudeLimitSwitch.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,EAAmD,KAAK,sBAAsB,EAAE,KAAK,mBAAmB,EAAE,MAAM,eAAe,CAAC;AAEvI,gHAAgH;AAChH,OAAO,EAAE,qCAAqC,EAAE,MAAM,uBAAuB,CAAC;AAE9E;;;;;GAKG;AACH,wBAAgB,+BAA+B,CAAC,KAAK,EAAE;IACrD,QAAQ,EAAE,SAAS,sBAAsB,EAAE,CAAC;IAC5C,4DAA4D;IAC5D,WAAW,EAAE,MAAM,CAAC;IACpB,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IACrB,KAAK,EAAE,MAAM,CAAC;CACf,GAAG,MAAM,EAAE,CAQX;AAED;;;;GAIG;AACH,wBAAgB,yBAAyB,CAAC,KAAK,EAAE;IAC/C,SAAS,EAAE,MAAM,GAAG,SAAS,CAAC;IAC9B,KAAK,EAAE,mBAAmB,GAAG,SAAS,CAAC;IACvC,oBAAoB,EAAE,MAAM,GAAG,IAAI,CAAC;IACpC,KAAK,EAAE,MAAM,CAAC;IACd,UAAU,EAAE,MAAM,CAAC;CACpB,GAAG,MAAM,CAWT"}
1
+ {"version":3,"file":"claudeLimitSwitch.d.ts","sourceRoot":"","sources":["../../src/utils/claudeLimitSwitch.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,EAAmD,KAAK,sBAAsB,EAAE,KAAK,mBAAmB,EAAE,MAAM,eAAe,CAAC;AAEvI,gHAAgH;AAChH,OAAO,EAAE,qCAAqC,EAAE,MAAM,uBAAuB,CAAC;AAE9E;;;;;;GAMG;AACH,wBAAgB,+BAA+B,CAAC,KAAK,EAAE;IACrD,QAAQ,EAAE,SAAS,sBAAsB,EAAE,CAAC;IAC5C,4DAA4D;IAC5D,WAAW,EAAE,MAAM,CAAC;IACpB,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IACrB,KAAK,EAAE,MAAM,CAAC;CACf,GAAG,MAAM,EAAE,CAQX;AAED;;;;GAIG;AACH,wBAAgB,yBAAyB,CAAC,KAAK,EAAE;IAC/C,SAAS,EAAE,MAAM,GAAG,SAAS,CAAC;IAC9B,KAAK,EAAE,mBAAmB,GAAG,SAAS,CAAC;IACvC,oBAAoB,EAAE,MAAM,GAAG,IAAI,CAAC;IACpC,KAAK,EAAE,MAAM,CAAC;IACd,UAAU,EAAE,MAAM,CAAC;CACpB,GAAG,MAAM,CAWT"}
@@ -22,12 +22,13 @@ Object.defineProperty(exports, "resolveClaudeAutoSwitchOnLimitEnabled", { enumer
22
22
  * @description The profiles that may take a topic's work over, best first: signed in, not marked limited, with
23
23
  * KNOWN and fresh usage that leaves headroom on the windows `model` drains, and not the profile that just hit
24
24
  * the limit. A profile whose usage is unknown or stale is left out on purpose — the switch is sold as "this
25
- * one has room", and a guess could land the topic in a second limit.
25
+ * one has room", and a guess could land the topic in a second limit. An account billed to API credits is never
26
+ * one of them: it has no windows to have room on, and only the operator decides to spend money (the chain's rung).
26
27
  */
27
28
  function pickClaudeLimitSwitchCandidates(input) {
28
29
  const report = (0, claudeUsage_1.buildClaudeProfilesReport)(input.profiles, input.model, input.nowMs);
29
30
  return report.profiles
30
- .filter((entry) => entry.name !== input.currentName)
31
+ .filter((entry) => entry.name !== input.currentName && entry.billing !== 'api')
31
32
  .filter((entry) => entry.isEligible && entry.loggedIn === true && !entry.isUsageStale)
32
33
  .filter((entry) => entry.headroomPercent !== null && entry.headroomPercent > 0)
33
34
  .sort((a, b) => (b.headroomPercent ?? 0) - (a.headroomPercent ?? 0))
@@ -1 +1 @@
1
- {"version":3,"file":"claudeLimitSwitch.js","sourceRoot":"","sources":["../../src/utils/claudeLimitSwitch.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;GAUG;;;AAaH,0EAcC;AAOD,8DAiBC;AAjDD,+CAAuI;AAEvI,gHAAgH;AAChH,6DAA8E;AAArE,4IAAA,qCAAqC,OAAA;AAE9C;;;;;GAKG;AACH,SAAgB,+BAA+B,CAAC,KAM/C;IACC,MAAM,MAAM,GAAG,IAAA,uCAAyB,EAAC,KAAK,CAAC,QAAQ,EAAE,KAAK,CAAC,KAAK,EAAE,KAAK,CAAC,KAAK,CAAC,CAAC;IACnF,OAAO,MAAM,CAAC,QAAQ;SACnB,MAAM,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,IAAI,KAAK,KAAK,CAAC,WAAW,CAAC;SACnD,MAAM,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,UAAU,IAAI,KAAK,CAAC,QAAQ,KAAK,IAAI,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC;SACrF,MAAM,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,eAAe,KAAK,IAAI,IAAI,KAAK,CAAC,eAAe,GAAG,CAAC,CAAC;SAC9E,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,eAAe,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,eAAe,IAAI,CAAC,CAAC,CAAC;SACnE,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;AAChC,CAAC;AAED;;;;GAIG;AACH,SAAgB,yBAAyB,CAAC,KAMzC;IACC,MAAM,YAAY,GAAG,IAAA,kCAAoB,EAAC,KAAK,CAAC,KAAK,EAAE,SAAS,CAAC,EAAE,QAAQ,IAAI,IAAI,CAAC;IACpF,MAAM,cAAc,GAAG,YAAY,KAAK,IAAI,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,CAAC;IACrF,IAAI,OAAO,GAAG,KAAK,CAAC,SAAS,KAAK,SAAS,IAAI,KAAK,CAAC,SAAS,GAAG,KAAK,CAAC,KAAK;QAC1E,CAAC,CAAC,KAAK,CAAC,SAAS;QACjB,CAAC,CAAC,MAAM,CAAC,QAAQ,CAAC,cAAc,CAAC,IAAI,cAAc,GAAG,KAAK,CAAC,KAAK;YAC/D,CAAC,CAAC,cAAc;YAChB,CAAC,CAAC,KAAK,CAAC,KAAK,GAAG,KAAK,CAAC,UAAU,CAAC;IACrC,MAAM,UAAU,GAAG,KAAK,CAAC,oBAAoB,KAAK,IAAI,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,oBAAoB,CAAC,CAAC;IAC7G,IAAI,MAAM,CAAC,QAAQ,CAAC,UAAU,CAAC,IAAI,UAAU,GAAG,OAAO;QAAE,OAAO,GAAG,UAAU,CAAC;IAC9E,OAAO,IAAI,IAAI,CAAC,OAAO,CAAC,CAAC,WAAW,EAAE,CAAC;AACzC,CAAC"}
1
+ {"version":3,"file":"claudeLimitSwitch.js","sourceRoot":"","sources":["../../src/utils/claudeLimitSwitch.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;GAUG;;;AAcH,0EAcC;AAOD,8DAiBC;AAlDD,+CAAuI;AAEvI,gHAAgH;AAChH,6DAA8E;AAArE,4IAAA,qCAAqC,OAAA;AAE9C;;;;;;GAMG;AACH,SAAgB,+BAA+B,CAAC,KAM/C;IACC,MAAM,MAAM,GAAG,IAAA,uCAAyB,EAAC,KAAK,CAAC,QAAQ,EAAE,KAAK,CAAC,KAAK,EAAE,KAAK,CAAC,KAAK,CAAC,CAAC;IACnF,OAAO,MAAM,CAAC,QAAQ;SACnB,MAAM,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,IAAI,KAAK,KAAK,CAAC,WAAW,IAAI,KAAK,CAAC,OAAO,KAAK,KAAK,CAAC;SAC9E,MAAM,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,UAAU,IAAI,KAAK,CAAC,QAAQ,KAAK,IAAI,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC;SACrF,MAAM,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,eAAe,KAAK,IAAI,IAAI,KAAK,CAAC,eAAe,GAAG,CAAC,CAAC;SAC9E,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,eAAe,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,eAAe,IAAI,CAAC,CAAC,CAAC;SACnE,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;AAChC,CAAC;AAED;;;;GAIG;AACH,SAAgB,yBAAyB,CAAC,KAMzC;IACC,MAAM,YAAY,GAAG,IAAA,kCAAoB,EAAC,KAAK,CAAC,KAAK,EAAE,SAAS,CAAC,EAAE,QAAQ,IAAI,IAAI,CAAC;IACpF,MAAM,cAAc,GAAG,YAAY,KAAK,IAAI,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,CAAC;IACrF,IAAI,OAAO,GAAG,KAAK,CAAC,SAAS,KAAK,SAAS,IAAI,KAAK,CAAC,SAAS,GAAG,KAAK,CAAC,KAAK;QAC1E,CAAC,CAAC,KAAK,CAAC,SAAS;QACjB,CAAC,CAAC,MAAM,CAAC,QAAQ,CAAC,cAAc,CAAC,IAAI,cAAc,GAAG,KAAK,CAAC,KAAK;YAC/D,CAAC,CAAC,cAAc;YAChB,CAAC,CAAC,KAAK,CAAC,KAAK,GAAG,KAAK,CAAC,UAAU,CAAC;IACrC,MAAM,UAAU,GAAG,KAAK,CAAC,oBAAoB,KAAK,IAAI,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,oBAAoB,CAAC,CAAC;IAC7G,IAAI,MAAM,CAAC,QAAQ,CAAC,UAAU,CAAC,IAAI,UAAU,GAAG,OAAO;QAAE,OAAO,GAAG,UAAU,CAAC;IAC9E,OAAO,IAAI,IAAI,CAAC,OAAO,CAAC,CAAC,WAAW,EAAE,CAAC;AACzC,CAAC"}
@@ -1,15 +1,30 @@
1
+ import type { ClaudeProfileBilling } from './claudeProfiles';
2
+ import { type ClaudeApiSpend } from './claudeApiSpend';
1
3
  import { type ClaudeUsageSnapshot } from './claudeUsage';
2
- /** What the lines read of a profile: its usage snapshot and limit mark (a state record and a usage view both fit). */
4
+ /**
5
+ * What the lines read of a profile: its usage snapshot, limit mark, billing and used-up-credits mark (a state record and
6
+ * a usage view both fit).
7
+ */
3
8
  export interface ClaudeProfileUsageSource {
4
9
  usage?: ClaudeUsageSnapshot;
5
10
  limitedUntil?: string | null;
11
+ billing?: ClaudeProfileBilling | null;
12
+ creditExhaustedAt?: string | null;
13
+ apiSpend?: ClaudeApiSpend;
6
14
  }
7
15
  /**
8
16
  * @description The profile's usage as display lines: the windows as `used% 🔄 reset` — 5h and weekly always (`—`
9
17
  * for one the snapshot lacks), Fable only when the account HAS that window (a corporate seat has none: nothing
10
18
  * is written about it) — `(stale)` when the last poll could not refresh, and the limit mark while it holds, the
11
- * reset instant in `timezone`. The lines carry the locale's own indentation (they hang under a row); empty for a
12
- * profile never polled and not limited.
19
+ * reset instant in `timezone`, and the used-up-credits mark while it holds. An account billed to API credits has no
20
+ * windows (its row already says it pays per use): what it spent through the bot, and that mark. The lines carry the
21
+ * locale's own indentation (they hang under a row); empty for an account with nothing to show.
13
22
  */
14
23
  export declare function formatClaudeProfileUsageLines(source: ClaudeProfileUsageSource | undefined, timezone: string, nowMs: number): string[];
24
+ /** The placeholders every spend text fills: `total`, `since` (the day, in `timezone`), `last` (the last turn's). */
25
+ export declare function formatClaudeApiSpendWords(spend: ClaudeApiSpend, timezone: string, nowMs: number): {
26
+ total: string;
27
+ since: string;
28
+ last: string;
29
+ };
15
30
  //# sourceMappingURL=claudeProfileUsageLines.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"claudeProfileUsageLines.d.ts","sourceRoot":"","sources":["../../src/utils/claudeProfileUsageLines.ts"],"names":[],"mappings":"AAKA,OAAO,EAML,KAAK,mBAAmB,EACzB,MAAM,eAAe,CAAC;AAEvB,sHAAsH;AACtH,MAAM,WAAW,wBAAwB;IACvC,KAAK,CAAC,EAAE,mBAAmB,CAAC;IAC5B,YAAY,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CAC9B;AAOD;;;;;;GAMG;AACH,wBAAgB,6BAA6B,CAAC,MAAM,EAAE,wBAAwB,GAAG,SAAS,EAAE,QAAQ,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,EAAE,CAoBrI"}
1
+ {"version":3,"file":"claudeProfileUsageLines.d.ts","sourceRoot":"","sources":["../../src/utils/claudeProfileUsageLines.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,kBAAkB,CAAC;AAC7D,OAAO,EAAkC,KAAK,cAAc,EAAE,MAAM,kBAAkB,CAAC;AACvF,OAAO,EAML,KAAK,mBAAmB,EACzB,MAAM,eAAe,CAAC;AAEvB;;;GAGG;AACH,MAAM,WAAW,wBAAwB;IACvC,KAAK,CAAC,EAAE,mBAAmB,CAAC;IAC5B,YAAY,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B,OAAO,CAAC,EAAE,oBAAoB,GAAG,IAAI,CAAC;IACtC,iBAAiB,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAClC,QAAQ,CAAC,EAAE,cAAc,CAAC;CAC3B;AAOD;;;;;;;GAOG;AACH,wBAAgB,6BAA6B,CAAC,MAAM,EAAE,wBAAwB,GAAG,SAAS,EAAE,QAAQ,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,EAAE,CAuBrI;AAUD,oHAAoH;AACpH,wBAAgB,yBAAyB,CAAC,KAAK,EAAE,cAAc,EAAE,QAAQ,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,CAEhJ"}
@@ -1,11 +1,13 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.formatClaudeProfileUsageLines = formatClaudeProfileUsageLines;
4
+ exports.formatClaudeApiSpendWords = formatClaudeApiSpendWords;
4
5
  /**
5
6
  * The usage lines of one Claude account profile — what `/accounts` prints under a profile row and `/limits`
6
7
  * prints at the top of its screen. ONE renderer for both, so the two screens can never word a window differently.
7
8
  */
8
9
  const i18n_1 = require("../i18n");
10
+ const claudeApiSpend_1 = require("./claudeApiSpend");
9
11
  const claudeUsage_1 = require("./claudeUsage");
10
12
  /** The localised words of a relative reset («🔄 in 2h»). */
11
13
  function getRelativeResetWords() {
@@ -15,10 +17,13 @@ function getRelativeResetWords() {
15
17
  * @description The profile's usage as display lines: the windows as `used% 🔄 reset` — 5h and weekly always (`—`
16
18
  * for one the snapshot lacks), Fable only when the account HAS that window (a corporate seat has none: nothing
17
19
  * is written about it) — `(stale)` when the last poll could not refresh, and the limit mark while it holds, the
18
- * reset instant in `timezone`. The lines carry the locale's own indentation (they hang under a row); empty for a
19
- * profile never polled and not limited.
20
+ * reset instant in `timezone`, and the used-up-credits mark while it holds. An account billed to API credits has no
21
+ * windows (its row already says it pays per use): what it spent through the bot, and that mark. The lines carry the
22
+ * locale's own indentation (they hang under a row); empty for an account with nothing to show.
20
23
  */
21
24
  function formatClaudeProfileUsageLines(source, timezone, nowMs) {
25
+ if (source?.billing === 'api')
26
+ return formatApiBillingLines(source, timezone, nowMs);
22
27
  const lines = [];
23
28
  const usage = source?.usage;
24
29
  if (usage && usage.buckets.length > 0) {
@@ -37,6 +42,22 @@ function formatClaudeProfileUsageLines(source, timezone, nowMs) {
37
42
  if (source?.limitedUntil && Date.parse(source.limitedUntil) > nowMs) {
38
43
  lines.push((0, i18n_1.t)('account.row.limited', { until: (0, claudeUsage_1.formatClaudeUsageResetAt)(source.limitedUntil, timezone, nowMs) }));
39
44
  }
45
+ // The refusal can come from any account (its billing unrecorded, extra usage): the mark keeps it out of the chain.
46
+ if (source?.creditExhaustedAt)
47
+ lines.push((0, i18n_1.t)('account.row.creditExhausted'));
40
48
  return lines;
41
49
  }
50
+ /** The lines of an account billed to API credits: its spend through the bot, and the used-up mark while it holds. */
51
+ function formatApiBillingLines(source, timezone, nowMs) {
52
+ const lines = [];
53
+ if (source.apiSpend)
54
+ lines.push((0, i18n_1.t)('account.row.apiSpend', formatClaudeApiSpendWords(source.apiSpend, timezone, nowMs)));
55
+ if (source.creditExhaustedAt)
56
+ lines.push((0, i18n_1.t)('account.row.creditExhausted'));
57
+ return lines;
58
+ }
59
+ /** The placeholders every spend text fills: `total`, `since` (the day, in `timezone`), `last` (the last turn's). */
60
+ function formatClaudeApiSpendWords(spend, timezone, nowMs) {
61
+ return { total: (0, claudeApiSpend_1.formatUsd)(spend.totalUsd), since: (0, claudeApiSpend_1.formatSpendSinceDay)(spend.since, timezone, nowMs), last: (0, claudeApiSpend_1.formatUsd)(spend.lastTurnUsd) };
62
+ }
42
63
  //# sourceMappingURL=claudeProfileUsageLines.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"claudeProfileUsageLines.js","sourceRoot":"","sources":["../../src/utils/claudeProfileUsageLines.ts"],"names":[],"mappings":";;AAgCA,sEAoBC;AApDD;;;GAGG;AACH,kCAA4B;AAC5B,+CAOuB;AAQvB,4DAA4D;AAC5D,SAAS,qBAAqB;IAC5B,OAAO,EAAE,OAAO,EAAE,IAAA,QAAC,EAAC,eAAe,CAAC,EAAE,GAAG,EAAE,IAAA,QAAC,EAAC,eAAe,CAAC,EAAE,IAAI,EAAE,IAAA,QAAC,EAAC,gBAAgB,CAAC,EAAE,MAAM,EAAE,IAAA,QAAC,EAAC,kBAAkB,CAAC,EAAE,CAAC;AAC5H,CAAC;AAED;;;;;;GAMG;AACH,SAAgB,6BAA6B,CAAC,MAA4C,EAAE,QAAgB,EAAE,KAAa;IACzH,MAAM,KAAK,GAAa,EAAE,CAAC;IAC3B,MAAM,KAAK,GAAG,MAAM,EAAE,KAAK,CAAC;IAC5B,IAAI,KAAK,IAAI,KAAK,CAAC,OAAO,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACtC,MAAM,KAAK,GAAG,qBAAqB,EAAE,CAAC;QACtC,0FAA0F;QAC1F,MAAM,WAAW,GAAG,IAAA,kCAAoB,EAAC,KAAK,EAAE,YAAY,CAAC,EAAE,QAAQ,IAAI,IAAI,CAAC;QAChF,MAAM,IAAI,GAAG,CAAC,IAA2B,EAAE,EAAE,CAAC,IAAA,qCAAuB,EAAC,IAAA,kCAAoB,EAAC,KAAK,EAAE,IAAI,CAAC,EAAE,KAAK,EAAE;YAC9G,KAAK;YACL,gBAAgB,EAAE,IAAI,KAAK,SAAS,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,IAAI;SAC1D,CAAC,CAAC;QACH,MAAM,KAAK,GAAG,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,IAAA,QAAC,EAAC,wBAAwB,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;QAC/D,MAAM,QAAQ,GAAG,IAAA,kCAAoB,EAAC,KAAK,EAAE,eAAe,CAAC,KAAK,IAAI,CAAC;QACvE,MAAM,KAAK,GAAG,QAAQ,CAAC,CAAC,CAAC,IAAA,QAAC,EAAC,wBAAwB,EAAE,EAAE,KAAK,EAAE,IAAI,CAAC,eAAe,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;QAC5F,KAAK,CAAC,IAAI,CAAC,IAAA,QAAC,EAAC,mBAAmB,EAAE,EAAE,OAAO,EAAE,IAAI,CAAC,SAAS,CAAC,EAAE,MAAM,EAAE,IAAI,CAAC,YAAY,CAAC,EAAE,KAAK,EAAE,CAAC,GAAG,KAAK,CAAC,CAAC;IAC9G,CAAC;IACD,IAAI,MAAM,EAAE,YAAY,IAAI,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,YAAY,CAAC,GAAG,KAAK,EAAE,CAAC;QACpE,KAAK,CAAC,IAAI,CAAC,IAAA,QAAC,EAAC,qBAAqB,EAAE,EAAE,KAAK,EAAE,IAAA,sCAAwB,EAAC,MAAM,CAAC,YAAY,EAAE,QAAQ,EAAE,KAAK,CAAC,EAAE,CAAC,CAAC,CAAC;IAClH,CAAC;IACD,OAAO,KAAK,CAAC;AACf,CAAC"}
1
+ {"version":3,"file":"claudeProfileUsageLines.js","sourceRoot":"","sources":["../../src/utils/claudeProfileUsageLines.ts"],"names":[],"mappings":"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"}
@@ -1,6 +1,8 @@
1
1
  /**
2
- * @description Claude ACCOUNT PROFILES — several Claude subscription logins kept side by side, one picked per
3
- * topic (`/account`). A profile is a Claude Code config directory of its own under
2
+ * @description Claude ACCOUNT PROFILES — several Claude logins kept side by side, one picked per topic
3
+ * (`/account`): subscriptions, and accounts billed to a Claude Console organization's API credits (`billing: 'api'` —
4
+ * a console login's key in the profile's own `.claude.json`, or a pasted key the profile's `apiKeyHelper` reads; see
5
+ * the «pasted API key» helpers below). Nothing of an API account ever goes through `ANTHROPIC_API_KEY`. A profile is a Claude Code config directory of its own under
4
6
  * `DATA_DIR/claude-profiles/<name>/`, handed to the CLI through `CLAUDE_CONFIG_DIR`: the CLI keeps its
5
7
  * login (`.credentials.json`, `.claude.json`) there, while the entries that must stay ONE across accounts —
6
8
  * the transcripts (`projects/`), settings, skills, plugins and the user memory — are symlinks back into
@@ -83,6 +85,12 @@ export declare function resolveClaudeProfileName(input: {
83
85
  threadOverride: string | undefined;
84
86
  knownNames: ReadonlySet<string>;
85
87
  }): string;
88
+ /**
89
+ * How an account pays for its requests: a Claude `subscription` (claude.ai login: usage windows, no bill per request)
90
+ * or the `api` balance of a Claude Console organization (a console login's API key, or a pasted key: billed per token,
91
+ * no windows — the limit is the balance).
92
+ */
93
+ export type ClaudeProfileBilling = 'subscription' | 'api';
86
94
  /** What the account picker shows per profile, as the CLI reports it (`claude auth status --json`). */
87
95
  export interface ClaudeAuthStatus {
88
96
  loggedIn: boolean;
@@ -90,12 +98,59 @@ export interface ClaudeAuthStatus {
90
98
  /** `pro` / `max` (personal), `team` / `enterprise` (corporate), or whatever newer CLIs add. */
91
99
  subscriptionType: string | null;
92
100
  orgName: string | null;
101
+ /** The CLI's `authMethod`: `claude.ai`, `api_key`, `api_key_helper`, `oauth_token`, `third_party`, `none`; `null` on an older CLI. */
102
+ authMethod: string | null;
103
+ /** Where an API key comes from: `/login managed key` (a console login), `apiKeyHelper`, `ANTHROPIC_API_KEY`. */
104
+ apiKeySource: string | null;
105
+ /** {@link getClaudeAuthBilling} of the two above; `null` when the method says nothing about it (signed out, unknown). */
106
+ billing: ClaudeProfileBilling | null;
93
107
  }
108
+ /**
109
+ * @description The billing an auth method means: an API key in any form (`api_key` — a console login or the
110
+ * variable — and `api_key_helper`) bills the Console balance; `claude.ai` is the subscription. Anything else (signed
111
+ * out, a cloud provider, a long-lived OAuth token) is `null`: the caller keeps what it knew.
112
+ */
113
+ export declare function getClaudeAuthBilling(authMethod: string | null): ClaudeProfileBilling | null;
94
114
  /**
95
115
  * @description Parse the CLI's auth status. `null` for anything that is not the JSON object the CLI prints
96
116
  * (the probe failed, an older CLI) — the caller treats it as "unknown", never as "logged out".
97
117
  */
98
118
  export declare function parseClaudeAuthStatus(statusJson: string): ClaudeAuthStatus | null;
119
+ /** The `apiKeySource` of a key a `claude auth login --console` created and stored in the profile's own `.claude.json`. */
120
+ export declare const claudeConsoleLoginKeySource = "/login managed key";
121
+ /**
122
+ * The file a pasted Anthropic API key is kept in, inside the profile's own directory (`0600`): never in `state.json`,
123
+ * never in the environment. The CLI reads it through `apiKeyHelper` (`utils/claudeApiKeyHelper.ts`), which rides
124
+ * the profile's `--settings` only.
125
+ */
126
+ export declare const claudeProfileApiKeyFileName = "charness-api-key";
127
+ /** The launch settings of a profile that holds a pasted key: the PreCompact hook AND the `apiKeyHelper` (one file — only the last `--settings` counts). */
128
+ export declare const claudeProfileLaunchSettingsFileName = "charness-settings.json";
129
+ /** An Anthropic credential anywhere in a text (the trace preview redacts it). */
130
+ export declare const anthropicSecretInTextRe: RegExp;
131
+ /** Whether `text` (trimmed) is an Anthropic API key that can run Claude Code. */
132
+ export declare function checkIsPlausibleAnthropicApiKey(text: string): boolean;
133
+ /**
134
+ * Whether `text` carries an Anthropic credential of any kind — it starts like one, or holds one anywhere
135
+ * (`ANTHROPIC_API_KEY=sk-ant-…` copied from an env file, a key inside a sentence): it is a secret, whatever else it is.
136
+ */
137
+ export declare function checkIsAnthropicSecretLike(text: string): boolean;
138
+ /**
139
+ * The one API key a pasted text carries — the bare key, or the key inside `ANTHROPIC_API_KEY=…`, quotes or a
140
+ * sentence; `null` when it carries no API key (an admin key, an OAuth token) or more than one credential.
141
+ */
142
+ export declare function extractAnthropicApiKey(text: string): string | null;
143
+ /** The key file of a profile directory. */
144
+ export declare function resolveClaudeProfileApiKeyFile(configDir: string): string;
145
+ /** Whether the profile directory holds a pasted key (`null` = `~/.claude`, which never does: the bot writes none there). */
146
+ export declare function checkHasClaudeProfileApiKey(configDir: string | null): boolean;
147
+ /**
148
+ * @description Store a pasted key in the profile's directory: `0600`, written through a temp file and renamed, so a
149
+ * process reading it through the helper never sees half a key. The key is never logged.
150
+ */
151
+ export declare function writeClaudeProfileApiKey(configDir: string, apiKey: string): void;
152
+ /** Drop a profile's pasted key (and the launch settings that point at it); a missing file is fine. */
153
+ export declare function removeClaudeProfileApiKey(configDir: string): void;
99
154
  /**
100
155
  * @description The stdout a failed `execFile` carries, `''` for anything else. `claude auth status --json`
101
156
  * exits NON-ZERO for a logged-out directory while printing its JSON (probed on 2.1.296), so the probe's
@@ -1 +1 @@
1
- {"version":3,"file":"claudeProfiles.d.ts","sourceRoot":"","sources":["../../src/utils/claudeProfiles.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAMH,uEAAuE;AACvE,eAAO,MAAM,wBAAwB,YAAY,CAAC;AAElD,8EAA8E;AAC9E,eAAO,MAAM,qBAAqB,oBAAoB,CAAC;AAEvD;;;;;GAKG;AACH,eAAO,MAAM,0BAA0B,6DAA8D,CAAC;AACtG,eAAO,MAAM,kCAAkC,wBAAyB,CAAC;AAEzE,iGAAiG;AACjG,eAAO,MAAM,0BAA0B,KAAK,CAAC;AAG7C,wHAAwH;AACxH,eAAO,MAAM,2BAA2B,UAAU,CAAC;AAEnD;;;GAGG;AACH,wBAAgB,6BAA6B,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAEnE;AAED,2GAA2G;AAC3G,wBAAgB,0BAA0B,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAE9D;AAED,wBAAgB,yBAAyB,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAEjE;AAED;;;GAGG;AACH,wBAAgB,uBAAuB,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAGpF;AAED,qEAAqE;AACrE,wBAAgB,oBAAoB,CAAC,OAAO,GAAE,MAAqB,GAAG,MAAM,CAE3E;AAED;;;;;GAKG;AACH,wBAAgB,yBAAyB,CAAC,KAAK,EAAE;IAAE,OAAO,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,aAAa,CAAC,EAAE,MAAM,CAAA;CAAE,GAAG,MAAM,CA6BlH;AAED;;;GAGG;AACH,wBAAgB,yBAAyB,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,IAAI,CAI7E;AAED;;;;;GAKG;AACH,wBAAgB,yBAAyB,CAAC,aAAa,GAAE,MAA+B,GAAG,OAAO,CAoBjG;AAED,2GAA2G;AAC3G,wBAAgB,2BAA2B,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAGlF;AAED;;;;GAIG;AACH,wBAAgB,wBAAwB,CAAC,KAAK,EAAE;IAC9C,aAAa,EAAE,MAAM,GAAG,SAAS,CAAC;IAClC,cAAc,EAAE,MAAM,GAAG,SAAS,CAAC;IACnC,UAAU,EAAE,WAAW,CAAC,MAAM,CAAC,CAAC;CACjC,GAAG,MAAM,CAMT;AAID,sGAAsG;AACtG,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,EAAE,OAAO,CAAC;IAClB,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IACrB,+FAA+F;IAC/F,gBAAgB,EAAE,MAAM,GAAG,IAAI,CAAC;IAChC,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;CACxB;AAED;;;GAGG;AACH,wBAAgB,qBAAqB,CAAC,UAAU,EAAE,MAAM,GAAG,gBAAgB,GAAG,IAAI,CAiBjF;AAED;;;;GAIG;AACH,wBAAgB,sBAAsB,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,CAM7D;AAED,MAAM,MAAM,iBAAiB,GAAG,UAAU,GAAG,WAAW,GAAG,SAAS,CAAC;AAErE,uHAAuH;AACvH,wBAAgB,oBAAoB,CAAC,gBAAgB,EAAE,MAAM,GAAG,IAAI,GAAG,iBAAiB,CAMvF;AAID,eAAO,MAAM,2BAA2B,sBAAsB,CAAC;AAE/D;;;;;GAKG;AACH,wBAAgB,0BAA0B,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,EAAE,KAAK,EAAE,MAAM,GAAG,IAAI,GAAG,OAAO,CAQ7F;AAED;;;;;;GAMG;AACH,wBAAgB,+BAA+B,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAM9E"}
1
+ {"version":3,"file":"claudeProfiles.d.ts","sourceRoot":"","sources":["../../src/utils/claudeProfiles.ts"],"names":[],"mappings":"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"}