tines 0.0.204 → 0.0.205
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 +430 -115
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -3536,22 +3536,22 @@ function runDurationLabel(run2, now = Date.now()) {
|
|
|
3536
3536
|
return seconds < 60 ? `${seconds}s` : `${Math.floor(seconds / 60)}m`;
|
|
3537
3537
|
}
|
|
3538
3538
|
function runCostLabel(run2) {
|
|
3539
|
-
const
|
|
3540
|
-
if (!
|
|
3541
|
-
if (
|
|
3542
|
-
const dollars =
|
|
3543
|
-
const source =
|
|
3539
|
+
const usage2 = run2.usage;
|
|
3540
|
+
if (!usage2) return null;
|
|
3541
|
+
if (usage2.cost_usd !== void 0) {
|
|
3542
|
+
const dollars = usage2.cost_usd === 0 ? "$0" : usage2.cost_usd < 0.01 ? "<$0.01" : `$${usage2.cost_usd.toFixed(2)}`;
|
|
3543
|
+
const source = usage2.cost_source === "provider" ? "Reported" : usage2.cost_source === "priced" ? "Estimated" : "Recorded";
|
|
3544
3544
|
return `${dollars} ${source}`;
|
|
3545
3545
|
}
|
|
3546
|
-
if (
|
|
3547
|
-
if (
|
|
3546
|
+
if (usage2.pricing?.status === "unpriced") return "Unpriced";
|
|
3547
|
+
if (usage2.cost_source === "none") return "Unreported";
|
|
3548
3548
|
const measured = [
|
|
3549
|
-
|
|
3550
|
-
|
|
3551
|
-
|
|
3552
|
-
|
|
3549
|
+
usage2.input_tokens,
|
|
3550
|
+
usage2.output_tokens,
|
|
3551
|
+
usage2.cache_read_tokens,
|
|
3552
|
+
usage2.cache_write_tokens
|
|
3553
3553
|
].some((value) => value !== void 0);
|
|
3554
|
-
const tokens = (
|
|
3554
|
+
const tokens = (usage2.input_tokens ?? 0) + (usage2.output_tokens ?? 0) + (usage2.cache_read_tokens ?? 0) + (usage2.cache_write_tokens ?? 0);
|
|
3555
3555
|
return tokens > 0 ? `${tokens.toLocaleString()} tok` : measured ? "Unpriced" : null;
|
|
3556
3556
|
}
|
|
3557
3557
|
function utilizationLabel(quota, activeRuns, stateName = (id2) => id2) {
|
|
@@ -3587,8 +3587,8 @@ function str(v) {
|
|
|
3587
3587
|
function isoTime(v) {
|
|
3588
3588
|
return typeof v === "number" && Number.isFinite(v) ? new Date(v).toISOString() : "an unknown time";
|
|
3589
3589
|
}
|
|
3590
|
-
function joinChanged(v,
|
|
3591
|
-
return Array.isArray(v) ? v.join(
|
|
3590
|
+
function joinChanged(v, sep4) {
|
|
3591
|
+
return Array.isArray(v) ? v.join(sep4) : "";
|
|
3592
3592
|
}
|
|
3593
3593
|
function action(type) {
|
|
3594
3594
|
return type.split(".")[1] ?? type;
|
|
@@ -5354,30 +5354,30 @@ function structuralDocument(value, allowMissingDigest) {
|
|
|
5354
5354
|
throw new LibraryValidationError([
|
|
5355
5355
|
{ path: "", code: "invalid_document", message: "Library document must be an object" }
|
|
5356
5356
|
]);
|
|
5357
|
-
const
|
|
5358
|
-
if (
|
|
5357
|
+
const object4 = value;
|
|
5358
|
+
if (object4.format !== "tines.library")
|
|
5359
5359
|
throw new LibraryValidationError([
|
|
5360
5360
|
{ path: "/format", code: "invalid_format", message: "Expected tines.library" }
|
|
5361
5361
|
]);
|
|
5362
|
-
if (
|
|
5362
|
+
if (object4.version !== 3)
|
|
5363
5363
|
throw new LibraryValidationError([
|
|
5364
5364
|
{
|
|
5365
5365
|
path: "/version",
|
|
5366
5366
|
code: "unsupported_version",
|
|
5367
|
-
message: `Unsupported library version ${String(
|
|
5367
|
+
message: `Unsupported library version ${String(object4.version)}`
|
|
5368
5368
|
}
|
|
5369
5369
|
]);
|
|
5370
|
-
if (
|
|
5370
|
+
if (object4.profile !== "workflow" && object4.profile !== "library")
|
|
5371
5371
|
throw new LibraryValidationError([
|
|
5372
5372
|
{ path: "/profile", code: "invalid_profile", message: "Expected workflow or library profile" }
|
|
5373
5373
|
]);
|
|
5374
|
-
const allowed = TOP_LEVEL[
|
|
5375
|
-
const unknown = Object.keys(
|
|
5374
|
+
const allowed = TOP_LEVEL[object4.profile];
|
|
5375
|
+
const unknown = Object.keys(object4).find((key) => !allowed.includes(key));
|
|
5376
5376
|
if (unknown)
|
|
5377
5377
|
throw new LibraryValidationError([
|
|
5378
5378
|
{ path: `/${unknown}`, code: "unknown_field", message: `Unknown field ${unknown}` }
|
|
5379
5379
|
]);
|
|
5380
|
-
if (!Number.isSafeInteger(
|
|
5380
|
+
if (!Number.isSafeInteger(object4.exported_at) || object4.exported_at < 0)
|
|
5381
5381
|
throw new LibraryValidationError([
|
|
5382
5382
|
{
|
|
5383
5383
|
path: "/exported_at",
|
|
@@ -5385,7 +5385,7 @@ function structuralDocument(value, allowMissingDigest) {
|
|
|
5385
5385
|
message: "exported_at must be a non-negative safe integer"
|
|
5386
5386
|
}
|
|
5387
5387
|
]);
|
|
5388
|
-
if (!(allowMissingDigest &&
|
|
5388
|
+
if (!(allowMissingDigest && object4.digest === void 0) && (typeof object4.digest !== "string" || !/^sha256:[0-9a-f]{64}$/.test(object4.digest)))
|
|
5389
5389
|
throw new LibraryValidationError([
|
|
5390
5390
|
{
|
|
5391
5391
|
path: "/digest",
|
|
@@ -5395,14 +5395,14 @@ function structuralDocument(value, allowMissingDigest) {
|
|
|
5395
5395
|
]);
|
|
5396
5396
|
for (const key of allowed) {
|
|
5397
5397
|
if (key === "digest" && allowMissingDigest) continue;
|
|
5398
|
-
if (!(key in
|
|
5398
|
+
if (!(key in object4))
|
|
5399
5399
|
throw new LibraryValidationError([
|
|
5400
5400
|
{ path: `/${key}`, code: "missing_field", message: `Missing required field ${key}` }
|
|
5401
5401
|
]);
|
|
5402
5402
|
}
|
|
5403
5403
|
return {
|
|
5404
|
-
...
|
|
5405
|
-
digest: typeof
|
|
5404
|
+
...object4,
|
|
5405
|
+
digest: typeof object4.digest === "string" ? object4.digest : ""
|
|
5406
5406
|
};
|
|
5407
5407
|
}
|
|
5408
5408
|
async function parseLibraryV3Document(input2, options = {}) {
|
|
@@ -5751,11 +5751,11 @@ function assertNewStatesHavePrompts(states, prompts) {
|
|
|
5751
5751
|
}
|
|
5752
5752
|
}
|
|
5753
5753
|
function parseScheduleRef(ref) {
|
|
5754
|
-
const
|
|
5755
|
-
if (
|
|
5754
|
+
const sep4 = ref.indexOf("/");
|
|
5755
|
+
if (sep4 < 1 || sep4 === ref.length - 1) {
|
|
5756
5756
|
throw new CliError(`schedule reference must look like <project>/<name>, got "${ref}"`);
|
|
5757
5757
|
}
|
|
5758
|
-
return { project: ref.slice(0,
|
|
5758
|
+
return { project: ref.slice(0, sep4), name: ref.slice(sep4 + 1) };
|
|
5759
5759
|
}
|
|
5760
5760
|
function parseIssueRef(ref) {
|
|
5761
5761
|
const match = ref.match(/^(.+)\/(\d+)$/);
|
|
@@ -5763,12 +5763,12 @@ function parseIssueRef(ref) {
|
|
|
5763
5763
|
return { project: match[1], number: Number.parseInt(match[2], 10) };
|
|
5764
5764
|
}
|
|
5765
5765
|
function parseFileSpec(spec) {
|
|
5766
|
-
const
|
|
5767
|
-
if (
|
|
5766
|
+
const sep4 = spec.indexOf("=");
|
|
5767
|
+
if (sep4 < 1 || sep4 === spec.length - 1) {
|
|
5768
5768
|
throw new CliError(`--file must look like <path>=@<local-file>, got "${spec}"`);
|
|
5769
5769
|
}
|
|
5770
|
-
const path2 = spec.slice(0,
|
|
5771
|
-
const source = spec.slice(
|
|
5770
|
+
const path2 = spec.slice(0, sep4);
|
|
5771
|
+
const source = spec.slice(sep4 + 1);
|
|
5772
5772
|
if (!source.startsWith("@")) {
|
|
5773
5773
|
throw new CliError(
|
|
5774
5774
|
`skill file content always comes from a local file: --file ${path2}=@<local-file>`
|
|
@@ -5782,10 +5782,10 @@ function parseFileSpec(spec) {
|
|
|
5782
5782
|
}
|
|
5783
5783
|
}
|
|
5784
5784
|
function parseTargetSpec(spec) {
|
|
5785
|
-
const
|
|
5786
|
-
if (
|
|
5787
|
-
const name2 = spec.slice(0,
|
|
5788
|
-
const tier = spec.slice(
|
|
5785
|
+
const sep4 = spec.lastIndexOf(":");
|
|
5786
|
+
if (sep4 === -1) return { name: spec };
|
|
5787
|
+
const name2 = spec.slice(0, sep4);
|
|
5788
|
+
const tier = spec.slice(sep4 + 1);
|
|
5789
5789
|
if (!name2) throw new CliError(`target must look like <runner>[:tier], got "${spec}"`);
|
|
5790
5790
|
if (!MODEL_TIERS.includes(tier)) {
|
|
5791
5791
|
throw new CliError(`unknown tier "${tier}" in "${spec}" (tiers: ${MODEL_TIERS.join(", ")})`);
|
|
@@ -5997,12 +5997,12 @@ async function resolveLabelFlag(api, ref) {
|
|
|
5997
5997
|
return match.id;
|
|
5998
5998
|
}
|
|
5999
5999
|
async function resolveStateFlag(api, ref) {
|
|
6000
|
-
const
|
|
6001
|
-
if (
|
|
6000
|
+
const sep4 = ref.indexOf("/");
|
|
6001
|
+
if (sep4 < 1 || sep4 === ref.length - 1) {
|
|
6002
6002
|
die(`--state must look like <workflow>/<state>, got "${ref}"`);
|
|
6003
6003
|
}
|
|
6004
|
-
const workflow2 = await resolveWorkflow(api, ref.slice(0,
|
|
6005
|
-
const stateRef2 = ref.slice(
|
|
6004
|
+
const workflow2 = await resolveWorkflow(api, ref.slice(0, sep4));
|
|
6005
|
+
const stateRef2 = ref.slice(sep4 + 1);
|
|
6006
6006
|
const state = workflow2.states.find((s) => s.name === stateRef2) ?? workflow2.states.find((s) => s.id === stateRef2);
|
|
6007
6007
|
if (!state) {
|
|
6008
6008
|
die(
|
|
@@ -8503,8 +8503,8 @@ import {
|
|
|
8503
8503
|
writeFileSync as writeFileSync3
|
|
8504
8504
|
} from "node:fs";
|
|
8505
8505
|
import { randomUUID } from "node:crypto";
|
|
8506
|
-
import { dirname as dirname4, join as
|
|
8507
|
-
import { StringDecoder } from "node:string_decoder";
|
|
8506
|
+
import { dirname as dirname4, join as join6 } from "node:path";
|
|
8507
|
+
import { StringDecoder as StringDecoder2 } from "node:string_decoder";
|
|
8508
8508
|
|
|
8509
8509
|
// src/version.ts
|
|
8510
8510
|
import { readFileSync as readFileSync6 } from "node:fs";
|
|
@@ -8531,7 +8531,17 @@ function copySummary(value) {
|
|
|
8531
8531
|
...value.pricingEvidence ? {
|
|
8532
8532
|
pricingEvidence: {
|
|
8533
8533
|
...value.pricingEvidence,
|
|
8534
|
-
...value.pricingEvidence.raw_usage ? { raw_usage: { ...value.pricingEvidence.raw_usage } } : {}
|
|
8534
|
+
...value.pricingEvidence.raw_usage ? { raw_usage: { ...value.pricingEvidence.raw_usage } } : {},
|
|
8535
|
+
...value.pricingEvidence.request_context ? {
|
|
8536
|
+
request_context: {
|
|
8537
|
+
...value.pricingEvidence.request_context,
|
|
8538
|
+
...value.pricingEvidence.request_context.status === "complete" ? {
|
|
8539
|
+
reconciled_usage: {
|
|
8540
|
+
...value.pricingEvidence.request_context.reconciled_usage
|
|
8541
|
+
}
|
|
8542
|
+
} : {}
|
|
8543
|
+
}
|
|
8544
|
+
} : {}
|
|
8535
8545
|
}
|
|
8536
8546
|
} : {}
|
|
8537
8547
|
};
|
|
@@ -8659,10 +8669,10 @@ var ClaudeStreamRenderer = class {
|
|
|
8659
8669
|
}
|
|
8660
8670
|
if (validMetric(event.num_turns)) this.collected.numTurns = event.num_turns;
|
|
8661
8671
|
if (validMetric(event.duration_ms)) this.collected.durationMs = event.duration_ms;
|
|
8662
|
-
const
|
|
8672
|
+
const usage2 = { cost_source: "provider" };
|
|
8663
8673
|
let measured = false;
|
|
8664
8674
|
if (validMetric(event.total_cost_usd)) {
|
|
8665
|
-
|
|
8675
|
+
usage2.cost_usd = event.total_cost_usd;
|
|
8666
8676
|
measured = true;
|
|
8667
8677
|
}
|
|
8668
8678
|
const raw = event.usage;
|
|
@@ -8674,12 +8684,12 @@ var ClaudeStreamRenderer = class {
|
|
|
8674
8684
|
["cache_creation_input_tokens", "cache_write_tokens"]
|
|
8675
8685
|
]) {
|
|
8676
8686
|
if (validMetric(raw[source])) {
|
|
8677
|
-
|
|
8687
|
+
usage2[destination] = raw[source];
|
|
8678
8688
|
measured = true;
|
|
8679
8689
|
}
|
|
8680
8690
|
}
|
|
8681
8691
|
}
|
|
8682
|
-
if (measured) this.collected.usage =
|
|
8692
|
+
if (measured) this.collected.usage = usage2;
|
|
8683
8693
|
}
|
|
8684
8694
|
};
|
|
8685
8695
|
|
|
@@ -8836,12 +8846,12 @@ var CodexStreamRenderer = class {
|
|
|
8836
8846
|
this.stickyStatus = "nonmonotonic";
|
|
8837
8847
|
}
|
|
8838
8848
|
status = this.stickyStatus ?? status;
|
|
8839
|
-
const
|
|
8840
|
-
if (complete)
|
|
8841
|
-
if (rawCached !== void 0)
|
|
8842
|
-
if (rawWrite !== void 0)
|
|
8843
|
-
if (output !== void 0)
|
|
8844
|
-
this.collected.usage =
|
|
8849
|
+
const usage2 = {};
|
|
8850
|
+
if (complete) usage2.input_tokens = input2;
|
|
8851
|
+
if (rawCached !== void 0) usage2.cache_read_tokens = rawCached;
|
|
8852
|
+
if (rawWrite !== void 0) usage2.cache_write_tokens = rawWrite;
|
|
8853
|
+
if (output !== void 0) usage2.output_tokens = output;
|
|
8854
|
+
this.collected.usage = usage2;
|
|
8845
8855
|
this.updateEvidence(status, void 0, rawUsage);
|
|
8846
8856
|
}
|
|
8847
8857
|
updateEvidence(status, rerouted, rawUsage) {
|
|
@@ -8862,6 +8872,261 @@ var CodexStreamRenderer = class {
|
|
|
8862
8872
|
}
|
|
8863
8873
|
};
|
|
8864
8874
|
|
|
8875
|
+
// src/daemon/codex-rollout.ts
|
|
8876
|
+
import { open, opendir, realpath, stat } from "node:fs/promises";
|
|
8877
|
+
import { isAbsolute, join as join3, relative, resolve, sep } from "node:path";
|
|
8878
|
+
import { homedir as homedir2 } from "node:os";
|
|
8879
|
+
import { StringDecoder } from "node:string_decoder";
|
|
8880
|
+
var CODEX_ROLLOUT_MAX_BYTES = 128 * 1024 * 1024;
|
|
8881
|
+
var CODEX_ROLLOUT_MAX_LINE_BYTES = 8 * 1024 * 1024;
|
|
8882
|
+
var CODEX_ROLLOUT_MAX_LINES = 25e4;
|
|
8883
|
+
var CODEX_ROLLOUT_MAX_REQUESTS = 1e4;
|
|
8884
|
+
var CODEX_ROLLOUT_TIMEOUT_MS = 5e3;
|
|
8885
|
+
var SUPPORTED_VERSION = "0.153.4";
|
|
8886
|
+
var FIELDS = [
|
|
8887
|
+
"input_tokens",
|
|
8888
|
+
"cached_input_tokens",
|
|
8889
|
+
"cache_write_input_tokens",
|
|
8890
|
+
"output_tokens"
|
|
8891
|
+
];
|
|
8892
|
+
var unavailable = (reason) => ({
|
|
8893
|
+
version: 1,
|
|
8894
|
+
normalization: "codex-rollout-delta-v1",
|
|
8895
|
+
status: "unavailable",
|
|
8896
|
+
reason
|
|
8897
|
+
});
|
|
8898
|
+
var invalid2 = (reason, harness_version) => ({
|
|
8899
|
+
version: 1,
|
|
8900
|
+
normalization: "codex-rollout-delta-v1",
|
|
8901
|
+
...harness_version ? { harness_version: harness_version.slice(0, 100) } : {},
|
|
8902
|
+
status: "invalid",
|
|
8903
|
+
reason
|
|
8904
|
+
});
|
|
8905
|
+
function object3(value) {
|
|
8906
|
+
return value !== null && typeof value === "object" && !Array.isArray(value) ? value : void 0;
|
|
8907
|
+
}
|
|
8908
|
+
function usage(value, validateClasses = true) {
|
|
8909
|
+
const raw = object3(value);
|
|
8910
|
+
if (!raw) return;
|
|
8911
|
+
const out = {};
|
|
8912
|
+
for (const field of FIELDS) {
|
|
8913
|
+
const metric = raw[field];
|
|
8914
|
+
if (!Number.isSafeInteger(metric) || metric < 0) return;
|
|
8915
|
+
out[field] = metric;
|
|
8916
|
+
}
|
|
8917
|
+
if (validateClasses && out.cached_input_tokens + out.cache_write_input_tokens > out.input_tokens)
|
|
8918
|
+
return;
|
|
8919
|
+
return out;
|
|
8920
|
+
}
|
|
8921
|
+
function equal(a, b) {
|
|
8922
|
+
return FIELDS.every((field) => a[field] === b[field]);
|
|
8923
|
+
}
|
|
8924
|
+
function reconcileCodexRollout(records, input2) {
|
|
8925
|
+
let metadata = false;
|
|
8926
|
+
let harnessVersion;
|
|
8927
|
+
let observedModel;
|
|
8928
|
+
let previous = {
|
|
8929
|
+
input_tokens: 0,
|
|
8930
|
+
cached_input_tokens: 0,
|
|
8931
|
+
cache_write_input_tokens: 0,
|
|
8932
|
+
output_tokens: 0
|
|
8933
|
+
};
|
|
8934
|
+
let observed = false;
|
|
8935
|
+
let requestCount = 0;
|
|
8936
|
+
let maxRequestInput = 0;
|
|
8937
|
+
let previousLast = { ...previous };
|
|
8938
|
+
for (const value of records) {
|
|
8939
|
+
const record = object3(value);
|
|
8940
|
+
const payload = object3(record?.payload);
|
|
8941
|
+
if (record?.type === "session_meta") {
|
|
8942
|
+
if (metadata) return invalid2("metadata_mismatch", harnessVersion);
|
|
8943
|
+
harnessVersion = typeof payload?.cli_version === "string" ? payload.cli_version : void 0;
|
|
8944
|
+
if (payload?.id !== input2.threadId || payload?.source !== "exec" || payload?.originator !== "codex_exec")
|
|
8945
|
+
return invalid2("metadata_mismatch", harnessVersion);
|
|
8946
|
+
metadata = true;
|
|
8947
|
+
continue;
|
|
8948
|
+
}
|
|
8949
|
+
if (record?.type === "turn_context" && typeof payload?.model === "string") {
|
|
8950
|
+
observedModel ??= payload.model;
|
|
8951
|
+
if (observedModel !== payload.model || input2.model && payload.model !== input2.model)
|
|
8952
|
+
return invalid2("model_mismatch", harnessVersion);
|
|
8953
|
+
continue;
|
|
8954
|
+
}
|
|
8955
|
+
if (record?.type !== "event_msg" || payload?.type !== "token_count") continue;
|
|
8956
|
+
const info = object3(payload.info);
|
|
8957
|
+
if (!info) continue;
|
|
8958
|
+
const total = usage(info.total_token_usage);
|
|
8959
|
+
const last = usage(info.last_token_usage, false);
|
|
8960
|
+
if (!total || !last) return invalid2("missing_dimension", harnessVersion);
|
|
8961
|
+
observed = true;
|
|
8962
|
+
if (equal(total, previous)) {
|
|
8963
|
+
if (!equal(last, previousLast)) return invalid2("delta_mismatch", harnessVersion);
|
|
8964
|
+
continue;
|
|
8965
|
+
}
|
|
8966
|
+
if (FIELDS.some((field) => total[field] < previous[field]))
|
|
8967
|
+
return invalid2("nonmonotonic", harnessVersion);
|
|
8968
|
+
const delta = {};
|
|
8969
|
+
for (const field of FIELDS) delta[field] = total[field] - previous[field];
|
|
8970
|
+
if (delta.cached_input_tokens + delta.cache_write_input_tokens > delta.input_tokens)
|
|
8971
|
+
return invalid2("nonmonotonic", harnessVersion);
|
|
8972
|
+
if (!equal(delta, last)) return invalid2("delta_mismatch", harnessVersion);
|
|
8973
|
+
requestCount++;
|
|
8974
|
+
if (requestCount > CODEX_ROLLOUT_MAX_REQUESTS) return invalid2("limit_exceeded", harnessVersion);
|
|
8975
|
+
maxRequestInput = Math.max(maxRequestInput, delta.input_tokens);
|
|
8976
|
+
previous = total;
|
|
8977
|
+
previousLast = delta;
|
|
8978
|
+
}
|
|
8979
|
+
if (!metadata) return invalid2("metadata_mismatch", harnessVersion);
|
|
8980
|
+
if (harnessVersion !== SUPPORTED_VERSION) {
|
|
8981
|
+
return {
|
|
8982
|
+
version: 1,
|
|
8983
|
+
normalization: "codex-rollout-delta-v1",
|
|
8984
|
+
...harnessVersion ? { harness_version: harnessVersion.slice(0, 100) } : {},
|
|
8985
|
+
status: "unsupported",
|
|
8986
|
+
reason: "unsupported_version"
|
|
8987
|
+
};
|
|
8988
|
+
}
|
|
8989
|
+
const terminalZero = FIELDS.every((field) => input2.terminalUsage[field] === 0);
|
|
8990
|
+
if (!observed && !terminalZero) return invalid2("missing_dimension", harnessVersion);
|
|
8991
|
+
if (!equal(previous, input2.terminalUsage)) return invalid2("terminal_mismatch", harnessVersion);
|
|
8992
|
+
return {
|
|
8993
|
+
version: 1,
|
|
8994
|
+
normalization: "codex-rollout-delta-v1",
|
|
8995
|
+
harness_version: SUPPORTED_VERSION,
|
|
8996
|
+
status: "complete",
|
|
8997
|
+
request_count: requestCount,
|
|
8998
|
+
max_request_input_tokens: maxRequestInput,
|
|
8999
|
+
reconciled_usage: { ...previous }
|
|
9000
|
+
};
|
|
9001
|
+
}
|
|
9002
|
+
function resolveCodexHome(env, workspace) {
|
|
9003
|
+
const configured = env.CODEX_HOME;
|
|
9004
|
+
return configured ? resolve(workspace, configured) : join3(homedir2(), ".codex");
|
|
9005
|
+
}
|
|
9006
|
+
function dateDirectories(startedAt, endedAt) {
|
|
9007
|
+
const first = new Date(startedAt);
|
|
9008
|
+
first.setUTCDate(first.getUTCDate() - 1);
|
|
9009
|
+
first.setUTCHours(0, 0, 0, 0);
|
|
9010
|
+
const last = new Date(endedAt);
|
|
9011
|
+
last.setUTCDate(last.getUTCDate() + 1);
|
|
9012
|
+
last.setUTCHours(0, 0, 0, 0);
|
|
9013
|
+
const result = [];
|
|
9014
|
+
for (let date = first; date <= last; date = new Date(date.getTime() + 864e5)) {
|
|
9015
|
+
result.push(
|
|
9016
|
+
join3(
|
|
9017
|
+
String(date.getUTCFullYear()),
|
|
9018
|
+
String(date.getUTCMonth() + 1).padStart(2, "0"),
|
|
9019
|
+
String(date.getUTCDate()).padStart(2, "0")
|
|
9020
|
+
)
|
|
9021
|
+
);
|
|
9022
|
+
if (result.length > 10) return null;
|
|
9023
|
+
}
|
|
9024
|
+
return result;
|
|
9025
|
+
}
|
|
9026
|
+
async function readCodexRolloutRecords(stream, timeoutMs) {
|
|
9027
|
+
let timedOut = false;
|
|
9028
|
+
const timer = setTimeout(
|
|
9029
|
+
() => {
|
|
9030
|
+
timedOut = true;
|
|
9031
|
+
stream.destroy(new Error("Codex rollout read deadline exceeded"));
|
|
9032
|
+
},
|
|
9033
|
+
Math.max(0, timeoutMs)
|
|
9034
|
+
);
|
|
9035
|
+
const decoder = new StringDecoder("utf8");
|
|
9036
|
+
let pending = "";
|
|
9037
|
+
let bytes2 = 0;
|
|
9038
|
+
let lines2 = 0;
|
|
9039
|
+
const records = [];
|
|
9040
|
+
const consume = (line) => {
|
|
9041
|
+
if (++lines2 > CODEX_ROLLOUT_MAX_LINES || Buffer.byteLength(line) > CODEX_ROLLOUT_MAX_LINE_BYTES)
|
|
9042
|
+
return { reason: "limit_exceeded" };
|
|
9043
|
+
if (!line.trim()) return;
|
|
9044
|
+
try {
|
|
9045
|
+
records.push(JSON.parse(line));
|
|
9046
|
+
} catch {
|
|
9047
|
+
return { reason: "malformed" };
|
|
9048
|
+
}
|
|
9049
|
+
};
|
|
9050
|
+
try {
|
|
9051
|
+
for await (const value of stream) {
|
|
9052
|
+
const chunk = Buffer.isBuffer(value) ? value : Buffer.from(value);
|
|
9053
|
+
bytes2 += chunk.length;
|
|
9054
|
+
if (bytes2 > CODEX_ROLLOUT_MAX_BYTES) return { reason: "limit_exceeded" };
|
|
9055
|
+
pending += decoder.write(chunk);
|
|
9056
|
+
let newline;
|
|
9057
|
+
while ((newline = pending.indexOf("\n")) >= 0) {
|
|
9058
|
+
const failure = consume(pending.slice(0, newline));
|
|
9059
|
+
if (failure) return failure;
|
|
9060
|
+
pending = pending.slice(newline + 1);
|
|
9061
|
+
}
|
|
9062
|
+
if (Buffer.byteLength(pending) > CODEX_ROLLOUT_MAX_LINE_BYTES)
|
|
9063
|
+
return { reason: "limit_exceeded" };
|
|
9064
|
+
}
|
|
9065
|
+
pending += decoder.end();
|
|
9066
|
+
if (pending.length) {
|
|
9067
|
+
const failure = consume(pending);
|
|
9068
|
+
if (failure) return failure;
|
|
9069
|
+
}
|
|
9070
|
+
return { records };
|
|
9071
|
+
} catch {
|
|
9072
|
+
return { reason: timedOut ? "limit_exceeded" : "read_failed" };
|
|
9073
|
+
} finally {
|
|
9074
|
+
clearTimeout(timer);
|
|
9075
|
+
stream.destroy();
|
|
9076
|
+
}
|
|
9077
|
+
}
|
|
9078
|
+
async function collectCodexRequestContext(input2) {
|
|
9079
|
+
if (!/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i.test(input2.threadId))
|
|
9080
|
+
return unavailable("thread_id_missing");
|
|
9081
|
+
const dates = dateDirectories(input2.startedAt, input2.endedAt);
|
|
9082
|
+
if (!dates) return unavailable("limit_exceeded");
|
|
9083
|
+
const sessions = join3(input2.codexHome, "sessions");
|
|
9084
|
+
let root;
|
|
9085
|
+
try {
|
|
9086
|
+
root = await realpath(sessions);
|
|
9087
|
+
} catch {
|
|
9088
|
+
return unavailable("rollout_missing");
|
|
9089
|
+
}
|
|
9090
|
+
const candidates = [];
|
|
9091
|
+
let entries = 0;
|
|
9092
|
+
const deadline = Date.now() + CODEX_ROLLOUT_TIMEOUT_MS;
|
|
9093
|
+
try {
|
|
9094
|
+
for (const date of dates) {
|
|
9095
|
+
const directory = join3(root, date);
|
|
9096
|
+
let stream;
|
|
9097
|
+
try {
|
|
9098
|
+
stream = await opendir(directory);
|
|
9099
|
+
} catch {
|
|
9100
|
+
continue;
|
|
9101
|
+
}
|
|
9102
|
+
for await (const entry of stream) {
|
|
9103
|
+
if (++entries > 2e4 || Date.now() > deadline) return unavailable("limit_exceeded");
|
|
9104
|
+
if ((entry.isFile() || entry.isSymbolicLink()) && entry.name.startsWith("rollout-") && entry.name.endsWith(`-${input2.threadId}.jsonl`))
|
|
9105
|
+
candidates.push(join3(directory, entry.name));
|
|
9106
|
+
}
|
|
9107
|
+
}
|
|
9108
|
+
if (candidates.length === 0) return unavailable("rollout_missing");
|
|
9109
|
+
if (candidates.length !== 1) return unavailable("rollout_ambiguous");
|
|
9110
|
+
const candidate = await realpath(candidates[0]);
|
|
9111
|
+
const inside = relative(root, candidate);
|
|
9112
|
+
if (inside.startsWith(`..${sep}`) || inside === ".." || isAbsolute(inside))
|
|
9113
|
+
return unavailable("unsafe_path");
|
|
9114
|
+
const before = await stat(candidate);
|
|
9115
|
+
if (!before.isFile() || before.size > CODEX_ROLLOUT_MAX_BYTES)
|
|
9116
|
+
return unavailable("limit_exceeded");
|
|
9117
|
+
const handle = await open(candidate, "r");
|
|
9118
|
+
const read = await readCodexRolloutRecords(handle.createReadStream(), deadline - Date.now());
|
|
9119
|
+
if ("reason" in read)
|
|
9120
|
+
return read.reason === "malformed" ? invalid2("malformed") : unavailable(read.reason);
|
|
9121
|
+
const after = await stat(candidate);
|
|
9122
|
+
if (before.dev !== after.dev || before.ino !== after.ino || before.size !== after.size || before.mtimeMs !== after.mtimeMs)
|
|
9123
|
+
return invalid2("read_failed");
|
|
9124
|
+
return reconcileCodexRollout(read.records, input2);
|
|
9125
|
+
} catch {
|
|
9126
|
+
return unavailable("read_failed");
|
|
9127
|
+
}
|
|
9128
|
+
}
|
|
9129
|
+
|
|
8865
9130
|
// src/daemon/rate-limit.ts
|
|
8866
9131
|
var USAGE_LIMIT_PREFIXES = [
|
|
8867
9132
|
"You've hit your",
|
|
@@ -8965,11 +9230,11 @@ var DURATION = /(\d+)\s*([dhms])/g;
|
|
|
8965
9230
|
function parseResetTime(text4, now) {
|
|
8966
9231
|
const raw = text4.trim();
|
|
8967
9232
|
if (!raw) return null;
|
|
8968
|
-
const
|
|
8969
|
-
if (
|
|
9233
|
+
const relative2 = raw.match(/^in\s+(.+)$/i);
|
|
9234
|
+
if (relative2) {
|
|
8970
9235
|
let ms = 0;
|
|
8971
9236
|
let matched = false;
|
|
8972
|
-
for (const [, amount, unit] of
|
|
9237
|
+
for (const [, amount, unit] of relative2[1].matchAll(DURATION)) {
|
|
8973
9238
|
const n = Number(amount);
|
|
8974
9239
|
ms += n * { d: 864e5, h: 36e5, m: 6e4, s: 1e3 }[unit];
|
|
8975
9240
|
matched = true;
|
|
@@ -9052,10 +9317,10 @@ var RateLimitDetector = class {
|
|
|
9052
9317
|
// src/daemon/cli-refresh.ts
|
|
9053
9318
|
import { spawn } from "node:child_process";
|
|
9054
9319
|
import { existsSync as existsSync4, mkdirSync as mkdirSync3, readFileSync as readFileSync7 } from "node:fs";
|
|
9055
|
-
import { dirname as dirname3, join as
|
|
9320
|
+
import { dirname as dirname3, join as join4 } from "node:path";
|
|
9056
9321
|
|
|
9057
9322
|
// src/daemon/support.ts
|
|
9058
|
-
import { delimiter, sep } from "node:path";
|
|
9323
|
+
import { delimiter, sep as sep2 } from "node:path";
|
|
9059
9324
|
var HARNESS_KINDS = ["claude_code", "codex", "custom"];
|
|
9060
9325
|
var KEEP_WORKSPACES_MODES = ["never", "failed", "always"];
|
|
9061
9326
|
function keepWorkspace(mode, outcome) {
|
|
@@ -9359,7 +9624,7 @@ function pendingSelfUpdate(cli, running) {
|
|
|
9359
9624
|
return isNewerVersion(cli.version, running) ? cli.version : null;
|
|
9360
9625
|
}
|
|
9361
9626
|
function pathWithin(path2, dir) {
|
|
9362
|
-
const root = dir.endsWith(
|
|
9627
|
+
const root = dir.endsWith(sep2) ? dir : dir + sep2;
|
|
9363
9628
|
return path2.startsWith(root);
|
|
9364
9629
|
}
|
|
9365
9630
|
function buildSpawnEnv(base, opts) {
|
|
@@ -9379,14 +9644,14 @@ function buildSpawnEnv(base, opts) {
|
|
|
9379
9644
|
var PACKAGE = "tines";
|
|
9380
9645
|
var NPM_ARGS = ["--min-release-age=0", "--no-audit", "--no-fund", "--loglevel=error"];
|
|
9381
9646
|
function agentCliPrefix(configDir) {
|
|
9382
|
-
return
|
|
9647
|
+
return join4(configDir, "cli");
|
|
9383
9648
|
}
|
|
9384
9649
|
function binDirOf(prefix) {
|
|
9385
|
-
return
|
|
9650
|
+
return join4(prefix, "node_modules", ".bin");
|
|
9386
9651
|
}
|
|
9387
9652
|
function installedVersion(prefix) {
|
|
9388
9653
|
try {
|
|
9389
|
-
const pkg = readFileSync7(
|
|
9654
|
+
const pkg = readFileSync7(join4(prefix, "node_modules", PACKAGE, "package.json"), "utf8");
|
|
9390
9655
|
const version = JSON.parse(pkg).version;
|
|
9391
9656
|
return typeof version === "string" ? version : null;
|
|
9392
9657
|
} catch {
|
|
@@ -9395,11 +9660,11 @@ function installedVersion(prefix) {
|
|
|
9395
9660
|
}
|
|
9396
9661
|
function lastGood(prefix) {
|
|
9397
9662
|
const binDir = binDirOf(prefix);
|
|
9398
|
-
if (!existsSync4(
|
|
9663
|
+
if (!existsSync4(join4(binDir, PACKAGE))) return AMBIENT_CLI;
|
|
9399
9664
|
return { binDir, version: installedVersion(prefix), source: "stale" };
|
|
9400
9665
|
}
|
|
9401
9666
|
function runNpm(file, args, cwd, timeoutMs) {
|
|
9402
|
-
return new Promise((
|
|
9667
|
+
return new Promise((resolve2) => {
|
|
9403
9668
|
let output = "";
|
|
9404
9669
|
let done = false;
|
|
9405
9670
|
let timedOut = false;
|
|
@@ -9414,7 +9679,7 @@ function runNpm(file, args, cwd, timeoutMs) {
|
|
|
9414
9679
|
if (done) return;
|
|
9415
9680
|
done = true;
|
|
9416
9681
|
clearTimeout(timer);
|
|
9417
|
-
|
|
9682
|
+
resolve2({ ...result, timedOut, output });
|
|
9418
9683
|
};
|
|
9419
9684
|
child.stdout?.on("data", (data) => output += data.toString("utf8"));
|
|
9420
9685
|
child.stderr?.on("data", (data) => output += data.toString("utf8"));
|
|
@@ -9440,7 +9705,7 @@ async function installAgentCli(opts) {
|
|
|
9440
9705
|
const args = ["install", "--prefix", prefix, `${PACKAGE}@latest`, ...NPM_ARGS];
|
|
9441
9706
|
let result = await runNpm("npm", args, prefix, timeoutMs);
|
|
9442
9707
|
if (result.spawnError?.code === "ENOENT") {
|
|
9443
|
-
const sibling =
|
|
9708
|
+
const sibling = join4(dirname3(process.execPath), "npm");
|
|
9444
9709
|
if (existsSync4(sibling)) result = await runNpm(sibling, args, prefix, timeoutMs);
|
|
9445
9710
|
}
|
|
9446
9711
|
if (result.code !== 0) {
|
|
@@ -9467,12 +9732,12 @@ import { arch, hostname, platform } from "node:os";
|
|
|
9467
9732
|
|
|
9468
9733
|
// src/daemon/store.ts
|
|
9469
9734
|
import { readdirSync as readdirSync2, readFileSync as readFileSync8, rmSync as rmSync2, statSync as statSync3 } from "node:fs";
|
|
9470
|
-
import { join as
|
|
9735
|
+
import { join as join5 } from "node:path";
|
|
9471
9736
|
function credentialsKey(url, name2) {
|
|
9472
9737
|
return `${url.replace(/\/+$/, "")}#${name2}`;
|
|
9473
9738
|
}
|
|
9474
9739
|
function credentialsPath(dir) {
|
|
9475
|
-
return
|
|
9740
|
+
return join5(dir, "runners.json");
|
|
9476
9741
|
}
|
|
9477
9742
|
function loadRunnerCredentials(dir, url, name2) {
|
|
9478
9743
|
const all = readJsonFile(credentialsPath(dir));
|
|
@@ -9495,7 +9760,7 @@ function clearRunnerCredentials(dir, url, name2) {
|
|
|
9495
9760
|
writeJsonFile(path2, all, { secret: true });
|
|
9496
9761
|
}
|
|
9497
9762
|
function daemonStatePath(dir, runnerId) {
|
|
9498
|
-
return
|
|
9763
|
+
return join5(dir, `daemon-state-${runnerId}.json`);
|
|
9499
9764
|
}
|
|
9500
9765
|
function loadDaemonState(path2) {
|
|
9501
9766
|
const state = readJsonFile(path2);
|
|
@@ -9509,8 +9774,8 @@ function saveDaemonState(path2, runs) {
|
|
|
9509
9774
|
}
|
|
9510
9775
|
function processStartTimeMs(pid) {
|
|
9511
9776
|
try {
|
|
9512
|
-
const
|
|
9513
|
-
const afterComm =
|
|
9777
|
+
const stat2 = readFileSync8(`/proc/${pid}/stat`, "utf8");
|
|
9778
|
+
const afterComm = stat2.slice(stat2.lastIndexOf(")") + 2).split(" ");
|
|
9514
9779
|
const startTicks = Number(afterComm[19]);
|
|
9515
9780
|
const btimeLine = readFileSync8("/proc/stat", "utf8").split("\n").find((line) => line.startsWith("btime "));
|
|
9516
9781
|
const btime = Number(btimeLine?.slice("btime ".length));
|
|
@@ -9521,10 +9786,10 @@ function processStartTimeMs(pid) {
|
|
|
9521
9786
|
}
|
|
9522
9787
|
}
|
|
9523
9788
|
function workspacesDir(configDir) {
|
|
9524
|
-
return
|
|
9789
|
+
return join5(configDir, "workspaces");
|
|
9525
9790
|
}
|
|
9526
9791
|
function keptMarkerPath(workspace) {
|
|
9527
|
-
return
|
|
9792
|
+
return join5(workspace, "kept.json");
|
|
9528
9793
|
}
|
|
9529
9794
|
function writeKeptMarker(workspace, marker) {
|
|
9530
9795
|
writeJsonFile(keptMarkerPath(workspace), marker);
|
|
@@ -9546,7 +9811,7 @@ function listKeptWorkspaces(configDir) {
|
|
|
9546
9811
|
}
|
|
9547
9812
|
const kept = [];
|
|
9548
9813
|
for (const name2 of names) {
|
|
9549
|
-
const path2 =
|
|
9814
|
+
const path2 = join5(root, name2);
|
|
9550
9815
|
const marker = readKeptMarker(path2);
|
|
9551
9816
|
if (marker) kept.push({ ...marker, path: path2 });
|
|
9552
9817
|
}
|
|
@@ -9583,7 +9848,7 @@ function directorySizeBytes(path2) {
|
|
|
9583
9848
|
return 0;
|
|
9584
9849
|
}
|
|
9585
9850
|
for (const entry of entries) {
|
|
9586
|
-
const child =
|
|
9851
|
+
const child = join5(path2, entry.name);
|
|
9587
9852
|
if (entry.isDirectory()) total += directorySizeBytes(child);
|
|
9588
9853
|
else if (entry.isFile()) {
|
|
9589
9854
|
try {
|
|
@@ -9636,7 +9901,7 @@ async function uploadRawLog(run2) {
|
|
|
9636
9901
|
if (!path2 || !run2.rawUpload) return;
|
|
9637
9902
|
run2.rawSpoolPath = void 0;
|
|
9638
9903
|
try {
|
|
9639
|
-
await new Promise((
|
|
9904
|
+
await new Promise((resolve2) => run2.rawSpool?.end(resolve2) ?? resolve2());
|
|
9640
9905
|
const size = statSync4(path2).size;
|
|
9641
9906
|
if (size > 0) {
|
|
9642
9907
|
let body = readFileSync9(path2);
|
|
@@ -9661,7 +9926,7 @@ async function uploadRawLog(run2) {
|
|
|
9661
9926
|
}
|
|
9662
9927
|
}
|
|
9663
9928
|
var log = (message3) => console.log(`[${(/* @__PURE__ */ new Date()).toISOString().slice(11, 19)}] ${message3}`);
|
|
9664
|
-
var sleep = (ms) => new Promise((
|
|
9929
|
+
var sleep = (ms) => new Promise((resolve2) => setTimeout(resolve2, ms));
|
|
9665
9930
|
function killTree(pid, signal) {
|
|
9666
9931
|
try {
|
|
9667
9932
|
process.kill(-pid, signal);
|
|
@@ -9741,7 +10006,7 @@ async function runDaemon(opts) {
|
|
|
9741
10006
|
const selfUpdate = opts.selfUpdate && opts.cliRefresh && managedInstall;
|
|
9742
10007
|
if (opts.selfUpdate && opts.cliRefresh) {
|
|
9743
10008
|
log(
|
|
9744
|
-
managedInstall ? `self-update: on \u2014 this daemon (tines ${DAEMON_VERSION}) runs from ${prefix} and will restart once idle after a newer release is installed there` : `self-update: off \u2014 this daemon (tines ${DAEMON_VERSION}) runs from ${selfPath ?? process.argv[1] ?? "?"}, not ${prefix}; launch it from ${
|
|
10009
|
+
managedInstall ? `self-update: on \u2014 this daemon (tines ${DAEMON_VERSION}) runs from ${prefix} and will restart once idle after a newer release is installed there` : `self-update: off \u2014 this daemon (tines ${DAEMON_VERSION}) runs from ${selfPath ?? process.argv[1] ?? "?"}, not ${prefix}; launch it from ${join6(prefix, "node_modules", ".bin", "tines")} to have refreshes apply on restart \u2014 \`tines runner install --name ${opts.name} --harness ${opts.harness.replaceAll("_", "-")}\` sets that up as a service (docs/runner-daemon.md)`
|
|
9745
10010
|
);
|
|
9746
10011
|
}
|
|
9747
10012
|
let pendingUpdate = null;
|
|
@@ -9763,11 +10028,49 @@ async function runDaemon(opts) {
|
|
|
9763
10028
|
{
|
|
9764
10029
|
finish: async (run2, status, error, judgment) => {
|
|
9765
10030
|
const summary = run2.renderer?.summary();
|
|
10031
|
+
if (summary?.pricingEvidence && opts.harness === "codex") {
|
|
10032
|
+
const raw = summary.pricingEvidence.raw_usage;
|
|
10033
|
+
const completeRaw = raw && [
|
|
10034
|
+
"input_tokens",
|
|
10035
|
+
"cached_input_tokens",
|
|
10036
|
+
"cache_write_input_tokens",
|
|
10037
|
+
"output_tokens"
|
|
10038
|
+
].every((field) => raw[field] !== void 0);
|
|
10039
|
+
if (status === "completed" && run2.pricingSessionMode === "cold" && summary.pricingEvidence.measurement_status === "complete" && completeRaw && summary.providerSessionId && run2.codexHome && run2.spawnedAt) {
|
|
10040
|
+
summary.pricingEvidence.request_context = await collectCodexRequestContext({
|
|
10041
|
+
codexHome: run2.codexHome,
|
|
10042
|
+
threadId: summary.providerSessionId,
|
|
10043
|
+
model: run2.pricingModel ?? null,
|
|
10044
|
+
startedAt: run2.spawnedAt,
|
|
10045
|
+
endedAt: Date.now(),
|
|
10046
|
+
terminalUsage: raw
|
|
10047
|
+
});
|
|
10048
|
+
if ("reason" in summary.pricingEvidence.request_context && summary.pricingEvidence.request_context.reason === "model_mismatch")
|
|
10049
|
+
summary.pricingEvidence.model_rerouted = true;
|
|
10050
|
+
} else {
|
|
10051
|
+
summary.pricingEvidence.request_context = {
|
|
10052
|
+
version: 1,
|
|
10053
|
+
normalization: "codex-rollout-delta-v1",
|
|
10054
|
+
status: "unavailable",
|
|
10055
|
+
reason: "not_applicable"
|
|
10056
|
+
};
|
|
10057
|
+
}
|
|
10058
|
+
}
|
|
10059
|
+
const accounting = {
|
|
10060
|
+
usage: summary?.usage ?? { cost_source: "none" },
|
|
10061
|
+
...summary?.pricingEvidence ? { pricing_evidence: summary.pricingEvidence } : {},
|
|
10062
|
+
...summary?.providerSessionId ? { provider_session_id: summary.providerSessionId } : {},
|
|
10063
|
+
daemon_version: DAEMON_VERSION,
|
|
10064
|
+
status
|
|
10065
|
+
};
|
|
10066
|
+
run2.batcher.append(`[usage] ${JSON.stringify(accounting)}
|
|
10067
|
+
`);
|
|
10068
|
+
await run2.batcher.flush();
|
|
9766
10069
|
const ended = await client2.finishRun(run2.runId, {
|
|
9767
10070
|
status,
|
|
9768
10071
|
...error ? { error } : {},
|
|
9769
10072
|
...judgment,
|
|
9770
|
-
usage:
|
|
10073
|
+
usage: accounting.usage,
|
|
9771
10074
|
...summary?.pricingEvidence ? {
|
|
9772
10075
|
pricing_evidence: {
|
|
9773
10076
|
...summary.pricingEvidence,
|
|
@@ -9868,7 +10171,7 @@ async function runDaemon(opts) {
|
|
|
9868
10171
|
`run ${runId}: resume workspace ${assignment.resume.workspace_path} is gone; launching fresh`
|
|
9869
10172
|
);
|
|
9870
10173
|
}
|
|
9871
|
-
const workspace = resume ? resume.workspace_path :
|
|
10174
|
+
const workspace = resume ? resume.workspace_path : join6(workspacesDir(opts.configDir), runId);
|
|
9872
10175
|
const issueLabel = assignment.run.issue_ref ? `${assignment.run.issue_ref.project_name}/${assignment.run.issue_ref.number}` : void 0;
|
|
9873
10176
|
const run2 = {
|
|
9874
10177
|
runId,
|
|
@@ -9896,21 +10199,21 @@ async function runDaemon(opts) {
|
|
|
9896
10199
|
rmSync3(workspace, { recursive: true, force: true });
|
|
9897
10200
|
mkdirSync4(workspace, { recursive: true });
|
|
9898
10201
|
} else {
|
|
9899
|
-
rmSync3(
|
|
10202
|
+
rmSync3(join6(workspace, "kept.json"), { force: true });
|
|
9900
10203
|
}
|
|
9901
|
-
writeFileSync3(
|
|
10204
|
+
writeFileSync3(join6(workspace, "prompt.md"), `${assignment.prompt}
|
|
9902
10205
|
`);
|
|
9903
10206
|
if (!resume)
|
|
9904
10207
|
for (const skill of assignment.bundle.skills) {
|
|
9905
10208
|
for (const file of skill.files) {
|
|
9906
|
-
const target =
|
|
10209
|
+
const target = join6(workspace, "skills", skill.name, file.path);
|
|
9907
10210
|
mkdirSync4(dirname4(target), { recursive: true });
|
|
9908
10211
|
writeFileSync3(target, file.content);
|
|
9909
10212
|
}
|
|
9910
10213
|
}
|
|
9911
10214
|
if (!resume)
|
|
9912
10215
|
writeFileSync3(
|
|
9913
|
-
|
|
10216
|
+
join6(workspace, "repos.json"),
|
|
9914
10217
|
`${JSON.stringify(assignment.bundle.repos, null, 2)}
|
|
9915
10218
|
`
|
|
9916
10219
|
);
|
|
@@ -9944,7 +10247,7 @@ async function runDaemon(opts) {
|
|
|
9944
10247
|
);
|
|
9945
10248
|
const harnessInput = {
|
|
9946
10249
|
workspace,
|
|
9947
|
-
promptFile:
|
|
10250
|
+
promptFile: join6(workspace, "prompt.md"),
|
|
9948
10251
|
prompt: assignment.prompt,
|
|
9949
10252
|
model: assignment.run.model,
|
|
9950
10253
|
...resume ? { resumeSessionId: resume.provider_session_id } : {}
|
|
@@ -9965,13 +10268,15 @@ async function runDaemon(opts) {
|
|
|
9965
10268
|
...resume ? { resumedFromRunId: resume.previous_run_id } : {}
|
|
9966
10269
|
})
|
|
9967
10270
|
);
|
|
10271
|
+
const spawnEnv = buildSpawnEnv(process.env, {
|
|
10272
|
+
binDir: cli.binDir,
|
|
10273
|
+
apiKey: assignment.run_key,
|
|
10274
|
+
apiUrl: baseUrl
|
|
10275
|
+
});
|
|
10276
|
+
if (opts.harness === "codex") run2.codexHome = resolveCodexHome(spawnEnv, workspace);
|
|
9968
10277
|
const child = spawn2(invocation.file, invocation.args, {
|
|
9969
10278
|
cwd: workspace,
|
|
9970
|
-
env:
|
|
9971
|
-
binDir: cli.binDir,
|
|
9972
|
-
apiKey: assignment.run_key,
|
|
9973
|
-
apiUrl: baseUrl
|
|
9974
|
-
}),
|
|
10279
|
+
env: spawnEnv,
|
|
9975
10280
|
stdio: ["ignore", "pipe", "pipe"],
|
|
9976
10281
|
detached: true
|
|
9977
10282
|
});
|
|
@@ -9987,12 +10292,12 @@ async function runDaemon(opts) {
|
|
|
9987
10292
|
(event) => limiter.noteStreamEvent(event)
|
|
9988
10293
|
);
|
|
9989
10294
|
run2.renderer = renderer;
|
|
9990
|
-
const spoolPath =
|
|
10295
|
+
const spoolPath = join6(opts.configDir, "rawlogs", `${runId}.ndjson`);
|
|
9991
10296
|
mkdirSync4(dirname4(spoolPath), { recursive: true });
|
|
9992
10297
|
run2.rawSpoolPath = spoolPath;
|
|
9993
10298
|
run2.rawSpool = createWriteStream(spoolPath);
|
|
9994
10299
|
run2.rawUpload = (body) => client2.putRunLogRaw(runId, body);
|
|
9995
|
-
const decoder = new
|
|
10300
|
+
const decoder = new StringDecoder2("utf8");
|
|
9996
10301
|
run2.drain = () => {
|
|
9997
10302
|
const trailing = decoder.end();
|
|
9998
10303
|
if (trailing) renderer.write(trailing);
|
|
@@ -10004,7 +10309,7 @@ async function runDaemon(opts) {
|
|
|
10004
10309
|
});
|
|
10005
10310
|
} else if (opts.harness === "codex") {
|
|
10006
10311
|
const renderer = new CodexStreamRenderer((line) => run2.batcher.append(line));
|
|
10007
|
-
const decoder = new
|
|
10312
|
+
const decoder = new StringDecoder2("utf8");
|
|
10008
10313
|
run2.renderer = renderer;
|
|
10009
10314
|
run2.drain = () => {
|
|
10010
10315
|
const trailing = decoder.end();
|
|
@@ -10173,12 +10478,12 @@ function realpathOrNull(path2) {
|
|
|
10173
10478
|
}
|
|
10174
10479
|
}
|
|
10175
10480
|
function runGit(args, cwd, batcher) {
|
|
10176
|
-
return new Promise((
|
|
10481
|
+
return new Promise((resolve2) => {
|
|
10177
10482
|
const child = spawn2("git", args, { cwd, stdio: ["ignore", "pipe", "pipe"] });
|
|
10178
10483
|
child.stdout?.on("data", (data) => batcher.append(data.toString("utf8")));
|
|
10179
10484
|
child.stderr?.on("data", (data) => batcher.append(data.toString("utf8")));
|
|
10180
|
-
child.on("error", () =>
|
|
10181
|
-
child.on("exit", (code) =>
|
|
10485
|
+
child.on("error", () => resolve2(127));
|
|
10486
|
+
child.on("exit", (code) => resolve2(code ?? 1));
|
|
10182
10487
|
});
|
|
10183
10488
|
}
|
|
10184
10489
|
|
|
@@ -10252,13 +10557,13 @@ function harnessFlag(harness) {
|
|
|
10252
10557
|
// src/commands/runner-service.ts
|
|
10253
10558
|
import { execFile } from "node:child_process";
|
|
10254
10559
|
import { existsSync as existsSync7, mkdirSync as mkdirSync5, readFileSync as readFileSync10, rmSync as rmSync4, statSync as statSync6, writeFileSync as writeFileSync4 } from "node:fs";
|
|
10255
|
-
import { homedir as
|
|
10560
|
+
import { homedir as homedir3, hostname as hostname3, userInfo } from "node:os";
|
|
10256
10561
|
import { dirname as dirname6 } from "node:path";
|
|
10257
10562
|
import { promisify } from "node:util";
|
|
10258
10563
|
|
|
10259
10564
|
// src/daemon/service.ts
|
|
10260
10565
|
import { existsSync as existsSync6, statSync as statSync5 } from "node:fs";
|
|
10261
|
-
import { delimiter as delimiter2, dirname as dirname5, join as
|
|
10566
|
+
import { delimiter as delimiter2, dirname as dirname5, join as join7, sep as sep3 } from "node:path";
|
|
10262
10567
|
function defaultServiceManager(platform2 = process.platform) {
|
|
10263
10568
|
if (platform2 === "darwin") return "launchd";
|
|
10264
10569
|
if (platform2 === "linux") return "systemd";
|
|
@@ -10269,13 +10574,13 @@ function serviceLabel(name2, kind) {
|
|
|
10269
10574
|
}
|
|
10270
10575
|
function unitPath(name2, kind, home) {
|
|
10271
10576
|
const label = serviceLabel(name2, kind);
|
|
10272
|
-
return kind === "launchd" ?
|
|
10577
|
+
return kind === "launchd" ? join7(home, "Library", "LaunchAgents", `${label}.plist`) : join7(home, ".config", "systemd", "user", `${label}.service`);
|
|
10273
10578
|
}
|
|
10274
10579
|
function serviceLogPath(configDir, name2) {
|
|
10275
|
-
return
|
|
10580
|
+
return join7(configDir, "logs", `runner-${name2}.log`);
|
|
10276
10581
|
}
|
|
10277
10582
|
function managedBinary(prefix) {
|
|
10278
|
-
return
|
|
10583
|
+
return join7(prefix, "node_modules", ".bin", "tines");
|
|
10279
10584
|
}
|
|
10280
10585
|
function daemonArgs(input2) {
|
|
10281
10586
|
const args = [
|
|
@@ -10303,7 +10608,7 @@ function daemonArgs(input2) {
|
|
|
10303
10608
|
function findOnPath(name2, envPath) {
|
|
10304
10609
|
for (const dir of (envPath ?? "").split(delimiter2)) {
|
|
10305
10610
|
if (!dir) continue;
|
|
10306
|
-
const candidate =
|
|
10611
|
+
const candidate = join7(dir, name2);
|
|
10307
10612
|
try {
|
|
10308
10613
|
if (statSync5(candidate).isFile()) return candidate;
|
|
10309
10614
|
} catch {
|
|
@@ -10435,7 +10740,7 @@ function matchDaemonProcesses(psOutput, query2) {
|
|
|
10435
10740
|
else if (w.startsWith("--name=")) name2 = w.slice("--name=".length);
|
|
10436
10741
|
}
|
|
10437
10742
|
if ((name2 ?? query2.hostname) !== query2.name) continue;
|
|
10438
|
-
const root = query2.prefix.endsWith(
|
|
10743
|
+
const root = query2.prefix.endsWith(sep3) ? query2.prefix : query2.prefix + sep3;
|
|
10439
10744
|
matches.push({ pid, args, managed: args.includes(root) });
|
|
10440
10745
|
}
|
|
10441
10746
|
return matches;
|
|
@@ -10500,12 +10805,12 @@ async function waitForStart(logPath, offset, name2) {
|
|
|
10500
10805
|
const content = readFileSync10(logPath, "utf8").slice(offset);
|
|
10501
10806
|
if (pattern.test(content)) return true;
|
|
10502
10807
|
}
|
|
10503
|
-
await new Promise((
|
|
10808
|
+
await new Promise((resolve2) => setTimeout(resolve2, 500));
|
|
10504
10809
|
}
|
|
10505
10810
|
return false;
|
|
10506
10811
|
}
|
|
10507
10812
|
function serviceTarget(name2, kind) {
|
|
10508
|
-
return { kind, name: name2, unitPath: unitPath(name2, kind,
|
|
10813
|
+
return { kind, name: name2, unitPath: unitPath(name2, kind, homedir3()), uid: userInfo().uid };
|
|
10509
10814
|
}
|
|
10510
10815
|
function registerServiceCommands(runnerCmd) {
|
|
10511
10816
|
withCommon(
|
|
@@ -11138,6 +11443,16 @@ function register8(program3) {
|
|
|
11138
11443
|
console.log(` exact estimated USD: ${b.cost_usd_exact}`);
|
|
11139
11444
|
console.log(" Standard API list-price estimate; not an invoice or subscription usage.");
|
|
11140
11445
|
}
|
|
11446
|
+
const proof = pricing?.evidence?.request_context;
|
|
11447
|
+
if (proof?.status === "complete") {
|
|
11448
|
+
console.log(
|
|
11449
|
+
`request context: ${proof.request_count.toLocaleString()} verified \xB7 largest input ${proof.max_request_input_tokens.toLocaleString()} \xB7 Codex ${proof.harness_version} \xB7 ${proof.normalization}`
|
|
11450
|
+
);
|
|
11451
|
+
} else if (proof) {
|
|
11452
|
+
console.log(
|
|
11453
|
+
`request context: ${proof.status} (${proof.reason})${proof.harness_version ? ` \xB7 Codex ${proof.harness_version}` : ""} \xB7 ${proof.normalization}`
|
|
11454
|
+
);
|
|
11455
|
+
}
|
|
11141
11456
|
}
|
|
11142
11457
|
if (run2.provider_session_id) console.log(`provider session: ${run2.provider_session_id}`);
|
|
11143
11458
|
if (run2.provider_url) console.log(`provider console: ${run2.provider_url}`);
|
|
@@ -11551,12 +11866,12 @@ function register10(program3) {
|
|
|
11551
11866
|
const api = client(opts);
|
|
11552
11867
|
const overrides = {};
|
|
11553
11868
|
for (const spec of opts.state) {
|
|
11554
|
-
const
|
|
11555
|
-
if (
|
|
11869
|
+
const sep4 = spec.lastIndexOf("=");
|
|
11870
|
+
if (sep4 < 1 || sep4 === spec.length - 1) {
|
|
11556
11871
|
die(`--state must look like <workflow>/<state>=<n>, got "${spec}"`);
|
|
11557
11872
|
}
|
|
11558
|
-
const limit = Number.parseInt(spec.slice(
|
|
11559
|
-
const { state } = await resolveStateFlag(api, spec.slice(0,
|
|
11873
|
+
const limit = Number.parseInt(spec.slice(sep4 + 1), 10);
|
|
11874
|
+
const { state } = await resolveStateFlag(api, spec.slice(0, sep4));
|
|
11560
11875
|
overrides[state.id] = limit;
|
|
11561
11876
|
}
|
|
11562
11877
|
const settings = await api.updateSupervisorSettings({
|
|
@@ -12043,9 +12358,9 @@ async function resolveStateBases(states, library) {
|
|
|
12043
12358
|
}
|
|
12044
12359
|
}
|
|
12045
12360
|
function resolveBasePair(lib, pair, stateName) {
|
|
12046
|
-
const
|
|
12047
|
-
const workflowRef = pair.slice(0,
|
|
12048
|
-
const stateRef2 = pair.slice(
|
|
12361
|
+
const sep4 = pair.indexOf("/");
|
|
12362
|
+
const workflowRef = pair.slice(0, sep4).trim();
|
|
12363
|
+
const stateRef2 = pair.slice(sep4 + 1).trim();
|
|
12049
12364
|
const where = `state "${stateName}" inherits from "${pair}"`;
|
|
12050
12365
|
if (!workflowRef || !stateRef2) {
|
|
12051
12366
|
die(`${where}, which is not a <workflow>/<state> pair`);
|
|
@@ -12339,8 +12654,8 @@ function registerPackageCommands(workflows) {
|
|
|
12339
12654
|
else {
|
|
12340
12655
|
console.log(`installed workflow package (${receipt.id})`);
|
|
12341
12656
|
console.log(`plan: ${receipt.plan_digest}`);
|
|
12342
|
-
for (const
|
|
12343
|
-
console.log(` ${
|
|
12657
|
+
for (const object4 of receipt.objects)
|
|
12658
|
+
console.log(` ${object4.kind}: ${object4.name} \u2014 ${object4.href}`);
|
|
12344
12659
|
}
|
|
12345
12660
|
}
|
|
12346
12661
|
);
|