@deksden-com/dd-flow-cli 0.9.0-beta.13 → 0.9.0-beta.133
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/CHANGELOG.md +666 -0
- package/README.md +101 -1
- package/dist/build-info.json +10 -10
- package/dist/cli/argument-values.js +38 -0
- package/dist/cli/command-inputs.js +306 -0
- package/dist/cli/help.js +88 -12
- package/dist/cli/hook-ingress.js +78 -0
- package/dist/cli/input-preparation.js +116 -0
- package/dist/cli/native-hook-ingress.js +80 -0
- package/dist/cli/run-cli.js +1465 -450
- package/dist/cli/runtime-maintenance-diagnostics.js +46 -0
- package/dist/cli/runtime-maintenance-ingress.js +52 -0
- package/dist/cli/runtime-process.js +153 -0
- package/dist/cli.js +17 -2
- package/dist/domain/stage-catalog.js +1 -1
- package/dist/harness-runtime/DD-ZCODE.md +99 -0
- package/dist/harness-runtime/bin/dd-agy.mjs +56 -0
- package/dist/harness-runtime/bin/dd-codex.mjs +27 -0
- package/dist/harness-runtime/bin/dd-droid.mjs +34 -0
- package/dist/harness-runtime/bin/dd-grok.mjs +40 -0
- package/dist/harness-runtime/bin/dd-opencode.mjs +22 -0
- package/dist/harness-runtime/bin/dd-zcode.mjs +87 -0
- package/dist/harness-runtime/lib/adapter-timeouts.d.mts +5 -0
- package/dist/harness-runtime/lib/adapter-timeouts.mjs +34 -0
- package/dist/harness-runtime/lib/agy-hooks.d.mts +1 -0
- package/dist/harness-runtime/lib/agy-hooks.mjs +9 -0
- package/dist/harness-runtime/lib/codex-capacity-policy.d.mts +10 -0
- package/dist/harness-runtime/lib/codex-capacity-policy.mjs +89 -0
- package/dist/harness-runtime/lib/daemon-observation.d.mts +2 -0
- package/dist/harness-runtime/lib/daemon-observation.mjs +163 -0
- package/dist/harness-runtime/lib/daemon-operations.mjs +370 -0
- package/dist/harness-runtime/lib/dd-agy-daemon.d.mts +6 -0
- package/dist/harness-runtime/lib/dd-agy-daemon.mjs +693 -0
- package/dist/harness-runtime/lib/dd-agy.mjs +59 -0
- package/dist/harness-runtime/lib/dd-codex-daemon.d.mts +1 -0
- package/dist/harness-runtime/lib/dd-codex-daemon.mjs +190 -0
- package/dist/harness-runtime/lib/dd-codex.d.mts +1 -0
- package/dist/harness-runtime/lib/dd-codex.mjs +805 -0
- package/dist/harness-runtime/lib/dd-droid-daemon.mjs +128 -0
- package/dist/harness-runtime/lib/dd-droid.mjs +561 -0
- package/dist/harness-runtime/lib/dd-grok-daemon.mjs +490 -0
- package/dist/harness-runtime/lib/dd-grok.mjs +177 -0
- package/dist/harness-runtime/lib/dd-opencode-daemon.mjs +255 -0
- package/dist/harness-runtime/lib/dd-opencode.mjs +128 -0
- package/dist/harness-runtime/lib/dd-zcode-daemon.mjs +703 -0
- package/dist/harness-runtime/lib/dd-zcode.mjs +1108 -0
- package/dist/harness-runtime/lib/delegation-instructions.d.mts +13 -0
- package/dist/harness-runtime/lib/delegation-instructions.mjs +144 -0
- package/dist/harness-runtime/lib/dispatch-fence.mjs +14 -0
- package/dist/harness-runtime/lib/driver-recovery.mjs +139 -0
- package/dist/harness-runtime/lib/droid-observation.mjs +66 -0
- package/dist/harness-runtime/lib/lease-renewal.d.mts +8 -0
- package/dist/harness-runtime/lib/lease-renewal.mjs +36 -0
- package/dist/harness-runtime/lib/lifecycle-command.d.mts +20 -0
- package/dist/harness-runtime/lib/lifecycle-command.mjs +272 -0
- package/dist/harness-runtime/lib/lifecycle-contract.d.mts +10 -0
- package/dist/harness-runtime/lib/lifecycle-contract.mjs +19 -0
- package/dist/harness-runtime/lib/managed-daemon.d.mts +12 -0
- package/dist/harness-runtime/lib/managed-daemon.mjs +619 -0
- package/dist/harness-runtime/lib/model-observations.mjs +101 -0
- package/dist/harness-runtime/lib/native-children.d.mts +13 -0
- package/dist/harness-runtime/lib/native-children.mjs +78 -0
- package/dist/harness-runtime/lib/native-hook-command.d.mts +7 -0
- package/dist/harness-runtime/lib/native-hook-command.mjs +251 -0
- package/dist/harness-runtime/lib/native-streams.mjs +45 -0
- package/dist/harness-runtime/lib/observation-clock.d.mts +18 -0
- package/dist/harness-runtime/lib/observation-clock.mjs +92 -0
- package/dist/harness-runtime/lib/operation-context.mjs +5 -0
- package/dist/harness-runtime/lib/operation-errors.d.mts +14 -0
- package/dist/harness-runtime/lib/operation-errors.mjs +116 -0
- package/dist/harness-runtime/lib/operation-progress.d.mts +7 -0
- package/dist/harness-runtime/lib/operation-progress.mjs +112 -0
- package/dist/harness-runtime/lib/process-json.d.mts +5 -0
- package/dist/harness-runtime/lib/process-json.mjs +201 -0
- package/dist/harness-runtime/lib/process-snapshot.mjs +10 -0
- package/dist/harness-runtime/lib/runner-events.mjs +200 -0
- package/dist/harness-runtime/lib/runner-lock.mjs +42 -0
- package/dist/harness-runtime/lib/session-settlement.mjs +30 -0
- package/dist/harness-runtime/lib/setup-progress.d.mts +9 -0
- package/dist/harness-runtime/lib/setup-progress.mjs +51 -0
- package/dist/harness-runtime/lib/tool-observations.d.mts +21 -0
- package/dist/harness-runtime/lib/tool-observations.mjs +228 -0
- package/dist/harness-runtime/lib/zcode-usage.mjs +55 -0
- package/dist/protocol/local-files.js +18 -9
- package/dist/runtime/context.js +8 -4
- package/dist/schemas/agent-profile.schema.json +1 -1
- package/dist/schemas/code-review-result.schema.json +1 -1
- package/dist/schemas/code-verification.schema.json +7 -5
- package/dist/schemas/code-work-batch.schema.json +2 -2
- package/dist/schemas/flow-run.schema.json +2 -0
- package/dist/schemas/plan-review-decision.schema.json +3 -3
- package/dist/schemas/plan-review-result.schema.json +2 -2
- package/dist/schemas/run-control-receipt.schema.json +118 -0
- package/dist/schemas/run-control-request.schema.json +36 -0
- package/dist/schemas/vnext-protocol-plan.schema.json +2 -2
- package/dist/services/branch-context.js +3 -3
- package/dist/services/canon.js +11 -8
- package/dist/services/check-runner-evidence.js +121 -0
- package/dist/services/cleanup.js +133 -40
- package/dist/services/cli-operation-classifier.js +22 -24
- package/dist/services/code-checks.js +851 -109
- package/dist/services/codex-capacity.js +367 -0
- package/dist/services/codex-hook-delivery.js +32 -0
- package/dist/services/command-context.js +80 -0
- package/dist/services/compatibility-preflight.js +13 -3
- package/dist/services/config.js +11 -8
- package/dist/services/continuation-outcome.js +20 -0
- package/dist/services/controller-fanout.js +119 -0
- package/dist/services/dashboard.js +135 -56
- package/dist/services/engines.js +245 -119
- package/dist/services/eval-snapshots.js +1146 -105
- package/dist/services/execution-policy.js +181 -0
- package/dist/services/external-work-launch.js +230 -0
- package/dist/services/harness-adapter.js +329 -36
- package/dist/services/harness-config.js +2 -0
- package/dist/services/hooks.js +747 -325
- package/dist/services/lanes.js +78 -65
- package/dist/services/lifecycle-command.js +1 -288
- package/dist/services/lifecycle-contract.js +1 -0
- package/dist/services/lifecycle-invocations.js +1774 -0
- package/dist/services/managed-daemon-binding.js +38 -0
- package/dist/services/managed-lease-monitor.js +133 -0
- package/dist/services/managed-processes.js +409 -51
- package/dist/services/merge-queue.js +228 -149
- package/dist/services/merge-server.js +163 -35
- package/dist/services/migrations.js +37 -16
- package/dist/services/native-daemon-history.js +49 -0
- package/dist/services/native-session-control.js +39 -0
- package/dist/services/plan-runtime.js +26 -11
- package/dist/services/plans.js +28 -25
- package/dist/services/projects.js +20 -15
- package/dist/services/prompts.js +28 -17
- package/dist/services/protocols.js +163 -87
- package/dist/services/recovery-observation-budget.js +121 -0
- package/dist/services/recovery-snapshot-database.js +145 -0
- package/dist/services/repair-intents.js +42 -0
- package/dist/services/review-copy.js +157 -0
- package/dist/services/review-deferral.js +23 -0
- package/dist/services/run-control-receipt.js +56 -0
- package/dist/services/run-control-worker.js +411 -0
- package/dist/services/run-control.js +985 -0
- package/dist/services/run-controller-adapter.js +399 -0
- package/dist/services/run-controller-capture.js +179 -0
- package/dist/services/run-controller-process.js +187 -0
- package/dist/services/run-controller-recovery.js +289 -0
- package/dist/services/run-controller-state.js +97 -0
- package/dist/services/run-controller.js +1035 -0
- package/dist/services/run-engine-bindings.js +1 -1
- package/dist/services/run-fork.js +147 -0
- package/dist/services/run-observations.js +152 -0
- package/dist/services/run-projection.js +22 -64
- package/dist/services/run-recovery-guard.js +75 -0
- package/dist/services/run-recovery-runtime.js +112 -0
- package/dist/services/run-recovery.js +349 -0
- package/dist/services/runs.js +558 -217
- package/dist/services/runtime-budget.js +430 -0
- package/dist/services/runtime-command.js +43 -0
- package/dist/services/runtime-scope-capture.js +52 -0
- package/dist/services/runtime-scope-control.js +468 -0
- package/dist/services/runtime-scope-resume.js +599 -0
- package/dist/services/runtime-scope-stop.js +180 -0
- package/dist/services/runtime-scope-worker.js +287 -0
- package/dist/services/runtime-service.js +96 -0
- package/dist/services/schema-validation.js +10 -8
- package/dist/services/scope-writer-cleanup.js +27 -0
- package/dist/services/sessions.js +35 -69
- package/dist/services/stage-blocker.js +17 -7
- package/dist/services/stage-context.js +185 -19
- package/dist/services/stage-lifecycle.js +98 -107
- package/dist/services/stage-pause.js +89 -75
- package/dist/services/stage-report-renderer.js +158 -6
- package/dist/services/stage-work-graph.js +35 -0
- package/dist/services/tooling.js +32 -23
- package/dist/services/usage.js +49 -101
- package/dist/services/verification-matrix.js +374 -0
- package/dist/services/vnext-code-review.js +222 -87
- package/dist/services/vnext-code.js +324 -251
- package/dist/services/vnext-contracts.js +10 -1
- package/dist/services/vnext-execution-profile.js +79 -4
- package/dist/services/vnext-fanout.js +177 -17
- package/dist/services/vnext-merge.js +335 -113
- package/dist/services/vnext-plan-review.js +276 -126
- package/dist/services/vnext-plan.js +227 -102
- package/dist/services/vnext-protocolize.js +335 -82
- package/dist/services/vnext-specify.js +119 -81
- package/dist/services/work-registry.js +1038 -192
- package/dist/services/workspace-bootstrap.js +87 -0
- package/dist/services/workspace-files.js +85 -0
- package/dist/services/worktrees.js +98 -44
- package/dist/shared/entity-references.js +8 -0
- package/dist/shared/errors.js +17 -0
- package/dist/storage/agent-output.js +26 -0
- package/dist/storage/database.js +781 -37
- package/dist/storage/foreign-key-transaction.js +39 -0
- package/dist/storage/immutable-input.js +45 -0
- package/dist/storage/import-guard.js +102 -0
- package/dist/storage/native-cleanup.js +52 -0
- package/dist/storage/paths.js +17 -4
- package/dist/storage/projection-lock.js +73 -0
- package/dist/storage/work-references.js +23 -0
- package/dist/storage/writer-contract.js +77 -0
- package/dist/storage/writer-migration.js +85 -0
- package/package.json +30 -13
- package/tools/repair-paused-run-status.mjs +84 -0
package/dist/services/usage.js
CHANGED
|
@@ -4,6 +4,8 @@ import { parseJsonObject } from "../shared/json.js";
|
|
|
4
4
|
import { resolveProjectRoot } from "../storage/paths.js";
|
|
5
5
|
import { registerProject, requireProjectByRoot } from "./projects.js";
|
|
6
6
|
import { publicSessionIdentity } from "./session-identity.js";
|
|
7
|
+
import { runObservations } from "./run-observations.js";
|
|
8
|
+
import { ToolObservations, codexToolObservation } from "../harness-runtime/lib/tool-observations.mjs";
|
|
7
9
|
export function ingestZcodeUsage(context, input) {
|
|
8
10
|
return ingestHarnessUsage(context, input, { harness: "zcode-acp", label: "ZCode", idPrefix: "ZUSG", sourceKind: "zcode_session_usage_v1" });
|
|
9
11
|
}
|
|
@@ -19,6 +21,14 @@ export function ingestOpenCodeUsage(context, input) {
|
|
|
19
21
|
export function ingestAgyUsage(context, input) {
|
|
20
22
|
return ingestHarnessUsage(context, input, { harness: "antigravity-cli", label: "Antigravity", idPrefix: "AUSG", sourceKind: "antigravity_cli_session_usage_v1" });
|
|
21
23
|
}
|
|
24
|
+
/** Droid counters must describe one physical Session; inclusive roots double-count children. */
|
|
25
|
+
export function ingestDroidUsage(context, input) {
|
|
26
|
+
const payload = parseJsonObject(input.stdin || "{}", "Droid usage snapshot");
|
|
27
|
+
if (payload.usage_scope !== "physical_session" || !["complete", "partial"].includes(String(payload.completeness))) {
|
|
28
|
+
throw new Error("Droid usage requires physical_session scope and complete or partial completeness");
|
|
29
|
+
}
|
|
30
|
+
return ingestHarnessUsage(context, input, { harness: "droid-cli", label: "Droid", idPrefix: "DUSG", sourceKind: "droid_session_usage_v1" });
|
|
31
|
+
}
|
|
22
32
|
function ingestHarnessUsage(context, input, harness) {
|
|
23
33
|
const payload = parseJsonObject(input.stdin || "{}", `${harness.label} usage snapshot`);
|
|
24
34
|
const usage = object(payload.usage);
|
|
@@ -157,8 +167,7 @@ export function recalculateRunUsage(context, input) {
|
|
|
157
167
|
const usageFinal = final && unsettledSessions.length === 0;
|
|
158
168
|
const persistRunProjection = !input.sessionId && !input.stage;
|
|
159
169
|
if (persistRunProjection) {
|
|
160
|
-
context.db.
|
|
161
|
-
try {
|
|
170
|
+
context.db.writeTransaction(() => {
|
|
162
171
|
context.db.run("DELETE FROM usage WHERE project_id = ? AND run_id = ?", [input.projectId, input.runId]);
|
|
163
172
|
for (const row of rows) {
|
|
164
173
|
context.db.run(`INSERT INTO usage (id, project_id, run_id, session_id, checkpoint, stage, stage_attempt, observed_at, total_tokens, input_tokens, cached_input_tokens, cache_read_input_tokens, cache_write_input_tokens, uncached_input_tokens, output_tokens, reasoning_output_tokens, source_kind, source_locator, source_sha256, source_size_bytes, source_mtime_ms, token_event_at, turn_id, turn_attribution, parser_version, extraction_status, diagnostic_code, created_at)
|
|
@@ -177,13 +186,10 @@ export function recalculateRunUsage(context, input) {
|
|
|
177
186
|
AND status = 'idle'
|
|
178
187
|
AND NOT EXISTS (SELECT 1 FROM work_sessions WHERE session_id = ? AND status = 'running')`, [observedAt, session.completed_at, input.projectId, input.runId, session.session_id, session.session_id]);
|
|
179
188
|
}
|
|
180
|
-
|
|
181
|
-
}
|
|
182
|
-
catch (error) {
|
|
183
|
-
context.db.exec("ROLLBACK");
|
|
184
|
-
throw error;
|
|
185
|
-
}
|
|
189
|
+
});
|
|
186
190
|
}
|
|
191
|
+
const observations = persistRunProjection ? runObservations(context, input.projectId, input.runId) : null;
|
|
192
|
+
const legacyTools = toolCallsForLinks(context, links, accountingAt);
|
|
187
193
|
return {
|
|
188
194
|
ok: true,
|
|
189
195
|
schema_id: "dd-flow/run-usage@2",
|
|
@@ -198,7 +204,8 @@ export function recalculateRunUsage(context, input) {
|
|
|
198
204
|
stopped: publicSessionIdentities(context, input.projectId, settledSessions.map((session) => session.session_id)),
|
|
199
205
|
unsettled: publicSessionIdentities(context, input.projectId, unsettledSessions)
|
|
200
206
|
},
|
|
201
|
-
tool_calls:
|
|
207
|
+
tool_calls: observations?.tools.observed_sessions ? observations.tools : legacyTools,
|
|
208
|
+
...(observations ? { observations, legacy_tool_calls: legacyTools } : {}),
|
|
202
209
|
coverage: rows.reduce((coverage, row) => ({ ...coverage, [row.status]: (coverage[row.status] ?? 0) + 1 }), {})
|
|
203
210
|
};
|
|
204
211
|
}
|
|
@@ -241,6 +248,7 @@ function publicSessionIdentities(context, projectId, storageIds) {
|
|
|
241
248
|
}
|
|
242
249
|
function toolCallsForLinks(context, links, observedAt) {
|
|
243
250
|
const result = { status: "unavailable", total: 0, failures: 0, by_tool: {}, observed_sessions: 0, unavailable_sessions: [] };
|
|
251
|
+
let incomplete = false;
|
|
244
252
|
const sessions = new Map();
|
|
245
253
|
for (const link of links)
|
|
246
254
|
sessions.set(link.session_id, [...(sessions.get(link.session_id) ?? []), link]);
|
|
@@ -253,18 +261,20 @@ function toolCallsForLinks(context, links, observedAt) {
|
|
|
253
261
|
result.unavailable_sessions.push(sessionId);
|
|
254
262
|
continue;
|
|
255
263
|
}
|
|
264
|
+
if ("completeness" in parsed && parsed.completeness !== "complete")
|
|
265
|
+
incomplete = true;
|
|
256
266
|
result.observed_sessions += 1;
|
|
257
267
|
result.total += parsed.total;
|
|
258
268
|
result.failures += parsed.failures;
|
|
259
269
|
for (const [name, count] of Object.entries(parsed.by_tool))
|
|
260
270
|
result.by_tool[name] = (result.by_tool[name] ?? 0) + count;
|
|
261
271
|
}
|
|
262
|
-
result.status = result.observed_sessions === 0 ? "unavailable" : result.unavailable_sessions.length ? "partial" : "measured";
|
|
272
|
+
result.status = result.observed_sessions === 0 ? "unavailable" : result.unavailable_sessions.length || incomplete ? "partial" : "measured";
|
|
263
273
|
return result;
|
|
264
274
|
}
|
|
265
|
-
function isExternalHarness(harness) { return harness === "zcode-acp" || harness === "grok-acp" || harness === "opencode-server" || harness === "antigravity-cli"; }
|
|
275
|
+
function isExternalHarness(harness) { return harness === "droid-cli" || harness === "zcode-acp" || harness === "grok-acp" || harness === "opencode-server" || harness === "antigravity-cli"; }
|
|
266
276
|
function harnessSourceKind(harness) {
|
|
267
|
-
return harness === "grok-acp" ? "grok_session_usage_v1" : harness === "zcode-acp" ? "zcode_session_usage_v1" : harness === "antigravity-cli" ? "antigravity_cli_session_usage_v1" : "opencode_session_usage_v1";
|
|
277
|
+
return harness === "droid-cli" ? "droid_session_usage_v1" : harness === "grok-acp" ? "grok_session_usage_v1" : harness === "zcode-acp" ? "zcode_session_usage_v1" : harness === "antigravity-cli" ? "antigravity_cli_session_usage_v1" : "opencode_session_usage_v1";
|
|
268
278
|
}
|
|
269
279
|
function readHarnessToolCallsWindow(context, harness, projectId, providerSessionId, startedAt, endedAt, observedAt) {
|
|
270
280
|
if (!providerSessionId)
|
|
@@ -302,9 +312,7 @@ function readToolCallsForWindows(transcriptPath, expectedSessionId, windows, obs
|
|
|
302
312
|
return null;
|
|
303
313
|
try {
|
|
304
314
|
let sessionId;
|
|
305
|
-
|
|
306
|
-
let failures = 0;
|
|
307
|
-
const byTool = {};
|
|
315
|
+
const tools = new ToolObservations();
|
|
308
316
|
for (const line of fs.readFileSync(transcriptPath, "utf8").split(/\r?\n/)) {
|
|
309
317
|
if (!line.trim())
|
|
310
318
|
continue;
|
|
@@ -313,6 +321,7 @@ function readToolCallsForWindows(transcriptPath, expectedSessionId, windows, obs
|
|
|
313
321
|
event = JSON.parse(line);
|
|
314
322
|
}
|
|
315
323
|
catch {
|
|
324
|
+
tools.gaps.add("journal_invalid_record");
|
|
316
325
|
continue;
|
|
317
326
|
}
|
|
318
327
|
const payload = object(event.payload);
|
|
@@ -321,20 +330,13 @@ function readToolCallsForWindows(transcriptPath, expectedSessionId, windows, obs
|
|
|
321
330
|
if (event.type !== "response_item" || !payload)
|
|
322
331
|
continue;
|
|
323
332
|
const eventAt = stringValue(event.timestamp);
|
|
324
|
-
if (eventAt && !windows.some((window) => eventInsideWindow(eventAt, window, observedAt)))
|
|
333
|
+
if (eventAt && windows.length && !windows.some((window) => eventInsideWindow(eventAt, window, observedAt)))
|
|
325
334
|
continue;
|
|
326
|
-
|
|
327
|
-
if (type === "function_call" || type === "custom_tool_call") {
|
|
328
|
-
const name = stringValue(payload.name) ?? "unknown";
|
|
329
|
-
byTool[name] = (byTool[name] ?? 0) + 1;
|
|
330
|
-
total += 1;
|
|
331
|
-
}
|
|
332
|
-
if ((type === "function_call_output" || type === "custom_tool_call_output") && outputIndicatesFailure(payload))
|
|
333
|
-
failures += 1;
|
|
335
|
+
tools.add(codexToolObservation(event, expectedSessionId));
|
|
334
336
|
}
|
|
335
337
|
if (sessionId && sessionId !== expectedSessionId)
|
|
336
338
|
return null;
|
|
337
|
-
return
|
|
339
|
+
return tools.summary();
|
|
338
340
|
}
|
|
339
341
|
catch {
|
|
340
342
|
return null;
|
|
@@ -346,37 +348,6 @@ function eventInsideWindow(eventAt, window, observedAt) {
|
|
|
346
348
|
const end = Date.parse(window.completed_at ?? observedAt);
|
|
347
349
|
return Number.isFinite(at) && (!Number.isFinite(start) || at >= start) && (!Number.isFinite(end) || at <= end);
|
|
348
350
|
}
|
|
349
|
-
function outputIndicatesFailure(payload) {
|
|
350
|
-
if (payload.error === true || typeof payload.error === "string")
|
|
351
|
-
return true;
|
|
352
|
-
return containsFailure(payload.output);
|
|
353
|
-
}
|
|
354
|
-
function containsFailure(value) {
|
|
355
|
-
if (Array.isArray(value))
|
|
356
|
-
return value.some(containsFailure);
|
|
357
|
-
if (typeof value === "string") {
|
|
358
|
-
if (/(?:^|\n)exit=(?:[1-9]\d*)\b|Process exited with code [1-9]\d*/.test(value))
|
|
359
|
-
return true;
|
|
360
|
-
const trimmed = value.trim();
|
|
361
|
-
if (trimmed.startsWith("{") || trimmed.startsWith("[")) {
|
|
362
|
-
try {
|
|
363
|
-
return containsFailure(JSON.parse(trimmed));
|
|
364
|
-
}
|
|
365
|
-
catch {
|
|
366
|
-
return false;
|
|
367
|
-
}
|
|
368
|
-
}
|
|
369
|
-
return false;
|
|
370
|
-
}
|
|
371
|
-
const item = object(value);
|
|
372
|
-
if (!item)
|
|
373
|
-
return false;
|
|
374
|
-
if (item.ok === false || item.is_error === true || item.isError === true || item.error === true || typeof item.error === "string")
|
|
375
|
-
return true;
|
|
376
|
-
if (typeof item.exit_code === "number" && item.exit_code !== 0)
|
|
377
|
-
return true;
|
|
378
|
-
return Object.values(item).some(containsFailure);
|
|
379
|
-
}
|
|
380
351
|
/** RUN accounting belongs to the physical provider Session, not to every Work link. */
|
|
381
352
|
function usageRowsForPhysicalSessions(context, links, observedAt, stage) {
|
|
382
353
|
const sessions = new Map();
|
|
@@ -398,7 +369,7 @@ function usageRowsForPhysicalSessions(context, links, observedAt, stage) {
|
|
|
398
369
|
: completedTurn?.completed_at ?? sessionLinks.map((item) => item.completed_at ?? observedAt).sort().at(-1);
|
|
399
370
|
const endedAt = stage?.completedAt ?? (Date.parse(naturalEnd) > Date.parse(observedAt) ? observedAt : naturalEnd);
|
|
400
371
|
const harnessUsage = isExternalHarness(link.harness)
|
|
401
|
-
? readHarnessUsageWindow(context, link.harness, link.project_id, link.provider_session_id, startedAt, endedAt, observedAt)
|
|
372
|
+
? readHarnessUsageWindow(context, link.harness, link.project_id, link.provider_session_id, startedAt, endedAt, observedAt, Boolean(stage))
|
|
402
373
|
: null;
|
|
403
374
|
const parsed = harnessUsage ?? readCodexTranscriptWindow(link.transcript_path, nativeSessionId(link), startedAt, endedAt);
|
|
404
375
|
return {
|
|
@@ -422,18 +393,31 @@ function hasInclusiveUsageSnapshot(context, projectId, harness, providerSessionI
|
|
|
422
393
|
return false;
|
|
423
394
|
return Boolean(context.db.get("SELECT 1 FROM harness_usage_snapshots WHERE project_id = ? AND harness = ? AND provider_session_id = ? AND usage_scope = 'execution_tree_inclusive' AND observed_at <= ? LIMIT 1", [projectId, harness, providerSessionId, observedAt]));
|
|
424
395
|
}
|
|
425
|
-
function readHarnessUsageWindow(context, harness, projectId, providerSessionId, startedAt, endedAt, observedAt) {
|
|
396
|
+
function readHarnessUsageWindow(context, harness, projectId, providerSessionId, startedAt, endedAt, observedAt, stageWindow) {
|
|
426
397
|
if (!providerSessionId)
|
|
427
398
|
return { status: "not_observable", diagnostic: "provider_session_id_missing" };
|
|
428
|
-
const snapshots = context.db.all(`SELECT observed_at, total_tokens, input_tokens, cache_read_input_tokens, cache_write_input_tokens, output_tokens, reasoning_output_tokens
|
|
399
|
+
const snapshots = context.db.all(`SELECT completeness, observed_at, total_tokens, input_tokens, cache_read_input_tokens, cache_write_input_tokens, output_tokens, reasoning_output_tokens
|
|
429
400
|
FROM harness_usage_snapshots
|
|
430
401
|
WHERE project_id = ? AND harness = ? AND provider_session_id = ? AND observed_at <= ?
|
|
431
402
|
ORDER BY observed_at, id`, [projectId, harness, providerSessionId, observedAt]);
|
|
432
|
-
const last = snapshots.find((snapshot) => Date.parse(snapshot.observed_at) > Date.parse(endedAt))
|
|
403
|
+
const last = (!stageWindow ? snapshots.find((snapshot) => Date.parse(snapshot.observed_at) > Date.parse(endedAt)) : undefined)
|
|
433
404
|
?? snapshots.filter((snapshot) => Date.parse(snapshot.observed_at) <= Date.parse(endedAt)).at(-1);
|
|
434
405
|
const before = snapshots.filter((snapshot) => Date.parse(snapshot.observed_at) <= Date.parse(startedAt)).at(-1);
|
|
435
406
|
if (!last || !before || last === before)
|
|
436
407
|
return { status: "not_yet_emitted", diagnostic: `${harness}_usage_window_incomplete` };
|
|
408
|
+
// Cumulative counters outside an attempt's boundaries cannot establish its
|
|
409
|
+
// spend: adjacent attempts would otherwise charge overlapping intervals.
|
|
410
|
+
if (stageWindow && (Date.parse(before.observed_at) !== Date.parse(startedAt)
|
|
411
|
+
|| Date.parse(last.observed_at) !== Date.parse(endedAt)
|
|
412
|
+
|| before.completeness !== "complete" || last.completeness !== "complete")) {
|
|
413
|
+
return { status: "not_observable", diagnostic: `${harness}_stage_window_unconfirmed` };
|
|
414
|
+
}
|
|
415
|
+
if (stageWindow && ["total_tokens", "input_tokens", "cache_read_input_tokens", "cache_write_input_tokens", "output_tokens", "reasoning_output_tokens"]
|
|
416
|
+
.some(key => last[key] !== null && before[key] !== null && last[key] < before[key])) {
|
|
417
|
+
return { status: "not_observable", diagnostic: `${harness}_stage_counter_reset` };
|
|
418
|
+
}
|
|
419
|
+
if (harness === "droid-cli" && (last.completeness !== "complete" || before.completeness !== "complete"))
|
|
420
|
+
return { status: "not_observable", diagnostic: "droid-cli_usage_window_partial" };
|
|
437
421
|
const delta = (value, baseline) => value === null || baseline === null ? null : Math.max(0, value - baseline);
|
|
438
422
|
const input = delta(last.input_tokens, before.input_tokens);
|
|
439
423
|
const cacheRead = delta(last.cache_read_input_tokens, before.cache_read_input_tokens);
|
|
@@ -575,62 +559,26 @@ function usageReport(context, input, refresh) {
|
|
|
575
559
|
}
|
|
576
560
|
function toolCallsForSessions(sessions) {
|
|
577
561
|
const result = { status: "unavailable", total: 0, failures: 0, by_tool: {}, observed_sessions: 0, unavailable_sessions: [] };
|
|
562
|
+
let incomplete = false;
|
|
578
563
|
for (const session of sessions) {
|
|
579
564
|
const parsed = readToolCalls(session.transcript_path, nativeSessionId(session));
|
|
580
565
|
if (!parsed) {
|
|
581
566
|
result.unavailable_sessions.push(session.session_id);
|
|
582
567
|
continue;
|
|
583
568
|
}
|
|
569
|
+
if (parsed.completeness !== "complete")
|
|
570
|
+
incomplete = true;
|
|
584
571
|
result.observed_sessions += 1;
|
|
585
572
|
result.total += parsed.total;
|
|
586
573
|
result.failures += parsed.failures;
|
|
587
574
|
for (const [name, count] of Object.entries(parsed.by_tool))
|
|
588
575
|
result.by_tool[name] = (result.by_tool[name] ?? 0) + count;
|
|
589
576
|
}
|
|
590
|
-
result.status = result.observed_sessions === 0 ? "unavailable" : result.unavailable_sessions.length
|
|
577
|
+
result.status = result.observed_sessions === 0 ? "unavailable" : result.unavailable_sessions.length || incomplete ? "partial" : "measured";
|
|
591
578
|
return result;
|
|
592
579
|
}
|
|
593
580
|
function readToolCalls(transcriptPath, expectedSessionId) {
|
|
594
|
-
|
|
595
|
-
return null;
|
|
596
|
-
try {
|
|
597
|
-
let sessionId;
|
|
598
|
-
const byTool = {};
|
|
599
|
-
let total = 0;
|
|
600
|
-
let failures = 0;
|
|
601
|
-
for (const line of fs.readFileSync(transcriptPath, "utf8").split(/\r?\n/)) {
|
|
602
|
-
if (!line.trim())
|
|
603
|
-
continue;
|
|
604
|
-
let event;
|
|
605
|
-
try {
|
|
606
|
-
event = JSON.parse(line);
|
|
607
|
-
}
|
|
608
|
-
catch {
|
|
609
|
-
continue;
|
|
610
|
-
}
|
|
611
|
-
const payload = object(event.payload);
|
|
612
|
-
if (!payload)
|
|
613
|
-
continue;
|
|
614
|
-
if (event.type === "session_meta")
|
|
615
|
-
sessionId = stringValue(payload.id) ?? sessionId;
|
|
616
|
-
if (event.type !== "response_item")
|
|
617
|
-
continue;
|
|
618
|
-
const type = stringValue(payload.type);
|
|
619
|
-
if (type === "function_call" || type === "custom_tool_call") {
|
|
620
|
-
const name = stringValue(payload.name) ?? "unknown";
|
|
621
|
-
byTool[name] = (byTool[name] ?? 0) + 1;
|
|
622
|
-
total += 1;
|
|
623
|
-
}
|
|
624
|
-
if ((type === "function_call_output" || type === "custom_tool_call_output") && outputIndicatesFailure(payload))
|
|
625
|
-
failures += 1;
|
|
626
|
-
}
|
|
627
|
-
if (sessionId && sessionId !== expectedSessionId)
|
|
628
|
-
return null;
|
|
629
|
-
return { total, failures, by_tool: Object.fromEntries(Object.entries(byTool).sort(([left], [right]) => left.localeCompare(right))) };
|
|
630
|
-
}
|
|
631
|
-
catch {
|
|
632
|
-
return null;
|
|
633
|
-
}
|
|
581
|
+
return readToolCallsForWindows(transcriptPath, expectedSessionId, [], new Date().toISOString());
|
|
634
582
|
}
|
|
635
583
|
function segmentUsage(context, session, segment) {
|
|
636
584
|
if (!session)
|