dsh-cursor-dev 0.12.0 → 0.12.2
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/README.md +9 -9
- package/docs/INSTALL.md +10 -10
- package/docs/skill-drafts/subagent-model-routing/SKILL.md +66 -0
- package/lib/index.js +9 -3
- package/lib/native-provider.js +18 -16
- package/lib/proxy.js +7 -9
- package/lib/quota-guard.js +113 -0
- package/lib/session-pool.js +4 -0
- package/lib/settings.js +4 -8
- package/lib/tool.js +24 -4
- package/lib/usage.js +436 -128
- package/package.json +2 -2
package/lib/tool.js
CHANGED
|
@@ -22,6 +22,7 @@ import { delegationDepthOf, resolveChildDepth } from './mirror.js';
|
|
|
22
22
|
import { sameModel } from './models.js';
|
|
23
23
|
import { buildPrompt } from './prompt.js';
|
|
24
24
|
import { storeKeyOf } from './session-pool.js';
|
|
25
|
+
import { cursorQuotaFailure, quotaBlockedMessage } from './quota-guard.js';
|
|
25
26
|
|
|
26
27
|
/** Default wall-clock budget for one Cursor turn. */
|
|
27
28
|
const DEFAULT_TIMEOUT_SECONDS = 1800;
|
|
@@ -89,7 +90,7 @@ function clean(value, seen) {
|
|
|
89
90
|
* @param deps - plugin services and shared state.
|
|
90
91
|
*/
|
|
91
92
|
export function cursorCodeTool(deps) {
|
|
92
|
-
const { pool, journal, index, logger, unavailable, mirrors } = deps;
|
|
93
|
+
const { pool, journal, index, logger, unavailable, mirrors, quotaGuard } = deps;
|
|
93
94
|
// The recursion budget this tool enforces: the child it starts is a real
|
|
94
95
|
// DSH child session, so a subagent calling this tool would create a
|
|
95
96
|
// GRANDCHILD. `1` is the platform's own default (only a top-level agent
|
|
@@ -291,6 +292,15 @@ export function cursorCodeTool(deps) {
|
|
|
291
292
|
}
|
|
292
293
|
}
|
|
293
294
|
|
|
295
|
+
const quotaStatus = await quotaGuard?.check?.();
|
|
296
|
+
if (quotaStatus?.blocked === true) {
|
|
297
|
+
return toLosslessJson({
|
|
298
|
+
ok: false, sessionKey: 'quota-exhausted', conversationKey,
|
|
299
|
+
stopReason: 'error', durationMs: 0,
|
|
300
|
+
error: quotaBlockedMessage(quotaStatus), steps: [], changes: [],
|
|
301
|
+
});
|
|
302
|
+
}
|
|
303
|
+
|
|
294
304
|
if (input.resetSession) {
|
|
295
305
|
pool.dropConversation(conversationKey);
|
|
296
306
|
journal.clear(conversationKey);
|
|
@@ -377,8 +387,8 @@ export function cursorCodeTool(deps) {
|
|
|
377
387
|
let reused = false;
|
|
378
388
|
let reloaded = false;
|
|
379
389
|
const lifecycle = exec.cursorLifecycle;
|
|
380
|
-
//
|
|
381
|
-
//
|
|
390
|
+
// The service's external lifecycle id is separate from this child:
|
|
391
|
+
// the panel follows the mirror, whose transcript is written below.
|
|
382
392
|
const mirrorEnabled = lifecycle?.mirror !== false;
|
|
383
393
|
const openChild = async () => {
|
|
384
394
|
const entry = await mirrors?.open({
|
|
@@ -436,6 +446,13 @@ export function cursorCodeTool(deps) {
|
|
|
436
446
|
if (pickedMode !== undefined && session.modes?.currentModeId !== pickedMode)
|
|
437
447
|
await session.setMode(pickedMode);
|
|
438
448
|
turn = await session.prompt(input.prompt, abort.signal);
|
|
449
|
+
if (cursorQuotaFailure(turn.text)) {
|
|
450
|
+
const status = quotaGuard?.observeFailure?.(turn.text);
|
|
451
|
+
if (status?.blocked === true) {
|
|
452
|
+
const partialTurn = { ...turn, stopReason: 'error' };
|
|
453
|
+
throw Object.assign(new Error(quotaBlockedMessage(status)), { partialTurn });
|
|
454
|
+
}
|
|
455
|
+
}
|
|
439
456
|
pool.recordTurn(sessionKey, turn);
|
|
440
457
|
const after = await fingerprint(workspaceRoot, deps.maxScanFiles);
|
|
441
458
|
const changes = mergeChanges(turn.diffs, compareFingerprints(before, after), workspaceRoot);
|
|
@@ -484,7 +501,10 @@ export function cursorCodeTool(deps) {
|
|
|
484
501
|
});
|
|
485
502
|
}
|
|
486
503
|
catch (error) {
|
|
487
|
-
const
|
|
504
|
+
const quotaStatus = cursorQuotaFailure(error) ? quotaGuard?.observeFailure?.(error) : undefined;
|
|
505
|
+
const message = quotaStatus?.blocked === true
|
|
506
|
+
? quotaBlockedMessage(quotaStatus)
|
|
507
|
+
: error instanceof Error ? error.message : String(error);
|
|
488
508
|
logger?.warn?.(`cursor_code failed: ${message}`);
|
|
489
509
|
return toLosslessJson({
|
|
490
510
|
ok: false, sessionKey, conversationKey, generation: picked.generation,
|