commonswarm 0.1.52 → 0.1.54
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/cswarm.cjs +492 -224
- package/package.json +1 -1
package/cswarm.cjs
CHANGED
|
@@ -13519,7 +13519,8 @@ __export(cli_exports, {
|
|
|
13519
13519
|
replyRefusalHint: () => replyRefusalHint,
|
|
13520
13520
|
resolveDetachedClaudeExecutable: () => resolveDetachedClaudeExecutable,
|
|
13521
13521
|
resolveDetachedCodexExecutable: () => resolveDetachedCodexExecutable,
|
|
13522
|
-
resolveTurnBudgetOrDefer: () => resolveTurnBudgetOrDefer
|
|
13522
|
+
resolveTurnBudgetOrDefer: () => resolveTurnBudgetOrDefer,
|
|
13523
|
+
usage: () => usage
|
|
13523
13524
|
});
|
|
13524
13525
|
module.exports = __toCommonJS(cli_exports);
|
|
13525
13526
|
var import_node_crypto22 = require("node:crypto");
|
|
@@ -13530,6 +13531,188 @@ var import_node_os10 = require("node:os");
|
|
|
13530
13531
|
var import_node_path21 = require("node:path");
|
|
13531
13532
|
var import_promises13 = require("node:readline/promises");
|
|
13532
13533
|
|
|
13534
|
+
// src/protocol/events.ts
|
|
13535
|
+
var SCHEMA_VERSION = 1;
|
|
13536
|
+
var EVENT_TYPES = [
|
|
13537
|
+
"TaskCreated",
|
|
13538
|
+
"LeaseAcquired",
|
|
13539
|
+
"LeaseRenewed",
|
|
13540
|
+
"LeaseHandedOff",
|
|
13541
|
+
"LeaseTakenOver",
|
|
13542
|
+
"TaskSubmitted",
|
|
13543
|
+
"TaskClosed",
|
|
13544
|
+
"TaskReopened",
|
|
13545
|
+
"CommandRejected"
|
|
13546
|
+
];
|
|
13547
|
+
|
|
13548
|
+
// src/protocol/reducer.ts
|
|
13549
|
+
function req(payload, keys, type, seq) {
|
|
13550
|
+
if (!payload || typeof payload !== "object") throw new StreamIntegrityError(`event "${type}" at seq ${seq} has a non-object payload`);
|
|
13551
|
+
for (const k of keys) {
|
|
13552
|
+
if (payload[k] === void 0) {
|
|
13553
|
+
throw new StreamIntegrityError(`event "${type}" at seq ${seq} is missing payload field "${String(k)}"`);
|
|
13554
|
+
}
|
|
13555
|
+
}
|
|
13556
|
+
return payload;
|
|
13557
|
+
}
|
|
13558
|
+
var UnknownEventTypeError = class extends Error {
|
|
13559
|
+
constructor(type, seq) {
|
|
13560
|
+
super(`unknown authoritative event type "${type}" at seq ${seq}; halting`);
|
|
13561
|
+
this.type = type;
|
|
13562
|
+
this.seq = seq;
|
|
13563
|
+
this.name = "UnknownEventTypeError";
|
|
13564
|
+
}
|
|
13565
|
+
type;
|
|
13566
|
+
seq;
|
|
13567
|
+
};
|
|
13568
|
+
var StreamIntegrityError = class extends Error {
|
|
13569
|
+
constructor(message) {
|
|
13570
|
+
super(message);
|
|
13571
|
+
this.name = "StreamIntegrityError";
|
|
13572
|
+
}
|
|
13573
|
+
};
|
|
13574
|
+
function reduceTask(prev, env) {
|
|
13575
|
+
if (!EVENT_TYPES.includes(env.type)) {
|
|
13576
|
+
throw new UnknownEventTypeError(env.type, env.seq);
|
|
13577
|
+
}
|
|
13578
|
+
if (env.schema_version !== SCHEMA_VERSION) {
|
|
13579
|
+
throw new StreamIntegrityError(`event "${env.type}" at seq ${env.seq} is schema v${env.schema_version}, expected v${SCHEMA_VERSION} (upcast before reduce)`);
|
|
13580
|
+
}
|
|
13581
|
+
if (env.type === "CommandRejected") {
|
|
13582
|
+
if (!prev) throw new StreamIntegrityError(`CommandRejected before task exists (seq ${env.seq})`);
|
|
13583
|
+
req(env.payload, ["task_id", "command", "reason", "detail"], env.type, env.seq);
|
|
13584
|
+
return prev;
|
|
13585
|
+
}
|
|
13586
|
+
if (env.type === "TaskCreated") {
|
|
13587
|
+
if (prev) throw new StreamIntegrityError(`TaskCreated for an already-existing task (seq ${env.seq})`);
|
|
13588
|
+
const p = req(env.payload, ["task_id", "slug"], env.type, env.seq);
|
|
13589
|
+
return {
|
|
13590
|
+
task_id: p.task_id,
|
|
13591
|
+
slug: p.slug,
|
|
13592
|
+
lifecycle: "open",
|
|
13593
|
+
version: 1,
|
|
13594
|
+
epoch: 0,
|
|
13595
|
+
owner: null,
|
|
13596
|
+
lease_expiry: null,
|
|
13597
|
+
submission: null,
|
|
13598
|
+
closed_disposition: null
|
|
13599
|
+
};
|
|
13600
|
+
}
|
|
13601
|
+
if (!prev) throw new StreamIntegrityError(`event "${env.type}" before TaskCreated (seq ${env.seq})`);
|
|
13602
|
+
const s = prev;
|
|
13603
|
+
function assertEpochIncrease(ep) {
|
|
13604
|
+
if (typeof ep !== "number" || ep <= s.epoch) {
|
|
13605
|
+
throw new StreamIntegrityError(`${env.type} at seq ${env.seq} has non-increasing epoch ${ep} (current ${s.epoch})`);
|
|
13606
|
+
}
|
|
13607
|
+
}
|
|
13608
|
+
const leaseLifecycle = s.submission ? "awaiting_review" : "active";
|
|
13609
|
+
switch (env.type) {
|
|
13610
|
+
case "LeaseAcquired": {
|
|
13611
|
+
const p = req(env.payload, ["task_id", "epoch", "owner", "lease_expiry"], env.type, env.seq);
|
|
13612
|
+
assertEpochIncrease(p.epoch);
|
|
13613
|
+
return { ...s, lifecycle: leaseLifecycle, epoch: p.epoch, owner: p.owner, lease_expiry: p.lease_expiry };
|
|
13614
|
+
}
|
|
13615
|
+
case "LeaseRenewed": {
|
|
13616
|
+
const p = req(env.payload, ["task_id", "epoch", "lease_expiry"], env.type, env.seq);
|
|
13617
|
+
if (p.epoch !== s.epoch) throw new StreamIntegrityError(`LeaseRenewed at seq ${env.seq} epoch ${p.epoch} != current ${s.epoch}`);
|
|
13618
|
+
return { ...s, lease_expiry: p.lease_expiry };
|
|
13619
|
+
}
|
|
13620
|
+
case "LeaseHandedOff": {
|
|
13621
|
+
const p = req(env.payload, ["task_id", "epoch", "from_owner", "to_owner", "lease_expiry"], env.type, env.seq);
|
|
13622
|
+
assertEpochIncrease(p.epoch);
|
|
13623
|
+
return { ...s, lifecycle: leaseLifecycle, epoch: p.epoch, owner: p.to_owner, lease_expiry: p.lease_expiry };
|
|
13624
|
+
}
|
|
13625
|
+
case "LeaseTakenOver": {
|
|
13626
|
+
const p = req(env.payload, ["task_id", "epoch", "owner", "lease_expiry", "grant_id"], env.type, env.seq);
|
|
13627
|
+
assertEpochIncrease(p.epoch);
|
|
13628
|
+
return { ...s, lifecycle: leaseLifecycle, epoch: p.epoch, owner: p.owner, lease_expiry: p.lease_expiry };
|
|
13629
|
+
}
|
|
13630
|
+
case "TaskSubmitted": {
|
|
13631
|
+
const p = req(env.payload, ["task_id", "epoch", "branch", "head_sha", "evidence_set"], env.type, env.seq);
|
|
13632
|
+
return {
|
|
13633
|
+
...s,
|
|
13634
|
+
lifecycle: "awaiting_review",
|
|
13635
|
+
submission: { epoch: p.epoch, branch: p.branch, head_sha: p.head_sha, evidence_set: [...p.evidence_set] }
|
|
13636
|
+
};
|
|
13637
|
+
}
|
|
13638
|
+
case "TaskClosed": {
|
|
13639
|
+
const p = req(env.payload, ["task_id", "epoch", "disposition", "grant_id"], env.type, env.seq);
|
|
13640
|
+
return { ...s, lifecycle: "done", closed_disposition: p.disposition };
|
|
13641
|
+
}
|
|
13642
|
+
case "TaskReopened": {
|
|
13643
|
+
const p = req(env.payload, ["task_id", "version"], env.type, env.seq);
|
|
13644
|
+
if (p.version <= s.version) throw new StreamIntegrityError(`TaskReopened at seq ${env.seq} version ${p.version} not > current ${s.version}`);
|
|
13645
|
+
return { ...s, lifecycle: "reopened", version: p.version, submission: null, owner: null, lease_expiry: null };
|
|
13646
|
+
}
|
|
13647
|
+
default: {
|
|
13648
|
+
throw new UnknownEventTypeError(env.type, env.seq);
|
|
13649
|
+
}
|
|
13650
|
+
}
|
|
13651
|
+
}
|
|
13652
|
+
|
|
13653
|
+
// src/protocol/idempotency.ts
|
|
13654
|
+
function canonicalJson(value) {
|
|
13655
|
+
return JSON.stringify(sortValue(value));
|
|
13656
|
+
}
|
|
13657
|
+
function sortValue(v) {
|
|
13658
|
+
if (Array.isArray(v)) return v.map(sortValue);
|
|
13659
|
+
if (v && typeof v === "object") {
|
|
13660
|
+
const out = {};
|
|
13661
|
+
for (const k of Object.keys(v).sort()) {
|
|
13662
|
+
out[k] = sortValue(v[k]);
|
|
13663
|
+
}
|
|
13664
|
+
return out;
|
|
13665
|
+
}
|
|
13666
|
+
return v;
|
|
13667
|
+
}
|
|
13668
|
+
|
|
13669
|
+
// src/protocol/upcasters.ts
|
|
13670
|
+
var registry = /* @__PURE__ */ new Map();
|
|
13671
|
+
function key(type, fromVersion) {
|
|
13672
|
+
return `${type}:${fromVersion}`;
|
|
13673
|
+
}
|
|
13674
|
+
function registerUpcaster(type, fromVersion, fn) {
|
|
13675
|
+
registry.set(key(type, fromVersion), fn);
|
|
13676
|
+
}
|
|
13677
|
+
var UpcastError = class extends Error {
|
|
13678
|
+
constructor(message) {
|
|
13679
|
+
super(message);
|
|
13680
|
+
this.name = "UpcastError";
|
|
13681
|
+
}
|
|
13682
|
+
};
|
|
13683
|
+
function upcastPayload(type, fromVersion, payload) {
|
|
13684
|
+
let v = fromVersion;
|
|
13685
|
+
let p = payload;
|
|
13686
|
+
if (v > SCHEMA_VERSION) {
|
|
13687
|
+
throw new UpcastError(`event "${type}" is schema v${v}, newer than supported v${SCHEMA_VERSION}; halting`);
|
|
13688
|
+
}
|
|
13689
|
+
while (v < SCHEMA_VERSION) {
|
|
13690
|
+
const fn = registry.get(key(type, v));
|
|
13691
|
+
if (!fn) throw new UpcastError(`no upcaster for "${type}" v${v}\u2192v${v + 1}`);
|
|
13692
|
+
p = fn(p);
|
|
13693
|
+
v += 1;
|
|
13694
|
+
}
|
|
13695
|
+
return { payload: p, schema_version: SCHEMA_VERSION };
|
|
13696
|
+
}
|
|
13697
|
+
function upcastEnvelope(raw) {
|
|
13698
|
+
const { payload, schema_version } = upcastPayload(raw.type, raw.schema_version, raw.payload);
|
|
13699
|
+
return { ...raw, payload, schema_version };
|
|
13700
|
+
}
|
|
13701
|
+
registerUpcaster("TaskCreated", 0, (p) => ({ task_id: p.id, slug: p.name }));
|
|
13702
|
+
|
|
13703
|
+
// src/protocol/workspace-commands.ts
|
|
13704
|
+
var INVITATION_MAX_TTL_MS = 7 * 24 * 60 * 60 * 1e3;
|
|
13705
|
+
var AGENT_TOKEN_DEFAULT_TTL_MS = 60 * 60 * 1e3;
|
|
13706
|
+
var AGENT_TOKEN_MAX_TTL_MS = 30 * 24 * 60 * 60 * 1e3;
|
|
13707
|
+
var RENEWAL_HORIZON_DEFAULT_MS = 30 * 24 * 60 * 60 * 1e3;
|
|
13708
|
+
var RENEWAL_HORIZON_MAX_MS = 90 * 24 * 60 * 60 * 1e3;
|
|
13709
|
+
|
|
13710
|
+
// src/protocol/brain-version-window.ts
|
|
13711
|
+
var BRAIN_FILE_PREFIX = "brain--";
|
|
13712
|
+
var BRAIN_FILE_SUFFIX = ".md";
|
|
13713
|
+
var BRAIN_TOPIC_MAX_LENGTH = 255 - BRAIN_FILE_PREFIX.length - BRAIN_FILE_SUFFIX.length;
|
|
13714
|
+
var FILE_VERSION_PRECONDITION_FAILED = "file_version_precondition_failed";
|
|
13715
|
+
|
|
13533
13716
|
// src/cloud/auth.ts
|
|
13534
13717
|
var import_node_crypto2 = require("node:crypto");
|
|
13535
13718
|
var import_node_http = require("node:http");
|
|
@@ -21959,189 +22142,6 @@ async function logout(target2, store2, scope = "local", options = {}) {
|
|
|
21959
22142
|
|
|
21960
22143
|
// src/cloud/command-client.ts
|
|
21961
22144
|
var import_node_crypto3 = require("node:crypto");
|
|
21962
|
-
|
|
21963
|
-
// src/protocol/events.ts
|
|
21964
|
-
var SCHEMA_VERSION = 1;
|
|
21965
|
-
var EVENT_TYPES = [
|
|
21966
|
-
"TaskCreated",
|
|
21967
|
-
"LeaseAcquired",
|
|
21968
|
-
"LeaseRenewed",
|
|
21969
|
-
"LeaseHandedOff",
|
|
21970
|
-
"LeaseTakenOver",
|
|
21971
|
-
"TaskSubmitted",
|
|
21972
|
-
"TaskClosed",
|
|
21973
|
-
"TaskReopened",
|
|
21974
|
-
"CommandRejected"
|
|
21975
|
-
];
|
|
21976
|
-
|
|
21977
|
-
// src/protocol/reducer.ts
|
|
21978
|
-
function req(payload, keys, type, seq) {
|
|
21979
|
-
if (!payload || typeof payload !== "object") throw new StreamIntegrityError(`event "${type}" at seq ${seq} has a non-object payload`);
|
|
21980
|
-
for (const k of keys) {
|
|
21981
|
-
if (payload[k] === void 0) {
|
|
21982
|
-
throw new StreamIntegrityError(`event "${type}" at seq ${seq} is missing payload field "${String(k)}"`);
|
|
21983
|
-
}
|
|
21984
|
-
}
|
|
21985
|
-
return payload;
|
|
21986
|
-
}
|
|
21987
|
-
var UnknownEventTypeError = class extends Error {
|
|
21988
|
-
constructor(type, seq) {
|
|
21989
|
-
super(`unknown authoritative event type "${type}" at seq ${seq}; halting`);
|
|
21990
|
-
this.type = type;
|
|
21991
|
-
this.seq = seq;
|
|
21992
|
-
this.name = "UnknownEventTypeError";
|
|
21993
|
-
}
|
|
21994
|
-
type;
|
|
21995
|
-
seq;
|
|
21996
|
-
};
|
|
21997
|
-
var StreamIntegrityError = class extends Error {
|
|
21998
|
-
constructor(message) {
|
|
21999
|
-
super(message);
|
|
22000
|
-
this.name = "StreamIntegrityError";
|
|
22001
|
-
}
|
|
22002
|
-
};
|
|
22003
|
-
function reduceTask(prev, env) {
|
|
22004
|
-
if (!EVENT_TYPES.includes(env.type)) {
|
|
22005
|
-
throw new UnknownEventTypeError(env.type, env.seq);
|
|
22006
|
-
}
|
|
22007
|
-
if (env.schema_version !== SCHEMA_VERSION) {
|
|
22008
|
-
throw new StreamIntegrityError(`event "${env.type}" at seq ${env.seq} is schema v${env.schema_version}, expected v${SCHEMA_VERSION} (upcast before reduce)`);
|
|
22009
|
-
}
|
|
22010
|
-
if (env.type === "CommandRejected") {
|
|
22011
|
-
if (!prev) throw new StreamIntegrityError(`CommandRejected before task exists (seq ${env.seq})`);
|
|
22012
|
-
req(env.payload, ["task_id", "command", "reason", "detail"], env.type, env.seq);
|
|
22013
|
-
return prev;
|
|
22014
|
-
}
|
|
22015
|
-
if (env.type === "TaskCreated") {
|
|
22016
|
-
if (prev) throw new StreamIntegrityError(`TaskCreated for an already-existing task (seq ${env.seq})`);
|
|
22017
|
-
const p = req(env.payload, ["task_id", "slug"], env.type, env.seq);
|
|
22018
|
-
return {
|
|
22019
|
-
task_id: p.task_id,
|
|
22020
|
-
slug: p.slug,
|
|
22021
|
-
lifecycle: "open",
|
|
22022
|
-
version: 1,
|
|
22023
|
-
epoch: 0,
|
|
22024
|
-
owner: null,
|
|
22025
|
-
lease_expiry: null,
|
|
22026
|
-
submission: null,
|
|
22027
|
-
closed_disposition: null
|
|
22028
|
-
};
|
|
22029
|
-
}
|
|
22030
|
-
if (!prev) throw new StreamIntegrityError(`event "${env.type}" before TaskCreated (seq ${env.seq})`);
|
|
22031
|
-
const s = prev;
|
|
22032
|
-
function assertEpochIncrease(ep) {
|
|
22033
|
-
if (typeof ep !== "number" || ep <= s.epoch) {
|
|
22034
|
-
throw new StreamIntegrityError(`${env.type} at seq ${env.seq} has non-increasing epoch ${ep} (current ${s.epoch})`);
|
|
22035
|
-
}
|
|
22036
|
-
}
|
|
22037
|
-
const leaseLifecycle = s.submission ? "awaiting_review" : "active";
|
|
22038
|
-
switch (env.type) {
|
|
22039
|
-
case "LeaseAcquired": {
|
|
22040
|
-
const p = req(env.payload, ["task_id", "epoch", "owner", "lease_expiry"], env.type, env.seq);
|
|
22041
|
-
assertEpochIncrease(p.epoch);
|
|
22042
|
-
return { ...s, lifecycle: leaseLifecycle, epoch: p.epoch, owner: p.owner, lease_expiry: p.lease_expiry };
|
|
22043
|
-
}
|
|
22044
|
-
case "LeaseRenewed": {
|
|
22045
|
-
const p = req(env.payload, ["task_id", "epoch", "lease_expiry"], env.type, env.seq);
|
|
22046
|
-
if (p.epoch !== s.epoch) throw new StreamIntegrityError(`LeaseRenewed at seq ${env.seq} epoch ${p.epoch} != current ${s.epoch}`);
|
|
22047
|
-
return { ...s, lease_expiry: p.lease_expiry };
|
|
22048
|
-
}
|
|
22049
|
-
case "LeaseHandedOff": {
|
|
22050
|
-
const p = req(env.payload, ["task_id", "epoch", "from_owner", "to_owner", "lease_expiry"], env.type, env.seq);
|
|
22051
|
-
assertEpochIncrease(p.epoch);
|
|
22052
|
-
return { ...s, lifecycle: leaseLifecycle, epoch: p.epoch, owner: p.to_owner, lease_expiry: p.lease_expiry };
|
|
22053
|
-
}
|
|
22054
|
-
case "LeaseTakenOver": {
|
|
22055
|
-
const p = req(env.payload, ["task_id", "epoch", "owner", "lease_expiry", "grant_id"], env.type, env.seq);
|
|
22056
|
-
assertEpochIncrease(p.epoch);
|
|
22057
|
-
return { ...s, lifecycle: leaseLifecycle, epoch: p.epoch, owner: p.owner, lease_expiry: p.lease_expiry };
|
|
22058
|
-
}
|
|
22059
|
-
case "TaskSubmitted": {
|
|
22060
|
-
const p = req(env.payload, ["task_id", "epoch", "branch", "head_sha", "evidence_set"], env.type, env.seq);
|
|
22061
|
-
return {
|
|
22062
|
-
...s,
|
|
22063
|
-
lifecycle: "awaiting_review",
|
|
22064
|
-
submission: { epoch: p.epoch, branch: p.branch, head_sha: p.head_sha, evidence_set: [...p.evidence_set] }
|
|
22065
|
-
};
|
|
22066
|
-
}
|
|
22067
|
-
case "TaskClosed": {
|
|
22068
|
-
const p = req(env.payload, ["task_id", "epoch", "disposition", "grant_id"], env.type, env.seq);
|
|
22069
|
-
return { ...s, lifecycle: "done", closed_disposition: p.disposition };
|
|
22070
|
-
}
|
|
22071
|
-
case "TaskReopened": {
|
|
22072
|
-
const p = req(env.payload, ["task_id", "version"], env.type, env.seq);
|
|
22073
|
-
if (p.version <= s.version) throw new StreamIntegrityError(`TaskReopened at seq ${env.seq} version ${p.version} not > current ${s.version}`);
|
|
22074
|
-
return { ...s, lifecycle: "reopened", version: p.version, submission: null, owner: null, lease_expiry: null };
|
|
22075
|
-
}
|
|
22076
|
-
default: {
|
|
22077
|
-
throw new UnknownEventTypeError(env.type, env.seq);
|
|
22078
|
-
}
|
|
22079
|
-
}
|
|
22080
|
-
}
|
|
22081
|
-
|
|
22082
|
-
// src/protocol/idempotency.ts
|
|
22083
|
-
function canonicalJson(value) {
|
|
22084
|
-
return JSON.stringify(sortValue(value));
|
|
22085
|
-
}
|
|
22086
|
-
function sortValue(v) {
|
|
22087
|
-
if (Array.isArray(v)) return v.map(sortValue);
|
|
22088
|
-
if (v && typeof v === "object") {
|
|
22089
|
-
const out = {};
|
|
22090
|
-
for (const k of Object.keys(v).sort()) {
|
|
22091
|
-
out[k] = sortValue(v[k]);
|
|
22092
|
-
}
|
|
22093
|
-
return out;
|
|
22094
|
-
}
|
|
22095
|
-
return v;
|
|
22096
|
-
}
|
|
22097
|
-
|
|
22098
|
-
// src/protocol/upcasters.ts
|
|
22099
|
-
var registry = /* @__PURE__ */ new Map();
|
|
22100
|
-
function key(type, fromVersion) {
|
|
22101
|
-
return `${type}:${fromVersion}`;
|
|
22102
|
-
}
|
|
22103
|
-
function registerUpcaster(type, fromVersion, fn) {
|
|
22104
|
-
registry.set(key(type, fromVersion), fn);
|
|
22105
|
-
}
|
|
22106
|
-
var UpcastError = class extends Error {
|
|
22107
|
-
constructor(message) {
|
|
22108
|
-
super(message);
|
|
22109
|
-
this.name = "UpcastError";
|
|
22110
|
-
}
|
|
22111
|
-
};
|
|
22112
|
-
function upcastPayload(type, fromVersion, payload) {
|
|
22113
|
-
let v = fromVersion;
|
|
22114
|
-
let p = payload;
|
|
22115
|
-
if (v > SCHEMA_VERSION) {
|
|
22116
|
-
throw new UpcastError(`event "${type}" is schema v${v}, newer than supported v${SCHEMA_VERSION}; halting`);
|
|
22117
|
-
}
|
|
22118
|
-
while (v < SCHEMA_VERSION) {
|
|
22119
|
-
const fn = registry.get(key(type, v));
|
|
22120
|
-
if (!fn) throw new UpcastError(`no upcaster for "${type}" v${v}\u2192v${v + 1}`);
|
|
22121
|
-
p = fn(p);
|
|
22122
|
-
v += 1;
|
|
22123
|
-
}
|
|
22124
|
-
return { payload: p, schema_version: SCHEMA_VERSION };
|
|
22125
|
-
}
|
|
22126
|
-
function upcastEnvelope(raw) {
|
|
22127
|
-
const { payload, schema_version } = upcastPayload(raw.type, raw.schema_version, raw.payload);
|
|
22128
|
-
return { ...raw, payload, schema_version };
|
|
22129
|
-
}
|
|
22130
|
-
registerUpcaster("TaskCreated", 0, (p) => ({ task_id: p.id, slug: p.name }));
|
|
22131
|
-
|
|
22132
|
-
// src/protocol/workspace-commands.ts
|
|
22133
|
-
var INVITATION_MAX_TTL_MS = 7 * 24 * 60 * 60 * 1e3;
|
|
22134
|
-
var AGENT_TOKEN_DEFAULT_TTL_MS = 60 * 60 * 1e3;
|
|
22135
|
-
var AGENT_TOKEN_MAX_TTL_MS = 30 * 24 * 60 * 60 * 1e3;
|
|
22136
|
-
var RENEWAL_HORIZON_DEFAULT_MS = 30 * 24 * 60 * 60 * 1e3;
|
|
22137
|
-
var RENEWAL_HORIZON_MAX_MS = 90 * 24 * 60 * 60 * 1e3;
|
|
22138
|
-
|
|
22139
|
-
// src/protocol/brain-version-window.ts
|
|
22140
|
-
var BRAIN_FILE_PREFIX = "brain--";
|
|
22141
|
-
var BRAIN_FILE_SUFFIX = ".md";
|
|
22142
|
-
var BRAIN_TOPIC_MAX_LENGTH = 255 - BRAIN_FILE_PREFIX.length - BRAIN_FILE_SUFFIX.length;
|
|
22143
|
-
|
|
22144
|
-
// src/cloud/command-client.ts
|
|
22145
22145
|
var AGENT_TOKEN_RE = /^swm_agt_[A-Za-z0-9_-]{43}$/;
|
|
22146
22146
|
var INVITATION_TOKEN_RE = /^swm_inv_[A-Za-z0-9_-]{43}$/;
|
|
22147
22147
|
var CAPABILITY_TOKEN_RE = /^swm_cap_[A-Za-z0-9_-]{43}$/;
|
|
@@ -22978,13 +22978,18 @@ async function sendFileCommand(options, command2) {
|
|
|
22978
22978
|
return body;
|
|
22979
22979
|
}
|
|
22980
22980
|
function fileVersionCreate(options, input) {
|
|
22981
|
+
const ifVersion = input.ifVersion ?? null;
|
|
22981
22982
|
return sendFileCommand(options, {
|
|
22982
22983
|
kind: "file_version_create",
|
|
22983
22984
|
file_id: input.fileId,
|
|
22984
22985
|
version_id: input.versionId,
|
|
22985
22986
|
name: input.name,
|
|
22986
22987
|
declared_size_bytes: input.declaredSizeBytes,
|
|
22987
|
-
content_type: input.contentType
|
|
22988
|
+
content_type: input.contentType,
|
|
22989
|
+
/* The server validates an exact key set, so the key is sent only when a
|
|
22990
|
+
* precondition was asked for. An unconditional write is byte-identical to
|
|
22991
|
+
* what every earlier client sent. */
|
|
22992
|
+
...ifVersion === null ? {} : { if_version: ifVersion }
|
|
22988
22993
|
});
|
|
22989
22994
|
}
|
|
22990
22995
|
function fileVersionCommit(options, input) {
|
|
@@ -34514,6 +34519,25 @@ async function resolveBudgetAndPrompt(session, prompt, budget) {
|
|
|
34514
34519
|
const timeoutMs = typeof budget === "number" ? budget : await budget();
|
|
34515
34520
|
return await session.prompt(prompt, { timeoutMs });
|
|
34516
34521
|
}
|
|
34522
|
+
var LISTENER_DELIVERY_MAX_LEASE_MS = 9e5;
|
|
34523
|
+
var LISTENER_DELIVERY_HOLD_RELEASE_REASONS = [
|
|
34524
|
+
"hold_budget",
|
|
34525
|
+
"lease_budget"
|
|
34526
|
+
];
|
|
34527
|
+
var LISTENER_DELIVERY_HOLD_RELEASE_CLAUSES = {
|
|
34528
|
+
hold_budget: "it used the turn budget for one delivery",
|
|
34529
|
+
lease_budget: "what was left of its lease could not cover the next step"
|
|
34530
|
+
};
|
|
34531
|
+
var LISTENER_DELIVERY_HOLD_RELEASE_REMEDIES = {
|
|
34532
|
+
hold_budget: `a larger --turn-budget gives one delivery more of the seat. Past the ${LISTENER_DELIVERY_MAX_LEASE_MS / 6e4} minutes the service leases a delivery for it stops helping, because the turn then outlives its lease and the reply can no longer be acknowledged. The bound is read when the listener starts, so stop this listener and start it again to change it`,
|
|
34533
|
+
/* NOT a cap: nothing clamps the turn budget to the lease, and leaseSpent
|
|
34534
|
+
refuses to START a phase rather than interrupting one, so a 60m budget
|
|
34535
|
+
really does hold the worker for 60m. The sentence says raising past the
|
|
34536
|
+
lease stops helping, and why, which is what the code supports. An earlier
|
|
34537
|
+
version read "up to the 15 minutes the service leases it for", which a
|
|
34538
|
+
review arm read as a cap the code does not enforce. */
|
|
34539
|
+
lease_budget: "nothing needs raising: the row comes back under a new lease of full length, so the next attempt starts with the room this one ran out of. If it keeps being handed back, the service stops retrying it in the end, so look at the delivery rather than at the bound"
|
|
34540
|
+
};
|
|
34517
34541
|
|
|
34518
34542
|
// src/listener/engine.ts
|
|
34519
34543
|
var UUID_RE14 = /^[0-9a-f]{8}-[0-9a-f]{4}-[1-8][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i;
|
|
@@ -36735,11 +36759,11 @@ function pendingMainEntry(signal, principalId, provenance, now, options = {}) {
|
|
|
36735
36759
|
// src/listener/runtime.ts
|
|
36736
36760
|
var LISTENER_PAGE_LIMIT = 100;
|
|
36737
36761
|
var LISTENER_IDLE_POLL_MS = 2e3;
|
|
36738
|
-
var LISTENER_DELIVERY_MAX_LEASE_MS = 9e5;
|
|
36739
36762
|
var LISTENER_DELIVERY_SAFETY_MARGIN_MS = 3e4;
|
|
36740
36763
|
var LISTENER_ACK_ONLY_MINIMUM_MS = DELIVERY_REQUEST_TIMEOUT_MS + LISTENER_DELIVERY_SAFETY_MARGIN_MS;
|
|
36741
36764
|
var LISTENER_REPLY_ONLY_MINIMUM_MS = SIGNAL_REQUEST_TIMEOUT_MS + LISTENER_ACK_ONLY_MINIMUM_MS;
|
|
36742
36765
|
var LISTENER_PROMPT_START_MINIMUM_MS = SIGNAL_READ_TIMEOUT_MS + ACP_DEFAULT_REQUEST_TIMEOUT_MS + LISTENER_REPLY_ONLY_MINIMUM_MS;
|
|
36766
|
+
var LISTENER_DELIVERY_HOLD_BUDGET_MS = LISTENER_PROMPT_TIMEOUT_MS;
|
|
36743
36767
|
var LISTENER_DELIVERY_RETRY_INITIAL_MS = 500;
|
|
36744
36768
|
var LISTENER_DELIVERY_RETRY_MAX_MS = 3e4;
|
|
36745
36769
|
var LISTENER_HOST_PORTS_PROBE_MS = 6e4;
|
|
@@ -37012,6 +37036,7 @@ async function runListenerRuntime(options) {
|
|
|
37012
37036
|
const pollMs = options.pollMs ?? LISTENER_IDLE_POLL_MS;
|
|
37013
37037
|
const routeMode = options.routeMode ?? "worker";
|
|
37014
37038
|
const deferOverChars = options.deferOverChars ?? null;
|
|
37039
|
+
const deliveryHoldBudgetMs = options.deliveryHoldBudgetMs ?? LISTENER_DELIVERY_HOLD_BUDGET_MS;
|
|
37015
37040
|
const abort = options.signal;
|
|
37016
37041
|
const hasInstanceId = options.listenerInstanceId !== void 0;
|
|
37017
37042
|
const hasJournal = options.deliveryJournal !== void 0;
|
|
@@ -37033,6 +37058,12 @@ async function runListenerRuntime(options) {
|
|
|
37033
37058
|
new Error("an injected delivery client requires durable delivery configuration")
|
|
37034
37059
|
);
|
|
37035
37060
|
}
|
|
37061
|
+
if (!Number.isSafeInteger(deliveryHoldBudgetMs) || deliveryHoldBudgetMs <= 0) {
|
|
37062
|
+
return await closeBeforeStart(
|
|
37063
|
+
options.model,
|
|
37064
|
+
new Error("listener delivery hold budget must be a positive number of milliseconds")
|
|
37065
|
+
);
|
|
37066
|
+
}
|
|
37036
37067
|
try {
|
|
37037
37068
|
decideListenerRoute(routeMode, deferOverChars, 0);
|
|
37038
37069
|
if (routeMode !== "worker" && options.pendingMainQueue === void 0) {
|
|
@@ -37626,6 +37657,8 @@ async function runListenerRuntime(options) {
|
|
|
37626
37657
|
stop = { reason: "cancelled" };
|
|
37627
37658
|
break;
|
|
37628
37659
|
}
|
|
37660
|
+
const claimedAtMs = Date.parse(active.claimCreatedAt);
|
|
37661
|
+
const holdStartedAtMs = Number.isFinite(claimedAtMs) ? Math.min(claimedAtMs, now()) : now();
|
|
37629
37662
|
const signal = authoritativeSignal(claimed);
|
|
37630
37663
|
let terminal = null;
|
|
37631
37664
|
try {
|
|
@@ -37692,22 +37725,18 @@ async function runListenerRuntime(options) {
|
|
|
37692
37725
|
throw new Error("stored listener effect does not match the authoritative delivery");
|
|
37693
37726
|
}
|
|
37694
37727
|
const requiredBudget = effectPhaseBudget(before);
|
|
37695
|
-
|
|
37696
|
-
|
|
37697
|
-
|
|
37698
|
-
|
|
37699
|
-
|
|
37700
|
-
|
|
37701
|
-
|
|
37702
|
-
|
|
37703
|
-
|
|
37704
|
-
|
|
37705
|
-
|
|
37706
|
-
}
|
|
37707
|
-
if (now() >= leasedUntilMs + LISTENER_DELIVERY_SAFETY_MARGIN_MS) {
|
|
37708
|
-
await journal.clearActive(eventTime(now));
|
|
37709
|
-
after = null;
|
|
37710
|
-
}
|
|
37728
|
+
const holdSpent = processAttempt > 0 && now() - holdStartedAtMs >= deliveryHoldBudgetMs;
|
|
37729
|
+
const leaseSpent = leasedUntilMs <= now() + requiredBudget;
|
|
37730
|
+
if (holdSpent || leaseSpent) {
|
|
37731
|
+
await journal.clearActive(eventTime(now));
|
|
37732
|
+
after = null;
|
|
37733
|
+
options.onEvent?.({
|
|
37734
|
+
type: "delivery_hold_released",
|
|
37735
|
+
signalId: signal.id,
|
|
37736
|
+
reason: holdSpent ? "hold_budget" : "lease_budget",
|
|
37737
|
+
heldMs: Math.max(0, now() - holdStartedAtMs),
|
|
37738
|
+
ts: eventTime(now)
|
|
37739
|
+
});
|
|
37711
37740
|
break;
|
|
37712
37741
|
}
|
|
37713
37742
|
const processed = await engine.process(signal);
|
|
@@ -38206,6 +38235,10 @@ var STATUS_ALLOWED_KEYS = /* @__PURE__ */ new Set([
|
|
|
38206
38235
|
"lastAckOutcome",
|
|
38207
38236
|
"consecutiveAckFailureCount",
|
|
38208
38237
|
"lastAckSignalId",
|
|
38238
|
+
"currentDeliverySignalId",
|
|
38239
|
+
"currentDeliverySince",
|
|
38240
|
+
"heldBackDeliveries",
|
|
38241
|
+
"pendingDeliveryCountAt",
|
|
38209
38242
|
"routeMode",
|
|
38210
38243
|
"deferOverChars",
|
|
38211
38244
|
"pendingForMainCount",
|
|
@@ -38250,6 +38283,30 @@ var STATUS_DELIVERY_KEYS = [
|
|
|
38250
38283
|
"consecutiveAckFailureCount"
|
|
38251
38284
|
];
|
|
38252
38285
|
var deliveryOutcomes = DELIVERY_ACK_OUTCOMES;
|
|
38286
|
+
var LISTENER_HELD_BACK_MAX = 16;
|
|
38287
|
+
function parseHeldBackDeliveries(value) {
|
|
38288
|
+
if (!Array.isArray(value) || value.length > LISTENER_HELD_BACK_MAX) return null;
|
|
38289
|
+
const parsed = [];
|
|
38290
|
+
for (const item of value) {
|
|
38291
|
+
if (!item || typeof item !== "object" || Array.isArray(item)) return null;
|
|
38292
|
+
const entry = item;
|
|
38293
|
+
for (const key2 of Object.keys(entry)) {
|
|
38294
|
+
if (key2 !== "signalId" && key2 !== "at" && key2 !== "reason") return null;
|
|
38295
|
+
}
|
|
38296
|
+
if (typeof entry.signalId !== "string" || !UUID_RE18.test(entry.signalId) || typeof entry.at !== "string" || !Number.isFinite(Date.parse(entry.at)) || typeof entry.reason !== "string" || !LISTENER_DELIVERY_HOLD_RELEASE_REASONS.includes(
|
|
38297
|
+
entry.reason
|
|
38298
|
+
)) {
|
|
38299
|
+
return null;
|
|
38300
|
+
}
|
|
38301
|
+
if (parsed.some((seen) => seen.signalId === entry.signalId)) return null;
|
|
38302
|
+
parsed.push({
|
|
38303
|
+
signalId: entry.signalId,
|
|
38304
|
+
at: entry.at,
|
|
38305
|
+
reason: entry.reason
|
|
38306
|
+
});
|
|
38307
|
+
}
|
|
38308
|
+
return parsed;
|
|
38309
|
+
}
|
|
38253
38310
|
function parseStatus(raw, rejectUnknownKeys = false) {
|
|
38254
38311
|
let value;
|
|
38255
38312
|
try {
|
|
@@ -38273,7 +38330,8 @@ function parseStatus(raw, rejectUnknownKeys = false) {
|
|
|
38273
38330
|
const nullableCount = (candidate) => candidate === null || typeof candidate === "number" && Number.isSafeInteger(candidate) && candidate >= 0;
|
|
38274
38331
|
const nullableTimestamp3 = (candidate) => candidate === null || typeof candidate === "string" && Number.isFinite(Date.parse(candidate));
|
|
38275
38332
|
const readHealth = row.readHealth === void 0 ? void 0 : parseListenerReadHealth(row.readHealth, rejectUnknownKeys);
|
|
38276
|
-
|
|
38333
|
+
const heldBackDeliveries = row.heldBackDeliveries === void 0 ? void 0 : parseHeldBackDeliveries(row.heldBackDeliveries);
|
|
38334
|
+
if (row.version !== 1 || typeof row.instanceId !== "string" || !UUID_RE18.test(row.instanceId) || row.provider !== "grok" && row.provider !== "opencode" && row.provider !== "claude" && row.provider !== "codex" || typeof row.profileId !== "string" || typeof row.workspaceId !== "string" || !UUID_RE18.test(row.workspaceId) || typeof row.principalId !== "string" || !UUID_RE18.test(row.principalId) || !Number.isSafeInteger(row.pid) || row.pid < 1 || typeof row.state !== "string" || !["starting", "ready", "stopping", "stopped", "failed"].includes(row.state) || typeof row.startedAt !== "string" || !Number.isFinite(Date.parse(row.startedAt)) || !(row.readyAt === null || typeof row.readyAt === "string" && Number.isFinite(Date.parse(row.readyAt))) || typeof row.updatedAt !== "string" || !Number.isFinite(Date.parse(row.updatedAt)) || !(row.stoppedAt === null || typeof row.stoppedAt === "string" && Number.isFinite(Date.parse(row.stoppedAt))) || !nullableUuid3(row.lastSignalId) || !(row.lastErrorCode === null || typeof row.lastErrorCode === "string" && /^[a-z0-9_-]{1,96}$/.test(row.lastErrorCode)) || !(row.lastErrorDetail === void 0 || row.lastErrorDetail === null || typeof row.lastErrorDetail === "string" && row.lastErrorDetail.length > 0 && row.lastErrorDetail.length <= 2048 && !/swm_(?:agt|inv|cap)_/i.test(row.lastErrorDetail)) || !(row.lastErrorReasonCode === void 0 || row.lastErrorReasonCode === null || typeof row.lastErrorReasonCode === "string" && /^[a-z0-9_-]{1,96}$/.test(row.lastErrorReasonCode)) || !(row.providerExecutable === void 0 || row.providerExecutable === null || typeof row.providerExecutable === "string" && (0, import_node_path16.isAbsolute)(row.providerExecutable)) || !(row.providerVersion === void 0 || row.providerVersion === null || typeof row.providerVersion === "string" && SEMVER_RE2.test(row.providerVersion)) || !(row.providerLastMeasuredVersion === void 0 || row.providerLastMeasuredVersion === null || typeof row.providerLastMeasuredVersion === "string" && SEMVER_RE2.test(row.providerLastMeasuredVersion)) || !(row.providerBundledAgentSdkVersion === void 0 || row.providerBundledAgentSdkVersion === null || typeof row.providerBundledAgentSdkVersion === "string" && SEMVER_RE2.test(row.providerBundledAgentSdkVersion)) || !(row.providerBundledClaudeCodeVersion === void 0 || row.providerBundledClaudeCodeVersion === null || typeof row.providerBundledClaudeCodeVersion === "string" && SEMVER_RE2.test(row.providerBundledClaudeCodeVersion)) || !(row.providerMinimumRequiredVersion === void 0 || row.providerMinimumRequiredVersion === null || typeof row.providerMinimumRequiredVersion === "string" && SEMVER_RE2.test(row.providerMinimumRequiredVersion)) || !(row.cswarmVersion === void 0 || row.cswarmVersion === null || typeof row.cswarmVersion === "string" && SEMVER_RE2.test(row.cswarmVersion)) || (row.providerVersion === null || row.providerVersion === void 0) !== (row.providerLastMeasuredVersion === null || row.providerLastMeasuredVersion === void 0) || !(row.lastWorkerStderrTail === void 0 || row.lastWorkerStderrTail === null || typeof row.lastWorkerStderrTail === "string" && row.lastWorkerStderrTail.length > 0 && row.lastWorkerStderrTail.length <= 2048 && !/swm_(?:agt|inv|cap)_/i.test(row.lastWorkerStderrTail)) || typeof row.logPath !== "string" || !(0, import_node_path16.isAbsolute)(row.logPath) || !(row.deliveryMode === void 0 || row.deliveryMode === null || typeof row.deliveryMode === "string" && STATUS_DELIVERY_MODES.has(row.deliveryMode)) || !(row.pendingDeliveryCount === void 0 || nullableCount(row.pendingDeliveryCount)) || !(row.lastTerminalDeliveryFailureCount === void 0 || nullableCount(row.lastTerminalDeliveryFailureCount)) || !(row.lastTerminalDeliveryFailureAt === void 0 || nullableTimestamp3(row.lastTerminalDeliveryFailureAt)) || !(row.lastClaimAt === void 0 || nullableTimestamp3(row.lastClaimAt)) || !(row.lastAckAt === void 0 || nullableTimestamp3(row.lastAckAt)) || !(row.lastAckOutcome === void 0 || row.lastAckOutcome === null || typeof row.lastAckOutcome === "string" && deliveryOutcomes.has(row.lastAckOutcome)) || !(row.consecutiveAckFailureCount === void 0 || nullableCount(row.consecutiveAckFailureCount)) || !(row.lastAckSignalId === void 0 || row.lastAckSignalId === null || typeof row.lastAckSignalId === "string" && UUID_RE18.test(row.lastAckSignalId)) || !(row.currentDeliverySignalId === void 0 || row.currentDeliverySignalId === null || typeof row.currentDeliverySignalId === "string" && UUID_RE18.test(row.currentDeliverySignalId)) || !(row.currentDeliverySince === void 0 || nullableTimestamp3(row.currentDeliverySince)) || heldBackDeliveries === null || !(row.pendingDeliveryCountAt === void 0 || nullableTimestamp3(row.pendingDeliveryCountAt)) || !(row.routeMode === void 0 || row.routeMode === "worker" || row.routeMode === "main" || row.routeMode === "split") || !(row.deferOverChars === void 0 || row.deferOverChars === null || typeof row.deferOverChars === "number" && Number.isSafeInteger(row.deferOverChars) && row.deferOverChars >= 1 && row.deferOverChars <= 1e4) || !(row.pendingForMainCount === void 0 || typeof row.pendingForMainCount === "number" && Number.isSafeInteger(row.pendingForMainCount) && row.pendingForMainCount >= 0) || !(row.droppedForMainCount === void 0 || typeof row.droppedForMainCount === "number" && Number.isSafeInteger(row.droppedForMainCount) && row.droppedForMainCount >= 0) || readHealth === null || !(row.connectionsOpened === void 0 || typeof row.connectionsOpened === "number" && Number.isSafeInteger(row.connectionsOpened) && row.connectionsOpened >= 0) || !(row.connectionReuseRatio === void 0 || typeof row.connectionReuseRatio === "number" && Number.isFinite(row.connectionReuseRatio) && row.connectionReuseRatio >= 0) || !(row.activityPublishFailures === void 0 || typeof row.activityPublishFailures === "number" && Number.isSafeInteger(row.activityPublishFailures) && row.activityPublishFailures >= 0) || !(row.activityLastErrorCode === void 0 || row.activityLastErrorCode === null || typeof row.activityLastErrorCode === "string" && STATUS_ACTIVITY_ERROR_CODES.has(
|
|
38277
38335
|
row.activityLastErrorCode
|
|
38278
38336
|
))) {
|
|
38279
38337
|
throw new Error("stored listener status is malformed");
|
|
@@ -38299,6 +38357,16 @@ function parseStatus(raw, rejectUnknownKeys = false) {
|
|
|
38299
38357
|
// Optional key: present only when the file carried it, so a status written
|
|
38300
38358
|
// without it round-trips byte-for-byte (the routeMode pattern).
|
|
38301
38359
|
...row.lastAckSignalId === void 0 ? {} : { lastAckSignalId: row.lastAckSignalId ?? null },
|
|
38360
|
+
...row.currentDeliverySignalId === void 0 ? {} : {
|
|
38361
|
+
currentDeliverySignalId: row.currentDeliverySignalId ?? null
|
|
38362
|
+
},
|
|
38363
|
+
...row.currentDeliverySince === void 0 ? {} : {
|
|
38364
|
+
currentDeliverySince: row.currentDeliverySince ?? null
|
|
38365
|
+
},
|
|
38366
|
+
...heldBackDeliveries === void 0 ? {} : { heldBackDeliveries },
|
|
38367
|
+
...row.pendingDeliveryCountAt === void 0 ? {} : {
|
|
38368
|
+
pendingDeliveryCountAt: row.pendingDeliveryCountAt ?? null
|
|
38369
|
+
},
|
|
38302
38370
|
lastErrorDetail: row.lastErrorDetail ?? null,
|
|
38303
38371
|
lastWorkerStderrTail: row.lastWorkerStderrTail ?? null,
|
|
38304
38372
|
providerVersion: row.providerVersion ?? null,
|
|
@@ -38375,7 +38443,10 @@ async function appendListenerEvent(paths, event) {
|
|
|
38375
38443
|
"defer_over_chars",
|
|
38376
38444
|
"body_length",
|
|
38377
38445
|
"pending_main_count",
|
|
38378
|
-
"dropped_count"
|
|
38446
|
+
"dropped_count",
|
|
38447
|
+
// How long one delivery held the worker seat, and why it gave it back.
|
|
38448
|
+
"held_ms",
|
|
38449
|
+
"release_reason"
|
|
38379
38450
|
]);
|
|
38380
38451
|
const deliveryModes = /* @__PURE__ */ new Set(["durable_claim", "cursor_fallback"]);
|
|
38381
38452
|
const routeModes = /* @__PURE__ */ new Set(["worker", "main", "split"]);
|
|
@@ -38437,6 +38508,14 @@ async function appendListenerEvent(paths, event) {
|
|
|
38437
38508
|
if ((key2 === "body_length" || key2 === "pending_main_count" || key2 === "dropped_count") && !(typeof value === "number" && Number.isSafeInteger(value) && value >= 0)) {
|
|
38438
38509
|
throw new Error("listener event main-route count is not allowed");
|
|
38439
38510
|
}
|
|
38511
|
+
if (key2 === "held_ms" && !(typeof value === "number" && Number.isSafeInteger(value) && value >= 0)) {
|
|
38512
|
+
throw new Error("listener event hold duration is not allowed");
|
|
38513
|
+
}
|
|
38514
|
+
if (key2 === "release_reason" && !(typeof value === "string" && LISTENER_DELIVERY_HOLD_RELEASE_REASONS.includes(
|
|
38515
|
+
value
|
|
38516
|
+
))) {
|
|
38517
|
+
throw new Error("listener event hold release reason is not allowed");
|
|
38518
|
+
}
|
|
38440
38519
|
if (key2 === "worker_stderr_tail" && !(typeof value === "string" && value.length > 0 && value.length <= 2048)) {
|
|
38441
38520
|
throw new Error("listener event stderr tail is not allowed");
|
|
38442
38521
|
}
|
|
@@ -38816,6 +38895,7 @@ async function runListenerSupervisor(options) {
|
|
|
38816
38895
|
lastWorkerStderrTail: null,
|
|
38817
38896
|
deliveryMode: null,
|
|
38818
38897
|
pendingDeliveryCount: null,
|
|
38898
|
+
pendingDeliveryCountAt: null,
|
|
38819
38899
|
lastTerminalDeliveryFailureCount: null,
|
|
38820
38900
|
lastTerminalDeliveryFailureAt: null,
|
|
38821
38901
|
lastClaimAt: null,
|
|
@@ -38827,6 +38907,11 @@ async function runListenerSupervisor(options) {
|
|
|
38827
38907
|
lastAckOutcome: carried?.lastAckOutcome ?? null,
|
|
38828
38908
|
consecutiveAckFailureCount: carried?.consecutiveAckFailureCount ?? null,
|
|
38829
38909
|
lastAckSignalId: carried?.lastAckSignalId ?? null,
|
|
38910
|
+
/* Never carried across a restart: a seat this process does not hold cannot
|
|
38911
|
+
be reported as held, and the queue age restarts with the observations. */
|
|
38912
|
+
currentDeliverySignalId: null,
|
|
38913
|
+
currentDeliverySince: null,
|
|
38914
|
+
heldBackDeliveries: [],
|
|
38830
38915
|
routeMode: options.routeMode ?? "worker",
|
|
38831
38916
|
deferOverChars: options.deferOverChars ?? null,
|
|
38832
38917
|
pendingForMainCount: 0,
|
|
@@ -38860,9 +38945,15 @@ async function runListenerSupervisor(options) {
|
|
|
38860
38945
|
chain(() => appendListenerEvent(options.paths, event));
|
|
38861
38946
|
};
|
|
38862
38947
|
const transition = (state, changes = {}) => {
|
|
38948
|
+
const notWatching = state === "starting" || state === "stopped" || state === "failed";
|
|
38863
38949
|
status = {
|
|
38864
38950
|
...status,
|
|
38865
38951
|
...changes,
|
|
38952
|
+
...notWatching ? {
|
|
38953
|
+
currentDeliverySignalId: null,
|
|
38954
|
+
currentDeliverySince: null,
|
|
38955
|
+
heldBackDeliveries: []
|
|
38956
|
+
} : {},
|
|
38866
38957
|
state,
|
|
38867
38958
|
updatedAt: iso2(now)
|
|
38868
38959
|
};
|
|
@@ -39051,6 +39142,7 @@ async function runListenerSupervisor(options) {
|
|
|
39051
39142
|
...status,
|
|
39052
39143
|
deliveryMode: event.mode,
|
|
39053
39144
|
pendingDeliveryCount: event.pendingDeliveryCount,
|
|
39145
|
+
pendingDeliveryCountAt: event.pendingDeliveryCount === null ? null : event.ts,
|
|
39054
39146
|
updatedAt: event.ts
|
|
39055
39147
|
};
|
|
39056
39148
|
persist();
|
|
@@ -39063,6 +39155,7 @@ async function runListenerSupervisor(options) {
|
|
|
39063
39155
|
return;
|
|
39064
39156
|
}
|
|
39065
39157
|
if (event.type === "delivery_claim") {
|
|
39158
|
+
const heldBack = (status.heldBackDeliveries ?? []).filter((entry) => entry.signalId !== event.signalId);
|
|
39066
39159
|
status = {
|
|
39067
39160
|
...status,
|
|
39068
39161
|
readHealth: recordListenerClaim(
|
|
@@ -39070,6 +39163,10 @@ async function runListenerSupervisor(options) {
|
|
|
39070
39163
|
event.ts
|
|
39071
39164
|
),
|
|
39072
39165
|
pendingDeliveryCount: event.pendingDeliveryCount,
|
|
39166
|
+
pendingDeliveryCountAt: event.ts,
|
|
39167
|
+
currentDeliverySignalId: event.signalId,
|
|
39168
|
+
currentDeliverySince: event.signalId === null ? null : event.ts,
|
|
39169
|
+
heldBackDeliveries: heldBack,
|
|
39073
39170
|
lastClaimAt: event.ts,
|
|
39074
39171
|
updatedAt: event.ts
|
|
39075
39172
|
};
|
|
@@ -39101,6 +39198,36 @@ async function runListenerSupervisor(options) {
|
|
|
39101
39198
|
});
|
|
39102
39199
|
return;
|
|
39103
39200
|
}
|
|
39201
|
+
if (event.type === "delivery_hold_released") {
|
|
39202
|
+
status = {
|
|
39203
|
+
...status,
|
|
39204
|
+
currentDeliverySignalId: null,
|
|
39205
|
+
currentDeliverySince: null,
|
|
39206
|
+
/* Held back, NOT waiting to be claimed: the row keeps its live lease,
|
|
39207
|
+
so the service cannot hand it to anyone until that lease expires.
|
|
39208
|
+
Both review arms on 33cd24b measured the earlier wording counting it
|
|
39209
|
+
among deliveries "waiting to be claimed". Newest first, deduplicated
|
|
39210
|
+
on the id (a row can be released, redelivered and released again),
|
|
39211
|
+
and bounded. */
|
|
39212
|
+
heldBackDeliveries: [
|
|
39213
|
+
{ signalId: event.signalId, at: event.ts, reason: event.reason },
|
|
39214
|
+
...(status.heldBackDeliveries ?? []).filter(
|
|
39215
|
+
(entry) => entry.signalId !== event.signalId
|
|
39216
|
+
)
|
|
39217
|
+
].slice(0, LISTENER_HELD_BACK_MAX),
|
|
39218
|
+
lastSignalId: event.signalId,
|
|
39219
|
+
updatedAt: event.ts
|
|
39220
|
+
};
|
|
39221
|
+
persist();
|
|
39222
|
+
log({
|
|
39223
|
+
ts: event.ts,
|
|
39224
|
+
event: "listener_delivery_hold_released",
|
|
39225
|
+
signal_id: event.signalId,
|
|
39226
|
+
release_reason: event.reason,
|
|
39227
|
+
held_ms: Math.max(0, Math.trunc(event.heldMs))
|
|
39228
|
+
});
|
|
39229
|
+
return;
|
|
39230
|
+
}
|
|
39104
39231
|
if (event.type === "delivery_ack") {
|
|
39105
39232
|
const failed = event.outcome === "failed_terminal";
|
|
39106
39233
|
const providerProven = DELIVERY_PROVIDER_PROVEN_OUTCOMES.has(event.outcome);
|
|
@@ -39111,6 +39238,13 @@ async function runListenerSupervisor(options) {
|
|
|
39111
39238
|
lastAckSignalId: event.signalId,
|
|
39112
39239
|
consecutiveAckFailureCount: failed ? (status.consecutiveAckFailureCount ?? 0) + 1 : providerProven ? 0 : status.consecutiveAckFailureCount,
|
|
39113
39240
|
pendingDeliveryCount: null,
|
|
39241
|
+
pendingDeliveryCountAt: null,
|
|
39242
|
+
currentDeliverySignalId: null,
|
|
39243
|
+
currentDeliverySince: null,
|
|
39244
|
+
// An acknowledged row is answered and gone; drop just that one.
|
|
39245
|
+
heldBackDeliveries: (status.heldBackDeliveries ?? []).filter(
|
|
39246
|
+
(entry) => entry.signalId !== event.signalId
|
|
39247
|
+
),
|
|
39114
39248
|
lastSignalId: event.signalId,
|
|
39115
39249
|
updatedAt: event.ts
|
|
39116
39250
|
};
|
|
@@ -39281,7 +39415,14 @@ async function effectiveListenerStatus(paths) {
|
|
|
39281
39415
|
state: "failed",
|
|
39282
39416
|
updatedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
39283
39417
|
stoppedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
39284
|
-
lastErrorCode: "unclean_exit"
|
|
39418
|
+
lastErrorCode: "unclean_exit",
|
|
39419
|
+
/* The process is gone: it holds nothing and observes nothing, so every
|
|
39420
|
+
field whose sentence is rendered in the present tense against read
|
|
39421
|
+
time is cleared. pendingDeliveryCount stays, because its line already
|
|
39422
|
+
says it is what the service reported. */
|
|
39423
|
+
currentDeliverySignalId: null,
|
|
39424
|
+
currentDeliverySince: null,
|
|
39425
|
+
heldBackDeliveries: []
|
|
39285
39426
|
};
|
|
39286
39427
|
await writeListenerStatus(paths, failed);
|
|
39287
39428
|
return failed;
|
|
@@ -41648,6 +41789,23 @@ var ListenerHttpClient = class {
|
|
|
41648
41789
|
|
|
41649
41790
|
// src/resume.ts
|
|
41650
41791
|
var import_node_child_process8 = require("node:child_process");
|
|
41792
|
+
var DEFAULT_PROCESS_TABLE_COMMAND = {
|
|
41793
|
+
file: "ps",
|
|
41794
|
+
args: ["-axo", "pid=,command="]
|
|
41795
|
+
};
|
|
41796
|
+
var ProcessTableError = class extends Error {
|
|
41797
|
+
constructor(command2, detail) {
|
|
41798
|
+
super(
|
|
41799
|
+
`could not read the host process table with ${command2.file}: ${detail}`
|
|
41800
|
+
);
|
|
41801
|
+
this.command = command2;
|
|
41802
|
+
this.detail = detail;
|
|
41803
|
+
this.name = "ProcessTableError";
|
|
41804
|
+
}
|
|
41805
|
+
command;
|
|
41806
|
+
detail;
|
|
41807
|
+
code = "process_table_unavailable";
|
|
41808
|
+
};
|
|
41651
41809
|
function execFileText(file, args) {
|
|
41652
41810
|
return new Promise((resolve3, reject) => {
|
|
41653
41811
|
(0, import_node_child_process8.execFile)(file, [...args], {
|
|
@@ -41659,15 +41817,76 @@ function execFileText(file, args) {
|
|
|
41659
41817
|
});
|
|
41660
41818
|
});
|
|
41661
41819
|
}
|
|
41662
|
-
function
|
|
41820
|
+
function parseProcessRow(line) {
|
|
41821
|
+
const match = /^\s*(\d+)\s+(.*)$/.exec(line);
|
|
41822
|
+
if (!match) return null;
|
|
41823
|
+
const pid = Number(match[1]);
|
|
41824
|
+
if (!Number.isSafeInteger(pid) || pid <= 0) return null;
|
|
41825
|
+
return { pid, command: match[2] };
|
|
41826
|
+
}
|
|
41827
|
+
var PROCESS_TABLE_STDERR_MAX_CHARS = 2e3;
|
|
41828
|
+
function systemProcessTable(options = {}) {
|
|
41829
|
+
const command2 = options.command ?? DEFAULT_PROCESS_TABLE_COMMAND;
|
|
41830
|
+
const retain = options.retain ?? (() => true);
|
|
41663
41831
|
return {
|
|
41664
|
-
|
|
41665
|
-
|
|
41666
|
-
|
|
41667
|
-
|
|
41668
|
-
|
|
41669
|
-
const
|
|
41670
|
-
|
|
41832
|
+
list() {
|
|
41833
|
+
return new Promise((resolve3, reject) => {
|
|
41834
|
+
const child = (0, import_node_child_process8.spawn)(command2.file, [...command2.args], {
|
|
41835
|
+
stdio: ["ignore", "pipe", "pipe"]
|
|
41836
|
+
});
|
|
41837
|
+
const rows3 = [];
|
|
41838
|
+
let pending = "";
|
|
41839
|
+
let stderr = "";
|
|
41840
|
+
let settled = false;
|
|
41841
|
+
const fail = (detail) => {
|
|
41842
|
+
if (settled) return;
|
|
41843
|
+
settled = true;
|
|
41844
|
+
child.stdout.destroy();
|
|
41845
|
+
reject(new ProcessTableError(command2, detail));
|
|
41846
|
+
};
|
|
41847
|
+
const take = (line) => {
|
|
41848
|
+
const row = parseProcessRow(line);
|
|
41849
|
+
if (row === null) return true;
|
|
41850
|
+
try {
|
|
41851
|
+
if (retain(row.command)) rows3.push(row);
|
|
41852
|
+
} catch {
|
|
41853
|
+
fail("its row filter threw");
|
|
41854
|
+
return false;
|
|
41855
|
+
}
|
|
41856
|
+
return true;
|
|
41857
|
+
};
|
|
41858
|
+
child.stdout.setEncoding("utf8");
|
|
41859
|
+
child.stdout.on("data", (chunk) => {
|
|
41860
|
+
if (settled) return;
|
|
41861
|
+
const lines = (pending + chunk).split("\n");
|
|
41862
|
+
pending = lines.pop() ?? "";
|
|
41863
|
+
for (const line of lines) {
|
|
41864
|
+
if (!take(line)) return;
|
|
41865
|
+
}
|
|
41866
|
+
});
|
|
41867
|
+
child.stderr.setEncoding("utf8");
|
|
41868
|
+
child.stderr.on("data", (chunk) => {
|
|
41869
|
+
const room = PROCESS_TABLE_STDERR_MAX_CHARS - stderr.length;
|
|
41870
|
+
if (room > 0) stderr += chunk.slice(0, room);
|
|
41871
|
+
});
|
|
41872
|
+
child.stdout.on("error", () => fail("its output stream failed"));
|
|
41873
|
+
child.stderr.on("error", () => fail("its error stream failed"));
|
|
41874
|
+
child.on("error", (error) => fail(error.name));
|
|
41875
|
+
child.on("close", (code, signal) => {
|
|
41876
|
+
if (settled) return;
|
|
41877
|
+
if (pending.length > 0 && !take(pending)) return;
|
|
41878
|
+
if (signal !== null) {
|
|
41879
|
+
fail(`it was stopped by ${signal}`);
|
|
41880
|
+
return;
|
|
41881
|
+
}
|
|
41882
|
+
if (code !== 0) {
|
|
41883
|
+
const trailer = stderr.trim().length > 0 ? `: ${stderr.trim().slice(0, PROCESS_TABLE_STDERR_MAX_CHARS)}` : "";
|
|
41884
|
+
fail(`it exited ${code}${trailer}`);
|
|
41885
|
+
return;
|
|
41886
|
+
}
|
|
41887
|
+
settled = true;
|
|
41888
|
+
resolve3(rows3);
|
|
41889
|
+
});
|
|
41671
41890
|
});
|
|
41672
41891
|
}
|
|
41673
41892
|
};
|
|
@@ -41717,7 +41936,10 @@ function isNotifyCommand(command2) {
|
|
|
41717
41936
|
return /(?:^|\s)inbox(?:\s|$)/.test(command2) && /(?:^|\s)--notify(?:\s|$)/.test(command2);
|
|
41718
41937
|
}
|
|
41719
41938
|
async function findNotifyWatchers(options) {
|
|
41720
|
-
const processTable = options.processTable ?? systemProcessTable(
|
|
41939
|
+
const processTable = options.processTable ?? systemProcessTable({
|
|
41940
|
+
retain: isNotifyCommand,
|
|
41941
|
+
...options.processTableCommand ? { command: options.processTableCommand } : {}
|
|
41942
|
+
});
|
|
41721
41943
|
const stdoutConsumer = options.stdoutConsumer ?? lsofStdoutConsumer();
|
|
41722
41944
|
const rows3 = await processTable.list();
|
|
41723
41945
|
const matches = rows3.flatMap((row) => {
|
|
@@ -41985,6 +42207,7 @@ var KNOWN_FLAGS = /* @__PURE__ */ new Set([
|
|
|
41985
42207
|
"grok-executable",
|
|
41986
42208
|
"head-sha",
|
|
41987
42209
|
"help",
|
|
42210
|
+
"if-version",
|
|
41988
42211
|
"include-stale",
|
|
41989
42212
|
"include-tombstoned",
|
|
41990
42213
|
"invitation-id",
|
|
@@ -42056,8 +42279,8 @@ var BOOLEAN_FLAGS = /* @__PURE__ */ new Set([
|
|
|
42056
42279
|
]);
|
|
42057
42280
|
var UUID_RE23 = /^[0-9a-f]{8}-[0-9a-f]{4}-[1-8][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i;
|
|
42058
42281
|
function packageVersion() {
|
|
42059
|
-
if ("0.1.
|
|
42060
|
-
return "0.1.
|
|
42282
|
+
if ("0.1.54".length > 0) {
|
|
42283
|
+
return "0.1.54";
|
|
42061
42284
|
}
|
|
42062
42285
|
try {
|
|
42063
42286
|
const value = JSON.parse(
|
|
@@ -42192,7 +42415,7 @@ Usage:
|
|
|
42192
42415
|
cswarm file restore <name|file-id> [--url <url> --anon-key <key>] [--workspace-id <uuid>] ${agentCredential2} [--json]
|
|
42193
42416
|
cswarm brain ls [--url <url> --anon-key <key>] [--workspace-id <uuid>] ${agentCredential2} [--json]
|
|
42194
42417
|
cswarm brain get <topic>[@<version>] [--version <n>] [--url <url> --anon-key <key>] [--workspace-id <uuid>] ${agentCredential2} [--json]
|
|
42195
|
-
cswarm brain put <topic> [<markdown-path>] [--url <url> --anon-key <key>] [--workspace-id <uuid>] ${agentCredential2} [--json] # without a path, reads Markdown from stdin
|
|
42418
|
+
cswarm brain put <topic> [<markdown-path>] [--url <url> --anon-key <key>] [--workspace-id <uuid>] ${agentCredential2} [--if-version <n>] [--json] # without a path, reads Markdown from stdin; --if-version refuses the write unless the live version is still <n>
|
|
42196
42419
|
cswarm feedback "<text>" --kind bug|idea|friction [--about <ref>] [--url <url> --anon-key <key>] [--workspace-id <uuid>] ${agentCredential2} [--json]
|
|
42197
42420
|
cswarm listen start ${requiredAgentCredential} [--url <url> --anon-key <key>] --workspace-id <uuid> --provider grok|opencode|claude|codex [--cwd <absolute-path>] [--model <model>] [--effort <level>] [--permissions deny|allow] [--grok-executable <path>] [--opencode-executable <path>] [--claude-executable <path>] [--codex-executable <path>] [--turn-budget <duration>] [--route worker|main|split] [--defer-over <chars>] [--allow-unattended] [--foreground] [--json]
|
|
42198
42421
|
cswarm listen canary ${requiredAgentCredential} [--url <url> --anon-key <key>] --workspace-id <uuid> [--state-dir <path>] [--wait <seconds>] [--json]
|
|
@@ -42282,7 +42505,10 @@ due \u2014 a turn never outlives its credential. Right after a rotation the full
|
|
|
42282
42505
|
budget is available up to the token TTL minus 60s (about 59m on the default 1h
|
|
42283
42506
|
TTL); a turn that lands just before a rotation can be clamped to the ~5m
|
|
42284
42507
|
renewal lead, and if it times out there, durable delivery retries it on the
|
|
42285
|
-
fresh credential.
|
|
42508
|
+
fresh credential. The same budget also bounds how long ONE delivery may hold the
|
|
42509
|
+
worker seat across its retries: when it is spent the listener hands the seat
|
|
42510
|
+
back and claims the next delivery. After the lease ends the service either
|
|
42511
|
+
delivers the released one again or terminates it.
|
|
42286
42512
|
|
|
42287
42513
|
listen start --route worker|main|split chooses where directed messages go. worker
|
|
42288
42514
|
is the unchanged default. main queues every ask or note for the interactive session.
|
|
@@ -45305,6 +45531,12 @@ function listenerStatusJson(status, permissionMode, evidence = {
|
|
|
45305
45531
|
lastAckOutcome: status.lastAckOutcome ?? null,
|
|
45306
45532
|
consecutiveAckFailureCount: status.consecutiveAckFailureCount ?? null,
|
|
45307
45533
|
lastAckSignalId: status.lastAckSignalId ?? null,
|
|
45534
|
+
currentDeliverySignalId: status.currentDeliverySignalId ?? null,
|
|
45535
|
+
currentDeliverySince: status.currentDeliverySince ?? null,
|
|
45536
|
+
currentDeliveryElapsedMs: status.currentDeliverySince ? Math.max(0, nowMs - Date.parse(status.currentDeliverySince)) : null,
|
|
45537
|
+
pendingDeliveryCountAt: status.pendingDeliveryCountAt ?? null,
|
|
45538
|
+
heldBackDeliveries: status.heldBackDeliveries ?? [],
|
|
45539
|
+
heldBackDeliveryCount: (status.heldBackDeliveries ?? []).length,
|
|
45308
45540
|
routeMode: status.routeMode ?? "worker",
|
|
45309
45541
|
deferOverChars: status.deferOverChars ?? null,
|
|
45310
45542
|
pendingForMainCount: status.pendingForMainCount ?? 0,
|
|
@@ -45427,8 +45659,26 @@ function renderListenerStatus(status, evidence = {
|
|
|
45427
45659
|
lines.push("Delivery mode has not been reported yet.");
|
|
45428
45660
|
}
|
|
45429
45661
|
if (status.pendingDeliveryCount !== null) {
|
|
45662
|
+
const observedAt = status.pendingDeliveryCountAt ?? null;
|
|
45663
|
+
lines.push(
|
|
45664
|
+
`Pending deliveries reported by the service: ${status.pendingDeliveryCount}.` + (observedAt === null ? " When the service reported it was not recorded." : ` The service reported that ${relativeAge(observedAt, nowMs)}.`)
|
|
45665
|
+
);
|
|
45666
|
+
}
|
|
45667
|
+
const currentDeliveryId = status.currentDeliverySignalId ?? null;
|
|
45668
|
+
const currentDeliverySince = status.currentDeliverySince ?? null;
|
|
45669
|
+
if (currentDeliveryId !== null && currentDeliverySince !== null) {
|
|
45670
|
+
lines.push(
|
|
45671
|
+
`Working on delivery ${currentDeliveryId}, claimed ${relativeAge(currentDeliverySince, nowMs)}.`
|
|
45672
|
+
);
|
|
45673
|
+
} else {
|
|
45674
|
+
lines.push("No delivery is being worked on right now.");
|
|
45675
|
+
}
|
|
45676
|
+
const heldBack = status.heldBackDeliveries ?? [];
|
|
45677
|
+
const newestHeldBack = heldBack[0];
|
|
45678
|
+
if (newestHeldBack !== void 0) {
|
|
45679
|
+
const others = heldBack.length - 1;
|
|
45430
45680
|
lines.push(
|
|
45431
|
-
`
|
|
45681
|
+
`Delivery ${newestHeldBack.signalId} was handed back ${relativeAge(newestHeldBack.at, nowMs)} because ${LISTENER_DELIVERY_HOLD_RELEASE_CLAUSES[newestHeldBack.reason]}.` + (others > 0 ? ` This listener is still tracking ${others} other handed-back ${others === 1 ? "delivery" : "deliveries"}.` : "") + ` This listener has not answered it. After the lease ends the service either delivers it again or terminates it. If this repeats, ${LISTENER_DELIVERY_HOLD_RELEASE_REMEDIES[newestHeldBack.reason]}.`
|
|
45432
45682
|
);
|
|
45433
45683
|
}
|
|
45434
45684
|
lines.push(
|
|
@@ -45969,6 +46219,9 @@ async function runConfiguredListener(options) {
|
|
|
45969
46219
|
},
|
|
45970
46220
|
routeMode,
|
|
45971
46221
|
deferOverChars,
|
|
46222
|
+
/* One delivery may hold the seat for one turn budget, not for the
|
|
46223
|
+
whole 15-minute lease. Same lever, so the two cannot drift. */
|
|
46224
|
+
deliveryHoldBudgetMs: turnBudgetMs,
|
|
45972
46225
|
pendingMainQueue,
|
|
45973
46226
|
fetcher: httpClient.fetch
|
|
45974
46227
|
});
|
|
@@ -46796,7 +47049,7 @@ async function resolveFileSelector(context, selector) {
|
|
|
46796
47049
|
}
|
|
46797
47050
|
return match.file_id;
|
|
46798
47051
|
}
|
|
46799
|
-
async function uploadNamedFile(context, name, bytes) {
|
|
47052
|
+
async function uploadNamedFile(context, name, bytes, options = {}) {
|
|
46800
47053
|
if (bytes.byteLength > FILE_MAX_VERSION_BYTES) {
|
|
46801
47054
|
throw new Error(
|
|
46802
47055
|
`this file is ${formatFileSize(bytes.byteLength)}; the per-file limit is ${formatFileSize(FILE_MAX_VERSION_BYTES)}, so the upload was not started`
|
|
@@ -46823,7 +47076,8 @@ async function uploadNamedFile(context, name, bytes) {
|
|
|
46823
47076
|
versionId,
|
|
46824
47077
|
name,
|
|
46825
47078
|
declaredSizeBytes: bytes.byteLength,
|
|
46826
|
-
contentType
|
|
47079
|
+
contentType,
|
|
47080
|
+
...options.ifVersion === void 0 ? {} : { ifVersion: options.ifVersion }
|
|
46827
47081
|
})
|
|
46828
47082
|
);
|
|
46829
47083
|
await onceRetried(
|
|
@@ -47117,7 +47371,8 @@ async function runBrainPut(args) {
|
|
|
47117
47371
|
"cswarm brain put cannot read both the credential and Markdown from stdin; use --agent-token-file or pass a Markdown path"
|
|
47118
47372
|
);
|
|
47119
47373
|
}
|
|
47120
|
-
const context = await fileContext(args, [], args.positionals.length);
|
|
47374
|
+
const context = await fileContext(args, ["if-version"], args.positionals.length);
|
|
47375
|
+
const ifVersion = args.optional("if-version") === void 0 ? void 0 : integer2(args, "if-version", { minimum: 0 });
|
|
47121
47376
|
let bytes;
|
|
47122
47377
|
if (localPath) {
|
|
47123
47378
|
try {
|
|
@@ -47132,7 +47387,19 @@ async function runBrainPut(args) {
|
|
|
47132
47387
|
bytes = await readBrainMarkdownFromStdin();
|
|
47133
47388
|
}
|
|
47134
47389
|
decodeBrainMarkdown(bytes);
|
|
47135
|
-
const committed = await uploadNamedFile(
|
|
47390
|
+
const committed = await uploadNamedFile(
|
|
47391
|
+
context,
|
|
47392
|
+
brainFileName(topic),
|
|
47393
|
+
bytes,
|
|
47394
|
+
ifVersion === void 0 ? {} : { ifVersion }
|
|
47395
|
+
).catch((error) => {
|
|
47396
|
+
if (error instanceof FileCommandRefused && error.code === FILE_VERSION_PRECONDITION_FAILED) {
|
|
47397
|
+
throw new Error(
|
|
47398
|
+
`${error.message}. Someone saved a new version after you read this topic. Re-read it, apply your change to that copy, then put it again: cswarm brain get ${topic}`
|
|
47399
|
+
);
|
|
47400
|
+
}
|
|
47401
|
+
throw error;
|
|
47402
|
+
});
|
|
47136
47403
|
if (args.has("json")) {
|
|
47137
47404
|
process.stdout.write(`${JSON.stringify({ topic, ...committed }, null, 2)}
|
|
47138
47405
|
`);
|
|
@@ -47634,5 +47901,6 @@ ${usage()}
|
|
|
47634
47901
|
replyRefusalHint,
|
|
47635
47902
|
resolveDetachedClaudeExecutable,
|
|
47636
47903
|
resolveDetachedCodexExecutable,
|
|
47637
|
-
resolveTurnBudgetOrDefer
|
|
47904
|
+
resolveTurnBudgetOrDefer,
|
|
47905
|
+
usage
|
|
47638
47906
|
});
|