@huynle/hub 0.8.7 → 0.9.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +129 -0
- package/README.md +69 -12
- package/package.json +5 -1
- package/packages/claude-code/package.json +1 -1
- package/packages/cli/dist/hub-cli.js +278 -35
- package/packages/cli/package.json +1 -1
- package/packages/cli/src/cli.ts +23 -10
- package/packages/cli/src/http.ts +1 -0
- package/packages/cli/src/launches.ts +5 -1
- package/packages/cli/src/mcp.ts +28 -8
- package/packages/cli/src/messaging.ts +14 -0
- package/packages/cli/src/team-intake-mcp.ts +26 -2
- package/packages/codex/package.json +1 -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 +677 -0
- package/packages/protocol/src/artifacts.ts +43 -0
- package/packages/protocol/src/credentials.ts +38 -0
- package/packages/protocol/src/index.ts +56 -5
- package/packages/protocol/src/launch.ts +7 -2
- package/packages/protocol/src/markdown.ts +753 -0
- package/packages/protocol/src/media-allowlist.ts +240 -0
- package/packages/protocol/src/media.ts +120 -0
- package/packages/protocol/src/preview-bundle.ts +221 -0
- package/packages/protocol/src/voice-recording.ts +8 -0
- 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/client.ts +17 -3
- package/packages/sdk/src/errors.ts +1 -0
- package/packages/sdk/src/team-intake.ts +8 -0
- package/packages/sdk/src/types.ts +16 -2
- package/packages/spoke-sdk/package.json +1 -1
- package/src/central/agent/delivery.ts +35 -6
- package/src/central/agent/errors.ts +2 -0
- package/src/central/agent/events.ts +11 -2
- package/src/central/agent/launch-engine.ts +65 -4
- package/src/central/agent/launch-routes.ts +8 -0
- package/src/central/agent/launch-spec.ts +18 -1
- package/src/central/agent/launch-store.ts +2 -2
- package/src/central/agent/message-routes.ts +49 -11
- package/src/central/agent/messages.ts +17 -4
- package/src/central/agent/not-after.ts +28 -0
- package/src/central/agent/placement.ts +36 -4
- package/src/central/agent/routes.ts +3 -1
- package/src/central/agent/webhook-routes.ts +21 -9
- package/src/central/agent/webhooks.ts +27 -9
- package/src/central/artifacts/host.ts +3 -1
- package/src/central/artifacts/maintenance.ts +2 -1
- package/src/central/artifacts/preview-bundle.ts +81 -0
- package/src/central/artifacts/previews.ts +94 -0
- package/src/central/artifacts/routes.ts +12 -1
- package/src/central/artifacts/store.ts +198 -8
- package/src/central/config.ts +34 -0
- package/src/central/fetch-budget.ts +59 -0
- package/src/central/fetcher.ts +372 -0
- package/src/central/http.ts +277 -22
- package/src/central/media-remote.ts +248 -0
- package/src/central/media-timeline.ts +317 -0
- package/src/central/media-unfurl.ts +119 -0
- package/src/central/profiles/content.ts +3 -35
- package/src/central/recording/routes.ts +2 -2
- package/src/central/recording/schema.ts +3 -1
- package/src/central/registry.ts +449 -21
- package/src/central/spoke-ws.ts +17 -3
- package/src/central/store.ts +21 -0
- package/src/central/teams/intake-routes.ts +2 -1
- package/src/central/teams/intake.ts +200 -15
- package/src/central/unfurl-parse.ts +313 -0
- package/src/index.ts +68 -8
- package/src/speakable.ts +33 -1
- package/src/spoke/conversation.ts +7 -4
- package/src/spoke/deliver.ts +19 -0
- package/src/spoke/media-bytes.ts +171 -0
- package/src/spoke/media-policy.ts +394 -0
- package/src/spoke/media.ts +189 -0
- package/src/spoke/own-server.ts +30 -0
- package/src/spoke/preview-bundle.ts +538 -0
- package/src/spoke/spoke.ts +387 -17
- package/src/spoke/timeline.ts +59 -5
- package/src/spoke/voice-front.ts +335 -0
- package/web/dist/assets/24BXRY42-Zfr7jm_p.js +2 -0
- package/web/dist/assets/4FHPYW2L-C6Z67098.js +2 -0
- package/web/dist/assets/4LWW3ZNH-CUiYeygH.js +1 -0
- package/web/dist/assets/5THPTBWS-Ce_hS451.js +1 -0
- package/web/dist/assets/5XYWFMKW-CW-BCKiK.js +4 -0
- package/web/dist/assets/64PMEAB3-BjpCDGU9.js +8 -0
- package/web/dist/assets/6BEWHPQE-BpNa96Ze.js +2 -0
- package/web/dist/assets/6PIGVMFT-YXn9Hgnb.js +1 -0
- package/web/dist/assets/75JW6PN6-BFpDBuGN.js +2 -0
- package/web/dist/assets/7WLXJQOR-D6QVYUu9.js +1 -0
- package/web/dist/assets/7XWI72E6-BMuIspEy.js +2 -0
- package/web/dist/assets/A4UD2L5Z-BQzcD9dU.js +8 -0
- package/web/dist/assets/ArtifactPage-4GoBqSpU.js +1 -0
- package/web/dist/assets/ArtifactPane-Dx_0iWwH.js +1 -0
- package/web/dist/assets/ArtifactWorkbench-CuHgARMk.js +6 -0
- package/web/dist/assets/BGW36YJW-CJMhya8S.js +4 -0
- package/web/dist/assets/CGIZI67J-DYDSLME8.js +2 -0
- package/web/dist/assets/DKTLEL5E-DciMwFJ1.js +1 -0
- package/web/dist/assets/DNNCRC2E-BIeKf5t-.js +5 -0
- package/web/dist/assets/Diagram-CZM_R7MG.js +1 -0
- package/web/dist/assets/Diagram-vdpmp3xu.css +1 -0
- package/web/dist/assets/E67EBMDD--AucIw59.js +5 -0
- package/web/dist/assets/EFYWJBJK-CVywe_D5.js +1 -0
- package/web/dist/assets/EXE5EH6O-DR1IHCTr.js +4 -0
- package/web/dist/assets/FTXIJQGB-BZVuiBn1.js +1 -0
- package/web/dist/assets/G3MDBVQH-BZmnMkFw.js +1 -0
- package/web/dist/assets/G6GPDDNC-DEz8F449.js +2 -0
- package/web/dist/assets/G76NGGFM-CrB2V34K.js +1 -0
- package/web/dist/assets/GH6G3TJC-D3RTYEH4.js +2 -0
- package/web/dist/assets/HPNUA7RO-B19NeNOJ.js +1 -0
- package/web/dist/assets/HQRGC5D7-Dmpzq6Rn.js +4 -0
- package/web/dist/assets/IX6Z2TVR-DphRHnek.js +5 -0
- package/web/dist/assets/J77NQRCJ-B7AGcxvw.js +3 -0
- package/web/dist/assets/JAD36DTZ-B9-dbsS0.js +5 -0
- package/web/dist/assets/LF3NJQAX-koL91UZ9.js +2 -0
- package/web/dist/assets/LRZCOFJZ-Cdjasfuf.js +6 -0
- package/web/dist/assets/Library-TwvrwqSk.js +2 -0
- package/web/dist/assets/Lightbox-C8KNKwOA.css +1 -0
- package/web/dist/assets/Lightbox-Du56MXGX.js +1 -0
- package/web/dist/assets/MediaImage-Ds_JUx3a.js +4 -0
- package/web/dist/assets/N5NF2FGY-OuapYTfr.js +2 -0
- package/web/dist/assets/N7OWWQHY-BNLd-Q_U.js +2 -0
- package/web/dist/assets/NT5JY5WP-1lJM-aun.js +1 -0
- package/web/dist/assets/OT7W3RNY-jDL3drzX.js +4 -0
- package/web/dist/assets/P67P66DB-CE-opRb8.js +3 -0
- package/web/dist/assets/PFLLLM7K-DDJFgzW3.js +2 -0
- package/web/dist/assets/PUAMC4MJ-CtBm-WuU.js +12 -0
- package/web/dist/assets/PVFCHRLY-CG5JXv60.js +2 -0
- package/web/dist/assets/ProfilesDestination-rKNDpLjR.js +1 -0
- package/web/dist/assets/QQW2P742-BbcEkpa4.js +1 -0
- package/web/dist/assets/RVARI57O-CgA1WoRv.js +1 -0
- package/web/dist/assets/S63OEDPG-CKlhpvl2.js +3 -0
- package/web/dist/assets/SG5TVYLW-BBtiwXPL.js +2 -0
- package/web/dist/assets/TeamsPage-DtJylLrt.js +1 -0
- package/web/dist/assets/UGRSUGA2-urZ_hx83.js +5 -0
- package/web/dist/assets/V44WA6U7-DYfX3OlM.js +1 -0
- package/web/dist/assets/V67O4WWV-xYxJ00QW.js +1 -0
- package/web/dist/assets/VBUCM3YD-JHGjuJC_.js +1 -0
- package/web/dist/assets/VINGRCPA-DZuJa3SH.js +7 -0
- package/web/dist/assets/WL6DNKX4-BHqripdA.js +2 -0
- package/web/dist/assets/WQ63CJYP-D6G5frDY.js +2 -0
- package/web/dist/assets/Watchtower-Bmgdyfjb.js +2 -0
- package/web/dist/assets/XOYAOB3S-L-KeA1EF.js +13 -0
- package/web/dist/assets/Y5LQLG3M-dr2-erb8.js +2 -0
- package/web/dist/assets/YIK6JTN6--1t-Ud8k.js +2 -0
- package/web/dist/assets/artifacts-DU9uRgs1.js +1 -0
- package/web/dist/assets/index-C3ci5UtY.css +1 -0
- package/web/dist/assets/index-D-xG9nrc.js +36 -0
- package/web/dist/assets/lazy-f3CuUNJZ.js +43 -0
- package/web/dist/assets/live-7q72Lyj2.js +5 -0
- package/web/dist/assets/mermaid.worker-WDVRAh32.js +1 -0
- package/web/dist/assets/pane-layout-0RrLHGDr.js +1 -0
- package/web/dist/assets/preload-helper-BLdHbfdN.js +1 -0
- package/web/dist/assets/{renderer2d-CYag1CnR.js → renderer2d-hfZxM6Xl.js} +1 -1
- package/web/dist/assets/{renderer3d-BRB6rgDJ.js → renderer3d-Km9vipTM.js} +1 -1
- package/web/dist/assets/{safe-area-fOy0AOuG.js → safe-area-BAbgBiFk.js} +1 -1
- package/web/dist/assets/{silero-worker-DhlIHyD_.js → silero-worker-e802lB5T.js} +1 -1
- package/web/dist/assets/smart-turn-v3.2-cpu-WpeLRbPA.onnx +0 -0
- package/web/dist/assets/smart-turn-worker-DaVJPdvJ.js +11 -0
- package/web/dist/assets/source-BWlvaODa.js +1 -0
- package/web/dist/assets/toast-Cuu2K0hx.js +1 -0
- package/web/dist/assets/ui-CFB4wQfF.js +3 -0
- package/web/dist/index.html +8 -6
- package/web/src/voice/turn/LICENSE +28 -0
- package/web/dist/assets/ArtifactPage-Dq7VW-bU.js +0 -1
- package/web/dist/assets/ArtifactPane-DKwbMTX9.js +0 -1
- package/web/dist/assets/ArtifactWorkbench-vrgIfncX.js +0 -6
- package/web/dist/assets/Library-D6-Go6Cu.js +0 -2
- package/web/dist/assets/ProfilesDestination-BOML2Dgf.js +0 -1
- package/web/dist/assets/TeamsPage-CNBTE8gB.js +0 -1
- package/web/dist/assets/Watchtower-Dor1Ubjy.js +0 -2
- package/web/dist/assets/hub-CrbItiwP.js +0 -13
- package/web/dist/assets/index-82Ce0IAf.css +0 -1
- package/web/dist/assets/index-D9SP3_0z.js +0 -22
- package/web/dist/assets/live-BNJgy0vg.js +0 -5
- package/web/dist/assets/pane-layout-EdR1kRrG.js +0 -1
- package/web/dist/assets/preload-helper-DqrJTq0t.js +0 -1
- package/web/dist/assets/source-Wbq35qGp.js +0 -1
- package/web/dist/assets/ui-j5FFk90B.js +0 -3
|
@@ -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.9.0",
|
|
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",
|
|
@@ -710,7 +710,11 @@ var decisionFields = (options) => {
|
|
|
710
710
|
var whyField = (options) => options.why !== undefined ? { why: options.why } : {};
|
|
711
711
|
var signalOf = (options) => options.signal ? { signal: options.signal } : {};
|
|
712
712
|
var idempotent = (options) => ({ ...signalOf(options), ...options.idempotencyKey ? { headers: { "idempotency-key": options.idempotencyKey } } : {} });
|
|
713
|
-
var sendFields = (options) => ({
|
|
713
|
+
var sendFields = (options) => ({
|
|
714
|
+
...options.wake !== undefined ? { wake: options.wake } : {},
|
|
715
|
+
...options.urgent !== undefined ? { urgent: options.urgent } : {},
|
|
716
|
+
...options.notAfter !== undefined ? { notAfter: options.notAfter } : {}
|
|
717
|
+
});
|
|
714
718
|
var roleTarget = (options) => ({ ...options.session ? { session: options.session } : {}, ...options.project !== undefined ? { project: options.project } : {} });
|
|
715
719
|
|
|
716
720
|
class HubClient {
|
|
@@ -916,7 +920,7 @@ class HubClient {
|
|
|
916
920
|
return this.call("POST", `${AGENT}/roles/release`, { body: { role: bareRole(role), ...roleTarget(options) }, ...signalOf(options) });
|
|
917
921
|
}
|
|
918
922
|
msg(to, text, options = {}) {
|
|
919
|
-
return this.call("POST", `${AGENT}/msg`, { body: { to, text, ...sendFields(options), ...options.all ? { all: true } : {} }, ...
|
|
923
|
+
return this.call("POST", `${AGENT}/msg`, { body: { to, text, ...sendFields(options), ...options.all ? { all: true } : {} }, ...idempotent(options) });
|
|
920
924
|
}
|
|
921
925
|
async ask(to, text, options = {}) {
|
|
922
926
|
if (options.all && options.wait !== undefined)
|
|
@@ -933,7 +937,7 @@ class HubClient {
|
|
|
933
937
|
...options.wait !== undefined ? { wait: first } : {},
|
|
934
938
|
...decisionFields(options)
|
|
935
939
|
};
|
|
936
|
-
const asked = await this.call("POST", `${AGENT}/ask`, { body, ...
|
|
940
|
+
const asked = await this.call("POST", `${AGENT}/ask`, { body, ...idempotent(options) });
|
|
937
941
|
if ("sent" in asked)
|
|
938
942
|
return asked;
|
|
939
943
|
let current = asked;
|
|
@@ -1110,6 +1114,7 @@ var EXIT_OF = {
|
|
|
1110
1114
|
offline: EXIT.unavailable,
|
|
1111
1115
|
busy: EXIT.unavailable,
|
|
1112
1116
|
gone: EXIT.gone,
|
|
1117
|
+
expired: EXIT.gone,
|
|
1113
1118
|
unauthorized: EXIT.unauthorized,
|
|
1114
1119
|
token_expired: EXIT.unauthorized
|
|
1115
1120
|
};
|
|
@@ -3551,6 +3556,113 @@ function sessionContextProblem(v) {
|
|
|
3551
3556
|
return;
|
|
3552
3557
|
}
|
|
3553
3558
|
|
|
3559
|
+
// packages/protocol/src/media.ts
|
|
3560
|
+
var MEDIA_LIMITS = {
|
|
3561
|
+
maxBytes: 8 * 1024 * 1024,
|
|
3562
|
+
maxPixels: 40000000,
|
|
3563
|
+
maxSide: 16384,
|
|
3564
|
+
chunkBytes: 512 * 1024,
|
|
3565
|
+
perRow: 8
|
|
3566
|
+
};
|
|
3567
|
+
var MEDIA_PATH_MAX = 4096;
|
|
3568
|
+
var MEDIA_REF_MAX = 2 + Math.ceil(MEDIA_PATH_MAX * 4 / 3) + 4;
|
|
3569
|
+
var FILE_REF = /^f(0|[1-9]\d{0,2})$/;
|
|
3570
|
+
var TOOL_REF = /^t(0|[1-9]\d{0,3})\.(0|[1-9]\d{0,2})$/;
|
|
3571
|
+
var PATH_REF = /^p:([A-Za-z0-9_-]+)$/;
|
|
3572
|
+
function base64url(bytes) {
|
|
3573
|
+
let binary = "";
|
|
3574
|
+
for (const byte of bytes)
|
|
3575
|
+
binary += String.fromCharCode(byte);
|
|
3576
|
+
return btoa(binary).replace(/\+/g, "-").replace(/\//g, "_").replace(/=+$/, "");
|
|
3577
|
+
}
|
|
3578
|
+
function fromBase64url(text) {
|
|
3579
|
+
if (text.length % 4 === 1)
|
|
3580
|
+
return;
|
|
3581
|
+
try {
|
|
3582
|
+
const binary = atob(text.replace(/-/g, "+").replace(/_/g, "/"));
|
|
3583
|
+
return Uint8Array.from(binary, (c) => c.charCodeAt(0));
|
|
3584
|
+
} catch {
|
|
3585
|
+
return;
|
|
3586
|
+
}
|
|
3587
|
+
}
|
|
3588
|
+
function mediaPathRef(path) {
|
|
3589
|
+
return `p:${base64url(new TextEncoder().encode(path))}`;
|
|
3590
|
+
}
|
|
3591
|
+
function parseMediaRef(ref) {
|
|
3592
|
+
if (typeof ref !== "string" || ref.length > MEDIA_REF_MAX)
|
|
3593
|
+
return;
|
|
3594
|
+
const file = FILE_REF.exec(ref);
|
|
3595
|
+
if (file)
|
|
3596
|
+
return { kind: "file", index: Number(file[1]) };
|
|
3597
|
+
const tool = TOOL_REF.exec(ref);
|
|
3598
|
+
if (tool)
|
|
3599
|
+
return { kind: "tool", part: Number(tool[1]), item: Number(tool[2]) };
|
|
3600
|
+
const path = PATH_REF.exec(ref);
|
|
3601
|
+
if (!path)
|
|
3602
|
+
return;
|
|
3603
|
+
const bytes = fromBase64url(path[1]);
|
|
3604
|
+
if (!bytes || bytes.length === 0 || bytes.length > MEDIA_PATH_MAX)
|
|
3605
|
+
return;
|
|
3606
|
+
let text;
|
|
3607
|
+
try {
|
|
3608
|
+
text = new TextDecoder("utf-8", { fatal: true }).decode(bytes);
|
|
3609
|
+
} catch {
|
|
3610
|
+
return;
|
|
3611
|
+
}
|
|
3612
|
+
if (text.includes("\x00") || mediaPathRef(text) !== ref)
|
|
3613
|
+
return;
|
|
3614
|
+
return { kind: "path", path: text };
|
|
3615
|
+
}
|
|
3616
|
+
var isMediaOffset = (offset) => Number.isInteger(offset) && offset >= 0 && offset <= MEDIA_LIMITS.maxBytes;
|
|
3617
|
+
|
|
3618
|
+
// packages/protocol/src/preview-bundle.ts
|
|
3619
|
+
var PREVIEW_BUNDLE_FEATURE = "previewBundle";
|
|
3620
|
+
var PREVIEW_BUNDLE_LIMITS = {
|
|
3621
|
+
files: 200,
|
|
3622
|
+
fileBytes: 5 * 1024 * 1024,
|
|
3623
|
+
totalBytes: 20 * 1024 * 1024,
|
|
3624
|
+
chunkBytes: 512 * 1024,
|
|
3625
|
+
inlineBytes: 384 * 1024,
|
|
3626
|
+
bundlePathMax: 200,
|
|
3627
|
+
pathMax: 4096,
|
|
3628
|
+
refMax: 300,
|
|
3629
|
+
skipped: 200
|
|
3630
|
+
};
|
|
3631
|
+
var PREVIEW_MEDIA_TYPES = {
|
|
3632
|
+
html: "text/html",
|
|
3633
|
+
htm: "text/html",
|
|
3634
|
+
css: "text/css",
|
|
3635
|
+
js: "text/javascript",
|
|
3636
|
+
mjs: "text/javascript",
|
|
3637
|
+
json: "application/json",
|
|
3638
|
+
txt: "text/plain",
|
|
3639
|
+
csv: "text/csv",
|
|
3640
|
+
md: "text/markdown",
|
|
3641
|
+
pdf: "application/pdf",
|
|
3642
|
+
png: "image/png",
|
|
3643
|
+
jpg: "image/jpeg",
|
|
3644
|
+
jpeg: "image/jpeg",
|
|
3645
|
+
gif: "image/gif",
|
|
3646
|
+
webp: "image/webp",
|
|
3647
|
+
svg: "image/svg+xml"
|
|
3648
|
+
};
|
|
3649
|
+
var MEDIA_TYPES = new Set(Object.values(PREVIEW_MEDIA_TYPES));
|
|
3650
|
+
var HEX64 = /^[0-9a-f]{64}$/;
|
|
3651
|
+
var int2 = (v, min, max) => Number.isSafeInteger(v) && v >= min && v <= max;
|
|
3652
|
+
var isPreviewPath = (v) => typeof v === "string" && v.length > 0 && v.length <= PREVIEW_BUNDLE_LIMITS.pathMax && !/[\u0000\r\n]/.test(v);
|
|
3653
|
+
function isPreviewBundleRequest(v) {
|
|
3654
|
+
if (typeof v.sessionID !== "string" || !v.sessionID)
|
|
3655
|
+
return false;
|
|
3656
|
+
if (typeof v.messageID !== "string" || !v.messageID || v.messageID.length > 300)
|
|
3657
|
+
return false;
|
|
3658
|
+
if (!isPreviewPath(v.path))
|
|
3659
|
+
return false;
|
|
3660
|
+
const chunk = [v.bundle, v.file, v.offset].filter((x) => x !== undefined).length;
|
|
3661
|
+
if (chunk === 0)
|
|
3662
|
+
return true;
|
|
3663
|
+
return chunk === 3 && typeof v.bundle === "string" && HEX64.test(v.bundle) && int2(v.file, 0, PREVIEW_BUNDLE_LIMITS.files - 1) && int2(v.offset, 0, PREVIEW_BUNDLE_LIMITS.fileBytes - 1);
|
|
3664
|
+
}
|
|
3665
|
+
|
|
3554
3666
|
// packages/protocol/src/harness-events.ts
|
|
3555
3667
|
var HARNESS_EVENTS = [
|
|
3556
3668
|
"session.created",
|
|
@@ -3936,6 +4048,60 @@ var ARTIFACT_LIMITS = {
|
|
|
3936
4048
|
aiJobsPerArtifact: 2,
|
|
3937
4049
|
aiInstructionChars: 8000
|
|
3938
4050
|
};
|
|
4051
|
+
// packages/protocol/src/media-allowlist.ts
|
|
4052
|
+
var PUBLIC_SUFFIXES = new Set([
|
|
4053
|
+
...["co", "org", "ac", "gov", "net", "me", "ltd", "plc", "sch", "nhs"].map((s) => `${s}.uk`),
|
|
4054
|
+
...["com", "net", "org", "edu", "gov", "id", "asn"].map((s) => `${s}.au`),
|
|
4055
|
+
...["co", "ne", "or", "ac", "go", "gr", "ed", "ad", "lg"].map((s) => `${s}.jp`),
|
|
4056
|
+
...["co", "org", "net", "ac", "govt", "school", "geek", "gen", "kiwi", "maori"].map((s) => `${s}.nz`),
|
|
4057
|
+
...["com", "net", "org", "gov", "edu"].map((s) => `${s}.br`),
|
|
4058
|
+
...["com", "net", "org", "gov", "edu", "ac"].map((s) => `${s}.cn`),
|
|
4059
|
+
...["com", "net", "org", "gob", "edu"].map((s) => `${s}.mx`),
|
|
4060
|
+
...["co", "net", "org", "firm", "gen", "ind", "ac", "edu", "gov", "res"].map((s) => `${s}.in`),
|
|
4061
|
+
...["co", "org", "net", "ac", "gov", "web"].map((s) => `${s}.za`),
|
|
4062
|
+
...["com", "net", "org", "gov", "edu"].map((s) => `${s}.tr`),
|
|
4063
|
+
...["com", "net", "org", "gov", "edu"].map((s) => `${s}.sg`),
|
|
4064
|
+
...["com", "net", "org", "gov", "edu"].map((s) => `${s}.hk`),
|
|
4065
|
+
...["co", "or", "ne", "go", "ac", "re"].map((s) => `${s}.kr`),
|
|
4066
|
+
...["com", "net", "org", "gov", "edu"].map((s) => `${s}.tw`),
|
|
4067
|
+
...["com", "net", "org", "gov", "edu"].map((s) => `${s}.ar`),
|
|
4068
|
+
...["co", "or", "ac", "go"].map((s) => `${s}.id`),
|
|
4069
|
+
...["co", "or", "ac", "go"].map((s) => `${s}.th`),
|
|
4070
|
+
...["com", "net", "org", "gov", "edu"].map((s) => `${s}.my`),
|
|
4071
|
+
...["com", "net", "org", "gov", "edu"].map((s) => `${s}.ph`),
|
|
4072
|
+
...["com", "net", "org", "gov", "edu"].map((s) => `${s}.pk`),
|
|
4073
|
+
...["com", "net", "org", "gov", "edu"].map((s) => `${s}.ua`),
|
|
4074
|
+
...["com", "net", "org", "gov", "edu"].map((s) => `${s}.pl`),
|
|
4075
|
+
...["co", "or", "ac"].map((s) => `${s}.at`),
|
|
4076
|
+
...["co", "org", "ac"].map((s) => `${s}.il`),
|
|
4077
|
+
"com.es",
|
|
4078
|
+
"org.es",
|
|
4079
|
+
"co.it",
|
|
4080
|
+
"com.ru",
|
|
4081
|
+
"co.ca",
|
|
4082
|
+
"eu.org",
|
|
4083
|
+
"github.io",
|
|
4084
|
+
"githubpreview.dev",
|
|
4085
|
+
"gitlab.io",
|
|
4086
|
+
"pages.dev",
|
|
4087
|
+
"workers.dev",
|
|
4088
|
+
"netlify.app",
|
|
4089
|
+
"vercel.app",
|
|
4090
|
+
"herokuapp.com",
|
|
4091
|
+
"appspot.com",
|
|
4092
|
+
"blogspot.com",
|
|
4093
|
+
"cloudfront.net",
|
|
4094
|
+
"azurewebsites.net",
|
|
4095
|
+
"web.app",
|
|
4096
|
+
"firebaseapp.com",
|
|
4097
|
+
"s3.amazonaws.com",
|
|
4098
|
+
"ngrok.io",
|
|
4099
|
+
"ngrok-free.app",
|
|
4100
|
+
"glitch.me",
|
|
4101
|
+
"repl.co",
|
|
4102
|
+
"fly.dev",
|
|
4103
|
+
"onrender.com"
|
|
4104
|
+
]);
|
|
3939
4105
|
// packages/protocol/src/graph.ts
|
|
3940
4106
|
var GRAPH_LIMITS = {
|
|
3941
4107
|
nodes: 2000,
|
|
@@ -4054,7 +4220,7 @@ var IMPLIED_OPENCODE_FEATURES = [
|
|
|
4054
4220
|
"expose",
|
|
4055
4221
|
"create"
|
|
4056
4222
|
];
|
|
4057
|
-
var OPTIONAL_SPOKE_FEATURES = [...IMPLIED_OPENCODE_FEATURES, "autoName", "sessionTokens", "deliver", "hubPrompt", "permissionMessage", "actTokens", "launch", "fork", "revert", "dismissError"];
|
|
4223
|
+
var OPTIONAL_SPOKE_FEATURES = [...IMPLIED_OPENCODE_FEATURES, "autoName", "sessionTokens", "deliver", "hubPrompt", "permissionMessage", "actTokens", "launch", "fork", "revert", "dismissError", "timelineMedia", PREVIEW_BUNDLE_FEATURE, "voiceFront"];
|
|
4058
4224
|
var CORE_OPS = ["turn", "steer", "interrupt", "stop", "permission", "form"];
|
|
4059
4225
|
var KNOWN_SPOKE_FEATURES = [...CORE_OPS, ...OPTIONAL_SPOKE_FEATURES, "turnEvents", PROFILE_APPLY_FEATURE, SESSION_CONTEXT_FEATURE];
|
|
4060
4226
|
var SPOKE_FEATURES = [...OPTIONAL_SPOKE_FEATURES, PROFILE_APPLY_FEATURE, SESSION_CONTEXT_FEATURE];
|
|
@@ -4072,6 +4238,8 @@ function featureForOp(op) {
|
|
|
4072
4238
|
case "revertRestore":
|
|
4073
4239
|
case "revertCommit":
|
|
4074
4240
|
return "revert";
|
|
4241
|
+
case "removeFront":
|
|
4242
|
+
return "voiceFront";
|
|
4075
4243
|
default:
|
|
4076
4244
|
return op;
|
|
4077
4245
|
}
|
|
@@ -4252,11 +4420,16 @@ function isServerRequest(v) {
|
|
|
4252
4420
|
return nonEmpty(v.sessionID) && promptBody(v);
|
|
4253
4421
|
case "timelineFile":
|
|
4254
4422
|
return nonEmpty(v.sessionID) && nonEmpty(v.messageID) && v.messageID.length <= 300 && Number.isInteger(v.index) && Number(v.index) >= 0 && Number(v.index) < 1000;
|
|
4423
|
+
case "timelineMedia":
|
|
4424
|
+
return nonEmpty(v.sessionID) && nonEmpty(v.messageID) && v.messageID.length <= 300 && str2(v.ref) && parseMediaRef(v.ref) !== undefined && (v.offset === undefined || isMediaOffset(v.offset));
|
|
4425
|
+
case "previewBundle":
|
|
4426
|
+
return isPreviewBundleRequest(v);
|
|
4255
4427
|
case "diff":
|
|
4256
4428
|
return nonEmpty(v.sessionID) && nonEmpty(v.file) && v.file.length <= 4096;
|
|
4257
4429
|
case "rename":
|
|
4258
4430
|
return nonEmpty(v.sessionID) && str2(v.title) && v.title.length <= 1000;
|
|
4259
4431
|
case "conversation":
|
|
4432
|
+
return nonEmpty(v.sessionID) && typeof v.on === "boolean" && (v.frontID === undefined || nonEmpty(v.frontID) && v.frontID.length <= 300);
|
|
4260
4433
|
case "expose":
|
|
4261
4434
|
return nonEmpty(v.sessionID) && typeof v.on === "boolean";
|
|
4262
4435
|
case "create":
|
|
@@ -4279,6 +4452,7 @@ function isServerRequest(v) {
|
|
|
4279
4452
|
case "revertRestore":
|
|
4280
4453
|
case "revertCommit":
|
|
4281
4454
|
case "dismissError":
|
|
4455
|
+
case "removeFront":
|
|
4282
4456
|
return nonEmpty(v.sessionID);
|
|
4283
4457
|
default:
|
|
4284
4458
|
return false;
|
|
@@ -5739,6 +5913,14 @@ function durationArg(value, flag) {
|
|
|
5739
5913
|
throw new UsageError(`${flag} takes seconds or a duration like 30s, 5m, 2h, 1d (got "${value}")`);
|
|
5740
5914
|
return Number(match[1]) * UNIT_S[match[2]];
|
|
5741
5915
|
}
|
|
5916
|
+
var ISO_DATE_TIME = /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}(?::\d{2}(?:\.\d{1,9})?)?(?:Z|[+-]\d{2}:?\d{2})?$/i;
|
|
5917
|
+
function notAfterArg(value, what) {
|
|
5918
|
+
const text = value.trim();
|
|
5919
|
+
const ms = /^\d+$/.test(text) ? Number(text) : ISO_DATE_TIME.test(text) ? Date.parse(text) : Number.NaN;
|
|
5920
|
+
if (!Number.isSafeInteger(ms))
|
|
5921
|
+
throw new UsageError(`${what} takes epoch milliseconds or an ISO 8601 date-time like 2027-01-15T12:00:00Z (got "${value}")`);
|
|
5922
|
+
return ms;
|
|
5923
|
+
}
|
|
5742
5924
|
var iso = (ms) => new Date(ms).toISOString().replace(/\.\d{3}Z$/, "Z");
|
|
5743
5925
|
function askOutcome(asked, waited) {
|
|
5744
5926
|
const { message, answer } = asked;
|
|
@@ -5911,7 +6093,8 @@ var LAUNCH_FLAGS = {
|
|
|
5911
6093
|
prompt: "string",
|
|
5912
6094
|
end: "string",
|
|
5913
6095
|
timeout: "string",
|
|
5914
|
-
cleanup: "string"
|
|
6096
|
+
cleanup: "string",
|
|
6097
|
+
"not-after": "string"
|
|
5915
6098
|
};
|
|
5916
6099
|
var choices = (options) => options.length === 2 ? options.join(" or ") : `${options.slice(0, -1).join(", ")} or ${options.at(-1)}`;
|
|
5917
6100
|
function oneOf3(flags, flag, options) {
|
|
@@ -5970,10 +6153,12 @@ async function launchSpecArg(flags, context) {
|
|
|
5970
6153
|
const runtime = kind === undefined ? undefined : { kind, ...profile !== undefined ? { profile } : {} };
|
|
5971
6154
|
const placement = defined({ labels: nodeLabels, machine, mode: flags.prefer === true ? "prefer" : undefined });
|
|
5972
6155
|
const end = defined({ when, timeout: str(flags, "timeout"), cleanup });
|
|
6156
|
+
const notAfterText = str(flags, "not-after");
|
|
6157
|
+
const notAfter = notAfterText === undefined ? undefined : notAfterArg(notAfterText, "--not-after");
|
|
5973
6158
|
return {
|
|
5974
6159
|
...defined({ key: str(flags, "key"), name, roles, harness: str(flags, "harness"), agent: str(flags, "agent"), model: str(flags, "model") }),
|
|
5975
6160
|
workspace,
|
|
5976
|
-
...defined({ runtime, placement, prompt, labels, end })
|
|
6161
|
+
...defined({ runtime, placement, prompt, labels, end, notAfter })
|
|
5977
6162
|
};
|
|
5978
6163
|
}
|
|
5979
6164
|
var at2 = (name) => `@${name.replace(/^@+/, "")}`;
|
|
@@ -6432,6 +6617,23 @@ function dueOf(args) {
|
|
|
6432
6617
|
throw new ToolArgError(`"due" must be an ISO date/time or epoch milliseconds`);
|
|
6433
6618
|
return ms;
|
|
6434
6619
|
}
|
|
6620
|
+
function notAfterOf(args) {
|
|
6621
|
+
const value = args.notAfter;
|
|
6622
|
+
if (value === undefined || value === null || value === "")
|
|
6623
|
+
return;
|
|
6624
|
+
if (typeof value === "number" && Number.isSafeInteger(value))
|
|
6625
|
+
return value;
|
|
6626
|
+
if (typeof value === "string") {
|
|
6627
|
+
try {
|
|
6628
|
+
return notAfterArg(value, `"notAfter"`);
|
|
6629
|
+
} catch (cause) {
|
|
6630
|
+
if (cause instanceof UsageError)
|
|
6631
|
+
throw new ToolArgError(cause.message);
|
|
6632
|
+
throw cause;
|
|
6633
|
+
}
|
|
6634
|
+
}
|
|
6635
|
+
throw new ToolArgError(`"notAfter" must be epoch milliseconds or an ISO 8601 date-time like 2027-01-15T12:00:00Z`);
|
|
6636
|
+
}
|
|
6435
6637
|
var line4 = (i) => `${i.id} ${i.status}${i.progress ? `/${i.progress}` : ""} ${i.priority} r${i.revision} ${sanitizeText(i.title).replace(/\s+/g, " ")}`;
|
|
6436
6638
|
function intakeText(i) {
|
|
6437
6639
|
const from = i.source.kind === "user" ? "the user" : i.source.kind === "app" ? `app ${i.source.tokenID}` : `session ${i.source.sessionID}`;
|
|
@@ -6441,6 +6643,7 @@ function intakeText(i) {
|
|
|
6441
6643
|
`status: ${i.status}${i.progress ? ` (${i.progress})` : ""} priority: ${i.priority} from: ${from}`,
|
|
6442
6644
|
...i.assignmentID ? [`assignment: ${i.assignmentID} in workspace ${i.workspaceID ?? "?"}${i.sessionID ? `, delivered to ${i.sessionID}` : ""}`] : [],
|
|
6443
6645
|
...i.due !== undefined ? [`due: ${new Date(i.due).toISOString()}`] : [],
|
|
6646
|
+
...i.notAfter !== undefined ? [`not after: ${new Date(i.notAfter).toISOString()}`] : [],
|
|
6444
6647
|
...i.labels?.length ? [`labels: ${i.labels.join(", ")}`] : [],
|
|
6445
6648
|
...i.criteria?.length ? ["done means:", ...i.criteria.map((c) => `- ${sanitizeText(c)}`)] : [],
|
|
6446
6649
|
...i.ref ? [`ref: ${sanitizeText(i.ref)}`] : [],
|
|
@@ -6452,7 +6655,7 @@ function intakeText(i) {
|
|
|
6452
6655
|
var teamIntakeTools = [
|
|
6453
6656
|
{
|
|
6454
6657
|
name: "team_submit",
|
|
6455
|
-
description: "Give work to a team: its entry role (e.g. the project manager) receives the task with the team's context and owns it as an assignment in the team's workspace; while the role is vacant it waits queued. Pass `key` to make retries idempotent. App tokens need scope teams:submit; sessions submit under the team's communication policy.",
|
|
6658
|
+
description: "Give work to a team: its entry role (e.g. the project manager) receives the task with the team's context and owns it as an assignment in the team's workspace; while the role is vacant it waits queued (with `notAfter`, only until then: still queued at that time, it is cancelled with reason not_after instead of delivered late). Pass `key` to make retries idempotent. App tokens need scope teams:submit; sessions submit under the team's communication policy.",
|
|
6456
6659
|
properties: {
|
|
6457
6660
|
team: TEAM,
|
|
6458
6661
|
title: { ...STRING3, description: "One line, at most 120 characters." },
|
|
@@ -6460,6 +6663,10 @@ var teamIntakeTools = [
|
|
|
6460
6663
|
priority: { type: "string", enum: PRIORITIES, description: "Default normal." },
|
|
6461
6664
|
labels: { type: "array", items: STRING3, description: "Slugs (lowercase letters, digits, dashes)." },
|
|
6462
6665
|
due: { ...STRING3, description: "When it is due: an ISO date/time." },
|
|
6666
|
+
notAfter: {
|
|
6667
|
+
type: ["number", "string"],
|
|
6668
|
+
description: "Never deliver after this time: epoch milliseconds or an ISO 8601 date-time (at most 30 days ahead). Already passed: nothing is submitted (expired). Still queued then: cancelled (reason not_after)."
|
|
6669
|
+
},
|
|
6463
6670
|
criteria: { type: "array", items: STRING3, description: "What done means (at most 8 lines)." },
|
|
6464
6671
|
ref: { ...STRING3, description: "An external reference, e.g. a Brain task ID." },
|
|
6465
6672
|
key: { ...STRING3, description: "Idempotency-Key: the same key and body return the original submission." }
|
|
@@ -6472,10 +6679,11 @@ var teamIntakeTools = [
|
|
|
6472
6679
|
const labels = strings2(args, "labels");
|
|
6473
6680
|
const criteria = strings2(args, "criteria");
|
|
6474
6681
|
const due = dueOf(args);
|
|
6682
|
+
const notAfter = notAfterOf(args);
|
|
6475
6683
|
const brief = optional4(args, "brief");
|
|
6476
6684
|
const ref = optional4(args, "ref");
|
|
6477
6685
|
const key = optional4(args, "key");
|
|
6478
|
-
const { intake, created } = await hub.teams.submit(need3(args, "team"), { title: need3(args, "title"), ...brief ? { brief } : {}, ...priority ? { priority } : {}, ...labels ? { labels } : {}, ...due !== undefined ? { due } : {}, ...criteria ? { criteria } : {}, ...ref ? { ref } : {} }, { signal, ...key ? { idempotencyKey: key } : {} });
|
|
6686
|
+
const { intake, created } = await hub.teams.submit(need3(args, "team"), { title: need3(args, "title"), ...brief ? { brief } : {}, ...priority ? { priority } : {}, ...labels ? { labels } : {}, ...due !== undefined ? { due } : {}, ...notAfter !== undefined ? { notAfter } : {}, ...criteria ? { criteria } : {}, ...ref ? { ref } : {} }, { signal, ...key ? { idempotencyKey: key } : {} });
|
|
6479
6687
|
return `${created ? "Submitted" : "Already submitted (same key)"}: ${intake.id} is ${intake.status}${intake.status === "queued" ? " (waiting for the entry role)" : ""}
|
|
6480
6688
|
${intakeText(intake)}`;
|
|
6481
6689
|
}
|
|
@@ -6641,7 +6849,7 @@ var revision = (args) => {
|
|
|
6641
6849
|
throw new ArgError(`"expectedRevision" is required: the team's revision you read (team_show)`);
|
|
6642
6850
|
return value;
|
|
6643
6851
|
};
|
|
6644
|
-
var
|
|
6852
|
+
var int3 = (args, key, min, max) => {
|
|
6645
6853
|
const value = args[key];
|
|
6646
6854
|
if (value === undefined || value === null)
|
|
6647
6855
|
return;
|
|
@@ -6748,7 +6956,7 @@ var teamTools = [
|
|
|
6748
6956
|
const tags = strings3(args, "tags");
|
|
6749
6957
|
const project = optional5(args, "project");
|
|
6750
6958
|
const metadata = record(args, "metadata");
|
|
6751
|
-
const limit =
|
|
6959
|
+
const limit = int3(args, "limit", 1, 200);
|
|
6752
6960
|
const cursor = optional5(args, "cursor");
|
|
6753
6961
|
if (args.paused !== undefined && typeof args.paused !== "boolean")
|
|
6754
6962
|
throw new ArgError(`"paused" must be true or false`);
|
|
@@ -6815,8 +7023,8 @@ var teamTools = [
|
|
|
6815
7023
|
required: ["team"],
|
|
6816
7024
|
readOnly: true,
|
|
6817
7025
|
run: async (hub, args, signal) => {
|
|
6818
|
-
const from =
|
|
6819
|
-
const to = args.to === undefined || args.to === null || args.to === "draft" ? "draft" :
|
|
7026
|
+
const from = int3(args, "from", 1, 1e9);
|
|
7027
|
+
const to = args.to === undefined || args.to === null || args.to === "draft" ? "draft" : int3(args, "to", 1, 1e9);
|
|
6820
7028
|
const { from: a, to: b, diff } = await hub.teams.diff(need4(args, "team"), { signal, ...from !== undefined ? { from } : {}, to });
|
|
6821
7029
|
const part = (label, d) => ["added", "removed", "changed"].flatMap((k) => d[k]?.length ? [`${label} ${k}: ${d[k].join(", ")}`] : []);
|
|
6822
7030
|
const lines = [
|
|
@@ -7387,10 +7595,28 @@ var optionalExpires = (args) => {
|
|
|
7387
7595
|
}
|
|
7388
7596
|
throw new ArgError3(`"expires" must be seconds or a duration like 30s, 5m, 2h, 1d`);
|
|
7389
7597
|
};
|
|
7598
|
+
var optionalNotAfter = (args) => {
|
|
7599
|
+
const value = args.notAfter;
|
|
7600
|
+
if (value === undefined || value === null)
|
|
7601
|
+
return;
|
|
7602
|
+
if (typeof value === "number" && Number.isSafeInteger(value))
|
|
7603
|
+
return value;
|
|
7604
|
+
if (typeof value === "string") {
|
|
7605
|
+
try {
|
|
7606
|
+
return notAfterArg(value, '"notAfter"');
|
|
7607
|
+
} catch (cause) {
|
|
7608
|
+
if (cause instanceof UsageError)
|
|
7609
|
+
throw new ArgError3(cause.message);
|
|
7610
|
+
throw cause;
|
|
7611
|
+
}
|
|
7612
|
+
}
|
|
7613
|
+
throw new ArgError3(`"notAfter" must be epoch milliseconds or an ISO 8601 date-time like 2027-01-15T12:00:00Z`);
|
|
7614
|
+
};
|
|
7390
7615
|
var sendOptions = (args) => {
|
|
7391
7616
|
const wake = optionalBool(args, "wake");
|
|
7392
7617
|
const urgent = optionalBool(args, "urgent");
|
|
7393
|
-
|
|
7618
|
+
const notAfter = optionalNotAfter(args);
|
|
7619
|
+
return { ...wake !== undefined ? { wake } : {}, ...urgent !== undefined ? { urgent } : {}, ...notAfter !== undefined ? { notAfter } : {} };
|
|
7394
7620
|
};
|
|
7395
7621
|
var whyOption = (args) => {
|
|
7396
7622
|
const why = optional7(args, "why");
|
|
@@ -7464,7 +7690,8 @@ function launchSpec(args) {
|
|
|
7464
7690
|
placement: definedFields({ labels: nodeLabels, machine, mode: prefer ? "prefer" : undefined }),
|
|
7465
7691
|
prompt: optional7(args, "prompt"),
|
|
7466
7692
|
labels: optionalLabels(args, "labels"),
|
|
7467
|
-
end: definedFields({ when: optionalEnum(args, "end", LAUNCH_END_WHEN), timeout: optional7(args, "timeout"), cleanup: optionalEnum(args, "cleanup", CLEANUP_POLICIES) })
|
|
7693
|
+
end: definedFields({ when: optionalEnum(args, "end", LAUNCH_END_WHEN), timeout: optional7(args, "timeout"), cleanup: optionalEnum(args, "cleanup", CLEANUP_POLICIES) }),
|
|
7694
|
+
notAfter: optionalNotAfter(args)
|
|
7468
7695
|
})
|
|
7469
7696
|
};
|
|
7470
7697
|
}
|
|
@@ -7514,6 +7741,7 @@ var STRING6 = { type: "string" };
|
|
|
7514
7741
|
var SEND = {
|
|
7515
7742
|
wake: { type: "boolean", description: "false: admit the message without starting a turn." },
|
|
7516
7743
|
urgent: { type: "boolean", description: "Steer into the recipient's running turn." },
|
|
7744
|
+
notAfter: { type: ["number", "string"], description: "Never deliver after this time: epoch milliseconds or an ISO 8601 date-time (at most 30 days ahead). Already passed: nothing is sent (expired)." },
|
|
7517
7745
|
all: { type: "boolean", description: "Send to every session the address names (each holder of a role)." }
|
|
7518
7746
|
};
|
|
7519
7747
|
var TO = { type: "string", description: "The recipient: @name, @@role, @@role#team (a role of one of your teams), @name.project, ses_…, or @me (the user)." };
|
|
@@ -7671,7 +7899,7 @@ var webhookText = (w) => `${w.id}${w.label ? ` ${w.label}` : ""} ${w.url} ${w
|
|
|
7671
7899
|
var webhookTools = [
|
|
7672
7900
|
{
|
|
7673
7901
|
name: "webhook_create",
|
|
7674
|
-
description:
|
|
7902
|
+
description: `Create a durable signed webhook for canonical compact events (e.g. launch.*, session.*, message.changed, team.intake). The signing secret is returned only here. Needs events:subscribe plus every selected family's scope; events ["team.intake"] alone needs only teams:submit (an app gets only its own submissions).`,
|
|
7675
7903
|
properties: { url: STRING6, events: { type: "array", items: STRING6 }, label: STRING6 },
|
|
7676
7904
|
required: ["url"],
|
|
7677
7905
|
readOnly: false,
|
|
@@ -8188,13 +8416,13 @@ var TOOLS = [
|
|
|
8188
8416
|
{
|
|
8189
8417
|
name: "msg",
|
|
8190
8418
|
description: "Tell a session something (fire and forget). Sent as this server's credential, not as an OpenCode session.",
|
|
8191
|
-
properties: { to: TO, text: { ...STRING6, description: "The message." }, ...SEND },
|
|
8419
|
+
properties: { to: TO, text: { ...STRING6, description: "The message." }, ...SEND, idempotencyKey: IDEMPOTENCY3 },
|
|
8192
8420
|
required: ["to", "text"],
|
|
8193
8421
|
readOnly: false,
|
|
8194
8422
|
run: async (hub, args, signal) => {
|
|
8195
8423
|
const to = need7(args, "to");
|
|
8196
8424
|
const text = need7(args, "text");
|
|
8197
|
-
const options = { ...sendOptions(args), signal };
|
|
8425
|
+
const options = { ...sendOptions(args), ...idemOption(args), signal };
|
|
8198
8426
|
if (optionalBool(args, "all"))
|
|
8199
8427
|
return sentAllText(await hub.msg(to, text, { ...options, all: true }));
|
|
8200
8428
|
return sentText(await hub.msg(to, text, options));
|
|
@@ -8208,7 +8436,8 @@ var TOOLS = [
|
|
|
8208
8436
|
text: { ...STRING6, description: "The question." },
|
|
8209
8437
|
wait: { type: "number", minimum: 0, maximum: WAIT_POLL_MAX_S, description: `Seconds to wait for the answer (0–${WAIT_POLL_MAX_S}).` },
|
|
8210
8438
|
expires: { type: ["number", "string"], description: "When the ask expires: seconds, or 30s, 5m, 2h, 1d (1 minute to 7 days; default 24 h)." },
|
|
8211
|
-
...SEND
|
|
8439
|
+
...SEND,
|
|
8440
|
+
idempotencyKey: IDEMPOTENCY3
|
|
8212
8441
|
},
|
|
8213
8442
|
required: ["to", "text"],
|
|
8214
8443
|
readOnly: false,
|
|
@@ -8217,7 +8446,7 @@ var TOOLS = [
|
|
|
8217
8446
|
const text = need7(args, "text");
|
|
8218
8447
|
const wait = optionalWait(args);
|
|
8219
8448
|
const expires = optionalExpires(args);
|
|
8220
|
-
const options = { ...sendOptions(args), ...expires !== undefined ? { expires } : {}, signal };
|
|
8449
|
+
const options = { ...sendOptions(args), ...expires !== undefined ? { expires } : {}, ...idemOption(args), signal };
|
|
8221
8450
|
if (optionalBool(args, "all")) {
|
|
8222
8451
|
if (wait !== undefined)
|
|
8223
8452
|
throw new ArgError3(`"wait" cannot be combined with "all"`);
|
|
@@ -8381,7 +8610,7 @@ ${decisionText((await hub.decision(need7(args, "id"), { signal })).decision)}`
|
|
|
8381
8610
|
},
|
|
8382
8611
|
{
|
|
8383
8612
|
name: "launch",
|
|
8384
|
-
description: "Start a new session on a node (a hub node with the repo under its workspace roots). The same key again answers the same launch. Needs an app token with scope sessions:launch and a grant with verb launch covering the repo.",
|
|
8613
|
+
description: "Start a new session on a node (a hub node with the repo under its workspace roots). The same key again answers the same launch. With notAfter, a launch still waiting for a machine at that time is never started (it ends expired). Needs an app token with scope sessions:launch and a grant with verb launch covering the repo.",
|
|
8385
8614
|
properties: {
|
|
8386
8615
|
repo: { ...STRING6, description: "Absolute path of the repository on the node (or where a clone goes)." },
|
|
8387
8616
|
mode: { type: "string", enum: [...WORKSPACE_MODES], description: "worktree (default: <repo>/.worktrees/<branch>, needs branch), checkout, or clone (needs remote)." },
|
|
@@ -8403,7 +8632,8 @@ ${decisionText((await hub.decision(need7(args, "id"), { signal })).decision)}`
|
|
|
8403
8632
|
prompt: { ...STRING6, description: "The session's first prompt." },
|
|
8404
8633
|
end: { type: "string", enum: [...LAUNCH_END_WHEN], description: "When it ends: idle (default; idle with nothing open for 30 s), asked (with a question open: needs_user), never." },
|
|
8405
8634
|
timeout: { ...STRING6, description: "Longest run, e.g. 4h or 90m." },
|
|
8406
|
-
cleanup: { type: "string", enum: [...CLEANUP_POLICIES], description: "keep (default) or remove the workspace when it ends." }
|
|
8635
|
+
cleanup: { type: "string", enum: [...CLEANUP_POLICIES], description: "keep (default) or remove the workspace when it ends." },
|
|
8636
|
+
notAfter: { type: ["number", "string"], description: "Do not start after this time: epoch milliseconds or an ISO 8601 date-time (at most 30 days ahead). Still waiting for a machine then, the launch ends expired; once placed it runs (timeout bounds it). Already passed: nothing is launched (expired)." }
|
|
8407
8637
|
},
|
|
8408
8638
|
required: ["repo"],
|
|
8409
8639
|
readOnly: false,
|
|
@@ -8945,7 +9175,7 @@ import { arch as osArch, platform as osPlatform } from "node:os";
|
|
|
8945
9175
|
// packages/node/package.json
|
|
8946
9176
|
var package_default2 = {
|
|
8947
9177
|
name: "@huynle/hub-node",
|
|
8948
|
-
version: "0.
|
|
9178
|
+
version: "0.9.0",
|
|
8949
9179
|
private: true,
|
|
8950
9180
|
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).",
|
|
8951
9181
|
license: "MIT",
|
|
@@ -10037,7 +10267,7 @@ import path14 from "node:path";
|
|
|
10037
10267
|
// packages/runtime-openshell/package.json
|
|
10038
10268
|
var package_default3 = {
|
|
10039
10269
|
name: "@huynle/hub-runtime-openshell",
|
|
10040
|
-
version: "0.
|
|
10270
|
+
version: "0.9.0",
|
|
10041
10271
|
private: true,
|
|
10042
10272
|
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).",
|
|
10043
10273
|
license: "MIT",
|
|
@@ -13721,7 +13951,7 @@ import path23 from "node:path";
|
|
|
13721
13951
|
// packages/claude-code/package.json
|
|
13722
13952
|
var package_default4 = {
|
|
13723
13953
|
name: "@huynle/hub-claude-code",
|
|
13724
|
-
version: "0.
|
|
13954
|
+
version: "0.9.0",
|
|
13725
13955
|
private: true,
|
|
13726
13956
|
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).",
|
|
13727
13957
|
license: "MIT",
|
|
@@ -14010,7 +14240,7 @@ import path26 from "node:path";
|
|
|
14010
14240
|
// packages/preset/package.json
|
|
14011
14241
|
var package_default5 = {
|
|
14012
14242
|
name: "@huynle/hub-preset",
|
|
14013
|
-
version: "0.
|
|
14243
|
+
version: "0.9.0",
|
|
14014
14244
|
private: true,
|
|
14015
14245
|
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).",
|
|
14016
14246
|
license: "MIT",
|
|
@@ -14535,7 +14765,7 @@ import { openSync as openSync6, closeSync as closeSync6, readFileSync as readFil
|
|
|
14535
14765
|
// packages/codex/package.json
|
|
14536
14766
|
var package_default6 = {
|
|
14537
14767
|
name: "@huynle/hub-codex",
|
|
14538
|
-
version: "0.
|
|
14768
|
+
version: "0.9.0",
|
|
14539
14769
|
private: true,
|
|
14540
14770
|
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).",
|
|
14541
14771
|
license: "MIT",
|
|
@@ -25130,10 +25360,13 @@ Identity
|
|
|
25130
25360
|
hub role release <role[.project]> [--session <addr>]
|
|
25131
25361
|
|
|
25132
25362
|
Messaging (text "-" reads it from stdin)
|
|
25133
|
-
hub msg <addr> "text" [--all] [--no-wake] [--urgent]
|
|
25134
|
-
|
|
25363
|
+
hub msg <addr> "text" [--all] [--no-wake] [--urgent] [--not-after <ms|ISO time>] [--key K]
|
|
25364
|
+
tell: fire and forget; --not-after: never delivered after that time
|
|
25365
|
+
hub ask <addr> "text" [--wait [secs]] [--expires 2h] [--not-after <ms|ISO time>] [--all] [--no-wake] [--urgent] [--key K]
|
|
25135
25366
|
tracked until answered, declined or expired; --wait alone waits until
|
|
25136
|
-
it expires; exit 0 answered, 1 declined or no answer yet, 8 expired
|
|
25367
|
+
it expires; exit 0 answered, 1 declined or no answer yet, 8 expired;
|
|
25368
|
+
--key (Idempotency-Key): a retry with the same key and text answers
|
|
25369
|
+
the first send again and sends nothing (24 h, per credential)
|
|
25137
25370
|
hub reply <msgID> "text" [--no-wake] goes to the real sender
|
|
25138
25371
|
hub decline <msgID> --why "reason"
|
|
25139
25372
|
hub ask @me "question" [--option id=label[:safe]]... [--recommend id [--why "…"]] [--urgency low|normal|high]
|
|
@@ -25168,9 +25401,10 @@ Launching (users; agents and app tokens with sessions:launch under a grant with
|
|
|
25168
25401
|
[--name <@name>] [--role R]... [--harness H] [--agent A] [--model provider/model]
|
|
25169
25402
|
[--runtime host|openshell [--profile P]] [--machine M] [--node-label k=v]... [--prefer]
|
|
25170
25403
|
[--label k=v]... [--prompt "text" | --prompt -] [--end idle|asked|never] [--timeout 4h]
|
|
25171
|
-
[--cleanup keep|remove] [--key K]
|
|
25404
|
+
[--cleanup keep|remove] [--key K] [--not-after <ms|ISO time>]
|
|
25172
25405
|
start a session; the same --key again answers the same launch;
|
|
25173
|
-
--label tags it for apps, --node-label picks nodes (--prefer: not required)
|
|
25406
|
+
--label tags it for apps, --node-label picks nodes (--prefer: not required);
|
|
25407
|
+
--not-after: still waiting for a machine then, it never starts (expired)
|
|
25174
25408
|
hub launches list [--state S[,S]] [--label k=v]... your launches (agents: the ones they started)
|
|
25175
25409
|
hub launches show <launchID> · hub launches stop <launchID> (stop: exit 8 when it already ended)
|
|
25176
25410
|
|
|
@@ -25299,7 +25533,16 @@ var whyOf = (flags) => {
|
|
|
25299
25533
|
const why = str(flags, "why");
|
|
25300
25534
|
return why !== undefined ? { why } : {};
|
|
25301
25535
|
};
|
|
25302
|
-
var sendFlags = (flags) =>
|
|
25536
|
+
var sendFlags = (flags) => {
|
|
25537
|
+
const notAfter = str(flags, "not-after");
|
|
25538
|
+
const key = str(flags, "key");
|
|
25539
|
+
return {
|
|
25540
|
+
...flags["no-wake"] === true ? { wake: false } : {},
|
|
25541
|
+
...flags.urgent === true ? { urgent: true } : {},
|
|
25542
|
+
...notAfter === undefined ? {} : { notAfter: notAfterArg(notAfter, "--not-after") },
|
|
25543
|
+
...key !== undefined ? { idempotencyKey: key } : {}
|
|
25544
|
+
};
|
|
25545
|
+
};
|
|
25303
25546
|
var nodeIo = (io) => ({
|
|
25304
25547
|
env: io.env,
|
|
25305
25548
|
home: io.home,
|
|
@@ -25421,7 +25664,7 @@ var COMMANDS = {
|
|
|
25421
25664
|
},
|
|
25422
25665
|
msg: {
|
|
25423
25666
|
args: ["<addr>", "<text>"],
|
|
25424
|
-
flags: { all: "bool", "no-wake": "bool", urgent: "bool" },
|
|
25667
|
+
flags: { all: "bool", "no-wake": "bool", urgent: "bool", "not-after": "string", key: "string" },
|
|
25425
25668
|
async handle(context) {
|
|
25426
25669
|
const { flags, args } = context.parsed;
|
|
25427
25670
|
const text = await textArg(args[1], context.io.stdin);
|
|
@@ -25433,7 +25676,7 @@ var COMMANDS = {
|
|
|
25433
25676
|
},
|
|
25434
25677
|
ask: {
|
|
25435
25678
|
args: ["<addr>", "<text>"],
|
|
25436
|
-
flags: { all: "bool", "no-wake": "bool", urgent: "bool", expires: "string", wait: "optional", ...DECISION_FLAGS },
|
|
25679
|
+
flags: { all: "bool", "no-wake": "bool", urgent: "bool", "not-after": "string", key: "string", expires: "string", wait: "optional", ...DECISION_FLAGS },
|
|
25437
25680
|
async handle(context) {
|
|
25438
25681
|
const { flags, args } = context.parsed;
|
|
25439
25682
|
const decision = decisionOptions(flags, args[0]);
|