@alook/daemon 0.1.27 → 0.1.29
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 +7 -5
- package/dist/cli/index.js +205 -39
- package/dist/index.js +205 -39
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -97,12 +97,14 @@ Pi declares the `in_process_sdk` transport and
|
|
|
97
97
|
`midTurnDelivery: "steer"`. Its lane delegates prompt, steer, abort, and dispose
|
|
98
98
|
to the SDK while preserving the same receipts, events, and terminal contract.
|
|
99
99
|
|
|
100
|
-
### Persistent
|
|
100
|
+
### Persistent steering runtime (Cursor)
|
|
101
101
|
|
|
102
102
|
Cursor keeps one `cursor-agent acp` process and ACP session for the logical
|
|
103
|
-
session.
|
|
104
|
-
|
|
105
|
-
|
|
103
|
+
session. A root command starts a `session/prompt`; busy commands steer the same
|
|
104
|
+
logical turn through concurrent prompt requests. Each request has its own
|
|
105
|
+
JSON-RPC id, while the root receipt remains the stable terminal owner. Old
|
|
106
|
+
responses cannot settle the current turn. Interrupt sends `session/cancel`
|
|
107
|
+
without killing the process.
|
|
106
108
|
|
|
107
109
|
### Persistent service runtime (OpenCode)
|
|
108
110
|
|
|
@@ -120,7 +122,7 @@ live stream handles permissions.
|
|
|
120
122
|
| **claude** | persistent session | stream-json NDJSON | `safe_boundary_queue` | stdin user-message line | stream-json |
|
|
121
123
|
| **codex** | persistent session | JSON-RPC 2.0 (`app-server --listen stdio://`) | `safe_boundary_queue` | `initialize` → `thread/start`/`resume` | JSON-RPC notifications |
|
|
122
124
|
| **pi** | persistent session | `@earendil-works/pi-coding-agent` | `steer` | `session.prompt()` | SDK callback |
|
|
123
|
-
| **cursor** | persistent session | ACP JSON-RPC 2.0 (`cursor-agent acp`) | `
|
|
125
|
+
| **cursor** | persistent session | ACP JSON-RPC 2.0 (`cursor-agent acp`) | `steer` | `session/prompt` | `session/update` + correlated prompt response |
|
|
124
126
|
| **opencode** | persistent session | authenticated HTTP + SSE (`opencode serve --pure`) | `steer` | v2 session prompt API | durable + live SSE |
|
|
125
127
|
|
|
126
128
|
(Exact launch flags live in `agent-driver/src/adapters/<backend>/`.)
|
package/dist/cli/index.js
CHANGED
|
@@ -16934,6 +16934,7 @@ var ALLOWED_ICON_MIME_TYPES = [
|
|
|
16934
16934
|
];
|
|
16935
16935
|
var MAX_ICON_SOURCE_FILE_SIZE_BYTES = 15 * 1024 * 1024;
|
|
16936
16936
|
// ../shared/src/provider-telemetry.ts
|
|
16937
|
+
var DAILY_TOKEN_USAGE_WINDOW_DAYS = 30;
|
|
16937
16938
|
var safeToken = exports_external.number().int().min(0).max(Number.MAX_SAFE_INTEGER);
|
|
16938
16939
|
var boundedText = exports_external.string().min(1).refine((value) => new TextEncoder().encode(value).length <= 64, { message: "must be at most 64 UTF-8 bytes" });
|
|
16939
16940
|
var DailyUsageMetricSchema = safeToken.nullable();
|
|
@@ -17665,7 +17666,7 @@ var AgentActivityMessageSchema = exports_external.object({
|
|
|
17665
17666
|
state: exports_external.enum(["idle", "starting", "running", "stopping"]),
|
|
17666
17667
|
usageTimeZone: exports_external.string().min(1).max(128).optional(),
|
|
17667
17668
|
usageDay: exports_external.string().regex(/^\d{4}-\d{2}-\d{2}$/).optional(),
|
|
17668
|
-
dailyUsage: exports_external.array(DailyUsageSnapshotSchema).max(
|
|
17669
|
+
dailyUsage: exports_external.array(DailyUsageSnapshotSchema).max(DAILY_TOKEN_USAGE_WINDOW_DAYS).optional(),
|
|
17669
17670
|
quota: ProviderQuotaSnapshotSchema.optional()
|
|
17670
17671
|
});
|
|
17671
17672
|
var AgentTypingMessageSchema = exports_external.object({
|
|
@@ -20637,11 +20638,33 @@ function tryParseJsonLine(line) {
|
|
|
20637
20638
|
|
|
20638
20639
|
// agent-driver/dist/adapters/claude/normalizer.js
|
|
20639
20640
|
var API_ERROR_RE = /API Error:.*(?:Connection error|\b[45]\d{2}\b)/i;
|
|
20641
|
+
var CLAUDE_USAGE_COMPONENTS = [
|
|
20642
|
+
"inputTokens",
|
|
20643
|
+
"outputTokens",
|
|
20644
|
+
"cacheReadInputTokens",
|
|
20645
|
+
"cacheCreationInputTokens"
|
|
20646
|
+
];
|
|
20647
|
+
function safeCount(value) {
|
|
20648
|
+
return typeof value === "number" && Number.isSafeInteger(value) && value >= 0 ? value : null;
|
|
20649
|
+
}
|
|
20650
|
+
function safeMoney(value) {
|
|
20651
|
+
return typeof value === "number" && Number.isFinite(value) && value >= 0 ? value : null;
|
|
20652
|
+
}
|
|
20653
|
+
function safeAdd(left, right) {
|
|
20654
|
+
const total = left + right;
|
|
20655
|
+
return Number.isSafeInteger(total) ? total : null;
|
|
20656
|
+
}
|
|
20657
|
+
function equalCost(left, right) {
|
|
20658
|
+
return Math.abs(left - right) <= Math.max(0.000000000001, Math.abs(right) * 0.000000001);
|
|
20659
|
+
}
|
|
20640
20660
|
|
|
20641
20661
|
class ClaudeEventNormalizer {
|
|
20642
20662
|
turnProtocol;
|
|
20643
20663
|
currentSession = null;
|
|
20644
20664
|
usageProjector = new SettledUsageProjector;
|
|
20665
|
+
claudeUsageSession = null;
|
|
20666
|
+
claudeModelUsageHighWater = new Map;
|
|
20667
|
+
claudeUsageMode = "unknown";
|
|
20645
20668
|
constructor(turnProtocol) {
|
|
20646
20669
|
this.turnProtocol = turnProtocol;
|
|
20647
20670
|
}
|
|
@@ -20755,14 +20778,39 @@ class ClaudeEventNormalizer {
|
|
|
20755
20778
|
return this.turnProtocol?.acceptsTurnWork() ?? true;
|
|
20756
20779
|
}
|
|
20757
20780
|
buildUsageTelemetry(event, rootRequestId) {
|
|
20758
|
-
const u = event?.usage;
|
|
20759
|
-
if (!u)
|
|
20760
|
-
return null;
|
|
20761
20781
|
const backendSessionId = event.session_id ?? this.currentSession;
|
|
20762
20782
|
if (typeof backendSessionId !== "string" || !backendSessionId)
|
|
20763
20783
|
return null;
|
|
20764
20784
|
const providerRecordId = rootRequestId ?? (typeof event.request_id === "string" ? event.request_id : "invocation-result");
|
|
20765
|
-
|
|
20785
|
+
const cumulative = this.prepareClaudeModelUsage(event, backendSessionId);
|
|
20786
|
+
if (cumulative === null)
|
|
20787
|
+
return null;
|
|
20788
|
+
if (cumulative) {
|
|
20789
|
+
const hasDelta = cumulative.input > 0 || cumulative.output > 0 || cumulative.cacheRead > 0 || cumulative.cacheWrite > 0;
|
|
20790
|
+
if (!hasDelta) {
|
|
20791
|
+
this.commitClaudeModelUsage(backendSessionId, cumulative);
|
|
20792
|
+
return null;
|
|
20793
|
+
}
|
|
20794
|
+
const projected2 = this.usageProjector.project({
|
|
20795
|
+
runtime: "claude",
|
|
20796
|
+
backendSessionId,
|
|
20797
|
+
providerRecordId,
|
|
20798
|
+
source: "claude_result_model_usage",
|
|
20799
|
+
input: cumulative.input,
|
|
20800
|
+
output: cumulative.output,
|
|
20801
|
+
cacheRead: cumulative.cacheRead,
|
|
20802
|
+
cacheWrite: cumulative.cacheWrite,
|
|
20803
|
+
inputIncludesCache: false,
|
|
20804
|
+
outputIncludesReasoning: true
|
|
20805
|
+
});
|
|
20806
|
+
if (projected2)
|
|
20807
|
+
this.commitClaudeModelUsage(backendSessionId, cumulative);
|
|
20808
|
+
return projected2;
|
|
20809
|
+
}
|
|
20810
|
+
const u = event?.usage;
|
|
20811
|
+
if (!u)
|
|
20812
|
+
return null;
|
|
20813
|
+
const projected = this.usageProjector.project({
|
|
20766
20814
|
runtime: "claude",
|
|
20767
20815
|
backendSessionId,
|
|
20768
20816
|
providerRecordId,
|
|
@@ -20774,6 +20822,102 @@ class ClaudeEventNormalizer {
|
|
|
20774
20822
|
inputIncludesCache: false,
|
|
20775
20823
|
outputIncludesReasoning: true
|
|
20776
20824
|
});
|
|
20825
|
+
if (projected)
|
|
20826
|
+
this.claudeUsageMode = "legacy";
|
|
20827
|
+
return projected;
|
|
20828
|
+
}
|
|
20829
|
+
prepareClaudeModelUsage(event, backendSessionId) {
|
|
20830
|
+
if (this.claudeUsageMode === "invalid")
|
|
20831
|
+
return null;
|
|
20832
|
+
if (!Object.hasOwn(event ?? {}, "modelUsage")) {
|
|
20833
|
+
if (this.claudeUsageMode !== "model_usage")
|
|
20834
|
+
return;
|
|
20835
|
+
return event?.usage ? this.lockClaudeUsageMode() : null;
|
|
20836
|
+
}
|
|
20837
|
+
if (this.claudeUsageMode === "legacy")
|
|
20838
|
+
return this.lockClaudeUsageMode();
|
|
20839
|
+
if (this.claudeUsageMode === "unknown")
|
|
20840
|
+
this.claudeUsageMode = "model_usage";
|
|
20841
|
+
this.claudeUsageSession ??= backendSessionId;
|
|
20842
|
+
if (this.claudeUsageSession !== null && this.claudeUsageSession !== backendSessionId) {
|
|
20843
|
+
return this.lockClaudeUsageMode();
|
|
20844
|
+
}
|
|
20845
|
+
if (!event.modelUsage || typeof event.modelUsage !== "object" || Array.isArray(event.modelUsage)) {
|
|
20846
|
+
return null;
|
|
20847
|
+
}
|
|
20848
|
+
const entries = Object.entries(event.modelUsage);
|
|
20849
|
+
if (entries.length === 0)
|
|
20850
|
+
return null;
|
|
20851
|
+
const highWater = new Map;
|
|
20852
|
+
let input = 0;
|
|
20853
|
+
let output = 0;
|
|
20854
|
+
let cacheRead = 0;
|
|
20855
|
+
let cacheWrite = 0;
|
|
20856
|
+
let snapshotCost = 0;
|
|
20857
|
+
for (const [model, rawValue] of entries) {
|
|
20858
|
+
if (!model.trim() || !rawValue || typeof rawValue !== "object" || Array.isArray(rawValue)) {
|
|
20859
|
+
return null;
|
|
20860
|
+
}
|
|
20861
|
+
const raw = rawValue;
|
|
20862
|
+
const current = {
|
|
20863
|
+
inputTokens: safeCount(raw.inputTokens),
|
|
20864
|
+
outputTokens: safeCount(raw.outputTokens),
|
|
20865
|
+
cacheReadInputTokens: safeCount(raw.cacheReadInputTokens),
|
|
20866
|
+
cacheCreationInputTokens: safeCount(raw.cacheCreationInputTokens),
|
|
20867
|
+
costUSD: safeMoney(raw.costUSD)
|
|
20868
|
+
};
|
|
20869
|
+
if (Object.values(current).some((value) => value === null)) {
|
|
20870
|
+
return null;
|
|
20871
|
+
}
|
|
20872
|
+
const snapshot = current;
|
|
20873
|
+
const prior = this.claudeModelUsageHighWater.get(model) ?? {
|
|
20874
|
+
inputTokens: 0,
|
|
20875
|
+
outputTokens: 0,
|
|
20876
|
+
cacheReadInputTokens: 0,
|
|
20877
|
+
cacheCreationInputTokens: 0,
|
|
20878
|
+
costUSD: 0
|
|
20879
|
+
};
|
|
20880
|
+
for (const component of CLAUDE_USAGE_COMPONENTS) {
|
|
20881
|
+
if (snapshot[component] < prior[component])
|
|
20882
|
+
return null;
|
|
20883
|
+
}
|
|
20884
|
+
if (snapshot.costUSD < prior.costUSD)
|
|
20885
|
+
return null;
|
|
20886
|
+
const nextInput = safeAdd(input, snapshot.inputTokens - prior.inputTokens);
|
|
20887
|
+
const nextOutput = safeAdd(output, snapshot.outputTokens - prior.outputTokens);
|
|
20888
|
+
const nextCacheRead = safeAdd(cacheRead, snapshot.cacheReadInputTokens - prior.cacheReadInputTokens);
|
|
20889
|
+
const nextCacheWrite = safeAdd(cacheWrite, snapshot.cacheCreationInputTokens - prior.cacheCreationInputTokens);
|
|
20890
|
+
if (nextInput === null || nextOutput === null || nextCacheRead === null || nextCacheWrite === null) {
|
|
20891
|
+
return null;
|
|
20892
|
+
}
|
|
20893
|
+
input = nextInput;
|
|
20894
|
+
output = nextOutput;
|
|
20895
|
+
cacheRead = nextCacheRead;
|
|
20896
|
+
cacheWrite = nextCacheWrite;
|
|
20897
|
+
snapshotCost += snapshot.costUSD;
|
|
20898
|
+
if (!Number.isFinite(snapshotCost))
|
|
20899
|
+
return null;
|
|
20900
|
+
highWater.set(model, snapshot);
|
|
20901
|
+
}
|
|
20902
|
+
for (const model of this.claudeModelUsageHighWater.keys()) {
|
|
20903
|
+
if (!highWater.has(model))
|
|
20904
|
+
return null;
|
|
20905
|
+
}
|
|
20906
|
+
if (Object.hasOwn(event, "total_cost_usd")) {
|
|
20907
|
+
const totalCost = safeMoney(event.total_cost_usd);
|
|
20908
|
+
if (totalCost === null || !equalCost(snapshotCost, totalCost))
|
|
20909
|
+
return null;
|
|
20910
|
+
}
|
|
20911
|
+
return { highWater, input, output, cacheRead, cacheWrite };
|
|
20912
|
+
}
|
|
20913
|
+
commitClaudeModelUsage(backendSessionId, projection) {
|
|
20914
|
+
this.claudeUsageSession ??= backendSessionId;
|
|
20915
|
+
this.claudeModelUsageHighWater = projection.highWater;
|
|
20916
|
+
this.claudeUsageMode = "model_usage";
|
|
20917
|
+
}
|
|
20918
|
+
lockClaudeUsageMode() {
|
|
20919
|
+
this.claudeUsageMode = "invalid";
|
|
20920
|
+
return null;
|
|
20777
20921
|
}
|
|
20778
20922
|
}
|
|
20779
20923
|
|
|
@@ -22255,7 +22399,8 @@ class CursorAcpLane {
|
|
|
22255
22399
|
started = false;
|
|
22256
22400
|
ready = false;
|
|
22257
22401
|
sessionId = null;
|
|
22258
|
-
|
|
22402
|
+
currentPromptRequestId = null;
|
|
22403
|
+
terminalOwner = null;
|
|
22259
22404
|
requestedStopReason;
|
|
22260
22405
|
spawnPromise;
|
|
22261
22406
|
stopPromise;
|
|
@@ -22327,16 +22472,19 @@ class CursorAcpLane {
|
|
|
22327
22472
|
async send(input) {
|
|
22328
22473
|
if (!this.ready || !this.process || this.isClosed())
|
|
22329
22474
|
return { ok: false, reason: "closed" };
|
|
22330
|
-
if (input.mode
|
|
22331
|
-
|
|
22475
|
+
if (input.mode === "busy") {
|
|
22476
|
+
if (this.currentPromptRequestId === null) {
|
|
22477
|
+
return { ok: false, reason: "runtime_busy", error: "Cursor ACP has no active prompt to steer" };
|
|
22478
|
+
}
|
|
22479
|
+
return this.admitPrompt(input.text, "steer");
|
|
22332
22480
|
}
|
|
22333
|
-
if (this.
|
|
22481
|
+
if (this.currentPromptRequestId !== null) {
|
|
22334
22482
|
return { ok: false, reason: "runtime_busy", error: "Cursor ACP prompt is still active" };
|
|
22335
22483
|
}
|
|
22336
22484
|
return this.admitPrompt(input.text);
|
|
22337
22485
|
}
|
|
22338
22486
|
async interrupt(_input) {
|
|
22339
|
-
if (!this.ready || !this.sessionId ||
|
|
22487
|
+
if (!this.ready || !this.sessionId || this.currentPromptRequestId === null || this.isClosed())
|
|
22340
22488
|
return false;
|
|
22341
22489
|
this.write({ jsonrpc: "2.0", method: "session/cancel", params: { sessionId: this.sessionId } });
|
|
22342
22490
|
return true;
|
|
@@ -22344,7 +22492,8 @@ class CursorAcpLane {
|
|
|
22344
22492
|
stop(input = {}) {
|
|
22345
22493
|
this.requestedStopReason ??= input.reason ?? "requested_stop";
|
|
22346
22494
|
this.ready = false;
|
|
22347
|
-
this.
|
|
22495
|
+
this.currentPromptRequestId = null;
|
|
22496
|
+
this.terminalOwner = null;
|
|
22348
22497
|
this.openToolCalls.clear();
|
|
22349
22498
|
this.rejectAllPending(new Error("Cursor ACP lane stopped"));
|
|
22350
22499
|
this.stopPromise ??= this.stopPhysicalOnce(input);
|
|
@@ -22450,19 +22599,22 @@ class CursorAcpLane {
|
|
|
22450
22599
|
throw new CursorAcpIncompatibleError("Cursor ACP did not confirm the exact configured model");
|
|
22451
22600
|
}
|
|
22452
22601
|
}
|
|
22453
|
-
admitPrompt(text2) {
|
|
22602
|
+
admitPrompt(text2, delivery = "prompt") {
|
|
22454
22603
|
if (!this.sessionId)
|
|
22455
22604
|
return { ok: false, reason: "not_ready", error: "Cursor ACP session is not ready" };
|
|
22456
|
-
if (this.activePrompt)
|
|
22457
|
-
return { ok: false, reason: "runtime_busy", error: "Cursor ACP prompt is still active" };
|
|
22458
22605
|
const requestId = ++this.requestSequence;
|
|
22459
|
-
const
|
|
22606
|
+
const prompt = {
|
|
22460
22607
|
requestId,
|
|
22461
22608
|
receipt: `cursor:acp:${requestId}`
|
|
22462
22609
|
};
|
|
22610
|
+
const previousPromptRequestId = this.currentPromptRequestId;
|
|
22611
|
+
const previousTerminalOwner = this.terminalOwner;
|
|
22612
|
+
const previousOpenToolCalls = new Set(this.openToolCalls);
|
|
22613
|
+
if (delivery === "prompt")
|
|
22614
|
+
this.terminalOwner = prompt.receipt;
|
|
22615
|
+
this.currentPromptRequestId = requestId;
|
|
22463
22616
|
this.openToolCalls.clear();
|
|
22464
|
-
this.
|
|
22465
|
-
this.pending.set(requestId, { kind: "prompt", method: "session/prompt", active });
|
|
22617
|
+
this.pending.set(requestId, { kind: "prompt", method: "session/prompt", prompt });
|
|
22466
22618
|
try {
|
|
22467
22619
|
this.write({
|
|
22468
22620
|
jsonrpc: "2.0",
|
|
@@ -22475,32 +22627,41 @@ class CursorAcpLane {
|
|
|
22475
22627
|
});
|
|
22476
22628
|
} catch (error51) {
|
|
22477
22629
|
this.pending.delete(requestId);
|
|
22478
|
-
if (this.
|
|
22479
|
-
this.
|
|
22630
|
+
if (this.currentPromptRequestId === requestId) {
|
|
22631
|
+
this.currentPromptRequestId = previousPromptRequestId;
|
|
22632
|
+
this.terminalOwner = previousTerminalOwner;
|
|
22633
|
+
this.openToolCalls.clear();
|
|
22634
|
+
for (const toolCallId of previousOpenToolCalls)
|
|
22635
|
+
this.openToolCalls.add(toolCallId);
|
|
22636
|
+
}
|
|
22480
22637
|
throw error51;
|
|
22481
22638
|
}
|
|
22482
|
-
return { ok: true, acceptedAs:
|
|
22639
|
+
return { ok: true, acceptedAs: delivery, receipt: prompt.receipt };
|
|
22483
22640
|
}
|
|
22484
|
-
completePrompt(
|
|
22485
|
-
if (this.
|
|
22641
|
+
completePrompt(prompt, value) {
|
|
22642
|
+
if (this.currentPromptRequestId !== prompt.requestId)
|
|
22486
22643
|
return;
|
|
22487
22644
|
const result = record3(value);
|
|
22488
22645
|
if (!result || typeof result.stopReason !== "string" || !PROMPT_STOP_REASONS.has(result.stopReason)) {
|
|
22489
|
-
this.failPrompt(
|
|
22646
|
+
this.failPrompt(prompt, new Error("Cursor ACP prompt response did not contain a supported stopReason"));
|
|
22490
22647
|
return;
|
|
22491
22648
|
}
|
|
22492
|
-
this.
|
|
22649
|
+
const terminalOwner = this.terminalOwner ?? prompt.receipt;
|
|
22650
|
+
this.currentPromptRequestId = null;
|
|
22651
|
+
this.terminalOwner = null;
|
|
22493
22652
|
this.openToolCalls.clear();
|
|
22494
22653
|
this.events.emit("runtime_event", {
|
|
22495
22654
|
kind: "turn_end",
|
|
22496
22655
|
sessionId: this.sessionId ?? undefined,
|
|
22497
|
-
turnOwner:
|
|
22656
|
+
turnOwner: terminalOwner
|
|
22498
22657
|
});
|
|
22499
22658
|
}
|
|
22500
|
-
failPrompt(
|
|
22501
|
-
if (this.
|
|
22659
|
+
failPrompt(prompt, error51) {
|
|
22660
|
+
if (this.currentPromptRequestId !== prompt.requestId)
|
|
22502
22661
|
return;
|
|
22503
|
-
this.
|
|
22662
|
+
const terminalOwner = this.terminalOwner ?? prompt.receipt;
|
|
22663
|
+
this.currentPromptRequestId = null;
|
|
22664
|
+
this.terminalOwner = null;
|
|
22504
22665
|
this.openToolCalls.clear();
|
|
22505
22666
|
this.events.emit("runtime_event", {
|
|
22506
22667
|
kind: "error",
|
|
@@ -22509,7 +22670,7 @@ class CursorAcpLane {
|
|
|
22509
22670
|
this.events.emit("runtime_event", {
|
|
22510
22671
|
kind: "turn_end",
|
|
22511
22672
|
sessionId: this.sessionId ?? undefined,
|
|
22512
|
-
turnOwner:
|
|
22673
|
+
turnOwner: terminalOwner
|
|
22513
22674
|
});
|
|
22514
22675
|
}
|
|
22515
22676
|
call(method, params) {
|
|
@@ -22595,7 +22756,8 @@ class CursorAcpLane {
|
|
|
22595
22756
|
}
|
|
22596
22757
|
this.processTerminal = true;
|
|
22597
22758
|
this.ready = false;
|
|
22598
|
-
this.
|
|
22759
|
+
this.currentPromptRequestId = null;
|
|
22760
|
+
this.terminalOwner = null;
|
|
22599
22761
|
this.openToolCalls.clear();
|
|
22600
22762
|
this.stopPromise ??= this.stopPhysicalOnce({ reason: "runtime_error", forceAfterMs: 0 });
|
|
22601
22763
|
this.stopPromise.catch(() => {});
|
|
@@ -22613,7 +22775,8 @@ class CursorAcpLane {
|
|
|
22613
22775
|
return;
|
|
22614
22776
|
this.processTerminal = true;
|
|
22615
22777
|
this.ready = false;
|
|
22616
|
-
this.
|
|
22778
|
+
this.currentPromptRequestId = null;
|
|
22779
|
+
this.terminalOwner = null;
|
|
22617
22780
|
this.openToolCalls.clear();
|
|
22618
22781
|
this.rejectAllPending(new Error("Cursor ACP process exited"));
|
|
22619
22782
|
if (this.suppressExit || !this.processActivated)
|
|
@@ -22655,11 +22818,11 @@ class CursorAcpLane {
|
|
|
22655
22818
|
this.pending.delete(id);
|
|
22656
22819
|
if (message2.error !== undefined) {
|
|
22657
22820
|
const payload = record3(message2.error);
|
|
22658
|
-
this.failPrompt(pending.
|
|
22821
|
+
this.failPrompt(pending.prompt, new CursorAcpRpcError(pending.method, typeof payload?.code === "number" ? payload.code : undefined, rpcErrorMessage(message2.error)));
|
|
22659
22822
|
} else if (!("result" in message2)) {
|
|
22660
|
-
this.failPrompt(pending.
|
|
22823
|
+
this.failPrompt(pending.prompt, new Error("Cursor ACP response omitted result"));
|
|
22661
22824
|
} else {
|
|
22662
|
-
this.completePrompt(pending.
|
|
22825
|
+
this.completePrompt(pending.prompt, message2.result);
|
|
22663
22826
|
}
|
|
22664
22827
|
return;
|
|
22665
22828
|
}
|
|
@@ -22700,7 +22863,7 @@ class CursorAcpLane {
|
|
|
22700
22863
|
const sameSession = payload?.sessionId === this.sessionId;
|
|
22701
22864
|
const options = Array.isArray(payload?.options) ? payload.options.map(record3).filter(Boolean) : [];
|
|
22702
22865
|
const allowOnce = options.find((option) => option.kind === "allow_once" && typeof option.optionId === "string" && option.optionId.trim().length > 0);
|
|
22703
|
-
if (!this.ready ||
|
|
22866
|
+
if (!this.ready || this.currentPromptRequestId === null || !sameSession || !allowOnce) {
|
|
22704
22867
|
this.write({ jsonrpc: "2.0", id, result: { outcome: { outcome: "cancelled" } } });
|
|
22705
22868
|
this.diagnostic("error", "Cursor ACP permission request was not allowed for the active prompt");
|
|
22706
22869
|
return;
|
|
@@ -22724,7 +22887,7 @@ class CursorAcpLane {
|
|
|
22724
22887
|
this.diagnostic("warning", "Cursor ACP emitted an update for a different session");
|
|
22725
22888
|
return;
|
|
22726
22889
|
}
|
|
22727
|
-
if (!this.ready ||
|
|
22890
|
+
if (!this.ready || this.currentPromptRequestId === null) {
|
|
22728
22891
|
this.diagnostic("warning", "Cursor ACP emitted a session update without an active prompt");
|
|
22729
22892
|
return;
|
|
22730
22893
|
}
|
|
@@ -24652,7 +24815,7 @@ var capabilities = {
|
|
|
24652
24815
|
commandOverride: true,
|
|
24653
24816
|
resume: "by_id",
|
|
24654
24817
|
sessionLifetime: "persistent",
|
|
24655
|
-
midTurnDelivery: "
|
|
24818
|
+
midTurnDelivery: "steer",
|
|
24656
24819
|
interrupt: true
|
|
24657
24820
|
},
|
|
24658
24821
|
opencode: {
|
|
@@ -32616,12 +32779,15 @@ class DaemonSelfSleepScheduler {
|
|
|
32616
32779
|
import { chmod, mkdir, open, readFile as readFile2, rename, rm } from "node:fs/promises";
|
|
32617
32780
|
import { dirname as dirname6, join as join14 } from "node:path";
|
|
32618
32781
|
import { randomUUID as randomUUID7 } from "node:crypto";
|
|
32782
|
+
var TOKEN_USAGE_WINDOW_DAYS = 30;
|
|
32783
|
+
var TOKEN_USAGE_RECOVERY_DAYS = 2;
|
|
32784
|
+
var TOKEN_USAGE_RETENTION_DAYS = TOKEN_USAGE_WINDOW_DAYS + TOKEN_USAGE_RECOVERY_DAYS;
|
|
32619
32785
|
function oldestRetainedDay(at, timeZone) {
|
|
32620
32786
|
const today = dayKeyInTimeZone(at, timeZone);
|
|
32621
|
-
return calendarDayKeyDaysAgo(today,
|
|
32787
|
+
return calendarDayKeyDaysAgo(today, TOKEN_USAGE_RETENTION_DAYS - 1);
|
|
32622
32788
|
}
|
|
32623
32789
|
function oldestVisibleDay(today) {
|
|
32624
|
-
return calendarDayKeyDaysAgo(today,
|
|
32790
|
+
return calendarDayKeyDaysAgo(today, TOKEN_USAGE_WINDOW_DAYS - 1);
|
|
32625
32791
|
}
|
|
32626
32792
|
function isMetric(value) {
|
|
32627
32793
|
return value === null || typeof value === "number" && Number.isSafeInteger(value) && value >= 0;
|
package/dist/index.js
CHANGED
|
@@ -1200,11 +1200,33 @@ function tryParseJsonLine(line) {
|
|
|
1200
1200
|
|
|
1201
1201
|
// agent-driver/dist/adapters/claude/normalizer.js
|
|
1202
1202
|
var API_ERROR_RE = /API Error:.*(?:Connection error|\b[45]\d{2}\b)/i;
|
|
1203
|
+
var CLAUDE_USAGE_COMPONENTS = [
|
|
1204
|
+
"inputTokens",
|
|
1205
|
+
"outputTokens",
|
|
1206
|
+
"cacheReadInputTokens",
|
|
1207
|
+
"cacheCreationInputTokens"
|
|
1208
|
+
];
|
|
1209
|
+
function safeCount(value) {
|
|
1210
|
+
return typeof value === "number" && Number.isSafeInteger(value) && value >= 0 ? value : null;
|
|
1211
|
+
}
|
|
1212
|
+
function safeMoney(value) {
|
|
1213
|
+
return typeof value === "number" && Number.isFinite(value) && value >= 0 ? value : null;
|
|
1214
|
+
}
|
|
1215
|
+
function safeAdd(left, right) {
|
|
1216
|
+
const total = left + right;
|
|
1217
|
+
return Number.isSafeInteger(total) ? total : null;
|
|
1218
|
+
}
|
|
1219
|
+
function equalCost(left, right) {
|
|
1220
|
+
return Math.abs(left - right) <= Math.max(0.000000000001, Math.abs(right) * 0.000000001);
|
|
1221
|
+
}
|
|
1203
1222
|
|
|
1204
1223
|
class ClaudeEventNormalizer {
|
|
1205
1224
|
turnProtocol;
|
|
1206
1225
|
currentSession = null;
|
|
1207
1226
|
usageProjector = new SettledUsageProjector;
|
|
1227
|
+
claudeUsageSession = null;
|
|
1228
|
+
claudeModelUsageHighWater = new Map;
|
|
1229
|
+
claudeUsageMode = "unknown";
|
|
1208
1230
|
constructor(turnProtocol) {
|
|
1209
1231
|
this.turnProtocol = turnProtocol;
|
|
1210
1232
|
}
|
|
@@ -1318,14 +1340,39 @@ class ClaudeEventNormalizer {
|
|
|
1318
1340
|
return this.turnProtocol?.acceptsTurnWork() ?? true;
|
|
1319
1341
|
}
|
|
1320
1342
|
buildUsageTelemetry(event, rootRequestId) {
|
|
1321
|
-
const u = event?.usage;
|
|
1322
|
-
if (!u)
|
|
1323
|
-
return null;
|
|
1324
1343
|
const backendSessionId = event.session_id ?? this.currentSession;
|
|
1325
1344
|
if (typeof backendSessionId !== "string" || !backendSessionId)
|
|
1326
1345
|
return null;
|
|
1327
1346
|
const providerRecordId = rootRequestId ?? (typeof event.request_id === "string" ? event.request_id : "invocation-result");
|
|
1328
|
-
|
|
1347
|
+
const cumulative = this.prepareClaudeModelUsage(event, backendSessionId);
|
|
1348
|
+
if (cumulative === null)
|
|
1349
|
+
return null;
|
|
1350
|
+
if (cumulative) {
|
|
1351
|
+
const hasDelta = cumulative.input > 0 || cumulative.output > 0 || cumulative.cacheRead > 0 || cumulative.cacheWrite > 0;
|
|
1352
|
+
if (!hasDelta) {
|
|
1353
|
+
this.commitClaudeModelUsage(backendSessionId, cumulative);
|
|
1354
|
+
return null;
|
|
1355
|
+
}
|
|
1356
|
+
const projected2 = this.usageProjector.project({
|
|
1357
|
+
runtime: "claude",
|
|
1358
|
+
backendSessionId,
|
|
1359
|
+
providerRecordId,
|
|
1360
|
+
source: "claude_result_model_usage",
|
|
1361
|
+
input: cumulative.input,
|
|
1362
|
+
output: cumulative.output,
|
|
1363
|
+
cacheRead: cumulative.cacheRead,
|
|
1364
|
+
cacheWrite: cumulative.cacheWrite,
|
|
1365
|
+
inputIncludesCache: false,
|
|
1366
|
+
outputIncludesReasoning: true
|
|
1367
|
+
});
|
|
1368
|
+
if (projected2)
|
|
1369
|
+
this.commitClaudeModelUsage(backendSessionId, cumulative);
|
|
1370
|
+
return projected2;
|
|
1371
|
+
}
|
|
1372
|
+
const u = event?.usage;
|
|
1373
|
+
if (!u)
|
|
1374
|
+
return null;
|
|
1375
|
+
const projected = this.usageProjector.project({
|
|
1329
1376
|
runtime: "claude",
|
|
1330
1377
|
backendSessionId,
|
|
1331
1378
|
providerRecordId,
|
|
@@ -1337,6 +1384,102 @@ class ClaudeEventNormalizer {
|
|
|
1337
1384
|
inputIncludesCache: false,
|
|
1338
1385
|
outputIncludesReasoning: true
|
|
1339
1386
|
});
|
|
1387
|
+
if (projected)
|
|
1388
|
+
this.claudeUsageMode = "legacy";
|
|
1389
|
+
return projected;
|
|
1390
|
+
}
|
|
1391
|
+
prepareClaudeModelUsage(event, backendSessionId) {
|
|
1392
|
+
if (this.claudeUsageMode === "invalid")
|
|
1393
|
+
return null;
|
|
1394
|
+
if (!Object.hasOwn(event ?? {}, "modelUsage")) {
|
|
1395
|
+
if (this.claudeUsageMode !== "model_usage")
|
|
1396
|
+
return;
|
|
1397
|
+
return event?.usage ? this.lockClaudeUsageMode() : null;
|
|
1398
|
+
}
|
|
1399
|
+
if (this.claudeUsageMode === "legacy")
|
|
1400
|
+
return this.lockClaudeUsageMode();
|
|
1401
|
+
if (this.claudeUsageMode === "unknown")
|
|
1402
|
+
this.claudeUsageMode = "model_usage";
|
|
1403
|
+
this.claudeUsageSession ??= backendSessionId;
|
|
1404
|
+
if (this.claudeUsageSession !== null && this.claudeUsageSession !== backendSessionId) {
|
|
1405
|
+
return this.lockClaudeUsageMode();
|
|
1406
|
+
}
|
|
1407
|
+
if (!event.modelUsage || typeof event.modelUsage !== "object" || Array.isArray(event.modelUsage)) {
|
|
1408
|
+
return null;
|
|
1409
|
+
}
|
|
1410
|
+
const entries = Object.entries(event.modelUsage);
|
|
1411
|
+
if (entries.length === 0)
|
|
1412
|
+
return null;
|
|
1413
|
+
const highWater = new Map;
|
|
1414
|
+
let input = 0;
|
|
1415
|
+
let output = 0;
|
|
1416
|
+
let cacheRead = 0;
|
|
1417
|
+
let cacheWrite = 0;
|
|
1418
|
+
let snapshotCost = 0;
|
|
1419
|
+
for (const [model, rawValue] of entries) {
|
|
1420
|
+
if (!model.trim() || !rawValue || typeof rawValue !== "object" || Array.isArray(rawValue)) {
|
|
1421
|
+
return null;
|
|
1422
|
+
}
|
|
1423
|
+
const raw = rawValue;
|
|
1424
|
+
const current = {
|
|
1425
|
+
inputTokens: safeCount(raw.inputTokens),
|
|
1426
|
+
outputTokens: safeCount(raw.outputTokens),
|
|
1427
|
+
cacheReadInputTokens: safeCount(raw.cacheReadInputTokens),
|
|
1428
|
+
cacheCreationInputTokens: safeCount(raw.cacheCreationInputTokens),
|
|
1429
|
+
costUSD: safeMoney(raw.costUSD)
|
|
1430
|
+
};
|
|
1431
|
+
if (Object.values(current).some((value) => value === null)) {
|
|
1432
|
+
return null;
|
|
1433
|
+
}
|
|
1434
|
+
const snapshot = current;
|
|
1435
|
+
const prior = this.claudeModelUsageHighWater.get(model) ?? {
|
|
1436
|
+
inputTokens: 0,
|
|
1437
|
+
outputTokens: 0,
|
|
1438
|
+
cacheReadInputTokens: 0,
|
|
1439
|
+
cacheCreationInputTokens: 0,
|
|
1440
|
+
costUSD: 0
|
|
1441
|
+
};
|
|
1442
|
+
for (const component of CLAUDE_USAGE_COMPONENTS) {
|
|
1443
|
+
if (snapshot[component] < prior[component])
|
|
1444
|
+
return null;
|
|
1445
|
+
}
|
|
1446
|
+
if (snapshot.costUSD < prior.costUSD)
|
|
1447
|
+
return null;
|
|
1448
|
+
const nextInput = safeAdd(input, snapshot.inputTokens - prior.inputTokens);
|
|
1449
|
+
const nextOutput = safeAdd(output, snapshot.outputTokens - prior.outputTokens);
|
|
1450
|
+
const nextCacheRead = safeAdd(cacheRead, snapshot.cacheReadInputTokens - prior.cacheReadInputTokens);
|
|
1451
|
+
const nextCacheWrite = safeAdd(cacheWrite, snapshot.cacheCreationInputTokens - prior.cacheCreationInputTokens);
|
|
1452
|
+
if (nextInput === null || nextOutput === null || nextCacheRead === null || nextCacheWrite === null) {
|
|
1453
|
+
return null;
|
|
1454
|
+
}
|
|
1455
|
+
input = nextInput;
|
|
1456
|
+
output = nextOutput;
|
|
1457
|
+
cacheRead = nextCacheRead;
|
|
1458
|
+
cacheWrite = nextCacheWrite;
|
|
1459
|
+
snapshotCost += snapshot.costUSD;
|
|
1460
|
+
if (!Number.isFinite(snapshotCost))
|
|
1461
|
+
return null;
|
|
1462
|
+
highWater.set(model, snapshot);
|
|
1463
|
+
}
|
|
1464
|
+
for (const model of this.claudeModelUsageHighWater.keys()) {
|
|
1465
|
+
if (!highWater.has(model))
|
|
1466
|
+
return null;
|
|
1467
|
+
}
|
|
1468
|
+
if (Object.hasOwn(event, "total_cost_usd")) {
|
|
1469
|
+
const totalCost = safeMoney(event.total_cost_usd);
|
|
1470
|
+
if (totalCost === null || !equalCost(snapshotCost, totalCost))
|
|
1471
|
+
return null;
|
|
1472
|
+
}
|
|
1473
|
+
return { highWater, input, output, cacheRead, cacheWrite };
|
|
1474
|
+
}
|
|
1475
|
+
commitClaudeModelUsage(backendSessionId, projection) {
|
|
1476
|
+
this.claudeUsageSession ??= backendSessionId;
|
|
1477
|
+
this.claudeModelUsageHighWater = projection.highWater;
|
|
1478
|
+
this.claudeUsageMode = "model_usage";
|
|
1479
|
+
}
|
|
1480
|
+
lockClaudeUsageMode() {
|
|
1481
|
+
this.claudeUsageMode = "invalid";
|
|
1482
|
+
return null;
|
|
1340
1483
|
}
|
|
1341
1484
|
}
|
|
1342
1485
|
|
|
@@ -2818,7 +2961,8 @@ class CursorAcpLane {
|
|
|
2818
2961
|
started = false;
|
|
2819
2962
|
ready = false;
|
|
2820
2963
|
sessionId = null;
|
|
2821
|
-
|
|
2964
|
+
currentPromptRequestId = null;
|
|
2965
|
+
terminalOwner = null;
|
|
2822
2966
|
requestedStopReason;
|
|
2823
2967
|
spawnPromise;
|
|
2824
2968
|
stopPromise;
|
|
@@ -2890,16 +3034,19 @@ class CursorAcpLane {
|
|
|
2890
3034
|
async send(input) {
|
|
2891
3035
|
if (!this.ready || !this.process || this.isClosed())
|
|
2892
3036
|
return { ok: false, reason: "closed" };
|
|
2893
|
-
if (input.mode
|
|
2894
|
-
|
|
3037
|
+
if (input.mode === "busy") {
|
|
3038
|
+
if (this.currentPromptRequestId === null) {
|
|
3039
|
+
return { ok: false, reason: "runtime_busy", error: "Cursor ACP has no active prompt to steer" };
|
|
3040
|
+
}
|
|
3041
|
+
return this.admitPrompt(input.text, "steer");
|
|
2895
3042
|
}
|
|
2896
|
-
if (this.
|
|
3043
|
+
if (this.currentPromptRequestId !== null) {
|
|
2897
3044
|
return { ok: false, reason: "runtime_busy", error: "Cursor ACP prompt is still active" };
|
|
2898
3045
|
}
|
|
2899
3046
|
return this.admitPrompt(input.text);
|
|
2900
3047
|
}
|
|
2901
3048
|
async interrupt(_input) {
|
|
2902
|
-
if (!this.ready || !this.sessionId ||
|
|
3049
|
+
if (!this.ready || !this.sessionId || this.currentPromptRequestId === null || this.isClosed())
|
|
2903
3050
|
return false;
|
|
2904
3051
|
this.write({ jsonrpc: "2.0", method: "session/cancel", params: { sessionId: this.sessionId } });
|
|
2905
3052
|
return true;
|
|
@@ -2907,7 +3054,8 @@ class CursorAcpLane {
|
|
|
2907
3054
|
stop(input = {}) {
|
|
2908
3055
|
this.requestedStopReason ??= input.reason ?? "requested_stop";
|
|
2909
3056
|
this.ready = false;
|
|
2910
|
-
this.
|
|
3057
|
+
this.currentPromptRequestId = null;
|
|
3058
|
+
this.terminalOwner = null;
|
|
2911
3059
|
this.openToolCalls.clear();
|
|
2912
3060
|
this.rejectAllPending(new Error("Cursor ACP lane stopped"));
|
|
2913
3061
|
this.stopPromise ??= this.stopPhysicalOnce(input);
|
|
@@ -3013,19 +3161,22 @@ class CursorAcpLane {
|
|
|
3013
3161
|
throw new CursorAcpIncompatibleError("Cursor ACP did not confirm the exact configured model");
|
|
3014
3162
|
}
|
|
3015
3163
|
}
|
|
3016
|
-
admitPrompt(text) {
|
|
3164
|
+
admitPrompt(text, delivery = "prompt") {
|
|
3017
3165
|
if (!this.sessionId)
|
|
3018
3166
|
return { ok: false, reason: "not_ready", error: "Cursor ACP session is not ready" };
|
|
3019
|
-
if (this.activePrompt)
|
|
3020
|
-
return { ok: false, reason: "runtime_busy", error: "Cursor ACP prompt is still active" };
|
|
3021
3167
|
const requestId = ++this.requestSequence;
|
|
3022
|
-
const
|
|
3168
|
+
const prompt = {
|
|
3023
3169
|
requestId,
|
|
3024
3170
|
receipt: `cursor:acp:${requestId}`
|
|
3025
3171
|
};
|
|
3172
|
+
const previousPromptRequestId = this.currentPromptRequestId;
|
|
3173
|
+
const previousTerminalOwner = this.terminalOwner;
|
|
3174
|
+
const previousOpenToolCalls = new Set(this.openToolCalls);
|
|
3175
|
+
if (delivery === "prompt")
|
|
3176
|
+
this.terminalOwner = prompt.receipt;
|
|
3177
|
+
this.currentPromptRequestId = requestId;
|
|
3026
3178
|
this.openToolCalls.clear();
|
|
3027
|
-
this.
|
|
3028
|
-
this.pending.set(requestId, { kind: "prompt", method: "session/prompt", active });
|
|
3179
|
+
this.pending.set(requestId, { kind: "prompt", method: "session/prompt", prompt });
|
|
3029
3180
|
try {
|
|
3030
3181
|
this.write({
|
|
3031
3182
|
jsonrpc: "2.0",
|
|
@@ -3038,32 +3189,41 @@ class CursorAcpLane {
|
|
|
3038
3189
|
});
|
|
3039
3190
|
} catch (error) {
|
|
3040
3191
|
this.pending.delete(requestId);
|
|
3041
|
-
if (this.
|
|
3042
|
-
this.
|
|
3192
|
+
if (this.currentPromptRequestId === requestId) {
|
|
3193
|
+
this.currentPromptRequestId = previousPromptRequestId;
|
|
3194
|
+
this.terminalOwner = previousTerminalOwner;
|
|
3195
|
+
this.openToolCalls.clear();
|
|
3196
|
+
for (const toolCallId of previousOpenToolCalls)
|
|
3197
|
+
this.openToolCalls.add(toolCallId);
|
|
3198
|
+
}
|
|
3043
3199
|
throw error;
|
|
3044
3200
|
}
|
|
3045
|
-
return { ok: true, acceptedAs:
|
|
3201
|
+
return { ok: true, acceptedAs: delivery, receipt: prompt.receipt };
|
|
3046
3202
|
}
|
|
3047
|
-
completePrompt(
|
|
3048
|
-
if (this.
|
|
3203
|
+
completePrompt(prompt, value) {
|
|
3204
|
+
if (this.currentPromptRequestId !== prompt.requestId)
|
|
3049
3205
|
return;
|
|
3050
3206
|
const result = record2(value);
|
|
3051
3207
|
if (!result || typeof result.stopReason !== "string" || !PROMPT_STOP_REASONS.has(result.stopReason)) {
|
|
3052
|
-
this.failPrompt(
|
|
3208
|
+
this.failPrompt(prompt, new Error("Cursor ACP prompt response did not contain a supported stopReason"));
|
|
3053
3209
|
return;
|
|
3054
3210
|
}
|
|
3055
|
-
this.
|
|
3211
|
+
const terminalOwner = this.terminalOwner ?? prompt.receipt;
|
|
3212
|
+
this.currentPromptRequestId = null;
|
|
3213
|
+
this.terminalOwner = null;
|
|
3056
3214
|
this.openToolCalls.clear();
|
|
3057
3215
|
this.events.emit("runtime_event", {
|
|
3058
3216
|
kind: "turn_end",
|
|
3059
3217
|
sessionId: this.sessionId ?? undefined,
|
|
3060
|
-
turnOwner:
|
|
3218
|
+
turnOwner: terminalOwner
|
|
3061
3219
|
});
|
|
3062
3220
|
}
|
|
3063
|
-
failPrompt(
|
|
3064
|
-
if (this.
|
|
3221
|
+
failPrompt(prompt, error) {
|
|
3222
|
+
if (this.currentPromptRequestId !== prompt.requestId)
|
|
3065
3223
|
return;
|
|
3066
|
-
this.
|
|
3224
|
+
const terminalOwner = this.terminalOwner ?? prompt.receipt;
|
|
3225
|
+
this.currentPromptRequestId = null;
|
|
3226
|
+
this.terminalOwner = null;
|
|
3067
3227
|
this.openToolCalls.clear();
|
|
3068
3228
|
this.events.emit("runtime_event", {
|
|
3069
3229
|
kind: "error",
|
|
@@ -3072,7 +3232,7 @@ class CursorAcpLane {
|
|
|
3072
3232
|
this.events.emit("runtime_event", {
|
|
3073
3233
|
kind: "turn_end",
|
|
3074
3234
|
sessionId: this.sessionId ?? undefined,
|
|
3075
|
-
turnOwner:
|
|
3235
|
+
turnOwner: terminalOwner
|
|
3076
3236
|
});
|
|
3077
3237
|
}
|
|
3078
3238
|
call(method, params) {
|
|
@@ -3158,7 +3318,8 @@ class CursorAcpLane {
|
|
|
3158
3318
|
}
|
|
3159
3319
|
this.processTerminal = true;
|
|
3160
3320
|
this.ready = false;
|
|
3161
|
-
this.
|
|
3321
|
+
this.currentPromptRequestId = null;
|
|
3322
|
+
this.terminalOwner = null;
|
|
3162
3323
|
this.openToolCalls.clear();
|
|
3163
3324
|
this.stopPromise ??= this.stopPhysicalOnce({ reason: "runtime_error", forceAfterMs: 0 });
|
|
3164
3325
|
this.stopPromise.catch(() => {});
|
|
@@ -3176,7 +3337,8 @@ class CursorAcpLane {
|
|
|
3176
3337
|
return;
|
|
3177
3338
|
this.processTerminal = true;
|
|
3178
3339
|
this.ready = false;
|
|
3179
|
-
this.
|
|
3340
|
+
this.currentPromptRequestId = null;
|
|
3341
|
+
this.terminalOwner = null;
|
|
3180
3342
|
this.openToolCalls.clear();
|
|
3181
3343
|
this.rejectAllPending(new Error("Cursor ACP process exited"));
|
|
3182
3344
|
if (this.suppressExit || !this.processActivated)
|
|
@@ -3218,11 +3380,11 @@ class CursorAcpLane {
|
|
|
3218
3380
|
this.pending.delete(id);
|
|
3219
3381
|
if (message.error !== undefined) {
|
|
3220
3382
|
const payload = record2(message.error);
|
|
3221
|
-
this.failPrompt(pending.
|
|
3383
|
+
this.failPrompt(pending.prompt, new CursorAcpRpcError(pending.method, typeof payload?.code === "number" ? payload.code : undefined, rpcErrorMessage(message.error)));
|
|
3222
3384
|
} else if (!("result" in message)) {
|
|
3223
|
-
this.failPrompt(pending.
|
|
3385
|
+
this.failPrompt(pending.prompt, new Error("Cursor ACP response omitted result"));
|
|
3224
3386
|
} else {
|
|
3225
|
-
this.completePrompt(pending.
|
|
3387
|
+
this.completePrompt(pending.prompt, message.result);
|
|
3226
3388
|
}
|
|
3227
3389
|
return;
|
|
3228
3390
|
}
|
|
@@ -3263,7 +3425,7 @@ class CursorAcpLane {
|
|
|
3263
3425
|
const sameSession = payload?.sessionId === this.sessionId;
|
|
3264
3426
|
const options = Array.isArray(payload?.options) ? payload.options.map(record2).filter(Boolean) : [];
|
|
3265
3427
|
const allowOnce = options.find((option) => option.kind === "allow_once" && typeof option.optionId === "string" && option.optionId.trim().length > 0);
|
|
3266
|
-
if (!this.ready ||
|
|
3428
|
+
if (!this.ready || this.currentPromptRequestId === null || !sameSession || !allowOnce) {
|
|
3267
3429
|
this.write({ jsonrpc: "2.0", id, result: { outcome: { outcome: "cancelled" } } });
|
|
3268
3430
|
this.diagnostic("error", "Cursor ACP permission request was not allowed for the active prompt");
|
|
3269
3431
|
return;
|
|
@@ -3287,7 +3449,7 @@ class CursorAcpLane {
|
|
|
3287
3449
|
this.diagnostic("warning", "Cursor ACP emitted an update for a different session");
|
|
3288
3450
|
return;
|
|
3289
3451
|
}
|
|
3290
|
-
if (!this.ready ||
|
|
3452
|
+
if (!this.ready || this.currentPromptRequestId === null) {
|
|
3291
3453
|
this.diagnostic("warning", "Cursor ACP emitted a session update without an active prompt");
|
|
3292
3454
|
return;
|
|
3293
3455
|
}
|
|
@@ -5215,7 +5377,7 @@ var capabilities = {
|
|
|
5215
5377
|
commandOverride: true,
|
|
5216
5378
|
resume: "by_id",
|
|
5217
5379
|
sessionLifetime: "persistent",
|
|
5218
|
-
midTurnDelivery: "
|
|
5380
|
+
midTurnDelivery: "steer",
|
|
5219
5381
|
interrupt: true
|
|
5220
5382
|
},
|
|
5221
5383
|
opencode: {
|
|
@@ -28394,6 +28556,7 @@ var ALLOWED_ICON_MIME_TYPES = [
|
|
|
28394
28556
|
];
|
|
28395
28557
|
var MAX_ICON_SOURCE_FILE_SIZE_BYTES = 15 * 1024 * 1024;
|
|
28396
28558
|
// ../shared/src/provider-telemetry.ts
|
|
28559
|
+
var DAILY_TOKEN_USAGE_WINDOW_DAYS = 30;
|
|
28397
28560
|
var safeToken = exports_external.number().int().min(0).max(Number.MAX_SAFE_INTEGER);
|
|
28398
28561
|
var boundedText = exports_external.string().min(1).refine((value) => new TextEncoder().encode(value).length <= 64, { message: "must be at most 64 UTF-8 bytes" });
|
|
28399
28562
|
var DailyUsageMetricSchema = safeToken.nullable();
|
|
@@ -29125,7 +29288,7 @@ var AgentActivityMessageSchema = exports_external.object({
|
|
|
29125
29288
|
state: exports_external.enum(["idle", "starting", "running", "stopping"]),
|
|
29126
29289
|
usageTimeZone: exports_external.string().min(1).max(128).optional(),
|
|
29127
29290
|
usageDay: exports_external.string().regex(/^\d{4}-\d{2}-\d{2}$/).optional(),
|
|
29128
|
-
dailyUsage: exports_external.array(DailyUsageSnapshotSchema).max(
|
|
29291
|
+
dailyUsage: exports_external.array(DailyUsageSnapshotSchema).max(DAILY_TOKEN_USAGE_WINDOW_DAYS).optional(),
|
|
29129
29292
|
quota: ProviderQuotaSnapshotSchema.optional()
|
|
29130
29293
|
});
|
|
29131
29294
|
var AgentTypingMessageSchema = exports_external.object({
|
|
@@ -32914,12 +33077,15 @@ class DaemonSelfSleepScheduler {
|
|
|
32914
33077
|
import { chmod, mkdir, open, readFile as readFile2, rename, rm } from "node:fs/promises";
|
|
32915
33078
|
import { dirname as dirname5, join as join14 } from "node:path";
|
|
32916
33079
|
import { randomUUID as randomUUID7 } from "node:crypto";
|
|
33080
|
+
var TOKEN_USAGE_WINDOW_DAYS = 30;
|
|
33081
|
+
var TOKEN_USAGE_RECOVERY_DAYS = 2;
|
|
33082
|
+
var TOKEN_USAGE_RETENTION_DAYS = TOKEN_USAGE_WINDOW_DAYS + TOKEN_USAGE_RECOVERY_DAYS;
|
|
32917
33083
|
function oldestRetainedDay(at, timeZone) {
|
|
32918
33084
|
const today = dayKeyInTimeZone(at, timeZone);
|
|
32919
|
-
return calendarDayKeyDaysAgo(today,
|
|
33085
|
+
return calendarDayKeyDaysAgo(today, TOKEN_USAGE_RETENTION_DAYS - 1);
|
|
32920
33086
|
}
|
|
32921
33087
|
function oldestVisibleDay(today) {
|
|
32922
|
-
return calendarDayKeyDaysAgo(today,
|
|
33088
|
+
return calendarDayKeyDaysAgo(today, TOKEN_USAGE_WINDOW_DAYS - 1);
|
|
32923
33089
|
}
|
|
32924
33090
|
function isMetric(value) {
|
|
32925
33091
|
return value === null || typeof value === "number" && Number.isSafeInteger(value) && value >= 0;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@alook/daemon",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.29",
|
|
4
4
|
"description": "Alook agent daemon — host-side runtime backend, process manager, credential proxy, and control plane.",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"homepage": "https://github.com/alookai/alook#readme",
|