agent-dealer 1.2.1 → 1.2.3
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/bundle/server/dist/adapters/linear-inbox.js +9 -5
- package/bundle/server/dist/capacity/adapter.js +2 -0
- package/bundle/server/dist/capacity/claude-events.js +45 -10
- package/bundle/server/dist/capacity/claude-events.test.js +7 -0
- package/bundle/server/dist/capacity/claude-local-cache.js +788 -0
- package/bundle/server/dist/capacity/claude-local-cache.test.js +520 -0
- package/bundle/server/dist/capacity/codex-app-server.js +100 -10
- package/bundle/server/dist/capacity/codex-app-server.test.js +195 -2
- package/bundle/server/dist/capacity/cursor-individual-credentials.js +425 -0
- package/bundle/server/dist/capacity/cursor-individual-credentials.test.js +369 -0
- package/bundle/server/dist/capacity/cursor-individual.js +1037 -0
- package/bundle/server/dist/capacity/cursor-individual.test.js +1081 -0
- package/bundle/server/dist/capacity/muse-host.js +748 -0
- package/bundle/server/dist/capacity/muse-host.test.js +480 -0
- package/bundle/server/dist/capacity/muse-lifecycle.test.js +97 -0
- package/bundle/server/dist/capacity/muse.js +389 -91
- package/bundle/server/dist/capacity/muse.test.js +100 -61
- package/bundle/server/dist/capacity/service.js +1 -0
- package/bundle/server/dist/coordinator/muse-spawn.js +143 -1
- package/bundle/server/dist/db/index.js +30 -0
- package/bundle/server/dist/db/schema.sql +27 -0
- package/bundle/server/dist/index.js +17 -2
- package/bundle/server/dist/repository/cursor-individual-billing.js +84 -0
- package/bundle/server/dist/repository/repository-mappings.js +46 -0
- package/bundle/server/dist/repository/repository-mappings.test.js +83 -0
- package/bundle/server/dist/repository/runtime-capacity.js +8 -3
- package/bundle/server/dist/repository/runtime-capacity.test.js +4 -0
- package/bundle/server/dist/routes/cursor-individual-billing.test.js +80 -0
- package/bundle/server/dist/routes/index.js +58 -9
- package/bundle/server/dist/routes/intake-linear.test.js +55 -1
- package/bundle/server/dist/routes/repository-mappings.js +22 -0
- package/bundle/server/dist/routes/repository-mappings.test.js +110 -0
- package/bundle/server/dist/routes/runtime-capacity.test.js +84 -8
- package/bundle/server/dist/runners/muse-code-jsonl.js +7 -1
- package/bundle/server/dist/runners/muse-serve-session.js +313 -0
- package/bundle/server/dist/runners/muse-serve-session.test.js +325 -0
- package/bundle/server/package.json +2 -2
- package/bundle/server/static-ui/assets/codex-YZSpL-SB.png +0 -0
- package/bundle/server/static-ui/assets/index-CYqRh_-S.css +1 -0
- package/bundle/server/static-ui/assets/index-UO4lHZw4.js +60 -0
- package/bundle/server/static-ui/assets/muse-CtdcC6ve.svg +33 -0
- package/bundle/server/static-ui/index.html +2 -2
- package/bundle/shared/dist/index.d.ts +6 -6
- package/bundle/shared/dist/linear-intake.d.ts +71 -0
- package/bundle/shared/dist/linear-intake.js +90 -0
- package/bundle/shared/dist/linear-intake.test.js +80 -1
- package/bundle/shared/dist/runtime-capacity.d.ts +89 -0
- package/bundle/shared/dist/runtime-capacity.js +60 -0
- package/bundle/shared/dist/runtime-capacity.test.js +1 -0
- package/bundle/shared/package.json +1 -1
- package/dist/doctor.d.ts +57 -0
- package/dist/doctor.js +211 -0
- package/dist/doctor.test.d.ts +1 -0
- package/dist/doctor.test.js +246 -0
- package/package.json +1 -1
- package/bundle/server/static-ui/assets/index-ChnI0F02.css +0 -1
- package/bundle/server/static-ui/assets/index-CyB1573Q.js +0 -60
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { resolveLinearRepoWithMappings } from "@agent-dealer/shared";
|
|
2
2
|
import { DEFAULT_LINEAR_STATE_FILTER, getLinearIntakeConfig } from "../repository/intake-settings.js";
|
|
3
|
+
import { listRepositoryMappings } from "../repository/repository-mappings.js";
|
|
3
4
|
import { linearGraphqlRequest } from "./linear-graphql.js";
|
|
4
5
|
export { DEFAULT_LINEAR_STATE_FILTER };
|
|
5
6
|
const PAGE_SIZE = 50;
|
|
@@ -20,7 +21,7 @@ async function linearQuery(operation, query, variables, opts) {
|
|
|
20
21
|
* deterministic (one valid label resolves, zero is unresolved, several
|
|
21
22
|
* conflict, a bad value is invalid) and never guesses from anything else.
|
|
22
23
|
*/
|
|
23
|
-
export function nodeToCandidate(n) {
|
|
24
|
+
export function nodeToCandidate(n, mappings) {
|
|
24
25
|
const labels = n.labels?.nodes.map((l) => l.name) ?? [];
|
|
25
26
|
return {
|
|
26
27
|
id: n.id,
|
|
@@ -31,7 +32,7 @@ export function nodeToCandidate(n) {
|
|
|
31
32
|
state: n.state?.name,
|
|
32
33
|
teamId: n.team?.id,
|
|
33
34
|
labels,
|
|
34
|
-
repoResolution:
|
|
35
|
+
repoResolution: resolveLinearRepoWithMappings(labels, mappings ?? []),
|
|
35
36
|
};
|
|
36
37
|
}
|
|
37
38
|
const ISSUE_FIELDS = `
|
|
@@ -106,7 +107,9 @@ export async function listLinearCandidates() {
|
|
|
106
107
|
break;
|
|
107
108
|
after = data.issues.pageInfo.endCursor;
|
|
108
109
|
}
|
|
109
|
-
|
|
110
|
+
// NOT-260: mappings load once per list operation, not once per candidate.
|
|
111
|
+
const mappings = listRepositoryMappings();
|
|
112
|
+
return nodes.map((n) => nodeToCandidate(n, mappings));
|
|
110
113
|
}
|
|
111
114
|
export async function getLinearIssue(issueId) {
|
|
112
115
|
const data = (await linearQuery("getLinearIssue", `query Issue($id: String!) {
|
|
@@ -114,7 +117,8 @@ export async function getLinearIssue(issueId) {
|
|
|
114
117
|
}`, { id: issueId }));
|
|
115
118
|
if (!data.issue)
|
|
116
119
|
return null;
|
|
117
|
-
|
|
120
|
+
// NOT-260: mappings load once per lookup operation.
|
|
121
|
+
return nodeToCandidate(data.issue, listRepositoryMappings());
|
|
118
122
|
}
|
|
119
123
|
const RELATION_PAGE_FIELDS = `
|
|
120
124
|
nodes { type issue { id identifier state { name type } } }
|
|
@@ -50,6 +50,7 @@ export function normalizeAdapterWindow(runtime, reading, nowMs = Date.now()) {
|
|
|
50
50
|
source: reading.source,
|
|
51
51
|
unavailableReason,
|
|
52
52
|
evidenceRef: reading.evidenceRef ?? null,
|
|
53
|
+
criticalRole: reading.criticalRole ?? null,
|
|
53
54
|
};
|
|
54
55
|
}
|
|
55
56
|
/** Normalize one provider failure into the persistable snapshot shape. */
|
|
@@ -70,6 +71,7 @@ export function normalizeUnavailableWindow(runtime, reading, nowMs = Date.now())
|
|
|
70
71
|
source: "unavailable",
|
|
71
72
|
unavailableReason: reading.reason,
|
|
72
73
|
evidenceRef: null,
|
|
74
|
+
criticalRole: reading.criticalRole ?? null,
|
|
73
75
|
};
|
|
74
76
|
}
|
|
75
77
|
// ---------------------------------------------------------------------------
|
|
@@ -170,6 +170,22 @@ export function inferClaudeDurationMinutes(bucket) {
|
|
|
170
170
|
return 10080;
|
|
171
171
|
return null;
|
|
172
172
|
}
|
|
173
|
+
/**
|
|
174
|
+
* The account-wide critical window's identity, decided here — once,
|
|
175
|
+
* authoritatively — and never re-derived downstream. Deliberately an exact
|
|
176
|
+
* match, unlike `inferClaudeDurationMinutes`'s loose regex: a model-specific
|
|
177
|
+
* extra like `seven_day_sonnet`/`seven_day_opus` shares the 10,080-minute
|
|
178
|
+
* duration with the real account-wide `seven_day`/`weekly` bucket but is
|
|
179
|
+
* not the critical window, so identity can't reuse that regex.
|
|
180
|
+
*/
|
|
181
|
+
export function claudeCriticalRole(bucket) {
|
|
182
|
+
const b = bucket.trim().toLowerCase();
|
|
183
|
+
if (b === "five_hour")
|
|
184
|
+
return "five_hour";
|
|
185
|
+
if (b === "seven_day" || b === "weekly")
|
|
186
|
+
return "weekly";
|
|
187
|
+
return null;
|
|
188
|
+
}
|
|
173
189
|
function windowReadingFromEntry(bucket, entry, observedAt) {
|
|
174
190
|
const cleanBucket = bucket.trim();
|
|
175
191
|
if (!cleanBucket)
|
|
@@ -218,6 +234,7 @@ function windowReadingFromEntry(bucket, entry, observedAt) {
|
|
|
218
234
|
observedAt,
|
|
219
235
|
source: "observed_event",
|
|
220
236
|
evidenceRef: CLAUDE_UNIFIED_WINDOWS_EVIDENCE_REF,
|
|
237
|
+
criticalRole: claudeCriticalRole(cleanBucket),
|
|
221
238
|
};
|
|
222
239
|
}
|
|
223
240
|
/**
|
|
@@ -303,20 +320,21 @@ export function extractClaudeCapacityFromEvents(events, nowMs = Date.now(), fall
|
|
|
303
320
|
return { runtime: CLAUDE_RUNTIME, windows: [...byKey.values()], unavailable: [] };
|
|
304
321
|
}
|
|
305
322
|
/**
|
|
306
|
-
* Persist
|
|
307
|
-
*
|
|
308
|
-
*
|
|
309
|
-
*
|
|
310
|
-
*
|
|
311
|
-
*
|
|
323
|
+
* Persist Claude window readings as normalized capacity snapshots
|
|
324
|
+
* (per-window upserts — siblings not in this observation are left untouched,
|
|
325
|
+
* and a stored row newer than the incoming reading is never overwritten).
|
|
326
|
+
* Shared by session-event ingestion and the local-cache/probe path (NOT-268):
|
|
327
|
+
* both sources write the same `claude_unified_*` window keys, so the freshest
|
|
328
|
+
* observation wins per window regardless of which source produced it.
|
|
329
|
+
* Returns the number of windows persisted, or null when no usable window was
|
|
330
|
+
* observed. Never touches `runtime_availability`.
|
|
312
331
|
*/
|
|
313
|
-
export function
|
|
332
|
+
export function recordClaudeWindowReadings(readings, runtime, nowMs = Date.now()) {
|
|
314
333
|
if (runtime !== CLAUDE_RUNTIME)
|
|
315
334
|
return null;
|
|
316
|
-
|
|
317
|
-
if (!result)
|
|
335
|
+
if (readings.length === 0)
|
|
318
336
|
return null;
|
|
319
|
-
const normalized =
|
|
337
|
+
const normalized = readings.map((w) => normalizeAdapterWindow(runtime, w, nowMs));
|
|
320
338
|
const persistable = normalized.filter((n) => n.unavailableReason === null && n.remainingPercent !== null);
|
|
321
339
|
if (persistable.length === 0)
|
|
322
340
|
return null;
|
|
@@ -350,9 +368,26 @@ export function recordClaudeCapacityFromEvents(events, runtime, nowMs = Date.now
|
|
|
350
368
|
source: w.source,
|
|
351
369
|
unavailableReason: w.unavailableReason,
|
|
352
370
|
evidenceRef: w.evidenceRef,
|
|
371
|
+
criticalRole: w.criticalRole,
|
|
353
372
|
})));
|
|
354
373
|
return fresh.length;
|
|
355
374
|
}
|
|
375
|
+
/**
|
|
376
|
+
* Persist naturally observed unified windows as normalized capacity
|
|
377
|
+
* snapshots. Status is irrelevant — allowed events carry the utilization
|
|
378
|
+
* signal; rejected ones additionally drive NOT-111 elsewhere. Thin wrapper
|
|
379
|
+
* over `recordClaudeWindowReadings`: per-window upserts, newer-wins, never
|
|
380
|
+
* touches `runtime_availability`. Returns the number of windows persisted,
|
|
381
|
+
* or null when the runtime is not Claude or no usable windows were observed.
|
|
382
|
+
*/
|
|
383
|
+
export function recordClaudeCapacityFromEvents(events, runtime, nowMs = Date.now(), fallbackObservedAtMs = nowMs) {
|
|
384
|
+
if (runtime !== CLAUDE_RUNTIME)
|
|
385
|
+
return null;
|
|
386
|
+
const result = extractClaudeCapacityFromEvents(events, nowMs, fallbackObservedAtMs);
|
|
387
|
+
if (!result)
|
|
388
|
+
return null;
|
|
389
|
+
return recordClaudeWindowReadings(result.windows, runtime, nowMs);
|
|
390
|
+
}
|
|
356
391
|
/**
|
|
357
392
|
* File variant for session-end ingestion from a Dealer-managed Claude log.
|
|
358
393
|
* `fallbackObservedAtMs` is the session's spawn start. Returns the persisted
|
|
@@ -67,6 +67,8 @@ test("five-hour and seven-day windows persist independently", () => {
|
|
|
67
67
|
assert.equal(fiveHour.remainingPercent, 83);
|
|
68
68
|
assert.equal(sevenDay.remainingPercent, 58);
|
|
69
69
|
assert.notEqual(fiveHour.resetAt, sevenDay.resetAt);
|
|
70
|
+
assert.equal(fiveHour.criticalRole, "five_hour");
|
|
71
|
+
assert.equal(sevenDay.criticalRole, "weekly");
|
|
70
72
|
// A later partial observation (five_hour only) upserts its row and leaves
|
|
71
73
|
// the seven-day sibling untouched.
|
|
72
74
|
const partial = [
|
|
@@ -94,6 +96,11 @@ test("model-specific and overage windows remain distinguishable", () => {
|
|
|
94
96
|
assert.equal(overage.durationMinutes, 10080);
|
|
95
97
|
assert.equal(sonnet.remainingPercent, 39);
|
|
96
98
|
assert.equal(overage.remainingPercent, 50);
|
|
99
|
+
// Same 10,080-minute duration as the real account-wide weekly window, but
|
|
100
|
+
// neither model-specific/overage extra is ever the critical window.
|
|
101
|
+
assert.equal(sonnet.criticalRole, null);
|
|
102
|
+
assert.equal(overage.criticalRole, null);
|
|
103
|
+
assert.equal(plain.criticalRole, "weekly");
|
|
97
104
|
});
|
|
98
105
|
test("legacy rejected fixture still caps (NOT-111) and fabricates no capacity", () => {
|
|
99
106
|
const events = parseNdjson(legacyRejectedFixture);
|