usebeeline 0.0.1 → 0.0.3
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/README.md +3 -3
- package/dist/usebeeline.mjs +268 -127
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -3,11 +3,11 @@
|
|
|
3
3
|
Connect a supported coding-agent harness to Beeline:
|
|
4
4
|
|
|
5
5
|
```sh
|
|
6
|
-
npx usebeeline connect
|
|
6
|
+
npx usebeeline connect <PAIRING_CODE_FROM_THE_APP>
|
|
7
7
|
```
|
|
8
8
|
|
|
9
|
-
The package also exposes a `beeline` bin alias. The connect command
|
|
10
|
-
short-lived
|
|
9
|
+
The package also exposes a `beeline` bin alias. The connect command uses the
|
|
10
|
+
short-lived code minted by the Beeline app, installs the signed current daemon bundle into
|
|
11
11
|
the canonical `~/.local` layout, and starts the supervised user service.
|
|
12
12
|
|
|
13
13
|
The wizard asks exactly for the harness, any required provider credential, the
|
package/dist/usebeeline.mjs
CHANGED
|
@@ -1264,18 +1264,18 @@ function validateTableBytes(numPoints, fpBytes) {
|
|
|
1264
1264
|
if (bytes > TABLE_BYTES_MAX)
|
|
1265
1265
|
throw new Error("invalid window size: table would need ~" + Math.ceil(bytes / 2 ** 20) + " MiB, max " + TABLE_BYTES_MAX / 2 ** 20 + " MiB");
|
|
1266
1266
|
}
|
|
1267
|
-
function probeRandomBytes(
|
|
1268
|
-
if (
|
|
1267
|
+
function probeRandomBytes(randomBytes7, length) {
|
|
1268
|
+
if (randomBytes7 === void 0)
|
|
1269
1269
|
return void 0;
|
|
1270
|
-
afunction(
|
|
1270
|
+
afunction(randomBytes7, "randomBytes");
|
|
1271
1271
|
try {
|
|
1272
|
-
const probe =
|
|
1272
|
+
const probe = randomBytes7(length);
|
|
1273
1273
|
if (!isBytes2(probe) || probe.length !== length)
|
|
1274
1274
|
return void 0;
|
|
1275
1275
|
} catch {
|
|
1276
1276
|
return void 0;
|
|
1277
1277
|
}
|
|
1278
|
-
return
|
|
1278
|
+
return randomBytes7;
|
|
1279
1279
|
}
|
|
1280
1280
|
function validateMSMPoints(points, c2) {
|
|
1281
1281
|
aarray(points, "points");
|
|
@@ -1431,9 +1431,9 @@ var init_curve = __esm({
|
|
|
1431
1431
|
baseCanBeBlinded;
|
|
1432
1432
|
bits;
|
|
1433
1433
|
// Parametrized with a given Point class (not individual point)
|
|
1434
|
-
constructor(Point,
|
|
1434
|
+
constructor(Point, randomBytes7) {
|
|
1435
1435
|
validatePointCons(Point);
|
|
1436
|
-
this.randomBytes = probeRandomBytes(
|
|
1436
|
+
this.randomBytes = probeRandomBytes(randomBytes7, BLIND_BYTES);
|
|
1437
1437
|
this.Point = Point;
|
|
1438
1438
|
this.BASE = Point.BASE;
|
|
1439
1439
|
this.ZERO = Point.ZERO;
|
|
@@ -1666,7 +1666,7 @@ function weierstrass(params, extraOpts = {}) {
|
|
|
1666
1666
|
randomBytes: "function"
|
|
1667
1667
|
});
|
|
1668
1668
|
const { endo, allowInfinityPoint } = extraOpts;
|
|
1669
|
-
const
|
|
1669
|
+
const randomBytes7 = extraOpts.randomBytes === void 0 ? randomBytes2 : extraOpts.randomBytes;
|
|
1670
1670
|
if (endo) {
|
|
1671
1671
|
if (!Fp.is0(CURVE.a) || typeof endo.beta !== "bigint" || !Array.isArray(endo.basises)) {
|
|
1672
1672
|
throw new Error('invalid endo: expected "beta": bigint and "basises": array');
|
|
@@ -2078,7 +2078,7 @@ function weierstrass(params, extraOpts = {}) {
|
|
|
2078
2078
|
}
|
|
2079
2079
|
}
|
|
2080
2080
|
const normalize3 = (points) => normalizeZ(Point, points);
|
|
2081
|
-
const wnaf = new ScalarMultiplier(Point,
|
|
2081
|
+
const wnaf = new ScalarMultiplier(Point, randomBytes7);
|
|
2082
2082
|
if (wnaf.bits >= 6)
|
|
2083
2083
|
Point.BASE.precompute(6);
|
|
2084
2084
|
Object.freeze(Point.prototype);
|
|
@@ -4102,7 +4102,7 @@ function ecdsa2(Point, hash, ecdsaOpts = {}) {
|
|
|
4102
4102
|
bits2int_modN: "function"
|
|
4103
4103
|
});
|
|
4104
4104
|
ecdsaOpts = Object.assign({}, ecdsaOpts);
|
|
4105
|
-
const
|
|
4105
|
+
const randomBytes7 = ecdsaOpts.randomBytes || randomBytes3;
|
|
4106
4106
|
const hmac2 = ecdsaOpts.hmac || ((key, msg) => hmac(hash, key, msg));
|
|
4107
4107
|
const { Fp, Fn } = Point;
|
|
4108
4108
|
const { ORDER: CURVE_ORDER, BITS: fnBits } = Fn;
|
|
@@ -4244,7 +4244,7 @@ function ecdsa2(Point, hash, ecdsaOpts = {}) {
|
|
|
4244
4244
|
throw new Error("invalid private key");
|
|
4245
4245
|
const seedArgs = [int2octets(d), int2octets(h1int)];
|
|
4246
4246
|
if (extraEntropy != null && extraEntropy !== false) {
|
|
4247
|
-
const e = extraEntropy === true ?
|
|
4247
|
+
const e = extraEntropy === true ? randomBytes7(lengths.secretKey) : extraEntropy;
|
|
4248
4248
|
seedArgs.push(abytes3(e, void 0, "extraEntropy"));
|
|
4249
4249
|
}
|
|
4250
4250
|
const seed = concatBytes3(...seedArgs);
|
|
@@ -11338,7 +11338,7 @@ var require_websocket = __commonJS({
|
|
|
11338
11338
|
var http = __require("http");
|
|
11339
11339
|
var net = __require("net");
|
|
11340
11340
|
var tls = __require("tls");
|
|
11341
|
-
var { randomBytes:
|
|
11341
|
+
var { randomBytes: randomBytes7, createHash: createHash15 } = __require("crypto");
|
|
11342
11342
|
var { Duplex, Readable } = __require("stream");
|
|
11343
11343
|
var { URL: URL2 } = __require("url");
|
|
11344
11344
|
var PerMessageDeflate2 = require_permessage_deflate();
|
|
@@ -11876,7 +11876,7 @@ var require_websocket = __commonJS({
|
|
|
11876
11876
|
}
|
|
11877
11877
|
}
|
|
11878
11878
|
const defaultPort = isSecure ? 443 : 80;
|
|
11879
|
-
const key =
|
|
11879
|
+
const key = randomBytes7(16).toString("base64");
|
|
11880
11880
|
const request = isSecure ? https.request : http.request;
|
|
11881
11881
|
const protocolSet = /* @__PURE__ */ new Set();
|
|
11882
11882
|
let perMessageDeflate;
|
|
@@ -12006,7 +12006,7 @@ var require_websocket = __commonJS({
|
|
|
12006
12006
|
abortHandshake(websocket, socket, "Invalid Upgrade header");
|
|
12007
12007
|
return;
|
|
12008
12008
|
}
|
|
12009
|
-
const digest2 =
|
|
12009
|
+
const digest2 = createHash15("sha1").update(key + GUID).digest("base64");
|
|
12010
12010
|
if (res.headers["sec-websocket-accept"] !== digest2) {
|
|
12011
12011
|
abortHandshake(websocket, socket, "Invalid Sec-WebSocket-Accept header");
|
|
12012
12012
|
return;
|
|
@@ -12375,7 +12375,7 @@ var require_websocket_server = __commonJS({
|
|
|
12375
12375
|
var EventEmitter2 = __require("events");
|
|
12376
12376
|
var http = __require("http");
|
|
12377
12377
|
var { Duplex } = __require("stream");
|
|
12378
|
-
var { createHash:
|
|
12378
|
+
var { createHash: createHash15 } = __require("crypto");
|
|
12379
12379
|
var extension2 = require_extension();
|
|
12380
12380
|
var PerMessageDeflate2 = require_permessage_deflate();
|
|
12381
12381
|
var subprotocol2 = require_subprotocol();
|
|
@@ -12682,7 +12682,7 @@ var require_websocket_server = __commonJS({
|
|
|
12682
12682
|
);
|
|
12683
12683
|
}
|
|
12684
12684
|
if (this._state > RUNNING) return abortHandshake(socket, 503);
|
|
12685
|
-
const digest2 =
|
|
12685
|
+
const digest2 = createHash15("sha1").update(key + GUID).digest("base64");
|
|
12686
12686
|
const headers2 = [
|
|
12687
12687
|
"HTTP/1.1 101 Switching Protocols",
|
|
12688
12688
|
"Upgrade: websocket",
|
|
@@ -22029,11 +22029,11 @@ function parseUpdateManifest(raw, platform) {
|
|
|
22029
22029
|
}
|
|
22030
22030
|
const bundle = entry;
|
|
22031
22031
|
const file = typeof bundle.file === "string" ? bundle.file : "";
|
|
22032
|
-
const
|
|
22032
|
+
const sha2564 = typeof bundle.sha256 === "string" ? bundle.sha256.toLowerCase() : "";
|
|
22033
22033
|
if (!file || !/^[a-z0-9][a-z0-9._-]*$/i.test(file)) {
|
|
22034
22034
|
throw new Error(`update manifest names an unusable bundle file: ${JSON.stringify(bundle.file)}`);
|
|
22035
22035
|
}
|
|
22036
|
-
if (!/^[0-9a-f]{64}$/.test(
|
|
22036
|
+
if (!/^[0-9a-f]{64}$/.test(sha2564)) {
|
|
22037
22037
|
throw new Error(`update manifest carries no usable sha256 for ${platform}`);
|
|
22038
22038
|
}
|
|
22039
22039
|
const sourceCommit = typeof bundle.commit === "string" && bundle.commit ? bundle.commit : typeof manifest.sourceCommit === "string" ? manifest.sourceCommit : void 0;
|
|
@@ -22045,7 +22045,7 @@ function parseUpdateManifest(raw, platform) {
|
|
|
22045
22045
|
bundles,
|
|
22046
22046
|
bundle: {
|
|
22047
22047
|
file,
|
|
22048
|
-
sha256:
|
|
22048
|
+
sha256: sha2564,
|
|
22049
22049
|
...typeof bundle.bytes === "number" ? { bytes: bundle.bytes } : {},
|
|
22050
22050
|
...sourceCommit ? { commit: sourceCommit } : {},
|
|
22051
22051
|
...version ? { version } : {},
|
|
@@ -24397,10 +24397,10 @@ function parseArtifact(value) {
|
|
|
24397
24397
|
const artifactId = token(input.artifactId);
|
|
24398
24398
|
const revision = integer(input.revision, 1);
|
|
24399
24399
|
const eventId = typeof input.eventId === "string" && HEX_64.test(input.eventId) ? input.eventId : void 0;
|
|
24400
|
-
const
|
|
24401
|
-
if (!artifactId || revision === void 0 || !eventId || !
|
|
24400
|
+
const sha2564 = typeof input.sha256 === "string" && SHA_256.test(input.sha256) ? input.sha256 : void 0;
|
|
24401
|
+
if (!artifactId || revision === void 0 || !eventId || !sha2564)
|
|
24402
24402
|
return void 0;
|
|
24403
|
-
return { artifactId, revision, eventId, sha256:
|
|
24403
|
+
return { artifactId, revision, eventId, sha256: sha2564 };
|
|
24404
24404
|
}
|
|
24405
24405
|
function parseArtifacts(value) {
|
|
24406
24406
|
if (!Array.isArray(value) || value.length === 0 || value.length > MAX_PERMISSION_LIST_ITEMS) {
|
|
@@ -30168,7 +30168,7 @@ function normalizeAttachmentReference(value) {
|
|
|
30168
30168
|
return null;
|
|
30169
30169
|
const thumbnailUrl = value.thumbnailUrl ? httpUrl2(value.thumbnailUrl) : void 0;
|
|
30170
30170
|
const previewUrl = value.previewUrl ? httpUrl2(value.previewUrl) : void 0;
|
|
30171
|
-
const
|
|
30171
|
+
const sha2564 = value.sha256?.toLowerCase();
|
|
30172
30172
|
const width = cleanSize(value.width ?? 0);
|
|
30173
30173
|
const height = cleanSize(value.height ?? 0);
|
|
30174
30174
|
return {
|
|
@@ -30177,7 +30177,7 @@ function normalizeAttachmentReference(value) {
|
|
|
30177
30177
|
mimeType,
|
|
30178
30178
|
size,
|
|
30179
30179
|
...previewUrl ? { previewUrl } : {},
|
|
30180
|
-
...
|
|
30180
|
+
...sha2564 && /^[0-9a-f]{64}$/.test(sha2564) ? { sha256: sha2564 } : {},
|
|
30181
30181
|
...thumbnailUrl ? { thumbnailUrl } : {},
|
|
30182
30182
|
...value.width !== void 0 && width !== void 0 && width > 0 ? { width } : {},
|
|
30183
30183
|
...value.height !== void 0 && height !== void 0 && height > 0 ? { height } : {}
|
|
@@ -47718,6 +47718,13 @@ Deliver artifacts from this corner; there is no branch to land.`;
|
|
|
47718
47718
|
}
|
|
47719
47719
|
/** Human decision path retained for a named repository outside the Room binding. */
|
|
47720
47720
|
async cornerOpenAudience(roomId, requesterPubkey) {
|
|
47721
|
+
if (this.daemonApi) {
|
|
47722
|
+
const authority = await this.daemonApi.execute("getRoomAuthority", {
|
|
47723
|
+
roomId,
|
|
47724
|
+
principalId: requesterPubkey
|
|
47725
|
+
});
|
|
47726
|
+
return authority.member && authority.principalKind === "human" ? [requesterPubkey] : [];
|
|
47727
|
+
}
|
|
47721
47728
|
const members = await listMembers(this.agentClientContext(), roomId);
|
|
47722
47729
|
const candidates = members.filter((member2) => member2.pubkey === requesterPubkey || member2.role === "admin" || member2.role === "owner");
|
|
47723
47730
|
const checked = await Promise.all(candidates.map(async (member2) => ({
|
|
@@ -47756,9 +47763,10 @@ Deliver artifacts from this corner; there is no branch to land.`;
|
|
|
47756
47763
|
message: published.message
|
|
47757
47764
|
};
|
|
47758
47765
|
}
|
|
47759
|
-
const permissionId = randomUUID5();
|
|
47766
|
+
const permissionId = this.daemonApi ? createHash10("sha256").update(`corner-permission\0${input.roomId}\0${input.request.eventId}`).digest("hex") : randomUUID5();
|
|
47760
47767
|
const repository2 = input.roomRepo ? this.repoId(input.roomRepo) : "repo-less";
|
|
47761
|
-
const
|
|
47768
|
+
const principalId = input.request.delegation?.rootHumanPubkey ?? input.request.authorPubkey;
|
|
47769
|
+
const audience = await this.cornerOpenAudience(input.roomId, principalId);
|
|
47762
47770
|
if (audience.length === 0) {
|
|
47763
47771
|
throw new AgentToolKnownFailure("approval_audience_unavailable", "No eligible human is available to decide this corner request.", true);
|
|
47764
47772
|
}
|
|
@@ -47766,7 +47774,18 @@ Deliver artifacts from this corner; there is no branch to land.`;
|
|
|
47766
47774
|
const requester = requesterAttribution?.handle ?? fallbackPersonName(input.request.authorPubkey);
|
|
47767
47775
|
const agent = (await this.roomAuthorAttributions(input.roomId, [this.agentIdentity.publicKey])).get(this.agentIdentity.publicKey)?.name ?? fallbackAgentName(this.agentIdentity.publicKey);
|
|
47768
47776
|
const message2 = `@${requester.replace(/^@/, "")} asked ${agent} to open a corner for: ` + input.objective;
|
|
47769
|
-
const card =
|
|
47777
|
+
const card = this.daemonApi ? await this.daemonApi.execute("postPermissionRequest", {
|
|
47778
|
+
roomId: input.roomId,
|
|
47779
|
+
principalId,
|
|
47780
|
+
permissionId,
|
|
47781
|
+
requestId: input.request.eventId,
|
|
47782
|
+
scope: {
|
|
47783
|
+
type: "operation.execute",
|
|
47784
|
+
connectorId: input.tool,
|
|
47785
|
+
target: repository2,
|
|
47786
|
+
payloadDigest: createHash10("sha256").update(input.objective).digest("hex")
|
|
47787
|
+
}
|
|
47788
|
+
}) : buildControlMessage("permission-request", input.roomId, this.agentIdentity, message2, [
|
|
47770
47789
|
["t", WRITE_PERMISSION_REQUEST_TAG],
|
|
47771
47790
|
["permission", permissionId],
|
|
47772
47791
|
["request", input.request.eventId],
|
|
@@ -47779,7 +47798,8 @@ Deliver artifacts from this corner; there is no branch to land.`;
|
|
|
47779
47798
|
...this.delegatedReplyTags(input.request),
|
|
47780
47799
|
...audience.map((pubkey2) => ["p", pubkey2])
|
|
47781
47800
|
]);
|
|
47782
|
-
|
|
47801
|
+
if (!this.daemonApi)
|
|
47802
|
+
await publishEvent2(card, this.agentIdentity);
|
|
47783
47803
|
void this.finishCornerApproval({ ...input, permissionId, repository: repository2, audience }).catch((error) => console.error("[body] corner approval settlement failed:", error));
|
|
47784
47804
|
return { request_id: permissionId, event_id: card.id, message: message2 };
|
|
47785
47805
|
})();
|
|
@@ -47792,6 +47812,8 @@ Deliver artifacts from this corner; there is no branch to land.`;
|
|
|
47792
47812
|
* the signed pending card already authored for this exact member request.
|
|
47793
47813
|
*/
|
|
47794
47814
|
async publishedCornerApproval(input) {
|
|
47815
|
+
if (this.daemonApi)
|
|
47816
|
+
return void 0;
|
|
47795
47817
|
const repository2 = input.roomRepo ? this.repoId(input.roomRepo) : "repo-less";
|
|
47796
47818
|
const events = await this.agentRelay.queryEvents([
|
|
47797
47819
|
{
|
|
@@ -47811,9 +47833,11 @@ Deliver artifacts from this corner; there is no branch to land.`;
|
|
|
47811
47833
|
return { permissionId, eventId: event.id, message: event.content, repository: repository2, audience };
|
|
47812
47834
|
}
|
|
47813
47835
|
async finishCornerApproval(input) {
|
|
47836
|
+
const principalId = input.request.delegation?.rootHumanPubkey ?? input.request.authorPubkey;
|
|
47814
47837
|
let deciderPubkey;
|
|
47815
47838
|
const decision = await this.waitForWritePermissionDecision(input.roomId, input.permissionId, input.request.eventId, input.repository, 10 * 6e4, {
|
|
47816
47839
|
allowedResponders: new Set(input.audience),
|
|
47840
|
+
principalId,
|
|
47817
47841
|
captureDecider: (pubkey2) => {
|
|
47818
47842
|
deciderPubkey = pubkey2;
|
|
47819
47843
|
}
|
|
@@ -47823,44 +47847,61 @@ Deliver artifacts from this corner; there is no branch to land.`;
|
|
|
47823
47847
|
if (decision === "allow") {
|
|
47824
47848
|
try {
|
|
47825
47849
|
const info = await this.openSubchannelForRequest(input.roomId, input.roomRepo, input.objective, input.request, { objective: input.objective, suppressOpenCard: true });
|
|
47826
|
-
await this.postWritePermissionStatus(input.roomId, input.permissionId, input.request.eventId, input.tool, input.repository, "allowed", `Corner approved by @${deciderHandle.replace(/^@/, "")} \u2014 view \u2192`, info.subchannelId, deciderPubkey,
|
|
47850
|
+
await this.postWritePermissionStatus(input.roomId, input.permissionId, input.request.eventId, input.tool, input.repository, "allowed", `Corner approved by @${deciderHandle.replace(/^@/, "")} \u2014 view \u2192`, info.subchannelId, deciderPubkey, principalId);
|
|
47827
47851
|
this.startCornerTaskOnce(info, input.objective, cornerOpenTaskPrompt(info.taskDescription, input.objective), {
|
|
47828
47852
|
requestId: input.request.eventId,
|
|
47829
47853
|
originalRequestId: input.request.eventId,
|
|
47830
47854
|
cause: "corner-opening"
|
|
47831
47855
|
});
|
|
47832
47856
|
} catch (error) {
|
|
47833
|
-
await this.postWritePermissionStatus(input.roomId, input.permissionId, input.request.eventId, input.tool, input.repository, "failed", `Corner approved by @${deciderHandle.replace(/^@/, "")}, but it could not start: ${this.safePermissionFailure(error)}`, void 0, deciderPubkey,
|
|
47857
|
+
await this.postWritePermissionStatus(input.roomId, input.permissionId, input.request.eventId, input.tool, input.repository, "failed", `Corner approved by @${deciderHandle.replace(/^@/, "")}, but it could not start: ${this.safePermissionFailure(error)}`, void 0, deciderPubkey, principalId);
|
|
47834
47858
|
}
|
|
47835
47859
|
return;
|
|
47836
47860
|
}
|
|
47837
|
-
await this.postWritePermissionStatus(input.roomId, input.permissionId, input.request.eventId, input.tool, input.repository, decision === "deny" ? "denied" : "expired", decision === "deny" ? `Corner denied by @${deciderHandle.replace(/^@/, "")}.` : "The corner request expired without a decision.", void 0, deciderPubkey,
|
|
47861
|
+
await this.postWritePermissionStatus(input.roomId, input.permissionId, input.request.eventId, input.tool, input.repository, decision === "deny" ? "denied" : "expired", decision === "deny" ? `Corner denied by @${deciderHandle.replace(/^@/, "")}.` : "The corner request expired without a decision.", void 0, deciderPubkey, principalId);
|
|
47838
47862
|
}
|
|
47839
47863
|
async requestEditCornerApproval(input) {
|
|
47840
47864
|
const { tlcChannelId, turn, repository: repository2, tool, objective, namedTarget, pendingMessage } = input;
|
|
47841
|
-
const permissionId = randomUUID5();
|
|
47842
|
-
const
|
|
47865
|
+
const permissionId = this.daemonApi ? createHash10("sha256").update(`edit-permission\0${tlcChannelId}\0${turn.request.eventId}`).digest("hex") : randomUUID5();
|
|
47866
|
+
const principalId = turn.request.delegation?.rootHumanPubkey ?? turn.request.authorPubkey;
|
|
47867
|
+
const audience = await this.cornerOpenAudience(tlcChannelId, principalId);
|
|
47843
47868
|
if (audience.length === 0) {
|
|
47844
47869
|
throw new AgentToolKnownFailure("approval_audience_unavailable", "No eligible human is available to decide this corner request.", true);
|
|
47845
47870
|
}
|
|
47846
|
-
const requesterAttribution = turn.request.delegation ? (await this.roomAuthorAttributions(tlcChannelId, [
|
|
47847
|
-
const requester = requesterAttribution?.handle ?? fallbackPersonName(
|
|
47848
|
-
|
|
47849
|
-
|
|
47850
|
-
|
|
47851
|
-
|
|
47852
|
-
|
|
47853
|
-
|
|
47854
|
-
|
|
47855
|
-
|
|
47856
|
-
|
|
47857
|
-
|
|
47858
|
-
|
|
47859
|
-
|
|
47860
|
-
|
|
47871
|
+
const requesterAttribution = turn.request.delegation ? (await this.roomAuthorAttributions(tlcChannelId, [principalId])).get(principalId) : turn.request.authorAttribution;
|
|
47872
|
+
const requester = requesterAttribution?.handle ?? fallbackPersonName(principalId);
|
|
47873
|
+
if (this.daemonApi) {
|
|
47874
|
+
await this.daemonApi.execute("postPermissionRequest", {
|
|
47875
|
+
roomId: tlcChannelId,
|
|
47876
|
+
principalId,
|
|
47877
|
+
permissionId,
|
|
47878
|
+
requestId: turn.request.eventId,
|
|
47879
|
+
scope: {
|
|
47880
|
+
type: "operation.execute",
|
|
47881
|
+
connectorId: tool,
|
|
47882
|
+
target: repository2,
|
|
47883
|
+
payloadDigest: createHash10("sha256").update(objective || pendingMessage).digest("hex")
|
|
47884
|
+
}
|
|
47885
|
+
});
|
|
47886
|
+
} else {
|
|
47887
|
+
await postControlMessage("permission-request", tlcChannelId, this.agentIdentity, `@${requester.replace(/^@/, "")} asked ${this.agentIdentity.name || "the agent"} to open a corner for: ${objective || pendingMessage}`, [
|
|
47888
|
+
["t", WRITE_PERMISSION_REQUEST_TAG],
|
|
47889
|
+
["permission", permissionId],
|
|
47890
|
+
["request", turn.request.eventId],
|
|
47891
|
+
["requester", turn.request.authorPubkey],
|
|
47892
|
+
["agent", this.agentIdentity.publicKey],
|
|
47893
|
+
...audience.map((pubkey2) => ["p", pubkey2]),
|
|
47894
|
+
["tool", tool],
|
|
47895
|
+
["repo", repository2],
|
|
47896
|
+
["objective", objective],
|
|
47897
|
+
["status", "pending"],
|
|
47898
|
+
...this.delegatedReplyTags(turn.request)
|
|
47899
|
+
]);
|
|
47900
|
+
}
|
|
47861
47901
|
let deciderPubkey;
|
|
47862
47902
|
const decision = await this.waitForWritePermissionDecision(tlcChannelId, permissionId, turn.request.eventId, repository2, 10 * 6e4, {
|
|
47863
47903
|
allowedResponders: new Set(audience),
|
|
47904
|
+
principalId,
|
|
47864
47905
|
captureDecider: (pubkey2) => {
|
|
47865
47906
|
deciderPubkey = pubkey2;
|
|
47866
47907
|
}
|
|
@@ -47876,7 +47917,7 @@ Deliver artifacts from this corner; there is no branch to land.`;
|
|
|
47876
47917
|
suppressOpenCard: true
|
|
47877
47918
|
}) : await this.openSubchannel(tlcChannelId, boundRepo, objective, { ...turn.request, content: objective }, { objective, suppressOpenCard: true });
|
|
47878
47919
|
turn.transitionedToCorner = true;
|
|
47879
|
-
await this.postWritePermissionStatus(tlcChannelId, permissionId, turn.request.eventId, tool, repository2, "allowed", `Corner approved by @${deciderHandle.replace(/^@/, "")} \u2014 view \u2192`, info.subchannelId, deciderPubkey,
|
|
47920
|
+
await this.postWritePermissionStatus(tlcChannelId, permissionId, turn.request.eventId, tool, repository2, "allowed", `Corner approved by @${deciderHandle.replace(/^@/, "")} \u2014 view \u2192`, info.subchannelId, deciderPubkey, principalId).catch((statusError) => console.error("[body] failed to publish direct corner navigation:", statusError));
|
|
47880
47921
|
this.startCornerTaskOnce(info, objective, cornerOpenTaskPrompt(info.taskDescription, objective), {
|
|
47881
47922
|
requestId: turn.request.eventId,
|
|
47882
47923
|
originalRequestId: turn.request.eventId,
|
|
@@ -47889,10 +47930,10 @@ Deliver artifacts from this corner; there is no branch to land.`;
|
|
|
47889
47930
|
return;
|
|
47890
47931
|
}
|
|
47891
47932
|
if (decision === "deny") {
|
|
47892
|
-
await this.postWritePermissionStatus(tlcChannelId, permissionId, turn.request.eventId, tool, repository2, "denied", `Corner denied by @${deciderHandle.replace(/^@/, "")}.`, void 0, deciderPubkey,
|
|
47933
|
+
await this.postWritePermissionStatus(tlcChannelId, permissionId, turn.request.eventId, tool, repository2, "denied", `Corner denied by @${deciderHandle.replace(/^@/, "")}.`, void 0, deciderPubkey, principalId);
|
|
47893
47934
|
return;
|
|
47894
47935
|
}
|
|
47895
|
-
await this.postWritePermissionStatus(tlcChannelId, permissionId, turn.request.eventId, tool, repository2, "expired", `The edit request for ${repository2} expired. The Agent remains read-only.`, void 0, void 0,
|
|
47936
|
+
await this.postWritePermissionStatus(tlcChannelId, permissionId, turn.request.eventId, tool, repository2, "expired", `The edit request for ${repository2} expired. The Agent remains read-only.`, void 0, void 0, principalId);
|
|
47896
47937
|
}
|
|
47897
47938
|
permissionToolLabel(permission) {
|
|
47898
47939
|
const title = permission.toolCall?.title?.trim();
|
|
@@ -48203,6 +48244,26 @@ Deliver artifacts from this corner; there is no branch to land.`;
|
|
|
48203
48244
|
return summarizeGitFailure(raw).replace(/https?:\/\/\S+/gi, "the configured remote").replace(/(?:[A-Za-z0-9._~+/=-]+):(?:[A-Za-z0-9._~+/=-]+)@/g, "[credentials]@").replace(/\s+/g, " ").trim().slice(0, 240) || "the repository could not be cloned or accessed";
|
|
48204
48245
|
}
|
|
48205
48246
|
postWritePermissionStatus(tlcChannelId, permissionId, requestId, tool, repository2, status, message2, subchannelId, deciderPubkey, requesterPubkey) {
|
|
48247
|
+
if (this.daemonApi) {
|
|
48248
|
+
const publishStatus = async () => {
|
|
48249
|
+
if (requesterPubkey && (status === "allowed" || status === "failed" || status === "expired")) {
|
|
48250
|
+
await this.daemonApi.execute("postPermissionExecution", {
|
|
48251
|
+
roomId: tlcChannelId,
|
|
48252
|
+
principalId: requesterPubkey,
|
|
48253
|
+
permissionId,
|
|
48254
|
+
status: status === "allowed" ? "succeeded" : "failed",
|
|
48255
|
+
result: message2
|
|
48256
|
+
});
|
|
48257
|
+
}
|
|
48258
|
+
await this.daemonApi.execute("postRoomMessage", {
|
|
48259
|
+
roomId: tlcChannelId,
|
|
48260
|
+
requestId,
|
|
48261
|
+
text: message2,
|
|
48262
|
+
presentation: "system"
|
|
48263
|
+
});
|
|
48264
|
+
};
|
|
48265
|
+
return publishStatus();
|
|
48266
|
+
}
|
|
48206
48267
|
return postControlMessage("permission-status", tlcChannelId, this.agentIdentity, message2, [
|
|
48207
48268
|
["t", WRITE_PERMISSION_REQUEST_TAG],
|
|
48208
48269
|
["permission", permissionId],
|
|
@@ -48227,6 +48288,53 @@ Deliver artifacts from this corner; there is no branch to land.`;
|
|
|
48227
48288
|
* pending decision until timeout.
|
|
48228
48289
|
*/
|
|
48229
48290
|
async waitForWritePermissionDecision(tlcChannelId, permissionId, requestId, repository2, timeoutMs = 10 * 6e4, options = {}) {
|
|
48291
|
+
if (this.daemonApi) {
|
|
48292
|
+
if (!options.principalId)
|
|
48293
|
+
throw new Error("monolith permission wait requires a principal");
|
|
48294
|
+
const deadline2 = Date.now() + timeoutMs;
|
|
48295
|
+
return new Promise((resolvePromise, rejectPromise) => {
|
|
48296
|
+
let settled = false;
|
|
48297
|
+
let polling = false;
|
|
48298
|
+
const finish = (result) => {
|
|
48299
|
+
if (settled)
|
|
48300
|
+
return;
|
|
48301
|
+
settled = true;
|
|
48302
|
+
clearTimeout(timer);
|
|
48303
|
+
clearInterval(backstop);
|
|
48304
|
+
resolvePromise(result);
|
|
48305
|
+
};
|
|
48306
|
+
const pollOnce = async () => {
|
|
48307
|
+
if (settled || polling)
|
|
48308
|
+
return;
|
|
48309
|
+
polling = true;
|
|
48310
|
+
try {
|
|
48311
|
+
const authority = await this.daemonApi.execute("getPermissionAuthority", {
|
|
48312
|
+
roomId: tlcChannelId,
|
|
48313
|
+
principalId: options.principalId,
|
|
48314
|
+
permissionId
|
|
48315
|
+
});
|
|
48316
|
+
if (authority.status === "authorized")
|
|
48317
|
+
finish("allow");
|
|
48318
|
+
if (authority.status === "denied")
|
|
48319
|
+
finish("deny");
|
|
48320
|
+
} catch (error) {
|
|
48321
|
+
if (!isTransientPermissionPollError(error)) {
|
|
48322
|
+
settled = true;
|
|
48323
|
+
clearTimeout(timer);
|
|
48324
|
+
clearInterval(backstop);
|
|
48325
|
+
rejectPromise(error);
|
|
48326
|
+
}
|
|
48327
|
+
} finally {
|
|
48328
|
+
polling = false;
|
|
48329
|
+
}
|
|
48330
|
+
};
|
|
48331
|
+
const timer = setTimeout(() => finish("timeout"), Math.max(0, deadline2 - Date.now()));
|
|
48332
|
+
timer.unref?.();
|
|
48333
|
+
const backstop = setInterval(() => void pollOnce(), WRITE_PERMISSION_BACKSTOP_POLL_MS);
|
|
48334
|
+
backstop.unref?.();
|
|
48335
|
+
void pollOnce();
|
|
48336
|
+
});
|
|
48337
|
+
}
|
|
48230
48338
|
const startedAt = Math.floor(Date.now() / 1e3) - 1;
|
|
48231
48339
|
const deadline = Date.now() + timeoutMs;
|
|
48232
48340
|
const matchingDecision = async (event) => {
|
|
@@ -51176,6 +51284,55 @@ async function assertRuntimeStorageWritable(supervisorRoot, agentPubkey) {
|
|
|
51176
51284
|
await rm7(probe, { force: true }).catch(() => void 0);
|
|
51177
51285
|
}
|
|
51178
51286
|
}
|
|
51287
|
+
async function stageMonolithAgentRuntime(input) {
|
|
51288
|
+
const supervisorRoot = input.supervisorRoot ? resolve28(input.supervisorRoot) : defaultSupervisorRoot(input.env);
|
|
51289
|
+
const baseUrl = new URL(input.monolithBaseUrl).origin;
|
|
51290
|
+
if (baseUrl !== input.monolithBaseUrl || !/^https?:$/.test(new URL(baseUrl).protocol)) {
|
|
51291
|
+
throw new Error("monolith base URL must be an HTTP or HTTPS origin");
|
|
51292
|
+
}
|
|
51293
|
+
if (!/^bde_[A-Za-z0-9_-]{43}$/.test(input.daemonExchangeToken)) {
|
|
51294
|
+
throw new Error("daemon exchange token is invalid");
|
|
51295
|
+
}
|
|
51296
|
+
const configPath = resolve28(runtimeDirectory(supervisorRoot, input.agentIdentity.publicKey), "runtime.json");
|
|
51297
|
+
if (await agentRuntimeExists(supervisorRoot, input.agentIdentity.publicKey)) {
|
|
51298
|
+
const existing = await readRuntimeRecord(configPath);
|
|
51299
|
+
const transport = existing.transport;
|
|
51300
|
+
const sameRuntime = existing.communityId === input.workspaceId && existing.pairedBy === input.pairedBy && existing.agent.publicKey === input.agentIdentity.publicKey && existing.agent.secretKeyHex === Buffer.from(input.agentIdentity.secretKey).toString("hex") && existing.body.publicKey === input.bodyIdentity.publicKey && transport?.kind === "monolith" && transport.baseUrl === baseUrl && ("daemonToken" in transport || transport.exchangeToken === input.daemonExchangeToken);
|
|
51301
|
+
if (!sameRuntime) {
|
|
51302
|
+
throw new Error(`agent identity ${input.agentIdentity.publicKey} already has another runtime`);
|
|
51303
|
+
}
|
|
51304
|
+
return { runtime: existing, configPath };
|
|
51305
|
+
}
|
|
51306
|
+
await assertRuntimeStorageWritable(supervisorRoot, input.agentIdentity.publicKey);
|
|
51307
|
+
const runtime = {
|
|
51308
|
+
version: 2,
|
|
51309
|
+
communityId: input.workspaceId,
|
|
51310
|
+
pairedBy: input.pairedBy,
|
|
51311
|
+
agent: storeIdentity(input.agentIdentity, DEFAULT_AGENT_IDENTITY_NAME),
|
|
51312
|
+
body: storeIdentity(input.bodyIdentity, DEFAULT_BODY_IDENTITY_NAME),
|
|
51313
|
+
rooms: [],
|
|
51314
|
+
supervisorRoot,
|
|
51315
|
+
// Required only by legacy records. Monolith runtimes never construct a
|
|
51316
|
+
// relay client, so retaining the server origin here cannot route traffic.
|
|
51317
|
+
relayBaseUrl: baseUrl,
|
|
51318
|
+
transport: {
|
|
51319
|
+
kind: "monolith",
|
|
51320
|
+
baseUrl,
|
|
51321
|
+
exchangeToken: input.daemonExchangeToken
|
|
51322
|
+
},
|
|
51323
|
+
...input.llmEnvFile ? { llmEnvFile: input.llmEnvFile } : {},
|
|
51324
|
+
accessPolicy: DEFAULT_ACCESS_POLICY,
|
|
51325
|
+
...input.modelSelection?.model || input.modelSelection?.effort ? { modelSelection: input.modelSelection } : {},
|
|
51326
|
+
agentKind: input.agentKind,
|
|
51327
|
+
agentCommand: input.agentCommand,
|
|
51328
|
+
agentArgs: [...input.agentArgs ?? []],
|
|
51329
|
+
agentBinary: input.agentBinary,
|
|
51330
|
+
mcpBinary: input.mcpBinary,
|
|
51331
|
+
createdAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
51332
|
+
};
|
|
51333
|
+
const writtenPath = await writeRuntimeRecord(runtime);
|
|
51334
|
+
return { runtime, configPath: writtenPath };
|
|
51335
|
+
}
|
|
51179
51336
|
async function writeRuntimePointer(gitCommonDir, agentPubkey, targetConfigPath) {
|
|
51180
51337
|
const directory = runtimeDirectory(gitCommonDir, agentPubkey);
|
|
51181
51338
|
const path = resolve28(directory, "runtime.json");
|
|
@@ -55703,33 +55860,49 @@ async function pairOneAgent(input) {
|
|
|
55703
55860
|
throw error;
|
|
55704
55861
|
}
|
|
55705
55862
|
}
|
|
55706
|
-
async function completeDevicePairing(grant) {
|
|
55707
|
-
const selectedAgent = await selectPairAgentCommand({
|
|
55863
|
+
async function completeDevicePairing(grant, options = {}) {
|
|
55864
|
+
const selectedAgent = options.selectedAgent ?? await selectPairAgentCommand({
|
|
55708
55865
|
explicitKind: grant.harness,
|
|
55709
55866
|
env: process.env,
|
|
55710
55867
|
cwd: process.cwd(),
|
|
55711
55868
|
interactive: true,
|
|
55712
55869
|
confirmInstall: async () => true
|
|
55713
55870
|
});
|
|
55714
|
-
const
|
|
55715
|
-
|
|
55716
|
-
selectedAgent,
|
|
55717
|
-
agentIdentity: identityFromKey(grant.agentSecretKey, grant.agentName),
|
|
55718
|
-
bodyIdentity: identityFromKey(grant.bodySecretKey, DEFAULT_BODY_IDENTITY_NAME),
|
|
55719
|
-
cwd: process.cwd(),
|
|
55720
|
-
repo: null,
|
|
55721
|
-
progressLabel: "Connecting agent\u2026",
|
|
55722
|
-
progressDone: (pid) => `Connected (pid ${pid}).`,
|
|
55871
|
+
const localConfig = options.localConfig ?? loadBodyConfig({
|
|
55872
|
+
workspaceRoot: process.cwd(),
|
|
55723
55873
|
...grant.llmEnvFile ? { llmEnvFile: grant.llmEnvFile } : {},
|
|
55724
|
-
|
|
55874
|
+
agent: selectedAgent
|
|
55875
|
+
});
|
|
55876
|
+
await (options.validateSelection ?? validateModelSelection)(selectedAgent, localConfig.agentEnv, {
|
|
55877
|
+
model: grant.model
|
|
55878
|
+
});
|
|
55879
|
+
const agentIdentity = identityFromKey(grant.agentSecretKey, grant.agentName);
|
|
55880
|
+
const staged = await stageMonolithAgentRuntime({
|
|
55881
|
+
workspaceId: grant.workspaceId,
|
|
55882
|
+
pairedBy: grant.pairedBy,
|
|
55883
|
+
monolithBaseUrl: grant.monolithBaseUrl,
|
|
55884
|
+
daemonExchangeToken: grant.daemonExchangeToken,
|
|
55885
|
+
...grant.llmEnvFile ? { llmEnvFile: grant.llmEnvFile } : {},
|
|
55886
|
+
agentBinary: localConfig.agentBinary,
|
|
55887
|
+
agentKind: selectedAgent.kind,
|
|
55888
|
+
agentCommand: selectedAgent.command,
|
|
55889
|
+
agentArgs: selectedAgent.args,
|
|
55725
55890
|
modelSelection: { model: grant.model },
|
|
55726
|
-
|
|
55727
|
-
|
|
55891
|
+
mcpBinary: localConfig.mcpBinary,
|
|
55892
|
+
agentIdentity,
|
|
55893
|
+
bodyIdentity: identityFromKey(grant.bodySecretKey, DEFAULT_BODY_IDENTITY_NAME),
|
|
55894
|
+
...options.supervisorRoot ? { supervisorRoot: options.supervisorRoot } : {}
|
|
55728
55895
|
});
|
|
55729
|
-
|
|
55730
|
-
|
|
55896
|
+
const activated = await activateDaemonTransport(staged.configPath, options.fetchImpl);
|
|
55897
|
+
if (!activated)
|
|
55898
|
+
throw new Error("monolith daemon transport activation failed");
|
|
55899
|
+
let pid;
|
|
55900
|
+
try {
|
|
55901
|
+
pid = await (options.launch ?? (async (configPath, publicKey) => process.platform === "linux" && process.env.BEELINE_SYSTEMD_USER !== "0" ? installAgentService(publicKey) : launchRuntimeDaemon(configPath)))(staged.configPath, agentIdentity.publicKey);
|
|
55902
|
+
} catch (error) {
|
|
55903
|
+
throw new Error(`agent ${agentIdentity.publicKey} is connected, but its daemon did not start: ${error instanceof Error ? error.message : String(error)}. Run \`beeline start --agent ${agentIdentity.publicKey}\`.`, { cause: error });
|
|
55731
55904
|
}
|
|
55732
|
-
return
|
|
55905
|
+
return { runtime: activated.runtime, configPath: staged.configPath, pid };
|
|
55733
55906
|
}
|
|
55734
55907
|
function printPairResult(result) {
|
|
55735
55908
|
console.log(`[buzz] paired agent ${import_picocolors3.default.bold(result.pairing.agent.displayName)}`);
|
|
@@ -55857,7 +56030,6 @@ async function runPairCommand(args, llmEnvFile, agentPrivateKey) {
|
|
|
55857
56030
|
|
|
55858
56031
|
// apps/body/dist/connect-command.js
|
|
55859
56032
|
import { spawn as spawn12 } from "node:child_process";
|
|
55860
|
-
import { createHash as createHash15, randomBytes as randomBytes7 } from "node:crypto";
|
|
55861
56033
|
import { chmod as chmod7, mkdir as mkdir18, readFile as readFile13, unlink as unlink5, writeFile as writeFile12 } from "node:fs/promises";
|
|
55862
56034
|
import { dirname as dirname16, resolve as resolve37 } from "node:path";
|
|
55863
56035
|
import { stdin as stdin4, stdout as stdout5 } from "node:process";
|
|
@@ -55999,9 +56171,6 @@ async function collectConnectWizard(prompts = clackPrompts, loadModels = loadCon
|
|
|
55999
56171
|
soul: soul.trim()
|
|
56000
56172
|
};
|
|
56001
56173
|
}
|
|
56002
|
-
function sha2564(value) {
|
|
56003
|
-
return createHash15("sha256").update(value).digest("hex");
|
|
56004
|
-
}
|
|
56005
56174
|
async function jsonRequest(url, body, fetchImpl) {
|
|
56006
56175
|
const response = await fetchImpl(url, {
|
|
56007
56176
|
method: "POST",
|
|
@@ -56015,41 +56184,15 @@ async function jsonRequest(url, body, fetchImpl) {
|
|
|
56015
56184
|
}
|
|
56016
56185
|
return response.json();
|
|
56017
56186
|
}
|
|
56018
|
-
|
|
56019
|
-
|
|
56020
|
-
|
|
56021
|
-
|
|
56022
|
-
|
|
56023
|
-
|
|
56024
|
-
|
|
56025
|
-
|
|
56026
|
-
|
|
56027
|
-
});
|
|
56028
|
-
});
|
|
56029
|
-
}
|
|
56030
|
-
async function pollDeviceGrant(input) {
|
|
56031
|
-
const deadline = Date.now() + input.start.expires_in * 1e3;
|
|
56032
|
-
while (Date.now() < deadline) {
|
|
56033
|
-
const response = await input.fetchImpl(`${input.baseUrl}/auth/device/token`, {
|
|
56034
|
-
method: "POST",
|
|
56035
|
-
headers: { "content-type": "application/json" },
|
|
56036
|
-
body: JSON.stringify({
|
|
56037
|
-
device_code: input.start.device_code,
|
|
56038
|
-
code_verifier: input.verifier
|
|
56039
|
-
}),
|
|
56040
|
-
signal: AbortSignal.timeout(3e4)
|
|
56041
|
-
});
|
|
56042
|
-
if (response.status === 428) {
|
|
56043
|
-
await new Promise((resolveWait) => setTimeout(resolveWait, input.start.interval * 1e3));
|
|
56044
|
-
continue;
|
|
56045
|
-
}
|
|
56046
|
-
if (!response.ok) {
|
|
56047
|
-
const detail = await response.json().catch(() => ({}));
|
|
56048
|
-
throw new Error(detail.message ?? detail.error ?? `authorization failed (HTTP ${response.status})`);
|
|
56049
|
-
}
|
|
56050
|
-
return response.json();
|
|
56051
|
-
}
|
|
56052
|
-
throw new Error("browser authorization expired; run `npx usebeeline connect` again");
|
|
56187
|
+
function requestConnectGrant(baseUrl, pairingCode, selection, fetchImpl) {
|
|
56188
|
+
return jsonRequest(`${baseUrl}/auth/agent/connect`, {
|
|
56189
|
+
pairing_code: pairingCode.trim().toUpperCase(),
|
|
56190
|
+
harness: selection.harness,
|
|
56191
|
+
...selection.provider ? { provider: selection.provider } : {},
|
|
56192
|
+
model: selection.model,
|
|
56193
|
+
soul: selection.soul,
|
|
56194
|
+
agent_name: selection.name
|
|
56195
|
+
}, fetchImpl);
|
|
56053
56196
|
}
|
|
56054
56197
|
async function installCurrentRelease(fetchImpl) {
|
|
56055
56198
|
const manifestUrl = resolveManifestUrl(process.env);
|
|
@@ -56136,34 +56279,23 @@ async function brassSpinner(message2, action) {
|
|
|
56136
56279
|
throw error;
|
|
56137
56280
|
}
|
|
56138
56281
|
}
|
|
56139
|
-
async function runConnectCommand(options = {}) {
|
|
56282
|
+
async function runConnectCommand(code, options = {}) {
|
|
56140
56283
|
if (!stdin4.isTTY || !stdout5.isTTY) {
|
|
56141
56284
|
throw new Error("`usebeeline connect` needs an interactive terminal");
|
|
56142
56285
|
}
|
|
56143
56286
|
intro(brass("Beeline connect"));
|
|
56287
|
+
const pairingCode = code?.trim() || await clackPrompts.text({
|
|
56288
|
+
message: brass("Pairing code from the app"),
|
|
56289
|
+
validate: (value) => value.trim() ? void 0 : "Pairing code is required"
|
|
56290
|
+
});
|
|
56144
56291
|
const selection = await collectConnectWizard();
|
|
56145
56292
|
const fetchImpl = options.fetchImpl ?? fetch;
|
|
56146
56293
|
const baseUrl = (process.env.BEELINE_AUTH_URL ?? "https://server.usebeeline.app").replace(/\/$/, "");
|
|
56147
|
-
const
|
|
56148
|
-
const start = await brassSpinner("Preparing secure sign-in\u2026", () => jsonRequest(`${baseUrl}/auth/device/connect`, {
|
|
56149
|
-
harness: selection.harness,
|
|
56150
|
-
...selection.provider ? { provider: selection.provider } : {},
|
|
56151
|
-
model: selection.model,
|
|
56152
|
-
soul: selection.soul,
|
|
56153
|
-
agent_name: selection.name,
|
|
56154
|
-
code_challenge: sha2564(verifier)
|
|
56155
|
-
}, fetchImpl));
|
|
56156
|
-
try {
|
|
56157
|
-
await openBrowser(start.verification_uri_complete);
|
|
56158
|
-
} catch {
|
|
56159
|
-
console.log(`Open this link to connect: ${start.verification_uri_complete}`);
|
|
56160
|
-
}
|
|
56161
|
-
const grant = await brassSpinner("Connecting to your Beeline Workspace\u2026", () => pollDeviceGrant({ baseUrl, start, verifier, fetchImpl }));
|
|
56294
|
+
const grant = await brassSpinner("Connecting to your Beeline Workspace\u2026", () => requestConnectGrant(baseUrl, pairingCode, selection, fetchImpl));
|
|
56162
56295
|
const installedBinary = await brassSpinner("Installing the Beeline daemon\u2026", () => installCurrentRelease(fetchImpl));
|
|
56163
56296
|
const llmEnvFile = await writeProviderEnv(selection, grant.agent_pubkey);
|
|
56164
56297
|
const grantPath = resolve37(defaultSupervisorRoot(process.env), "beeline", "connect", `grant-${process.pid}-${Date.now()}.json`);
|
|
56165
56298
|
await writePrivateJson(grantPath, {
|
|
56166
|
-
pairingCode: grant.pairing_code,
|
|
56167
56299
|
agentSecretKey: grant.agent_secret_key,
|
|
56168
56300
|
bodySecretKey: grant.body_secret_key,
|
|
56169
56301
|
agentName: grant.agent_name,
|
|
@@ -56172,6 +56304,9 @@ async function runConnectCommand(options = {}) {
|
|
|
56172
56304
|
soul: grant.soul,
|
|
56173
56305
|
workspaceId: grant.workspace_id,
|
|
56174
56306
|
workspaceName: grant.workspace_name,
|
|
56307
|
+
pairedBy: grant.paired_by,
|
|
56308
|
+
monolithBaseUrl: baseUrl,
|
|
56309
|
+
daemonExchangeToken: grant.daemon_exchange_token,
|
|
56175
56310
|
...llmEnvFile ? { llmEnvFile } : {}
|
|
56176
56311
|
});
|
|
56177
56312
|
await brassSpinner("Starting your agent\u2026", () => runInstalledFinish(installedBinary, grantPath));
|
|
@@ -56184,7 +56319,13 @@ function isDevicePairingGrant(value) {
|
|
|
56184
56319
|
if (!value || typeof value !== "object")
|
|
56185
56320
|
return false;
|
|
56186
56321
|
const grant = value;
|
|
56187
|
-
|
|
56322
|
+
let monolithOrigin = "";
|
|
56323
|
+
try {
|
|
56324
|
+
monolithOrigin = new URL(grant.monolithBaseUrl ?? "").origin;
|
|
56325
|
+
} catch {
|
|
56326
|
+
return false;
|
|
56327
|
+
}
|
|
56328
|
+
return typeof grant.agentSecretKey === "string" && /^[0-9a-f]{64}$/.test(grant.agentSecretKey) && typeof grant.bodySecretKey === "string" && /^[0-9a-f]{64}$/.test(grant.bodySecretKey) && typeof grant.agentName === "string" && CONNECT_HARNESSES.includes(grant.harness) && typeof grant.model === "string" && typeof grant.soul === "string" && typeof grant.workspaceId === "string" && typeof grant.workspaceName === "string" && typeof grant.pairedBy === "string" && /^[0-9a-f]{64}$/.test(grant.pairedBy) && typeof grant.monolithBaseUrl === "string" && grant.monolithBaseUrl === monolithOrigin && /^https?:$/.test(new URL(monolithOrigin).protocol) && typeof grant.daemonExchangeToken === "string" && /^bde_[A-Za-z0-9_-]{43}$/.test(grant.daemonExchangeToken);
|
|
56188
56329
|
}
|
|
56189
56330
|
async function runConnectFinishCommand(path) {
|
|
56190
56331
|
if (!path)
|
|
@@ -57200,7 +57341,7 @@ ${import_picocolors6.default.dim("Usage:")}
|
|
|
57200
57341
|
beeline archive <subchannel-uuid> Archive subchannel
|
|
57201
57342
|
beeline pair <BUZZ-XXXX-XXXX> [options] Pair an agent (optionally to this repo)
|
|
57202
57343
|
and start its durable daemon
|
|
57203
|
-
beeline connect
|
|
57344
|
+
beeline connect [BUZZ-XXXX-XXXX] Install and connect an app-authorized agent
|
|
57204
57345
|
beeline start [agent-pubkey] Start \u2014 or RESTART when already running,
|
|
57205
57346
|
stopping cleanly after in-flight work \u2014
|
|
57206
57347
|
this repo's (or, outside a repo, this
|
|
@@ -57590,7 +57731,7 @@ async function main2() {
|
|
|
57590
57731
|
return;
|
|
57591
57732
|
}
|
|
57592
57733
|
if (command === "connect") {
|
|
57593
|
-
await runConnectCommand();
|
|
57734
|
+
await runConnectCommand(args[1]);
|
|
57594
57735
|
return;
|
|
57595
57736
|
}
|
|
57596
57737
|
if (command === "connect-finish") {
|