@rosthq/cli 0.7.95 → 0.7.96
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/index.js +116 -20
- package/dist/index.js.map +3 -3
- package/dist/runner-serve.d.ts +4 -0
- package/dist/runner-serve.d.ts.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -41569,6 +41569,7 @@ var compassImportOutputSchema = external_exports.object({
|
|
|
41569
41569
|
citations: external_exports.number().int().nonnegative()
|
|
41570
41570
|
}).strict();
|
|
41571
41571
|
var goalStatusSchema = external_exports.enum(["on", "off", "done", "dropped"]);
|
|
41572
|
+
var goalStatusSourceSchema = external_exports.enum(["human", "agent", "rollup", "signal"]);
|
|
41572
41573
|
var goalListInputSchema = external_exports.object({
|
|
41573
41574
|
cycle_id: uuidSchema9.optional(),
|
|
41574
41575
|
seat_id: uuidSchema9.optional()
|
|
@@ -41584,7 +41585,7 @@ var goalSummarySchema = external_exports.object({
|
|
|
41584
41585
|
parent_goal_id: uuidSchema9.nullable(),
|
|
41585
41586
|
title: external_exports.string(),
|
|
41586
41587
|
status: goalStatusSchema,
|
|
41587
|
-
status_source:
|
|
41588
|
+
status_source: goalStatusSourceSchema
|
|
41588
41589
|
}).strict();
|
|
41589
41590
|
var goalListOutputSchema = external_exports.object({
|
|
41590
41591
|
goals: external_exports.array(goalSummarySchema)
|
|
@@ -41604,7 +41605,7 @@ var goalMutationOutputSchema = external_exports.object({
|
|
|
41604
41605
|
parent_goal_id: uuidSchema9.nullable(),
|
|
41605
41606
|
title: external_exports.string(),
|
|
41606
41607
|
status: goalStatusSchema,
|
|
41607
|
-
status_source:
|
|
41608
|
+
status_source: goalStatusSourceSchema
|
|
41608
41609
|
}).strict();
|
|
41609
41610
|
var goalUpdateInputSchema = external_exports.object({
|
|
41610
41611
|
goal_id: uuidSchema9,
|
|
@@ -41655,7 +41656,6 @@ var goalListAtRiskOutputSchema = external_exports.object({
|
|
|
41655
41656
|
goals: external_exports.array(goalAtRiskSchema)
|
|
41656
41657
|
}).strict();
|
|
41657
41658
|
var goalSignalStateSchema = external_exports.enum(["ok", "risk", "crit", "pending"]);
|
|
41658
|
-
var goalStatusSourceSchema = external_exports.enum(["human", "agent", "rollup", "signal"]);
|
|
41659
41659
|
var goalMeasurableRoleSchema = external_exports.enum(["drives_status", "informs"]);
|
|
41660
41660
|
var goalDriverAnchorSchema = external_exports.object({
|
|
41661
41661
|
// The closed period being anchored on (an ISO date / period label — free-form so a
|
|
@@ -43438,7 +43438,11 @@ var fleetDigestAgentSchema = fleetOverviewRowSchema.extend({
|
|
|
43438
43438
|
spend_7d_usd: external_exports.string(),
|
|
43439
43439
|
spend_30d_usd: external_exports.string(),
|
|
43440
43440
|
cost_drift_percent: external_exports.number().int().nullable(),
|
|
43441
|
-
|
|
43441
|
+
// DER-1905: "idle" added — cadence-aware grading now distinguishes an
|
|
43442
|
+
// on-demand agent with nothing pending (idle, neutral) from a scheduled
|
|
43443
|
+
// agent that missed its cron (stale, alarming). Purely additive to this
|
|
43444
|
+
// enum; no other field on this schema changed.
|
|
43445
|
+
health_status: external_exports.enum(["needs_review", "stale", "idle", "setup_gap", "awaiting_data", "awaiting_data_overdue", "healthy"]),
|
|
43442
43446
|
health_reasons: external_exports.array(external_exports.string()),
|
|
43443
43447
|
recent_failed_runs: external_exports.array(fleetDigestRunSchema),
|
|
43444
43448
|
unresolved_errors: external_exports.array(fleetDigestErrorSchema),
|
|
@@ -43509,8 +43513,11 @@ var seatRunDetailSchema = seatRunSchema.extend({
|
|
|
43509
43513
|
task_id: uuidSchema14.nullable(),
|
|
43510
43514
|
work_order_id: uuidSchema14.nullable(),
|
|
43511
43515
|
transcript_ref: external_exports.string(),
|
|
43512
|
-
|
|
43513
|
-
|
|
43516
|
+
// DER-1913: null = usage UNKNOWN — a Codex / read-status / timeout / spawn-error
|
|
43517
|
+
// runner turn reports no model-usage envelope, so the run records no token count.
|
|
43518
|
+
// Never coerced to a fabricated 0; surfaces (CLI/MCP/UI) render it as unknown.
|
|
43519
|
+
input_tokens: external_exports.number().int().nonnegative().nullable(),
|
|
43520
|
+
output_tokens: external_exports.number().int().nonnegative().nullable(),
|
|
43514
43521
|
outcome: external_exports.record(external_exports.string(), external_exports.unknown()),
|
|
43515
43522
|
error_logs: external_exports.array(seatRunErrorLogSchema),
|
|
43516
43523
|
skill_activations: external_exports.array(external_exports.object({
|
|
@@ -56383,7 +56390,8 @@ function parseSemver2(value) {
|
|
|
56383
56390
|
// src/runner-serve.ts
|
|
56384
56391
|
import { execFile as execFileCallback5, spawn } from "node:child_process";
|
|
56385
56392
|
import { createHash as createHash2 } from "node:crypto";
|
|
56386
|
-
import {
|
|
56393
|
+
import { constants as fsConstants2 } from "node:fs";
|
|
56394
|
+
import { access as access3, chmod as chmod2, mkdir as mkdir5, readFile as readFile5, rename, rm as rm5, statfs, writeFile as writeFile5 } from "node:fs/promises";
|
|
56387
56395
|
import { cpus, homedir as homedir4, hostname as hostname3, platform, totalmem, tmpdir as tmpdir2 } from "node:os";
|
|
56388
56396
|
import path7 from "node:path";
|
|
56389
56397
|
import { setTimeout as sleep3 } from "node:timers/promises";
|
|
@@ -57699,11 +57707,43 @@ function resolveSandboxPosture(env, homeDir) {
|
|
|
57699
57707
|
function resolveSandboxNetworkFlag(env) {
|
|
57700
57708
|
return parseSandboxNetwork(env.RUNNER_SANDBOX_NETWORK).allowNetwork ? "allow" : "deny";
|
|
57701
57709
|
}
|
|
57710
|
+
var CAPABILITY_PROBE_TIMEOUT_MS = 1e4;
|
|
57711
|
+
function classifyProbeError(err) {
|
|
57712
|
+
if (!err || typeof err !== "object") {
|
|
57713
|
+
return "absent";
|
|
57714
|
+
}
|
|
57715
|
+
const candidate = err;
|
|
57716
|
+
const message = typeof candidate.message === "string" ? candidate.message.toLowerCase() : "";
|
|
57717
|
+
if (candidate.code === "ENOENT" || message.includes("not found")) {
|
|
57718
|
+
return "absent";
|
|
57719
|
+
}
|
|
57720
|
+
if (candidate.killed === true || candidate.code === "ETIMEDOUT" || candidate.signal === "SIGTERM") {
|
|
57721
|
+
return "present_slow";
|
|
57722
|
+
}
|
|
57723
|
+
return "absent";
|
|
57724
|
+
}
|
|
57725
|
+
async function isResolvableOnPath(command) {
|
|
57726
|
+
const dirs = (process.env.PATH ?? "").split(path7.delimiter).filter((dir) => dir.length > 0);
|
|
57727
|
+
const suffixes = process.platform === "win32" ? (process.env.PATHEXT ?? ".EXE;.CMD;.BAT;.COM").split(";").filter((ext) => ext.length > 0) : [""];
|
|
57728
|
+
for (const dir of dirs) {
|
|
57729
|
+
for (const suffix of suffixes) {
|
|
57730
|
+
try {
|
|
57731
|
+
await access3(path7.join(dir, `${command}${suffix}`), fsConstants2.X_OK);
|
|
57732
|
+
return true;
|
|
57733
|
+
} catch {
|
|
57734
|
+
}
|
|
57735
|
+
}
|
|
57736
|
+
}
|
|
57737
|
+
return false;
|
|
57738
|
+
}
|
|
57702
57739
|
async function probe(command) {
|
|
57703
57740
|
try {
|
|
57704
|
-
const { stdout, stderr } = await execFile5(command, ["--version"], { timeout:
|
|
57741
|
+
const { stdout, stderr } = await execFile5(command, ["--version"], { timeout: CAPABILITY_PROBE_TIMEOUT_MS });
|
|
57705
57742
|
return { installed: true, version: (stdout || stderr).trim() || null, auth_state: "ready" };
|
|
57706
|
-
} catch {
|
|
57743
|
+
} catch (err) {
|
|
57744
|
+
if (classifyProbeError(err) === "present_slow" && await isResolvableOnPath(command)) {
|
|
57745
|
+
return { installed: true, version: null, auth_state: "unknown" };
|
|
57746
|
+
}
|
|
57707
57747
|
return { installed: false, version: null, auth_state: "unknown" };
|
|
57708
57748
|
}
|
|
57709
57749
|
}
|
|
@@ -57739,7 +57779,7 @@ async function probeClaude() {
|
|
|
57739
57779
|
}
|
|
57740
57780
|
async function probeClaudeStreamJsonInterface() {
|
|
57741
57781
|
try {
|
|
57742
|
-
const { stdout, stderr } = await execFile5("claude", ["--help"], { timeout:
|
|
57782
|
+
const { stdout, stderr } = await execFile5("claude", ["--help"], { timeout: CAPABILITY_PROBE_TIMEOUT_MS, maxBuffer: 1024 * 1024 });
|
|
57743
57783
|
return supportsClaudeStreamJsonInterface(`${stdout ?? ""}
|
|
57744
57784
|
${stderr ?? ""}`);
|
|
57745
57785
|
} catch {
|
|
@@ -57751,7 +57791,7 @@ function supportsClaudeStreamJsonInterface(helpText2) {
|
|
|
57751
57791
|
}
|
|
57752
57792
|
async function probeGit() {
|
|
57753
57793
|
try {
|
|
57754
|
-
const { stdout, stderr } = await execFile5("git", ["--version"], { timeout:
|
|
57794
|
+
const { stdout, stderr } = await execFile5("git", ["--version"], { timeout: CAPABILITY_PROBE_TIMEOUT_MS });
|
|
57755
57795
|
const raw = (stdout || stderr).trim();
|
|
57756
57796
|
return { installed: true, version: /(\d+\.\d+(?:\.\d+)?)/.exec(raw)?.[1] ?? (raw || null) };
|
|
57757
57797
|
} catch {
|
|
@@ -57760,7 +57800,7 @@ async function probeGit() {
|
|
|
57760
57800
|
}
|
|
57761
57801
|
async function probeGh() {
|
|
57762
57802
|
try {
|
|
57763
|
-
const { stdout, stderr } = await execFile5("gh", ["--version"], { timeout:
|
|
57803
|
+
const { stdout, stderr } = await execFile5("gh", ["--version"], { timeout: CAPABILITY_PROBE_TIMEOUT_MS });
|
|
57764
57804
|
const raw = (stdout || stderr).trim().split("\n")[0]?.trim() ?? "";
|
|
57765
57805
|
const authenticated = await probeGhAuth();
|
|
57766
57806
|
return { installed: true, version: /(\d+\.\d+\.\d+)/.exec(raw)?.[1] ?? (raw || null), authenticated };
|
|
@@ -57886,6 +57926,11 @@ async function executeClaimedUnit(fetchImpl, appUrl2, state, config2, io, runtim
|
|
|
57886
57926
|
summary: capResultSummary(result.summary),
|
|
57887
57927
|
log_ref: input.logRef(id),
|
|
57888
57928
|
model: (turnRuntime ?? runtime) === "codex" ? "codex-cli" : "claude-cli",
|
|
57929
|
+
// DER-1915: token usage lifted from the claude JSON envelope (extractClaudeUsage), sent for
|
|
57930
|
+
// BOTH kinds when present — never defaulted to 0 (see RunnerTurnResult.inputTokens/outputTokens).
|
|
57931
|
+
// Both result routes (work-orders and turn-executions) accept these snake_case fields.
|
|
57932
|
+
...result.inputTokens != null ? { input_tokens: result.inputTokens } : {},
|
|
57933
|
+
...result.outputTokens != null ? { output_tokens: result.outputTokens } : {},
|
|
57889
57934
|
// Artifact-bearing result fields (T1.5) — only sent when the harness produced them, so
|
|
57890
57935
|
// the result route's `.strict()` schema still accepts a plain read-status report.
|
|
57891
57936
|
...result.prUrl ? { pr_url: result.prUrl } : {},
|
|
@@ -58019,9 +58064,14 @@ function resolveTurnPlan(input) {
|
|
|
58019
58064
|
],
|
|
58020
58065
|
codexSandbox: execution.local_tools === "workspace_write" ? "workspace-write" : "read-only",
|
|
58021
58066
|
// Forge build/review turns emit a structured JSON envelope (reusing the AICOS
|
|
58022
|
-
// --output-format json pattern) so their summary is a real contract, not a stdout
|
|
58023
|
-
//
|
|
58024
|
-
|
|
58067
|
+
// --output-format json pattern) so their summary is a real contract, not a stdout slice.
|
|
58068
|
+
// DER-1915: seat_work ALSO uses the JSON envelope now, purely so its usage block
|
|
58069
|
+
// (extractClaudeUsage) is reportable — the DER-1333 intent (a free-form status summary,
|
|
58070
|
+
// not a structured contract) is unchanged, because `extractRunnerSummary` unwraps the
|
|
58071
|
+
// envelope down to the model's own `result` text either way; json just adds parseable
|
|
58072
|
+
// metadata (usage, session_id) alongside it. Only read_status (a read-only status stub,
|
|
58073
|
+
// not a real MCP turn) still uses plain text.
|
|
58074
|
+
outputFormat: execution.profile === "forge_build" || execution.profile === "forge_review" || execution.profile === "seat_work" ? "json" : "text",
|
|
58025
58075
|
// Only a Forge workspace grants a repo cwd; a needs_repo contract with no prepared
|
|
58026
58076
|
// workspace (broker/clone failed upstream) falls back to tmpdir rather than a bad cwd.
|
|
58027
58077
|
repoDir: execution.needs_repo ? input.repoDir : null,
|
|
@@ -58702,11 +58752,21 @@ function runModelProcess(input) {
|
|
|
58702
58752
|
let err = "";
|
|
58703
58753
|
const timer = setTimeout(() => {
|
|
58704
58754
|
killProcessTree(child);
|
|
58755
|
+
const seconds = Math.round(input.timeoutMs / 1e3);
|
|
58705
58756
|
const partial2 = scrubTranscriptSessionIds(redactForLog((out || err || "").trim()));
|
|
58757
|
+
let transcriptBody = partial2;
|
|
58758
|
+
if (transcriptBody.length === 0) {
|
|
58759
|
+
const redactedErr = scrubTranscriptSessionIds(redactForLog(err.trim()));
|
|
58760
|
+
transcriptBody = `turn timed out after ${seconds}s; no model output was captured before the process was killed.`;
|
|
58761
|
+
if (redactedErr.length > 0) {
|
|
58762
|
+
transcriptBody += `
|
|
58763
|
+
${redactedErr}`;
|
|
58764
|
+
}
|
|
58765
|
+
}
|
|
58706
58766
|
finish({
|
|
58707
58767
|
ok: false,
|
|
58708
|
-
summary: `turn timed out after ${
|
|
58709
|
-
|
|
58768
|
+
summary: `turn timed out after ${seconds}s`,
|
|
58769
|
+
transcript: transcriptBody.slice(0, MAX_TRANSCRIPT_CHARS)
|
|
58710
58770
|
});
|
|
58711
58771
|
}, input.timeoutMs);
|
|
58712
58772
|
child.stdout.on("data", (data) => {
|
|
@@ -58721,18 +58781,30 @@ function runModelProcess(input) {
|
|
|
58721
58781
|
const redacted = redactForLog(rawOutput);
|
|
58722
58782
|
const evidence = input.collectEvidence && code === 0 ? extractRunnerEvidence(rawOutput) : [];
|
|
58723
58783
|
const planArtifact = input.collectEvidence && code === 0 ? extractForgePlanArtifact(rawOutput) : void 0;
|
|
58784
|
+
const transcriptSource = !input.collectEvidence && redacted.trim().startsWith("{") ? extractRunnerSummary(redacted) : redacted;
|
|
58724
58785
|
finish({
|
|
58725
58786
|
ok: code === 0,
|
|
58726
58787
|
summary: extractRunnerSummary(redacted).slice(0, 12e3),
|
|
58727
|
-
transcript: scrubTranscriptSessionIds(
|
|
58788
|
+
transcript: scrubTranscriptSessionIds(transcriptSource).slice(0, MAX_TRANSCRIPT_CHARS),
|
|
58728
58789
|
...evidence.length > 0 ? { evidence } : {},
|
|
58729
58790
|
...input.expectSessionEnvelope ? extractClaudeSessionId(rawOutput) : {},
|
|
58730
|
-
...planArtifact ? { planArtifact } : {}
|
|
58791
|
+
...planArtifact ? { planArtifact } : {},
|
|
58792
|
+
// DER-1915: attempt the token-usage extraction for BOTH work_order and turn_execution
|
|
58793
|
+
// kinds (unlike the session id, which is scoped to expectSessionEnvelope/resume) — a
|
|
58794
|
+
// Forge build/review work order runs claude with the same JSON envelope and its usage
|
|
58795
|
+
// is just as reportable. Safe to attempt unconditionally: non-JSON/no-usage output
|
|
58796
|
+
// yields {}, never a fabricated zero.
|
|
58797
|
+
...extractClaudeUsage(rawOutput)
|
|
58731
58798
|
});
|
|
58732
58799
|
});
|
|
58733
58800
|
child.on("error", (error51) => {
|
|
58734
58801
|
clearTimeout(timer);
|
|
58735
|
-
|
|
58802
|
+
const message = redactForLog(error51.message);
|
|
58803
|
+
finish({
|
|
58804
|
+
ok: false,
|
|
58805
|
+
summary: `spawn error: ${message}`,
|
|
58806
|
+
transcript: `spawn error: ${message}`.slice(0, MAX_TRANSCRIPT_CHARS)
|
|
58807
|
+
});
|
|
58736
58808
|
});
|
|
58737
58809
|
});
|
|
58738
58810
|
}
|
|
@@ -58852,6 +58924,30 @@ function extractClaudeSessionId(output) {
|
|
|
58852
58924
|
return {};
|
|
58853
58925
|
}
|
|
58854
58926
|
}
|
|
58927
|
+
function extractClaudeUsage(output) {
|
|
58928
|
+
const trimmed = output.trim();
|
|
58929
|
+
if (!trimmed.startsWith("{")) {
|
|
58930
|
+
return {};
|
|
58931
|
+
}
|
|
58932
|
+
try {
|
|
58933
|
+
const parsed = JSON.parse(trimmed);
|
|
58934
|
+
const usage2 = parsed.usage;
|
|
58935
|
+
if (!usage2 || typeof usage2 !== "object" || Array.isArray(usage2)) {
|
|
58936
|
+
return {};
|
|
58937
|
+
}
|
|
58938
|
+
const record2 = usage2;
|
|
58939
|
+
const result = {};
|
|
58940
|
+
if (typeof record2.input_tokens === "number" && Number.isFinite(record2.input_tokens) && record2.input_tokens >= 0) {
|
|
58941
|
+
result.inputTokens = Math.floor(record2.input_tokens);
|
|
58942
|
+
}
|
|
58943
|
+
if (typeof record2.output_tokens === "number" && Number.isFinite(record2.output_tokens) && record2.output_tokens >= 0) {
|
|
58944
|
+
result.outputTokens = Math.floor(record2.output_tokens);
|
|
58945
|
+
}
|
|
58946
|
+
return result;
|
|
58947
|
+
} catch {
|
|
58948
|
+
return {};
|
|
58949
|
+
}
|
|
58950
|
+
}
|
|
58855
58951
|
function runtimeSessionKey(state, workOrder) {
|
|
58856
58952
|
const seatId = extractSeatId(workOrder);
|
|
58857
58953
|
const userId = extractTurnUserId(workOrder);
|