@huynle/hub 0.9.2 → 0.10.1
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/CHANGELOG.md +320 -0
- package/Dockerfile +5 -1
- package/README.md +154 -77
- package/package.json +7 -4
- package/packages/claude-code/package.json +1 -1
- package/packages/cli/dist/hub-cli.js +534 -261
- package/packages/cli/package.json +1 -1
- package/packages/cli/src/cli.ts +36 -1
- package/packages/cli/src/subscriptions.ts +49 -0
- package/packages/codex/package.json +1 -1
- package/packages/codex/src/sessions.ts +10 -6
- package/packages/codex/src/spoke.ts +2 -1
- package/packages/node/package.json +1 -1
- package/packages/preset/package.json +1 -1
- package/packages/protocol/package.json +1 -1
- package/packages/protocol/schema/app-delivery/v1.schema.json +7 -5
- package/packages/protocol/schema/app-front/v1.schema.json +410 -0
- package/packages/protocol/src/app-front.ts +293 -0
- package/packages/protocol/src/concierge.ts +10 -1
- package/packages/protocol/src/context-cards.ts +59 -0
- package/packages/protocol/src/credentials.ts +39 -2
- package/packages/protocol/src/index.ts +81 -11
- package/packages/runtime-openshell/package.json +1 -1
- package/packages/runtime-sdk/package.json +1 -1
- package/packages/sdk/package.json +1 -1
- package/packages/sdk/src/app-front.ts +524 -0
- package/packages/sdk/src/client.ts +37 -4
- package/packages/sdk/src/envelope.ts +9 -2
- package/packages/sdk/src/errors.ts +1 -0
- package/packages/sdk/src/index.ts +1 -0
- package/packages/sdk/src/types.ts +39 -1
- package/packages/spoke-sdk/package.json +1 -1
- package/packages/spoke-sdk/src/delivery.ts +17 -1
- package/packages/spoke-sdk/src/harness-spoke.ts +4 -3
- package/packages/voice-client/README.md +146 -0
- package/packages/voice-client/src/vad/LICENSE +21 -0
- package/src/central/agent/acting-routes.ts +17 -3
- package/src/central/agent/acting.ts +12 -3
- package/src/central/agent/actor.ts +6 -1
- package/src/central/agent/app-decisions.ts +146 -0
- package/src/central/agent/app-tokens.ts +9 -3
- package/src/central/agent/audit.ts +3 -0
- package/src/central/agent/connect-routes.ts +64 -0
- package/src/central/agent/connect.ts +868 -0
- package/src/central/agent/conversation.ts +625 -0
- package/src/central/agent/decisions.ts +71 -6
- package/src/central/agent/delivery.ts +3 -0
- package/src/central/agent/directory.ts +5 -0
- package/src/central/agent/errors.ts +2 -0
- package/src/central/agent/grant-requests.ts +46 -9
- package/src/central/agent/grants.ts +13 -2
- package/src/central/agent/message-limits.ts +2 -2
- package/src/central/agent/message-routes.ts +13 -4
- package/src/central/agent/read-routes.ts +16 -2
- package/src/central/agent/routes.ts +108 -6
- package/src/central/agent/speech-routes.ts +316 -0
- package/src/central/agent/subscription-routes.ts +174 -0
- package/src/central/agent/subscriptions.ts +980 -0
- package/src/central/agent-data.ts +43 -1
- package/src/central/backend/memory-counters.ts +2 -2
- package/src/central/backend/types.ts +5 -2
- package/src/central/backend/valkey-counters.ts +5 -4
- package/src/central/client-address.ts +16 -0
- package/src/central/concierge/board-render.ts +52 -1
- package/src/central/concierge/board-routes.ts +25 -2
- package/src/central/concierge/board.ts +11 -1
- package/src/central/concierge/context.ts +29 -8
- package/src/central/concierge/grant-request.ts +216 -0
- package/src/central/concierge/prompt.ts +49 -2
- package/src/central/concierge/session-routes.ts +3 -0
- package/src/central/config.ts +64 -3
- package/src/central/context-cards/budget.ts +121 -0
- package/src/central/context-cards/changes.ts +29 -0
- package/src/central/context-cards/config.ts +145 -0
- package/src/central/context-cards/engine.ts +379 -0
- package/src/central/context-cards/inputs.ts +111 -0
- package/src/central/context-cards/pickup.ts +134 -0
- package/src/central/context-cards/registry.ts +89 -0
- package/src/central/context-cards/routes.ts +37 -0
- package/src/central/context-cards/service.ts +367 -0
- package/src/central/context-cards/store.ts +67 -0
- package/src/central/context-cards/types.ts +88 -0
- package/src/central/fetcher.ts +10 -2
- package/src/central/front-relays.ts +423 -0
- package/src/central/http.ts +547 -58
- package/src/central/human-activity.ts +453 -0
- package/src/central/llm/chat.ts +133 -0
- package/src/central/registry.ts +162 -9
- package/src/central/speech/service.ts +9 -0
- package/src/central/spoke-ws.ts +13 -0
- package/src/central/store.ts +9 -12
- package/src/config.ts +30 -13
- package/src/index.ts +45 -43
- package/src/rpc.ts +33 -4
- package/src/spoke/concierge-agent.ts +1 -1
- package/src/spoke/conversation.ts +6 -75
- package/src/spoke/deliver.ts +18 -8
- package/src/spoke/hub-rpc.ts +7 -2
- package/src/spoke/hub-tool-subscriptions.ts +82 -0
- package/src/spoke/hub-tool-title.ts +89 -0
- package/src/spoke/hub-tool.ts +56 -18
- package/src/spoke/session-context.ts +10 -2
- package/src/spoke/spoke.ts +227 -237
- package/src/spoke/summary.ts +36 -1
- package/src/spoke/taskboard.ts +5 -6
- package/src/spoke/voice-front.ts +323 -30
- package/src/spoke/who-teams.ts +51 -2
- package/src/tui-messaging.ts +24 -10
- package/src/tui.ts +6 -6
- package/web/dist/assets/{ArtifactPage-BKISN-Qj.js → ArtifactPage-CsPjam8D.js} +1 -1
- package/web/dist/assets/{ArtifactPane-CKOiAUNH.js → ArtifactPane-B9weO8L6.js} +1 -1
- package/web/dist/assets/ArtifactWorkbench-DzKhMs3l.js +6 -0
- package/web/dist/assets/{Diagram-vdpmp3xu.css → Diagram-7y8kg3og.css} +1 -1
- package/web/dist/assets/Diagram-CuRIffka.js +1 -0
- package/web/dist/assets/{Library-CcjZXsfF.js → Library-rv5DGtrm.js} +2 -2
- package/web/dist/assets/Lightbox-BlbivCkd.js +1 -0
- package/web/dist/assets/MediaImage-Ch3ryIdR.js +4 -0
- package/web/dist/assets/ProfilesDestination-DUuQ9jmd.js +1 -0
- package/web/dist/assets/{TeamsPage-CDyjrK-I.js → TeamsPage-D_17MkvN.js} +1 -1
- package/web/dist/assets/{Watchtower-DYwoUWME.js → Watchtower-DlrNOJ7X.js} +2 -2
- package/web/dist/assets/{artifacts-DU9uRgs1.js → artifacts-But87Jfo.js} +1 -1
- package/web/dist/assets/index-bX8B6NLo.js +33 -0
- package/web/dist/assets/index-rW6LKQj1.css +1 -0
- package/web/dist/assets/{live-ycZ_aQZO.js → live-BGLA-peO.js} +2 -2
- package/web/dist/assets/{pane-layout-0RrLHGDr.js → pane-layout-BW0RdX5a.js} +1 -1
- package/web/dist/assets/{renderer2d-BIwbgRoX.js → renderer2d-DyANQ1WS.js} +1 -1
- package/web/dist/assets/{renderer3d-C1a7eYGQ.js → renderer3d-vYYKFAJq.js} +1 -1
- package/web/dist/assets/{safe-area-DHhPy61Q.js → safe-area-B2Bk__FK.js} +1 -1
- package/web/dist/assets/{source-BWlvaODa.js → source-C-De8L3s.js} +1 -1
- package/web/dist/assets/toast-CXTwTvDw.js +9 -0
- package/web/dist/assets/vad-worklet-BfxJhrXy.js +27 -0
- package/web/dist/index.html +6 -6
- package/web/dist/assets/ArtifactWorkbench-d7R1o-rs.js +0 -6
- package/web/dist/assets/Diagram-azw2B_QH.js +0 -1
- package/web/dist/assets/Lightbox-Du56MXGX.js +0 -1
- package/web/dist/assets/MediaImage-Ds_JUx3a.js +0 -4
- package/web/dist/assets/ProfilesDestination-DdzbzmeK.js +0 -1
- package/web/dist/assets/index-C3ci5UtY.css +0 -1
- package/web/dist/assets/index-LNMZCqgE.js +0 -36
- package/web/dist/assets/toast-Cuu2K0hx.js +0 -1
- /package/{web/src/voice → packages/voice-client/src}/turn/LICENSE +0 -0
|
@@ -7,7 +7,7 @@ import { createInterface } from "readline";
|
|
|
7
7
|
// packages/cli/package.json
|
|
8
8
|
var package_default = {
|
|
9
9
|
name: "@huynle/hub-cli",
|
|
10
|
-
version: "0.
|
|
10
|
+
version: "0.10.1",
|
|
11
11
|
private: true,
|
|
12
12
|
description: "The hub CLI (`hub` / `hubctl`) for agents and scripts (internal; bundled into @huynle/hub, not published on its own).",
|
|
13
13
|
license: "MIT",
|
|
@@ -419,138 +419,6 @@ function parseAddress(addr) {
|
|
|
419
419
|
const scope = project ? { project } : {};
|
|
420
420
|
return role ? { kind: "role", role: match[1], ...scope } : { kind: "name", name: match[1], ...scope };
|
|
421
421
|
}
|
|
422
|
-
// packages/sdk/src/artifact-jobs.ts
|
|
423
|
-
var PATH = "/api/agent/artifacts";
|
|
424
|
-
var seg = (value) => encodeURIComponent(value);
|
|
425
|
-
var sig = (options = {}) => options.signal ? { signal: options.signal } : {};
|
|
426
|
-
function artifactJobsApi(hub) {
|
|
427
|
-
const jobs = (id) => `${PATH}/${seg(id)}/jobs`;
|
|
428
|
-
const job = (id, jobID, tail = "") => `${jobs(id)}/${seg(jobID)}${tail}`;
|
|
429
|
-
return {
|
|
430
|
-
create: async (artifactID, input, options = {}) => {
|
|
431
|
-
const response = await hub.request("POST", jobs(artifactID), { body: input, ...options.idempotencyKey ? { headers: { "idempotency-key": options.idempotencyKey } } : {}, ...sig(options) });
|
|
432
|
-
const answer = await response.json();
|
|
433
|
-
return { job: answer.job, created: response.status === 201 };
|
|
434
|
-
},
|
|
435
|
-
list: (artifactID, options = {}) => hub.call("GET", jobs(artifactID), { query: { limit: options.limit, cursor: options.cursor }, ...sig(options) }),
|
|
436
|
-
get: (artifactID, jobID, options) => hub.call("GET", job(artifactID, jobID), sig(options)),
|
|
437
|
-
context: (artifactID, jobID, options) => hub.call("GET", job(artifactID, jobID, "/context"), sig(options)),
|
|
438
|
-
proposal: (artifactID, jobID, options) => hub.call("GET", job(artifactID, jobID, "/proposal"), sig(options)),
|
|
439
|
-
submit: (artifactID, jobID, result, options) => hub.call("POST", job(artifactID, jobID, "/result"), { body: result, ...sig(options) }),
|
|
440
|
-
apply: (artifactID, jobID, expectedRevision, options) => hub.call("POST", job(artifactID, jobID, "/apply"), { body: { expectedRevision }, ...sig(options) }),
|
|
441
|
-
cancel: (artifactID, jobID, expectedRevision, options) => hub.call("POST", job(artifactID, jobID, "/cancel"), { body: { expectedRevision }, ...sig(options) })
|
|
442
|
-
};
|
|
443
|
-
}
|
|
444
|
-
|
|
445
|
-
// packages/sdk/src/artifacts.ts
|
|
446
|
-
var PATH2 = "/api/agent/artifacts";
|
|
447
|
-
var seg2 = (value) => encodeURIComponent(value);
|
|
448
|
-
var sig2 = (options = {}) => options.signal ? { signal: options.signal } : {};
|
|
449
|
-
function artifactsApi(hub) {
|
|
450
|
-
const publish = async (pathname, body, options = {}) => {
|
|
451
|
-
const response = await hub.request("POST", pathname, { body, ...options.idempotencyKey ? { headers: { "idempotency-key": options.idempotencyKey } } : {}, ...sig2(options) });
|
|
452
|
-
const answer = await response.json();
|
|
453
|
-
return { artifact: answer.artifact, revision: answer.revision, created: response.status === 201 };
|
|
454
|
-
};
|
|
455
|
-
return {
|
|
456
|
-
list: (filter = {}) => hub.call("GET", PATH2, { query: { limit: filter.limit, cursor: filter.cursor, state: filter.state, workspace: filter.workspace }, ...sig2(filter) }),
|
|
457
|
-
get: (id, options) => hub.call("GET", `${PATH2}/${seg2(id)}`, sig2(options)),
|
|
458
|
-
create: (input, options) => publish(PATH2, input, options),
|
|
459
|
-
revise: (id, input, options) => publish(`${PATH2}/${seg2(id)}/revisions`, input, options),
|
|
460
|
-
revisions: (id, options = {}) => hub.call("GET", `${PATH2}/${seg2(id)}/revisions`, { query: { limit: options.limit, cursor: options.cursor }, ...sig2(options) }),
|
|
461
|
-
revision: (id, revisionID, options) => hub.call("GET", `${PATH2}/${seg2(id)}/revisions/${seg2(revisionID)}`, sig2(options)),
|
|
462
|
-
uploadBlob: async (body, mediaType, options = {}) => {
|
|
463
|
-
const response = await hub.request("POST", `${PATH2}/blobs`, { raw: { body, contentType: mediaType }, ...options.hash ? { headers: { "x-blob-hash": options.hash } } : {}, ...sig2(options) });
|
|
464
|
-
return await response.json();
|
|
465
|
-
},
|
|
466
|
-
download: (id, revisionID, hash, options) => hub.request("GET", `${PATH2}/${seg2(id)}/revisions/${seg2(revisionID)}/blobs/${seg2(hash)}`, sig2(options)),
|
|
467
|
-
update: (id, input, options) => hub.call("PATCH", `${PATH2}/${seg2(id)}`, { body: input, ...sig2(options) }),
|
|
468
|
-
setVisibility: (id, input, options) => hub.call("PUT", `${PATH2}/${seg2(id)}/visibility`, { body: input, ...sig2(options) }),
|
|
469
|
-
archive: (id, expectedRevision, options) => hub.call("POST", `${PATH2}/${seg2(id)}/archive`, { body: { expectedRevision }, ...sig2(options) }),
|
|
470
|
-
unarchive: (id, expectedRevision, options) => hub.call("POST", `${PATH2}/${seg2(id)}/unarchive`, { body: { expectedRevision }, ...sig2(options) }),
|
|
471
|
-
delete: async (id, expectedRevision, options) => {
|
|
472
|
-
await hub.call("DELETE", `${PATH2}/${seg2(id)}`, { body: { expectedRevision }, ...sig2(options) });
|
|
473
|
-
},
|
|
474
|
-
jobs: artifactJobsApi(hub)
|
|
475
|
-
};
|
|
476
|
-
}
|
|
477
|
-
// packages/sdk/src/team-intake.ts
|
|
478
|
-
var seg3 = (value) => encodeURIComponent(value);
|
|
479
|
-
var sig3 = (options = {}) => options.signal ? { signal: options.signal } : {};
|
|
480
|
-
var path3 = (team) => `/api/agent/teams/${seg3(team)}/intake`;
|
|
481
|
-
function teamIntakeApi(hub) {
|
|
482
|
-
return {
|
|
483
|
-
submit: async (team, input, options = {}) => {
|
|
484
|
-
const response = await hub.request("POST", path3(team), { body: input, ...options.idempotencyKey ? { headers: { "idempotency-key": options.idempotencyKey } } : {}, ...sig3(options) });
|
|
485
|
-
const answer = await response.json();
|
|
486
|
-
return { intake: answer.intake, created: response.status === 201 };
|
|
487
|
-
},
|
|
488
|
-
intake: (team, intakeID, options) => hub.call("GET", `${path3(team)}/${seg3(intakeID)}`, sig3(options)),
|
|
489
|
-
intakes: (team, filter = {}) => hub.call("GET", path3(team), { query: { status: filter.status, limit: filter.limit, cursor: filter.cursor }, ...sig3(filter) }),
|
|
490
|
-
setIntakeStatus: (team, intakeID, input, options) => hub.call("POST", `${path3(team)}/${seg3(intakeID)}/status`, { body: input, ...sig3(options) })
|
|
491
|
-
};
|
|
492
|
-
}
|
|
493
|
-
var TEAM_INTAKE_STATUS_INPUTS = ["open", "in_progress", "blocked", "done", "failed", "cancelled"];
|
|
494
|
-
async function reportIntakeStatus(api, team, intakeID, input, options = {}) {
|
|
495
|
-
const expectedRevision = input.expectedRevision ?? (await api.intake(team, intakeID, options)).intake.revision;
|
|
496
|
-
return api.setIntakeStatus(team, intakeID, { status: input.status, expectedRevision, ...input.reason !== undefined ? { reason: input.reason } : {} }, options);
|
|
497
|
-
}
|
|
498
|
-
// packages/sdk/src/teams.ts
|
|
499
|
-
var seg4 = (value) => encodeURIComponent(value);
|
|
500
|
-
var sig4 = (options = {}) => options.signal ? { signal: options.signal } : {};
|
|
501
|
-
var key = (options = {}) => options.idempotencyKey ? { headers: { "idempotency-key": options.idempotencyKey } } : {};
|
|
502
|
-
var base = (team) => `/api/agent/teams/${seg4(team)}`;
|
|
503
|
-
function teamsApi(hub) {
|
|
504
|
-
const created = async (method, pathname, body, options = {}) => {
|
|
505
|
-
const response = await hub.request(method, pathname, { body, ...key(options), ...sig4(options) });
|
|
506
|
-
return { ...await response.json(), created: response.status === 201 };
|
|
507
|
-
};
|
|
508
|
-
const revised = (verb) => (team, expectedRevision, options) => hub.call("POST", `${base(team)}/${verb}`, { body: { expectedRevision }, ...sig4(options) });
|
|
509
|
-
return {
|
|
510
|
-
...teamIntakeApi(hub),
|
|
511
|
-
create: (spec, options) => created("POST", "/api/agent/teams", spec, options),
|
|
512
|
-
list: (filter = {}) => hub.call("GET", "/api/agent/teams", {
|
|
513
|
-
query: {
|
|
514
|
-
state: filter.state,
|
|
515
|
-
tag: filter.tags,
|
|
516
|
-
project: filter.project,
|
|
517
|
-
metadata: filter.metadata ? Object.entries(filter.metadata).map(([k, v]) => `${k}=${v}`) : undefined,
|
|
518
|
-
paused: filter.paused === undefined ? undefined : String(filter.paused),
|
|
519
|
-
limit: filter.limit,
|
|
520
|
-
cursor: filter.cursor
|
|
521
|
-
},
|
|
522
|
-
...sig4(filter)
|
|
523
|
-
}),
|
|
524
|
-
get: (team, options) => hub.call("GET", base(team), sig4(options)),
|
|
525
|
-
update: (team, patch, expectedRevision, options = {}) => hub.call("PATCH", base(team), { body: { ...patch, expectedRevision, ...options.publish ? { publish: true } : {} }, ...sig4(options) }),
|
|
526
|
-
draft: (team, options) => hub.call("GET", `${base(team)}/draft`, sig4(options)),
|
|
527
|
-
discardDraft: (team, expectedRevision, options) => hub.call("DELETE", `${base(team)}/draft`, { query: { expectedRevision }, ...sig4(options) }),
|
|
528
|
-
setRole: (team, role, expectedRevision, options) => {
|
|
529
|
-
const { name, ...fields } = role;
|
|
530
|
-
return hub.call("PUT", `${base(team)}/draft/roles/${seg4(name)}`, { body: { ...fields, expectedRevision }, ...sig4(options) });
|
|
531
|
-
},
|
|
532
|
-
removeRole: (team, role, expectedRevision, options) => hub.call("DELETE", `${base(team)}/draft/roles/${seg4(role)}`, { query: { expectedRevision }, ...sig4(options) }),
|
|
533
|
-
setEdge: (team, edge, expectedRevision, options) => hub.call("PUT", `${base(team)}/draft/edges`, { body: { ...edge, expectedRevision }, ...sig4(options) }),
|
|
534
|
-
removeEdge: (team, from, to, expectedRevision, options) => hub.call("DELETE", `${base(team)}/draft/edges`, { query: { from, to, expectedRevision }, ...sig4(options) }),
|
|
535
|
-
publish: (team, expectedRevision, options) => hub.call("POST", `${base(team)}/publish`, { body: { expectedRevision }, ...sig4(options) }),
|
|
536
|
-
pause: revised("pause"),
|
|
537
|
-
resume: revised("resume"),
|
|
538
|
-
archive: revised("archive"),
|
|
539
|
-
restore: revised("restore"),
|
|
540
|
-
versions: (team, options = {}) => hub.call("GET", `${base(team)}/versions`, { query: { limit: options.limit, cursor: options.cursor }, ...sig4(options) }),
|
|
541
|
-
version: (team, version, options) => hub.call("GET", `${base(team)}/versions/${version}`, sig4(options)),
|
|
542
|
-
diff: (team, options = {}) => hub.call("GET", `${base(team)}/diff`, { query: { from: options.from, to: options.to }, ...sig4(options) }),
|
|
543
|
-
staffing: (team, options = {}) => hub.call("GET", `${base(team)}/staffing`, { query: { ended: options.ended ? 1 : undefined }, ...sig4(options) }),
|
|
544
|
-
staff: (team, input, options) => created("PUT", `${base(team)}/staffing`, input, options),
|
|
545
|
-
launchMember: (team, input, options) => created("POST", `${base(team)}/staffing/launch`, input, options),
|
|
546
|
-
replace: (team, staffingID, input, options) => hub.call("POST", `${base(team)}/staffing/${seg4(staffingID)}/replace`, { body: input, ...sig4(options) }),
|
|
547
|
-
unstaff: (team, staffingID, expectedRevision, options) => hub.call("DELETE", `${base(team)}/staffing/${seg4(staffingID)}`, { query: { expectedRevision }, ...sig4(options) }),
|
|
548
|
-
roster: (team, options) => hub.call("GET", `${base(team)}/roster`, sig4(options)),
|
|
549
|
-
status: (team, options) => hub.call("GET", `${base(team)}/status`, sig4(options)),
|
|
550
|
-
settings: (options) => hub.call("GET", "/api/agent/team-settings", sig4(options)),
|
|
551
|
-
setSettings: (input, expectedRevision, options) => hub.call("PUT", "/api/agent/team-settings", { body: { teamIsolation: input.teamIsolation, expectedRevision }, ...sig4(options) })
|
|
552
|
-
};
|
|
553
|
-
}
|
|
554
422
|
// packages/sdk/src/errors.ts
|
|
555
423
|
class HubError extends Error {
|
|
556
424
|
status;
|
|
@@ -667,15 +535,288 @@ async function* sseEvents(response, signal) {
|
|
|
667
535
|
}
|
|
668
536
|
}
|
|
669
537
|
|
|
538
|
+
// packages/sdk/src/app-front.ts
|
|
539
|
+
var AGENT = "/api/agent";
|
|
540
|
+
var sig = (options = {}) => options.signal ? { signal: options.signal } : {};
|
|
541
|
+
var seg = (value) => encodeURIComponent(value).replace(/%40/g, "@");
|
|
542
|
+
var RESUMABLE = new Set(["slow", "token_expired"]);
|
|
543
|
+
function speechApi(hub) {
|
|
544
|
+
return {
|
|
545
|
+
async transcribe(audio, options = {}) {
|
|
546
|
+
const type = options.type ?? (audio instanceof Blob && audio.type ? audio.type : "audio/webm");
|
|
547
|
+
const response = await hub.request("POST", `${AGENT}/speech/transcribe`, { raw: { body: audio, contentType: type }, ...sig(options) });
|
|
548
|
+
return await response.json();
|
|
549
|
+
},
|
|
550
|
+
async speak(text, options = {}) {
|
|
551
|
+
const response = await hub.request("POST", `${AGENT}/speech/speak`, { body: { text }, ...sig(options) });
|
|
552
|
+
if (!response.body)
|
|
553
|
+
throw new HubTransportError("bad_response", "the hub sent no audio");
|
|
554
|
+
return response.body;
|
|
555
|
+
}
|
|
556
|
+
};
|
|
557
|
+
}
|
|
558
|
+
function conversationApi(hub) {
|
|
559
|
+
const at = (addr, verb) => `${AGENT}/sessions/${seg(addr)}/${verb}`;
|
|
560
|
+
return {
|
|
561
|
+
set: (addr, on, options = {}) => hub.call("POST", at(addr, "conversation"), { body: options.front === undefined ? { on } : { on, front: options.front }, ...sig(options) }),
|
|
562
|
+
utterance: (addr, text, options = {}) => hub.call("POST", at(addr, "utterance"), { body: { text }, ...sig(options) }),
|
|
563
|
+
interrupt: async (addr, options = {}) => {
|
|
564
|
+
await hub.request("POST", at(addr, "interrupt"), sig(options));
|
|
565
|
+
},
|
|
566
|
+
stream: (addr, options = {}) => streamFrames(hub, at(addr, "stream"), options)
|
|
567
|
+
};
|
|
568
|
+
}
|
|
569
|
+
function appDecisionsApi(hub) {
|
|
570
|
+
return {
|
|
571
|
+
list: (options = {}) => hub.call("GET", `${AGENT}/decisions`, { query: { answerable: 1, state: options.state }, ...sig(options) }),
|
|
572
|
+
answer: (id, answer) => {
|
|
573
|
+
const { signal: _signal, ...body } = answer;
|
|
574
|
+
return hub.call("POST", `${AGENT}/decisions/${seg(id)}/answer`, { body, ...sig(answer) });
|
|
575
|
+
}
|
|
576
|
+
};
|
|
577
|
+
}
|
|
578
|
+
function retryable(cause) {
|
|
579
|
+
if (cause instanceof HubError)
|
|
580
|
+
return cause.status === 429 || cause.status >= 500;
|
|
581
|
+
if (cause instanceof HubTransportError)
|
|
582
|
+
return cause.kind === "unreachable" || cause.kind === "stream" || cause.kind === "http" && (cause.status === undefined || cause.status === 429 || cause.status >= 500);
|
|
583
|
+
return false;
|
|
584
|
+
}
|
|
585
|
+
var wait = (ms, signal) => new Promise((resolve) => {
|
|
586
|
+
if (signal?.aborted)
|
|
587
|
+
return resolve();
|
|
588
|
+
const done = () => {
|
|
589
|
+
clearTimeout(timer);
|
|
590
|
+
signal?.removeEventListener("abort", done);
|
|
591
|
+
resolve();
|
|
592
|
+
};
|
|
593
|
+
const timer = setTimeout(done, ms);
|
|
594
|
+
signal?.addEventListener("abort", done, { once: true });
|
|
595
|
+
});
|
|
596
|
+
async function* streamFrames(hub, pathname, options) {
|
|
597
|
+
const resume = options.resume ?? true;
|
|
598
|
+
const maxReconnects = options.maxReconnects ?? 5;
|
|
599
|
+
const base = options.reconnectDelayMs ?? 1000;
|
|
600
|
+
const cap = options.maxReconnectDelayMs ?? 30000;
|
|
601
|
+
let cursor = options.cursor;
|
|
602
|
+
let misses = 0;
|
|
603
|
+
let lastFailure;
|
|
604
|
+
let retryAfterMs = 0;
|
|
605
|
+
for (let attempt = 0;; attempt++) {
|
|
606
|
+
if (options.signal?.aborted)
|
|
607
|
+
return;
|
|
608
|
+
let response;
|
|
609
|
+
try {
|
|
610
|
+
response = await hub.request("GET", pathname, { headers: { accept: "text/event-stream", ...cursor ? { "last-event-id": cursor } : {} }, ...sig(options) });
|
|
611
|
+
} catch (cause) {
|
|
612
|
+
if (attempt === 0 || options.signal?.aborted || !retryable(cause))
|
|
613
|
+
throw cause;
|
|
614
|
+
lastFailure = cause;
|
|
615
|
+
retryAfterMs = cause instanceof HubError && cause.retryAfter !== undefined ? cause.retryAfter * 1000 : 0;
|
|
616
|
+
}
|
|
617
|
+
if (response) {
|
|
618
|
+
retryAfterMs = 0;
|
|
619
|
+
if (!response.body)
|
|
620
|
+
throw new HubTransportError("bad_response", "the hub sent no stream");
|
|
621
|
+
const reader = response.body.getReader();
|
|
622
|
+
const stop = () => void reader.cancel().catch(() => {});
|
|
623
|
+
options.signal?.addEventListener("abort", stop, { once: true });
|
|
624
|
+
const parser = new SseParser;
|
|
625
|
+
const decoder = new TextDecoder;
|
|
626
|
+
lastFailure = undefined;
|
|
627
|
+
try {
|
|
628
|
+
read:
|
|
629
|
+
for (;; ) {
|
|
630
|
+
let chunk;
|
|
631
|
+
try {
|
|
632
|
+
chunk = await reader.read();
|
|
633
|
+
} catch (cause) {
|
|
634
|
+
lastFailure = cause;
|
|
635
|
+
break;
|
|
636
|
+
}
|
|
637
|
+
if (chunk.done || options.signal?.aborted)
|
|
638
|
+
break;
|
|
639
|
+
for (const event of parser.push(decoder.decode(chunk.value, { stream: true }))) {
|
|
640
|
+
if (event.id)
|
|
641
|
+
cursor = event.id;
|
|
642
|
+
if (event.event !== "message")
|
|
643
|
+
continue;
|
|
644
|
+
let frame;
|
|
645
|
+
try {
|
|
646
|
+
frame = JSON.parse(event.data);
|
|
647
|
+
} catch {
|
|
648
|
+
continue;
|
|
649
|
+
}
|
|
650
|
+
if (frame.type === "end") {
|
|
651
|
+
if (resume && RESUMABLE.has(frame.reason)) {
|
|
652
|
+
lastFailure = new HubTransportError("stream", `the stream ended (${frame.reason})`);
|
|
653
|
+
break read;
|
|
654
|
+
}
|
|
655
|
+
yield { frame };
|
|
656
|
+
return;
|
|
657
|
+
}
|
|
658
|
+
if (frame.type !== "ready")
|
|
659
|
+
misses = 0;
|
|
660
|
+
yield cursor ? { frame, cursor } : { frame };
|
|
661
|
+
if (options.signal?.aborted)
|
|
662
|
+
return;
|
|
663
|
+
}
|
|
664
|
+
}
|
|
665
|
+
} finally {
|
|
666
|
+
options.signal?.removeEventListener("abort", stop);
|
|
667
|
+
stop();
|
|
668
|
+
}
|
|
669
|
+
if (options.signal?.aborted || !resume)
|
|
670
|
+
return;
|
|
671
|
+
}
|
|
672
|
+
if (++misses > maxReconnects) {
|
|
673
|
+
throw new HubTransportError("stream", `the conversation stream gave up after ${maxReconnects} reconnects${lastFailure instanceof Error ? ` (${lastFailure.message})` : ""}`, { cause: lastFailure });
|
|
674
|
+
}
|
|
675
|
+
const backoff = Math.min(cap, base * 2 ** (misses - 1));
|
|
676
|
+
await wait(Math.max(retryAfterMs, backoff * (0.5 + Math.random() * 0.5)), options.signal);
|
|
677
|
+
}
|
|
678
|
+
}
|
|
679
|
+
// packages/sdk/src/artifact-jobs.ts
|
|
680
|
+
var PATH = "/api/agent/artifacts";
|
|
681
|
+
var seg2 = (value) => encodeURIComponent(value);
|
|
682
|
+
var sig2 = (options = {}) => options.signal ? { signal: options.signal } : {};
|
|
683
|
+
function artifactJobsApi(hub) {
|
|
684
|
+
const jobs = (id) => `${PATH}/${seg2(id)}/jobs`;
|
|
685
|
+
const job = (id, jobID, tail = "") => `${jobs(id)}/${seg2(jobID)}${tail}`;
|
|
686
|
+
return {
|
|
687
|
+
create: async (artifactID, input, options = {}) => {
|
|
688
|
+
const response = await hub.request("POST", jobs(artifactID), { body: input, ...options.idempotencyKey ? { headers: { "idempotency-key": options.idempotencyKey } } : {}, ...sig2(options) });
|
|
689
|
+
const answer = await response.json();
|
|
690
|
+
return { job: answer.job, created: response.status === 201 };
|
|
691
|
+
},
|
|
692
|
+
list: (artifactID, options = {}) => hub.call("GET", jobs(artifactID), { query: { limit: options.limit, cursor: options.cursor }, ...sig2(options) }),
|
|
693
|
+
get: (artifactID, jobID, options) => hub.call("GET", job(artifactID, jobID), sig2(options)),
|
|
694
|
+
context: (artifactID, jobID, options) => hub.call("GET", job(artifactID, jobID, "/context"), sig2(options)),
|
|
695
|
+
proposal: (artifactID, jobID, options) => hub.call("GET", job(artifactID, jobID, "/proposal"), sig2(options)),
|
|
696
|
+
submit: (artifactID, jobID, result, options) => hub.call("POST", job(artifactID, jobID, "/result"), { body: result, ...sig2(options) }),
|
|
697
|
+
apply: (artifactID, jobID, expectedRevision, options) => hub.call("POST", job(artifactID, jobID, "/apply"), { body: { expectedRevision }, ...sig2(options) }),
|
|
698
|
+
cancel: (artifactID, jobID, expectedRevision, options) => hub.call("POST", job(artifactID, jobID, "/cancel"), { body: { expectedRevision }, ...sig2(options) })
|
|
699
|
+
};
|
|
700
|
+
}
|
|
701
|
+
|
|
702
|
+
// packages/sdk/src/artifacts.ts
|
|
703
|
+
var PATH2 = "/api/agent/artifacts";
|
|
704
|
+
var seg3 = (value) => encodeURIComponent(value);
|
|
705
|
+
var sig3 = (options = {}) => options.signal ? { signal: options.signal } : {};
|
|
706
|
+
function artifactsApi(hub) {
|
|
707
|
+
const publish = async (pathname, body, options = {}) => {
|
|
708
|
+
const response = await hub.request("POST", pathname, { body, ...options.idempotencyKey ? { headers: { "idempotency-key": options.idempotencyKey } } : {}, ...sig3(options) });
|
|
709
|
+
const answer = await response.json();
|
|
710
|
+
return { artifact: answer.artifact, revision: answer.revision, created: response.status === 201 };
|
|
711
|
+
};
|
|
712
|
+
return {
|
|
713
|
+
list: (filter = {}) => hub.call("GET", PATH2, { query: { limit: filter.limit, cursor: filter.cursor, state: filter.state, workspace: filter.workspace }, ...sig3(filter) }),
|
|
714
|
+
get: (id, options) => hub.call("GET", `${PATH2}/${seg3(id)}`, sig3(options)),
|
|
715
|
+
create: (input, options) => publish(PATH2, input, options),
|
|
716
|
+
revise: (id, input, options) => publish(`${PATH2}/${seg3(id)}/revisions`, input, options),
|
|
717
|
+
revisions: (id, options = {}) => hub.call("GET", `${PATH2}/${seg3(id)}/revisions`, { query: { limit: options.limit, cursor: options.cursor }, ...sig3(options) }),
|
|
718
|
+
revision: (id, revisionID, options) => hub.call("GET", `${PATH2}/${seg3(id)}/revisions/${seg3(revisionID)}`, sig3(options)),
|
|
719
|
+
uploadBlob: async (body, mediaType, options = {}) => {
|
|
720
|
+
const response = await hub.request("POST", `${PATH2}/blobs`, { raw: { body, contentType: mediaType }, ...options.hash ? { headers: { "x-blob-hash": options.hash } } : {}, ...sig3(options) });
|
|
721
|
+
return await response.json();
|
|
722
|
+
},
|
|
723
|
+
download: (id, revisionID, hash, options) => hub.request("GET", `${PATH2}/${seg3(id)}/revisions/${seg3(revisionID)}/blobs/${seg3(hash)}`, sig3(options)),
|
|
724
|
+
update: (id, input, options) => hub.call("PATCH", `${PATH2}/${seg3(id)}`, { body: input, ...sig3(options) }),
|
|
725
|
+
setVisibility: (id, input, options) => hub.call("PUT", `${PATH2}/${seg3(id)}/visibility`, { body: input, ...sig3(options) }),
|
|
726
|
+
archive: (id, expectedRevision, options) => hub.call("POST", `${PATH2}/${seg3(id)}/archive`, { body: { expectedRevision }, ...sig3(options) }),
|
|
727
|
+
unarchive: (id, expectedRevision, options) => hub.call("POST", `${PATH2}/${seg3(id)}/unarchive`, { body: { expectedRevision }, ...sig3(options) }),
|
|
728
|
+
delete: async (id, expectedRevision, options) => {
|
|
729
|
+
await hub.call("DELETE", `${PATH2}/${seg3(id)}`, { body: { expectedRevision }, ...sig3(options) });
|
|
730
|
+
},
|
|
731
|
+
jobs: artifactJobsApi(hub)
|
|
732
|
+
};
|
|
733
|
+
}
|
|
734
|
+
// packages/sdk/src/team-intake.ts
|
|
735
|
+
var seg4 = (value) => encodeURIComponent(value);
|
|
736
|
+
var sig4 = (options = {}) => options.signal ? { signal: options.signal } : {};
|
|
737
|
+
var path3 = (team) => `/api/agent/teams/${seg4(team)}/intake`;
|
|
738
|
+
function teamIntakeApi(hub) {
|
|
739
|
+
return {
|
|
740
|
+
submit: async (team, input, options = {}) => {
|
|
741
|
+
const response = await hub.request("POST", path3(team), { body: input, ...options.idempotencyKey ? { headers: { "idempotency-key": options.idempotencyKey } } : {}, ...sig4(options) });
|
|
742
|
+
const answer = await response.json();
|
|
743
|
+
return { intake: answer.intake, created: response.status === 201 };
|
|
744
|
+
},
|
|
745
|
+
intake: (team, intakeID, options) => hub.call("GET", `${path3(team)}/${seg4(intakeID)}`, sig4(options)),
|
|
746
|
+
intakes: (team, filter = {}) => hub.call("GET", path3(team), { query: { status: filter.status, limit: filter.limit, cursor: filter.cursor }, ...sig4(filter) }),
|
|
747
|
+
setIntakeStatus: (team, intakeID, input, options) => hub.call("POST", `${path3(team)}/${seg4(intakeID)}/status`, { body: input, ...sig4(options) })
|
|
748
|
+
};
|
|
749
|
+
}
|
|
750
|
+
var TEAM_INTAKE_STATUS_INPUTS = ["open", "in_progress", "blocked", "done", "failed", "cancelled"];
|
|
751
|
+
async function reportIntakeStatus(api, team, intakeID, input, options = {}) {
|
|
752
|
+
const expectedRevision = input.expectedRevision ?? (await api.intake(team, intakeID, options)).intake.revision;
|
|
753
|
+
return api.setIntakeStatus(team, intakeID, { status: input.status, expectedRevision, ...input.reason !== undefined ? { reason: input.reason } : {} }, options);
|
|
754
|
+
}
|
|
755
|
+
// packages/sdk/src/teams.ts
|
|
756
|
+
var seg5 = (value) => encodeURIComponent(value);
|
|
757
|
+
var sig5 = (options = {}) => options.signal ? { signal: options.signal } : {};
|
|
758
|
+
var key = (options = {}) => options.idempotencyKey ? { headers: { "idempotency-key": options.idempotencyKey } } : {};
|
|
759
|
+
var base = (team) => `/api/agent/teams/${seg5(team)}`;
|
|
760
|
+
function teamsApi(hub) {
|
|
761
|
+
const created = async (method, pathname, body, options = {}) => {
|
|
762
|
+
const response = await hub.request(method, pathname, { body, ...key(options), ...sig5(options) });
|
|
763
|
+
return { ...await response.json(), created: response.status === 201 };
|
|
764
|
+
};
|
|
765
|
+
const revised = (verb) => (team, expectedRevision, options) => hub.call("POST", `${base(team)}/${verb}`, { body: { expectedRevision }, ...sig5(options) });
|
|
766
|
+
return {
|
|
767
|
+
...teamIntakeApi(hub),
|
|
768
|
+
create: (spec, options) => created("POST", "/api/agent/teams", spec, options),
|
|
769
|
+
list: (filter = {}) => hub.call("GET", "/api/agent/teams", {
|
|
770
|
+
query: {
|
|
771
|
+
state: filter.state,
|
|
772
|
+
tag: filter.tags,
|
|
773
|
+
project: filter.project,
|
|
774
|
+
metadata: filter.metadata ? Object.entries(filter.metadata).map(([k, v]) => `${k}=${v}`) : undefined,
|
|
775
|
+
paused: filter.paused === undefined ? undefined : String(filter.paused),
|
|
776
|
+
limit: filter.limit,
|
|
777
|
+
cursor: filter.cursor
|
|
778
|
+
},
|
|
779
|
+
...sig5(filter)
|
|
780
|
+
}),
|
|
781
|
+
get: (team, options) => hub.call("GET", base(team), sig5(options)),
|
|
782
|
+
update: (team, patch, expectedRevision, options = {}) => hub.call("PATCH", base(team), { body: { ...patch, expectedRevision, ...options.publish ? { publish: true } : {} }, ...sig5(options) }),
|
|
783
|
+
draft: (team, options) => hub.call("GET", `${base(team)}/draft`, sig5(options)),
|
|
784
|
+
discardDraft: (team, expectedRevision, options) => hub.call("DELETE", `${base(team)}/draft`, { query: { expectedRevision }, ...sig5(options) }),
|
|
785
|
+
setRole: (team, role, expectedRevision, options) => {
|
|
786
|
+
const { name, ...fields } = role;
|
|
787
|
+
return hub.call("PUT", `${base(team)}/draft/roles/${seg5(name)}`, { body: { ...fields, expectedRevision }, ...sig5(options) });
|
|
788
|
+
},
|
|
789
|
+
removeRole: (team, role, expectedRevision, options) => hub.call("DELETE", `${base(team)}/draft/roles/${seg5(role)}`, { query: { expectedRevision }, ...sig5(options) }),
|
|
790
|
+
setEdge: (team, edge, expectedRevision, options) => hub.call("PUT", `${base(team)}/draft/edges`, { body: { ...edge, expectedRevision }, ...sig5(options) }),
|
|
791
|
+
removeEdge: (team, from, to, expectedRevision, options) => hub.call("DELETE", `${base(team)}/draft/edges`, { query: { from, to, expectedRevision }, ...sig5(options) }),
|
|
792
|
+
publish: (team, expectedRevision, options) => hub.call("POST", `${base(team)}/publish`, { body: { expectedRevision }, ...sig5(options) }),
|
|
793
|
+
pause: revised("pause"),
|
|
794
|
+
resume: revised("resume"),
|
|
795
|
+
archive: revised("archive"),
|
|
796
|
+
restore: revised("restore"),
|
|
797
|
+
versions: (team, options = {}) => hub.call("GET", `${base(team)}/versions`, { query: { limit: options.limit, cursor: options.cursor }, ...sig5(options) }),
|
|
798
|
+
version: (team, version, options) => hub.call("GET", `${base(team)}/versions/${version}`, sig5(options)),
|
|
799
|
+
diff: (team, options = {}) => hub.call("GET", `${base(team)}/diff`, { query: { from: options.from, to: options.to }, ...sig5(options) }),
|
|
800
|
+
staffing: (team, options = {}) => hub.call("GET", `${base(team)}/staffing`, { query: { ended: options.ended ? 1 : undefined }, ...sig5(options) }),
|
|
801
|
+
staff: (team, input, options) => created("PUT", `${base(team)}/staffing`, input, options),
|
|
802
|
+
launchMember: (team, input, options) => created("POST", `${base(team)}/staffing/launch`, input, options),
|
|
803
|
+
replace: (team, staffingID, input, options) => hub.call("POST", `${base(team)}/staffing/${seg5(staffingID)}/replace`, { body: input, ...sig5(options) }),
|
|
804
|
+
unstaff: (team, staffingID, expectedRevision, options) => hub.call("DELETE", `${base(team)}/staffing/${seg5(staffingID)}`, { query: { expectedRevision }, ...sig5(options) }),
|
|
805
|
+
roster: (team, options) => hub.call("GET", `${base(team)}/roster`, sig5(options)),
|
|
806
|
+
status: (team, options) => hub.call("GET", `${base(team)}/status`, sig5(options)),
|
|
807
|
+
settings: (options) => hub.call("GET", "/api/agent/team-settings", sig5(options)),
|
|
808
|
+
setSettings: (input, expectedRevision, options) => hub.call("PUT", "/api/agent/team-settings", { body: { teamIsolation: input.teamIsolation, expectedRevision }, ...sig5(options) })
|
|
809
|
+
};
|
|
810
|
+
}
|
|
670
811
|
// packages/sdk/src/concierge.ts
|
|
671
812
|
var WATCHLIST = "/api/agent/concierge/watchlist";
|
|
672
|
-
var
|
|
813
|
+
var sig6 = (options = {}) => options.signal ? { signal: options.signal } : {};
|
|
673
814
|
function conciergeApi(hub) {
|
|
674
|
-
const verb = (name) => (addr, options) => hub.call("POST", `${WATCHLIST}/${name}`, { body: { session: addr }, ...
|
|
815
|
+
const verb = (name) => (addr, options) => hub.call("POST", `${WATCHLIST}/${name}`, { body: { session: addr }, ...sig6(options) });
|
|
675
816
|
return {
|
|
676
817
|
watchlist: {
|
|
677
|
-
get: (options) => hub.call("GET", WATCHLIST,
|
|
678
|
-
update: (patch, expectedRevision, options) => hub.call("PUT", WATCHLIST, { body: { ...patch, expectedRevision }, ...
|
|
818
|
+
get: (options) => hub.call("GET", WATCHLIST, sig6(options)),
|
|
819
|
+
update: (patch, expectedRevision, options) => hub.call("PUT", WATCHLIST, { body: { ...patch, expectedRevision }, ...sig6(options) }),
|
|
679
820
|
watch: verb("watch"),
|
|
680
821
|
unwatch: verb("unwatch"),
|
|
681
822
|
mute: verb("mute"),
|
|
@@ -685,7 +826,7 @@ function conciergeApi(hub) {
|
|
|
685
826
|
}
|
|
686
827
|
|
|
687
828
|
// packages/sdk/src/client.ts
|
|
688
|
-
var
|
|
829
|
+
var AGENT2 = "/api/agent";
|
|
689
830
|
var WAIT_POLL_MAX_S = 60;
|
|
690
831
|
function queryString(query = {}) {
|
|
691
832
|
const params = new URLSearchParams;
|
|
@@ -724,69 +865,72 @@ class HubClient {
|
|
|
724
865
|
#fetch;
|
|
725
866
|
launches = {
|
|
726
867
|
create: async (spec, options = {}) => {
|
|
727
|
-
const response = await this.request("POST", `${
|
|
728
|
-
const body = await this.#json(response, `${
|
|
868
|
+
const response = await this.request("POST", `${AGENT2}/launches`, { body: spec, ...signalOf(options) });
|
|
869
|
+
const body = await this.#json(response, `${AGENT2}/launches`);
|
|
729
870
|
return { launch: body.launch, created: response.status === 201 };
|
|
730
871
|
},
|
|
731
872
|
list: (filter = {}) => {
|
|
732
873
|
const state = typeof filter.state === "string" ? filter.state : filter.state?.join(",");
|
|
733
|
-
return this.call("GET", `${
|
|
874
|
+
return this.call("GET", `${AGENT2}/launches`, { query: { state, label: filter.label }, ...signalOf(filter) });
|
|
734
875
|
},
|
|
735
|
-
get: (id, options = {}) => this.call("GET", `${
|
|
736
|
-
stop: (id, options = {}) => this.call("DELETE", `${
|
|
876
|
+
get: (id, options = {}) => this.call("GET", `${AGENT2}/launches/${segment(id)}`, signalOf(options)),
|
|
877
|
+
stop: (id, options = {}) => this.call("DELETE", `${AGENT2}/launches/${segment(id)}`, signalOf(options))
|
|
737
878
|
};
|
|
738
879
|
profiles = {
|
|
739
|
-
create: (input, options = {}) => this.call("POST", `${
|
|
740
|
-
import: (input, options = {}) => this.call("POST", `${
|
|
741
|
-
list: (filter = {}) => this.call("GET", `${
|
|
742
|
-
get: (id, options = {}) => this.call("GET", `${
|
|
743
|
-
update: (id, patch, options = {}) => this.call("PATCH", `${
|
|
744
|
-
usage: (id, options = {}) => this.call("GET", `${
|
|
745
|
-
versions: (id, options = {}) => this.call("GET", `${
|
|
746
|
-
createVersion: (id, input, options = {}) => this.call("POST", `${
|
|
747
|
-
version: (id, version, options = {}) => this.call("GET", `${
|
|
748
|
-
skill: (id, version, name, options = {}) => this.call("GET", `${
|
|
749
|
-
render: (id, version, name, params, options = {}) => this.call("POST", `${
|
|
750
|
-
ofSession: (addr, options = {}) => this.call("GET", `${
|
|
751
|
-
assign: (addr, input, options = {}) => this.call("PUT", `${
|
|
752
|
-
unassign: (addr, expectedRevision, options = {}) => this.call("DELETE", `${
|
|
753
|
-
sessionSkill: (addr, name, options = {}) => this.call("GET", `${
|
|
754
|
-
sessionRender: (addr, name, params, options = {}) => this.call("POST", `${
|
|
880
|
+
create: (input, options = {}) => this.call("POST", `${AGENT2}/profiles`, { body: input, ...idempotent(options) }),
|
|
881
|
+
import: (input, options = {}) => this.call("POST", `${AGENT2}/profiles/import`, { body: input, ...idempotent(options) }),
|
|
882
|
+
list: (filter = {}) => this.call("GET", `${AGENT2}/profiles`, { query: { state: filter.state, limit: filter.limit, cursor: filter.cursor, include: filter.include }, ...signalOf(filter) }),
|
|
883
|
+
get: (id, options = {}) => this.call("GET", `${AGENT2}/profiles/${segment(id)}`, signalOf(options)),
|
|
884
|
+
update: (id, patch, options = {}) => this.call("PATCH", `${AGENT2}/profiles/${segment(id)}`, { body: patch, ...signalOf(options) }),
|
|
885
|
+
usage: (id, options = {}) => this.call("GET", `${AGENT2}/profiles/${segment(id)}/usage`, { query: { limit: options.limit, cursor: options.cursor }, ...signalOf(options) }),
|
|
886
|
+
versions: (id, options = {}) => this.call("GET", `${AGENT2}/profiles/${segment(id)}/versions`, { query: { limit: options.limit, cursor: options.cursor }, ...signalOf(options) }),
|
|
887
|
+
createVersion: (id, input, options = {}) => this.call("POST", `${AGENT2}/profiles/${segment(id)}/versions`, { body: input, ...idempotent(options) }),
|
|
888
|
+
version: (id, version, options = {}) => this.call("GET", `${AGENT2}/profiles/${segment(id)}/versions/${version}`, signalOf(options)),
|
|
889
|
+
skill: (id, version, name, options = {}) => this.call("GET", `${AGENT2}/profiles/${segment(id)}/versions/${version}/skills/${segment(name)}`, signalOf(options)),
|
|
890
|
+
render: (id, version, name, params, options = {}) => this.call("POST", `${AGENT2}/profiles/${segment(id)}/versions/${version}/commands/${segment(name)}/render`, { body: { params }, ...signalOf(options) }),
|
|
891
|
+
ofSession: (addr, options = {}) => this.call("GET", `${AGENT2}/sessions/${segment(addr)}/profile`, signalOf(options)),
|
|
892
|
+
assign: (addr, input, options = {}) => this.call("PUT", `${AGENT2}/sessions/${segment(addr)}/profile`, { body: input, ...signalOf(options) }),
|
|
893
|
+
unassign: (addr, expectedRevision, options = {}) => this.call("DELETE", `${AGENT2}/sessions/${segment(addr)}/profile`, { query: { expectedRevision }, ...signalOf(options) }),
|
|
894
|
+
sessionSkill: (addr, name, options = {}) => this.call("GET", `${AGENT2}/sessions/${segment(addr)}/profile/skills/${segment(name)}`, signalOf(options)),
|
|
895
|
+
sessionRender: (addr, name, params, options = {}) => this.call("POST", `${AGENT2}/sessions/${segment(addr)}/profile/commands/${segment(name)}/render`, { body: { params }, ...signalOf(options) })
|
|
755
896
|
};
|
|
756
897
|
workspaces = {
|
|
757
|
-
create: (input, options = {}) => this.call("POST", `${
|
|
758
|
-
list: (filter = {}) => this.call("GET", `${
|
|
759
|
-
get: (id, options = {}) => this.call("GET", `${
|
|
760
|
-
update: (id, patch, options = {}) => this.call("PATCH", `${
|
|
761
|
-
archive: (id, expectedRevision, options = {}) => this.call("POST", `${
|
|
762
|
-
restore: (id, expectedRevision, options = {}) => this.call("POST", `${
|
|
763
|
-
bindings: (id, options = {}) => this.call("GET", `${
|
|
764
|
-
bind: (id, input, options = {}) => this.call("POST", `${
|
|
765
|
-
unbind: (id, bindingID, expectedRevision, options = {}) => this.call("DELETE", `${
|
|
766
|
-
members: (id, options = {}) => this.call("GET", `${
|
|
767
|
-
join: (id, input, options = {}) => this.call("POST", `${
|
|
768
|
-
setRole: (id, memberID, role, expectedRevision, options = {}) => this.call("PATCH", `${
|
|
769
|
-
leave: (id, memberID, expectedRevision, options = {}) => this.call("DELETE", `${
|
|
770
|
-
assignments: (id, filter = {}) => this.call("GET", `${
|
|
771
|
-
assignment: (id, assignmentID, options = {}) => this.call("GET", `${
|
|
772
|
-
assign: (id, input, options = {}) => this.call("POST", `${
|
|
773
|
-
setAssignmentStatus: (id, assignmentID, status, expectedRevision, options = {}) => this.call("PATCH", `${
|
|
774
|
-
reassign: (id, assignmentID, memberID, expectedRevision, options = {}) => this.call("PATCH", `${
|
|
775
|
-
supervision: (id, options = {}) => this.call("GET", `${
|
|
776
|
-
supervise: (id, input, options = {}) => this.call("PUT", `${
|
|
777
|
-
board: (id, options = {}) => this.call("GET", `${
|
|
778
|
-
master: (id, options = {}) => this.call("GET", `${
|
|
779
|
-
replaceMaster: (id, input, options = {}) => this.call("POST", `${
|
|
780
|
-
createSideChat: (id, input, options = {}) => this.call("POST", `${
|
|
781
|
-
sideChats: (id, filter = {}) => this.call("GET", `${
|
|
782
|
-
sideChat: (id, sideChatID, options = {}) => this.call("GET", `${
|
|
783
|
-
sideChatByID: (sideChatID, options = {}) => this.call("GET", `${
|
|
784
|
-
refreshSideChat: (id, sideChatID, expectedRevision, options = {}) => this.call("POST", `${
|
|
785
|
-
sendToMain: (id, sideChatID, text, options = {}) => this.call("POST", `${
|
|
898
|
+
create: (input, options = {}) => this.call("POST", `${AGENT2}/workspaces`, { body: input, ...idempotent(options) }),
|
|
899
|
+
list: (filter = {}) => this.call("GET", `${AGENT2}/workspaces`, { query: { state: filter.state, limit: filter.limit, cursor: filter.cursor }, ...signalOf(filter) }),
|
|
900
|
+
get: (id, options = {}) => this.call("GET", `${AGENT2}/workspaces/${segment(id)}`, signalOf(options)),
|
|
901
|
+
update: (id, patch, options = {}) => this.call("PATCH", `${AGENT2}/workspaces/${segment(id)}`, { body: patch, ...signalOf(options) }),
|
|
902
|
+
archive: (id, expectedRevision, options = {}) => this.call("POST", `${AGENT2}/workspaces/${segment(id)}/archive`, { body: { expectedRevision }, ...signalOf(options) }),
|
|
903
|
+
restore: (id, expectedRevision, options = {}) => this.call("POST", `${AGENT2}/workspaces/${segment(id)}/restore`, { body: { expectedRevision }, ...signalOf(options) }),
|
|
904
|
+
bindings: (id, options = {}) => this.call("GET", `${AGENT2}/workspaces/${segment(id)}/bindings`, signalOf(options)),
|
|
905
|
+
bind: (id, input, options = {}) => this.call("POST", `${AGENT2}/workspaces/${segment(id)}/bindings`, { body: input, ...idempotent(options) }),
|
|
906
|
+
unbind: (id, bindingID, expectedRevision, options = {}) => this.call("DELETE", `${AGENT2}/workspaces/${segment(id)}/bindings`, { query: { bindingID, expectedRevision }, ...signalOf(options) }),
|
|
907
|
+
members: (id, options = {}) => this.call("GET", `${AGENT2}/workspaces/${segment(id)}/members`, { query: { includeLeft: options.includeLeft ? 1 : undefined }, ...signalOf(options) }),
|
|
908
|
+
join: (id, input, options = {}) => this.call("POST", `${AGENT2}/workspaces/${segment(id)}/members`, { body: input, ...idempotent(options) }),
|
|
909
|
+
setRole: (id, memberID, role, expectedRevision, options = {}) => this.call("PATCH", `${AGENT2}/workspaces/${segment(id)}/members/${segment(memberID)}`, { body: { role, expectedRevision }, ...signalOf(options) }),
|
|
910
|
+
leave: (id, memberID, expectedRevision, options = {}) => this.call("DELETE", `${AGENT2}/workspaces/${segment(id)}/members/${segment(memberID)}`, { query: { expectedRevision }, ...signalOf(options) }),
|
|
911
|
+
assignments: (id, filter = {}) => this.call("GET", `${AGENT2}/workspaces/${segment(id)}/assignments`, { query: { memberID: filter.memberID, status: filter.status, limit: filter.limit, cursor: filter.cursor }, ...signalOf(filter) }),
|
|
912
|
+
assignment: (id, assignmentID, options = {}) => this.call("GET", `${AGENT2}/workspaces/${segment(id)}/assignments/${segment(assignmentID)}`, signalOf(options)),
|
|
913
|
+
assign: (id, input, options = {}) => this.call("POST", `${AGENT2}/workspaces/${segment(id)}/assignments`, { body: input, ...idempotent(options) }),
|
|
914
|
+
setAssignmentStatus: (id, assignmentID, status, expectedRevision, options = {}) => this.call("PATCH", `${AGENT2}/workspaces/${segment(id)}/assignments/${segment(assignmentID)}`, { body: { status, expectedRevision }, ...signalOf(options) }),
|
|
915
|
+
reassign: (id, assignmentID, memberID, expectedRevision, options = {}) => this.call("PATCH", `${AGENT2}/workspaces/${segment(id)}/assignments/${segment(assignmentID)}`, { body: { memberID, expectedRevision }, ...signalOf(options) }),
|
|
916
|
+
supervision: (id, options = {}) => this.call("GET", `${AGENT2}/workspaces/${segment(id)}/supervision`, signalOf(options)),
|
|
917
|
+
supervise: (id, input, options = {}) => this.call("PUT", `${AGENT2}/workspaces/${segment(id)}/supervision`, { body: input, ...signalOf(options) }),
|
|
918
|
+
board: (id, options = {}) => this.call("GET", `${AGENT2}/workspaces/${segment(id)}/board`, signalOf(options)),
|
|
919
|
+
master: (id, options = {}) => this.call("GET", `${AGENT2}/workspaces/${segment(id)}/master`, signalOf(options)),
|
|
920
|
+
replaceMaster: (id, input, options = {}) => this.call("POST", `${AGENT2}/workspaces/${segment(id)}/master`, { body: input, ...idempotent(options) }),
|
|
921
|
+
createSideChat: (id, input, options = {}) => this.call("POST", `${AGENT2}/workspaces/${segment(id)}/side-chats`, { body: input, ...idempotent(options) }),
|
|
922
|
+
sideChats: (id, filter = {}) => this.call("GET", `${AGENT2}/workspaces/${segment(id)}/side-chats`, { query: { limit: filter.limit, cursor: filter.cursor }, ...signalOf(filter) }),
|
|
923
|
+
sideChat: (id, sideChatID, options = {}) => this.call("GET", `${AGENT2}/workspaces/${segment(id)}/side-chats/${segment(sideChatID)}`, signalOf(options)),
|
|
924
|
+
sideChatByID: (sideChatID, options = {}) => this.call("GET", `${AGENT2}/side-chats/${segment(sideChatID)}`, signalOf(options)),
|
|
925
|
+
refreshSideChat: (id, sideChatID, expectedRevision, options = {}) => this.call("POST", `${AGENT2}/workspaces/${segment(id)}/side-chats/${segment(sideChatID)}/refresh`, { body: { expectedRevision }, ...signalOf(options) }),
|
|
926
|
+
sendToMain: (id, sideChatID, text, options = {}) => this.call("POST", `${AGENT2}/workspaces/${segment(id)}/side-chats/${segment(sideChatID)}/send`, { body: { text, confirmed: true }, ...signalOf(options) })
|
|
786
927
|
};
|
|
787
928
|
artifacts = artifactsApi(this);
|
|
788
929
|
teams = teamsApi(this);
|
|
789
930
|
concierge = conciergeApi(this);
|
|
931
|
+
speech = speechApi(this);
|
|
932
|
+
conversation = conversationApi(this);
|
|
933
|
+
appDecisions = appDecisionsApi(this);
|
|
790
934
|
constructor(options) {
|
|
791
935
|
this.url = options.url;
|
|
792
936
|
this.#base = options.url.replace(/\/+$/, "");
|
|
@@ -795,7 +939,8 @@ class HubClient {
|
|
|
795
939
|
}
|
|
796
940
|
async request(method, pathname, options = {}) {
|
|
797
941
|
const target = `${pathname}${queryString(options.query)}`;
|
|
798
|
-
const
|
|
942
|
+
const token = typeof this.#token === "string" ? this.#token : await this.#token();
|
|
943
|
+
const headers = { ...options.headers, authorization: `Bearer ${token}`, accept: "application/json" };
|
|
799
944
|
if (options.body !== undefined)
|
|
800
945
|
headers["content-type"] = "application/json";
|
|
801
946
|
if (options.raw)
|
|
@@ -842,26 +987,26 @@ class HubClient {
|
|
|
842
987
|
}
|
|
843
988
|
}
|
|
844
989
|
whoami(options = {}) {
|
|
845
|
-
return this.call("GET", `${
|
|
990
|
+
return this.call("GET", `${AGENT2}/whoami`, signalOf(options));
|
|
846
991
|
}
|
|
847
992
|
status(options = {}) {
|
|
848
|
-
return this.call("GET", `${
|
|
993
|
+
return this.call("GET", `${AGENT2}/status`, signalOf(options));
|
|
849
994
|
}
|
|
850
995
|
sessions(filter = {}) {
|
|
851
996
|
const state = typeof filter.state === "string" ? filter.state : filter.state?.join(",");
|
|
852
|
-
return this.call("GET", `${
|
|
997
|
+
return this.call("GET", `${AGENT2}/sessions`, {
|
|
853
998
|
query: { project: filter.project, state, machine: filter.machine, label: filter.label, q: filter.q },
|
|
854
999
|
...signalOf(filter)
|
|
855
1000
|
});
|
|
856
1001
|
}
|
|
857
1002
|
show(addr, options = {}) {
|
|
858
|
-
return this.call("GET", `${
|
|
1003
|
+
return this.call("GET", `${AGENT2}/sessions/${segment(addr)}`, signalOf(options));
|
|
859
1004
|
}
|
|
860
1005
|
log(addr, options = {}) {
|
|
861
|
-
return this.call("GET", `${
|
|
1006
|
+
return this.call("GET", `${AGENT2}/sessions/${segment(addr)}/log`, { query: { n: options.n }, ...signalOf(options) });
|
|
862
1007
|
}
|
|
863
1008
|
who(options = {}) {
|
|
864
|
-
return this.call("GET", `${
|
|
1009
|
+
return this.call("GET", `${AGENT2}/who`, { query: { project: options.project, role: options.role === undefined ? undefined : bareRole(options.role), team: options.team }, ...signalOf(options) });
|
|
865
1010
|
}
|
|
866
1011
|
async* watch(options = {}) {
|
|
867
1012
|
const { signal } = options;
|
|
@@ -869,7 +1014,7 @@ class HubClient {
|
|
|
869
1014
|
return;
|
|
870
1015
|
let response;
|
|
871
1016
|
try {
|
|
872
|
-
response = await this.request("GET", `${
|
|
1017
|
+
response = await this.request("GET", `${AGENT2}/watch`, { query: { blocked: options.blocked ? "1" : undefined, session: options.session, cursor: options.cursor }, ...signalOf(options) });
|
|
873
1018
|
} catch (cause) {
|
|
874
1019
|
if (signal?.aborted)
|
|
875
1020
|
return;
|
|
@@ -878,49 +1023,61 @@ class HubClient {
|
|
|
878
1023
|
yield* sseEvents(response, signal);
|
|
879
1024
|
}
|
|
880
1025
|
events(options = {}) {
|
|
881
|
-
return this.call("GET", `${
|
|
1026
|
+
return this.call("GET", `${AGENT2}/events`, { query: { cursor: options.cursor, wait: options.wait, limit: options.limit, type: options.types, session: options.sessions }, ...signalOf(options) });
|
|
882
1027
|
}
|
|
883
1028
|
webhookCreate(input, options = {}) {
|
|
884
|
-
return this.call("POST", `${
|
|
1029
|
+
return this.call("POST", `${AGENT2}/webhooks`, { body: input, ...signalOf(options) });
|
|
885
1030
|
}
|
|
886
1031
|
webhooks(options = {}) {
|
|
887
|
-
return this.call("GET", `${
|
|
1032
|
+
return this.call("GET", `${AGENT2}/webhooks`, signalOf(options));
|
|
888
1033
|
}
|
|
889
1034
|
webhook(id, options = {}) {
|
|
890
|
-
return this.call("GET", `${
|
|
1035
|
+
return this.call("GET", `${AGENT2}/webhooks/${segment(id)}`, signalOf(options));
|
|
891
1036
|
}
|
|
892
1037
|
webhookDelete(id, options = {}) {
|
|
893
|
-
return this.call("DELETE", `${
|
|
1038
|
+
return this.call("DELETE", `${AGENT2}/webhooks/${segment(id)}`, signalOf(options));
|
|
1039
|
+
}
|
|
1040
|
+
subscribe(input, options = {}) {
|
|
1041
|
+
return this.call("POST", `${AGENT2}/subscriptions`, { body: input, ...signalOf(options) });
|
|
1042
|
+
}
|
|
1043
|
+
subscriptions(options = {}) {
|
|
1044
|
+
return this.call("GET", `${AGENT2}/subscriptions`, { query: { session: options.session }, ...signalOf(options) });
|
|
1045
|
+
}
|
|
1046
|
+
subscription(id, options = {}) {
|
|
1047
|
+
return this.call("GET", `${AGENT2}/subscriptions/${segment(id)}`, signalOf(options));
|
|
1048
|
+
}
|
|
1049
|
+
unsubscribe(id, options = {}) {
|
|
1050
|
+
return this.call("DELETE", `${AGENT2}/subscriptions/${segment(id)}`, signalOf(options));
|
|
894
1051
|
}
|
|
895
1052
|
setArchived(addr, archived, options = {}) {
|
|
896
|
-
return this.call("PUT", `${
|
|
1053
|
+
return this.call("PUT", `${AGENT2}/sessions/${segment(addr)}/archive`, { body: { archived }, ...signalOf(options) });
|
|
897
1054
|
}
|
|
898
1055
|
setPinned(addr, pinned, options = {}) {
|
|
899
|
-
return this.call("PUT", `${
|
|
1056
|
+
return this.call("PUT", `${AGENT2}/sessions/${segment(addr)}/pin`, { body: { pinned }, ...signalOf(options) });
|
|
900
1057
|
}
|
|
901
1058
|
intent(addr, options = {}) {
|
|
902
|
-
return this.call("GET", `${
|
|
1059
|
+
return this.call("GET", `${AGENT2}/sessions/${segment(addr)}/intent`, signalOf(options));
|
|
903
1060
|
}
|
|
904
1061
|
setIntent(addr, text, expectedRevision, options = {}) {
|
|
905
|
-
return this.call("PUT", `${
|
|
1062
|
+
return this.call("PUT", `${AGENT2}/sessions/${segment(addr)}/intent`, { body: { text, expectedRevision }, ...signalOf(options) });
|
|
906
1063
|
}
|
|
907
1064
|
previewArchiveInactive(inactiveFor, limit, options = {}) {
|
|
908
|
-
return this.call("POST", `${
|
|
1065
|
+
return this.call("POST", `${AGENT2}/sessions/archive-inactive`, { body: { preview: true, inactiveFor, limit }, ...signalOf(options) });
|
|
909
1066
|
}
|
|
910
1067
|
archiveInactive(previewToken, options = {}) {
|
|
911
|
-
return this.call("POST", `${
|
|
1068
|
+
return this.call("POST", `${AGENT2}/sessions/archive-inactive`, { body: { previewToken, confirm: true }, ...signalOf(options) });
|
|
912
1069
|
}
|
|
913
1070
|
name(name, options = {}) {
|
|
914
|
-
return this.call("POST", `${
|
|
1071
|
+
return this.call("POST", `${AGENT2}/name`, { body: { name, ...options.session ? { session: options.session } : {} }, ...signalOf(options) });
|
|
915
1072
|
}
|
|
916
1073
|
claimRole(role, options = {}) {
|
|
917
|
-
return this.call("POST", `${
|
|
1074
|
+
return this.call("POST", `${AGENT2}/roles/claim`, { body: { role: bareRole(role), ...options.exclusive ? { exclusive: true } : {}, ...roleTarget(options) }, ...signalOf(options) });
|
|
918
1075
|
}
|
|
919
1076
|
releaseRole(role, options = {}) {
|
|
920
|
-
return this.call("POST", `${
|
|
1077
|
+
return this.call("POST", `${AGENT2}/roles/release`, { body: { role: bareRole(role), ...roleTarget(options) }, ...signalOf(options) });
|
|
921
1078
|
}
|
|
922
1079
|
msg(to, text, options = {}) {
|
|
923
|
-
return this.call("POST", `${
|
|
1080
|
+
return this.call("POST", `${AGENT2}/msg`, { body: { to, text, ...sendFields(options), ...options.all ? { all: true } : {} }, ...idempotent(options) });
|
|
924
1081
|
}
|
|
925
1082
|
async ask(to, text, options = {}) {
|
|
926
1083
|
if (options.all && options.wait !== undefined)
|
|
@@ -937,7 +1094,7 @@ class HubClient {
|
|
|
937
1094
|
...options.wait !== undefined ? { wait: first } : {},
|
|
938
1095
|
...decisionFields(options)
|
|
939
1096
|
};
|
|
940
|
-
const asked = await this.call("POST", `${
|
|
1097
|
+
const asked = await this.call("POST", `${AGENT2}/ask`, { body, ...idempotent(options) });
|
|
941
1098
|
if ("sent" in asked)
|
|
942
1099
|
return asked;
|
|
943
1100
|
let current = asked;
|
|
@@ -949,28 +1106,28 @@ class HubClient {
|
|
|
949
1106
|
return current;
|
|
950
1107
|
}
|
|
951
1108
|
message(id, options = {}) {
|
|
952
|
-
return this.call("GET", `${
|
|
1109
|
+
return this.call("GET", `${AGENT2}/messages/${segment(id)}`, { query: { wait: options.wait }, ...signalOf(options) });
|
|
953
1110
|
}
|
|
954
1111
|
reply(id, text, options = {}) {
|
|
955
|
-
return this.call("POST", `${
|
|
1112
|
+
return this.call("POST", `${AGENT2}/reply`, { body: { replyTo: id, text, ...options.wake !== undefined ? { wake: options.wake } : {} }, ...signalOf(options) });
|
|
956
1113
|
}
|
|
957
1114
|
decline(id, why, options = {}) {
|
|
958
|
-
return this.call("POST", `${
|
|
1115
|
+
return this.call("POST", `${AGENT2}/decline`, { body: { replyTo: id, why }, ...signalOf(options) });
|
|
959
1116
|
}
|
|
960
1117
|
inbox(options = {}) {
|
|
961
|
-
return this.call("GET", `${
|
|
1118
|
+
return this.call("GET", `${AGENT2}/inbox`, signalOf(options));
|
|
962
1119
|
}
|
|
963
1120
|
mute(session, options = {}) {
|
|
964
|
-
return this.call("POST", `${
|
|
1121
|
+
return this.call("POST", `${AGENT2}/mute`, { body: { session }, ...signalOf(options) });
|
|
965
1122
|
}
|
|
966
1123
|
unmute(session, options = {}) {
|
|
967
|
-
return this.call("POST", `${
|
|
1124
|
+
return this.call("POST", `${AGENT2}/unmute`, { body: { session }, ...signalOf(options) });
|
|
968
1125
|
}
|
|
969
1126
|
decisions(options = {}) {
|
|
970
|
-
return this.call("GET", `${
|
|
1127
|
+
return this.call("GET", `${AGENT2}/decisions`, { query: { state: options.state }, ...signalOf(options) });
|
|
971
1128
|
}
|
|
972
1129
|
decision(id, options = {}) {
|
|
973
|
-
return this.call("GET", `${
|
|
1130
|
+
return this.call("GET", `${AGENT2}/decisions/${segment(id)}`, signalOf(options));
|
|
974
1131
|
}
|
|
975
1132
|
answerDecision(id, answer) {
|
|
976
1133
|
const { signal: _signal, ...body } = answer;
|
|
@@ -978,16 +1135,16 @@ class HubClient {
|
|
|
978
1135
|
}
|
|
979
1136
|
approve(addr, requestID, options = {}) {
|
|
980
1137
|
const body = { requestID, ...options.always ? { always: true } : {}, ...options.recommend ? { recommend: true } : {}, ...whyField(options) };
|
|
981
|
-
return this.call("POST", `${
|
|
1138
|
+
return this.call("POST", `${AGENT2}/sessions/${segment(addr)}/approve`, { body, ...signalOf(options) });
|
|
982
1139
|
}
|
|
983
1140
|
deny(addr, requestID, options = {}) {
|
|
984
|
-
return this.call("POST", `${
|
|
1141
|
+
return this.call("POST", `${AGENT2}/sessions/${segment(addr)}/deny`, { body: { requestID, ...whyField(options) }, ...signalOf(options) });
|
|
985
1142
|
}
|
|
986
1143
|
answer(addr, formID, answer, options = {}) {
|
|
987
|
-
return this.call("POST", `${
|
|
1144
|
+
return this.call("POST", `${AGENT2}/sessions/${segment(addr)}/answer`, { body: { formID, answer, ...whyField(options) }, ...signalOf(options) });
|
|
988
1145
|
}
|
|
989
1146
|
cancelForm(addr, formID, options = {}) {
|
|
990
|
-
return this.call("POST", `${
|
|
1147
|
+
return this.call("POST", `${AGENT2}/sessions/${segment(addr)}/answer`, { body: { formID, cancel: true, ...whyField(options) }, ...signalOf(options) });
|
|
991
1148
|
}
|
|
992
1149
|
prompt(addr, text, options = {}) {
|
|
993
1150
|
const body = {
|
|
@@ -997,38 +1154,38 @@ class HubClient {
|
|
|
997
1154
|
...options.wake !== undefined ? { wake: options.wake } : {},
|
|
998
1155
|
...whyField(options)
|
|
999
1156
|
};
|
|
1000
|
-
return this.call("POST", `${
|
|
1157
|
+
return this.call("POST", `${AGENT2}/sessions/${segment(addr)}/prompt`, { body, ...signalOf(options) });
|
|
1001
1158
|
}
|
|
1002
1159
|
stop(addr, options = {}) {
|
|
1003
|
-
return this.call("POST", `${
|
|
1160
|
+
return this.call("POST", `${AGENT2}/sessions/${segment(addr)}/stop`, { body: whyField(options), ...signalOf(options) });
|
|
1004
1161
|
}
|
|
1005
1162
|
grants(options = {}) {
|
|
1006
|
-
return this.call("GET", `${
|
|
1163
|
+
return this.call("GET", `${AGENT2}/grants`, signalOf(options));
|
|
1007
1164
|
}
|
|
1008
1165
|
grant(id, options = {}) {
|
|
1009
|
-
return this.call("GET", `${
|
|
1166
|
+
return this.call("GET", `${AGENT2}/grants/${segment(id)}`, signalOf(options));
|
|
1010
1167
|
}
|
|
1011
1168
|
createGrant(spec, options = {}) {
|
|
1012
|
-
return this.call("POST", `${
|
|
1169
|
+
return this.call("POST", `${AGENT2}/grants`, { body: spec, ...signalOf(options) });
|
|
1013
1170
|
}
|
|
1014
1171
|
updateGrant(id, spec, options = {}) {
|
|
1015
|
-
return this.call("PUT", `${
|
|
1172
|
+
return this.call("PUT", `${AGENT2}/grants/${segment(id)}`, { body: spec, ...signalOf(options) });
|
|
1016
1173
|
}
|
|
1017
1174
|
revokeGrant(id, options = {}) {
|
|
1018
|
-
return this.call("DELETE", `${
|
|
1175
|
+
return this.call("DELETE", `${AGENT2}/grants/${segment(id)}`, signalOf(options));
|
|
1019
1176
|
}
|
|
1020
1177
|
requestGrant(grant, why, options = {}) {
|
|
1021
|
-
return this.call("POST", `${
|
|
1178
|
+
return this.call("POST", `${AGENT2}/grants/requests`, { body: { grant, why }, ...signalOf(options) });
|
|
1022
1179
|
}
|
|
1023
1180
|
createAppToken(input = {}) {
|
|
1024
1181
|
const { signal: _signal, ...body } = input;
|
|
1025
|
-
return this.call("POST", `${
|
|
1182
|
+
return this.call("POST", `${AGENT2}/app-tokens`, { body, ...signalOf(input) });
|
|
1026
1183
|
}
|
|
1027
1184
|
appTokens(options = {}) {
|
|
1028
|
-
return this.call("GET", `${
|
|
1185
|
+
return this.call("GET", `${AGENT2}/app-tokens`, signalOf(options));
|
|
1029
1186
|
}
|
|
1030
1187
|
revokeAppToken(id, options = {}) {
|
|
1031
|
-
return this.call("DELETE", `${
|
|
1188
|
+
return this.call("DELETE", `${AGENT2}/app-tokens/${segment(id)}`, signalOf(options));
|
|
1032
1189
|
}
|
|
1033
1190
|
}
|
|
1034
1191
|
// packages/sdk/src/envelope.ts
|
|
@@ -1065,13 +1222,15 @@ function escapeBody(text) {
|
|
|
1065
1222
|
`).map((line) => FORGEABLE.test(line) ? `\\${line}` : line).join(`
|
|
1066
1223
|
`);
|
|
1067
1224
|
}
|
|
1225
|
+
var NOTICE_ONLY_APPS = new Set(["subscriptions"]);
|
|
1226
|
+
var noticeOnly = (from) => from.kind === "app" && NOTICE_ONLY_APPS.has(from.tokenID);
|
|
1068
1227
|
function renderEnvelope(input) {
|
|
1069
1228
|
const { id, kind } = input;
|
|
1070
1229
|
const to = sanitizeLabel(input.to);
|
|
1071
1230
|
const target = kind === "reply" || kind === "decline" ? `to you · re ${sanitizeLabel(input.replyTo ?? "")}` : to.startsWith("@@") ? `to ${to} → you` : "to you";
|
|
1072
1231
|
const header = `[hub] ${kind} from ${partyLabel(input.from)} ${target} · ${stamp(input.at)} · ${id}`;
|
|
1073
1232
|
const boundary = `----- ${id} -----`;
|
|
1074
|
-
const hint = kind === "ask" ? `↩ hub reply ${id} "…" · hub decline ${id} --why "…"${input.expiresAt === undefined ? "" : ` · expires ${stamp(input.expiresAt)}`}` : `↩ hub reply ${id} "…"`;
|
|
1233
|
+
const hint = noticeOnly(input.from) ? "↩ a notice: no reply needed (hub unsubscribe <sub_…> stops it)" : kind === "ask" ? `↩ hub reply ${id} "…" · hub decline ${id} --why "…"${input.expiresAt === undefined ? "" : ` · expires ${stamp(input.expiresAt)}`}` : `↩ hub reply ${id} "…"`;
|
|
1075
1234
|
return [header, boundary, escapeBody(input.text), boundary, hint].join(`
|
|
1076
1235
|
`);
|
|
1077
1236
|
}
|
|
@@ -3591,7 +3750,7 @@ function profileTemplateParts(template) {
|
|
|
3591
3750
|
|
|
3592
3751
|
// packages/protocol/src/concierge.ts
|
|
3593
3752
|
var SESSION_CONTEXT_FEATURE = "sessionContext";
|
|
3594
|
-
var SESSION_CONTEXT_KEYS = ["instructions", "board", "notes"];
|
|
3753
|
+
var SESSION_CONTEXT_KEYS = ["instructions", "board", "notes", "frontBoard"];
|
|
3595
3754
|
var SESSION_CONTEXT_LIMITS = { partChars: 40000, denyGlobs: 50, globChars: 100, allowTools: 50 };
|
|
3596
3755
|
var isRecord3 = (v) => typeof v === "object" && v !== null && !Array.isArray(v);
|
|
3597
3756
|
var TOOL_GLOB = /^[A-Za-z0-9_.*-]+$/;
|
|
@@ -4166,6 +4325,19 @@ var RECORDING_LIMITS = {
|
|
|
4166
4325
|
hubFlushMs: 2000,
|
|
4167
4326
|
hubFlushEvents: 100
|
|
4168
4327
|
};
|
|
4328
|
+
// packages/protocol/src/app-front.ts
|
|
4329
|
+
var ACCESS_TOKEN_TTL_MS = 60 * 60000;
|
|
4330
|
+
var REFRESH_TOKEN_IDLE_MS = 30 * 24 * 60 * 60000;
|
|
4331
|
+
var CONNECT_FLOW_TTL_MS = 10 * 60000;
|
|
4332
|
+
var APP_STREAM_LIMITS = {
|
|
4333
|
+
heartbeatMs: 20000,
|
|
4334
|
+
retryMs: 2000,
|
|
4335
|
+
recheckMs: 30000,
|
|
4336
|
+
bufferMaxBytes: 1 << 20,
|
|
4337
|
+
streamsPerApp: 4,
|
|
4338
|
+
streamsPerUser: 20
|
|
4339
|
+
};
|
|
4340
|
+
var LOOPBACK_HOSTS2 = new Set(["127.0.0.1", "[::1]", "localhost"]);
|
|
4169
4341
|
// packages/protocol/src/index.ts
|
|
4170
4342
|
var PROTOCOL_VERSION = 1;
|
|
4171
4343
|
var FORM_ANSWER_MAX_KEYS = 50;
|
|
@@ -4249,10 +4421,12 @@ var IMPLIED_OPENCODE_FEATURES = [
|
|
|
4249
4421
|
"expose",
|
|
4250
4422
|
"create"
|
|
4251
4423
|
];
|
|
4252
|
-
var OPTIONAL_SPOKE_FEATURES = [...IMPLIED_OPENCODE_FEATURES, "autoName", "sessionTokens", "deliver", "hubPrompt", "permissionMessage", "actTokens", "launch", "fork", "revert", "dismissError", "timelineMedia", PREVIEW_BUNDLE_FEATURE, "voiceFront"];
|
|
4424
|
+
var OPTIONAL_SPOKE_FEATURES = [...IMPLIED_OPENCODE_FEATURES, "autoName", "sessionTokens", "deliver", "hubPrompt", "permissionMessage", "actTokens", "launch", "fork", "revert", "dismissError", "timelineMedia", PREVIEW_BUNDLE_FEATURE, "voiceFront", "conciergeFront", "inboxCarried", "setModel"];
|
|
4253
4425
|
var CORE_OPS = ["turn", "steer", "interrupt", "stop", "permission", "form"];
|
|
4254
4426
|
var KNOWN_SPOKE_FEATURES = [...CORE_OPS, ...OPTIONAL_SPOKE_FEATURES, "turnEvents", PROFILE_APPLY_FEATURE, SESSION_CONTEXT_FEATURE];
|
|
4255
4427
|
var SPOKE_FEATURES = [...OPTIONAL_SPOKE_FEATURES, PROFILE_APPLY_FEATURE, SESSION_CONTEXT_FEATURE];
|
|
4428
|
+
var RELAY_TEXT_MAX = 4000;
|
|
4429
|
+
var FRONT_UPDATE_MAX = 8000;
|
|
4256
4430
|
var SESSION_TOKENS_MAX = 500;
|
|
4257
4431
|
var SESSION_TOKEN_MAX_CHARS = 4096;
|
|
4258
4432
|
var MESSAGE_KINDS = ["msg", "ask", "reply", "decline", "primer", "decision", "prompt"];
|
|
@@ -4269,6 +4443,8 @@ function featureForOp(op) {
|
|
|
4269
4443
|
return "revert";
|
|
4270
4444
|
case "removeFront":
|
|
4271
4445
|
return "voiceFront";
|
|
4446
|
+
case "frontUpdate":
|
|
4447
|
+
return "conciergeFront";
|
|
4272
4448
|
default:
|
|
4273
4449
|
return op;
|
|
4274
4450
|
}
|
|
@@ -4359,6 +4535,9 @@ function isSpokeRequest(v) {
|
|
|
4359
4535
|
return nonEmpty(v.sessionID);
|
|
4360
4536
|
if (v.op === "openLink")
|
|
4361
4537
|
return (v.sessionID === undefined || nonEmpty(v.sessionID)) && (v.voice === undefined || typeof v.voice === "boolean");
|
|
4538
|
+
if (v.op === "relayToSession") {
|
|
4539
|
+
return nonEmpty(v.frontID) && v.frontID.length <= 300 && nonEmpty(v.session) && v.session.length <= 300 && str2(v.text) && v.text.trim().length > 0 && v.text.length <= RELAY_TEXT_MAX && (v.previous === undefined || typeof v.previous === "boolean") && (v.confirm === undefined || typeof v.confirm === "boolean");
|
|
4540
|
+
}
|
|
4362
4541
|
return false;
|
|
4363
4542
|
}
|
|
4364
4543
|
var PROMPT_IMAGE_MIMES = ["image/png", "image/jpeg", "image/webp", "image/gif"];
|
|
@@ -4441,6 +4620,8 @@ function isServerRequest(v) {
|
|
|
4441
4620
|
return nonEmpty(v.sessionID);
|
|
4442
4621
|
case "setModelPrefs":
|
|
4443
4622
|
return nonEmpty(v.sessionID) && (v.voice === undefined || v.voice === null || isModelSelection(v.voice)) && (v.worker === undefined || v.worker === null || isModelSelection(v.worker)) && (v.voice !== undefined || v.worker !== undefined);
|
|
4623
|
+
case "setModel":
|
|
4624
|
+
return nonEmpty(v.sessionID) && isModelSelection(v.model);
|
|
4444
4625
|
case "timeline":
|
|
4445
4626
|
return nonEmpty(v.sessionID) && (v.limit === undefined || Number.isInteger(v.limit) && Number(v.limit) >= 1 && Number(v.limit) <= 200) && (v.cursor === undefined || str2(v.cursor) && v.cursor.length <= 4096) && (v.order === undefined || v.order === "asc" || v.order === "desc") && (v.before === undefined || nonEmpty(v.before) && v.before.length <= 4096) && (v.cursor === undefined || v.before === undefined && v.order !== "desc");
|
|
4446
4627
|
case "timelinePart":
|
|
@@ -4483,6 +4664,8 @@ function isServerRequest(v) {
|
|
|
4483
4664
|
case "dismissError":
|
|
4484
4665
|
case "removeFront":
|
|
4485
4666
|
return nonEmpty(v.sessionID);
|
|
4667
|
+
case "frontUpdate":
|
|
4668
|
+
return nonEmpty(v.sessionID) && str2(v.text) && v.text.trim().length > 0 && v.text.length <= FRONT_UPDATE_MAX && (v.finished === undefined || typeof v.finished === "boolean");
|
|
4486
4669
|
default:
|
|
4487
4670
|
return false;
|
|
4488
4671
|
}
|
|
@@ -4591,8 +4774,22 @@ var JOB_STATUSES = new Set(["running", "exited", "timeout", "killed"]);
|
|
|
4591
4774
|
var DEFAULT_LIST = Object.freeze({ days: 30, max: 100 });
|
|
4592
4775
|
var LIST_LIMITS = { days: 365, max: 500 };
|
|
4593
4776
|
var DEFAULT_SERVER = "http://127.0.0.1:4097";
|
|
4594
|
-
var
|
|
4595
|
-
var
|
|
4777
|
+
var OBSOLETE_CONFIG_KEYS = ["subagent", "workModel"];
|
|
4778
|
+
var OBSOLETE_WHY = {
|
|
4779
|
+
subagent: "the voice agent that delegated to it is gone",
|
|
4780
|
+
workModel: "the voice agent whose workers used it is gone"
|
|
4781
|
+
};
|
|
4782
|
+
var warnedKeys = new Set;
|
|
4783
|
+
function warnObsoleteKeys(raw, log = console.warn, seen = warnedKeys) {
|
|
4784
|
+
if (typeof raw !== "object" || raw === null || Array.isArray(raw))
|
|
4785
|
+
return;
|
|
4786
|
+
for (const key of OBSOLETE_CONFIG_KEYS) {
|
|
4787
|
+
if (!(key in raw) || seen.has(key))
|
|
4788
|
+
continue;
|
|
4789
|
+
seen.add(key);
|
|
4790
|
+
log(`[hub] config.json: "${key}" is obsolete (${OBSOLETE_WHY[key]}: Voice mode always uses the voice front now); it is ignored and removed on the next save`);
|
|
4791
|
+
}
|
|
4792
|
+
}
|
|
4596
4793
|
var MODEL_REF = /^[A-Za-z0-9_.-]+\/[A-Za-z0-9_.:\/-]+(?:#[A-Za-z0-9_.-]+)?$/;
|
|
4597
4794
|
var modelRef = (v) => typeof v === "string" && v.length <= 200 && MODEL_REF.test(v) ? v : undefined;
|
|
4598
4795
|
function configPath(env = process.env, home = homedir()) {
|
|
@@ -4609,7 +4806,7 @@ function prepareConfigPath(env = process.env, home = homedir(), log) {
|
|
|
4609
4806
|
return file;
|
|
4610
4807
|
}
|
|
4611
4808
|
function defaults(machineName) {
|
|
4612
|
-
return { server: DEFAULT_SERVER, mode: "off", sessions: [], machineName,
|
|
4809
|
+
return { server: DEFAULT_SERVER, mode: "off", sessions: [], machineName, autoStartLocalHub: true, herdr: true, list: { ...DEFAULT_LIST } };
|
|
4613
4810
|
}
|
|
4614
4811
|
function normalize(raw, machineName) {
|
|
4615
4812
|
const base = defaults(machineName);
|
|
@@ -4624,12 +4821,10 @@ function normalize(raw, machineName) {
|
|
|
4624
4821
|
mode,
|
|
4625
4822
|
sessions,
|
|
4626
4823
|
machineName: typeof r.machineName === "string" && r.machineName ? r.machineName : machineName,
|
|
4627
|
-
subagent: typeof r.subagent === "string" && AGENT_ID.test(r.subagent) ? r.subagent : base.subagent,
|
|
4628
4824
|
autoStartLocalHub: r.autoStartLocalHub !== false,
|
|
4629
4825
|
herdr: r.herdr !== false,
|
|
4630
4826
|
list: listWindow(r.list),
|
|
4631
4827
|
...modelRef(r.voiceModel) ? { voiceModel: modelRef(r.voiceModel) } : {},
|
|
4632
|
-
...modelRef(r.workModel) ? { workModel: modelRef(r.workModel) } : {},
|
|
4633
4828
|
...typeof r.machineID === "string" && r.machineID ? { machineID: r.machineID } : {},
|
|
4634
4829
|
...typeof r.token === "string" && r.token ? { token: r.token } : {}
|
|
4635
4830
|
};
|
|
@@ -4644,7 +4839,9 @@ function listWindow(raw) {
|
|
|
4644
4839
|
}
|
|
4645
4840
|
function readConfig(file, machineName) {
|
|
4646
4841
|
try {
|
|
4647
|
-
|
|
4842
|
+
const raw = JSON.parse(readFileSync3(file, "utf8"));
|
|
4843
|
+
warnObsoleteKeys(raw);
|
|
4844
|
+
return normalize(raw, machineName);
|
|
4648
4845
|
} catch {
|
|
4649
4846
|
return defaults(machineName);
|
|
4650
4847
|
}
|
|
@@ -5721,7 +5918,7 @@ function normalizeDirectories(raw, field, problems, options) {
|
|
|
5721
5918
|
}
|
|
5722
5919
|
return out;
|
|
5723
5920
|
}
|
|
5724
|
-
var
|
|
5921
|
+
var LOOPBACK_HOSTS3 = new Set(["127.0.0.1", "[::1]", "localhost"]);
|
|
5725
5922
|
function loopbackOrigin(raw) {
|
|
5726
5923
|
if (typeof raw !== "string" || raw.length > 2048)
|
|
5727
5924
|
return;
|
|
@@ -5733,7 +5930,7 @@ function loopbackOrigin(raw) {
|
|
|
5733
5930
|
}
|
|
5734
5931
|
if (url.protocol !== "http:" && url.protocol !== "https:")
|
|
5735
5932
|
return;
|
|
5736
|
-
if (url.username || url.password || !
|
|
5933
|
+
if (url.username || url.password || !LOOPBACK_HOSTS3.has(url.hostname))
|
|
5737
5934
|
return;
|
|
5738
5935
|
if (url.pathname !== "/" && url.pathname !== "" || url.search || url.hash)
|
|
5739
5936
|
return;
|
|
@@ -9227,7 +9424,7 @@ import { arch as osArch, platform as osPlatform } from "node:os";
|
|
|
9227
9424
|
// packages/node/package.json
|
|
9228
9425
|
var package_default2 = {
|
|
9229
9426
|
name: "@huynle/hub-node",
|
|
9230
|
-
version: "0.
|
|
9427
|
+
version: "0.10.1",
|
|
9231
9428
|
private: true,
|
|
9232
9429
|
description: "`hub node`: the per-machine daemon that prepares, collects and cleans up launch workspaces (internal; shipped inside @huynle/hub, not published on its own).",
|
|
9233
9430
|
license: "MIT",
|
|
@@ -10682,7 +10879,7 @@ import path14 from "node:path";
|
|
|
10682
10879
|
// packages/runtime-openshell/package.json
|
|
10683
10880
|
var package_default3 = {
|
|
10684
10881
|
name: "@huynle/hub-runtime-openshell",
|
|
10685
|
-
version: "0.
|
|
10882
|
+
version: "0.10.1",
|
|
10686
10883
|
private: true,
|
|
10687
10884
|
description: "The `openshell` runtime of `hub node`: launches in NVIDIA OpenShell sandboxes, driven through the openshell CLI (internal; shipped inside @huynle/hub, not published on its own).",
|
|
10688
10885
|
license: "MIT",
|
|
@@ -12337,6 +12534,46 @@ function openShellCheckText(report) {
|
|
|
12337
12534
|
`);
|
|
12338
12535
|
}
|
|
12339
12536
|
|
|
12537
|
+
// packages/cli/src/subscriptions.ts
|
|
12538
|
+
var SUBSCRIBE_FLAGS = { type: "multi", delivery: "string", batch: "string", expires: "string", "max-per-hour": "string", subscriber: "string", note: "string" };
|
|
12539
|
+
var DELIVERIES2 = ["queue", "steer", "silent"];
|
|
12540
|
+
var safe2 = (v, max = 120) => sanitizeLabel(String(v), max);
|
|
12541
|
+
function subscribeInput(addrs, flags) {
|
|
12542
|
+
if (!addrs.length)
|
|
12543
|
+
throw new UsageError("needs at least one address (a session, @@role, #team or children)");
|
|
12544
|
+
const delivery = str(flags, "delivery");
|
|
12545
|
+
if (delivery !== undefined && !DELIVERIES2.includes(delivery))
|
|
12546
|
+
throw new UsageError(`--delivery is one of ${DELIVERIES2.join(", ")}`);
|
|
12547
|
+
const batch = str(flags, "batch");
|
|
12548
|
+
const expires = str(flags, "expires");
|
|
12549
|
+
const max = str(flags, "max-per-hour");
|
|
12550
|
+
if (max !== undefined && !/^\d+$/.test(max))
|
|
12551
|
+
throw new UsageError("--max-per-hour takes a whole number (1–120)");
|
|
12552
|
+
const types = flags.type;
|
|
12553
|
+
const subscriber = str(flags, "subscriber");
|
|
12554
|
+
const note = str(flags, "note");
|
|
12555
|
+
return {
|
|
12556
|
+
to: addrs.length === 1 ? addrs[0] : [...addrs],
|
|
12557
|
+
...types?.length ? { types: types.flatMap((t) => t.split(",")).map((t) => t.trim()).filter(Boolean) } : {},
|
|
12558
|
+
...delivery !== undefined ? { delivery } : {},
|
|
12559
|
+
...batch !== undefined ? { batch: durationArg(batch, "--batch") } : {},
|
|
12560
|
+
...expires !== undefined ? { expires: durationArg(expires, "--expires") } : {},
|
|
12561
|
+
...max !== undefined ? { maxPerHour: Number(max) } : {},
|
|
12562
|
+
...subscriber !== undefined ? { subscriber } : {},
|
|
12563
|
+
...note !== undefined ? { note } : {}
|
|
12564
|
+
};
|
|
12565
|
+
}
|
|
12566
|
+
var targets = (s) => s.targets.map((t) => t.kind === "children" ? "its subagents" : safe2(t.addr, 80)).join(", ");
|
|
12567
|
+
var iso4 = (ms) => new Date(ms).toISOString().slice(0, 16) + "Z";
|
|
12568
|
+
function subscriptionLine(s) {
|
|
12569
|
+
const extra = [safe2(s.delivery, 10), `batch ${Math.round(s.batchMs / 1000)}s`, `≤${s.maxPerHour}/h`, `expires ${iso4(s.expiresAt)}`, `${s.stats.delivered} delivered`, ...s.pending ? [`${s.pending} pending`] : [], ...s.stats.dropped ? [`${s.stats.dropped} dropped`] : [], ...s.stats.suppressed ? [`${s.stats.suppressed} loop-suppressed`] : []];
|
|
12570
|
+
return `${safe2(s.id, 40)} ${safe2(s.subscriber, 80)} ← ${targets(s)} [${s.types.map((t) => safe2(t, 40)).join(",")}] ${extra.join(" · ")}${s.note ? ` "${safe2(s.note, 200)}"` : ""}`;
|
|
12571
|
+
}
|
|
12572
|
+
var subscribedText = (b) => `subscribed ${subscriptionLine(b.subscription)}
|
|
12573
|
+
the subscriber gets one hub message per batch window; stop with \`hub unsubscribe ${safe2(b.subscription.id, 40)}\``;
|
|
12574
|
+
var subscriptionsText = (b) => b.subscriptions.length ? b.subscriptions.map(subscriptionLine).join(`
|
|
12575
|
+
`) : "no subscriptions";
|
|
12576
|
+
|
|
12340
12577
|
// packages/claude-code/src/main.ts
|
|
12341
12578
|
import { spawnSync as spawnSync2 } from "node:child_process";
|
|
12342
12579
|
import { realpathSync as realpathSync5 } from "node:fs";
|
|
@@ -13022,7 +13259,7 @@ function buildHarnessHello(options) {
|
|
|
13022
13259
|
}
|
|
13023
13260
|
// packages/spoke-sdk/src/harness-spoke.ts
|
|
13024
13261
|
var INSPECT2 = Symbol.for("nodejs.util.inspect.custom");
|
|
13025
|
-
var MODIFIER_NEEDS = { permissionMessage: "permission", launch: "create", hubPrompt: "deliver", turnEvents: null };
|
|
13262
|
+
var MODIFIER_NEEDS = { permissionMessage: "permission", launch: "create", hubPrompt: "deliver", turnEvents: null, inboxCarried: null };
|
|
13026
13263
|
var ALWAYS = ["sessionTokens", "actTokens"];
|
|
13027
13264
|
var CORE2 = CORE_OPS;
|
|
13028
13265
|
|
|
@@ -13445,7 +13682,7 @@ var LINE_MAX = 16 * 1024 * 1024;
|
|
|
13445
13682
|
var STDERR_KEEP = 2000;
|
|
13446
13683
|
var record2 = (v) => typeof v === "object" && v !== null && !Array.isArray(v) ? v : {};
|
|
13447
13684
|
var sleep6 = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
|
|
13448
|
-
var
|
|
13685
|
+
var AGENT3 = /^[A-Za-z0-9][A-Za-z0-9._-]{0,99}$/;
|
|
13449
13686
|
var MODEL = /^[A-Za-z0-9][A-Za-z0-9._:@/\[\]-]{0,299}$/;
|
|
13450
13687
|
var PROVIDERS = new Set(["anthropic", "claude-code"]);
|
|
13451
13688
|
function launchDirectory(directory, roots) {
|
|
@@ -13475,7 +13712,7 @@ function launchDirectory(directory, roots) {
|
|
|
13475
13712
|
function launchAgent(agent) {
|
|
13476
13713
|
if (agent === undefined)
|
|
13477
13714
|
return;
|
|
13478
|
-
if (!
|
|
13715
|
+
if (!AGENT3.test(agent))
|
|
13479
13716
|
throw new Error(`Claude Code cannot take agent ${JSON.stringify(agent)} (letters, digits, ".", "_" and "-")`);
|
|
13480
13717
|
return agent;
|
|
13481
13718
|
}
|
|
@@ -14640,7 +14877,7 @@ import path23 from "node:path";
|
|
|
14640
14877
|
// packages/claude-code/package.json
|
|
14641
14878
|
var package_default4 = {
|
|
14642
14879
|
name: "@huynle/hub-claude-code",
|
|
14643
|
-
version: "0.
|
|
14880
|
+
version: "0.10.1",
|
|
14644
14881
|
private: true,
|
|
14645
14882
|
description: "The Claude Code hooks spoke: per-user daemon, hook bridge, plugin dir, `hub claude` wrapper and daemon-backed MCP server (internal; shipped inside @huynle/hub, not published on its own).",
|
|
14646
14883
|
license: "MIT",
|
|
@@ -14929,7 +15166,7 @@ import path26 from "node:path";
|
|
|
14929
15166
|
// packages/preset/package.json
|
|
14930
15167
|
var package_default5 = {
|
|
14931
15168
|
name: "@huynle/hub-preset",
|
|
14932
|
-
version: "0.
|
|
15169
|
+
version: "0.10.1",
|
|
14933
15170
|
private: true,
|
|
14934
15171
|
description: "The preset spoke: drives a harness without a spoke of its own through a terminal pane (tmux), described by a data-only preset; official presets in presets/ (internal; shipped inside @huynle/hub, not published on its own).",
|
|
14935
15172
|
license: "MIT",
|
|
@@ -15454,7 +15691,7 @@ import { openSync as openSync6, closeSync as closeSync6, readFileSync as readFil
|
|
|
15454
15691
|
// packages/codex/package.json
|
|
15455
15692
|
var package_default6 = {
|
|
15456
15693
|
name: "@huynle/hub-codex",
|
|
15457
|
-
version: "0.
|
|
15694
|
+
version: "0.10.1",
|
|
15458
15695
|
private: true,
|
|
15459
15696
|
description: "The Codex app-server spoke: attaches to Codex's app-server (its own over stdio, and the shared daemon's socket when present), and the `hub codex` wrapper (internal; shipped inside @huynle/hub, not published on its own).",
|
|
15460
15697
|
license: "MIT",
|
|
@@ -16026,7 +16263,7 @@ class CodexSessions {
|
|
|
16026
16263
|
const thread = this.#thread(req.sessionID);
|
|
16027
16264
|
if (thread.turnID)
|
|
16028
16265
|
throw new Error("The Codex session is busy (a turn is running); steer it instead");
|
|
16029
|
-
const turnID = await this.#startTurn(thread, input(req.text, req.images), "
|
|
16266
|
+
const turnID = await this.#startTurn(thread, input(req.text, req.images), "carried");
|
|
16030
16267
|
const end = await this.#waitTurn(thread, turnID);
|
|
16031
16268
|
const reply = thread.reply?.text ?? "";
|
|
16032
16269
|
if (!end)
|
|
@@ -16038,7 +16275,7 @@ class CodexSessions {
|
|
|
16038
16275
|
async steer(req) {
|
|
16039
16276
|
const thread = this.#thread(req.sessionID);
|
|
16040
16277
|
const id = inboxID();
|
|
16041
|
-
await this.#steerOrStart(thread, input(req.text, req.images), "
|
|
16278
|
+
await this.#steerOrStart(thread, input(req.text, req.images), "carried", id);
|
|
16042
16279
|
return { inboxID: id };
|
|
16043
16280
|
}
|
|
16044
16281
|
async interrupt(req) {
|
|
@@ -16224,7 +16461,9 @@ class CodexSessions {
|
|
|
16224
16461
|
const origin = clientID ? thread.inputs.get(clientID) : undefined;
|
|
16225
16462
|
if (clientID)
|
|
16226
16463
|
thread.inputs.delete(clientID);
|
|
16227
|
-
|
|
16464
|
+
const inboxID = plainID3(clientID && origin ? clientID : item.id);
|
|
16465
|
+
const data = origin === "hub" ? { origin: "hub" } : origin === "carried" ? { origin: "user", carried: true } : { origin: "user" };
|
|
16466
|
+
this.#emit({ type: "session.inbox.delivered", data: { sessionID: thread.hubID, inboxID, ...data } });
|
|
16228
16467
|
return;
|
|
16229
16468
|
}
|
|
16230
16469
|
if (!TOOL_ITEMS.has(item.type))
|
|
@@ -16610,7 +16849,7 @@ function startCodexSpoke(options) {
|
|
|
16610
16849
|
profileApply: profiles.handle
|
|
16611
16850
|
},
|
|
16612
16851
|
deliver: (req) => sessions.deliver(req),
|
|
16613
|
-
features: ["hubPrompt", "launch", "turnEvents"],
|
|
16852
|
+
features: ["hubPrompt", "launch", "turnEvents", "inboxCarried"],
|
|
16614
16853
|
onState: (state, error) => log(`hub connection ${state}${error ? `: ${error}` : ""}`),
|
|
16615
16854
|
...options.socket ? { socket: options.socket } : {},
|
|
16616
16855
|
...options.backoff ? { backoff: options.backoff } : {}
|
|
@@ -23277,7 +23516,7 @@ var PROVIDER_TIMEOUT_MS = 90000;
|
|
|
23277
23516
|
var MAX_OUTPUT3 = 1024 * 1024;
|
|
23278
23517
|
var VERSION_IN = /(?:^|[^0-9.])v?(\d+\.\d+\.\d+(?:-[0-9A-Za-z.-]+)?)(?![0-9A-Za-z.-])/;
|
|
23279
23518
|
var MODEL_LINE = /^[A-Za-z0-9][A-Za-z0-9._-]*\/\S+$/;
|
|
23280
|
-
var
|
|
23519
|
+
var safe3 = (detail) => isSecretValue(detail) ? "(details withheld: they looked like they carried a credential)" : detail.replace(/\s+/g, " ").trim().slice(0, 200);
|
|
23281
23520
|
var errorText5 = (error) => error instanceof Error ? error.message : String(error);
|
|
23282
23521
|
async function runOnce(options, context, argv, timeoutMs) {
|
|
23283
23522
|
try {
|
|
@@ -23352,7 +23591,7 @@ async function verifyOpencode(context, options) {
|
|
|
23352
23591
|
results = [await versionProbe2(options, context), await providerProbe(options, context), await spokeProbe2(options, context)];
|
|
23353
23592
|
}
|
|
23354
23593
|
const observedAt = context.now();
|
|
23355
|
-
return { harness: "opencode", probes: results.map((p) => ({ ...p, observedAt, ...p.detail !== undefined ? { detail:
|
|
23594
|
+
return { harness: "opencode", probes: results.map((p) => ({ ...p, observedAt, ...p.detail !== undefined ? { detail: safe3(p.detail) } : {} })) };
|
|
23356
23595
|
}
|
|
23357
23596
|
function locateOpencodeBinary(probe) {
|
|
23358
23597
|
const snap = discover(probe, { now: 0 });
|
|
@@ -25999,7 +26238,7 @@ Reading
|
|
|
25999
26238
|
|
|
26000
26239
|
Identity
|
|
26001
26240
|
hub whoami who this credential is
|
|
26002
|
-
hub who [--project P] [--role R] [--team T] named and role-holding sessions (team members: their teams)
|
|
26241
|
+
hub who [--project P] [--role R] [--team T] online, named and role-holding sessions (team members: their teams)
|
|
26003
26242
|
hub name <@name> [--session <addr>]
|
|
26004
26243
|
hub intent <addr> [text… | --clear] what the session is for (one line, ≤ 280 characters, untrusted);
|
|
26005
26244
|
no text: show it (else its title); a session token sets only its own
|
|
@@ -26116,6 +26355,15 @@ Codex (app-server spoke)
|
|
|
26116
26355
|
hub codex-spoke install|uninstall [--dry-run] | status
|
|
26117
26356
|
the spoke service as a launchd agent / systemd user unit (printed, never loaded)
|
|
26118
26357
|
|
|
26358
|
+
Subscriptions (a session hears other sessions' events as batched hub messages; docs/subscriptions.md)
|
|
26359
|
+
hub subscribe <addr|@@role|#team|children>... [--type T]... [--delivery queue|steer|silent] [--batch 30s]
|
|
26360
|
+
[--expires 1d] [--max-per-hour N] [--subscriber <addr>] [--note "…"]
|
|
26361
|
+
types: state, state:idle, blocker, message, launch, naming, presence,
|
|
26362
|
+
manage, exact types or * (default state, blocker); in a session's shell it
|
|
26363
|
+
subscribes itself, a login names --subscriber (app tokens: events:subscribe)
|
|
26364
|
+
hub subscriptions [--session <addr>] yours (or what a session subscribes to and what follows it)
|
|
26365
|
+
hub unsubscribe <subID>
|
|
26366
|
+
|
|
26119
26367
|
Concierge watchlist (users; app tokens: sessions:read to show, sessions:manage to change)
|
|
26120
26368
|
hub watchlist [show] what the Concierge watches now, and why; its config and revision
|
|
26121
26369
|
hub watchlist watch|unwatch <addr> watch a session (a subagent: its root), or stop
|
|
@@ -26699,6 +26947,31 @@ ${openedText(body.decision)}` : outcome.text);
|
|
|
26699
26947
|
answer(context, body, (b) => watchlistVerbText("unmute", b));
|
|
26700
26948
|
}
|
|
26701
26949
|
},
|
|
26950
|
+
subscribe: {
|
|
26951
|
+
args: ["addr..."],
|
|
26952
|
+
flags: SUBSCRIBE_FLAGS,
|
|
26953
|
+
async handle(context) {
|
|
26954
|
+
const input = subscribeInput(context.parsed.args, context.parsed.flags);
|
|
26955
|
+
const body = await context.hub((hub) => hub.subscribe(input));
|
|
26956
|
+
answer(context, body, subscribedText);
|
|
26957
|
+
}
|
|
26958
|
+
},
|
|
26959
|
+
subscriptions: {
|
|
26960
|
+
flags: { session: "string" },
|
|
26961
|
+
async handle(context) {
|
|
26962
|
+
const session = str(context.parsed.flags, "session");
|
|
26963
|
+
const body = await context.hub((hub) => hub.subscriptions(session !== undefined ? { session } : {}));
|
|
26964
|
+
answer(context, body, subscriptionsText);
|
|
26965
|
+
}
|
|
26966
|
+
},
|
|
26967
|
+
unsubscribe: {
|
|
26968
|
+
args: ["<subID>"],
|
|
26969
|
+
async handle(context) {
|
|
26970
|
+
const id = context.parsed.args[0];
|
|
26971
|
+
await context.hub((hub) => hub.unsubscribe(id));
|
|
26972
|
+
answer(context, { removed: id }, () => `removed ${id}`);
|
|
26973
|
+
}
|
|
26974
|
+
},
|
|
26702
26975
|
logout: {
|
|
26703
26976
|
async handle(context) {
|
|
26704
26977
|
const file = loginFile(context.io.env, context.io.home);
|