@kaitranntt/ccs 8.10.0-dev.17 → 8.10.0-dev.19

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/dist/cliproxy/accounts/claude-pool-policy-api.d.ts +12 -0
  2. package/dist/cliproxy/accounts/claude-pool-policy-api.d.ts.map +1 -0
  3. package/dist/cliproxy/accounts/claude-pool-policy-api.js +74 -0
  4. package/dist/cliproxy/accounts/claude-pool-policy-api.js.map +1 -0
  5. package/dist/cliproxy/accounts/claude-pool-policy-lease.d.ts +11 -0
  6. package/dist/cliproxy/accounts/claude-pool-policy-lease.d.ts.map +1 -0
  7. package/dist/cliproxy/accounts/claude-pool-policy-lease.js +55 -0
  8. package/dist/cliproxy/accounts/claude-pool-policy-lease.js.map +1 -0
  9. package/dist/cliproxy/accounts/claude-pool-policy-reconciliation.d.ts +13 -0
  10. package/dist/cliproxy/accounts/claude-pool-policy-reconciliation.d.ts.map +1 -0
  11. package/dist/cliproxy/accounts/claude-pool-policy-reconciliation.js +215 -0
  12. package/dist/cliproxy/accounts/claude-pool-policy-reconciliation.js.map +1 -0
  13. package/dist/cliproxy/accounts/claude-pool-policy-runtime.d.ts +19 -0
  14. package/dist/cliproxy/accounts/claude-pool-policy-runtime.d.ts.map +1 -0
  15. package/dist/cliproxy/accounts/claude-pool-policy-runtime.js +65 -0
  16. package/dist/cliproxy/accounts/claude-pool-policy-runtime.js.map +1 -0
  17. package/dist/cliproxy/accounts/claude-pool-policy-state.d.ts +37 -0
  18. package/dist/cliproxy/accounts/claude-pool-policy-state.d.ts.map +1 -0
  19. package/dist/cliproxy/accounts/claude-pool-policy-state.js +205 -0
  20. package/dist/cliproxy/accounts/claude-pool-policy-state.js.map +1 -0
  21. package/dist/cliproxy/accounts/claude-pool-policy.d.ts +48 -0
  22. package/dist/cliproxy/accounts/claude-pool-policy.d.ts.map +1 -0
  23. package/dist/cliproxy/accounts/claude-pool-policy.js +401 -0
  24. package/dist/cliproxy/accounts/claude-pool-policy.js.map +1 -0
  25. package/dist/cliproxy/accounts/drain-order.d.ts +1 -1
  26. package/dist/cliproxy/accounts/drain-order.d.ts.map +1 -1
  27. package/dist/cliproxy/accounts/drain-order.js +17 -0
  28. package/dist/cliproxy/accounts/drain-order.js.map +1 -1
  29. package/dist/cliproxy/accounts/pool-state.d.ts +1 -1
  30. package/dist/cliproxy/accounts/pool-state.d.ts.map +1 -1
  31. package/dist/cliproxy/accounts/registry-config.d.ts +4 -0
  32. package/dist/cliproxy/accounts/registry-config.d.ts.map +1 -0
  33. package/dist/cliproxy/accounts/registry-config.js +46 -0
  34. package/dist/cliproxy/accounts/registry-config.js.map +1 -0
  35. package/dist/cliproxy/accounts/token-file-ops.d.ts +1 -2
  36. package/dist/cliproxy/accounts/token-file-ops.d.ts.map +1 -1
  37. package/dist/cliproxy/accounts/token-file-ops.js +2 -7
  38. package/dist/cliproxy/accounts/token-file-ops.js.map +1 -1
  39. package/dist/cliproxy/accounts/types.d.ts +1 -1
  40. package/dist/cliproxy/accounts/types.d.ts.map +1 -1
  41. package/dist/cliproxy/config/generator.d.ts +2 -1
  42. package/dist/cliproxy/config/generator.d.ts.map +1 -1
  43. package/dist/cliproxy/config/generator.js +7 -2
  44. package/dist/cliproxy/config/generator.js.map +1 -1
  45. package/dist/cliproxy/quota/quota-fetcher-claude-normalizer.d.ts +17 -4
  46. package/dist/cliproxy/quota/quota-fetcher-claude-normalizer.d.ts.map +1 -1
  47. package/dist/cliproxy/quota/quota-fetcher-claude-normalizer.js +246 -153
  48. package/dist/cliproxy/quota/quota-fetcher-claude-normalizer.js.map +1 -1
  49. package/dist/cliproxy/quota/quota-fetcher-claude-probe-state.d.ts +3 -0
  50. package/dist/cliproxy/quota/quota-fetcher-claude-probe-state.d.ts.map +1 -1
  51. package/dist/cliproxy/quota/quota-fetcher-claude-probe-state.js +17 -10
  52. package/dist/cliproxy/quota/quota-fetcher-claude-probe-state.js.map +1 -1
  53. package/dist/cliproxy/quota/quota-fetcher-claude.d.ts +4 -4
  54. package/dist/cliproxy/quota/quota-fetcher-claude.d.ts.map +1 -1
  55. package/dist/cliproxy/quota/quota-fetcher-claude.js +118 -29
  56. package/dist/cliproxy/quota/quota-fetcher-claude.js.map +1 -1
  57. package/dist/cliproxy/quota/quota-label-sanitizer.d.ts +3 -2
  58. package/dist/cliproxy/quota/quota-label-sanitizer.d.ts.map +1 -1
  59. package/dist/cliproxy/quota/quota-label-sanitizer.js +6 -5
  60. package/dist/cliproxy/quota/quota-label-sanitizer.js.map +1 -1
  61. package/dist/cliproxy/quota/quota-manager.d.ts.map +1 -1
  62. package/dist/cliproxy/quota/quota-manager.js +3 -9
  63. package/dist/cliproxy/quota/quota-manager.js.map +1 -1
  64. package/dist/cliproxy/quota/quota-types.d.ts +12 -0
  65. package/dist/cliproxy/quota/quota-types.d.ts.map +1 -1
  66. package/dist/commands/cliproxy/help-subcommand.d.ts.map +1 -1
  67. package/dist/commands/cliproxy/help-subcommand.js +9 -0
  68. package/dist/commands/cliproxy/help-subcommand.js.map +1 -1
  69. package/dist/commands/cliproxy/order-subcommand.d.ts.map +1 -1
  70. package/dist/commands/cliproxy/order-subcommand.js +86 -44
  71. package/dist/commands/cliproxy/order-subcommand.js.map +1 -1
  72. package/dist/commands/cliproxy/pool-state-renderer.d.ts.map +1 -1
  73. package/dist/commands/cliproxy/pool-state-renderer.js +9 -2
  74. package/dist/commands/cliproxy/pool-state-renderer.js.map +1 -1
  75. package/dist/commands/cliproxy/quota-subcommand/claude-window-helpers.d.ts +1 -2
  76. package/dist/commands/cliproxy/quota-subcommand/claude-window-helpers.d.ts.map +1 -1
  77. package/dist/commands/cliproxy/quota-subcommand/claude-window-helpers.js +5 -16
  78. package/dist/commands/cliproxy/quota-subcommand/claude-window-helpers.js.map +1 -1
  79. package/dist/commands/cliproxy/quota-subcommand/sections/claude.d.ts.map +1 -1
  80. package/dist/commands/cliproxy/quota-subcommand/sections/claude.js +1 -1
  81. package/dist/commands/cliproxy/quota-subcommand/sections/claude.js.map +1 -1
  82. package/dist/docker/docker-bootstrap.d.ts.map +1 -1
  83. package/dist/docker/docker-bootstrap.js +29 -5
  84. package/dist/docker/docker-bootstrap.js.map +1 -1
  85. package/dist/shared/claude-pool-policy.d.ts +20 -0
  86. package/dist/shared/claude-pool-policy.d.ts.map +1 -0
  87. package/dist/shared/claude-pool-policy.js +3 -0
  88. package/dist/shared/claude-pool-policy.js.map +1 -0
  89. package/dist/ui/assets/{Trans-ButNUgI0.js → Trans-Dlb02vqu.js} +1 -1
  90. package/dist/ui/assets/{accounts-MLY7WLik.js → accounts-NMmfEBnl.js} +1 -1
  91. package/dist/ui/assets/{alert-dialog-B5gsPnVB.js → alert-dialog-CLeTz0Di.js} +1 -1
  92. package/dist/ui/assets/{api-Bz71asnK.js → api-DxGxeHbw.js} +1 -1
  93. package/dist/ui/assets/{auth-section-BqGQc4ub.js → auth-section-AI2YNrUB.js} +1 -1
  94. package/dist/ui/assets/{backups-section-BP8fVjA2.js → backups-section-CxyuzCda.js} +1 -1
  95. package/dist/ui/assets/{channels-CXItlOs8.js → channels-SBcIEMn0.js} +1 -1
  96. package/dist/ui/assets/{checkbox-D3_x-6PV.js → checkbox-C1D6YcRy.js} +1 -1
  97. package/dist/ui/assets/{claude-extension-DvAAS238.js → claude-extension-C3Ik79tl.js} +1 -1
  98. package/dist/ui/assets/{cliproxy-io8Z1slq.js → cliproxy-BySCuRxu.js} +1 -1
  99. package/dist/ui/assets/{cliproxy-ai-providers-DkgBWX_r.js → cliproxy-ai-providers-B8LPZhj3.js} +1 -1
  100. package/dist/ui/assets/{cliproxy-control-panel-C6IMwMpu.js → cliproxy-control-panel-Dsv31SI_.js} +1 -1
  101. package/dist/ui/assets/{codex-BKntGtWm.js → codex-CWZlSLEn.js} +1 -1
  102. package/dist/ui/assets/{confirm-dialog-CU4RRUuI.js → confirm-dialog-tpU9d5TR.js} +1 -1
  103. package/dist/ui/assets/{copilot-S045zi-v.js → copilot-C5uwBK-k.js} +1 -1
  104. package/dist/ui/assets/{cursor-q4VVsOHM.js → cursor-BwoYXKM4.js} +1 -1
  105. package/dist/ui/assets/{droid-C4hxPz1p.js → droid-Cv6mZctn.js} +1 -1
  106. package/dist/ui/assets/{globalenv-section-DeVJimxG.js → globalenv-section-CKc1Udhj.js} +1 -1
  107. package/dist/ui/assets/{health-D5k73-1v.js → health-Ctfcm6p0.js} +1 -1
  108. package/dist/ui/assets/{index-BJJcWQcN.js → index--TAxR0Iy.js} +1 -1
  109. package/dist/ui/assets/index-0hASk2BU.css +1 -0
  110. package/dist/ui/assets/{index-DpL-rgkN.js → index-C2ABCKof.js} +1 -1
  111. package/dist/ui/assets/{index-CSfupFf3.js → index-C5YaR--I.js} +1 -1
  112. package/dist/ui/assets/{index-9RHJNAlK.js → index-CBKaNavQ.js} +1 -1
  113. package/dist/ui/assets/{index-DQWeKrTw.js → index-DnnSa3K6.js} +1 -1
  114. package/dist/ui/assets/{index-Nd8v14jh.js → index-G9JzuSyw.js} +1 -1
  115. package/dist/ui/assets/{index-B7Y50Pmj.js → index-gX7Mi5Ws.js} +37 -37
  116. package/dist/ui/assets/{logs-DBRI0Vct.js → logs-D6LiKkzU.js} +1 -1
  117. package/dist/ui/assets/{masked-input-CO6eBTBI.js → masked-input-CmtENW5h.js} +1 -1
  118. package/dist/ui/assets/proxy-status-widget-DqVBhfEP.js +1 -0
  119. package/dist/ui/assets/{raw-json-settings-editor-panel-Czb-dWwA.js → raw-json-settings-editor-panel-C9-_RC57.js} +1 -1
  120. package/dist/ui/assets/{searchable-select-EyJfxEUO.js → searchable-select-BeEQJh2E.js} +1 -1
  121. package/dist/ui/assets/{separator-DbhOtMVl.js → separator-CB-e5SCL.js} +1 -1
  122. package/dist/ui/assets/{shared-Dx9MtTlc.js → shared-GU9wziRt.js} +1 -1
  123. package/dist/ui/assets/{table-NcM1_A4G.js → table-BFrniqUJ.js} +1 -1
  124. package/dist/ui/assets/{updates-BmhLCm82.js → updates-DYhBCREi.js} +1 -1
  125. package/dist/ui/assets/{use-accounts-sRp8XTDE.js → use-accounts-xaNW9KeG.js} +1 -1
  126. package/dist/ui/index.html +2 -2
  127. package/dist/web-server/index.d.ts +1 -1
  128. package/dist/web-server/index.d.ts.map +1 -1
  129. package/dist/web-server/index.js +4 -1
  130. package/dist/web-server/index.js.map +1 -1
  131. package/dist/web-server/routes/bar-pool-account-quota-adapter.d.ts.map +1 -1
  132. package/dist/web-server/routes/bar-pool-account-quota-adapter.js +1 -3
  133. package/dist/web-server/routes/bar-pool-account-quota-adapter.js.map +1 -1
  134. package/dist/web-server/routes/cliproxy-routing-routes.d.ts.map +1 -1
  135. package/dist/web-server/routes/cliproxy-routing-routes.js +16 -0
  136. package/dist/web-server/routes/cliproxy-routing-routes.js.map +1 -1
  137. package/dist/web-server/shutdown.d.ts +2 -3
  138. package/dist/web-server/shutdown.d.ts.map +1 -1
  139. package/dist/web-server/shutdown.js +16 -8
  140. package/dist/web-server/shutdown.js.map +1 -1
  141. package/dist/web-server/usage/native-quota-collector.d.ts.map +1 -1
  142. package/dist/web-server/usage/native-quota-collector.js +33 -65
  143. package/dist/web-server/usage/native-quota-collector.js.map +1 -1
  144. package/package.json +1 -1
  145. package/dist/ui/assets/index-h0wykXqj.css +0 -1
  146. package/dist/ui/assets/proxy-status-widget-Bfp37KO_.js +0 -1
