@open-artifacts/bus 0.124.0 → 0.125.0
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/assets/oa-bus.ts +25 -2
- package/dist/index.js +618 -222
- package/package.json +1 -1
package/assets/oa-bus.ts
CHANGED
|
@@ -11,7 +11,7 @@ import { StringDecoder } from "node:string_decoder";
|
|
|
11
11
|
type Json = Record<string, unknown>;
|
|
12
12
|
|
|
13
13
|
/** The IPC marker (CONTRACT.md): the package version, stamped by the CLI's bundler. */
|
|
14
|
-
const CLIENT_VERSION = "0.
|
|
14
|
+
const CLIENT_VERSION = "0.125.0";
|
|
15
15
|
|
|
16
16
|
type Frame = Json & { type: string; id: string };
|
|
17
17
|
type Ctx = {
|
|
@@ -116,6 +116,16 @@ const refusals: Record<
|
|
|
116
116
|
`200 messages are already waiting.`,
|
|
117
117
|
"Send again once some are delivered or expire.",
|
|
118
118
|
],
|
|
119
|
+
// #1295: the cap sockets' inbox_full (pending count, bytes or the hub total).
|
|
120
|
+
mailbox_full: [
|
|
121
|
+
"Its mailbox is full.",
|
|
122
|
+
"Send again once it has read some, or message another agent.",
|
|
123
|
+
],
|
|
124
|
+
// #1295: a name only held after a move; no one reads it.
|
|
125
|
+
reserved_name: [
|
|
126
|
+
"No one has that name now; it was left by an agent that moved.",
|
|
127
|
+
"Run the oa_bus list_agents tool to find who has it now.",
|
|
128
|
+
],
|
|
119
129
|
too_large: [
|
|
120
130
|
"It is too large to send (the limit is 1 MB).",
|
|
121
131
|
"Send a shorter message.",
|
|
@@ -416,6 +426,14 @@ function statusSaysText(
|
|
|
416
426
|
].join(" · ");
|
|
417
427
|
}
|
|
418
428
|
|
|
429
|
+
/** "2026-11-05 10:00 UTC" from an ISO time; unreadable times are shown as sent. */
|
|
430
|
+
const awayTime = (iso: string): string => {
|
|
431
|
+
const t = Date.parse(iso);
|
|
432
|
+
return Number.isNaN(t)
|
|
433
|
+
? iso
|
|
434
|
+
: `${new Date(t).toISOString().slice(0, 16).replace("T", " ")} UTC`;
|
|
435
|
+
};
|
|
436
|
+
|
|
419
437
|
/** @oa/bus-ipc rosterLine: one list_agents line. */
|
|
420
438
|
function rosterLine(
|
|
421
439
|
a: StatusFields & {
|
|
@@ -424,11 +442,13 @@ function rosterLine(
|
|
|
424
442
|
namespace: string;
|
|
425
443
|
machine_label?: unknown;
|
|
426
444
|
queued: boolean;
|
|
445
|
+
/** #1295: ISO time the agent went away; it is closed, its mailbox kept. */
|
|
446
|
+
away?: string | undefined;
|
|
427
447
|
},
|
|
428
448
|
now = Date.now(),
|
|
429
449
|
): string {
|
|
430
450
|
const says = statusSaysText(a, now);
|
|
431
|
-
return `- ${a.name} (${displayKind(a.kind)}, ${a.namespace}${typeof a.machine_label === "string" && a.machine_label ? `, ${a.machine_label}` : ""})${a.queued ? " (queued)" : ""}${says ? ` ${says}` : ""}`;
|
|
451
|
+
return `- ${a.name} (${displayKind(a.kind)}, ${a.namespace}${typeof a.machine_label === "string" && a.machine_label ? `, ${a.machine_label}` : ""})${a.away !== undefined ? (a.away ? ` (away since ${awayTime(a.away)})` : " (away)") : a.queued ? " (queued)" : ""}${says ? ` ${says}` : ""}`;
|
|
432
452
|
}
|
|
433
453
|
|
|
434
454
|
/** @oa/bus-ipc selfText: the agent entry, its status cleaned. */
|
|
@@ -838,6 +858,8 @@ function open(
|
|
|
838
858
|
pid: process.pid,
|
|
839
859
|
cwd: id.cwd,
|
|
840
860
|
proposed_name: id.name,
|
|
861
|
+
// #1295: this asset decodes away rows and the new refusals.
|
|
862
|
+
caps: ["mailbox"],
|
|
841
863
|
attest: start ? { proc_start: start } : {},
|
|
842
864
|
}),
|
|
843
865
|
);
|
|
@@ -1032,6 +1054,7 @@ export default function oaBus(pi: Pi): void {
|
|
|
1032
1054
|
namespace: String(a.namespace),
|
|
1033
1055
|
queued:
|
|
1034
1056
|
(a.state ?? (a.live ? "live" : "queued")) === "queued",
|
|
1057
|
+
away: a.state === "away" ? String(a.since ?? "") : undefined,
|
|
1035
1058
|
},
|
|
1036
1059
|
now,
|
|
1037
1060
|
),
|
package/dist/index.js
CHANGED
|
@@ -31389,7 +31389,17 @@ var init_caps = __esm({
|
|
|
31389
31389
|
* to a socket whose hello listed it, and lists it in `hello_ok.caps`; the
|
|
31390
31390
|
* client sends `to_id` only when it did.
|
|
31391
31391
|
*/
|
|
31392
|
-
ids: "ids"
|
|
31392
|
+
ids: "ids",
|
|
31393
|
+
/**
|
|
31394
|
+
* Lasting mailboxes (#1295): the client decodes a send receipt's `queued`
|
|
31395
|
+
* and `since`, the `mailbox_full` and `reserved_name` refusals, and roster
|
|
31396
|
+
* rows with `state: "away"` and `since`. The hub sends those only to a
|
|
31397
|
+
* socket whose hello listed it, and lists it in `hello_ok.caps`; any other
|
|
31398
|
+
* socket sees today's shapes (`inbox_full`, `unknown_agent`, no away rows).
|
|
31399
|
+
* A client also lists it to have the hub hand an address over on `agent_up`
|
|
31400
|
+
* `replaces` (a /clear).
|
|
31401
|
+
*/
|
|
31402
|
+
mailbox: "mailbox"
|
|
31393
31403
|
};
|
|
31394
31404
|
MAX_CAPS = 16;
|
|
31395
31405
|
CapTokenSchema = external_exports.string().regex(/^[a-z][a-z0-9_-]{0,31}$/);
|
|
@@ -31819,6 +31829,33 @@ var init_names = __esm({
|
|
|
31819
31829
|
}
|
|
31820
31830
|
});
|
|
31821
31831
|
|
|
31832
|
+
// ../bus-protocol/src/status.ts
|
|
31833
|
+
var IsoTimeSchema, STATUS_STATES, StatusStateSchema, StatusLabelSchema, AgentStatusSchema;
|
|
31834
|
+
var init_status = __esm({
|
|
31835
|
+
"../bus-protocol/src/status.ts"() {
|
|
31836
|
+
"use strict";
|
|
31837
|
+
init_zod();
|
|
31838
|
+
init_limits();
|
|
31839
|
+
init_refs();
|
|
31840
|
+
IsoTimeSchema = external_exports.string().datetime({ offset: true });
|
|
31841
|
+
STATUS_STATES = [
|
|
31842
|
+
"working",
|
|
31843
|
+
"idle",
|
|
31844
|
+
"blocked",
|
|
31845
|
+
"waiting_on_owner"
|
|
31846
|
+
];
|
|
31847
|
+
StatusStateSchema = external_exports.enum(STATUS_STATES);
|
|
31848
|
+
StatusLabelSchema = MachineLabelSchema.refine(
|
|
31849
|
+
(s) => [...s].length <= LIMITS.maxLabelChars,
|
|
31850
|
+
"status label too long"
|
|
31851
|
+
);
|
|
31852
|
+
AgentStatusSchema = external_exports.strictObject({
|
|
31853
|
+
state: StatusStateSchema,
|
|
31854
|
+
label: StatusLabelSchema.optional()
|
|
31855
|
+
});
|
|
31856
|
+
}
|
|
31857
|
+
});
|
|
31858
|
+
|
|
31822
31859
|
// ../bus-protocol/src/receipts.ts
|
|
31823
31860
|
var RECEIPT_STATES, ReceiptStateSchema, REFUSAL_REASONS, RefusalReasonSchema, ReceiptReasonSchema, MsgIdSchema, receiptReasonMatchesState, receiptShape, ReceiptSchema;
|
|
31824
31861
|
var init_receipts = __esm({
|
|
@@ -31826,6 +31863,7 @@ var init_receipts = __esm({
|
|
|
31826
31863
|
"use strict";
|
|
31827
31864
|
init_zod();
|
|
31828
31865
|
init_names();
|
|
31866
|
+
init_status();
|
|
31829
31867
|
RECEIPT_STATES = [
|
|
31830
31868
|
"pending",
|
|
31831
31869
|
"delivered",
|
|
@@ -31848,7 +31886,19 @@ var init_receipts = __esm({
|
|
|
31848
31886
|
*/
|
|
31849
31887
|
"role_vacant",
|
|
31850
31888
|
/** A reply's `to_id` no longer holds the name: the agent it answers is gone. */
|
|
31851
|
-
"agent_gone"
|
|
31889
|
+
"agent_gone",
|
|
31890
|
+
/**
|
|
31891
|
+
* #1295: the address's mailbox is full (pending count or bytes). Sent only
|
|
31892
|
+
* to a socket whose hello listed `BUS_CAPS.mailbox`; any other gets
|
|
31893
|
+
* `inbox_full`.
|
|
31894
|
+
*/
|
|
31895
|
+
"mailbox_full",
|
|
31896
|
+
/**
|
|
31897
|
+
* #1295: the name is only a `held` reservation of a moved or flipped agent;
|
|
31898
|
+
* it has no mailbox. Sent only to a `BUS_CAPS.mailbox` socket; any other
|
|
31899
|
+
* gets `unknown_agent`.
|
|
31900
|
+
*/
|
|
31901
|
+
"reserved_name"
|
|
31852
31902
|
];
|
|
31853
31903
|
RefusalReasonSchema = external_exports.enum(REFUSAL_REASONS);
|
|
31854
31904
|
ReceiptReasonSchema = external_exports.union([
|
|
@@ -31867,39 +31917,20 @@ var init_receipts = __esm({
|
|
|
31867
31917
|
* through a role address (#1296, the role's holder), to a socket whose
|
|
31868
31918
|
* hello listed `BUS_CAPS.roles`. An ordinary send never carries it.
|
|
31869
31919
|
*/
|
|
31870
|
-
to_name: BusNameSchema.optional()
|
|
31920
|
+
to_name: BusNameSchema.optional(),
|
|
31921
|
+
/**
|
|
31922
|
+
* #1295, on a `pending` send receipt only, to a socket whose hello listed
|
|
31923
|
+
* `BUS_CAPS.mailbox`: the mail was stored, not pushed. `away`: the
|
|
31924
|
+
* recipient is closed and its mailbox waits for it. `offline`: it is open
|
|
31925
|
+
* but its machine is offline. `since` is when that began.
|
|
31926
|
+
*/
|
|
31927
|
+
queued: external_exports.enum(["away", "offline"]).optional(),
|
|
31928
|
+
since: IsoTimeSchema.optional()
|
|
31871
31929
|
};
|
|
31872
31930
|
ReceiptSchema = external_exports.strictObject(receiptShape).refine(receiptReasonMatchesState, "reason does not match state");
|
|
31873
31931
|
}
|
|
31874
31932
|
});
|
|
31875
31933
|
|
|
31876
|
-
// ../bus-protocol/src/status.ts
|
|
31877
|
-
var IsoTimeSchema, STATUS_STATES, StatusStateSchema, StatusLabelSchema, AgentStatusSchema;
|
|
31878
|
-
var init_status = __esm({
|
|
31879
|
-
"../bus-protocol/src/status.ts"() {
|
|
31880
|
-
"use strict";
|
|
31881
|
-
init_zod();
|
|
31882
|
-
init_limits();
|
|
31883
|
-
init_refs();
|
|
31884
|
-
IsoTimeSchema = external_exports.string().datetime({ offset: true });
|
|
31885
|
-
STATUS_STATES = [
|
|
31886
|
-
"working",
|
|
31887
|
-
"idle",
|
|
31888
|
-
"blocked",
|
|
31889
|
-
"waiting_on_owner"
|
|
31890
|
-
];
|
|
31891
|
-
StatusStateSchema = external_exports.enum(STATUS_STATES);
|
|
31892
|
-
StatusLabelSchema = MachineLabelSchema.refine(
|
|
31893
|
-
(s) => [...s].length <= LIMITS.maxLabelChars,
|
|
31894
|
-
"status label too long"
|
|
31895
|
-
);
|
|
31896
|
-
AgentStatusSchema = external_exports.strictObject({
|
|
31897
|
-
state: StatusStateSchema,
|
|
31898
|
-
label: StatusLabelSchema.optional()
|
|
31899
|
-
});
|
|
31900
|
-
}
|
|
31901
|
-
});
|
|
31902
|
-
|
|
31903
31934
|
// ../bus-protocol/src/rename.ts
|
|
31904
31935
|
var NAME_KINDS, NameKindSchema, FormerNameSchema, FormerNamesSchema;
|
|
31905
31936
|
var init_rename = __esm({
|
|
@@ -32063,7 +32094,17 @@ var init_protocol2 = __esm({
|
|
|
32063
32094
|
* decoder older than this field refuses the unknown key, so a client sends
|
|
32064
32095
|
* it only to hubs that accept it.
|
|
32065
32096
|
*/
|
|
32066
|
-
name_kind: NameKindSchema.optional()
|
|
32097
|
+
name_kind: NameKindSchema.optional(),
|
|
32098
|
+
/**
|
|
32099
|
+
* #1295: the agent_ref this one takes over from, after a /clear: the same
|
|
32100
|
+
* live process now reports a new session. The hub honours it only for a
|
|
32101
|
+
* socket whose hello listed `BUS_CAPS.mailbox`, when the old ref is an
|
|
32102
|
+
* agent of the same machine; the new ref then inherits the old address
|
|
32103
|
+
* (name, former names) and its pending mail, instead of `<name>-2`. A hub
|
|
32104
|
+
* decoder older than this field refuses the key, so a client sends it only
|
|
32105
|
+
* after `hello_ok.caps` listed `mailbox`.
|
|
32106
|
+
*/
|
|
32107
|
+
replaces: AgentRefSchema.optional()
|
|
32067
32108
|
});
|
|
32068
32109
|
AgentDown = external_exports.strictObject({
|
|
32069
32110
|
...base,
|
|
@@ -32169,9 +32210,16 @@ var init_protocol2 = __esm({
|
|
|
32169
32210
|
global: external_exports.boolean(),
|
|
32170
32211
|
/**
|
|
32171
32212
|
* `live`: machine connected. `queued`: machine disconnected but the session
|
|
32172
|
-
* was last reported open (mail waits
|
|
32213
|
+
* was last reported open (mail waits). `away` (#1295, cap-gated): closed,
|
|
32214
|
+
* its mailbox kept for 7 d. Other closed agents are omitted.
|
|
32173
32215
|
*/
|
|
32174
|
-
state: external_exports.enum(["live", "queued"]),
|
|
32216
|
+
state: external_exports.enum(["live", "queued", "away"]),
|
|
32217
|
+
/**
|
|
32218
|
+
* When an `away` agent closed (#1295). Sent, with `state: "away"`, only to
|
|
32219
|
+
* a socket whose hello listed `BUS_CAPS.mailbox`: a decoder older than
|
|
32220
|
+
* either refuses the row, and with it the whole roster.
|
|
32221
|
+
*/
|
|
32222
|
+
since: IsoTimeSchema.optional(),
|
|
32175
32223
|
/** The agent's machine label. */
|
|
32176
32224
|
machine_label: MachineLabelSchema.optional(),
|
|
32177
32225
|
/** Self-reported ("agent says"); cleared on close. */
|
|
@@ -32344,7 +32392,7 @@ var init_src = __esm({
|
|
|
32344
32392
|
});
|
|
32345
32393
|
|
|
32346
32394
|
// ../bus-ipc/src/frames.ts
|
|
32347
|
-
var V, MAX_BODY_BYTES, MAX_LINE_BYTES, INLINE_CAP_BYTES, KIND, KIND_TOKEN, AGENT_REF, base2, late, isWellFormed2, WELL_FORMED, CLIENT_VERSION, clientVersion, Hello2, SPAWNED_SOURCES, optIn, Send2, List2, Self, Fetch2, Ack2, SetStatus, StatusRequest, AdapterFrame, AgentInfo, Welcome, Receipt, Roster2, Agent, StatusSet, Body, Deliver2, Notice2, ErrorFrame2, StatusReply, DaemonFrame;
|
|
32395
|
+
var V, MAX_BODY_BYTES, MAX_LINE_BYTES, INLINE_CAP_BYTES, KIND, KIND_TOKEN, AGENT_REF, base2, late, isWellFormed2, WELL_FORMED, CLIENT_VERSION, clientVersion, ADAPTER_CAPS, Hello2, SPAWNED_SOURCES, optIn, Send2, List2, Self, Fetch2, Ack2, SetStatus, StatusRequest, AdapterFrame, ConfigFile, AgentInfo, Welcome, Receipt, Roster2, Agent, StatusSet, Body, Deliver2, Notice2, ErrorFrame2, StatusReply, DaemonFrame;
|
|
32348
32396
|
var init_frames = __esm({
|
|
32349
32397
|
"../bus-ipc/src/frames.ts"() {
|
|
32350
32398
|
"use strict";
|
|
@@ -32361,10 +32409,11 @@ var init_frames = __esm({
|
|
|
32361
32409
|
late = { late: external_exports.array(external_exports.string().min(1)).optional() };
|
|
32362
32410
|
isWellFormed2 = (s) => s.isWellFormed();
|
|
32363
32411
|
WELL_FORMED = { message: "text is not well-formed unicode" };
|
|
32364
|
-
CLIENT_VERSION = true ? "0.
|
|
32412
|
+
CLIENT_VERSION = true ? "0.125.0" : "0.0.0";
|
|
32365
32413
|
clientVersion = {
|
|
32366
32414
|
client_version: external_exports.string().min(1).max(64).optional()
|
|
32367
32415
|
};
|
|
32416
|
+
ADAPTER_CAPS = { mailbox: "mailbox" };
|
|
32368
32417
|
Hello2 = external_exports.object({
|
|
32369
32418
|
...base2,
|
|
32370
32419
|
...clientVersion,
|
|
@@ -32379,6 +32428,8 @@ var init_frames = __esm({
|
|
|
32379
32428
|
*/
|
|
32380
32429
|
cwd: external_exports.string().min(1).max(4096).optional(),
|
|
32381
32430
|
proposed_name: external_exports.string().min(1).max(64).refine(isWellFormed2, WELL_FORMED).optional(),
|
|
32431
|
+
/** What this adapter can decode (ADAPTER_CAPS); absent means none. */
|
|
32432
|
+
caps: external_exports.array(external_exports.string().max(32)).max(16).optional(),
|
|
32382
32433
|
/** What the harness told the adapter, re-checked by the daemon. */
|
|
32383
32434
|
attest: external_exports.object({
|
|
32384
32435
|
session_id: external_exports.string().optional(),
|
|
@@ -32474,21 +32525,34 @@ var init_frames = __esm({
|
|
|
32474
32525
|
Ack2,
|
|
32475
32526
|
SetStatus
|
|
32476
32527
|
]);
|
|
32528
|
+
ConfigFile = external_exports.object({
|
|
32529
|
+
file: external_exports.string(),
|
|
32530
|
+
state: external_exports.enum(["refused", "noted"]),
|
|
32531
|
+
reason: external_exports.string(),
|
|
32532
|
+
fix: external_exports.string()
|
|
32533
|
+
});
|
|
32477
32534
|
AgentInfo = external_exports.object({
|
|
32478
32535
|
name: external_exports.string(),
|
|
32479
32536
|
namespace: external_exports.string(),
|
|
32480
32537
|
kind: KIND_TOKEN,
|
|
32481
32538
|
/** `state === "live"`; kept for older adapters. */
|
|
32482
32539
|
live: external_exports.boolean(),
|
|
32483
|
-
/**
|
|
32484
|
-
|
|
32540
|
+
/**
|
|
32541
|
+
* Roster entries only: `queued` means the agent's machine is disconnected;
|
|
32542
|
+
* `away` (#1295) means it is closed and its mailbox is kept, with `since`.
|
|
32543
|
+
*/
|
|
32544
|
+
state: external_exports.enum(["live", "queued", "away"]).optional(),
|
|
32545
|
+
/** When an `away` agent closed. */
|
|
32546
|
+
since: IsoTimeSchema.optional(),
|
|
32485
32547
|
global: external_exports.boolean(),
|
|
32486
32548
|
/** The agent's machine (B13); absent when the hub is older. */
|
|
32487
32549
|
machine_label: MachineLabelSchema.optional(),
|
|
32488
32550
|
/** The agent's own status claim, from the hub. */
|
|
32489
32551
|
status: StatusStateSchema.optional(),
|
|
32490
32552
|
status_label: StatusLabelSchema.optional(),
|
|
32491
|
-
status_at: IsoTimeSchema.optional()
|
|
32553
|
+
status_at: IsoTimeSchema.optional(),
|
|
32554
|
+
/** `self` with `row` only: config files refused or noted. Older adapters ignore it. */
|
|
32555
|
+
config_files: external_exports.array(ConfigFile).optional()
|
|
32492
32556
|
});
|
|
32493
32557
|
Welcome = external_exports.object({
|
|
32494
32558
|
...base2,
|
|
@@ -32599,6 +32663,8 @@ var init_frames = __esm({
|
|
|
32599
32663
|
)
|
|
32600
32664
|
})
|
|
32601
32665
|
),
|
|
32666
|
+
/** Config files refused or noted (#1527). Absent from older daemons, and when there are none. */
|
|
32667
|
+
config_files: external_exports.array(ConfigFile).optional(),
|
|
32602
32668
|
/** Messages sent from this machine the hub delivered after the 5 s window, within the last hour. */
|
|
32603
32669
|
late: external_exports.array(
|
|
32604
32670
|
external_exports.object({
|
|
@@ -32984,7 +33050,7 @@ function statusSaysText(row, now = Date.now()) {
|
|
|
32984
33050
|
}
|
|
32985
33051
|
function rosterLine(a, now = Date.now()) {
|
|
32986
33052
|
const says = statusSaysText(a, now);
|
|
32987
|
-
return `- ${a.name} (${displayKind(a.kind)}, ${a.namespace}${typeof a.machine_label === "string" && a.machine_label ? `, ${a.machine_label}` : ""})${a.queued ? " (queued)" : ""}${says ? ` ${says}` : ""}`;
|
|
33053
|
+
return `- ${a.name} (${displayKind(a.kind)}, ${a.namespace}${typeof a.machine_label === "string" && a.machine_label ? `, ${a.machine_label}` : ""})${a.away !== void 0 ? a.away ? ` (away since ${awayTime(a.away)})` : " (away)" : a.queued ? " (queued)" : ""}${says ? ` ${says}` : ""}`;
|
|
32988
33054
|
}
|
|
32989
33055
|
function selfText(agent) {
|
|
32990
33056
|
if (!agent) return JSON.stringify(agent, null, 2);
|
|
@@ -32998,7 +33064,7 @@ function selfText(agent) {
|
|
|
32998
33064
|
};
|
|
32999
33065
|
return JSON.stringify(shown2, null, 2);
|
|
33000
33066
|
}
|
|
33001
|
-
var MAX_COLS, RETAIN, MB, refusals, quoted, TERMINAL_CONTROLS, CUT_OFF, stripTerminalControls, KIND_CHARS, displayKind, neutralizeBody, deliveredText, oversizedText, INVISIBLES, EXCERPT_CHARS, STATUS_COPY, BAD_LABEL_CHARS2, cleanStatusLabel, statusLabelTooLong, statusSetText, earlierStatusText, STATUS_STALE_MS, agoText, displayLabel, replyGoneText;
|
|
33067
|
+
var MAX_COLS, RETAIN, MB, refusals, quoted, TERMINAL_CONTROLS, CUT_OFF, stripTerminalControls, KIND_CHARS, displayKind, neutralizeBody, deliveredText, oversizedText, INVISIBLES, EXCERPT_CHARS, STATUS_COPY, BAD_LABEL_CHARS2, cleanStatusLabel, statusLabelTooLong, statusSetText, earlierStatusText, STATUS_STALE_MS, agoText, displayLabel, awayTime, replyGoneText;
|
|
33002
33068
|
var init_copy = __esm({
|
|
33003
33069
|
"../bus-ipc/src/copy.ts"() {
|
|
33004
33070
|
"use strict";
|
|
@@ -33019,6 +33085,16 @@ var init_copy = __esm({
|
|
|
33019
33085
|
`${MAILBOX_PENDING_CAP} messages are already waiting.`,
|
|
33020
33086
|
"Send again once some are delivered or expire."
|
|
33021
33087
|
],
|
|
33088
|
+
// #1295: the cap sockets' inbox_full (pending count, bytes or the hub total).
|
|
33089
|
+
mailbox_full: [
|
|
33090
|
+
"Its mailbox is full.",
|
|
33091
|
+
"Send again once it has read some, or message another agent."
|
|
33092
|
+
],
|
|
33093
|
+
// #1295: a name only held after a move; no one reads it.
|
|
33094
|
+
reserved_name: [
|
|
33095
|
+
"No one has that name now; it was left by an agent that moved.",
|
|
33096
|
+
"Run the oa_bus list_agents tool to find who has it now."
|
|
33097
|
+
],
|
|
33022
33098
|
too_large: [
|
|
33023
33099
|
`It is too large to send (the limit is ${MB}).`,
|
|
33024
33100
|
"Send a shorter message."
|
|
@@ -33099,6 +33175,10 @@ ${neutralizeBody(m.body)}`;
|
|
|
33099
33175
|
return `${Math.round(ms / 864e5)} d ago`;
|
|
33100
33176
|
};
|
|
33101
33177
|
displayLabel = (label) => [...cleanStatusLabel(stripTerminalControls(label).replace(INVISIBLES, ""))].slice(0, LIMITS.maxLabelChars).join("").replaceAll('"', "'");
|
|
33178
|
+
awayTime = (iso) => {
|
|
33179
|
+
const t = Date.parse(iso);
|
|
33180
|
+
return Number.isNaN(t) ? iso : `${new Date(t).toISOString().slice(0, 16).replace("T", " ")} UTC`;
|
|
33181
|
+
};
|
|
33102
33182
|
replyGoneText = (name) => `[oa-bus] Information: your reply to ${name} was not sent. The agent that wrote to you as ${name} is gone, or wrote over an hour ago, and another agent may hold that name now. Use the oa_bus list_agents and send_message tools to reach the agent you mean.`;
|
|
33103
33183
|
}
|
|
33104
33184
|
});
|
|
@@ -33441,7 +33521,16 @@ async function run(name, args, request) {
|
|
|
33441
33521
|
if (r.type !== "roster") return failed(r);
|
|
33442
33522
|
const now = Date.now();
|
|
33443
33523
|
return text(
|
|
33444
|
-
r.agents.length ? r.agents.map(
|
|
33524
|
+
r.agents.length ? r.agents.map(
|
|
33525
|
+
(a) => rosterLine(
|
|
33526
|
+
{
|
|
33527
|
+
...a,
|
|
33528
|
+
queued: queued(a),
|
|
33529
|
+
away: a.state === "away" ? a.since ?? "" : void 0
|
|
33530
|
+
},
|
|
33531
|
+
now
|
|
33532
|
+
)
|
|
33533
|
+
).join("\n") : "No agents in your namespace."
|
|
33445
33534
|
);
|
|
33446
33535
|
}
|
|
33447
33536
|
if (name === "send_message") {
|
|
@@ -33669,6 +33758,7 @@ function codexHello(call, pid, ppid) {
|
|
|
33669
33758
|
pid,
|
|
33670
33759
|
...call.cwd ? { cwd: call.cwd } : {},
|
|
33671
33760
|
proposed_name: "codex",
|
|
33761
|
+
caps: [ADAPTER_CAPS.mailbox],
|
|
33672
33762
|
codex: {
|
|
33673
33763
|
thread_id: call.threadId,
|
|
33674
33764
|
call_id: call.callId,
|
|
@@ -33911,6 +34001,7 @@ function sessionHello(session, pid, cwd) {
|
|
|
33911
34001
|
pid,
|
|
33912
34002
|
cwd,
|
|
33913
34003
|
proposed_name: fitName(session.name, 64) || void 0,
|
|
34004
|
+
caps: [ADAPTER_CAPS.mailbox],
|
|
33914
34005
|
attest: {
|
|
33915
34006
|
session_id: session.sessionId,
|
|
33916
34007
|
socket_path: session.socketPath ?? void 0
|
|
@@ -33989,8 +34080,8 @@ function shortSocketDir(home2) {
|
|
|
33989
34080
|
);
|
|
33990
34081
|
}
|
|
33991
34082
|
function daemonSocketPath(home2) {
|
|
33992
|
-
const
|
|
33993
|
-
return fits(
|
|
34083
|
+
const plain3 = join2(canonicalHome(home2), "daemon.sock");
|
|
34084
|
+
return fits(plain3) ? plain3 : join2(shortSocketDir(home2), "daemon.sock");
|
|
33994
34085
|
}
|
|
33995
34086
|
function claudeReturnDir(home2) {
|
|
33996
34087
|
const dir = join2(canonicalHome(home2), "claude-return");
|
|
@@ -37803,6 +37894,7 @@ async function handleToolCall(input2) {
|
|
|
37803
37894
|
pid: process.pid,
|
|
37804
37895
|
cwd: session.directory,
|
|
37805
37896
|
proposed_name: nameOf(session.title),
|
|
37897
|
+
caps: [ADAPTER_CAPS.mailbox],
|
|
37806
37898
|
attest: { session_id: sessionId }
|
|
37807
37899
|
});
|
|
37808
37900
|
let client;
|
|
@@ -38088,6 +38180,33 @@ var init_codex_main = __esm({
|
|
|
38088
38180
|
}
|
|
38089
38181
|
});
|
|
38090
38182
|
|
|
38183
|
+
// ../shared/src/harness-skills.ts
|
|
38184
|
+
var harnessSkills = {
|
|
38185
|
+
claude: {
|
|
38186
|
+
skillPath: "~/.claude/skills/open-artifacts/SKILL.md",
|
|
38187
|
+
busToolName: (tool) => `mcp__oa_bus__${tool}`
|
|
38188
|
+
},
|
|
38189
|
+
// CODEX_TOOL_NAMESPACE = "mcp__oa_bus" (packages/bus-daemon/src/codex-attest.ts).
|
|
38190
|
+
codex: {
|
|
38191
|
+
skillPath: "~/.codex/AGENTS.md",
|
|
38192
|
+
busToolName: (tool) => `mcp__oa_bus__${tool}`,
|
|
38193
|
+
agentsMd: true
|
|
38194
|
+
},
|
|
38195
|
+
opencode: {
|
|
38196
|
+
skillPath: "~/.config/opencode/skills/open-artifacts/SKILL.md",
|
|
38197
|
+
busToolName: (tool) => `oa_bus_${tool}`
|
|
38198
|
+
},
|
|
38199
|
+
pi: {
|
|
38200
|
+
skillPath: "~/.agents/skills/open-artifacts/SKILL.md"
|
|
38201
|
+
},
|
|
38202
|
+
omp: {
|
|
38203
|
+
skillPath: "~/.agents/skills/open-artifacts/SKILL.md"
|
|
38204
|
+
}
|
|
38205
|
+
};
|
|
38206
|
+
|
|
38207
|
+
// src/harness-table.ts
|
|
38208
|
+
var harnessNames = Object.keys(harnessSkills);
|
|
38209
|
+
|
|
38091
38210
|
// src/main.ts
|
|
38092
38211
|
import { resolve as resolve7 } from "node:path";
|
|
38093
38212
|
|
|
@@ -38097,7 +38216,7 @@ import { join as join15 } from "node:path";
|
|
|
38097
38216
|
|
|
38098
38217
|
// ../bus-daemon/src/index.ts
|
|
38099
38218
|
init_src3();
|
|
38100
|
-
import { lstatSync as lstatSync6, writeFileSync as writeFileSync4 } from "node:fs";
|
|
38219
|
+
import { lstatSync as lstatSync6, realpathSync as realpathSync6, writeFileSync as writeFileSync4 } from "node:fs";
|
|
38101
38220
|
import { basename as basename5, isAbsolute as isAbsolute5, join as join11 } from "node:path";
|
|
38102
38221
|
|
|
38103
38222
|
// ../bus-adapter-opencode/src/version.ts
|
|
@@ -38949,7 +39068,7 @@ function sessionFiles(dir) {
|
|
|
38949
39068
|
return out;
|
|
38950
39069
|
}
|
|
38951
39070
|
var alive = (s, deps) => deps.isRunning(s.pid) && deps.procStart(s.pid, s.stamp) === s.procStart;
|
|
38952
|
-
var strip = ({
|
|
39071
|
+
var strip = ({ stamp: _, ...s }) => s;
|
|
38953
39072
|
function liveClaudeSessions(deps) {
|
|
38954
39073
|
return sessionFiles(deps.dir).filter((s) => alive(s, deps)).map(strip);
|
|
38955
39074
|
}
|
|
@@ -39081,6 +39200,314 @@ function defaultOpenSessions() {
|
|
|
39081
39200
|
});
|
|
39082
39201
|
}
|
|
39083
39202
|
|
|
39203
|
+
// ../bus-daemon/src/config-issues.ts
|
|
39204
|
+
init_src();
|
|
39205
|
+
import { realpathSync as realpathSync4 } from "node:fs";
|
|
39206
|
+
import { dirname as dirname4, join as join8 } from "node:path";
|
|
39207
|
+
|
|
39208
|
+
// ../bus-daemon/src/global.ts
|
|
39209
|
+
import { randomBytes } from "node:crypto";
|
|
39210
|
+
import {
|
|
39211
|
+
chmodSync as chmodSync3,
|
|
39212
|
+
closeSync as closeSync3,
|
|
39213
|
+
lstatSync as lstatSync4,
|
|
39214
|
+
mkdirSync as mkdirSync4,
|
|
39215
|
+
openSync as openSync3,
|
|
39216
|
+
realpathSync as realpathSync3,
|
|
39217
|
+
renameSync as renameSync2,
|
|
39218
|
+
statSync as statSync6,
|
|
39219
|
+
unlinkSync,
|
|
39220
|
+
writeSync
|
|
39221
|
+
} from "node:fs";
|
|
39222
|
+
import { dirname as dirname3, isAbsolute as isAbsolute3, join as join7, sep } from "node:path";
|
|
39223
|
+
|
|
39224
|
+
// ../bus-daemon/src/own-file.ts
|
|
39225
|
+
import {
|
|
39226
|
+
closeSync as closeSync2,
|
|
39227
|
+
constants,
|
|
39228
|
+
fstatSync as fstatSync2,
|
|
39229
|
+
openSync as openSync2,
|
|
39230
|
+
readFileSync as readFileSync6
|
|
39231
|
+
} from "node:fs";
|
|
39232
|
+
import { userInfo } from "node:os";
|
|
39233
|
+
function isPrivateGroup(gid, user, read = () => readFileSync6("/etc/group", "utf8"), readPasswd = () => readFileSync6("/etc/passwd", "utf8")) {
|
|
39234
|
+
let text3;
|
|
39235
|
+
let passwd;
|
|
39236
|
+
try {
|
|
39237
|
+
text3 = read();
|
|
39238
|
+
passwd = readPasswd();
|
|
39239
|
+
} catch {
|
|
39240
|
+
return false;
|
|
39241
|
+
}
|
|
39242
|
+
for (const line of passwd.split("\n")) {
|
|
39243
|
+
const f = line.split(":");
|
|
39244
|
+
if (f[3] === String(gid) && f[0] !== user) return false;
|
|
39245
|
+
}
|
|
39246
|
+
for (const line of text3.split("\n")) {
|
|
39247
|
+
const [name, , id, members2] = line.split(":");
|
|
39248
|
+
if (id === String(gid))
|
|
39249
|
+
return name === user && (members2 ?? "").trim() === "";
|
|
39250
|
+
}
|
|
39251
|
+
return false;
|
|
39252
|
+
}
|
|
39253
|
+
var ownGroup = () => ({
|
|
39254
|
+
gid: process.getgid?.(),
|
|
39255
|
+
isPrivate: (gid) => {
|
|
39256
|
+
if (process.platform !== "linux") return false;
|
|
39257
|
+
try {
|
|
39258
|
+
return isPrivateGroup(gid, userInfo().username);
|
|
39259
|
+
} catch {
|
|
39260
|
+
return false;
|
|
39261
|
+
}
|
|
39262
|
+
}
|
|
39263
|
+
});
|
|
39264
|
+
function readOwnFile(file2, uid = process.getuid?.(), opts = {}) {
|
|
39265
|
+
let fd;
|
|
39266
|
+
try {
|
|
39267
|
+
fd = openSync2(
|
|
39268
|
+
file2,
|
|
39269
|
+
constants.O_RDONLY | (constants.O_NOFOLLOW ?? 0) | (constants.O_NONBLOCK ?? 0)
|
|
39270
|
+
);
|
|
39271
|
+
} catch (e) {
|
|
39272
|
+
const code2 = e.code;
|
|
39273
|
+
if (code2 === "ENOENT" || code2 === "ENOTDIR") return { state: "none" };
|
|
39274
|
+
return {
|
|
39275
|
+
state: "unsafe",
|
|
39276
|
+
why: code2 === "ELOOP" ? "is a symlink" : `cannot be read (${code2})`
|
|
39277
|
+
};
|
|
39278
|
+
}
|
|
39279
|
+
try {
|
|
39280
|
+
const st = fstatSync2(fd);
|
|
39281
|
+
if (!st.isFile()) return { state: "unsafe", why: "is not a regular file" };
|
|
39282
|
+
if (uid !== void 0 && st.uid !== uid)
|
|
39283
|
+
return { state: "unsafe", why: "belongs to another user" };
|
|
39284
|
+
if (opts.allowGroupWrite) {
|
|
39285
|
+
if (st.mode & 2)
|
|
39286
|
+
return { state: "unsafe", why: "is writable by everyone" };
|
|
39287
|
+
let note;
|
|
39288
|
+
if (st.mode & 16) {
|
|
39289
|
+
const g = opts.group ?? ownGroup();
|
|
39290
|
+
if (st.gid !== g.gid || !g.isPrivate(st.gid))
|
|
39291
|
+
return {
|
|
39292
|
+
state: "unsafe",
|
|
39293
|
+
why: "is writable by a group others share"
|
|
39294
|
+
};
|
|
39295
|
+
note = "is writable by its group";
|
|
39296
|
+
}
|
|
39297
|
+
return {
|
|
39298
|
+
state: "ok",
|
|
39299
|
+
text: readFileSync6(fd, "utf8"),
|
|
39300
|
+
...note ? { note } : {}
|
|
39301
|
+
};
|
|
39302
|
+
}
|
|
39303
|
+
if (st.mode & 18)
|
|
39304
|
+
return { state: "unsafe", why: "is writable by others" };
|
|
39305
|
+
return { state: "ok", text: readFileSync6(fd, "utf8") };
|
|
39306
|
+
} catch (e) {
|
|
39307
|
+
return {
|
|
39308
|
+
state: "unsafe",
|
|
39309
|
+
why: `cannot be read (${e.code ?? String(e)})`
|
|
39310
|
+
};
|
|
39311
|
+
} finally {
|
|
39312
|
+
closeSync2(fd);
|
|
39313
|
+
}
|
|
39314
|
+
}
|
|
39315
|
+
|
|
39316
|
+
// ../bus-daemon/src/global.ts
|
|
39317
|
+
var globalFile = (h = home()) => join7(h, "global.json");
|
|
39318
|
+
var canonicalPath = (path) => realpathSync3.native(path);
|
|
39319
|
+
function readGlobalDirs(file2 = globalFile()) {
|
|
39320
|
+
const own2 = readOwnFile(file2);
|
|
39321
|
+
if (own2.state === "none") return { dirs: [] };
|
|
39322
|
+
if (own2.state === "unsafe") return { dirs: [], error: own2.why };
|
|
39323
|
+
try {
|
|
39324
|
+
const raw = JSON.parse(own2.text);
|
|
39325
|
+
const dirs = raw?.dirs;
|
|
39326
|
+
if (!Array.isArray(raw) && Array.isArray(dirs) && dirs.every((d) => typeof d === "string" && isAbsolute3(d)))
|
|
39327
|
+
return { dirs };
|
|
39328
|
+
} catch {
|
|
39329
|
+
}
|
|
39330
|
+
return { dirs: [], error: "is not valid JSON" };
|
|
39331
|
+
}
|
|
39332
|
+
var idOf = (path, follow = true) => {
|
|
39333
|
+
try {
|
|
39334
|
+
const st = follow ? statSync6(path) : lstatSync4(path);
|
|
39335
|
+
return st.isDirectory() ? `${st.dev}:${st.ino}` : void 0;
|
|
39336
|
+
} catch {
|
|
39337
|
+
return void 0;
|
|
39338
|
+
}
|
|
39339
|
+
};
|
|
39340
|
+
var loose = (p) => p.normalize("NFC").toLowerCase();
|
|
39341
|
+
function isGlobalDir(dir, dirs, onStale) {
|
|
39342
|
+
let real2;
|
|
39343
|
+
try {
|
|
39344
|
+
real2 = realpathSync3(dir);
|
|
39345
|
+
} catch {
|
|
39346
|
+
return false;
|
|
39347
|
+
}
|
|
39348
|
+
const near = loose(real2);
|
|
39349
|
+
const ids = /* @__PURE__ */ new Set();
|
|
39350
|
+
for (const entry of dirs) {
|
|
39351
|
+
const e = loose(entry);
|
|
39352
|
+
const prefix = e.endsWith(sep) ? e : `${e}${sep}`;
|
|
39353
|
+
if (near !== e && !near.startsWith(prefix)) continue;
|
|
39354
|
+
let still;
|
|
39355
|
+
try {
|
|
39356
|
+
still = realpathSync3.native(entry);
|
|
39357
|
+
} catch {
|
|
39358
|
+
}
|
|
39359
|
+
if (still !== entry) {
|
|
39360
|
+
if (still !== void 0) onStale?.(entry);
|
|
39361
|
+
continue;
|
|
39362
|
+
}
|
|
39363
|
+
const id = idOf(entry, false);
|
|
39364
|
+
if (id !== void 0) ids.add(id);
|
|
39365
|
+
}
|
|
39366
|
+
if (ids.size === 0) return false;
|
|
39367
|
+
for (let d = real2; ; d = dirname3(d)) {
|
|
39368
|
+
const id = idOf(d);
|
|
39369
|
+
if (id !== void 0 && ids.has(id)) return true;
|
|
39370
|
+
if (dirname3(d) === d) return false;
|
|
39371
|
+
}
|
|
39372
|
+
}
|
|
39373
|
+
function sameDir(entry, dir) {
|
|
39374
|
+
try {
|
|
39375
|
+
if (realpathSync3.native(entry) !== entry) return false;
|
|
39376
|
+
} catch {
|
|
39377
|
+
return false;
|
|
39378
|
+
}
|
|
39379
|
+
const id = idOf(entry, false);
|
|
39380
|
+
return id !== void 0 && id === idOf(dir);
|
|
39381
|
+
}
|
|
39382
|
+
function writeGlobalDirs(dirs, h = home()) {
|
|
39383
|
+
mkdirSync4(h, { recursive: true, mode: 448 });
|
|
39384
|
+
chmodSync3(h, 448);
|
|
39385
|
+
const tmp = join7(h, `.global.json.${randomBytes(8).toString("hex")}.tmp`);
|
|
39386
|
+
const fd = openSync3(tmp, "wx", 384);
|
|
39387
|
+
try {
|
|
39388
|
+
writeSync(fd, `${JSON.stringify({ dirs }, null, 2)}
|
|
39389
|
+
`);
|
|
39390
|
+
} catch (e) {
|
|
39391
|
+
closeSync3(fd);
|
|
39392
|
+
unlinkSync(tmp);
|
|
39393
|
+
throw e;
|
|
39394
|
+
}
|
|
39395
|
+
closeSync3(fd);
|
|
39396
|
+
try {
|
|
39397
|
+
chmodSync3(tmp, 384);
|
|
39398
|
+
renameSync2(tmp, globalFile(h));
|
|
39399
|
+
} catch (e) {
|
|
39400
|
+
unlinkSync(tmp);
|
|
39401
|
+
throw e;
|
|
39402
|
+
}
|
|
39403
|
+
}
|
|
39404
|
+
|
|
39405
|
+
// ../bus-daemon/src/config-issues.ts
|
|
39406
|
+
var shq = (s) => `'${s.replace(/'/g, "'\\''")}'`;
|
|
39407
|
+
function fixFor(file2, why) {
|
|
39408
|
+
const q = shq(file2);
|
|
39409
|
+
if (why === "is writable by everyone") return `run chmod o-w ${q}`;
|
|
39410
|
+
if (why === "is writable by others") return `run chmod go-w ${q}`;
|
|
39411
|
+
if (why === "is writable by a group others share")
|
|
39412
|
+
return `run chmod g-w ${q}`;
|
|
39413
|
+
if (why === "belongs to another user")
|
|
39414
|
+
return `remove it (rm ${q}) or take it over (chown "$USER" ${q})`;
|
|
39415
|
+
if (why === "is a symlink" || why === "is not a regular file")
|
|
39416
|
+
return `remove it (rm ${q}), then save a regular file there`;
|
|
39417
|
+
if (why.startsWith("cannot be read")) return `run chmod u+r ${q}`;
|
|
39418
|
+
return `fix or remove ${q}`;
|
|
39419
|
+
}
|
|
39420
|
+
function configIssue(file2, own2, valid2 = true) {
|
|
39421
|
+
if (own2.state === "unsafe")
|
|
39422
|
+
return {
|
|
39423
|
+
file: file2,
|
|
39424
|
+
state: "refused",
|
|
39425
|
+
reason: own2.why,
|
|
39426
|
+
fix: fixFor(file2, own2.why)
|
|
39427
|
+
};
|
|
39428
|
+
if (own2.state === "ok" && !valid2)
|
|
39429
|
+
return {
|
|
39430
|
+
file: file2,
|
|
39431
|
+
state: "refused",
|
|
39432
|
+
reason: "is not a valid .oa-bus.json",
|
|
39433
|
+
fix: `edit ${shq(file2)} to valid JSON, or remove it`
|
|
39434
|
+
};
|
|
39435
|
+
if (own2.state === "ok" && own2.note)
|
|
39436
|
+
return {
|
|
39437
|
+
file: file2,
|
|
39438
|
+
state: "noted",
|
|
39439
|
+
reason: own2.note,
|
|
39440
|
+
fix: `optional: run chmod g-w ${shq(file2)}`
|
|
39441
|
+
};
|
|
39442
|
+
return void 0;
|
|
39443
|
+
}
|
|
39444
|
+
function isValidConfig(text3) {
|
|
39445
|
+
try {
|
|
39446
|
+
return BusConfigSchema.safeParse(JSON.parse(text3)).success;
|
|
39447
|
+
} catch {
|
|
39448
|
+
return false;
|
|
39449
|
+
}
|
|
39450
|
+
}
|
|
39451
|
+
function inspectConfig(file2, uid, group) {
|
|
39452
|
+
const own2 = readOwnFile(file2, uid, {
|
|
39453
|
+
allowGroupWrite: true,
|
|
39454
|
+
...group ? { group } : {}
|
|
39455
|
+
});
|
|
39456
|
+
return configIssue(file2, own2, own2.state !== "ok" || isValidConfig(own2.text));
|
|
39457
|
+
}
|
|
39458
|
+
function inspectGlobal(file2 = globalFile()) {
|
|
39459
|
+
const { error: error62 } = readGlobalDirs(file2);
|
|
39460
|
+
if (error62 === void 0) return void 0;
|
|
39461
|
+
return {
|
|
39462
|
+
file: file2,
|
|
39463
|
+
state: "refused",
|
|
39464
|
+
reason: error62,
|
|
39465
|
+
fix: error62 === "is not valid JSON" ? `remove it (rm ${shq(file2)}), then run oa-bus global add <dir> again` : fixFor(file2, error62)
|
|
39466
|
+
};
|
|
39467
|
+
}
|
|
39468
|
+
var ConfigIssues = class {
|
|
39469
|
+
#files = /* @__PURE__ */ new Map();
|
|
39470
|
+
/** Records the result of reading `file` (undefined: it is fine now). */
|
|
39471
|
+
set(file2, uid, issue2, group) {
|
|
39472
|
+
if (issue2) this.#files.set(file2, { uid, group });
|
|
39473
|
+
else this.#files.delete(file2);
|
|
39474
|
+
}
|
|
39475
|
+
/** Every tracked file, re-read now; `within` keeps only those at these paths. */
|
|
39476
|
+
list(within) {
|
|
39477
|
+
const out = [];
|
|
39478
|
+
for (const [file2, { uid, group }] of [...this.#files]) {
|
|
39479
|
+
if (within && !within.has(file2)) continue;
|
|
39480
|
+
const issue2 = inspectConfig(file2, uid, group);
|
|
39481
|
+
if (issue2) out.push(issue2);
|
|
39482
|
+
else this.#files.delete(file2);
|
|
39483
|
+
}
|
|
39484
|
+
return out;
|
|
39485
|
+
}
|
|
39486
|
+
};
|
|
39487
|
+
function scanConfigFiles(cwd, opts = {}) {
|
|
39488
|
+
const uid = opts.uid ?? process.getuid?.();
|
|
39489
|
+
const out = [];
|
|
39490
|
+
let real2 = cwd;
|
|
39491
|
+
try {
|
|
39492
|
+
real2 = realpathSync4(cwd);
|
|
39493
|
+
} catch {
|
|
39494
|
+
}
|
|
39495
|
+
for (const file2 of configPaths(real2)) {
|
|
39496
|
+
const issue2 = inspectConfig(file2, uid, opts.group);
|
|
39497
|
+
if (issue2) out.push(issue2);
|
|
39498
|
+
}
|
|
39499
|
+
const g = inspectGlobal(opts.globalFile);
|
|
39500
|
+
if (g) out.push(g);
|
|
39501
|
+
return out;
|
|
39502
|
+
}
|
|
39503
|
+
function configPaths(cwd) {
|
|
39504
|
+
const out = [];
|
|
39505
|
+
for (let dir = cwd; ; dir = dirname4(dir)) {
|
|
39506
|
+
out.push(join8(dir, CONFIG_FILE));
|
|
39507
|
+
if (dirname4(dir) === dir) return out;
|
|
39508
|
+
}
|
|
39509
|
+
}
|
|
39510
|
+
|
|
39084
39511
|
// ../bus-daemon/src/deliver.ts
|
|
39085
39512
|
init_src2();
|
|
39086
39513
|
init_src();
|
|
@@ -39510,7 +39937,9 @@ var HubConnection = class {
|
|
|
39510
39937
|
machine_label: this.opts.label,
|
|
39511
39938
|
client_version: this.opts.version,
|
|
39512
39939
|
// Reply ids: the hub then names each sender's agent (deliver.from_id).
|
|
39513
|
-
|
|
39940
|
+
// Mailboxes: the hub then sends queued/since, away rows and the new
|
|
39941
|
+
// refusals, and honours agent_up.replaces (#1295).
|
|
39942
|
+
caps: [BUS_CAPS.ids, BUS_CAPS.mailbox]
|
|
39514
39943
|
});
|
|
39515
39944
|
this.#guard("sessions", () => {
|
|
39516
39945
|
this.send({
|
|
@@ -39592,156 +40021,8 @@ function defaultBackoff(attempt) {
|
|
|
39592
40021
|
// ../bus-daemon/src/namespace.ts
|
|
39593
40022
|
init_src();
|
|
39594
40023
|
import { execFileSync as execFileSync4 } from "node:child_process";
|
|
39595
|
-
import { realpathSync as
|
|
39596
|
-
import { basename as basename4,
|
|
39597
|
-
|
|
39598
|
-
// ../bus-daemon/src/global.ts
|
|
39599
|
-
import { randomBytes } from "node:crypto";
|
|
39600
|
-
import {
|
|
39601
|
-
chmodSync as chmodSync3,
|
|
39602
|
-
closeSync as closeSync3,
|
|
39603
|
-
lstatSync as lstatSync4,
|
|
39604
|
-
mkdirSync as mkdirSync4,
|
|
39605
|
-
openSync as openSync3,
|
|
39606
|
-
realpathSync as realpathSync3,
|
|
39607
|
-
renameSync as renameSync2,
|
|
39608
|
-
statSync as statSync6,
|
|
39609
|
-
unlinkSync,
|
|
39610
|
-
writeSync
|
|
39611
|
-
} from "node:fs";
|
|
39612
|
-
import { dirname as dirname3, isAbsolute as isAbsolute3, join as join7, sep } from "node:path";
|
|
39613
|
-
|
|
39614
|
-
// ../bus-daemon/src/own-file.ts
|
|
39615
|
-
import {
|
|
39616
|
-
closeSync as closeSync2,
|
|
39617
|
-
constants,
|
|
39618
|
-
fstatSync as fstatSync2,
|
|
39619
|
-
openSync as openSync2,
|
|
39620
|
-
readFileSync as readFileSync6
|
|
39621
|
-
} from "node:fs";
|
|
39622
|
-
function readOwnFile(file2, uid = process.getuid?.()) {
|
|
39623
|
-
let fd;
|
|
39624
|
-
try {
|
|
39625
|
-
fd = openSync2(
|
|
39626
|
-
file2,
|
|
39627
|
-
constants.O_RDONLY | (constants.O_NOFOLLOW ?? 0) | (constants.O_NONBLOCK ?? 0)
|
|
39628
|
-
);
|
|
39629
|
-
} catch (e) {
|
|
39630
|
-
const code2 = e.code;
|
|
39631
|
-
if (code2 === "ENOENT" || code2 === "ENOTDIR") return { state: "none" };
|
|
39632
|
-
return {
|
|
39633
|
-
state: "unsafe",
|
|
39634
|
-
why: code2 === "ELOOP" ? "is a symlink" : `cannot be read (${code2})`
|
|
39635
|
-
};
|
|
39636
|
-
}
|
|
39637
|
-
try {
|
|
39638
|
-
const st = fstatSync2(fd);
|
|
39639
|
-
if (!st.isFile()) return { state: "unsafe", why: "is not a regular file" };
|
|
39640
|
-
if (uid !== void 0 && st.uid !== uid)
|
|
39641
|
-
return { state: "unsafe", why: "belongs to another user" };
|
|
39642
|
-
if (st.mode & 18)
|
|
39643
|
-
return { state: "unsafe", why: "is writable by others" };
|
|
39644
|
-
return { state: "ok", text: readFileSync6(fd, "utf8") };
|
|
39645
|
-
} catch (e) {
|
|
39646
|
-
return {
|
|
39647
|
-
state: "unsafe",
|
|
39648
|
-
why: `cannot be read (${e.code ?? String(e)})`
|
|
39649
|
-
};
|
|
39650
|
-
} finally {
|
|
39651
|
-
closeSync2(fd);
|
|
39652
|
-
}
|
|
39653
|
-
}
|
|
39654
|
-
|
|
39655
|
-
// ../bus-daemon/src/global.ts
|
|
39656
|
-
var globalFile = (h = home()) => join7(h, "global.json");
|
|
39657
|
-
var canonicalPath = (path) => realpathSync3.native(path);
|
|
39658
|
-
function readGlobalDirs(file2 = globalFile()) {
|
|
39659
|
-
const own2 = readOwnFile(file2);
|
|
39660
|
-
if (own2.state === "none") return { dirs: [] };
|
|
39661
|
-
if (own2.state === "unsafe") return { dirs: [], error: own2.why };
|
|
39662
|
-
try {
|
|
39663
|
-
const raw = JSON.parse(own2.text);
|
|
39664
|
-
const dirs = raw?.dirs;
|
|
39665
|
-
if (!Array.isArray(raw) && Array.isArray(dirs) && dirs.every((d) => typeof d === "string" && isAbsolute3(d)))
|
|
39666
|
-
return { dirs };
|
|
39667
|
-
} catch {
|
|
39668
|
-
}
|
|
39669
|
-
return { dirs: [], error: "is not valid JSON" };
|
|
39670
|
-
}
|
|
39671
|
-
var idOf = (path, follow = true) => {
|
|
39672
|
-
try {
|
|
39673
|
-
const st = follow ? statSync6(path) : lstatSync4(path);
|
|
39674
|
-
return st.isDirectory() ? `${st.dev}:${st.ino}` : void 0;
|
|
39675
|
-
} catch {
|
|
39676
|
-
return void 0;
|
|
39677
|
-
}
|
|
39678
|
-
};
|
|
39679
|
-
var loose = (p) => p.normalize("NFC").toLowerCase();
|
|
39680
|
-
function isGlobalDir(dir, dirs, onStale) {
|
|
39681
|
-
let real2;
|
|
39682
|
-
try {
|
|
39683
|
-
real2 = realpathSync3(dir);
|
|
39684
|
-
} catch {
|
|
39685
|
-
return false;
|
|
39686
|
-
}
|
|
39687
|
-
const near = loose(real2);
|
|
39688
|
-
const ids = /* @__PURE__ */ new Set();
|
|
39689
|
-
for (const entry of dirs) {
|
|
39690
|
-
const e = loose(entry);
|
|
39691
|
-
const prefix = e.endsWith(sep) ? e : `${e}${sep}`;
|
|
39692
|
-
if (near !== e && !near.startsWith(prefix)) continue;
|
|
39693
|
-
let still;
|
|
39694
|
-
try {
|
|
39695
|
-
still = realpathSync3.native(entry);
|
|
39696
|
-
} catch {
|
|
39697
|
-
}
|
|
39698
|
-
if (still !== entry) {
|
|
39699
|
-
if (still !== void 0) onStale?.(entry);
|
|
39700
|
-
continue;
|
|
39701
|
-
}
|
|
39702
|
-
const id = idOf(entry, false);
|
|
39703
|
-
if (id !== void 0) ids.add(id);
|
|
39704
|
-
}
|
|
39705
|
-
if (ids.size === 0) return false;
|
|
39706
|
-
for (let d = real2; ; d = dirname3(d)) {
|
|
39707
|
-
const id = idOf(d);
|
|
39708
|
-
if (id !== void 0 && ids.has(id)) return true;
|
|
39709
|
-
if (dirname3(d) === d) return false;
|
|
39710
|
-
}
|
|
39711
|
-
}
|
|
39712
|
-
function sameDir(entry, dir) {
|
|
39713
|
-
try {
|
|
39714
|
-
if (realpathSync3.native(entry) !== entry) return false;
|
|
39715
|
-
} catch {
|
|
39716
|
-
return false;
|
|
39717
|
-
}
|
|
39718
|
-
const id = idOf(entry, false);
|
|
39719
|
-
return id !== void 0 && id === idOf(dir);
|
|
39720
|
-
}
|
|
39721
|
-
function writeGlobalDirs(dirs, h = home()) {
|
|
39722
|
-
mkdirSync4(h, { recursive: true, mode: 448 });
|
|
39723
|
-
chmodSync3(h, 448);
|
|
39724
|
-
const tmp = join7(h, `.global.json.${randomBytes(8).toString("hex")}.tmp`);
|
|
39725
|
-
const fd = openSync3(tmp, "wx", 384);
|
|
39726
|
-
try {
|
|
39727
|
-
writeSync(fd, `${JSON.stringify({ dirs }, null, 2)}
|
|
39728
|
-
`);
|
|
39729
|
-
} catch (e) {
|
|
39730
|
-
closeSync3(fd);
|
|
39731
|
-
unlinkSync(tmp);
|
|
39732
|
-
throw e;
|
|
39733
|
-
}
|
|
39734
|
-
closeSync3(fd);
|
|
39735
|
-
try {
|
|
39736
|
-
chmodSync3(tmp, 384);
|
|
39737
|
-
renameSync2(tmp, globalFile(h));
|
|
39738
|
-
} catch (e) {
|
|
39739
|
-
unlinkSync(tmp);
|
|
39740
|
-
throw e;
|
|
39741
|
-
}
|
|
39742
|
-
}
|
|
39743
|
-
|
|
39744
|
-
// ../bus-daemon/src/namespace.ts
|
|
40024
|
+
import { realpathSync as realpathSync5 } from "node:fs";
|
|
40025
|
+
import { basename as basename4, resolve as resolve2 } from "node:path";
|
|
39745
40026
|
var warned = /* @__PURE__ */ new Set();
|
|
39746
40027
|
var once = (deps, key2, msg) => {
|
|
39747
40028
|
if (warned.has(key2)) return;
|
|
@@ -39752,7 +40033,7 @@ function resolveNamespace(start, deps = {}) {
|
|
|
39752
40033
|
let cwd;
|
|
39753
40034
|
let missing2 = false;
|
|
39754
40035
|
try {
|
|
39755
|
-
cwd =
|
|
40036
|
+
cwd = realpathSync5(start);
|
|
39756
40037
|
} catch (e) {
|
|
39757
40038
|
if (!deps.allowMissing) throw e;
|
|
39758
40039
|
cwd = resolve2(start);
|
|
@@ -39811,12 +40092,16 @@ function readConfigs(cwd, deps) {
|
|
|
39811
40092
|
const uid = deps.uid ?? process.getuid?.();
|
|
39812
40093
|
const configs = [];
|
|
39813
40094
|
const asked = [];
|
|
39814
|
-
for (
|
|
39815
|
-
const
|
|
39816
|
-
|
|
40095
|
+
for (const file2 of configPaths(cwd)) {
|
|
40096
|
+
const own2 = readOwnFile(file2, uid, {
|
|
40097
|
+
allowGroupWrite: true,
|
|
40098
|
+
...deps.group ? { group: deps.group } : {}
|
|
40099
|
+
});
|
|
39817
40100
|
if (own2.state === "unsafe")
|
|
39818
40101
|
once(deps, file2, `ignoring ${file2}: it ${own2.why}`);
|
|
40102
|
+
let valid2 = true;
|
|
39819
40103
|
if (own2.state === "ok") {
|
|
40104
|
+
if (own2.note) once(deps, `note:${file2}`, `using ${file2}: it ${own2.note}`);
|
|
39820
40105
|
let parsed;
|
|
39821
40106
|
try {
|
|
39822
40107
|
parsed = BusConfigSchema.safeParse(JSON.parse(own2.text));
|
|
@@ -39825,15 +40110,18 @@ function readConfigs(cwd, deps) {
|
|
|
39825
40110
|
if (parsed?.success) {
|
|
39826
40111
|
configs.push(parsed.data);
|
|
39827
40112
|
if (parsed.data.global === true) asked.push(file2);
|
|
39828
|
-
} else
|
|
40113
|
+
} else {
|
|
40114
|
+
valid2 = false;
|
|
40115
|
+
deps.log?.(`ignoring invalid ${file2}`);
|
|
40116
|
+
}
|
|
39829
40117
|
}
|
|
39830
|
-
|
|
40118
|
+
deps.issues?.set(file2, uid, configIssue(file2, own2, valid2), deps.group);
|
|
39831
40119
|
}
|
|
39832
40120
|
return { cfg: mergeConfigs(configs), asked };
|
|
39833
40121
|
}
|
|
39834
40122
|
function nearestConfig(dir, deps = {}) {
|
|
39835
40123
|
try {
|
|
39836
|
-
return readConfigs(
|
|
40124
|
+
return readConfigs(realpathSync5(dir), deps).cfg;
|
|
39837
40125
|
} catch {
|
|
39838
40126
|
return {};
|
|
39839
40127
|
}
|
|
@@ -40058,6 +40346,7 @@ var Resends = class {
|
|
|
40058
40346
|
};
|
|
40059
40347
|
|
|
40060
40348
|
// ../bus-daemon/src/routes.ts
|
|
40349
|
+
init_src2();
|
|
40061
40350
|
init_src();
|
|
40062
40351
|
|
|
40063
40352
|
// ../bus-daemon/src/status.ts
|
|
@@ -40278,6 +40567,27 @@ var statusOf = (row) => Object.fromEntries(
|
|
|
40278
40567
|
(k) => row?.[k] === void 0 ? [] : [[k, row[k]]]
|
|
40279
40568
|
)
|
|
40280
40569
|
);
|
|
40570
|
+
var OLD_REASON = {
|
|
40571
|
+
mailbox_full: "inbox_full",
|
|
40572
|
+
reserved_name: "unknown_agent"
|
|
40573
|
+
};
|
|
40574
|
+
function forOldAdapter(f) {
|
|
40575
|
+
if (f.type === "roster")
|
|
40576
|
+
return {
|
|
40577
|
+
...f,
|
|
40578
|
+
agents: f.agents.filter((a) => a.state !== "away").map(({ since: _since, ...a }) => a)
|
|
40579
|
+
};
|
|
40580
|
+
if (f.type === "receipt") {
|
|
40581
|
+
const {
|
|
40582
|
+
queued: _q,
|
|
40583
|
+
since: _s,
|
|
40584
|
+
...r
|
|
40585
|
+
} = f;
|
|
40586
|
+
const reason = r.reason !== void 0 && r.reason in OLD_REASON ? OLD_REASON[r.reason] : r.reason;
|
|
40587
|
+
return { ...r, ...reason === void 0 ? {} : { reason } };
|
|
40588
|
+
}
|
|
40589
|
+
return f;
|
|
40590
|
+
}
|
|
40281
40591
|
function routeLocal(frame, hello, reply, ctx) {
|
|
40282
40592
|
const agent = ctx.agents.byRef(hello.agent_ref);
|
|
40283
40593
|
if (!agent)
|
|
@@ -40285,6 +40595,7 @@ function routeLocal(frame, hello, reply, ctx) {
|
|
|
40285
40595
|
const ref = agent.ref;
|
|
40286
40596
|
switch (frame.type) {
|
|
40287
40597
|
case "self": {
|
|
40598
|
+
const files = frame.row ? ctx.configFiles?.(agent.cwd) ?? [] : [];
|
|
40288
40599
|
const self = {
|
|
40289
40600
|
type: "agent",
|
|
40290
40601
|
agent: {
|
|
@@ -40292,7 +40603,8 @@ function routeLocal(frame, hello, reply, ctx) {
|
|
|
40292
40603
|
namespace: agent.namespace,
|
|
40293
40604
|
kind: agent.kind,
|
|
40294
40605
|
live: agent.live,
|
|
40295
|
-
global: agent.global
|
|
40606
|
+
global: agent.global,
|
|
40607
|
+
...files.length > 0 ? { config_files: files } : {}
|
|
40296
40608
|
}
|
|
40297
40609
|
};
|
|
40298
40610
|
const own2 = frame.row ? ctx.ownRow?.(ref) : void 0;
|
|
@@ -40354,7 +40666,8 @@ function routeLocal(frame, hello, reply, ctx) {
|
|
|
40354
40666
|
code: "bad_frame",
|
|
40355
40667
|
message: "the frame is not valid on the hub wire"
|
|
40356
40668
|
};
|
|
40357
|
-
const
|
|
40669
|
+
const gated = hello.caps?.includes(ADAPTER_CAPS.mailbox) ? reply : (f) => reply(forOldAdapter(f));
|
|
40670
|
+
const id = ctx.pending.open(frame.id, gated);
|
|
40358
40671
|
if (ctx.hub.send(build(id))) return void 0;
|
|
40359
40672
|
ctx.pending.cancel(id);
|
|
40360
40673
|
return {
|
|
@@ -41809,7 +42122,9 @@ async function runDaemon(deps = {}) {
|
|
|
41809
42122
|
kind: kind2,
|
|
41810
42123
|
proposed_name: fitName(rec.proposedName, 64),
|
|
41811
42124
|
namespace: rec.namespace,
|
|
41812
|
-
global: rec.global
|
|
42125
|
+
global: rec.global,
|
|
42126
|
+
// A /clear: the new ref takes over the old address and its mail (#1295).
|
|
42127
|
+
...rec.replaces !== void 0 && hubMailbox ? { replaces: rec.replaces } : {}
|
|
41813
42128
|
});
|
|
41814
42129
|
};
|
|
41815
42130
|
const markLimited = (ref, message) => {
|
|
@@ -41829,7 +42144,20 @@ async function runDaemon(deps = {}) {
|
|
|
41829
42144
|
limited.delete(ref);
|
|
41830
42145
|
caps.delete(ref);
|
|
41831
42146
|
};
|
|
41832
|
-
const
|
|
42147
|
+
const configIssues = new ConfigIssues();
|
|
42148
|
+
const configFiles = (cwd) => {
|
|
42149
|
+
const g = inspectGlobal();
|
|
42150
|
+
let within;
|
|
42151
|
+
if (cwd !== void 0) {
|
|
42152
|
+
try {
|
|
42153
|
+
within = new Set(configPaths(realpathSync6(cwd)));
|
|
42154
|
+
} catch {
|
|
42155
|
+
within = new Set(configPaths(cwd));
|
|
42156
|
+
}
|
|
42157
|
+
}
|
|
42158
|
+
return [...configIssues.list(within), ...g ? [g] : []];
|
|
42159
|
+
};
|
|
42160
|
+
const resolveNs = (cwd, allowMissing) => (deps.resolveNamespace ?? ((dir) => resolveNamespace(dir, { log, allowMissing, issues: configIssues })))(cwd);
|
|
41833
42161
|
const cl = deps.claude ?? {};
|
|
41834
42162
|
const listenPath = deps.socketPath ?? socketPath();
|
|
41835
42163
|
const returnDir = cl.socketsDir ?? claudeReturnDir2();
|
|
@@ -42025,6 +42353,14 @@ async function runDaemon(deps = {}) {
|
|
|
42025
42353
|
if (agent) void claude.notify(agent, replyGoneText(peerName));
|
|
42026
42354
|
}
|
|
42027
42355
|
});
|
|
42356
|
+
const clearedFrom = (ref, pid, procStart, liveRefs) => agents.all().filter(
|
|
42357
|
+
(a) => a.kind === "claude-code" && a.pid === pid && procStart !== void 0 && a.procStart === procStart && a.ref !== ref && !liveRefs.has(a.ref) && !takenOver.has(a.ref)
|
|
42358
|
+
).sort(
|
|
42359
|
+
(a, b) => Number(b.live) - Number(a.live) || (seenAt.get(b.ref) ?? 0) - (seenAt.get(a.ref) ?? 0)
|
|
42360
|
+
)[0];
|
|
42361
|
+
const takenOver = /* @__PURE__ */ new Set();
|
|
42362
|
+
const seenAt = /* @__PURE__ */ new Map();
|
|
42363
|
+
let seenSeq = 0;
|
|
42028
42364
|
const syncClaude = () => {
|
|
42029
42365
|
const live = liveClaudeSessions(claudeSessions);
|
|
42030
42366
|
const liveRefs = new Set(live.map((s) => s.ref));
|
|
@@ -42032,8 +42368,13 @@ async function runDaemon(deps = {}) {
|
|
|
42032
42368
|
for (const s of live) {
|
|
42033
42369
|
const prev = agents.byRef(s.ref);
|
|
42034
42370
|
if (prev && prev.kind !== "claude-code") continue;
|
|
42371
|
+
if (prev && prev.procStart === void 0 && prev.pid === s.pid)
|
|
42372
|
+
prev.procStart = s.procStart;
|
|
42035
42373
|
if (prev?.live) {
|
|
42036
|
-
if (!livePid(s.ref, prev.pid))
|
|
42374
|
+
if (!livePid(s.ref, prev.pid)) {
|
|
42375
|
+
prev.pid = s.pid;
|
|
42376
|
+
prev.procStart = s.procStart;
|
|
42377
|
+
}
|
|
42037
42378
|
continue;
|
|
42038
42379
|
}
|
|
42039
42380
|
if (prev && prev.pid === s.pid) continue;
|
|
@@ -42045,15 +42386,20 @@ async function runDaemon(deps = {}) {
|
|
|
42045
42386
|
continue;
|
|
42046
42387
|
}
|
|
42047
42388
|
if (!WireNamespaceSchema.safeParse(ns.namespace).success) continue;
|
|
42389
|
+
seenAt.set(s.ref, ++seenSeq);
|
|
42390
|
+
const old = prev ? void 0 : clearedFrom(s.ref, s.pid, s.procStart, liveRefs);
|
|
42391
|
+
if (old) takenOver.add(old.ref);
|
|
42048
42392
|
announceUp(
|
|
42049
42393
|
agents.up({
|
|
42394
|
+
...old ? { replaces: old.ref } : {},
|
|
42050
42395
|
ref: s.ref,
|
|
42051
42396
|
kind: "claude-code",
|
|
42052
|
-
proposedName: s.name,
|
|
42053
|
-
busName: prev?.busName ?? s.name,
|
|
42397
|
+
proposedName: old?.busName ?? s.name,
|
|
42398
|
+
busName: prev?.busName ?? old?.busName ?? s.name,
|
|
42054
42399
|
namespace: ns.namespace,
|
|
42055
42400
|
global: ns.global,
|
|
42056
42401
|
pid: s.pid,
|
|
42402
|
+
procStart: s.procStart,
|
|
42057
42403
|
cwd: s.cwd,
|
|
42058
42404
|
live: true
|
|
42059
42405
|
})
|
|
@@ -42105,6 +42451,7 @@ async function runDaemon(deps = {}) {
|
|
|
42105
42451
|
let hubEver = false;
|
|
42106
42452
|
let hubDroppedAt;
|
|
42107
42453
|
let hubIds = false;
|
|
42454
|
+
let hubMailbox = false;
|
|
42108
42455
|
let hubVersion;
|
|
42109
42456
|
const hub = new HubConnection({
|
|
42110
42457
|
url: `${cfg.hub.replace(/^http/, "ws").replace(/\/+$/, "")}${BUS_ROUTES.connect}`,
|
|
@@ -42123,7 +42470,10 @@ async function runDaemon(deps = {}) {
|
|
|
42123
42470
|
upIds.delete(frame.id);
|
|
42124
42471
|
clearLimited(frame.agent_ref);
|
|
42125
42472
|
const agent = agents.byRef(frame.agent_ref);
|
|
42126
|
-
if (agent)
|
|
42473
|
+
if (agent) {
|
|
42474
|
+
agent.busName = frame.bus_name;
|
|
42475
|
+
delete agent.replaces;
|
|
42476
|
+
}
|
|
42127
42477
|
resends.up(frame.agent_ref);
|
|
42128
42478
|
return;
|
|
42129
42479
|
}
|
|
@@ -42190,6 +42540,7 @@ async function runDaemon(deps = {}) {
|
|
|
42190
42540
|
case "hello_ok":
|
|
42191
42541
|
hubVersion = frame.server_version;
|
|
42192
42542
|
hubIds = frame.caps?.includes(BUS_CAPS.ids) ?? false;
|
|
42543
|
+
hubMailbox = frame.caps?.includes(BUS_CAPS.mailbox) ?? false;
|
|
42193
42544
|
outbox.flush();
|
|
42194
42545
|
return;
|
|
42195
42546
|
}
|
|
@@ -42235,6 +42586,7 @@ async function runDaemon(deps = {}) {
|
|
|
42235
42586
|
upIds.clear();
|
|
42236
42587
|
hubVersion = void 0;
|
|
42237
42588
|
hubIds = false;
|
|
42589
|
+
hubMailbox = false;
|
|
42238
42590
|
statusRelay.dropped();
|
|
42239
42591
|
receipts.release();
|
|
42240
42592
|
resends.dropped();
|
|
@@ -42315,11 +42667,11 @@ async function runDaemon(deps = {}) {
|
|
|
42315
42667
|
const local = live.filter((a) => a.namespace === namespace);
|
|
42316
42668
|
const mine = new Map(local.map((a) => [a.busName, a.kind]));
|
|
42317
42669
|
const roster2 = local[0] && hub.open ? await hubRoster(local[0].ref) : void 0;
|
|
42318
|
-
const rows = roster2 ? roster2.map((a) => ({
|
|
42670
|
+
const rows = roster2 ? roster2.filter((a) => a.state !== "away").map((a) => ({
|
|
42319
42671
|
name: a.name,
|
|
42320
42672
|
kind: a.kind,
|
|
42321
42673
|
machine: a.machine_label ?? (mine.get(a.name) === a.kind ? cfg.label : ""),
|
|
42322
|
-
state: a.state ?? "live",
|
|
42674
|
+
state: a.state === "away" ? "queued" : a.state ?? "live",
|
|
42323
42675
|
...a.status === void 0 ? {} : { status: a.status },
|
|
42324
42676
|
...a.status_label === void 0 ? {} : { status_label: a.status_label },
|
|
42325
42677
|
...a.status_at === void 0 ? {} : { status_at: a.status_at }
|
|
@@ -42332,10 +42684,12 @@ async function runDaemon(deps = {}) {
|
|
|
42332
42684
|
return { namespace, agents: rows };
|
|
42333
42685
|
})
|
|
42334
42686
|
);
|
|
42687
|
+
const config_files = configFiles();
|
|
42335
42688
|
return {
|
|
42336
42689
|
pid: process.pid,
|
|
42337
42690
|
version: version2,
|
|
42338
42691
|
label: cfg.label,
|
|
42692
|
+
...config_files.length > 0 ? { config_files } : {},
|
|
42339
42693
|
hub: hub.open ? "connected" : "connecting",
|
|
42340
42694
|
...hub.open || !hub.lastError ? {} : { hub_error: hub.lastError },
|
|
42341
42695
|
hub_ever: hubEver,
|
|
@@ -42418,14 +42772,28 @@ async function runDaemon(deps = {}) {
|
|
|
42418
42772
|
};
|
|
42419
42773
|
attested(pid);
|
|
42420
42774
|
const proposedName = hello.proposed_name ?? hello.agent_ref;
|
|
42775
|
+
const files = hello.kind === "claude-code" ? liveClaudeSessions(claudeSessions) : [];
|
|
42776
|
+
const mine = files.find(
|
|
42777
|
+
(x) => x.ref === hello.agent_ref && x.pid === pid
|
|
42778
|
+
);
|
|
42779
|
+
const old = mine && !prev ? clearedFrom(
|
|
42780
|
+
hello.agent_ref,
|
|
42781
|
+
pid,
|
|
42782
|
+
mine.procStart,
|
|
42783
|
+
new Set(files.map((x) => x.ref))
|
|
42784
|
+
) : void 0;
|
|
42785
|
+
seenAt.set(hello.agent_ref, ++seenSeq);
|
|
42786
|
+
if (old) takenOver.add(old.ref);
|
|
42421
42787
|
const rec = agents.up({
|
|
42788
|
+
...old ? { replaces: old.ref } : {},
|
|
42422
42789
|
ref: hello.agent_ref,
|
|
42423
42790
|
kind: hello.kind,
|
|
42424
|
-
proposedName,
|
|
42425
|
-
busName: prev?.busName ?? proposedName,
|
|
42791
|
+
proposedName: old?.busName ?? proposedName,
|
|
42792
|
+
busName: prev?.busName ?? old?.busName ?? proposedName,
|
|
42426
42793
|
namespace: ns.namespace,
|
|
42427
42794
|
global: ns.global,
|
|
42428
42795
|
pid,
|
|
42796
|
+
...mine ? { procStart: mine.procStart } : {},
|
|
42429
42797
|
cwd,
|
|
42430
42798
|
live: true
|
|
42431
42799
|
});
|
|
@@ -42462,6 +42830,7 @@ async function runDaemon(deps = {}) {
|
|
|
42462
42830
|
pending,
|
|
42463
42831
|
limited: (ref) => limited.has(ref) ? caps.get(ref) ?? "machine" : void 0,
|
|
42464
42832
|
version: version2,
|
|
42833
|
+
configFiles,
|
|
42465
42834
|
// The self tool's status: the agent's own row on its roster.
|
|
42466
42835
|
ownRow: (ref) => {
|
|
42467
42836
|
const me = agents.byRef(ref);
|
|
@@ -42605,7 +42974,7 @@ async function runDaemon(deps = {}) {
|
|
|
42605
42974
|
init_src3();
|
|
42606
42975
|
import { execFileSync as execFileSync5, spawn as spawn2 } from "node:child_process";
|
|
42607
42976
|
import { closeSync as closeSync4, openSync as openSync4, readFileSync as readFileSync13 } from "node:fs";
|
|
42608
|
-
import { homedir as homedir3, userInfo } from "node:os";
|
|
42977
|
+
import { homedir as homedir3, userInfo as userInfo2 } from "node:os";
|
|
42609
42978
|
init_src2();
|
|
42610
42979
|
|
|
42611
42980
|
// src/copy.ts
|
|
@@ -43116,6 +43485,14 @@ function copy(style) {
|
|
|
43116
43485
|
next(p("muted", clip(`It ${why}.`, 3))),
|
|
43117
43486
|
next(`Remove it, then run ${BUS_CMD} global add <dir> again.`)
|
|
43118
43487
|
],
|
|
43488
|
+
/** A refused or noted config file (#1527): the reason, then the exact fix. Paths arrive already shortened. */
|
|
43489
|
+
configFile: (f) => [
|
|
43490
|
+
warn(
|
|
43491
|
+
f.state === "refused" ? `${f.file} ${f.reason}, so it is ignored.` : `${f.file} ${f.reason}; it is still used.`
|
|
43492
|
+
),
|
|
43493
|
+
next(`Fix: ${f.fix}`),
|
|
43494
|
+
...f.restart ? [next("Restart the session to pick up a fix.")] : []
|
|
43495
|
+
],
|
|
43119
43496
|
globalAsked: () => [
|
|
43120
43497
|
warn("This repo's .oa-bus.json asks for global, which is ignored here."),
|
|
43121
43498
|
next(`Allow it with ${BUS_CMD} global add .`)
|
|
@@ -43321,7 +43698,7 @@ import {
|
|
|
43321
43698
|
existsSync as existsSync3,
|
|
43322
43699
|
lstatSync as lstatSync8,
|
|
43323
43700
|
mkdirSync as mkdirSync7,
|
|
43324
|
-
realpathSync as
|
|
43701
|
+
realpathSync as realpathSync7,
|
|
43325
43702
|
renameSync as renameSync7,
|
|
43326
43703
|
rmSync as rmSync4,
|
|
43327
43704
|
writeFileSync as writeFileSync6
|
|
@@ -44535,7 +44912,7 @@ function writeReplacing(path, text3) {
|
|
|
44535
44912
|
var real = (path) => {
|
|
44536
44913
|
const abs = resolve4(path);
|
|
44537
44914
|
try {
|
|
44538
|
-
return
|
|
44915
|
+
return realpathSync7(abs);
|
|
44539
44916
|
} catch {
|
|
44540
44917
|
const parent = dirname7(abs);
|
|
44541
44918
|
return parent === abs ? abs : join13(real(parent), basename6(abs));
|
|
@@ -44768,7 +45145,7 @@ var noService = {
|
|
|
44768
45145
|
remove: async () => ({}),
|
|
44769
45146
|
cli: () => ["oa-bus"]
|
|
44770
45147
|
};
|
|
44771
|
-
var VERSION = true ? "0.
|
|
45148
|
+
var VERSION = true ? "0.125.0" : JSON.parse(
|
|
44772
45149
|
readFileSync13(new URL("../package.json", import.meta.url), "utf8")
|
|
44773
45150
|
).version;
|
|
44774
45151
|
var which = (cmd) => {
|
|
@@ -44814,7 +45191,7 @@ var spawnDaemon = (cmd, args, opts) => {
|
|
|
44814
45191
|
};
|
|
44815
45192
|
var userName = () => {
|
|
44816
45193
|
try {
|
|
44817
|
-
return
|
|
45194
|
+
return userInfo2().username;
|
|
44818
45195
|
} catch {
|
|
44819
45196
|
return "";
|
|
44820
45197
|
}
|
|
@@ -44909,6 +45286,17 @@ var sayErr = (ctx, ...lines) => {
|
|
|
44909
45286
|
};
|
|
44910
45287
|
var tildeReason = (ctx, harness, reason) => harness === "codex" && reason.startsWith(`${ctx.userHome}/`) ? `~${reason.slice(ctx.userHome.length)}` : reason;
|
|
44911
45288
|
var tilde = (ctx, path) => path === ctx.userHome ? "~" : path.startsWith(`${ctx.userHome}/`) ? `~${path.slice(ctx.userHome.length)}` : path;
|
|
45289
|
+
var plain2 = (text3) => stripTerminalControls(text3).replace(/[\r\n\t]/g, " ");
|
|
45290
|
+
var configFileLines = (ctx, files) => files.flatMap(
|
|
45291
|
+
(f) => ctx.copy.configFile({
|
|
45292
|
+
state: f.state,
|
|
45293
|
+
reason: plain2(f.reason),
|
|
45294
|
+
file: plain2(tilde(ctx, f.file)),
|
|
45295
|
+
fix: plain2(f.fix),
|
|
45296
|
+
// The namespace is resolved when a session starts.
|
|
45297
|
+
restart: f.file.endsWith("/.oa-bus.json")
|
|
45298
|
+
})
|
|
45299
|
+
);
|
|
44912
45300
|
|
|
44913
45301
|
// src/machine.ts
|
|
44914
45302
|
import { readFileSync as readFileSync14, statSync as statSync8 } from "node:fs";
|
|
@@ -47399,6 +47787,7 @@ async function status(ctx) {
|
|
|
47399
47787
|
async () => (await health).version
|
|
47400
47788
|
);
|
|
47401
47789
|
if (update) say(ctx, c.updateAvailable(update, st.version));
|
|
47790
|
+
if (st.config_files?.length) say(ctx, configFileLines(ctx, st.config_files));
|
|
47402
47791
|
if (st.hub !== "connected") {
|
|
47403
47792
|
sayErr(ctx, c.hubNotReachable(host, st.hub_error, "status"));
|
|
47404
47793
|
return 1;
|
|
@@ -47590,19 +47979,26 @@ async function doctor(ctx) {
|
|
|
47590
47979
|
const allow = globalFile(ctx.home);
|
|
47591
47980
|
const list = readGlobalDirs(allow);
|
|
47592
47981
|
if (list.error) warn(c.globalUnusable(tilde(ctx, allow), list.error));
|
|
47982
|
+
const files = scanConfigFiles(ctx.cwd, { globalFile: allow }).filter(
|
|
47983
|
+
(f) => f.file !== allow
|
|
47984
|
+
);
|
|
47985
|
+
if (files.length > 0) {
|
|
47986
|
+
n.warnings += files.length;
|
|
47987
|
+
say(ctx, configFileLines(ctx, files));
|
|
47988
|
+
}
|
|
47593
47989
|
if (asksForGlobal(ctx, list.dirs)) warn(c.globalAsked());
|
|
47594
47990
|
say(ctx, "", c.summary(n.failed, n.warnings, n.passed));
|
|
47595
47991
|
return n.failed > 0 ? 1 : 0;
|
|
47596
47992
|
}
|
|
47597
47993
|
|
|
47598
47994
|
// src/commands/global.ts
|
|
47599
|
-
import { realpathSync as
|
|
47995
|
+
import { realpathSync as realpathSync8, statSync as statSync10 } from "node:fs";
|
|
47600
47996
|
import { resolve as resolve6 } from "node:path";
|
|
47601
47997
|
function shown(ctx, path) {
|
|
47602
47998
|
const t = tilde(ctx, path);
|
|
47603
47999
|
if (t !== path) return t;
|
|
47604
48000
|
try {
|
|
47605
|
-
return tilde({ userHome:
|
|
48001
|
+
return tilde({ userHome: realpathSync8(ctx.userHome) }, path);
|
|
47606
48002
|
} catch {
|
|
47607
48003
|
return path;
|
|
47608
48004
|
}
|