@kaitranntt/ccs 6.7.0-dev.2 → 6.7.0-dev.4
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.
- package/dist/cliproxy/cliproxy-executor.d.ts.map +1 -1
- package/dist/cliproxy/cliproxy-executor.js +59 -48
- package/dist/cliproxy/cliproxy-executor.js.map +1 -1
- package/dist/cliproxy/index.d.ts +4 -0
- package/dist/cliproxy/index.d.ts.map +1 -1
- package/dist/cliproxy/index.js +8 -1
- package/dist/cliproxy/index.js.map +1 -1
- package/dist/cliproxy/proxy-detector.d.ts +70 -0
- package/dist/cliproxy/proxy-detector.d.ts.map +1 -0
- package/dist/cliproxy/proxy-detector.js +177 -0
- package/dist/cliproxy/proxy-detector.js.map +1 -0
- package/dist/cliproxy/service-manager.d.ts.map +1 -1
- package/dist/cliproxy/service-manager.js +113 -86
- package/dist/cliproxy/service-manager.js.map +1 -1
- package/dist/cliproxy/startup-lock.d.ts +57 -0
- package/dist/cliproxy/startup-lock.d.ts.map +1 -0
- package/dist/cliproxy/startup-lock.js +216 -0
- package/dist/cliproxy/startup-lock.js.map +1 -0
- package/dist/management/recovery-manager.d.ts +26 -1
- package/dist/management/recovery-manager.d.ts.map +1 -1
- package/dist/management/recovery-manager.js +182 -6
- package/dist/management/recovery-manager.js.map +1 -1
- package/package.json +1 -1
|
@@ -40,8 +40,10 @@ const child_process_1 = require("child_process");
|
|
|
40
40
|
const net = __importStar(require("net"));
|
|
41
41
|
const binary_manager_1 = require("./binary-manager");
|
|
42
42
|
const config_generator_1 = require("./config-generator");
|
|
43
|
-
const stats_fetcher_1 = require("./stats-fetcher");
|
|
44
43
|
const session_tracker_1 = require("./session-tracker");
|
|
44
|
+
const proxy_detector_1 = require("./proxy-detector");
|
|
45
|
+
const startup_lock_1 = require("./startup-lock");
|
|
46
|
+
const stats_fetcher_1 = require("./stats-fetcher");
|
|
45
47
|
/** Background proxy process reference */
|
|
46
48
|
let proxyProcess = null;
|
|
47
49
|
/** Cleanup registered flag */
|
|
@@ -108,9 +110,6 @@ async function ensureCliproxyService(port = config_generator_1.CLIPROXY_DEFAULT_
|
|
|
108
110
|
console.error(`[cliproxy-service] ${msg}`);
|
|
109
111
|
}
|
|
110
112
|
};
|
|
111
|
-
// Check if already running (from another process or previous start)
|
|
112
|
-
log(`Checking if CLIProxy is running on port ${port}...`);
|
|
113
|
-
const running = await (0, stats_fetcher_1.isCliproxyRunning)(port);
|
|
114
113
|
// Check if config needs update (even if running)
|
|
115
114
|
let configRegenerated = false;
|
|
116
115
|
if ((0, config_generator_1.configNeedsRegeneration)()) {
|
|
@@ -118,92 +117,120 @@ async function ensureCliproxyService(port = config_generator_1.CLIPROXY_DEFAULT_
|
|
|
118
117
|
(0, config_generator_1.regenerateConfig)(port);
|
|
119
118
|
configRegenerated = true;
|
|
120
119
|
}
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
120
|
+
// Use startup lock to coordinate with other CCS processes (ccs agy, ccs config, etc.)
|
|
121
|
+
return await (0, startup_lock_1.withStartupLock)(async () => {
|
|
122
|
+
// Use unified detection (HTTP check + session-lock + port-process)
|
|
123
|
+
log(`Checking if CLIProxy is running on port ${port}...`);
|
|
124
|
+
const proxyStatus = await (0, proxy_detector_1.detectRunningProxy)(port);
|
|
125
|
+
log(`Proxy detection: ${JSON.stringify(proxyStatus)}`);
|
|
126
|
+
if (proxyStatus.running && proxyStatus.verified) {
|
|
127
|
+
// Already running and healthy
|
|
128
|
+
log('CLIProxy already running');
|
|
129
|
+
if (configRegenerated) {
|
|
130
|
+
log('Config was updated - running instance will use new config on next restart');
|
|
131
|
+
}
|
|
132
|
+
return { started: true, alreadyRunning: true, port, configRegenerated };
|
|
125
133
|
}
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
//
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
134
|
+
if (proxyStatus.running && !proxyStatus.verified) {
|
|
135
|
+
// Proxy detected but not ready yet (another process is starting it)
|
|
136
|
+
log(`Proxy starting up (detected via ${proxyStatus.method}), waiting...`);
|
|
137
|
+
const becameHealthy = await (0, proxy_detector_1.waitForProxyHealthy)(port, 5000);
|
|
138
|
+
if (becameHealthy) {
|
|
139
|
+
log('Proxy became healthy');
|
|
140
|
+
return { started: true, alreadyRunning: true, port, configRegenerated };
|
|
141
|
+
}
|
|
142
|
+
// Proxy didn't become healthy - will try to start fresh below
|
|
143
|
+
log('Proxy detected but not responding, will start fresh');
|
|
144
|
+
}
|
|
145
|
+
if (proxyStatus.blocked) {
|
|
146
|
+
// Port blocked by non-CLIProxy process - try HTTP as last resort
|
|
147
|
+
const isActuallyOurs = await (0, proxy_detector_1.waitForProxyHealthy)(port, 1000);
|
|
148
|
+
if (isActuallyOurs) {
|
|
149
|
+
log('Reclaimed CLIProxy with unrecognized process name');
|
|
150
|
+
return { started: true, alreadyRunning: true, port, configRegenerated };
|
|
151
|
+
}
|
|
152
|
+
// Truly blocked
|
|
153
|
+
return {
|
|
154
|
+
started: false,
|
|
155
|
+
alreadyRunning: false,
|
|
156
|
+
port,
|
|
157
|
+
error: `Port ${port} is blocked by ${proxyStatus.blocker?.processName}`,
|
|
158
|
+
};
|
|
159
|
+
}
|
|
160
|
+
// Need to start new instance
|
|
161
|
+
log('CLIProxy not running, starting background instance...');
|
|
162
|
+
// 1. Ensure binary exists
|
|
163
|
+
let binaryPath;
|
|
164
|
+
try {
|
|
165
|
+
binaryPath = await (0, binary_manager_1.ensureCLIProxyBinary)(verbose);
|
|
166
|
+
log(`Binary ready: ${binaryPath}`);
|
|
167
|
+
}
|
|
168
|
+
catch (error) {
|
|
169
|
+
const err = error;
|
|
170
|
+
return {
|
|
171
|
+
started: false,
|
|
172
|
+
alreadyRunning: false,
|
|
173
|
+
port,
|
|
174
|
+
error: `Failed to prepare binary: ${err.message}`,
|
|
175
|
+
};
|
|
176
|
+
}
|
|
177
|
+
// 2. Ensure/regenerate config if needed
|
|
178
|
+
let configPath;
|
|
179
|
+
if ((0, config_generator_1.configNeedsRegeneration)()) {
|
|
180
|
+
log('Config needs regeneration, updating...');
|
|
181
|
+
configPath = (0, config_generator_1.regenerateConfig)(port);
|
|
182
|
+
}
|
|
183
|
+
else {
|
|
184
|
+
configPath = (0, config_generator_1.generateConfig)('gemini', port);
|
|
185
|
+
}
|
|
186
|
+
log(`Config ready: ${configPath}`);
|
|
187
|
+
// 3. Spawn background process
|
|
188
|
+
const proxyArgs = ['--config', configPath];
|
|
189
|
+
log(`Spawning: ${binaryPath} ${proxyArgs.join(' ')}`);
|
|
190
|
+
proxyProcess = (0, child_process_1.spawn)(binaryPath, proxyArgs, {
|
|
191
|
+
stdio: ['ignore', verbose ? 'pipe' : 'ignore', verbose ? 'pipe' : 'ignore'],
|
|
192
|
+
detached: true,
|
|
193
|
+
env: {
|
|
194
|
+
...process.env,
|
|
195
|
+
WRITABLE_PATH: (0, config_generator_1.getCliproxyWritablePath)(),
|
|
196
|
+
},
|
|
171
197
|
});
|
|
172
|
-
|
|
173
|
-
|
|
198
|
+
if (verbose) {
|
|
199
|
+
proxyProcess.stdout?.on('data', (data) => {
|
|
200
|
+
process.stderr.write(`[cliproxy] ${data.toString()}`);
|
|
201
|
+
});
|
|
202
|
+
proxyProcess.stderr?.on('data', (data) => {
|
|
203
|
+
process.stderr.write(`[cliproxy-err] ${data.toString()}`);
|
|
204
|
+
});
|
|
205
|
+
}
|
|
206
|
+
proxyProcess.unref();
|
|
207
|
+
proxyProcess.on('error', (error) => {
|
|
208
|
+
log(`Spawn error: ${error.message}`);
|
|
174
209
|
});
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
proxyProcess.kill('SIGTERM');
|
|
191
|
-
proxyProcess = null;
|
|
210
|
+
registerCleanup();
|
|
211
|
+
// 4. Wait for proxy to be ready
|
|
212
|
+
log(`Waiting for CLIProxy on port ${port}...`);
|
|
213
|
+
const ready = await waitForPort(port, 5000);
|
|
214
|
+
if (!ready) {
|
|
215
|
+
if (proxyProcess && !proxyProcess.killed) {
|
|
216
|
+
proxyProcess.kill('SIGTERM');
|
|
217
|
+
proxyProcess = null;
|
|
218
|
+
}
|
|
219
|
+
return {
|
|
220
|
+
started: false,
|
|
221
|
+
alreadyRunning: false,
|
|
222
|
+
port,
|
|
223
|
+
error: `CLIProxy failed to start within 5s on port ${port}`,
|
|
224
|
+
};
|
|
192
225
|
}
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
port,
|
|
197
|
-
|
|
198
|
-
}
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
// 5. Register session so stopProxy() can find and kill this process
|
|
202
|
-
if (proxyProcess.pid) {
|
|
203
|
-
(0, session_tracker_1.registerSession)(port, proxyProcess.pid);
|
|
204
|
-
log(`Session registered for PID ${proxyProcess.pid}`);
|
|
205
|
-
}
|
|
206
|
-
return { started: true, alreadyRunning: false, port };
|
|
226
|
+
log(`CLIProxy service started on port ${port}`);
|
|
227
|
+
// 5. Register session
|
|
228
|
+
if (proxyProcess.pid) {
|
|
229
|
+
(0, session_tracker_1.registerSession)(port, proxyProcess.pid);
|
|
230
|
+
log(`Session registered for PID ${proxyProcess.pid}`);
|
|
231
|
+
}
|
|
232
|
+
return { started: true, alreadyRunning: false, port };
|
|
233
|
+
});
|
|
207
234
|
}
|
|
208
235
|
exports.ensureCliproxyService = ensureCliproxyService;
|
|
209
236
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"service-manager.js","sourceRoot":"","sources":["../../src/cliproxy/service-manager.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;;GAWG;;;;;;;;;;;;;;;;;;;;;;;;;;AAEH,iDAAoD;AACpD,yCAA2B;AAC3B,qDAAwD;AACxD,yDAM4B;AAC5B,
|
|
1
|
+
{"version":3,"file":"service-manager.js","sourceRoot":"","sources":["../../src/cliproxy/service-manager.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;;GAWG;;;;;;;;;;;;;;;;;;;;;;;;;;AAEH,iDAAoD;AACpD,yCAA2B;AAC3B,qDAAwD;AACxD,yDAM4B;AAC5B,uDAAoD;AACpD,qDAA2E;AAC3E,iDAAiD;AACjD,mDAAoD;AAEpD,yCAAyC;AACzC,IAAI,YAAY,GAAwB,IAAI,CAAC;AAE7C,8BAA8B;AAC9B,IAAI,iBAAiB,GAAG,KAAK,CAAC;AAE9B;;GAEG;AACH,KAAK,UAAU,WAAW,CACxB,IAAY,EACZ,UAAkB,IAAI,EACtB,eAAuB,GAAG;IAE1B,MAAM,KAAK,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;IAEzB,OAAO,IAAI,CAAC,GAAG,EAAE,GAAG,KAAK,GAAG,OAAO,EAAE,CAAC;QACpC,IAAI,CAAC;YACH,MAAM,IAAI,OAAO,CAAO,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;gBAC1C,MAAM,MAAM,GAAG,GAAG,CAAC,gBAAgB,CAAC,EAAE,IAAI,EAAE,IAAI,EAAE,WAAW,EAAE,EAAE,GAAG,EAAE;oBACpE,MAAM,CAAC,OAAO,EAAE,CAAC;oBACjB,OAAO,EAAE,CAAC;gBACZ,CAAC,CAAC,CAAC;gBAEH,MAAM,CAAC,EAAE,CAAC,OAAO,EAAE,CAAC,GAAG,EAAE,EAAE;oBACzB,MAAM,CAAC,OAAO,EAAE,CAAC;oBACjB,MAAM,CAAC,GAAG,CAAC,CAAC;gBACd,CAAC,CAAC,CAAC;gBAEH,MAAM,CAAC,UAAU,CAAC,GAAG,EAAE,GAAG,EAAE;oBAC1B,MAAM,CAAC,OAAO,EAAE,CAAC;oBACjB,MAAM,CAAC,IAAI,KAAK,CAAC,oBAAoB,CAAC,CAAC,CAAC;gBAC1C,CAAC,CAAC,CAAC;YACL,CAAC,CAAC,CAAC;YAEH,OAAO,IAAI,CAAC,CAAC,wBAAwB;QACvC,CAAC;QAAC,MAAM,CAAC;YACP,MAAM,IAAI,OAAO,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,UAAU,CAAC,CAAC,EAAE,YAAY,CAAC,CAAC,CAAC;QACxD,CAAC;IACH,CAAC;IAED,OAAO,KAAK,CAAC;AACf,CAAC;AAED;;GAEG;AACH,SAAS,eAAe;IACtB,IAAI,iBAAiB;QAAE,OAAO;IAE9B,MAAM,OAAO,GAAG,GAAG,EAAE;QACnB,IAAI,YAAY,IAAI,CAAC,YAAY,CAAC,MAAM,EAAE,CAAC;YACzC,YAAY,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;YAC7B,YAAY,GAAG,IAAI,CAAC;QACtB,CAAC;IACH,CAAC,CAAC;IAEF,OAAO,CAAC,IAAI,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAC9B,OAAO,CAAC,IAAI,CAAC,SAAS,EAAE,OAAO,CAAC,CAAC;IACjC,OAAO,CAAC,IAAI,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC;IAEhC,iBAAiB,GAAG,IAAI,CAAC;AAC3B,CAAC;AAUD;;;;;;;;;GASG;AACI,KAAK,UAAU,qBAAqB,CACzC,OAAe,wCAAqB,EACpC,UAAmB,KAAK;IAExB,MAAM,GAAG,GAAG,CAAC,GAAW,EAAE,EAAE;QAC1B,IAAI,OAAO,EAAE,CAAC;YACZ,OAAO,CAAC,KAAK,CAAC,sBAAsB,GAAG,EAAE,CAAC,CAAC;QAC7C,CAAC;IACH,CAAC,CAAC;IAEF,iDAAiD;IACjD,IAAI,iBAAiB,GAAG,KAAK,CAAC;IAC9B,IAAI,IAAA,0CAAuB,GAAE,EAAE,CAAC;QAC9B,GAAG,CAAC,kCAAkC,CAAC,CAAC;QACxC,IAAA,mCAAgB,EAAC,IAAI,CAAC,CAAC;QACvB,iBAAiB,GAAG,IAAI,CAAC;IAC3B,CAAC;IAED,sFAAsF;IACtF,OAAO,MAAM,IAAA,8BAAe,EAAC,KAAK,IAAI,EAAE;QACtC,mEAAmE;QACnE,GAAG,CAAC,2CAA2C,IAAI,KAAK,CAAC,CAAC;QAC1D,MAAM,WAAW,GAAG,MAAM,IAAA,mCAAkB,EAAC,IAAI,CAAC,CAAC;QACnD,GAAG,CAAC,oBAAoB,IAAI,CAAC,SAAS,CAAC,WAAW,CAAC,EAAE,CAAC,CAAC;QAEvD,IAAI,WAAW,CAAC,OAAO,IAAI,WAAW,CAAC,QAAQ,EAAE,CAAC;YAChD,8BAA8B;YAC9B,GAAG,CAAC,0BAA0B,CAAC,CAAC;YAChC,IAAI,iBAAiB,EAAE,CAAC;gBACtB,GAAG,CAAC,2EAA2E,CAAC,CAAC;YACnF,CAAC;YACD,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,cAAc,EAAE,IAAI,EAAE,IAAI,EAAE,iBAAiB,EAAE,CAAC;QAC1E,CAAC;QAED,IAAI,WAAW,CAAC,OAAO,IAAI,CAAC,WAAW,CAAC,QAAQ,EAAE,CAAC;YACjD,oEAAoE;YACpE,GAAG,CAAC,mCAAmC,WAAW,CAAC,MAAM,eAAe,CAAC,CAAC;YAC1E,MAAM,aAAa,GAAG,MAAM,IAAA,oCAAmB,EAAC,IAAI,EAAE,IAAI,CAAC,CAAC;YAC5D,IAAI,aAAa,EAAE,CAAC;gBAClB,GAAG,CAAC,sBAAsB,CAAC,CAAC;gBAC5B,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,cAAc,EAAE,IAAI,EAAE,IAAI,EAAE,iBAAiB,EAAE,CAAC;YAC1E,CAAC;YACD,8DAA8D;YAC9D,GAAG,CAAC,qDAAqD,CAAC,CAAC;QAC7D,CAAC;QAED,IAAI,WAAW,CAAC,OAAO,EAAE,CAAC;YACxB,iEAAiE;YACjE,MAAM,cAAc,GAAG,MAAM,IAAA,oCAAmB,EAAC,IAAI,EAAE,IAAI,CAAC,CAAC;YAC7D,IAAI,cAAc,EAAE,CAAC;gBACnB,GAAG,CAAC,mDAAmD,CAAC,CAAC;gBACzD,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,cAAc,EAAE,IAAI,EAAE,IAAI,EAAE,iBAAiB,EAAE,CAAC;YAC1E,CAAC;YACD,gBAAgB;YAChB,OAAO;gBACL,OAAO,EAAE,KAAK;gBACd,cAAc,EAAE,KAAK;gBACrB,IAAI;gBACJ,KAAK,EAAE,QAAQ,IAAI,kBAAkB,WAAW,CAAC,OAAO,EAAE,WAAW,EAAE;aACxE,CAAC;QACJ,CAAC;QAED,6BAA6B;QAC7B,GAAG,CAAC,uDAAuD,CAAC,CAAC;QAE7D,0BAA0B;QAC1B,IAAI,UAAkB,CAAC;QACvB,IAAI,CAAC;YACH,UAAU,GAAG,MAAM,IAAA,qCAAoB,EAAC,OAAO,CAAC,CAAC;YACjD,GAAG,CAAC,iBAAiB,UAAU,EAAE,CAAC,CAAC;QACrC,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,MAAM,GAAG,GAAG,KAAc,CAAC;YAC3B,OAAO;gBACL,OAAO,EAAE,KAAK;gBACd,cAAc,EAAE,KAAK;gBACrB,IAAI;gBACJ,KAAK,EAAE,6BAA6B,GAAG,CAAC,OAAO,EAAE;aAClD,CAAC;QACJ,CAAC;QAED,wCAAwC;QACxC,IAAI,UAAkB,CAAC;QACvB,IAAI,IAAA,0CAAuB,GAAE,EAAE,CAAC;YAC9B,GAAG,CAAC,wCAAwC,CAAC,CAAC;YAC9C,UAAU,GAAG,IAAA,mCAAgB,EAAC,IAAI,CAAC,CAAC;QACtC,CAAC;aAAM,CAAC;YACN,UAAU,GAAG,IAAA,iCAAc,EAAC,QAAQ,EAAE,IAAI,CAAC,CAAC;QAC9C,CAAC;QACD,GAAG,CAAC,iBAAiB,UAAU,EAAE,CAAC,CAAC;QAEnC,8BAA8B;QAC9B,MAAM,SAAS,GAAG,CAAC,UAAU,EAAE,UAAU,CAAC,CAAC;QAC3C,GAAG,CAAC,aAAa,UAAU,IAAI,SAAS,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;QAEtD,YAAY,GAAG,IAAA,qBAAK,EAAC,UAAU,EAAE,SAAS,EAAE;YAC1C,KAAK,EAAE,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,QAAQ,CAAC;YAC3E,QAAQ,EAAE,IAAI;YACd,GAAG,EAAE;gBACH,GAAG,OAAO,CAAC,GAAG;gBACd,aAAa,EAAE,IAAA,0CAAuB,GAAE;aACzC;SACF,CAAC,CAAC;QAEH,IAAI,OAAO,EAAE,CAAC;YACZ,YAAY,CAAC,MAAM,EAAE,EAAE,CAAC,MAAM,EAAE,CAAC,IAAY,EAAE,EAAE;gBAC/C,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,cAAc,IAAI,CAAC,QAAQ,EAAE,EAAE,CAAC,CAAC;YACxD,CAAC,CAAC,CAAC;YACH,YAAY,CAAC,MAAM,EAAE,EAAE,CAAC,MAAM,EAAE,CAAC,IAAY,EAAE,EAAE;gBAC/C,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,kBAAkB,IAAI,CAAC,QAAQ,EAAE,EAAE,CAAC,CAAC;YAC5D,CAAC,CAAC,CAAC;QACL,CAAC;QAED,YAAY,CAAC,KAAK,EAAE,CAAC;QAErB,YAAY,CAAC,EAAE,CAAC,OAAO,EAAE,CAAC,KAAK,EAAE,EAAE;YACjC,GAAG,CAAC,gBAAgB,KAAK,CAAC,OAAO,EAAE,CAAC,CAAC;QACvC,CAAC,CAAC,CAAC;QAEH,eAAe,EAAE,CAAC;QAElB,gCAAgC;QAChC,GAAG,CAAC,gCAAgC,IAAI,KAAK,CAAC,CAAC;QAC/C,MAAM,KAAK,GAAG,MAAM,WAAW,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;QAE5C,IAAI,CAAC,KAAK,EAAE,CAAC;YACX,IAAI,YAAY,IAAI,CAAC,YAAY,CAAC,MAAM,EAAE,CAAC;gBACzC,YAAY,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;gBAC7B,YAAY,GAAG,IAAI,CAAC;YACtB,CAAC;YAED,OAAO;gBACL,OAAO,EAAE,KAAK;gBACd,cAAc,EAAE,KAAK;gBACrB,IAAI;gBACJ,KAAK,EAAE,8CAA8C,IAAI,EAAE;aAC5D,CAAC;QACJ,CAAC;QAED,GAAG,CAAC,oCAAoC,IAAI,EAAE,CAAC,CAAC;QAEhD,sBAAsB;QACtB,IAAI,YAAY,CAAC,GAAG,EAAE,CAAC;YACrB,IAAA,iCAAe,EAAC,IAAI,EAAE,YAAY,CAAC,GAAG,CAAC,CAAC;YACxC,GAAG,CAAC,8BAA8B,YAAY,CAAC,GAAG,EAAE,CAAC,CAAC;QACxD,CAAC;QAED,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,cAAc,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC;IACxD,CAAC,CAAC,CAAC;AACL,CAAC;AApJD,sDAoJC;AAED;;GAEG;AACH,SAAgB,mBAAmB;IACjC,IAAI,YAAY,IAAI,CAAC,YAAY,CAAC,MAAM,EAAE,CAAC;QACzC,YAAY,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;QAC7B,YAAY,GAAG,IAAI,CAAC;QACpB,OAAO,IAAI,CAAC;IACd,CAAC;IACD,OAAO,KAAK,CAAC;AACf,CAAC;AAPD,kDAOC;AAED;;GAEG;AACI,KAAK,UAAU,gBAAgB,CAAC,OAAe,wCAAqB;IAKzE,MAAM,OAAO,GAAG,MAAM,IAAA,iCAAiB,EAAC,IAAI,CAAC,CAAC;IAC9C,MAAM,WAAW,GAAG,YAAY,KAAK,IAAI,IAAI,CAAC,YAAY,CAAC,MAAM,CAAC;IAElE,OAAO,EAAE,OAAO,EAAE,WAAW,EAAE,IAAI,EAAE,CAAC;AACxC,CAAC;AATD,4CASC"}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Startup Lock for CLIProxy
|
|
3
|
+
*
|
|
4
|
+
* File-based mutex to prevent race conditions when multiple
|
|
5
|
+
* CCS processes try to start CLIProxy simultaneously.
|
|
6
|
+
*
|
|
7
|
+
* Uses a lock file with PID and timestamp to coordinate startup.
|
|
8
|
+
* Lock is automatically released after timeout or process exit.
|
|
9
|
+
*
|
|
10
|
+
* Lock Timeout Rationale (10 seconds):
|
|
11
|
+
* - CLIProxy startup typically takes 1-3s (binary spawn + port bind)
|
|
12
|
+
* - HTTP health check takes ~1s timeout
|
|
13
|
+
* - Session registration takes <100ms
|
|
14
|
+
* - Total expected lock hold time: 2-5s
|
|
15
|
+
* - 10s provides 2x safety margin for slow systems/disk I/O
|
|
16
|
+
* - Too short: legitimate startups fail on slow systems
|
|
17
|
+
* - Too long: dead processes block other terminals unnecessarily
|
|
18
|
+
*
|
|
19
|
+
* Why file-based instead of port-based:
|
|
20
|
+
* - Works before port is bound (prevents duplicate spawn attempts)
|
|
21
|
+
* - Survives process crashes (stale detection via PID check)
|
|
22
|
+
* - Cross-platform (Windows, macOS, Linux)
|
|
23
|
+
*/
|
|
24
|
+
/** Lock acquisition result */
|
|
25
|
+
export interface LockResult {
|
|
26
|
+
acquired: boolean;
|
|
27
|
+
lockPath: string;
|
|
28
|
+
release: () => void;
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Acquire the startup lock with retries.
|
|
32
|
+
*
|
|
33
|
+
* @param options.retries Number of retry attempts (default: 20)
|
|
34
|
+
* @param options.retryInterval Ms between retries (default: 250)
|
|
35
|
+
* @param options.verbose Enable verbose logging (default: false)
|
|
36
|
+
* @returns LockResult
|
|
37
|
+
* @throws Error if lock cannot be acquired after all retries
|
|
38
|
+
*/
|
|
39
|
+
export declare function acquireStartupLock(options?: {
|
|
40
|
+
retries?: number;
|
|
41
|
+
retryInterval?: number;
|
|
42
|
+
verbose?: boolean;
|
|
43
|
+
}): Promise<LockResult>;
|
|
44
|
+
/**
|
|
45
|
+
* Execute a function while holding the startup lock.
|
|
46
|
+
* Lock is automatically released after function completes or throws.
|
|
47
|
+
*
|
|
48
|
+
* @param fn Function to execute
|
|
49
|
+
* @param options Lock acquisition options (retries, retryInterval, verbose)
|
|
50
|
+
* @returns Result of fn
|
|
51
|
+
*/
|
|
52
|
+
export declare function withStartupLock<T>(fn: () => Promise<T>, options?: {
|
|
53
|
+
retries?: number;
|
|
54
|
+
retryInterval?: number;
|
|
55
|
+
verbose?: boolean;
|
|
56
|
+
}): Promise<T>;
|
|
57
|
+
//# sourceMappingURL=startup-lock.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"startup-lock.d.ts","sourceRoot":"","sources":["../../src/cliproxy/startup-lock.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;GAsBG;AAaH,8BAA8B;AAC9B,MAAM,WAAW,UAAU;IACzB,QAAQ,EAAE,OAAO,CAAC;IAClB,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,MAAM,IAAI,CAAC;CACrB;AAkID;;;;;;;;GAQG;AACH,wBAAsB,kBAAkB,CAAC,OAAO,CAAC,EAAE;IACjD,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB,GAAG,OAAO,CAAC,UAAU,CAAC,CAwBtB;AAED;;;;;;;GAOG;AACH,wBAAsB,eAAe,CAAC,CAAC,EACrC,EAAE,EAAE,MAAM,OAAO,CAAC,CAAC,CAAC,EACpB,OAAO,CAAC,EAAE;IAAE,OAAO,CAAC,EAAE,MAAM,CAAC;IAAC,aAAa,CAAC,EAAE,MAAM,CAAC;IAAC,OAAO,CAAC,EAAE,OAAO,CAAA;CAAE,GACxE,OAAO,CAAC,CAAC,CAAC,CAOZ"}
|
|
@@ -0,0 +1,216 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Startup Lock for CLIProxy
|
|
4
|
+
*
|
|
5
|
+
* File-based mutex to prevent race conditions when multiple
|
|
6
|
+
* CCS processes try to start CLIProxy simultaneously.
|
|
7
|
+
*
|
|
8
|
+
* Uses a lock file with PID and timestamp to coordinate startup.
|
|
9
|
+
* Lock is automatically released after timeout or process exit.
|
|
10
|
+
*
|
|
11
|
+
* Lock Timeout Rationale (10 seconds):
|
|
12
|
+
* - CLIProxy startup typically takes 1-3s (binary spawn + port bind)
|
|
13
|
+
* - HTTP health check takes ~1s timeout
|
|
14
|
+
* - Session registration takes <100ms
|
|
15
|
+
* - Total expected lock hold time: 2-5s
|
|
16
|
+
* - 10s provides 2x safety margin for slow systems/disk I/O
|
|
17
|
+
* - Too short: legitimate startups fail on slow systems
|
|
18
|
+
* - Too long: dead processes block other terminals unnecessarily
|
|
19
|
+
*
|
|
20
|
+
* Why file-based instead of port-based:
|
|
21
|
+
* - Works before port is bound (prevents duplicate spawn attempts)
|
|
22
|
+
* - Survives process crashes (stale detection via PID check)
|
|
23
|
+
* - Cross-platform (Windows, macOS, Linux)
|
|
24
|
+
*/
|
|
25
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
26
|
+
if (k2 === undefined) k2 = k;
|
|
27
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
28
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
29
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
30
|
+
}
|
|
31
|
+
Object.defineProperty(o, k2, desc);
|
|
32
|
+
}) : (function(o, m, k, k2) {
|
|
33
|
+
if (k2 === undefined) k2 = k;
|
|
34
|
+
o[k2] = m[k];
|
|
35
|
+
}));
|
|
36
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
37
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
38
|
+
}) : function(o, v) {
|
|
39
|
+
o["default"] = v;
|
|
40
|
+
});
|
|
41
|
+
var __importStar = (this && this.__importStar) || function (mod) {
|
|
42
|
+
if (mod && mod.__esModule) return mod;
|
|
43
|
+
var result = {};
|
|
44
|
+
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
|
|
45
|
+
__setModuleDefault(result, mod);
|
|
46
|
+
return result;
|
|
47
|
+
};
|
|
48
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
49
|
+
exports.withStartupLock = exports.acquireStartupLock = void 0;
|
|
50
|
+
const fs = __importStar(require("fs"));
|
|
51
|
+
const path = __importStar(require("path"));
|
|
52
|
+
const config_generator_1 = require("./config-generator");
|
|
53
|
+
/** Lock file name */
|
|
54
|
+
const LOCK_FILE = '.startup.lock';
|
|
55
|
+
/** Lock timeout in ms (stale lock auto-released) */
|
|
56
|
+
const LOCK_TIMEOUT_MS = 10000; // 10 seconds - see module docstring for rationale
|
|
57
|
+
/** No-op logger for when verbose is disabled */
|
|
58
|
+
const noopLog = () => { };
|
|
59
|
+
/**
|
|
60
|
+
* Get path to startup lock file
|
|
61
|
+
*/
|
|
62
|
+
function getLockPath() {
|
|
63
|
+
return path.join((0, config_generator_1.getCliproxyDir)(), LOCK_FILE);
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* Check if a lock is stale (old or from dead process)
|
|
67
|
+
*/
|
|
68
|
+
function isLockStale(lockData) {
|
|
69
|
+
// Check timestamp
|
|
70
|
+
if (Date.now() - lockData.timestamp > LOCK_TIMEOUT_MS) {
|
|
71
|
+
return true;
|
|
72
|
+
}
|
|
73
|
+
// Check if PID is still running
|
|
74
|
+
try {
|
|
75
|
+
process.kill(lockData.pid, 0);
|
|
76
|
+
return false; // Process exists
|
|
77
|
+
}
|
|
78
|
+
catch {
|
|
79
|
+
return true; // Process dead
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
/**
|
|
83
|
+
* Try to acquire the startup lock once.
|
|
84
|
+
*
|
|
85
|
+
* @param log Logger function for verbose output
|
|
86
|
+
* @returns LockResult with acquired=true if lock obtained
|
|
87
|
+
*/
|
|
88
|
+
function tryAcquireLockOnce(log) {
|
|
89
|
+
const lockPath = getLockPath();
|
|
90
|
+
const dir = path.dirname(lockPath);
|
|
91
|
+
// Ensure directory exists
|
|
92
|
+
if (!fs.existsSync(dir)) {
|
|
93
|
+
log(`Creating lock directory: ${dir}`);
|
|
94
|
+
fs.mkdirSync(dir, { recursive: true, mode: 0o700 });
|
|
95
|
+
}
|
|
96
|
+
// Check for existing lock
|
|
97
|
+
if (fs.existsSync(lockPath)) {
|
|
98
|
+
try {
|
|
99
|
+
const content = fs.readFileSync(lockPath, 'utf-8');
|
|
100
|
+
const lockData = JSON.parse(content);
|
|
101
|
+
if (!isLockStale(lockData)) {
|
|
102
|
+
// Lock is held by another active process
|
|
103
|
+
log(`Lock held by PID ${lockData.pid} (age: ${Date.now() - lockData.timestamp}ms)`);
|
|
104
|
+
return {
|
|
105
|
+
acquired: false,
|
|
106
|
+
lockPath,
|
|
107
|
+
release: () => { },
|
|
108
|
+
};
|
|
109
|
+
}
|
|
110
|
+
// Lock is stale - remove and continue
|
|
111
|
+
log(`Removing stale lock from PID ${lockData.pid}`);
|
|
112
|
+
}
|
|
113
|
+
catch {
|
|
114
|
+
// Invalid lock file - remove and continue
|
|
115
|
+
log('Removing invalid lock file');
|
|
116
|
+
}
|
|
117
|
+
try {
|
|
118
|
+
fs.unlinkSync(lockPath);
|
|
119
|
+
}
|
|
120
|
+
catch {
|
|
121
|
+
// Ignore removal errors
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
// Try to create lock atomically
|
|
125
|
+
const lockData = {
|
|
126
|
+
pid: process.pid,
|
|
127
|
+
timestamp: Date.now(),
|
|
128
|
+
hostname: require('os').hostname(),
|
|
129
|
+
};
|
|
130
|
+
try {
|
|
131
|
+
// Use 'wx' flag for exclusive creation (fails if exists)
|
|
132
|
+
fs.writeFileSync(lockPath, JSON.stringify(lockData), { flag: 'wx', mode: 0o600 });
|
|
133
|
+
log(`Lock acquired by PID ${process.pid}`);
|
|
134
|
+
}
|
|
135
|
+
catch (err) {
|
|
136
|
+
const error = err;
|
|
137
|
+
if (error.code === 'EEXIST') {
|
|
138
|
+
// Another process created lock between our check and write
|
|
139
|
+
log('Lock acquisition race - another process won');
|
|
140
|
+
return {
|
|
141
|
+
acquired: false,
|
|
142
|
+
lockPath,
|
|
143
|
+
release: () => { },
|
|
144
|
+
};
|
|
145
|
+
}
|
|
146
|
+
throw error;
|
|
147
|
+
}
|
|
148
|
+
// Lock acquired - return release function
|
|
149
|
+
const release = () => {
|
|
150
|
+
try {
|
|
151
|
+
// Only release if we still own it
|
|
152
|
+
const content = fs.readFileSync(lockPath, 'utf-8');
|
|
153
|
+
const currentLock = JSON.parse(content);
|
|
154
|
+
if (currentLock.pid === process.pid) {
|
|
155
|
+
fs.unlinkSync(lockPath);
|
|
156
|
+
log('Lock released');
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
catch {
|
|
160
|
+
// Ignore release errors
|
|
161
|
+
}
|
|
162
|
+
};
|
|
163
|
+
return {
|
|
164
|
+
acquired: true,
|
|
165
|
+
lockPath,
|
|
166
|
+
release,
|
|
167
|
+
};
|
|
168
|
+
}
|
|
169
|
+
/**
|
|
170
|
+
* Acquire the startup lock with retries.
|
|
171
|
+
*
|
|
172
|
+
* @param options.retries Number of retry attempts (default: 20)
|
|
173
|
+
* @param options.retryInterval Ms between retries (default: 250)
|
|
174
|
+
* @param options.verbose Enable verbose logging (default: false)
|
|
175
|
+
* @returns LockResult
|
|
176
|
+
* @throws Error if lock cannot be acquired after all retries
|
|
177
|
+
*/
|
|
178
|
+
async function acquireStartupLock(options) {
|
|
179
|
+
const retries = options?.retries ?? 20;
|
|
180
|
+
const retryInterval = options?.retryInterval ?? 250;
|
|
181
|
+
const log = options?.verbose ? (msg) => console.error(`[startup-lock] ${msg}`) : noopLog;
|
|
182
|
+
log(`Attempting to acquire startup lock (max ${retries} retries, ${retryInterval}ms interval)`);
|
|
183
|
+
for (let attempt = 0; attempt <= retries; attempt++) {
|
|
184
|
+
const result = tryAcquireLockOnce(log);
|
|
185
|
+
if (result.acquired) {
|
|
186
|
+
return result;
|
|
187
|
+
}
|
|
188
|
+
if (attempt < retries) {
|
|
189
|
+
log(`Retry ${attempt + 1}/${retries} in ${retryInterval}ms...`);
|
|
190
|
+
await new Promise((r) => setTimeout(r, retryInterval));
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
log(`Failed to acquire lock after ${retries} attempts`);
|
|
194
|
+
throw new Error(`Failed to acquire startup lock after ${retries} attempts. ` +
|
|
195
|
+
`Another CCS process may be starting CLIProxy.`);
|
|
196
|
+
}
|
|
197
|
+
exports.acquireStartupLock = acquireStartupLock;
|
|
198
|
+
/**
|
|
199
|
+
* Execute a function while holding the startup lock.
|
|
200
|
+
* Lock is automatically released after function completes or throws.
|
|
201
|
+
*
|
|
202
|
+
* @param fn Function to execute
|
|
203
|
+
* @param options Lock acquisition options (retries, retryInterval, verbose)
|
|
204
|
+
* @returns Result of fn
|
|
205
|
+
*/
|
|
206
|
+
async function withStartupLock(fn, options) {
|
|
207
|
+
const lock = await acquireStartupLock(options);
|
|
208
|
+
try {
|
|
209
|
+
return await fn();
|
|
210
|
+
}
|
|
211
|
+
finally {
|
|
212
|
+
lock.release();
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
exports.withStartupLock = withStartupLock;
|
|
216
|
+
//# sourceMappingURL=startup-lock.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"startup-lock.js","sourceRoot":"","sources":["../../src/cliproxy/startup-lock.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Auto-recovery for missing or corrupted configuration
|
|
3
|
+
* Lazy initialization: Creates ~/.ccs/ structure on first CLI run
|
|
4
|
+
* Mirrors postinstall.js behavior for package managers that skip lifecycle scripts (e.g., bun)
|
|
3
5
|
*/
|
|
4
6
|
/**
|
|
5
7
|
* Recovery Manager Class
|
|
@@ -8,6 +10,8 @@ declare class RecoveryManager {
|
|
|
8
10
|
private readonly homedir;
|
|
9
11
|
private readonly ccsDir;
|
|
10
12
|
private readonly claudeDir;
|
|
13
|
+
private readonly sharedDir;
|
|
14
|
+
private readonly completionsDir;
|
|
11
15
|
private recovered;
|
|
12
16
|
constructor();
|
|
13
17
|
/**
|
|
@@ -23,7 +27,28 @@ declare class RecoveryManager {
|
|
|
23
27
|
*/
|
|
24
28
|
ensureClaudeSettings(): boolean;
|
|
25
29
|
/**
|
|
26
|
-
*
|
|
30
|
+
* Ensure ~/.ccs/shared/ directory structure exists
|
|
31
|
+
*/
|
|
32
|
+
ensureSharedDirectories(): boolean;
|
|
33
|
+
/**
|
|
34
|
+
* Ensure GLM settings file exists
|
|
35
|
+
*/
|
|
36
|
+
ensureGlmSettings(): boolean;
|
|
37
|
+
/**
|
|
38
|
+
* Ensure GLMT settings file exists
|
|
39
|
+
*/
|
|
40
|
+
ensureGlmtSettings(): boolean;
|
|
41
|
+
/**
|
|
42
|
+
* Ensure Kimi settings file exists
|
|
43
|
+
*/
|
|
44
|
+
ensureKimiSettings(): boolean;
|
|
45
|
+
/**
|
|
46
|
+
* Install shell completion files
|
|
47
|
+
*/
|
|
48
|
+
ensureShellCompletions(): boolean;
|
|
49
|
+
/**
|
|
50
|
+
* Run all recovery operations (lazy initialization)
|
|
51
|
+
* Mirrors postinstall.js behavior
|
|
27
52
|
*/
|
|
28
53
|
recoverAll(): boolean;
|
|
29
54
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"recovery-manager.d.ts","sourceRoot":"","sources":["../../src/management/recovery-manager.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"recovery-manager.d.ts","sourceRoot":"","sources":["../../src/management/recovery-manager.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAcH;;GAEG;AACH,cAAM,eAAe;IACnB,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAS;IACjC,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAS;IAChC,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAS;IACnC,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAS;IACnC,OAAO,CAAC,QAAQ,CAAC,cAAc,CAAS;IACxC,OAAO,CAAC,SAAS,CAAW;;IAW5B;;OAEG;IACH,kBAAkB,IAAI,OAAO;IAS7B;;OAEG;IACH,gBAAgB,IAAI,OAAO;IAoC3B;;OAEG;IACH,oBAAoB,IAAI,OAAO;IAsB/B;;OAEG;IACH,uBAAuB,IAAI,OAAO;IAuBlC;;OAEG;IACH,iBAAiB,IAAI,OAAO;IAsB5B;;OAEG;IACH,kBAAkB,IAAI,OAAO;IA6B7B;;OAEG;IACH,kBAAkB,IAAI,OAAO;IAuB7B;;OAEG;IACH,sBAAsB,IAAI,OAAO;IA+CjC;;;OAGG;IACH,UAAU,IAAI,OAAO;IAoBrB;;OAEG;IACH,kBAAkB,IAAI,MAAM,EAAE;IAI9B;;OAEG;IACH,iBAAiB,IAAI,IAAI;CAiC1B;AAED,eAAe,eAAe,CAAC"}
|