@@ -0,0 +1,205 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || function (mod) {
19
+ if (mod && mod.__esModule) return mod;
20
+ var result = {};
21
+ if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
22
+ __setModuleDefault(result, mod);
23
+ return result;
24
+ };
25
+ Object.defineProperty(exports, "__esModule", { value: true });
26
+ exports.buildClaudePoolPolicyStatus = exports.confirmClaudePoolClass = exports.effectiveClaudePoolClass = exports.claudePoolClassPriority = exports.writeClaudePoolPolicyState = exports.readClaudePoolPolicyState = exports.createClaudePoolPolicyState = exports.getClaudePoolPolicyStatePath = exports.CLAUDE_POOL_RECONCILE_MS = exports.CLAUDE_POOL_CLASS_MAX_AGE_MS = void 0;
27
+ const error_types_1 = require("../../errors/error-types");
28
+ const fs = __importStar(require("node:fs"));
29
+ const path = __importStar(require("node:path"));
30
+ const config_manager_1 = require("../../utils/config-manager");
31
+ exports.CLAUDE_POOL_CLASS_MAX_AGE_MS = 6 * 60 * 60000;
32
+ exports.CLAUDE_POOL_RECONCILE_MS = 60000;
33
+ function getClaudePoolPolicyStatePath() {
34
+ return path.join((0, config_manager_1.getCcsDir)(), 'cache', 'claude-pool-order.json');
35
+ }
36
+ exports.getClaudePoolPolicyStatePath = getClaudePoolPolicyStatePath;
37
+ function createClaudePoolPolicyState(target) {
38
+ return {
39
+ version: 1,
40
+ target,
41
+ previousDrainOrder: null,
42
+ entries: {},
43
+ lastReconciledAt: null,
44
+ status: 'inactive',
45
+ };
46
+ }
47
+ exports.createClaudePoolPolicyState = createClaudePoolPolicyState;
48
+ /** Corrupt ownership records must never be silently replaced before mutation. */
49
+ function readClaudePoolPolicyState(file = getClaudePoolPolicyStatePath()) {
50
+ let raw;
51
+ try {
52
+ raw = fs.readFileSync(file, 'utf8');
53
+ }
54
+ catch (error) {
55
+ if (error.code === 'ENOENT')
56
+ return null;
57
+ throw new error_types_1.ConfigError('Cannot read Claude pool ownership state. Check its file permissions.');
58
+ }
59
+ try {
60
+ const state = JSON.parse(raw);
61
+ if (state.version !== 1 ||
62
+ typeof state.target !== 'string' ||
63
+ !['inactive', 'pending', 'active', 'degraded'].includes(state.status) ||
64
+ (state.lastReconciledAt !== null && !Number.isFinite(state.lastReconciledAt)) ||
65
+ (state.restoring !== undefined && typeof state.restoring !== 'boolean') ||
66
+ !state.entries ||
67
+ typeof state.entries !== 'object' ||
68
+ Array.isArray(state.entries)) {
69
+ throw new error_types_1.ConfigError('invalid state');
70
+ }
71
+ for (const entry of Object.values(state.entries)) {
72
+ if (!entry ||
73
+ typeof entry.tokenFile !== 'string' ||
74
+ !['five-hour-only', 'five-hour-weekly', 'weekly-only', 'unknown'].includes(entry.class) ||
75
+ typeof entry.ownsPriority !== 'boolean' ||
76
+ !isPriority(entry.originalPriority) ||
77
+ !isPriority(entry.lastAppliedPriority) ||
78
+ (entry.pendingPriority !== undefined && !isPriority(entry.pendingPriority)) ||
79
+ (entry.confirmedAt !== null && !Number.isFinite(entry.confirmedAt))) {
80
+ throw new error_types_1.ConfigError('invalid entry');
81
+ }
82
+ }
83
+ return state;
84
+ }
85
+ catch {
86
+ throw new error_types_1.ConfigError('Claude pool ownership state is invalid. Preserve it and repair it before changing priorities.');
87
+ }
88
+ }
89
+ exports.readClaudePoolPolicyState = readClaudePoolPolicyState;
90
+ function isPriority(value) {
91
+ return value === null || (typeof value === 'number' && Number.isSafeInteger(value));
92
+ }
93
+ function writeClaudePoolPolicyState(state, file = getClaudePoolPolicyStatePath()) {
94
+ fs.mkdirSync(path.dirname(file), { recursive: true, mode: 0o700 });
95
+ const temporary = `${file}.${process.pid}.tmp`;
96
+ try {
97
+ fs.writeFileSync(temporary, JSON.stringify(state), { mode: 0o600 });
98
+ fs.renameSync(temporary, file);
99
+ }
100
+ finally {
101
+ try {
102
+ fs.unlinkSync(temporary);
103
+ }
104
+ catch {
105
+ // A successful rename has already removed the temporary file.
106
+ }
107
+ }
108
+ }
109
+ exports.writeClaudePoolPolicyState = writeClaudePoolPolicyState;
110
+ function claudePoolClassPriority(value) {
111
+ switch (value) {
112
+ case 'five-hour-only':
113
+ return 4;
114
+ case 'five-hour-weekly':
115
+ return 3;
116
+ case 'weekly-only':
117
+ return 2;
118
+ default:
119
+ return 1;
120
+ }
121
+ }
122
+ exports.claudePoolClassPriority = claudePoolClassPriority;
123
+ function effectiveClaudePoolClass(entry, now) {
124
+ return entry.confirmedAt !== null &&
125
+ entry.confirmedAt <= now &&
126
+ now - entry.confirmedAt < exports.CLAUDE_POOL_CLASS_MAX_AGE_MS
127
+ ? entry.class
128
+ : 'unknown';
129
+ }
130
+ exports.effectiveClaudePoolClass = effectiveClaudePoolClass;
131
+ /** Only fresh, complete provider observations confirm shape, never filtered stale windows. */
132
+ function confirmClaudePoolClass(previous, quota, now) {
133
+ const presence = quota.generalWindowPresence;
134
+ if (!quota.success ||
135
+ quota.stale ||
136
+ !presence ||
137
+ !['present', 'absent', 'unknown'].includes(presence.fiveHour) ||
138
+ !['present', 'absent', 'unknown'].includes(presence.weekly) ||
139
+ presence.fiveHour === 'unknown' ||
140
+ presence.weekly === 'unknown' ||
141
+ !Number.isFinite(quota.lastUpdated) ||
142
+ quota.lastUpdated > now ||
143
+ now - quota.lastUpdated >= exports.CLAUDE_POOL_CLASS_MAX_AGE_MS ||
144
+ (previous.confirmedAt !== null && quota.lastUpdated < previous.confirmedAt))
145
+ return previous;
146
+ const hasFiveHour = presence.fiveHour === 'present';
147
+ const hasWeekly = presence.weekly === 'present';
148
+ const quotaClass = hasFiveHour
149
+ ? hasWeekly
150
+ ? 'five-hour-weekly'
151
+ : 'five-hour-only'
152
+ : hasWeekly
153
+ ? 'weekly-only'
154
+ : 'unknown';
155
+ return { class: quotaClass, confirmedAt: quota.lastUpdated };
156
+ }
157
+ exports.confirmClaudePoolClass = confirmClaudePoolClass;
158
+ function buildClaudePoolPolicyStatus(enabled, controllerActive, state, inputAccounts, now, startedAt) {
159
+ const accounts = inputAccounts.map((account) => {
160
+ const entry = state && Object.prototype.hasOwnProperty.call(state.entries, account.id)
161
+ ? state.entries[account.id]
162
+ : undefined;
163
+ const quotaClass = entry ? effectiveClaudePoolClass(entry, now) : 'unknown';
164
+ return {
165
+ accountId: account.id,
166
+ class: quotaClass,
167
+ confirmedAt: entry?.confirmedAt ?? null,
168
+ desiredPriority: claudePoolClassPriority(quotaClass),
169
+ effectivePriority: entry?.effectivePriority !== undefined
170
+ ? entry.effectivePriority
171
+ : (entry?.lastAppliedPriority ?? null),
172
+ state: account.paused
173
+ ? 'paused'
174
+ : (entry?.state ?? (entry?.ownsPriority ? 'applied' : 'pending')),
175
+ };
176
+ });
177
+ let status = enabled
178
+ ? !controllerActive
179
+ ? 'pending'
180
+ : (state?.status ?? 'pending')
181
+ : state?.restoring || state?.status === 'degraded'
182
+ ? 'degraded'
183
+ : 'inactive';
184
+ if (enabled && status === 'active') {
185
+ if (state?.lastReconciledAt === null ||
186
+ (startedAt !== undefined && (state?.lastReconciledAt ?? 0) < startedAt) ||
187
+ accounts.some((account) => account.state !== 'paused' && account.effectivePriority !== account.desiredPriority))
188
+ status = 'pending';
189
+ }
190
+ return {
191
+ enabled,
192
+ status,
193
+ controllerActive,
194
+ lastReconciledAt: state?.lastReconciledAt ?? null,
195
+ ...(state?.error ? { error: state.error } : {}),
196
+ ...(!controllerActive && enabled
197
+ ? {
198
+ error: 'No persistent CCS controller is available. Run the dashboard or integrated Docker service.',
199
+ }
200
+ : {}),
201
+ accounts,
202
+ };
203
+ }
204
+ exports.buildClaudePoolPolicyStatus = buildClaudePoolPolicyStatus;
205
+ //# sourceMappingURL=claude-pool-policy-state.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"claude-pool-policy-state.js","sourceRoot":"","sources":["../../../src/cliproxy/accounts/claude-pool-policy-state.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,48 @@
1
+ import type { ClaudePoolPolicyStatus } from '../../shared/claude-pool-policy';
2
+ import { type ClaudePoolPolicyDependencies } from './claude-pool-policy-runtime';
3
+ export type { ClaudePoolPolicyDependencies } from './claude-pool-policy-runtime';
4
+ /** A controller lease and a separate mutation mutex coordinate different CCS processes. */
5
+ export declare class ClaudePoolPolicyController {
6
+ private readonly deps;
7
+ private readonly owner;
8
+ private releaseLeadership;
9
+ private heartbeat;
10
+ private interval;
11
+ private stopped;
12
+ private compromised;
13
+ private busy;
14
+ private activeCycle;
15
+ private readonly activeMutations;
16
+ private startedAt;
17
+ private lifecycleAbort;
18
+ private readonly manualMutation;
19
+ constructor(overrides?: Partial<ClaudePoolPolicyDependencies>);
20
+ private get leaseFile();
21
+ private get ownerFile();
22
+ private get mutationFile();
23
+ private readState;
24
+ private writeState;
25
+ private reconciliationContext;
26
+ private controllerActive;
27
+ private renewLease;
28
+ private withMutation;
29
+ private verifiedApi;
30
+ getStatus(): ClaudePoolPolicyStatus;
31
+ setEnabled(enabled: boolean): Promise<ClaudePoolPolicyStatus>;
32
+ /** Explicit manual changes supersede this policy without restoring over the chosen order. */
33
+ relinquishForManualOrder(): Promise<void>;
34
+ /** Keep the mutex through validation, priority application and manual-config commit. */
35
+ withManualOrder<T>(operation: () => Promise<T>): Promise<T>;
36
+ /** Public deterministic cycle used by lifecycle hooks and synthetic tests. */
37
+ reconcile(valid?: () => boolean): Promise<void>;
38
+ private release;
39
+ private tick;
40
+ private launchTick;
41
+ /** Wake a running controller without overlapping its current cycle. */
42
+ wake(): Promise<void>;
43
+ start(): () => Promise<void>;
44
+ stop(): Promise<void>;
45
+ }
46
+ export declare function getClaudePoolPolicyController(): ClaudePoolPolicyController;
47
+ export declare function startClaudePoolPolicyController(): () => Promise<void>;
48
+ //# sourceMappingURL=claude-pool-policy.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"claude-pool-policy.d.ts","sourceRoot":"","sources":["../../../src/cliproxy/accounts/claude-pool-policy.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,iCAAiC,CAAC;AAa9E,OAAO,EAEL,KAAK,4BAA4B,EAClC,MAAM,8BAA8B,CAAC;AAMtC,YAAY,EAAE,4BAA4B,EAAE,MAAM,8BAA8B,CAAC;AAwBjF,2FAA2F;AAC3F,qBAAa,0BAA0B;IACrC,OAAO,CAAC,QAAQ,CAAC,IAAI,CAA+B;IACpD,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAgB;IACtC,OAAO,CAAC,iBAAiB,CAAsC;IAC/D,OAAO,CAAC,SAAS,CAA+C;IAChE,OAAO,CAAC,QAAQ,CAA+C;IAC/D,OAAO,CAAC,OAAO,CAAQ;IACvB,OAAO,CAAC,WAAW,CAAS;IAC5B,OAAO,CAAC,IAAI,CAAS;IACrB,OAAO,CAAC,WAAW,CAA8B;IACjD,OAAO,CAAC,QAAQ,CAAC,eAAe,CAA4B;IAC5D,OAAO,CAAC,SAAS,CAAK;IACtB,OAAO,CAAC,cAAc,CAAyB;IAC/C,OAAO,CAAC,QAAQ,CAAC,cAAc,CAAoC;gBAEvD,SAAS,GAAE,OAAO,CAAC,4BAA4B,CAAM;IAIjE,OAAO,KAAK,SAAS,GAEpB;IACD,OAAO,KAAK,SAAS,GAEpB;IACD,OAAO,KAAK,YAAY,GAEvB;IAED,OAAO,CAAC,SAAS;IAIjB,OAAO,CAAC,UAAU;IAIlB,OAAO,CAAC,qBAAqB;IAS7B,OAAO,CAAC,gBAAgB;IAWxB,OAAO,CAAC,UAAU;YAaJ,YAAY;YAqCZ,WAAW;IAiBzB,SAAS,IAAI,sBAAsB;IA8B7B,UAAU,CAAC,OAAO,EAAE,OAAO,GAAG,OAAO,CAAC,sBAAsB,CAAC;IA0DnE,6FAA6F;IACvF,wBAAwB,IAAI,OAAO,CAAC,IAAI,CAAC;IAyB/C,wFAAwF;IAClF,eAAe,CAAC,CAAC,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC;IAIjE,8EAA8E;IACxE,SAAS,CAAC,KAAK,GAAE,MAAM,OAAoB,GAAG,OAAO,CAAC,IAAI,CAAC;YAuBnD,OAAO;YAgBP,IAAI;IA4ClB,OAAO,CAAC,UAAU;IAOlB,uEAAuE;IACjE,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;IAM3B,KAAK,IAAI,MAAM,OAAO,CAAC,IAAI,CAAC;IAatB,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;CAS5B;AAID,wBAAgB,6BAA6B,IAAI,0BAA0B,CAQ1E;AAED,wBAAgB,+BAA+B,IAAI,MAAM,OAAO,CAAC,IAAI,CAAC,CAErE"}
@@ -0,0 +1,401 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || function (mod) {
19
+ if (mod && mod.__esModule) return mod;
20
+ var result = {};
21
+ if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
22
+ __setModuleDefault(result, mod);
23
+ return result;
24
+ };
25
+ Object.defineProperty(exports, "__esModule", { value: true });
26
+ exports.startClaudePoolPolicyController = exports.getClaudePoolPolicyController = exports.ClaudePoolPolicyController = void 0;
27
+ const error_types_1 = require("../../errors/error-types");
28
+ const fs = __importStar(require("node:fs"));
29
+ const path = __importStar(require("node:path"));
30
+ const os = __importStar(require("node:os"));
31
+ const node_crypto_1 = require("node:crypto");
32
+ const node_async_hooks_1 = require("node:async_hooks");
33
+ const lockfile = __importStar(require("proper-lockfile"));
34
+ const claude_pool_policy_state_1 = require("./claude-pool-policy-state");
35
+ const claude_pool_policy_runtime_1 = require("./claude-pool-policy-runtime");
36
+ const claude_pool_policy_reconciliation_1 = require("./claude-pool-policy-reconciliation");
37
+ const claude_pool_policy_lease_1 = require("./claude-pool-policy-lease");
38
+ const LEASE_STALE_MS = 30000;
39
+ const HEARTBEAT_MS = 5000;
40
+ function targetKey(target) {
41
+ return `${target.protocol}://${target.host}:${target.port}`;
42
+ }
43
+ function ensureLockTarget(file) {
44
+ fs.mkdirSync(path.dirname(file), { recursive: true, mode: 0o700 });
45
+ try {
46
+ fs.writeFileSync(file, '', { flag: 'wx', mode: 0o600 });
47
+ }
48
+ catch (error) {
49
+ if (error.code !== 'EEXIST')
50
+ throw error;
51
+ }
52
+ }
53
+ /** A controller lease and a separate mutation mutex coordinate different CCS processes. */
54
+ class ClaudePoolPolicyController {
55
+ constructor(overrides = {}) {
56
+ this.owner = (0, node_crypto_1.randomUUID)();
57
+ this.releaseLeadership = null;
58
+ this.heartbeat = null;
59
+ this.interval = null;
60
+ this.stopped = true;
61
+ this.compromised = false;
62
+ this.busy = false;
63
+ this.activeCycle = null;
64
+ this.activeMutations = new Set();
65
+ this.startedAt = 0;
66
+ this.lifecycleAbort = new AbortController();
67
+ this.manualMutation = new node_async_hooks_1.AsyncLocalStorage();
68
+ this.deps = (0, claude_pool_policy_runtime_1.createClaudePoolPolicyDependencies)(overrides);
69
+ }
70
+ get leaseFile() {
71
+ return `${this.deps.file}.controller`;
72
+ }
73
+ get ownerFile() {
74
+ return `${this.leaseFile}.owner`;
75
+ }
76
+ get mutationFile() {
77
+ return `${this.deps.file}.mutation`;
78
+ }
79
+ readState() {
80
+ return (0, claude_pool_policy_state_1.readClaudePoolPolicyState)(this.deps.file);
81
+ }
82
+ writeState(state) {
83
+ (0, claude_pool_policy_state_1.writeClaudePoolPolicyState)(state, this.deps.file);
84
+ }
85
+ reconciliationContext() {
86
+ return {
87
+ deps: this.deps,
88
+ readState: () => this.readState(),
89
+ writeState: (state) => this.writeState(state),
90
+ signal: this.lifecycleAbort.signal,
91
+ };
92
+ }
93
+ controllerActive() {
94
+ return ((0, claude_pool_policy_lease_1.readActiveClaudePoolControllerLease)(this.ownerFile, targetKey(this.deps.target()), this.deps.now(), LEASE_STALE_MS) !== null);
95
+ }
96
+ renewLease() {
97
+ if (!this.releaseLeadership || this.compromised)
98
+ return;
99
+ const lease = {
100
+ owner: this.owner,
101
+ pid: process.pid,
102
+ hostname: os.hostname(),
103
+ target: targetKey(this.deps.target()),
104
+ updatedAt: this.deps.now(),
105
+ startedAt: this.startedAt,
106
+ };
107
+ (0, claude_pool_policy_lease_1.writeClaudePoolControllerLease)(this.ownerFile, lease);
108
+ }
109
+ async withMutation(operation) {
110
+ let complete = () => { };
111
+ const completion = new Promise((resolve) => {
112
+ complete = resolve;
113
+ });
114
+ this.activeMutations.add(completion);
115
+ try {
116
+ ensureLockTarget(this.mutationFile);
117
+ let compromised = false;
118
+ const release = await lockfile
119
+ .lock(this.mutationFile, {
120
+ realpath: false,
121
+ stale: LEASE_STALE_MS,
122
+ update: HEARTBEAT_MS,
123
+ retries: { retries: 50, minTimeout: 100, maxTimeout: 100 },
124
+ onCompromised: () => {
125
+ compromised = true;
126
+ },
127
+ })
128
+ .catch(() => {
129
+ throw new error_types_1.ConfigError('Another CCS process is updating Claude pool order. Retry after the current operation finishes.');
130
+ });
131
+ try {
132
+ if (compromised)
133
+ throw new error_types_1.ConfigError('Claude pool mutation ownership was lost. Retry the operation.');
134
+ return await operation(() => !compromised);
135
+ }
136
+ finally {
137
+ await release().catch(() => { });
138
+ }
139
+ }
140
+ finally {
141
+ complete();
142
+ this.activeMutations.delete(completion);
143
+ }
144
+ }
145
+ async verifiedApi() {
146
+ const target = this.deps.target();
147
+ if (target.isRemote || !['127.0.0.1', 'localhost', '::1'].includes(target.host)) {
148
+ throw new error_types_1.ConfigError('Claude quota ordering must be configured on the host running the local proxy.');
149
+ }
150
+ if (!(await this.deps.verifyProxy(target))) {
151
+ throw new error_types_1.ConfigError('The local proxy must be running and verified before changing Claude quota ordering.');
152
+ }
153
+ const api = this.deps.management(target, this.lifecycleAbort.signal);
154
+ await api.checkCapabilities();
155
+ return { api, target };
156
+ }
157
+ getStatus() {
158
+ const enabled = this.deps.drainOrder()?.mode === 'quota';
159
+ const controllerActive = this.controllerActive();
160
+ try {
161
+ const lease = (0, claude_pool_policy_lease_1.readActiveClaudePoolControllerLease)(this.ownerFile, targetKey(this.deps.target()), this.deps.now(), LEASE_STALE_MS);
162
+ return (0, claude_pool_policy_state_1.buildClaudePoolPolicyStatus)(enabled, controllerActive, this.readState(), this.deps.accounts(), this.deps.now(), lease?.startedAt);
163
+ }
164
+ catch (error) {
165
+ return {
166
+ enabled,
167
+ status: 'degraded',
168
+ controllerActive,
169
+ lastReconciledAt: null,
170
+ error: error.message,
171
+ accounts: [],
172
+ };
173
+ }
174
+ }
175
+ async setEnabled(enabled) {
176
+ await this.withMutation(async (valid) => {
177
+ const { api, target } = await this.verifiedApi();
178
+ if (enabled) {
179
+ if (!this.deps.poolEnabled())
180
+ throw new error_types_1.ConfigError('Enable pool routing before enabling Claude quota ordering.');
181
+ if (!this.controllerActive())
182
+ throw new error_types_1.ConfigError('Start a persistent CCS dashboard or integrated Docker service before enabling quota ordering.');
183
+ if (this.deps.drainOrder()?.mode !== 'quota') {
184
+ const retained = this.readState();
185
+ if (retained?.restoring)
186
+ throw new error_types_1.ConfigError('Previous Claude priority restoration is pending. Resolve it before enabling the policy.');
187
+ const state = (0, claude_pool_policy_state_1.createClaudePoolPolicyState)(targetKey(target));
188
+ state.previousDrainOrder = this.deps.drainOrder() ?? null;
189
+ state.status = 'pending';
190
+ // Commit the ownership snapshot before enabling the config or writing any priority.
191
+ this.writeState(state);
192
+ this.deps.saveDrainOrder({ mode: 'quota' });
193
+ try {
194
+ await this.deps.regenerate(target);
195
+ }
196
+ catch (error) {
197
+ this.deps.saveDrainOrder(state.previousDrainOrder);
198
+ state.status = 'degraded';
199
+ state.error =
200
+ 'Could not regenerate proxy configuration. The quota policy was not enabled.';
201
+ this.writeState(state);
202
+ throw error;
203
+ }
204
+ }
205
+ await (0, claude_pool_policy_reconciliation_1.reconcileClaudePoolPriorities)(this.reconciliationContext(), api, target, valid);
206
+ }
207
+ else {
208
+ const state = this.readState();
209
+ if (!state) {
210
+ if (this.deps.drainOrder()?.mode === 'quota')
211
+ throw new error_types_1.ConfigError('Claude quota ownership state is missing. Preserve priorities and repair state before disabling.');
212
+ return;
213
+ }
214
+ if (state.target !== targetKey(target))
215
+ throw new error_types_1.ConfigError('Restore the original local proxy target before restoring Claude pool priorities.');
216
+ if (this.deps.drainOrder()?.mode === 'quota')
217
+ this.deps.saveDrainOrder(state.previousDrainOrder);
218
+ state.restoring = true;
219
+ this.writeState(state);
220
+ await this.deps.regenerate(target);
221
+ await (0, claude_pool_policy_reconciliation_1.restoreClaudePoolPriorities)(this.reconciliationContext(), state, api, valid);
222
+ }
223
+ });
224
+ return this.getStatus();
225
+ }
226
+ /** Explicit manual changes supersede this policy without restoring over the chosen order. */
227
+ async relinquishForManualOrder() {
228
+ const relinquish = async () => {
229
+ if (this.deps.drainOrder()?.mode !== 'quota' && !this.readState()?.restoring)
230
+ return;
231
+ const state = this.readState();
232
+ if (state && state.target !== targetKey(this.deps.target()))
233
+ throw new error_types_1.ConfigError('Restore the original local proxy target before changing Claude pool ownership.');
234
+ this.deps.saveDrainOrder(null);
235
+ if (state) {
236
+ for (const entry of Object.values(state.entries)) {
237
+ entry.ownsPriority = false;
238
+ delete entry.pendingPriority;
239
+ }
240
+ state.restoring = false;
241
+ state.status = 'inactive';
242
+ delete state.error;
243
+ this.writeState(state);
244
+ }
245
+ await this.deps.regenerate(this.deps.target());
246
+ };
247
+ if (this.manualMutation.getStore())
248
+ await relinquish();
249
+ else
250
+ await this.withMutation(relinquish);
251
+ }
252
+ /** Keep the mutex through validation, priority application and manual-config commit. */
253
+ async withManualOrder(operation) {
254
+ return this.withMutation(async () => this.manualMutation.run(true, operation));
255
+ }
256
+ /** Public deterministic cycle used by lifecycle hooks and synthetic tests. */
257
+ async reconcile(valid = () => true) {
258
+ await this.withMutation(async (mutationValid) => {
259
+ if (this.deps.drainOrder()?.mode !== 'quota' && !this.readState()?.restoring)
260
+ return;
261
+ try {
262
+ const { api, target } = await this.verifiedApi();
263
+ await (0, claude_pool_policy_reconciliation_1.reconcileClaudePoolPriorities)(this.reconciliationContext(), api, target, () => valid() && mutationValid());
264
+ }
265
+ catch (error) {
266
+ const state = this.readState();
267
+ if (state) {
268
+ state.status = 'degraded';
269
+ state.error = error.message;
270
+ this.writeState(state);
271
+ }
272
+ throw error;
273
+ }
274
+ });
275
+ }
276
+ async release() {
277
+ const release = this.releaseLeadership;
278
+ this.releaseLeadership = null;
279
+ if (this.heartbeat)
280
+ clearInterval(this.heartbeat);
281
+ this.heartbeat = null;
282
+ try {
283
+ const owner = JSON.parse(fs.readFileSync(this.ownerFile, 'utf8'));
284
+ if (owner.owner === this.owner)
285
+ fs.unlinkSync(this.ownerFile);
286
+ }
287
+ catch {
288
+ /* Another owner or process cleanup already removed the lease. */
289
+ }
290
+ if (release)
291
+ await release().catch(() => { });
292
+ }
293
+ async tick() {
294
+ if (this.stopped || this.busy)
295
+ return;
296
+ this.busy = true;
297
+ try {
298
+ if (this.deps.target().isRemote) {
299
+ await this.release();
300
+ return;
301
+ }
302
+ if (!this.releaseLeadership) {
303
+ ensureLockTarget(this.leaseFile);
304
+ try {
305
+ this.compromised = false;
306
+ this.releaseLeadership = await lockfile.lock(this.leaseFile, {
307
+ realpath: false,
308
+ stale: LEASE_STALE_MS,
309
+ update: HEARTBEAT_MS,
310
+ retries: 0,
311
+ onCompromised: () => {
312
+ this.compromised = true;
313
+ },
314
+ });
315
+ }
316
+ catch {
317
+ return;
318
+ }
319
+ this.renewLease();
320
+ this.heartbeat = setInterval(() => {
321
+ try {
322
+ this.renewLease();
323
+ }
324
+ catch {
325
+ this.compromised = true;
326
+ }
327
+ }, HEARTBEAT_MS);
328
+ this.heartbeat.unref();
329
+ }
330
+ const valid = () => !this.stopped && !this.compromised && this.releaseLeadership !== null;
331
+ if (valid())
332
+ await this.reconcile(valid);
333
+ }
334
+ catch {
335
+ // The persisted status carries the actionable error; the next cycle retries safely.
336
+ }
337
+ finally {
338
+ this.busy = false;
339
+ if (this.stopped || this.compromised)
340
+ await this.release();
341
+ }
342
+ }
343
+ launchTick() {
344
+ if (this.activeCycle)
345
+ return;
346
+ this.activeCycle = this.tick().finally(() => {
347
+ this.activeCycle = null;
348
+ });
349
+ }
350
+ /** Wake a running controller without overlapping its current cycle. */
351
+ async wake() {
352
+ if (this.stopped)
353
+ return;
354
+ this.launchTick();
355
+ if (this.activeCycle)
356
+ await this.activeCycle;
357
+ }
358
+ start() {
359
+ if (!this.stopped)
360
+ return () => this.stop();
361
+ this.stopped = false;
362
+ if (this.lifecycleAbort.signal.aborted)
363
+ this.lifecycleAbort = new AbortController();
364
+ this.startedAt = this.deps.now();
365
+ this.launchTick();
366
+ this.interval = setInterval(() => {
367
+ this.launchTick();
368
+ }, claude_pool_policy_state_1.CLAUDE_POOL_RECONCILE_MS);
369
+ this.interval.unref();
370
+ return () => this.stop();
371
+ }
372
+ async stop() {
373
+ this.stopped = true;
374
+ this.lifecycleAbort.abort();
375
+ if (this.interval)
376
+ clearInterval(this.interval);
377
+ this.interval = null;
378
+ if (this.activeCycle)
379
+ await this.activeCycle;
380
+ while (this.activeMutations.size > 0)
381
+ await Promise.all([...this.activeMutations]);
382
+ await this.release();
383
+ }
384
+ }
385
+ exports.ClaudePoolPolicyController = ClaudePoolPolicyController;
386
+ const controllers = new Map();
387
+ function getClaudePoolPolicyController() {
388
+ const file = (0, claude_pool_policy_state_1.getClaudePoolPolicyStatePath)();
389
+ let controller = controllers.get(file);
390
+ if (!controller) {
391
+ controller = new ClaudePoolPolicyController({ file });
392
+ controllers.set(file, controller);
393
+ }
394
+ return controller;
395
+ }
396
+ exports.getClaudePoolPolicyController = getClaudePoolPolicyController;
397
+ function startClaudePoolPolicyController() {
398
+ return getClaudePoolPolicyController().start();
399
+ }
400
+ exports.startClaudePoolPolicyController = startClaudePoolPolicyController;
401
+ //# sourceMappingURL=claude-pool-policy.js.map