@lesscap/baton-cli 0.2.13 → 0.3.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/LICENSE +21 -0
- package/dist/baton.mjs +1548 -1004
- package/package.json +10 -11
package/dist/baton.mjs
CHANGED
|
@@ -467,235 +467,609 @@ function _getBuiltinFlags(long, short, userNames, userAliases) {
|
|
|
467
467
|
return [`--${long}`, `-${short}`];
|
|
468
468
|
}
|
|
469
469
|
|
|
470
|
-
//
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
var authHeaders = {};
|
|
476
|
-
var loginGate = null;
|
|
477
|
-
var setAuthHeaders = (h) => {
|
|
478
|
-
authHeaders = h;
|
|
470
|
+
// ../../node_modules/.pnpm/eventsource-parser@3.1.0/node_modules/eventsource-parser/dist/index.js
|
|
471
|
+
var ParseError = class extends Error {
|
|
472
|
+
constructor(message, options) {
|
|
473
|
+
super(message), this.name = "ParseError", this.type = options.type, this.field = options.field, this.value = options.value, this.line = options.line;
|
|
474
|
+
}
|
|
479
475
|
};
|
|
480
|
-
var
|
|
481
|
-
|
|
476
|
+
var LF = 10;
|
|
477
|
+
var CR = 13;
|
|
478
|
+
var SPACE = 32;
|
|
479
|
+
function noop(_arg) {
|
|
480
|
+
}
|
|
481
|
+
function createParser(config) {
|
|
482
|
+
if (typeof config == "function")
|
|
483
|
+
throw new TypeError(
|
|
484
|
+
"`config` must be an object, got a function instead. Did you mean `createParser({onEvent: fn})`?"
|
|
485
|
+
);
|
|
486
|
+
const { onEvent = noop, onError = noop, onRetry = noop, onComment, maxBufferSize } = config, pendingFragments = [];
|
|
487
|
+
let pendingFragmentsLength = 0, isFirstChunk = true, id, data = "", dataLines = 0, eventType, terminated = false;
|
|
488
|
+
function feed(chunk) {
|
|
489
|
+
if (terminated)
|
|
490
|
+
throw new Error(
|
|
491
|
+
"Cannot feed parser: it was terminated after exceeding the configured max buffer size. Call `reset()` to resume parsing."
|
|
492
|
+
);
|
|
493
|
+
if (isFirstChunk && (isFirstChunk = false, chunk.charCodeAt(0) === 239 && chunk.charCodeAt(1) === 187 && chunk.charCodeAt(2) === 191 && (chunk = chunk.slice(3))), pendingFragments.length === 0) {
|
|
494
|
+
const trailing2 = processLines(chunk);
|
|
495
|
+
trailing2 !== "" && (pendingFragments.push(trailing2), pendingFragmentsLength = trailing2.length), checkBufferSize();
|
|
496
|
+
return;
|
|
497
|
+
}
|
|
498
|
+
if (chunk.indexOf(`
|
|
499
|
+
`) === -1 && chunk.indexOf("\r") === -1) {
|
|
500
|
+
pendingFragments.push(chunk), pendingFragmentsLength += chunk.length, checkBufferSize();
|
|
501
|
+
return;
|
|
502
|
+
}
|
|
503
|
+
pendingFragments.push(chunk);
|
|
504
|
+
const input = pendingFragments.join("");
|
|
505
|
+
pendingFragments.length = 0, pendingFragmentsLength = 0;
|
|
506
|
+
const trailing = processLines(input);
|
|
507
|
+
trailing !== "" && (pendingFragments.push(trailing), pendingFragmentsLength = trailing.length), checkBufferSize();
|
|
508
|
+
}
|
|
509
|
+
function checkBufferSize() {
|
|
510
|
+
maxBufferSize !== void 0 && (pendingFragmentsLength + data.length <= maxBufferSize || (terminated = true, pendingFragments.length = 0, pendingFragmentsLength = 0, id = void 0, data = "", dataLines = 0, eventType = void 0, onError(
|
|
511
|
+
new ParseError(`Buffered data exceeded max buffer size of ${maxBufferSize} characters`, {
|
|
512
|
+
type: "max-buffer-size-exceeded"
|
|
513
|
+
})
|
|
514
|
+
)));
|
|
515
|
+
}
|
|
516
|
+
function processLines(chunk) {
|
|
517
|
+
let searchIndex = 0;
|
|
518
|
+
if (chunk.indexOf("\r") === -1) {
|
|
519
|
+
let lfIndex = chunk.indexOf(`
|
|
520
|
+
`, searchIndex);
|
|
521
|
+
for (; lfIndex !== -1; ) {
|
|
522
|
+
if (searchIndex === lfIndex) {
|
|
523
|
+
dataLines > 0 && onEvent({ id, event: eventType, data }), id = void 0, data = "", dataLines = 0, eventType = void 0, searchIndex = lfIndex + 1, lfIndex = chunk.indexOf(`
|
|
524
|
+
`, searchIndex);
|
|
525
|
+
continue;
|
|
526
|
+
}
|
|
527
|
+
const firstCharCode = chunk.charCodeAt(searchIndex);
|
|
528
|
+
if (isDataPrefix(chunk, searchIndex, firstCharCode)) {
|
|
529
|
+
const valueStart = chunk.charCodeAt(searchIndex + 5) === SPACE ? searchIndex + 6 : searchIndex + 5, value = chunk.slice(valueStart, lfIndex);
|
|
530
|
+
if (dataLines === 0 && chunk.charCodeAt(lfIndex + 1) === LF) {
|
|
531
|
+
onEvent({ id, event: eventType, data: value }), id = void 0, data = "", eventType = void 0, searchIndex = lfIndex + 2, lfIndex = chunk.indexOf(`
|
|
532
|
+
`, searchIndex);
|
|
533
|
+
continue;
|
|
534
|
+
}
|
|
535
|
+
data = dataLines === 0 ? value : `${data}
|
|
536
|
+
${value}`, dataLines++;
|
|
537
|
+
} else isEventPrefix(chunk, searchIndex, firstCharCode) ? eventType = chunk.slice(
|
|
538
|
+
chunk.charCodeAt(searchIndex + 6) === SPACE ? searchIndex + 7 : searchIndex + 6,
|
|
539
|
+
lfIndex
|
|
540
|
+
) || void 0 : parseLine(chunk, searchIndex, lfIndex);
|
|
541
|
+
searchIndex = lfIndex + 1, lfIndex = chunk.indexOf(`
|
|
542
|
+
`, searchIndex);
|
|
543
|
+
}
|
|
544
|
+
return chunk.slice(searchIndex);
|
|
545
|
+
}
|
|
546
|
+
for (; searchIndex < chunk.length; ) {
|
|
547
|
+
const crIndex = chunk.indexOf("\r", searchIndex), lfIndex = chunk.indexOf(`
|
|
548
|
+
`, searchIndex);
|
|
549
|
+
let lineEnd = -1;
|
|
550
|
+
if (crIndex !== -1 && lfIndex !== -1 ? lineEnd = crIndex < lfIndex ? crIndex : lfIndex : crIndex !== -1 ? crIndex === chunk.length - 1 ? lineEnd = -1 : lineEnd = crIndex : lfIndex !== -1 && (lineEnd = lfIndex), lineEnd === -1)
|
|
551
|
+
break;
|
|
552
|
+
parseLine(chunk, searchIndex, lineEnd), searchIndex = lineEnd + 1, chunk.charCodeAt(searchIndex - 1) === CR && chunk.charCodeAt(searchIndex) === LF && searchIndex++;
|
|
553
|
+
}
|
|
554
|
+
return chunk.slice(searchIndex);
|
|
555
|
+
}
|
|
556
|
+
function parseLine(chunk, start, end) {
|
|
557
|
+
if (start === end) {
|
|
558
|
+
dispatchEvent();
|
|
559
|
+
return;
|
|
560
|
+
}
|
|
561
|
+
const firstCharCode = chunk.charCodeAt(start);
|
|
562
|
+
if (isDataPrefix(chunk, start, firstCharCode)) {
|
|
563
|
+
const valueStart = chunk.charCodeAt(start + 5) === SPACE ? start + 6 : start + 5, value2 = chunk.slice(valueStart, end);
|
|
564
|
+
data = dataLines === 0 ? value2 : `${data}
|
|
565
|
+
${value2}`, dataLines++;
|
|
566
|
+
return;
|
|
567
|
+
}
|
|
568
|
+
if (isEventPrefix(chunk, start, firstCharCode)) {
|
|
569
|
+
eventType = chunk.slice(chunk.charCodeAt(start + 6) === SPACE ? start + 7 : start + 6, end) || void 0;
|
|
570
|
+
return;
|
|
571
|
+
}
|
|
572
|
+
if (firstCharCode === 105 && chunk.charCodeAt(start + 1) === 100 && chunk.charCodeAt(start + 2) === 58) {
|
|
573
|
+
const value2 = chunk.slice(chunk.charCodeAt(start + 3) === SPACE ? start + 4 : start + 3, end);
|
|
574
|
+
id = value2.includes("\0") ? void 0 : value2;
|
|
575
|
+
return;
|
|
576
|
+
}
|
|
577
|
+
if (firstCharCode === 58) {
|
|
578
|
+
if (onComment) {
|
|
579
|
+
const line2 = chunk.slice(start, end);
|
|
580
|
+
onComment(line2.slice(chunk.charCodeAt(start + 1) === SPACE ? 2 : 1));
|
|
581
|
+
}
|
|
582
|
+
return;
|
|
583
|
+
}
|
|
584
|
+
const line = chunk.slice(start, end), fieldSeparatorIndex = line.indexOf(":");
|
|
585
|
+
if (fieldSeparatorIndex === -1) {
|
|
586
|
+
processField(line, "", line);
|
|
587
|
+
return;
|
|
588
|
+
}
|
|
589
|
+
const field = line.slice(0, fieldSeparatorIndex), offset = line.charCodeAt(fieldSeparatorIndex + 1) === SPACE ? 2 : 1, value = line.slice(fieldSeparatorIndex + offset);
|
|
590
|
+
processField(field, value, line);
|
|
591
|
+
}
|
|
592
|
+
function processField(field, value, line) {
|
|
593
|
+
switch (field) {
|
|
594
|
+
case "event":
|
|
595
|
+
eventType = value || void 0;
|
|
596
|
+
break;
|
|
597
|
+
case "data":
|
|
598
|
+
data = dataLines === 0 ? value : `${data}
|
|
599
|
+
${value}`, dataLines++;
|
|
600
|
+
break;
|
|
601
|
+
case "id":
|
|
602
|
+
id = value.includes("\0") ? void 0 : value;
|
|
603
|
+
break;
|
|
604
|
+
case "retry":
|
|
605
|
+
/^\d+$/.test(value) ? onRetry(parseInt(value, 10)) : onError(
|
|
606
|
+
new ParseError(`Invalid \`retry\` value: "${value}"`, {
|
|
607
|
+
type: "invalid-retry",
|
|
608
|
+
value,
|
|
609
|
+
line
|
|
610
|
+
})
|
|
611
|
+
);
|
|
612
|
+
break;
|
|
613
|
+
default:
|
|
614
|
+
onError(
|
|
615
|
+
new ParseError(
|
|
616
|
+
`Unknown field "${field.length > 20 ? `${field.slice(0, 20)}\u2026` : field}"`,
|
|
617
|
+
{ type: "unknown-field", field, value, line }
|
|
618
|
+
)
|
|
619
|
+
);
|
|
620
|
+
break;
|
|
621
|
+
}
|
|
622
|
+
}
|
|
623
|
+
function dispatchEvent() {
|
|
624
|
+
dataLines > 0 && onEvent({
|
|
625
|
+
id,
|
|
626
|
+
event: eventType,
|
|
627
|
+
data
|
|
628
|
+
}), id = void 0, data = "", dataLines = 0, eventType = void 0;
|
|
629
|
+
}
|
|
630
|
+
function reset(options = {}) {
|
|
631
|
+
if (options.consume && pendingFragments.length > 0) {
|
|
632
|
+
const incompleteLine = pendingFragments.join("");
|
|
633
|
+
parseLine(incompleteLine, 0, incompleteLine.length);
|
|
634
|
+
}
|
|
635
|
+
isFirstChunk = true, id = void 0, data = "", dataLines = 0, eventType = void 0, pendingFragments.length = 0, pendingFragmentsLength = 0, terminated = false;
|
|
636
|
+
}
|
|
637
|
+
return { feed, reset };
|
|
638
|
+
}
|
|
639
|
+
function isDataPrefix(chunk, i, firstCharCode) {
|
|
640
|
+
return firstCharCode === 100 && chunk.charCodeAt(i + 1) === 97 && chunk.charCodeAt(i + 2) === 116 && chunk.charCodeAt(i + 3) === 97 && chunk.charCodeAt(i + 4) === 58;
|
|
641
|
+
}
|
|
642
|
+
function isEventPrefix(chunk, i, firstCharCode) {
|
|
643
|
+
return firstCharCode === 101 && chunk.charCodeAt(i + 1) === 118 && chunk.charCodeAt(i + 2) === 101 && chunk.charCodeAt(i + 3) === 110 && chunk.charCodeAt(i + 4) === 116 && chunk.charCodeAt(i + 5) === 58;
|
|
644
|
+
}
|
|
645
|
+
|
|
646
|
+
// ../../node_modules/.pnpm/eventsource@4.1.0/node_modules/eventsource/dist/index.js
|
|
647
|
+
var ErrorEvent = class extends Event {
|
|
648
|
+
/**
|
|
649
|
+
* Constructs a new `ErrorEvent` instance. This is typically not called directly,
|
|
650
|
+
* but rather emitted by the `EventSource` object when an error occurs.
|
|
651
|
+
*
|
|
652
|
+
* @param type - The type of the event (should be "error")
|
|
653
|
+
* @param errorEventInitDict - Optional properties to include in the error event
|
|
654
|
+
*/
|
|
655
|
+
constructor(type, errorEventInitDict) {
|
|
656
|
+
var _a, _b;
|
|
657
|
+
super(type), this.code = (_a = errorEventInitDict == null ? void 0 : errorEventInitDict.code) != null ? _a : void 0, this.message = (_b = errorEventInitDict == null ? void 0 : errorEventInitDict.message) != null ? _b : void 0;
|
|
658
|
+
}
|
|
659
|
+
/**
|
|
660
|
+
* Node.js "hides" the `message` and `code` properties of the `ErrorEvent` instance,
|
|
661
|
+
* when it is `console.log`'ed. This makes it harder to debug errors. To ease debugging,
|
|
662
|
+
* we explicitly include the properties in the `inspect` method.
|
|
663
|
+
*
|
|
664
|
+
* This is automatically called by Node.js when you `console.log` an instance of this class.
|
|
665
|
+
*
|
|
666
|
+
* @param _depth - The current depth
|
|
667
|
+
* @param options - The options passed to `util.inspect`
|
|
668
|
+
* @param inspect - The inspect function to use (prevents having to import it from `util`)
|
|
669
|
+
* @returns A string representation of the error
|
|
670
|
+
*/
|
|
671
|
+
[/* @__PURE__ */ Symbol.for("nodejs.util.inspect.custom")](_depth, options, inspect) {
|
|
672
|
+
return inspect(inspectableError(this), options);
|
|
673
|
+
}
|
|
674
|
+
/**
|
|
675
|
+
* Deno "hides" the `message` and `code` properties of the `ErrorEvent` instance,
|
|
676
|
+
* when it is `console.log`'ed. This makes it harder to debug errors. To ease debugging,
|
|
677
|
+
* we explicitly include the properties in the `inspect` method.
|
|
678
|
+
*
|
|
679
|
+
* This is automatically called by Deno when you `console.log` an instance of this class.
|
|
680
|
+
*
|
|
681
|
+
* @param inspect - The inspect function to use (prevents having to import it from `util`)
|
|
682
|
+
* @param options - The options passed to `Deno.inspect`
|
|
683
|
+
* @returns A string representation of the error
|
|
684
|
+
*/
|
|
685
|
+
[/* @__PURE__ */ Symbol.for("Deno.customInspect")](inspect, options) {
|
|
686
|
+
return inspect(inspectableError(this), options);
|
|
687
|
+
}
|
|
482
688
|
};
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
689
|
+
function syntaxError(message) {
|
|
690
|
+
const DomException = globalThis.DOMException;
|
|
691
|
+
return typeof DomException == "function" ? new DomException(message, "SyntaxError") : new SyntaxError(message);
|
|
692
|
+
}
|
|
693
|
+
function flattenError(err) {
|
|
694
|
+
return err instanceof Error ? "errors" in err && Array.isArray(err.errors) ? err.errors.map(flattenError).join(", ") : "cause" in err && err.cause instanceof Error ? `${err}: ${flattenError(err.cause)}` : err.message : `${err}`;
|
|
695
|
+
}
|
|
696
|
+
function inspectableError(err) {
|
|
697
|
+
return {
|
|
698
|
+
type: err.type,
|
|
699
|
+
message: err.message,
|
|
700
|
+
code: err.code,
|
|
701
|
+
defaultPrevented: err.defaultPrevented,
|
|
702
|
+
cancelable: err.cancelable,
|
|
703
|
+
timeStamp: err.timeStamp
|
|
704
|
+
};
|
|
705
|
+
}
|
|
706
|
+
var __typeError = (msg) => {
|
|
707
|
+
throw TypeError(msg);
|
|
494
708
|
};
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
var
|
|
498
|
-
var
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
709
|
+
var __accessCheck = (obj, member, msg) => member.has(obj) || __typeError("Cannot " + msg);
|
|
710
|
+
var __privateGet = (obj, member, getter) => (__accessCheck(obj, member, "read from private field"), getter ? getter.call(obj) : member.get(obj));
|
|
711
|
+
var __privateAdd = (obj, member, value) => member.has(obj) ? __typeError("Cannot add the same private member more than once") : member instanceof WeakSet ? member.add(obj) : member.set(obj, value);
|
|
712
|
+
var __privateSet = (obj, member, value, setter) => (__accessCheck(obj, member, "write to private field"), member.set(obj, value), value);
|
|
713
|
+
var __privateMethod = (obj, member, method) => (__accessCheck(obj, member, "access private method"), method);
|
|
714
|
+
var _readyState;
|
|
715
|
+
var _url;
|
|
716
|
+
var _redirectUrl;
|
|
717
|
+
var _withCredentials;
|
|
718
|
+
var _fetch;
|
|
719
|
+
var _reconnectInterval;
|
|
720
|
+
var _reconnectTimer;
|
|
721
|
+
var _lastEventId;
|
|
722
|
+
var _controller;
|
|
723
|
+
var _parser;
|
|
724
|
+
var _onError;
|
|
725
|
+
var _onMessage;
|
|
726
|
+
var _onOpen;
|
|
727
|
+
var _EventSource_instances;
|
|
728
|
+
var connect_fn;
|
|
729
|
+
var _onFetchResponse;
|
|
730
|
+
var _onFetchError;
|
|
731
|
+
var getRequestOptions_fn;
|
|
732
|
+
var _onEvent;
|
|
733
|
+
var _onRetryChange;
|
|
734
|
+
var failConnection_fn;
|
|
735
|
+
var scheduleReconnect_fn;
|
|
736
|
+
var _reconnect;
|
|
737
|
+
var EventSource = class extends EventTarget {
|
|
738
|
+
constructor(url, eventSourceInitDict) {
|
|
739
|
+
var _a, _b;
|
|
740
|
+
super(), __privateAdd(this, _EventSource_instances), this.CONNECTING = 0, this.OPEN = 1, this.CLOSED = 2, __privateAdd(this, _readyState), __privateAdd(this, _url), __privateAdd(this, _redirectUrl), __privateAdd(this, _withCredentials), __privateAdd(this, _fetch), __privateAdd(this, _reconnectInterval), __privateAdd(this, _reconnectTimer), __privateAdd(this, _lastEventId, null), __privateAdd(this, _controller), __privateAdd(this, _parser), __privateAdd(this, _onError, null), __privateAdd(this, _onMessage, null), __privateAdd(this, _onOpen, null), __privateAdd(this, _onFetchResponse, async (response) => {
|
|
741
|
+
var _a2;
|
|
742
|
+
__privateGet(this, _parser).reset();
|
|
743
|
+
const { body, redirected, status, headers } = response;
|
|
744
|
+
if (status === 204) {
|
|
745
|
+
__privateMethod(this, _EventSource_instances, failConnection_fn).call(this, "Server sent HTTP 204, not reconnecting", 204), this.close();
|
|
746
|
+
return;
|
|
747
|
+
}
|
|
748
|
+
if (redirected ? __privateSet(this, _redirectUrl, new URL(response.url)) : __privateSet(this, _redirectUrl, void 0), status !== 200) {
|
|
749
|
+
__privateMethod(this, _EventSource_instances, failConnection_fn).call(this, `Non-200 status code (${status})`, status);
|
|
750
|
+
return;
|
|
751
|
+
}
|
|
752
|
+
if (!(headers.get("content-type") || "").startsWith("text/event-stream")) {
|
|
753
|
+
__privateMethod(this, _EventSource_instances, failConnection_fn).call(this, 'Invalid content type, expected "text/event-stream"', status);
|
|
754
|
+
return;
|
|
755
|
+
}
|
|
756
|
+
if (__privateGet(this, _readyState) === this.CLOSED)
|
|
757
|
+
return;
|
|
758
|
+
__privateSet(this, _readyState, this.OPEN);
|
|
759
|
+
const openEvent = new Event("open");
|
|
760
|
+
if ((_a2 = __privateGet(this, _onOpen)) == null || _a2.call(this, openEvent), this.dispatchEvent(openEvent), typeof body != "object" || !body || !("getReader" in body)) {
|
|
761
|
+
__privateMethod(this, _EventSource_instances, failConnection_fn).call(this, "Invalid response body, expected a web ReadableStream", status), this.close();
|
|
762
|
+
return;
|
|
763
|
+
}
|
|
764
|
+
const decoder = new TextDecoder(), reader = body.getReader();
|
|
765
|
+
let open = true;
|
|
766
|
+
do {
|
|
767
|
+
const { done, value } = await reader.read();
|
|
768
|
+
value && __privateGet(this, _parser).feed(decoder.decode(value, { stream: !done })), done && (open = false, __privateGet(this, _parser).reset(), __privateMethod(this, _EventSource_instances, scheduleReconnect_fn).call(this));
|
|
769
|
+
} while (open);
|
|
770
|
+
}), __privateAdd(this, _onFetchError, (err) => {
|
|
771
|
+
__privateSet(this, _controller, void 0), !(err.name === "AbortError" || err.type === "aborted") && __privateMethod(this, _EventSource_instances, scheduleReconnect_fn).call(this, flattenError(err));
|
|
772
|
+
}), __privateAdd(this, _onEvent, (event) => {
|
|
773
|
+
typeof event.id == "string" && __privateSet(this, _lastEventId, event.id);
|
|
774
|
+
const messageEvent = new MessageEvent(event.event || "message", {
|
|
775
|
+
data: event.data,
|
|
776
|
+
origin: __privateGet(this, _redirectUrl) ? __privateGet(this, _redirectUrl).origin : __privateGet(this, _url).origin,
|
|
777
|
+
lastEventId: event.id || ""
|
|
778
|
+
});
|
|
779
|
+
__privateGet(this, _onMessage) && (!event.event || event.event === "message") && __privateGet(this, _onMessage).call(this, messageEvent), this.dispatchEvent(messageEvent);
|
|
780
|
+
}), __privateAdd(this, _onRetryChange, (value) => {
|
|
781
|
+
__privateSet(this, _reconnectInterval, value);
|
|
782
|
+
}), __privateAdd(this, _reconnect, () => {
|
|
783
|
+
__privateSet(this, _reconnectTimer, void 0), __privateGet(this, _readyState) === this.CONNECTING && __privateMethod(this, _EventSource_instances, connect_fn).call(this);
|
|
784
|
+
});
|
|
785
|
+
try {
|
|
786
|
+
if (url instanceof URL)
|
|
787
|
+
__privateSet(this, _url, url);
|
|
788
|
+
else if (typeof url == "string")
|
|
789
|
+
__privateSet(this, _url, new URL(url, getBaseURL()));
|
|
790
|
+
else
|
|
791
|
+
throw new Error("Invalid URL");
|
|
792
|
+
} catch {
|
|
793
|
+
throw syntaxError("An invalid or illegal string was specified");
|
|
794
|
+
}
|
|
795
|
+
__privateSet(this, _parser, createParser({
|
|
796
|
+
onEvent: __privateGet(this, _onEvent),
|
|
797
|
+
onRetry: __privateGet(this, _onRetryChange)
|
|
798
|
+
})), __privateSet(this, _readyState, this.CONNECTING), __privateSet(this, _reconnectInterval, 3e3), __privateSet(this, _fetch, (_a = eventSourceInitDict == null ? void 0 : eventSourceInitDict.fetch) != null ? _a : globalThis.fetch), __privateSet(this, _withCredentials, (_b = eventSourceInitDict == null ? void 0 : eventSourceInitDict.withCredentials) != null ? _b : false), __privateMethod(this, _EventSource_instances, connect_fn).call(this);
|
|
799
|
+
}
|
|
800
|
+
/**
|
|
801
|
+
* Returns the state of this EventSource object's connection. It can have the values described below.
|
|
802
|
+
*
|
|
803
|
+
* [MDN Reference](https://developer.mozilla.org/docs/Web/API/EventSource/readyState)
|
|
804
|
+
*
|
|
805
|
+
* Note: typed as `number` instead of `0 | 1 | 2` for compatibility with the `EventSource` interface,
|
|
806
|
+
* defined in the TypeScript `dom` library.
|
|
807
|
+
*
|
|
808
|
+
* @public
|
|
809
|
+
*/
|
|
810
|
+
get readyState() {
|
|
811
|
+
return __privateGet(this, _readyState);
|
|
812
|
+
}
|
|
813
|
+
/**
|
|
814
|
+
* Returns the URL providing the event stream.
|
|
815
|
+
*
|
|
816
|
+
* [MDN Reference](https://developer.mozilla.org/docs/Web/API/EventSource/url)
|
|
817
|
+
*
|
|
818
|
+
* @public
|
|
819
|
+
*/
|
|
820
|
+
get url() {
|
|
821
|
+
return __privateGet(this, _url).href;
|
|
822
|
+
}
|
|
823
|
+
/**
|
|
824
|
+
* Returns true if the credentials mode for connection requests to the URL providing the event stream is set to "include", and false otherwise.
|
|
825
|
+
*
|
|
826
|
+
* [MDN Reference](https://developer.mozilla.org/docs/Web/API/EventSource/withCredentials)
|
|
827
|
+
*/
|
|
828
|
+
get withCredentials() {
|
|
829
|
+
return __privateGet(this, _withCredentials);
|
|
830
|
+
}
|
|
831
|
+
/** [MDN Reference](https://developer.mozilla.org/docs/Web/API/EventSource/error_event) */
|
|
832
|
+
get onerror() {
|
|
833
|
+
return __privateGet(this, _onError);
|
|
834
|
+
}
|
|
835
|
+
set onerror(value) {
|
|
836
|
+
__privateSet(this, _onError, value);
|
|
837
|
+
}
|
|
838
|
+
/** [MDN Reference](https://developer.mozilla.org/docs/Web/API/EventSource/message_event) */
|
|
839
|
+
get onmessage() {
|
|
840
|
+
return __privateGet(this, _onMessage);
|
|
841
|
+
}
|
|
842
|
+
set onmessage(value) {
|
|
843
|
+
__privateSet(this, _onMessage, value);
|
|
844
|
+
}
|
|
845
|
+
/** [MDN Reference](https://developer.mozilla.org/docs/Web/API/EventSource/open_event) */
|
|
846
|
+
get onopen() {
|
|
847
|
+
return __privateGet(this, _onOpen);
|
|
848
|
+
}
|
|
849
|
+
set onopen(value) {
|
|
850
|
+
__privateSet(this, _onOpen, value);
|
|
851
|
+
}
|
|
852
|
+
addEventListener(type, listener, options) {
|
|
853
|
+
const listen = listener;
|
|
854
|
+
super.addEventListener(type, listen, options);
|
|
855
|
+
}
|
|
856
|
+
removeEventListener(type, listener, options) {
|
|
857
|
+
const listen = listener;
|
|
858
|
+
super.removeEventListener(type, listen, options);
|
|
859
|
+
}
|
|
860
|
+
/**
|
|
861
|
+
* Aborts any instances of the fetch algorithm started for this EventSource object, and sets the readyState attribute to CLOSED.
|
|
862
|
+
*
|
|
863
|
+
* [MDN Reference](https://developer.mozilla.org/docs/Web/API/EventSource/close)
|
|
864
|
+
*
|
|
865
|
+
* @public
|
|
866
|
+
*/
|
|
867
|
+
close() {
|
|
868
|
+
__privateGet(this, _reconnectTimer) && clearTimeout(__privateGet(this, _reconnectTimer)), __privateGet(this, _readyState) !== this.CLOSED && (__privateGet(this, _controller) && __privateGet(this, _controller).abort(), __privateSet(this, _readyState, this.CLOSED), __privateSet(this, _controller, void 0));
|
|
505
869
|
}
|
|
506
|
-
const username = process.env.BATON_USER;
|
|
507
|
-
const password = process.env.BATON_PASS;
|
|
508
|
-
if (!username || !password) return;
|
|
509
|
-
setLoginGate(
|
|
510
|
-
(async () => {
|
|
511
|
-
const res = await fetch(`${baseUrl}/auth/login`, {
|
|
512
|
-
method: "POST",
|
|
513
|
-
headers: { "content-type": "application/json" },
|
|
514
|
-
body: JSON.stringify({ username, password })
|
|
515
|
-
});
|
|
516
|
-
const cookie = (res.headers.getSetCookie()[0] ?? "").split(";")[0];
|
|
517
|
-
if (res.ok && cookie) setAuthHeaders({ cookie });
|
|
518
|
-
})().catch(() => {
|
|
519
|
-
})
|
|
520
|
-
);
|
|
521
|
-
};
|
|
522
|
-
|
|
523
|
-
// src/client/projects.ts
|
|
524
|
-
var projectClient = (baseUrl) => {
|
|
525
|
-
const u = (p) => `${baseUrl}${p}`;
|
|
526
|
-
return {
|
|
527
|
-
create: (input) => request(u("/projects"), { method: "POST", body: input }),
|
|
528
|
-
listByWorkspace: (workspaceId) => request(u(`/workspaces/${workspaceId}/projects`), { method: "GET" }),
|
|
529
|
-
get: (id) => request(u(`/projects/${id}`), { method: "GET" }),
|
|
530
|
-
update: (id, patch2) => request(u(`/projects/${id}`), { method: "PATCH", body: patch2 }),
|
|
531
|
-
remove: (id) => request(u(`/projects/${id}`), { method: "DELETE" })
|
|
532
|
-
};
|
|
533
|
-
};
|
|
534
|
-
|
|
535
|
-
// src/client/items.ts
|
|
536
|
-
var fetchItemByCode = async (baseUrl, projectId, code, expectKind) => {
|
|
537
|
-
const r = await request(
|
|
538
|
-
`${baseUrl}/projects/${projectId}/items/${encodeURIComponent(code)}`,
|
|
539
|
-
{ method: "GET" }
|
|
540
|
-
);
|
|
541
|
-
if (r.kind !== expectKind) throw new Error(`expected ${expectKind} but got ${r.kind} for ${code}`);
|
|
542
|
-
return r.item;
|
|
543
870
|
};
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
871
|
+
_readyState = /* @__PURE__ */ new WeakMap(), _url = /* @__PURE__ */ new WeakMap(), _redirectUrl = /* @__PURE__ */ new WeakMap(), _withCredentials = /* @__PURE__ */ new WeakMap(), _fetch = /* @__PURE__ */ new WeakMap(), _reconnectInterval = /* @__PURE__ */ new WeakMap(), _reconnectTimer = /* @__PURE__ */ new WeakMap(), _lastEventId = /* @__PURE__ */ new WeakMap(), _controller = /* @__PURE__ */ new WeakMap(), _parser = /* @__PURE__ */ new WeakMap(), _onError = /* @__PURE__ */ new WeakMap(), _onMessage = /* @__PURE__ */ new WeakMap(), _onOpen = /* @__PURE__ */ new WeakMap(), _EventSource_instances = /* @__PURE__ */ new WeakSet(), /**
|
|
872
|
+
* Connect to the given URL and start receiving events
|
|
873
|
+
*
|
|
874
|
+
* @internal
|
|
875
|
+
*/
|
|
876
|
+
connect_fn = function() {
|
|
877
|
+
__privateSet(this, _readyState, this.CONNECTING), __privateSet(this, _controller, new AbortController()), __privateGet(this, _fetch)(__privateGet(this, _url), __privateMethod(this, _EventSource_instances, getRequestOptions_fn).call(this)).then(__privateGet(this, _onFetchResponse)).catch(__privateGet(this, _onFetchError));
|
|
878
|
+
}, _onFetchResponse = /* @__PURE__ */ new WeakMap(), _onFetchError = /* @__PURE__ */ new WeakMap(), /**
|
|
879
|
+
* Get request options for the `fetch()` request
|
|
880
|
+
*
|
|
881
|
+
* @returns The request options
|
|
882
|
+
* @internal
|
|
883
|
+
*/
|
|
884
|
+
getRequestOptions_fn = function() {
|
|
885
|
+
var _a;
|
|
886
|
+
const init2 = {
|
|
887
|
+
// [spec] Let `corsAttributeState` be `Anonymous`…
|
|
888
|
+
// [spec] …will have their mode set to "cors"…
|
|
889
|
+
mode: "cors",
|
|
890
|
+
redirect: "follow",
|
|
891
|
+
headers: { Accept: "text/event-stream", ...__privateGet(this, _lastEventId) ? { "Last-Event-ID": __privateGet(this, _lastEventId) } : void 0 },
|
|
892
|
+
cache: "no-store",
|
|
893
|
+
signal: (_a = __privateGet(this, _controller)) == null ? void 0 : _a.signal
|
|
556
894
|
};
|
|
557
|
-
|
|
895
|
+
return "window" in globalThis && (init2.credentials = this.withCredentials ? "include" : "same-origin"), init2;
|
|
896
|
+
}, _onEvent = /* @__PURE__ */ new WeakMap(), _onRetryChange = /* @__PURE__ */ new WeakMap(), /**
|
|
897
|
+
* Handles the process referred to in the EventSource specification as "failing a connection".
|
|
898
|
+
*
|
|
899
|
+
* @param error - The error causing the connection to fail
|
|
900
|
+
* @param code - The HTTP status code, if available
|
|
901
|
+
* @internal
|
|
902
|
+
*/
|
|
903
|
+
failConnection_fn = function(message, code) {
|
|
904
|
+
var _a;
|
|
905
|
+
__privateGet(this, _readyState) !== this.CLOSED && __privateSet(this, _readyState, this.CLOSED);
|
|
906
|
+
const errorEvent = new ErrorEvent("error", { code, message });
|
|
907
|
+
(_a = __privateGet(this, _onError)) == null || _a.call(this, errorEvent), this.dispatchEvent(errorEvent);
|
|
908
|
+
}, /**
|
|
909
|
+
* Schedules a reconnection attempt against the EventSource endpoint.
|
|
910
|
+
*
|
|
911
|
+
* @param message - The error causing the connection to fail
|
|
912
|
+
* @param code - The HTTP status code, if available
|
|
913
|
+
* @internal
|
|
914
|
+
*/
|
|
915
|
+
scheduleReconnect_fn = function(message, code) {
|
|
916
|
+
var _a;
|
|
917
|
+
if (__privateGet(this, _readyState) === this.CLOSED)
|
|
918
|
+
return;
|
|
919
|
+
__privateSet(this, _readyState, this.CONNECTING);
|
|
920
|
+
const errorEvent = new ErrorEvent("error", { code, message });
|
|
921
|
+
(_a = __privateGet(this, _onError)) == null || _a.call(this, errorEvent), this.dispatchEvent(errorEvent), __privateSet(this, _reconnectTimer, setTimeout(__privateGet(this, _reconnect), __privateGet(this, _reconnectInterval)));
|
|
922
|
+
}, _reconnect = /* @__PURE__ */ new WeakMap(), /**
|
|
923
|
+
* ReadyState representing an EventSource currently trying to connect
|
|
924
|
+
*
|
|
925
|
+
* @public
|
|
926
|
+
*/
|
|
927
|
+
EventSource.CONNECTING = 0, /**
|
|
928
|
+
* ReadyState representing an EventSource connection that is open (eg connected)
|
|
929
|
+
*
|
|
930
|
+
* @public
|
|
931
|
+
*/
|
|
932
|
+
EventSource.OPEN = 1, /**
|
|
933
|
+
* ReadyState representing an EventSource connection that is closed (eg disconnected)
|
|
934
|
+
*
|
|
935
|
+
* @public
|
|
936
|
+
*/
|
|
937
|
+
EventSource.CLOSED = 2;
|
|
938
|
+
Object.defineProperty(EventSource, /* @__PURE__ */ Symbol.for("eventsource.supports-fetch-override"), {
|
|
939
|
+
value: true,
|
|
940
|
+
writable: false,
|
|
941
|
+
configurable: false,
|
|
942
|
+
enumerable: false
|
|
943
|
+
});
|
|
944
|
+
function getBaseURL() {
|
|
945
|
+
const doc = "document" in globalThis ? globalThis.document : void 0;
|
|
946
|
+
return doc && typeof doc == "object" && "baseURI" in doc && typeof doc.baseURI == "string" ? doc.baseURI : void 0;
|
|
947
|
+
}
|
|
558
948
|
|
|
559
|
-
// src/client/
|
|
560
|
-
var
|
|
949
|
+
// src/client/channel.ts
|
|
950
|
+
var channelClient = (baseUrl) => {
|
|
561
951
|
const u = (p) => `${baseUrl}${p}`;
|
|
952
|
+
const authed = (token) => ({ authorization: `Bearer ${token}` });
|
|
953
|
+
const sendJson = (token) => ({ "content-type": "application/json", ...authed(token) });
|
|
954
|
+
const member = (channelId, name) => u(`/channels/${channelId}/members/${encodeURIComponent(name)}`);
|
|
562
955
|
return {
|
|
563
|
-
create: (
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
body: { active },
|
|
572
|
-
headers: { authorization: `Bearer ${workerToken}` }
|
|
573
|
-
}),
|
|
574
|
-
setName: (id, name, workerToken) => request(u(`/sessions/${id}`), {
|
|
575
|
-
method: "PATCH",
|
|
576
|
-
body: { name },
|
|
577
|
-
headers: { authorization: `Bearer ${workerToken}` }
|
|
578
|
-
}),
|
|
579
|
-
resume: (id) => request(u(`/sessions/${id}/resume`), { method: "POST" }),
|
|
580
|
-
stop: (id) => request(u(`/sessions/${id}/stop`), { method: "POST" }),
|
|
581
|
-
clear: (id) => request(u(`/sessions/${id}/clear`), { method: "POST" }),
|
|
582
|
-
abort: (id) => request(u(`/sessions/${id}/abort`), { method: "POST" }),
|
|
583
|
-
rename: (id, name) => request(u(`/sessions/${id}/rename`), { method: "POST", body: { name } }),
|
|
584
|
-
listByProject: (projectId) => request(u(`/projects/${projectId}/sessions`), { method: "GET" }),
|
|
585
|
-
get: (id) => request(u(`/sessions/${id}`), { method: "GET" }),
|
|
586
|
-
findByName: async (projectId, name) => {
|
|
587
|
-
const all = await request(u(`/projects/${projectId}/sessions`), { method: "GET" });
|
|
588
|
-
const matches = all.filter((s) => s.name === name);
|
|
589
|
-
return matches.length === 0 ? null : matches[matches.length - 1] ?? null;
|
|
956
|
+
create: async (title, description) => {
|
|
957
|
+
const res = await fetch(u("/channels"), {
|
|
958
|
+
method: "POST",
|
|
959
|
+
headers: { "content-type": "application/json" },
|
|
960
|
+
body: JSON.stringify({ ...title ? { title } : {}, ...description ? { description } : {} })
|
|
961
|
+
});
|
|
962
|
+
if (!res.ok) throw new Error(`POST /channels \u2192 ${res.status}: ${await res.text()}`);
|
|
963
|
+
return await res.json();
|
|
590
964
|
},
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
}
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
965
|
+
manifest: async (channelId, token) => {
|
|
966
|
+
const res = await fetch(u(`/channels/${channelId}`), { headers: authed(token) });
|
|
967
|
+
if (!res.ok) throw new Error(`GET channel \u2192 ${res.status}: ${await res.text()}`);
|
|
968
|
+
return await res.json();
|
|
969
|
+
},
|
|
970
|
+
update: async (channelId, token, patch2) => {
|
|
971
|
+
const res = await fetch(u(`/channels/${channelId}`), {
|
|
972
|
+
method: "PATCH",
|
|
973
|
+
headers: sendJson(token),
|
|
974
|
+
body: JSON.stringify(patch2)
|
|
975
|
+
});
|
|
976
|
+
if (!res.ok) throw new Error(`PATCH channel \u2192 ${res.status}: ${await res.text()}`);
|
|
977
|
+
return await res.json();
|
|
978
|
+
},
|
|
979
|
+
help: async () => {
|
|
980
|
+
const res = await fetch(u("/channels/help"));
|
|
981
|
+
if (!res.ok) throw new Error(`GET /channels/help \u2192 ${res.status}: ${await res.text()}`);
|
|
982
|
+
return await res.text();
|
|
983
|
+
},
|
|
984
|
+
destroy: async (channelId, token) => {
|
|
985
|
+
const res = await fetch(u(`/channels/${channelId}`), {
|
|
986
|
+
method: "DELETE",
|
|
987
|
+
headers: authed(token)
|
|
988
|
+
});
|
|
989
|
+
if (!res.ok) throw new Error(`DELETE channel \u2192 ${res.status}: ${await res.text()}`);
|
|
990
|
+
},
|
|
991
|
+
join: async (channelId, token, name, kind) => {
|
|
992
|
+
const res = await fetch(member(channelId, name), {
|
|
993
|
+
method: "PUT",
|
|
994
|
+
headers: sendJson(token),
|
|
995
|
+
body: JSON.stringify({ kind: kind ?? "agent" })
|
|
996
|
+
});
|
|
997
|
+
if (!res.ok) throw new Error(`join channel \u2192 ${res.status}: ${await res.text()}`);
|
|
998
|
+
return (await res.json()).members;
|
|
999
|
+
},
|
|
1000
|
+
leave: async (channelId, token, name) => {
|
|
1001
|
+
const res = await fetch(member(channelId, name), { method: "DELETE", headers: authed(token) });
|
|
1002
|
+
if (!res.ok) throw new Error(`leave channel \u2192 ${res.status}: ${await res.text()}`);
|
|
1003
|
+
},
|
|
1004
|
+
members: async (channelId, token) => {
|
|
1005
|
+
const res = await fetch(u(`/channels/${channelId}/members`), { headers: authed(token) });
|
|
1006
|
+
if (!res.ok) throw new Error(`GET members \u2192 ${res.status}: ${await res.text()}`);
|
|
1007
|
+
return (await res.json()).members;
|
|
1008
|
+
},
|
|
1009
|
+
send: async (channelId, token, msg) => {
|
|
1010
|
+
const res = await fetch(u(`/channels/${channelId}/messages`), {
|
|
605
1011
|
method: "POST",
|
|
606
|
-
|
|
607
|
-
|
|
1012
|
+
headers: sendJson(token),
|
|
1013
|
+
body: JSON.stringify(msg)
|
|
608
1014
|
});
|
|
609
|
-
if (!res.ok) throw new Error(`POST
|
|
1015
|
+
if (!res.ok) throw new Error(`POST channel message \u2192 ${res.status}: ${await res.text()}`);
|
|
1016
|
+
return await res.json();
|
|
1017
|
+
},
|
|
1018
|
+
uploadAttachment: async (channelId, token, input) => {
|
|
1019
|
+
const res = await fetch(
|
|
1020
|
+
u(`/channels/${channelId}/attachments?filename=${encodeURIComponent(input.filename)}`),
|
|
1021
|
+
{
|
|
1022
|
+
method: "POST",
|
|
1023
|
+
headers: { "content-type": input.contentType, ...authed(token) },
|
|
1024
|
+
body: input.body
|
|
1025
|
+
}
|
|
1026
|
+
);
|
|
1027
|
+
if (!res.ok) throw new Error(`upload attachment \u2192 ${res.status}: ${await res.text()}`);
|
|
610
1028
|
return await res.json();
|
|
611
1029
|
},
|
|
612
|
-
|
|
613
|
-
await
|
|
614
|
-
|
|
615
|
-
};
|
|
616
|
-
};
|
|
617
|
-
|
|
618
|
-
// src/client/tasks.ts
|
|
619
|
-
var taskClient = (baseUrl) => {
|
|
620
|
-
const u = (p) => `${baseUrl}${p}`;
|
|
621
|
-
return {
|
|
622
|
-
create: (input) => request(u("/tasks"), { method: "POST", body: input }),
|
|
623
|
-
listByRequirement: (requirementId) => request(u(`/requirements/${requirementId}/tasks`), { method: "GET" }),
|
|
624
|
-
get: (id) => request(u(`/tasks/${id}`), { method: "GET" }),
|
|
625
|
-
getByCode: (projectId, code) => fetchItemByCode(baseUrl, projectId, code, "task"),
|
|
626
|
-
update: (id, patch2) => request(u(`/tasks/${id}`), { method: "PATCH", body: patch2 }),
|
|
627
|
-
setStatus: (id, status) => request(u(`/tasks/${id}`), { method: "PATCH", body: { status } }),
|
|
628
|
-
remove: (id) => request(u(`/tasks/${id}`), { method: "DELETE" }),
|
|
629
|
-
listComments: (id) => request(u(`/tasks/${id}/comments`), { method: "GET" }),
|
|
630
|
-
addComment: (id, body, workerId) => request(u(`/tasks/${id}/comments`), { method: "POST", body: { body, workerId } })
|
|
631
|
-
};
|
|
632
|
-
};
|
|
633
|
-
|
|
634
|
-
// src/client/workers.ts
|
|
635
|
-
var workersClient = (baseUrl) => {
|
|
636
|
-
const u = (p) => `${baseUrl}${p}`;
|
|
637
|
-
return {
|
|
638
|
-
register: (input) => request(u("/workers"), { method: "POST", body: input }),
|
|
639
|
-
listByProject: (projectId) => request(u(`/projects/${projectId}/workers`), { method: "GET" }),
|
|
640
|
-
get: (id) => request(u(`/workers/${id}`), { method: "GET" }),
|
|
641
|
-
findByName: async (projectId, name) => {
|
|
642
|
-
const all = await request(u(`/projects/${projectId}/workers`), {
|
|
643
|
-
method: "GET"
|
|
1030
|
+
downloadAttachment: async (channelId, token, attId) => {
|
|
1031
|
+
const res = await fetch(u(`/channels/${channelId}/attachments/${attId}`), {
|
|
1032
|
+
headers: authed(token)
|
|
644
1033
|
});
|
|
645
|
-
|
|
646
|
-
return
|
|
1034
|
+
if (!res.ok) throw new Error(`download attachment \u2192 ${res.status}: ${await res.text()}`);
|
|
1035
|
+
return res;
|
|
647
1036
|
},
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
1037
|
+
read: async (channelId, token, opts) => {
|
|
1038
|
+
const params = new URLSearchParams({ since: String(opts?.since ?? 0) });
|
|
1039
|
+
if (opts?.for) params.set("for", opts.for);
|
|
1040
|
+
const res = await fetch(u(`/channels/${channelId}/messages?${params}`), {
|
|
1041
|
+
headers: authed(token)
|
|
1042
|
+
});
|
|
1043
|
+
if (!res.ok) throw new Error(`GET messages \u2192 ${res.status}: ${await res.text()}`);
|
|
1044
|
+
return (await res.json()).messages;
|
|
1045
|
+
},
|
|
1046
|
+
listen: (channelId, token, opts) => {
|
|
1047
|
+
let cursor = opts.since ?? 0;
|
|
1048
|
+
const params = new URLSearchParams({ since: String(cursor) });
|
|
1049
|
+
if (opts.for) params.set("for", opts.for);
|
|
1050
|
+
if (opts.as) params.set("as", opts.as);
|
|
1051
|
+
const es = new EventSource(u(`/channels/${channelId}/stream?${params}`), {
|
|
1052
|
+
fetch: (url, init2) => fetch(url, {
|
|
1053
|
+
...init2,
|
|
1054
|
+
headers: { ...init2?.headers, ...authed(token) }
|
|
1055
|
+
})
|
|
1056
|
+
});
|
|
1057
|
+
es.onmessage = (e) => {
|
|
1058
|
+
try {
|
|
1059
|
+
const m = JSON.parse(e.data);
|
|
1060
|
+
if (m.seq <= cursor) return;
|
|
1061
|
+
cursor = m.seq;
|
|
1062
|
+
opts.onMessage(m);
|
|
1063
|
+
} catch (err) {
|
|
1064
|
+
opts.onError?.(err);
|
|
1065
|
+
}
|
|
1066
|
+
};
|
|
1067
|
+
es.onerror = (err) => opts.onError?.(err);
|
|
1068
|
+
return () => es.close();
|
|
651
1069
|
}
|
|
652
1070
|
};
|
|
653
1071
|
};
|
|
654
1072
|
|
|
655
|
-
// src/client/workspaces.ts
|
|
656
|
-
var workspaceClient = (baseUrl) => {
|
|
657
|
-
const u = (p) => `${baseUrl}${p}`;
|
|
658
|
-
return {
|
|
659
|
-
create: (input) => request(u("/workspaces"), { method: "POST", body: input }),
|
|
660
|
-
list: () => request(u("/workspaces"), { method: "GET" }),
|
|
661
|
-
get: (id) => request(u(`/workspaces/${id}`), { method: "GET" }),
|
|
662
|
-
update: (id, patch2) => request(u(`/workspaces/${id}`), { method: "PATCH", body: patch2 }),
|
|
663
|
-
remove: (id) => request(u(`/workspaces/${id}`), { method: "DELETE" })
|
|
664
|
-
};
|
|
665
|
-
};
|
|
666
|
-
|
|
667
|
-
// src/client.ts
|
|
668
|
-
var createClient = (baseUrl, opts) => {
|
|
669
|
-
if (opts?.bearer) setAuthHeaders({ authorization: `Bearer ${opts.bearer}` });
|
|
670
|
-
else primeLogin(baseUrl);
|
|
671
|
-
return clientFromBase(baseUrl);
|
|
672
|
-
};
|
|
673
|
-
var clientFromBase = (baseUrl) => ({
|
|
674
|
-
workspaces: workspaceClient(baseUrl),
|
|
675
|
-
projects: projectClient(baseUrl),
|
|
676
|
-
requirements: requirementClient(baseUrl),
|
|
677
|
-
tasks: taskClient(baseUrl),
|
|
678
|
-
sessions: sessionsClient(baseUrl),
|
|
679
|
-
workers: workersClient(baseUrl)
|
|
680
|
-
});
|
|
681
|
-
var createWorkerClient = (baseUrl, workerToken, sessionId) => {
|
|
682
|
-
const u = (p) => `${baseUrl}${p}`;
|
|
683
|
-
const auth = { authorization: `Bearer ${workerToken}` };
|
|
684
|
-
return {
|
|
685
|
-
emitEvent: (type, payload) => request(u(`/sessions/${sessionId}/events`), {
|
|
686
|
-
method: "POST",
|
|
687
|
-
body: { type, payload },
|
|
688
|
-
headers: auth
|
|
689
|
-
}),
|
|
690
|
-
setActive: (active) => request(u(`/sessions/${sessionId}/status`), {
|
|
691
|
-
method: "POST",
|
|
692
|
-
body: { active },
|
|
693
|
-
headers: auth
|
|
694
|
-
}),
|
|
695
|
-
listEvents: () => request(u(`/sessions/${sessionId}/events`), { method: "GET", headers: auth })
|
|
696
|
-
};
|
|
697
|
-
};
|
|
698
|
-
|
|
699
1073
|
// src/project-config.ts
|
|
700
1074
|
import { existsSync, readFileSync, writeFileSync } from "node:fs";
|
|
701
1075
|
import { join } from "node:path";
|
|
@@ -705,165 +1079,63 @@ var configPathFromArgs = (args, cwd) => args.config ?? projectConfigPath(cwd);
|
|
|
705
1079
|
var loadProjectConfig = (path) => {
|
|
706
1080
|
try {
|
|
707
1081
|
return JSON.parse(readFileSync(path, "utf8"));
|
|
708
|
-
} catch (err) {
|
|
709
|
-
const cause = err.code === "ENOENT" ? `not found at ${path}` : String(err);
|
|
710
|
-
throw new Error(`${PROJECT_CONFIG_NAME} ${cause} \u2014 run \`baton init\` first`);
|
|
711
|
-
}
|
|
712
|
-
};
|
|
713
|
-
var loadProjectConfigOrNull = (path) => {
|
|
714
|
-
if (!existsSync(path)) return null;
|
|
715
|
-
try {
|
|
716
|
-
return JSON.parse(readFileSync(path, "utf8"));
|
|
717
|
-
} catch {
|
|
718
|
-
return null;
|
|
719
|
-
}
|
|
720
|
-
};
|
|
721
|
-
var saveProjectConfig = (path, config) => {
|
|
722
|
-
writeFileSync(path, `${JSON.stringify(config, null, 2)}
|
|
723
|
-
`, "utf8");
|
|
724
|
-
};
|
|
725
|
-
var patch = (path, fn) => {
|
|
726
|
-
saveProjectConfig(path, fn(loadProjectConfig(path)));
|
|
727
|
-
};
|
|
728
|
-
var setWorker = (path, w) => patch(path, (cfg) => ({ ...cfg, worker: w }));
|
|
729
|
-
var requireBase = (cfg) => {
|
|
730
|
-
if (!cfg.server || !cfg.project || !cfg.worker)
|
|
731
|
-
throw new Error("project-config missing server/project/worker \u2014 run `baton worker register`");
|
|
732
|
-
return { server: cfg.server, project: cfg.project, worker: cfg.worker };
|
|
733
|
-
};
|
|
734
|
-
var viewWorker = (cfg) => {
|
|
735
|
-
const { server, project: project2, worker: worker2 } = requireBase(cfg);
|
|
736
|
-
return {
|
|
737
|
-
server,
|
|
738
|
-
projectId: project2,
|
|
739
|
-
workerId: worker2.id,
|
|
740
|
-
name: worker2.name,
|
|
741
|
-
machineId: worker2.machineId,
|
|
742
|
-
apiToken: worker2.apiToken
|
|
743
|
-
};
|
|
744
|
-
};
|
|
745
|
-
var worktreeConfig = (cfg) => ({
|
|
746
|
-
server: cfg.server,
|
|
747
|
-
project: cfg.projectId,
|
|
748
|
-
worker: { id: cfg.workerId, name: cfg.name, machineId: cfg.machineId, apiToken: cfg.apiToken }
|
|
749
|
-
});
|
|
750
|
-
|
|
751
|
-
// src/config.ts
|
|
752
|
-
var resolveBaseUrl = (urlArg, env = process.env) => {
|
|
753
|
-
if (urlArg) return urlArg;
|
|
754
|
-
const cfg = loadProjectConfigOrNull(projectConfigPath());
|
|
755
|
-
if (cfg?.server) return cfg.server;
|
|
756
|
-
return env.BATON_URL ?? "http://localhost:3280";
|
|
757
|
-
};
|
|
758
|
-
var resolveBaseUrlOrNull = (urlArg, env = process.env) => {
|
|
759
|
-
if (urlArg) return urlArg;
|
|
760
|
-
const cfg = loadProjectConfigOrNull(projectConfigPath());
|
|
761
|
-
if (cfg?.server) return cfg.server;
|
|
762
|
-
return env.BATON_URL ?? null;
|
|
763
|
-
};
|
|
764
|
-
|
|
765
|
-
// src/util.ts
|
|
766
|
-
var common = {
|
|
767
|
-
url: {
|
|
768
|
-
type: "string",
|
|
769
|
-
description: "baton server url (--url > .baton.json > BATON_URL > http://localhost:3280)"
|
|
770
|
-
},
|
|
771
|
-
json: { type: "boolean", description: "output JSON" }
|
|
772
|
-
};
|
|
773
|
-
var resolveAuth = (env, fileToken) => {
|
|
774
|
-
const envBearer = env.BATON_TOKEN ?? env.BATON_WORKER_TOKEN;
|
|
775
|
-
if (envBearer) return { bearer: envBearer };
|
|
776
|
-
if (env.BATON_USER && env.BATON_PASS) return "cookie";
|
|
777
|
-
return fileToken ? { bearer: fileToken } : void 0;
|
|
778
|
-
};
|
|
779
|
-
var clientFor = (args) => {
|
|
780
|
-
const baseUrl = resolveBaseUrl(args.url);
|
|
781
|
-
const fileToken = loadProjectConfigOrNull(projectConfigPath())?.worker?.apiToken;
|
|
782
|
-
const auth = resolveAuth(process.env, fileToken);
|
|
783
|
-
return createClient(baseUrl, auth && auth !== "cookie" ? auth : void 0);
|
|
784
|
-
};
|
|
785
|
-
var resolveProjectId = (args) => {
|
|
786
|
-
if (args.project !== void 0 && args.project !== "") return Number(args.project);
|
|
787
|
-
const cfg = loadProjectConfigOrNull(projectConfigPath());
|
|
788
|
-
if (cfg?.project !== void 0) return cfg.project;
|
|
789
|
-
throw new Error("no project in scope. pass --project <id> or run `baton init` in this directory.");
|
|
790
|
-
};
|
|
791
|
-
var resolveWorkspaceId = (args) => {
|
|
792
|
-
if (args.workspace !== void 0 && args.workspace !== "") return Number(args.workspace);
|
|
793
|
-
const cfg = loadProjectConfigOrNull(projectConfigPath());
|
|
794
|
-
if (cfg?.workspace !== void 0) return cfg.workspace;
|
|
795
|
-
throw new Error(
|
|
796
|
-
"no workspace in scope. pass --workspace <id> or run `baton init` in this directory."
|
|
797
|
-
);
|
|
798
|
-
};
|
|
799
|
-
var parseWorkerHandle = (handle) => {
|
|
800
|
-
const m = handle.trim().match(/^(?:[wW]-)?(\d+)$/);
|
|
801
|
-
return m ? Number(m[1]) : null;
|
|
802
|
-
};
|
|
803
|
-
var splitCsv = (s) => s ? s.split(",").map((x) => x.trim()).filter(Boolean) : void 0;
|
|
804
|
-
|
|
805
|
-
// src/commands/init.ts
|
|
806
|
-
var promptPick = async (label, items) => {
|
|
807
|
-
if (items.length === 0) throw new Error(`no ${label}s found on server`);
|
|
808
|
-
console.log(`${label}s:`);
|
|
809
|
-
items.forEach((it, i) => {
|
|
810
|
-
console.log(` [${i + 1}] #${it.id} ${it.name}`);
|
|
811
|
-
});
|
|
812
|
-
const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
|
|
813
|
-
try {
|
|
814
|
-
const ans = (await rl.question(`pick a ${label} (1-${items.length}): `)).trim();
|
|
815
|
-
const idx = Number(ans) - 1;
|
|
816
|
-
const picked = items[idx];
|
|
817
|
-
if (!picked) throw new Error(`invalid choice: ${ans}`);
|
|
818
|
-
return picked;
|
|
819
|
-
} finally {
|
|
820
|
-
rl.close();
|
|
821
|
-
}
|
|
822
|
-
};
|
|
823
|
-
var init = defineCommand({
|
|
824
|
-
meta: {
|
|
825
|
-
name: "init",
|
|
826
|
-
description: `write ${PROJECT_CONFIG_NAME} in the current directory (local state, gitignored)`
|
|
827
|
-
},
|
|
828
|
-
args: {
|
|
829
|
-
workspace: { type: "string", description: "workspace id (skip prompt)" },
|
|
830
|
-
project: { type: "string", description: "project id (skip prompt)" },
|
|
831
|
-
force: { type: "boolean", description: `overwrite existing ${PROJECT_CONFIG_NAME}` },
|
|
832
|
-
...common
|
|
833
|
-
},
|
|
834
|
-
run: async ({ args }) => {
|
|
835
|
-
const server = resolveBaseUrl(args.url);
|
|
836
|
-
const cfgPath = projectConfigPath();
|
|
837
|
-
if (existsSync2(cfgPath) && !args.force)
|
|
838
|
-
throw new Error(`${PROJECT_CONFIG_NAME} already exists. use --force to overwrite.`);
|
|
839
|
-
const c = createClient(server);
|
|
840
|
-
let project2;
|
|
841
|
-
let workspace2;
|
|
842
|
-
if (args.project) {
|
|
843
|
-
project2 = await c.projects.get(Number(args.project));
|
|
844
|
-
workspace2 = await c.workspaces.get(project2.workspaceId);
|
|
845
|
-
} else {
|
|
846
|
-
const wsList = await c.workspaces.list();
|
|
847
|
-
workspace2 = args.workspace ? wsList.find((w) => w.id === Number(args.workspace)) ?? (() => {
|
|
848
|
-
throw new Error(`workspace ${args.workspace} not found`);
|
|
849
|
-
})() : await promptPick("workspace", wsList);
|
|
850
|
-
const projects = await c.projects.listByWorkspace(workspace2.id);
|
|
851
|
-
project2 = await promptPick("project", projects);
|
|
852
|
-
}
|
|
853
|
-
const cfg = {
|
|
854
|
-
server,
|
|
855
|
-
workspace: workspace2.id,
|
|
856
|
-
project: project2.id,
|
|
857
|
-
name: project2.name
|
|
858
|
-
};
|
|
859
|
-
saveProjectConfig(cfgPath, cfg);
|
|
860
|
-
console.log(`wrote ${cfgPath}`);
|
|
861
|
-
console.log(` server: ${server}`);
|
|
862
|
-
console.log(` workspace: #${workspace2.id} ${workspace2.name}`);
|
|
863
|
-
console.log(` project: #${project2.id} ${project2.name}`);
|
|
1082
|
+
} catch (err) {
|
|
1083
|
+
const cause = err.code === "ENOENT" ? `not found at ${path}` : String(err);
|
|
1084
|
+
throw new Error(`${PROJECT_CONFIG_NAME} ${cause} \u2014 run \`baton init\` first`);
|
|
1085
|
+
}
|
|
1086
|
+
};
|
|
1087
|
+
var loadProjectConfigOrNull = (path) => {
|
|
1088
|
+
if (!existsSync(path)) return null;
|
|
1089
|
+
try {
|
|
1090
|
+
return JSON.parse(readFileSync(path, "utf8"));
|
|
1091
|
+
} catch {
|
|
1092
|
+
return null;
|
|
864
1093
|
}
|
|
1094
|
+
};
|
|
1095
|
+
var saveProjectConfig = (path, config) => {
|
|
1096
|
+
writeFileSync(path, `${JSON.stringify(config, null, 2)}
|
|
1097
|
+
`, "utf8");
|
|
1098
|
+
};
|
|
1099
|
+
var patch = (path, fn) => {
|
|
1100
|
+
saveProjectConfig(path, fn(loadProjectConfig(path)));
|
|
1101
|
+
};
|
|
1102
|
+
var setWorker = (path, w) => patch(path, (cfg) => ({ ...cfg, worker: w }));
|
|
1103
|
+
var requireBase = (cfg) => {
|
|
1104
|
+
if (!cfg.server || !cfg.project || !cfg.worker)
|
|
1105
|
+
throw new Error("project-config missing server/project/worker \u2014 run `baton worker register`");
|
|
1106
|
+
return { server: cfg.server, project: cfg.project, worker: cfg.worker };
|
|
1107
|
+
};
|
|
1108
|
+
var viewWorker = (cfg) => {
|
|
1109
|
+
const { server, project: project2, worker: worker2 } = requireBase(cfg);
|
|
1110
|
+
return {
|
|
1111
|
+
server,
|
|
1112
|
+
projectId: project2,
|
|
1113
|
+
workerId: worker2.id,
|
|
1114
|
+
name: worker2.name,
|
|
1115
|
+
machineId: worker2.machineId,
|
|
1116
|
+
apiToken: worker2.apiToken
|
|
1117
|
+
};
|
|
1118
|
+
};
|
|
1119
|
+
var worktreeConfig = (cfg) => ({
|
|
1120
|
+
server: cfg.server,
|
|
1121
|
+
project: cfg.projectId,
|
|
1122
|
+
worker: { id: cfg.workerId, name: cfg.name, machineId: cfg.machineId, apiToken: cfg.apiToken }
|
|
865
1123
|
});
|
|
866
1124
|
|
|
1125
|
+
// src/config.ts
|
|
1126
|
+
var resolveBaseUrl = (urlArg, env = process.env) => {
|
|
1127
|
+
if (urlArg) return urlArg;
|
|
1128
|
+
const cfg = loadProjectConfigOrNull(projectConfigPath());
|
|
1129
|
+
if (cfg?.server) return cfg.server;
|
|
1130
|
+
return env.BATON_URL ?? "http://localhost:3280";
|
|
1131
|
+
};
|
|
1132
|
+
var resolveBaseUrlOrNull = (urlArg, env = process.env) => {
|
|
1133
|
+
if (urlArg) return urlArg;
|
|
1134
|
+
const cfg = loadProjectConfigOrNull(projectConfigPath());
|
|
1135
|
+
if (cfg?.server) return cfg.server;
|
|
1136
|
+
return env.BATON_URL ?? null;
|
|
1137
|
+
};
|
|
1138
|
+
|
|
867
1139
|
// src/output.ts
|
|
868
1140
|
var toJson = (data) => JSON.stringify(data, null, 2);
|
|
869
1141
|
var fmtWorkspace = (w) => `${w.id} ${w.name}`;
|
|
@@ -883,563 +1155,874 @@ var renderList = (items, fmt, json) => {
|
|
|
883
1155
|
};
|
|
884
1156
|
var removed = (kind, id, json) => json ? toJson({ ok: true, deleted: id }) : `deleted ${kind} ${id}`;
|
|
885
1157
|
|
|
886
|
-
// src/
|
|
887
|
-
var
|
|
888
|
-
var
|
|
889
|
-
var
|
|
890
|
-
|
|
891
|
-
|
|
892
|
-
var
|
|
893
|
-
|
|
894
|
-
|
|
895
|
-
|
|
896
|
-
|
|
897
|
-
|
|
898
|
-
|
|
899
|
-
|
|
900
|
-
|
|
901
|
-
|
|
902
|
-
|
|
903
|
-
|
|
904
|
-
|
|
905
|
-
|
|
906
|
-
|
|
907
|
-
|
|
908
|
-
|
|
909
|
-
|
|
910
|
-
|
|
911
|
-
|
|
912
|
-
|
|
913
|
-
|
|
914
|
-
|
|
915
|
-
|
|
916
|
-
|
|
917
|
-
},
|
|
918
|
-
run: async ({ args }) => {
|
|
919
|
-
console.log(
|
|
920
|
-
await listProjects(clientFor(args), resolveWorkspaceId(args), Boolean(args.json))
|
|
921
|
-
);
|
|
922
|
-
}
|
|
923
|
-
}),
|
|
924
|
-
get: defineCommand({
|
|
925
|
-
meta: { name: "get", description: "get a project" },
|
|
926
|
-
args: { id: { type: "positional", required: true }, ...common },
|
|
927
|
-
run: async ({ args }) => {
|
|
928
|
-
console.log(await getProject(clientFor(args), Number(args.id), Boolean(args.json)));
|
|
929
|
-
}
|
|
930
|
-
}),
|
|
931
|
-
update: defineCommand({
|
|
932
|
-
meta: { name: "update", description: "rename a project / set its description" },
|
|
933
|
-
args: {
|
|
934
|
-
id: { type: "positional", required: true },
|
|
935
|
-
name: { type: "string", description: "new name" },
|
|
936
|
-
desc: { type: "string", description: "new description" },
|
|
937
|
-
...common
|
|
938
|
-
},
|
|
939
|
-
run: async ({ args }) => {
|
|
940
|
-
const patch2 = {
|
|
941
|
-
...args.name !== void 0 ? { name: args.name } : {},
|
|
942
|
-
...args.desc !== void 0 ? { description: args.desc } : {}
|
|
943
|
-
};
|
|
944
|
-
if (Object.keys(patch2).length === 0) throw new Error("pass --name and/or --desc");
|
|
945
|
-
console.log(
|
|
946
|
-
await updateProject(clientFor(args), Number(args.id), patch2, Boolean(args.json))
|
|
947
|
-
);
|
|
948
|
-
}
|
|
949
|
-
}),
|
|
950
|
-
rm: defineCommand({
|
|
951
|
-
meta: { name: "rm", description: "delete a project" },
|
|
952
|
-
args: { id: { type: "positional", required: true }, ...common },
|
|
953
|
-
run: async ({ args }) => {
|
|
954
|
-
console.log(await removeProject(clientFor(args), Number(args.id), Boolean(args.json)));
|
|
955
|
-
}
|
|
956
|
-
})
|
|
957
|
-
}
|
|
958
|
-
});
|
|
959
|
-
|
|
960
|
-
// src/commands/relay.ts
|
|
961
|
-
import { mkdirSync, readFileSync as readFileSync2, writeFileSync as writeFileSync2 } from "node:fs";
|
|
962
|
-
import { tmpdir } from "node:os";
|
|
963
|
-
import { join as join2 } from "node:path";
|
|
964
|
-
|
|
965
|
-
// ../../node_modules/.pnpm/eventsource-parser@3.1.0/node_modules/eventsource-parser/dist/index.js
|
|
966
|
-
var ParseError = class extends Error {
|
|
967
|
-
constructor(message, options) {
|
|
968
|
-
super(message), this.name = "ParseError", this.type = options.type, this.field = options.field, this.value = options.value, this.line = options.line;
|
|
969
|
-
}
|
|
970
|
-
};
|
|
971
|
-
var LF = 10;
|
|
972
|
-
var CR = 13;
|
|
973
|
-
var SPACE = 32;
|
|
974
|
-
function noop(_arg) {
|
|
975
|
-
}
|
|
976
|
-
function createParser(config) {
|
|
977
|
-
if (typeof config == "function")
|
|
978
|
-
throw new TypeError(
|
|
979
|
-
"`config` must be an object, got a function instead. Did you mean `createParser({onEvent: fn})`?"
|
|
980
|
-
);
|
|
981
|
-
const { onEvent = noop, onError = noop, onRetry = noop, onComment, maxBufferSize } = config, pendingFragments = [];
|
|
982
|
-
let pendingFragmentsLength = 0, isFirstChunk = true, id, data = "", dataLines = 0, eventType, terminated = false;
|
|
983
|
-
function feed(chunk) {
|
|
984
|
-
if (terminated)
|
|
985
|
-
throw new Error(
|
|
986
|
-
"Cannot feed parser: it was terminated after exceeding the configured max buffer size. Call `reset()` to resume parsing."
|
|
987
|
-
);
|
|
988
|
-
if (isFirstChunk && (isFirstChunk = false, chunk.charCodeAt(0) === 239 && chunk.charCodeAt(1) === 187 && chunk.charCodeAt(2) === 191 && (chunk = chunk.slice(3))), pendingFragments.length === 0) {
|
|
989
|
-
const trailing2 = processLines(chunk);
|
|
990
|
-
trailing2 !== "" && (pendingFragments.push(trailing2), pendingFragmentsLength = trailing2.length), checkBufferSize();
|
|
991
|
-
return;
|
|
992
|
-
}
|
|
993
|
-
if (chunk.indexOf(`
|
|
994
|
-
`) === -1 && chunk.indexOf("\r") === -1) {
|
|
995
|
-
pendingFragments.push(chunk), pendingFragmentsLength += chunk.length, checkBufferSize();
|
|
996
|
-
return;
|
|
997
|
-
}
|
|
998
|
-
pendingFragments.push(chunk);
|
|
999
|
-
const input = pendingFragments.join("");
|
|
1000
|
-
pendingFragments.length = 0, pendingFragmentsLength = 0;
|
|
1001
|
-
const trailing = processLines(input);
|
|
1002
|
-
trailing !== "" && (pendingFragments.push(trailing), pendingFragmentsLength = trailing.length), checkBufferSize();
|
|
1003
|
-
}
|
|
1004
|
-
function checkBufferSize() {
|
|
1005
|
-
maxBufferSize !== void 0 && (pendingFragmentsLength + data.length <= maxBufferSize || (terminated = true, pendingFragments.length = 0, pendingFragmentsLength = 0, id = void 0, data = "", dataLines = 0, eventType = void 0, onError(
|
|
1006
|
-
new ParseError(`Buffered data exceeded max buffer size of ${maxBufferSize} characters`, {
|
|
1007
|
-
type: "max-buffer-size-exceeded"
|
|
1008
|
-
})
|
|
1009
|
-
)));
|
|
1010
|
-
}
|
|
1011
|
-
function processLines(chunk) {
|
|
1012
|
-
let searchIndex = 0;
|
|
1013
|
-
if (chunk.indexOf("\r") === -1) {
|
|
1014
|
-
let lfIndex = chunk.indexOf(`
|
|
1015
|
-
`, searchIndex);
|
|
1016
|
-
for (; lfIndex !== -1; ) {
|
|
1017
|
-
if (searchIndex === lfIndex) {
|
|
1018
|
-
dataLines > 0 && onEvent({ id, event: eventType, data }), id = void 0, data = "", dataLines = 0, eventType = void 0, searchIndex = lfIndex + 1, lfIndex = chunk.indexOf(`
|
|
1019
|
-
`, searchIndex);
|
|
1020
|
-
continue;
|
|
1021
|
-
}
|
|
1022
|
-
const firstCharCode = chunk.charCodeAt(searchIndex);
|
|
1023
|
-
if (isDataPrefix(chunk, searchIndex, firstCharCode)) {
|
|
1024
|
-
const valueStart = chunk.charCodeAt(searchIndex + 5) === SPACE ? searchIndex + 6 : searchIndex + 5, value = chunk.slice(valueStart, lfIndex);
|
|
1025
|
-
if (dataLines === 0 && chunk.charCodeAt(lfIndex + 1) === LF) {
|
|
1026
|
-
onEvent({ id, event: eventType, data: value }), id = void 0, data = "", eventType = void 0, searchIndex = lfIndex + 2, lfIndex = chunk.indexOf(`
|
|
1027
|
-
`, searchIndex);
|
|
1028
|
-
continue;
|
|
1029
|
-
}
|
|
1030
|
-
data = dataLines === 0 ? value : `${data}
|
|
1031
|
-
${value}`, dataLines++;
|
|
1032
|
-
} else isEventPrefix(chunk, searchIndex, firstCharCode) ? eventType = chunk.slice(
|
|
1033
|
-
chunk.charCodeAt(searchIndex + 6) === SPACE ? searchIndex + 7 : searchIndex + 6,
|
|
1034
|
-
lfIndex
|
|
1035
|
-
) || void 0 : parseLine(chunk, searchIndex, lfIndex);
|
|
1036
|
-
searchIndex = lfIndex + 1, lfIndex = chunk.indexOf(`
|
|
1037
|
-
`, searchIndex);
|
|
1038
|
-
}
|
|
1039
|
-
return chunk.slice(searchIndex);
|
|
1040
|
-
}
|
|
1041
|
-
for (; searchIndex < chunk.length; ) {
|
|
1042
|
-
const crIndex = chunk.indexOf("\r", searchIndex), lfIndex = chunk.indexOf(`
|
|
1043
|
-
`, searchIndex);
|
|
1044
|
-
let lineEnd = -1;
|
|
1045
|
-
if (crIndex !== -1 && lfIndex !== -1 ? lineEnd = crIndex < lfIndex ? crIndex : lfIndex : crIndex !== -1 ? crIndex === chunk.length - 1 ? lineEnd = -1 : lineEnd = crIndex : lfIndex !== -1 && (lineEnd = lfIndex), lineEnd === -1)
|
|
1046
|
-
break;
|
|
1047
|
-
parseLine(chunk, searchIndex, lineEnd), searchIndex = lineEnd + 1, chunk.charCodeAt(searchIndex - 1) === CR && chunk.charCodeAt(searchIndex) === LF && searchIndex++;
|
|
1048
|
-
}
|
|
1049
|
-
return chunk.slice(searchIndex);
|
|
1050
|
-
}
|
|
1051
|
-
function parseLine(chunk, start, end) {
|
|
1052
|
-
if (start === end) {
|
|
1053
|
-
dispatchEvent();
|
|
1054
|
-
return;
|
|
1055
|
-
}
|
|
1056
|
-
const firstCharCode = chunk.charCodeAt(start);
|
|
1057
|
-
if (isDataPrefix(chunk, start, firstCharCode)) {
|
|
1058
|
-
const valueStart = chunk.charCodeAt(start + 5) === SPACE ? start + 6 : start + 5, value2 = chunk.slice(valueStart, end);
|
|
1059
|
-
data = dataLines === 0 ? value2 : `${data}
|
|
1060
|
-
${value2}`, dataLines++;
|
|
1061
|
-
return;
|
|
1062
|
-
}
|
|
1063
|
-
if (isEventPrefix(chunk, start, firstCharCode)) {
|
|
1064
|
-
eventType = chunk.slice(chunk.charCodeAt(start + 6) === SPACE ? start + 7 : start + 6, end) || void 0;
|
|
1065
|
-
return;
|
|
1066
|
-
}
|
|
1067
|
-
if (firstCharCode === 105 && chunk.charCodeAt(start + 1) === 100 && chunk.charCodeAt(start + 2) === 58) {
|
|
1068
|
-
const value2 = chunk.slice(chunk.charCodeAt(start + 3) === SPACE ? start + 4 : start + 3, end);
|
|
1069
|
-
id = value2.includes("\0") ? void 0 : value2;
|
|
1070
|
-
return;
|
|
1071
|
-
}
|
|
1072
|
-
if (firstCharCode === 58) {
|
|
1073
|
-
if (onComment) {
|
|
1074
|
-
const line2 = chunk.slice(start, end);
|
|
1075
|
-
onComment(line2.slice(chunk.charCodeAt(start + 1) === SPACE ? 2 : 1));
|
|
1076
|
-
}
|
|
1077
|
-
return;
|
|
1078
|
-
}
|
|
1079
|
-
const line = chunk.slice(start, end), fieldSeparatorIndex = line.indexOf(":");
|
|
1080
|
-
if (fieldSeparatorIndex === -1) {
|
|
1081
|
-
processField(line, "", line);
|
|
1082
|
-
return;
|
|
1083
|
-
}
|
|
1084
|
-
const field = line.slice(0, fieldSeparatorIndex), offset = line.charCodeAt(fieldSeparatorIndex + 1) === SPACE ? 2 : 1, value = line.slice(fieldSeparatorIndex + offset);
|
|
1085
|
-
processField(field, value, line);
|
|
1158
|
+
// src/client/request.ts
|
|
1159
|
+
var authHeaders = {};
|
|
1160
|
+
var loginGate = null;
|
|
1161
|
+
var setAuthHeaders = (h) => {
|
|
1162
|
+
authHeaders = h;
|
|
1163
|
+
};
|
|
1164
|
+
var setLoginGate = (p) => {
|
|
1165
|
+
loginGate = p;
|
|
1166
|
+
};
|
|
1167
|
+
var request = async (url, init2) => {
|
|
1168
|
+
if (loginGate) await loginGate;
|
|
1169
|
+
const baseHeaders = init2.body !== void 0 ? { "content-type": "application/json" } : {};
|
|
1170
|
+
const res = await fetch(url, {
|
|
1171
|
+
method: init2.method,
|
|
1172
|
+
headers: { ...baseHeaders, ...authHeaders, ...init2.headers ?? {} },
|
|
1173
|
+
...init2.body !== void 0 ? { body: JSON.stringify(init2.body) } : {}
|
|
1174
|
+
});
|
|
1175
|
+
if (!res.ok) throw new Error(`${init2.method} ${url} \u2192 ${res.status}: ${await res.text()}`);
|
|
1176
|
+
if (res.status === 204) return void 0;
|
|
1177
|
+
return await res.json();
|
|
1178
|
+
};
|
|
1179
|
+
|
|
1180
|
+
// src/client/auth.ts
|
|
1181
|
+
var primed = false;
|
|
1182
|
+
var primeLogin = (baseUrl) => {
|
|
1183
|
+
if (primed) return;
|
|
1184
|
+
primed = true;
|
|
1185
|
+
const token = process.env.BATON_TOKEN;
|
|
1186
|
+
if (token) {
|
|
1187
|
+
setAuthHeaders({ authorization: `Bearer ${token}` });
|
|
1188
|
+
return;
|
|
1086
1189
|
}
|
|
1087
|
-
|
|
1088
|
-
|
|
1089
|
-
|
|
1090
|
-
|
|
1091
|
-
|
|
1092
|
-
|
|
1093
|
-
|
|
1094
|
-
|
|
1095
|
-
|
|
1096
|
-
|
|
1097
|
-
|
|
1098
|
-
|
|
1099
|
-
|
|
1100
|
-
|
|
1101
|
-
|
|
1102
|
-
|
|
1103
|
-
|
|
1104
|
-
|
|
1105
|
-
|
|
1106
|
-
|
|
1107
|
-
|
|
1108
|
-
|
|
1109
|
-
|
|
1110
|
-
|
|
1111
|
-
|
|
1112
|
-
|
|
1113
|
-
|
|
1114
|
-
|
|
1115
|
-
|
|
1190
|
+
const username = process.env.BATON_USER;
|
|
1191
|
+
const password = process.env.BATON_PASS;
|
|
1192
|
+
if (!username || !password) return;
|
|
1193
|
+
setLoginGate(
|
|
1194
|
+
(async () => {
|
|
1195
|
+
const res = await fetch(`${baseUrl}/auth/login`, {
|
|
1196
|
+
method: "POST",
|
|
1197
|
+
headers: { "content-type": "application/json" },
|
|
1198
|
+
body: JSON.stringify({ username, password })
|
|
1199
|
+
});
|
|
1200
|
+
const cookie = (res.headers.getSetCookie()[0] ?? "").split(";")[0];
|
|
1201
|
+
if (res.ok && cookie) setAuthHeaders({ cookie });
|
|
1202
|
+
})().catch(() => {
|
|
1203
|
+
})
|
|
1204
|
+
);
|
|
1205
|
+
};
|
|
1206
|
+
|
|
1207
|
+
// src/client/projects.ts
|
|
1208
|
+
var projectClient = (baseUrl) => {
|
|
1209
|
+
const u = (p) => `${baseUrl}${p}`;
|
|
1210
|
+
return {
|
|
1211
|
+
create: (input) => request(u("/projects"), { method: "POST", body: input }),
|
|
1212
|
+
listByWorkspace: (workspaceId) => request(u(`/workspaces/${workspaceId}/projects`), { method: "GET" }),
|
|
1213
|
+
get: (id) => request(u(`/projects/${id}`), { method: "GET" }),
|
|
1214
|
+
update: (id, patch2) => request(u(`/projects/${id}`), { method: "PATCH", body: patch2 }),
|
|
1215
|
+
remove: (id) => request(u(`/projects/${id}`), { method: "DELETE" })
|
|
1216
|
+
};
|
|
1217
|
+
};
|
|
1218
|
+
|
|
1219
|
+
// src/client/items.ts
|
|
1220
|
+
var fetchItemByCode = async (baseUrl, projectId, code, expectKind) => {
|
|
1221
|
+
const r = await request(
|
|
1222
|
+
`${baseUrl}/projects/${projectId}/items/${encodeURIComponent(code)}`,
|
|
1223
|
+
{ method: "GET" }
|
|
1224
|
+
);
|
|
1225
|
+
if (r.kind !== expectKind) throw new Error(`expected ${expectKind} but got ${r.kind} for ${code}`);
|
|
1226
|
+
return r.item;
|
|
1227
|
+
};
|
|
1228
|
+
|
|
1229
|
+
// src/client/requirements.ts
|
|
1230
|
+
var requirementClient = (baseUrl) => {
|
|
1231
|
+
const u = (p) => `${baseUrl}${p}`;
|
|
1232
|
+
return {
|
|
1233
|
+
create: (input) => request(u("/requirements"), { method: "POST", body: input }),
|
|
1234
|
+
listByProject: (projectId) => request(u(`/projects/${projectId}/requirements`), { method: "GET" }),
|
|
1235
|
+
get: (id) => request(u(`/requirements/${id}`), { method: "GET" }),
|
|
1236
|
+
getByCode: (projectId, code) => fetchItemByCode(baseUrl, projectId, code, "requirement"),
|
|
1237
|
+
update: (id, patch2) => request(u(`/requirements/${id}`), { method: "PATCH", body: patch2 }),
|
|
1238
|
+
setStatus: (id, status) => request(u(`/requirements/${id}`), { method: "PATCH", body: { status } }),
|
|
1239
|
+
remove: (id) => request(u(`/requirements/${id}`), { method: "DELETE" })
|
|
1240
|
+
};
|
|
1241
|
+
};
|
|
1242
|
+
|
|
1243
|
+
// src/client/retry.ts
|
|
1244
|
+
var sleep = (ms) => new Promise((resolve2) => setTimeout(resolve2, ms));
|
|
1245
|
+
var withRetry = async (fn, opts = {}) => {
|
|
1246
|
+
const tries = Math.max(1, opts.tries ?? 4);
|
|
1247
|
+
const baseMs = opts.baseMs ?? 300;
|
|
1248
|
+
let lastErr;
|
|
1249
|
+
for (let i = 0; i < tries; i++) {
|
|
1250
|
+
try {
|
|
1251
|
+
return await fn();
|
|
1252
|
+
} catch (err) {
|
|
1253
|
+
lastErr = err;
|
|
1254
|
+
if (i === tries - 1) break;
|
|
1255
|
+
const backoff = baseMs * 2 ** i;
|
|
1256
|
+
await sleep(backoff + Math.random() * baseMs);
|
|
1116
1257
|
}
|
|
1117
1258
|
}
|
|
1118
|
-
|
|
1119
|
-
|
|
1120
|
-
|
|
1121
|
-
|
|
1122
|
-
|
|
1123
|
-
|
|
1124
|
-
|
|
1125
|
-
|
|
1126
|
-
|
|
1127
|
-
|
|
1128
|
-
|
|
1259
|
+
throw lastErr;
|
|
1260
|
+
};
|
|
1261
|
+
|
|
1262
|
+
// src/client/sessions.ts
|
|
1263
|
+
var sessionsClient = (baseUrl) => {
|
|
1264
|
+
const u = (p) => `${baseUrl}${p}`;
|
|
1265
|
+
return {
|
|
1266
|
+
create: (input) => request(u("/sessions"), { method: "POST", body: input }),
|
|
1267
|
+
materialize: (id, input, workerToken) => request(u(`/sessions/${id}`), {
|
|
1268
|
+
method: "PATCH",
|
|
1269
|
+
body: input,
|
|
1270
|
+
headers: { authorization: `Bearer ${workerToken}` }
|
|
1271
|
+
}),
|
|
1272
|
+
setStatus: (id, active, workerToken) => request(u(`/sessions/${id}/status`), {
|
|
1273
|
+
method: "POST",
|
|
1274
|
+
body: { active },
|
|
1275
|
+
headers: { authorization: `Bearer ${workerToken}` }
|
|
1276
|
+
}),
|
|
1277
|
+
setName: (id, name, workerToken) => request(u(`/sessions/${id}`), {
|
|
1278
|
+
method: "PATCH",
|
|
1279
|
+
body: { name },
|
|
1280
|
+
headers: { authorization: `Bearer ${workerToken}` }
|
|
1281
|
+
}),
|
|
1282
|
+
resume: (id) => request(u(`/sessions/${id}/resume`), { method: "POST" }),
|
|
1283
|
+
stop: (id) => request(u(`/sessions/${id}/stop`), { method: "POST" }),
|
|
1284
|
+
clear: (id) => request(u(`/sessions/${id}/clear`), { method: "POST" }),
|
|
1285
|
+
abort: (id) => request(u(`/sessions/${id}/abort`), { method: "POST" }),
|
|
1286
|
+
rename: (id, name) => request(u(`/sessions/${id}/rename`), { method: "POST", body: { name } }),
|
|
1287
|
+
listByProject: (projectId) => request(u(`/projects/${projectId}/sessions`), { method: "GET" }),
|
|
1288
|
+
get: (id) => request(u(`/sessions/${id}`), { method: "GET" }),
|
|
1289
|
+
findByName: async (projectId, name) => {
|
|
1290
|
+
const all = await request(u(`/projects/${projectId}/sessions`), { method: "GET" });
|
|
1291
|
+
const matches = all.filter((s) => s.name === name);
|
|
1292
|
+
return matches.length === 0 ? null : matches[matches.length - 1] ?? null;
|
|
1293
|
+
},
|
|
1294
|
+
sendMessage: (id, text, attachments, planMode) => request(u(`/sessions/${id}/messages`), {
|
|
1295
|
+
method: "POST",
|
|
1296
|
+
body: {
|
|
1297
|
+
text,
|
|
1298
|
+
...attachments && attachments.length > 0 ? { attachments } : {},
|
|
1299
|
+
...planMode ? { planMode: true } : {}
|
|
1300
|
+
}
|
|
1301
|
+
}),
|
|
1302
|
+
// Raw-body upload: the file streams as the request body (no multipart), so
|
|
1303
|
+
// a Blob backed by a file on disk uploads without buffering. filename rides
|
|
1304
|
+
// a query param; content-type carries the media type.
|
|
1305
|
+
uploadAttachment: async (id, input) => {
|
|
1306
|
+
const url = u(`/sessions/${id}/attachments?filename=${encodeURIComponent(input.filename)}`);
|
|
1307
|
+
const res = await fetch(url, {
|
|
1308
|
+
method: "POST",
|
|
1309
|
+
body: input.body,
|
|
1310
|
+
headers: { "content-type": input.contentType }
|
|
1311
|
+
});
|
|
1312
|
+
if (!res.ok) throw new Error(`POST ${url} \u2192 ${res.status}: ${await res.text()}`);
|
|
1313
|
+
return await res.json();
|
|
1314
|
+
},
|
|
1315
|
+
destroy: async (id) => {
|
|
1316
|
+
await request(u(`/sessions/${id}`), { method: "DELETE" });
|
|
1129
1317
|
}
|
|
1130
|
-
|
|
1131
|
-
|
|
1132
|
-
return { feed, reset };
|
|
1133
|
-
}
|
|
1134
|
-
function isDataPrefix(chunk, i, firstCharCode) {
|
|
1135
|
-
return firstCharCode === 100 && chunk.charCodeAt(i + 1) === 97 && chunk.charCodeAt(i + 2) === 116 && chunk.charCodeAt(i + 3) === 97 && chunk.charCodeAt(i + 4) === 58;
|
|
1136
|
-
}
|
|
1137
|
-
function isEventPrefix(chunk, i, firstCharCode) {
|
|
1138
|
-
return firstCharCode === 101 && chunk.charCodeAt(i + 1) === 118 && chunk.charCodeAt(i + 2) === 101 && chunk.charCodeAt(i + 3) === 110 && chunk.charCodeAt(i + 4) === 116 && chunk.charCodeAt(i + 5) === 58;
|
|
1139
|
-
}
|
|
1318
|
+
};
|
|
1319
|
+
};
|
|
1140
1320
|
|
|
1141
|
-
//
|
|
1142
|
-
var
|
|
1143
|
-
|
|
1144
|
-
|
|
1145
|
-
|
|
1146
|
-
|
|
1147
|
-
|
|
1148
|
-
|
|
1149
|
-
|
|
1150
|
-
|
|
1151
|
-
|
|
1152
|
-
|
|
1153
|
-
|
|
1154
|
-
|
|
1155
|
-
|
|
1156
|
-
|
|
1157
|
-
|
|
1158
|
-
|
|
1159
|
-
|
|
1160
|
-
|
|
1161
|
-
|
|
1162
|
-
|
|
1163
|
-
|
|
1164
|
-
|
|
1165
|
-
|
|
1166
|
-
|
|
1167
|
-
|
|
1168
|
-
|
|
1169
|
-
|
|
1170
|
-
|
|
1171
|
-
|
|
1172
|
-
|
|
1173
|
-
|
|
1174
|
-
|
|
1175
|
-
|
|
1176
|
-
* @param inspect - The inspect function to use (prevents having to import it from `util`)
|
|
1177
|
-
* @param options - The options passed to `Deno.inspect`
|
|
1178
|
-
* @returns A string representation of the error
|
|
1179
|
-
*/
|
|
1180
|
-
[/* @__PURE__ */ Symbol.for("Deno.customInspect")](inspect, options) {
|
|
1181
|
-
return inspect(inspectableError(this), options);
|
|
1182
|
-
}
|
|
1321
|
+
// src/client/tasks.ts
|
|
1322
|
+
var taskClient = (baseUrl) => {
|
|
1323
|
+
const u = (p) => `${baseUrl}${p}`;
|
|
1324
|
+
return {
|
|
1325
|
+
create: (input) => request(u("/tasks"), { method: "POST", body: input }),
|
|
1326
|
+
listByRequirement: (requirementId) => request(u(`/requirements/${requirementId}/tasks`), { method: "GET" }),
|
|
1327
|
+
get: (id) => request(u(`/tasks/${id}`), { method: "GET" }),
|
|
1328
|
+
getByCode: (projectId, code) => fetchItemByCode(baseUrl, projectId, code, "task"),
|
|
1329
|
+
update: (id, patch2) => request(u(`/tasks/${id}`), { method: "PATCH", body: patch2 }),
|
|
1330
|
+
setStatus: (id, status) => request(u(`/tasks/${id}`), { method: "PATCH", body: { status } }),
|
|
1331
|
+
remove: (id) => request(u(`/tasks/${id}`), { method: "DELETE" }),
|
|
1332
|
+
listComments: (id) => request(u(`/tasks/${id}/comments`), { method: "GET" }),
|
|
1333
|
+
addComment: (id, body, workerId) => request(u(`/tasks/${id}/comments`), { method: "POST", body: { body, workerId } })
|
|
1334
|
+
};
|
|
1335
|
+
};
|
|
1336
|
+
|
|
1337
|
+
// src/client/workers.ts
|
|
1338
|
+
var workersClient = (baseUrl) => {
|
|
1339
|
+
const u = (p) => `${baseUrl}${p}`;
|
|
1340
|
+
return {
|
|
1341
|
+
register: (input) => request(u("/workers"), { method: "POST", body: input }),
|
|
1342
|
+
listByProject: (projectId) => request(u(`/projects/${projectId}/workers`), { method: "GET" }),
|
|
1343
|
+
get: (id) => request(u(`/workers/${id}`), { method: "GET" }),
|
|
1344
|
+
findByName: async (projectId, name) => {
|
|
1345
|
+
const all = await request(u(`/projects/${projectId}/workers`), {
|
|
1346
|
+
method: "GET"
|
|
1347
|
+
});
|
|
1348
|
+
const matches = all.filter((w) => w.name === name);
|
|
1349
|
+
return matches.length === 0 ? null : matches[matches.length - 1] ?? null;
|
|
1350
|
+
},
|
|
1351
|
+
heartbeat: (machineId) => request(u("/workers/heartbeat"), { method: "POST", body: { machineId } }),
|
|
1352
|
+
destroy: async (id) => {
|
|
1353
|
+
await request(u(`/workers/${id}`), { method: "DELETE" });
|
|
1354
|
+
}
|
|
1355
|
+
};
|
|
1183
1356
|
};
|
|
1184
|
-
|
|
1185
|
-
|
|
1186
|
-
|
|
1187
|
-
}
|
|
1188
|
-
function flattenError(err) {
|
|
1189
|
-
return err instanceof Error ? "errors" in err && Array.isArray(err.errors) ? err.errors.map(flattenError).join(", ") : "cause" in err && err.cause instanceof Error ? `${err}: ${flattenError(err.cause)}` : err.message : `${err}`;
|
|
1190
|
-
}
|
|
1191
|
-
function inspectableError(err) {
|
|
1357
|
+
|
|
1358
|
+
// src/client/workspaces.ts
|
|
1359
|
+
var workspaceClient = (baseUrl) => {
|
|
1360
|
+
const u = (p) => `${baseUrl}${p}`;
|
|
1192
1361
|
return {
|
|
1193
|
-
|
|
1194
|
-
|
|
1195
|
-
|
|
1196
|
-
|
|
1197
|
-
|
|
1198
|
-
timeStamp: err.timeStamp
|
|
1362
|
+
create: (input) => request(u("/workspaces"), { method: "POST", body: input }),
|
|
1363
|
+
list: () => request(u("/workspaces"), { method: "GET" }),
|
|
1364
|
+
get: (id) => request(u(`/workspaces/${id}`), { method: "GET" }),
|
|
1365
|
+
update: (id, patch2) => request(u(`/workspaces/${id}`), { method: "PATCH", body: patch2 }),
|
|
1366
|
+
remove: (id) => request(u(`/workspaces/${id}`), { method: "DELETE" })
|
|
1199
1367
|
};
|
|
1200
|
-
}
|
|
1201
|
-
var __typeError = (msg) => {
|
|
1202
|
-
throw TypeError(msg);
|
|
1203
1368
|
};
|
|
1204
|
-
|
|
1205
|
-
|
|
1206
|
-
var
|
|
1207
|
-
|
|
1208
|
-
|
|
1209
|
-
|
|
1210
|
-
|
|
1211
|
-
var
|
|
1212
|
-
|
|
1213
|
-
|
|
1214
|
-
|
|
1215
|
-
|
|
1216
|
-
|
|
1217
|
-
|
|
1218
|
-
|
|
1219
|
-
var
|
|
1220
|
-
|
|
1221
|
-
|
|
1222
|
-
|
|
1223
|
-
|
|
1224
|
-
var
|
|
1225
|
-
var
|
|
1226
|
-
|
|
1227
|
-
|
|
1228
|
-
|
|
1229
|
-
|
|
1230
|
-
|
|
1231
|
-
|
|
1232
|
-
|
|
1233
|
-
|
|
1234
|
-
var _a, _b;
|
|
1235
|
-
super(), __privateAdd(this, _EventSource_instances), this.CONNECTING = 0, this.OPEN = 1, this.CLOSED = 2, __privateAdd(this, _readyState), __privateAdd(this, _url), __privateAdd(this, _redirectUrl), __privateAdd(this, _withCredentials), __privateAdd(this, _fetch), __privateAdd(this, _reconnectInterval), __privateAdd(this, _reconnectTimer), __privateAdd(this, _lastEventId, null), __privateAdd(this, _controller), __privateAdd(this, _parser), __privateAdd(this, _onError, null), __privateAdd(this, _onMessage, null), __privateAdd(this, _onOpen, null), __privateAdd(this, _onFetchResponse, async (response) => {
|
|
1236
|
-
var _a2;
|
|
1237
|
-
__privateGet(this, _parser).reset();
|
|
1238
|
-
const { body, redirected, status, headers } = response;
|
|
1239
|
-
if (status === 204) {
|
|
1240
|
-
__privateMethod(this, _EventSource_instances, failConnection_fn).call(this, "Server sent HTTP 204, not reconnecting", 204), this.close();
|
|
1241
|
-
return;
|
|
1242
|
-
}
|
|
1243
|
-
if (redirected ? __privateSet(this, _redirectUrl, new URL(response.url)) : __privateSet(this, _redirectUrl, void 0), status !== 200) {
|
|
1244
|
-
__privateMethod(this, _EventSource_instances, failConnection_fn).call(this, `Non-200 status code (${status})`, status);
|
|
1245
|
-
return;
|
|
1246
|
-
}
|
|
1247
|
-
if (!(headers.get("content-type") || "").startsWith("text/event-stream")) {
|
|
1248
|
-
__privateMethod(this, _EventSource_instances, failConnection_fn).call(this, 'Invalid content type, expected "text/event-stream"', status);
|
|
1249
|
-
return;
|
|
1250
|
-
}
|
|
1251
|
-
if (__privateGet(this, _readyState) === this.CLOSED)
|
|
1252
|
-
return;
|
|
1253
|
-
__privateSet(this, _readyState, this.OPEN);
|
|
1254
|
-
const openEvent = new Event("open");
|
|
1255
|
-
if ((_a2 = __privateGet(this, _onOpen)) == null || _a2.call(this, openEvent), this.dispatchEvent(openEvent), typeof body != "object" || !body || !("getReader" in body)) {
|
|
1256
|
-
__privateMethod(this, _EventSource_instances, failConnection_fn).call(this, "Invalid response body, expected a web ReadableStream", status), this.close();
|
|
1257
|
-
return;
|
|
1258
|
-
}
|
|
1259
|
-
const decoder = new TextDecoder(), reader = body.getReader();
|
|
1260
|
-
let open = true;
|
|
1261
|
-
do {
|
|
1262
|
-
const { done, value } = await reader.read();
|
|
1263
|
-
value && __privateGet(this, _parser).feed(decoder.decode(value, { stream: !done })), done && (open = false, __privateGet(this, _parser).reset(), __privateMethod(this, _EventSource_instances, scheduleReconnect_fn).call(this));
|
|
1264
|
-
} while (open);
|
|
1265
|
-
}), __privateAdd(this, _onFetchError, (err) => {
|
|
1266
|
-
__privateSet(this, _controller, void 0), !(err.name === "AbortError" || err.type === "aborted") && __privateMethod(this, _EventSource_instances, scheduleReconnect_fn).call(this, flattenError(err));
|
|
1267
|
-
}), __privateAdd(this, _onEvent, (event) => {
|
|
1268
|
-
typeof event.id == "string" && __privateSet(this, _lastEventId, event.id);
|
|
1269
|
-
const messageEvent = new MessageEvent(event.event || "message", {
|
|
1270
|
-
data: event.data,
|
|
1271
|
-
origin: __privateGet(this, _redirectUrl) ? __privateGet(this, _redirectUrl).origin : __privateGet(this, _url).origin,
|
|
1272
|
-
lastEventId: event.id || ""
|
|
1369
|
+
|
|
1370
|
+
// src/client.ts
|
|
1371
|
+
var createClient = (baseUrl, opts) => {
|
|
1372
|
+
if (opts?.bearer) setAuthHeaders({ authorization: `Bearer ${opts.bearer}` });
|
|
1373
|
+
else primeLogin(baseUrl);
|
|
1374
|
+
return clientFromBase(baseUrl);
|
|
1375
|
+
};
|
|
1376
|
+
var clientFromBase = (baseUrl) => ({
|
|
1377
|
+
workspaces: workspaceClient(baseUrl),
|
|
1378
|
+
projects: projectClient(baseUrl),
|
|
1379
|
+
requirements: requirementClient(baseUrl),
|
|
1380
|
+
tasks: taskClient(baseUrl),
|
|
1381
|
+
sessions: sessionsClient(baseUrl),
|
|
1382
|
+
workers: workersClient(baseUrl)
|
|
1383
|
+
});
|
|
1384
|
+
var BOUNDARY_EVENTS = /* @__PURE__ */ new Set([
|
|
1385
|
+
"turn_start",
|
|
1386
|
+
"turn_complete",
|
|
1387
|
+
"turn_error"
|
|
1388
|
+
]);
|
|
1389
|
+
var emitRetries = () => Number(process.env.BATON_EMIT_RETRIES) || 4;
|
|
1390
|
+
var createWorkerClient = (baseUrl, workerToken, sessionId) => {
|
|
1391
|
+
const u = (p) => `${baseUrl}${p}`;
|
|
1392
|
+
const auth = { authorization: `Bearer ${workerToken}` };
|
|
1393
|
+
return {
|
|
1394
|
+
emitEvent: (type, payload) => {
|
|
1395
|
+
const post = () => request(u(`/sessions/${sessionId}/events`), {
|
|
1396
|
+
method: "POST",
|
|
1397
|
+
body: { type, payload },
|
|
1398
|
+
headers: auth
|
|
1273
1399
|
});
|
|
1274
|
-
|
|
1275
|
-
}
|
|
1276
|
-
|
|
1277
|
-
|
|
1278
|
-
|
|
1279
|
-
|
|
1280
|
-
|
|
1281
|
-
|
|
1282
|
-
|
|
1283
|
-
|
|
1284
|
-
|
|
1285
|
-
|
|
1286
|
-
|
|
1287
|
-
|
|
1288
|
-
|
|
1400
|
+
return BOUNDARY_EVENTS.has(type) ? withRetry(post, { tries: emitRetries() }) : post();
|
|
1401
|
+
},
|
|
1402
|
+
setActive: (active) => request(u(`/sessions/${sessionId}/status`), {
|
|
1403
|
+
method: "POST",
|
|
1404
|
+
body: { active },
|
|
1405
|
+
headers: auth
|
|
1406
|
+
}),
|
|
1407
|
+
listEvents: () => request(u(`/sessions/${sessionId}/events`), { method: "GET", headers: auth })
|
|
1408
|
+
};
|
|
1409
|
+
};
|
|
1410
|
+
|
|
1411
|
+
// src/util.ts
|
|
1412
|
+
var common = {
|
|
1413
|
+
url: {
|
|
1414
|
+
type: "string",
|
|
1415
|
+
description: "baton server url (--url > .baton.json > BATON_URL > http://localhost:3280)"
|
|
1416
|
+
},
|
|
1417
|
+
json: { type: "boolean", description: "output JSON" }
|
|
1418
|
+
};
|
|
1419
|
+
var resolveAuth = (env, fileToken) => {
|
|
1420
|
+
const envBearer = env.BATON_TOKEN ?? env.BATON_WORKER_TOKEN;
|
|
1421
|
+
if (envBearer) return { bearer: envBearer };
|
|
1422
|
+
if (env.BATON_USER && env.BATON_PASS) return "cookie";
|
|
1423
|
+
return fileToken ? { bearer: fileToken } : void 0;
|
|
1424
|
+
};
|
|
1425
|
+
var clientFor = (args) => {
|
|
1426
|
+
const baseUrl = resolveBaseUrl(args.url);
|
|
1427
|
+
const fileToken = loadProjectConfigOrNull(projectConfigPath())?.worker?.apiToken;
|
|
1428
|
+
const auth = resolveAuth(process.env, fileToken);
|
|
1429
|
+
return createClient(baseUrl, auth && auth !== "cookie" ? auth : void 0);
|
|
1430
|
+
};
|
|
1431
|
+
var resolveProjectId = (args) => {
|
|
1432
|
+
if (args.project !== void 0 && args.project !== "") return Number(args.project);
|
|
1433
|
+
const cfg = loadProjectConfigOrNull(projectConfigPath());
|
|
1434
|
+
if (cfg?.project !== void 0) return cfg.project;
|
|
1435
|
+
throw new Error("no project in scope. pass --project <id> or run `baton init` in this directory.");
|
|
1436
|
+
};
|
|
1437
|
+
var resolveWorkspaceId = (args) => {
|
|
1438
|
+
if (args.workspace !== void 0 && args.workspace !== "") return Number(args.workspace);
|
|
1439
|
+
const cfg = loadProjectConfigOrNull(projectConfigPath());
|
|
1440
|
+
if (cfg?.workspace !== void 0) return cfg.workspace;
|
|
1441
|
+
throw new Error(
|
|
1442
|
+
"no workspace in scope. pass --workspace <id> or run `baton init` in this directory."
|
|
1443
|
+
);
|
|
1444
|
+
};
|
|
1445
|
+
var parseWorkerHandle = (handle) => {
|
|
1446
|
+
const m = handle.trim().match(/^(?:[wW]-)?(\d+)$/);
|
|
1447
|
+
return m ? Number(m[1]) : null;
|
|
1448
|
+
};
|
|
1449
|
+
var splitCsv = (s) => s ? s.split(",").map((x) => x.trim()).filter(Boolean) : void 0;
|
|
1450
|
+
|
|
1451
|
+
// src/commands/channel/close.ts
|
|
1452
|
+
var closeCommand = defineCommand({
|
|
1453
|
+
meta: { name: "close", description: "delete a channel (removes the room and all its messages)" },
|
|
1454
|
+
args: {
|
|
1455
|
+
channel: { type: "positional", required: true, description: "channel id" },
|
|
1456
|
+
token: { type: "string", required: true, description: "channel token" },
|
|
1457
|
+
...common
|
|
1458
|
+
},
|
|
1459
|
+
run: async ({ args }) => {
|
|
1460
|
+
await channelClient(resolveBaseUrl(args.url)).destroy(args.channel, args.token);
|
|
1461
|
+
console.log(args.json ? toJson({ ok: true, deleted: args.channel }) : `closed ${args.channel}`);
|
|
1462
|
+
}
|
|
1463
|
+
});
|
|
1464
|
+
|
|
1465
|
+
// src/commands/channel/shared.ts
|
|
1466
|
+
var readStdin = async () => {
|
|
1467
|
+
const chunks = [];
|
|
1468
|
+
for await (const c of process.stdin) chunks.push(c);
|
|
1469
|
+
return Buffer.concat(chunks).toString("utf8");
|
|
1470
|
+
};
|
|
1471
|
+
var renderRoster = (members) => members.length ? members.map((m) => ` ${m.name} (${m.kind})`).join("\n") : " (nobody online)";
|
|
1472
|
+
var webLink = (url, channelId, token) => {
|
|
1473
|
+
const origin = url.replace(/\/api\/?$/, "");
|
|
1474
|
+
return origin === url ? null : `${origin}/channel/${channelId}#token=${token}`;
|
|
1475
|
+
};
|
|
1476
|
+
var inviteBlock = (url, channelId, token) => {
|
|
1477
|
+
const web = webLink(url, channelId, token);
|
|
1478
|
+
return [
|
|
1479
|
+
"\u2500\u2500 Share this to invite anyone into the room \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500",
|
|
1480
|
+
...web ? [`Humans \u2014 open in a browser: ${web}`, ""] : [],
|
|
1481
|
+
"Agents \u2014 two curl steps:",
|
|
1482
|
+
` 1) see the room: curl -sS -H "authorization: Bearer ${token}" "${url}/channels/${channelId}"`,
|
|
1483
|
+
` 2) read protocol: curl -sS "${url}/channels/help" (then join / listen / send, pick your own NAME)`,
|
|
1484
|
+
"",
|
|
1485
|
+
`connection: url=${url} channel=${channelId} token=${token}`,
|
|
1486
|
+
"\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500"
|
|
1487
|
+
].join("\n");
|
|
1488
|
+
};
|
|
1489
|
+
|
|
1490
|
+
// src/commands/channel/create.ts
|
|
1491
|
+
var createCommand = defineCommand({
|
|
1492
|
+
meta: { name: "create", description: "open a channel (chat room) and print an invite" },
|
|
1493
|
+
args: {
|
|
1494
|
+
name: { type: "string", description: "room title (optional)" },
|
|
1495
|
+
desc: { type: "string", description: "room self-description: purpose / topic / how to participate" },
|
|
1496
|
+
...common
|
|
1497
|
+
},
|
|
1498
|
+
run: async ({ args }) => {
|
|
1499
|
+
const url = resolveBaseUrl(args.url);
|
|
1500
|
+
const { channelId, token } = await channelClient(url).create(args.name, args.desc);
|
|
1501
|
+
if (args.json) {
|
|
1502
|
+
console.log(toJson({ channelId, token, url, name: args.name, description: args.desc }));
|
|
1503
|
+
return;
|
|
1289
1504
|
}
|
|
1290
|
-
|
|
1291
|
-
|
|
1292
|
-
|
|
1293
|
-
})), __privateSet(this, _readyState, this.CONNECTING), __privateSet(this, _reconnectInterval, 3e3), __privateSet(this, _fetch, (_a = eventSourceInitDict == null ? void 0 : eventSourceInitDict.fetch) != null ? _a : globalThis.fetch), __privateSet(this, _withCredentials, (_b = eventSourceInitDict == null ? void 0 : eventSourceInitDict.withCredentials) != null ? _b : false), __privateMethod(this, _EventSource_instances, connect_fn).call(this);
|
|
1505
|
+
console.log(`channel ${channelId} opened
|
|
1506
|
+
`);
|
|
1507
|
+
console.log(inviteBlock(url, channelId, token));
|
|
1294
1508
|
}
|
|
1295
|
-
|
|
1296
|
-
|
|
1297
|
-
|
|
1298
|
-
|
|
1299
|
-
|
|
1300
|
-
|
|
1301
|
-
|
|
1302
|
-
|
|
1303
|
-
|
|
1304
|
-
|
|
1305
|
-
|
|
1306
|
-
|
|
1509
|
+
});
|
|
1510
|
+
|
|
1511
|
+
// src/commands/channel/download.ts
|
|
1512
|
+
import { writeFileSync as writeFileSync2 } from "node:fs";
|
|
1513
|
+
var downloadCommand = defineCommand({
|
|
1514
|
+
meta: { name: "download", description: "download a channel attachment to a file" },
|
|
1515
|
+
args: {
|
|
1516
|
+
channel: { type: "positional", required: true, description: "channel id" },
|
|
1517
|
+
att: { type: "positional", required: true, description: "attachment id (from a message ref)" },
|
|
1518
|
+
token: { type: "string", required: true, description: "channel token" },
|
|
1519
|
+
out: { type: "string", alias: "o", description: "output file path (default: ./<attId>)" },
|
|
1520
|
+
...common
|
|
1521
|
+
},
|
|
1522
|
+
run: async ({ args }) => {
|
|
1523
|
+
const url = resolveBaseUrl(args.url);
|
|
1524
|
+
const res = await channelClient(url).downloadAttachment(args.channel, args.token, args.att);
|
|
1525
|
+
const out = args.out ?? args.att;
|
|
1526
|
+
writeFileSync2(out, Buffer.from(await res.arrayBuffer()));
|
|
1527
|
+
console.log(`saved \u2192 ${out}`);
|
|
1528
|
+
}
|
|
1529
|
+
});
|
|
1530
|
+
|
|
1531
|
+
// src/commands/channel/info.ts
|
|
1532
|
+
var aboutCommand = defineCommand({
|
|
1533
|
+
meta: { name: "about", description: "show a channel's manifest (description + online roster)" },
|
|
1534
|
+
args: {
|
|
1535
|
+
channel: { type: "positional", required: true, description: "channel id" },
|
|
1536
|
+
token: { type: "string", required: true, description: "channel token" },
|
|
1537
|
+
...common
|
|
1538
|
+
},
|
|
1539
|
+
run: async ({ args }) => {
|
|
1540
|
+
const url = resolveBaseUrl(args.url);
|
|
1541
|
+
const m = await channelClient(url).manifest(args.channel, args.token);
|
|
1542
|
+
if (args.json) {
|
|
1543
|
+
console.log(toJson(m));
|
|
1544
|
+
return;
|
|
1545
|
+
}
|
|
1546
|
+
console.log(`${m.title ?? "(untitled)"} [${m.id}]`);
|
|
1547
|
+
if (m.description) console.log(m.description);
|
|
1548
|
+
console.log(`
|
|
1549
|
+
online (${m.members.length}):
|
|
1550
|
+
${renderRoster(m.members)}`);
|
|
1551
|
+
console.log(`
|
|
1552
|
+
protocol: curl -sS "${url}${m.help}"`);
|
|
1307
1553
|
}
|
|
1308
|
-
|
|
1309
|
-
|
|
1310
|
-
|
|
1311
|
-
|
|
1312
|
-
|
|
1313
|
-
|
|
1314
|
-
*/
|
|
1315
|
-
get url() {
|
|
1316
|
-
return __privateGet(this, _url).href;
|
|
1554
|
+
});
|
|
1555
|
+
var helpCommand = defineCommand({
|
|
1556
|
+
meta: { name: "help", description: "print the channel protocol doc (no token needed)" },
|
|
1557
|
+
args: { ...common },
|
|
1558
|
+
run: async ({ args }) => {
|
|
1559
|
+
console.log(await channelClient(resolveBaseUrl(args.url)).help());
|
|
1317
1560
|
}
|
|
1318
|
-
|
|
1319
|
-
|
|
1320
|
-
|
|
1321
|
-
|
|
1322
|
-
|
|
1323
|
-
|
|
1324
|
-
|
|
1561
|
+
});
|
|
1562
|
+
var membersCommand = defineCommand({
|
|
1563
|
+
meta: { name: "members", description: "list the channel's online roster" },
|
|
1564
|
+
args: {
|
|
1565
|
+
channel: { type: "positional", required: true, description: "channel id" },
|
|
1566
|
+
token: { type: "string", required: true, description: "channel token" },
|
|
1567
|
+
...common
|
|
1568
|
+
},
|
|
1569
|
+
run: async ({ args }) => {
|
|
1570
|
+
const url = resolveBaseUrl(args.url);
|
|
1571
|
+
const members = await channelClient(url).members(args.channel, args.token);
|
|
1572
|
+
console.log(args.json ? toJson(members) : renderRoster(members));
|
|
1325
1573
|
}
|
|
1326
|
-
|
|
1327
|
-
|
|
1328
|
-
|
|
1574
|
+
});
|
|
1575
|
+
var updateCommand = defineCommand({
|
|
1576
|
+
meta: { name: "update", description: "update a channel's title / description (topic + rules)" },
|
|
1577
|
+
args: {
|
|
1578
|
+
channel: { type: "positional", required: true, description: "channel id" },
|
|
1579
|
+
token: { type: "string", required: true, description: "channel token" },
|
|
1580
|
+
title: { type: "string", description: "new title" },
|
|
1581
|
+
desc: { type: "string", description: "new description (purpose / topic / rules)" },
|
|
1582
|
+
...common
|
|
1583
|
+
},
|
|
1584
|
+
run: async ({ args }) => {
|
|
1585
|
+
if (args.title === void 0 && args.desc === void 0)
|
|
1586
|
+
throw new Error("nothing to update: pass --title and/or --desc");
|
|
1587
|
+
const url = resolveBaseUrl(args.url);
|
|
1588
|
+
const ch = await channelClient(url).update(args.channel, args.token, {
|
|
1589
|
+
title: args.title,
|
|
1590
|
+
description: args.desc
|
|
1591
|
+
});
|
|
1592
|
+
console.log(args.json ? toJson(ch) : `updated ${ch.id}${ch.title ? ` \u2014 ${ch.title}` : ""}`);
|
|
1329
1593
|
}
|
|
1330
|
-
|
|
1331
|
-
|
|
1594
|
+
});
|
|
1595
|
+
|
|
1596
|
+
// src/commands/channel/listen.ts
|
|
1597
|
+
import { mkdirSync, writeFileSync as writeFileSync3 } from "node:fs";
|
|
1598
|
+
import { tmpdir } from "node:os";
|
|
1599
|
+
import { join as join2 } from "node:path";
|
|
1600
|
+
|
|
1601
|
+
// ../shared/src/domain/attachment.ts
|
|
1602
|
+
var isImageAttachment = (att) => att.contentType.startsWith("image/");
|
|
1603
|
+
var labelAttachments = (attachments) => {
|
|
1604
|
+
const counters = { image: 0, file: 0 };
|
|
1605
|
+
return attachments.map((att) => {
|
|
1606
|
+
const kind = isImageAttachment(att) ? "image" : "file";
|
|
1607
|
+
counters[kind] += 1;
|
|
1608
|
+
return `${kind}-${counters[kind]}`;
|
|
1609
|
+
});
|
|
1610
|
+
};
|
|
1611
|
+
|
|
1612
|
+
// ../shared/src/domain/channel.ts
|
|
1613
|
+
var isMessageFor = (msg, name) => !msg.to || msg.to.length === 0 || msg.to.includes(name);
|
|
1614
|
+
|
|
1615
|
+
// ../shared/src/domain/session-event.ts
|
|
1616
|
+
var startedMessageIds = (events) => {
|
|
1617
|
+
const ids = /* @__PURE__ */ new Set();
|
|
1618
|
+
for (const e of events) {
|
|
1619
|
+
if (e.type !== "turn_start") continue;
|
|
1620
|
+
const id = e.payload?.messageId;
|
|
1621
|
+
if (typeof id === "number") ids.add(id);
|
|
1332
1622
|
}
|
|
1333
|
-
|
|
1334
|
-
|
|
1335
|
-
|
|
1623
|
+
return ids;
|
|
1624
|
+
};
|
|
1625
|
+
var unstartedUserMessages = (events) => {
|
|
1626
|
+
const started = startedMessageIds(events);
|
|
1627
|
+
return events.filter((e) => e.type === "user_message" && !started.has(e.id));
|
|
1628
|
+
};
|
|
1629
|
+
var opensTurn = (e) => e.type === "user_message" || e.type === "turn_start";
|
|
1630
|
+
var closesTurn = (e) => e.type === "turn_complete" || e.type === "turn_error";
|
|
1631
|
+
var isAgentWorking = (events) => {
|
|
1632
|
+
const last = events.findLast((e) => opensTurn(e) || closesTurn(e));
|
|
1633
|
+
return last ? opensTurn(last) : false;
|
|
1634
|
+
};
|
|
1635
|
+
|
|
1636
|
+
// src/commands/channel/listen.ts
|
|
1637
|
+
var PREVIEW = 280;
|
|
1638
|
+
var describe = (e) => {
|
|
1639
|
+
const ev = e;
|
|
1640
|
+
return ev?.code ? `${ev.code}${ev.message ? ` ${ev.message}` : ""}` : String(e);
|
|
1641
|
+
};
|
|
1642
|
+
var runListen = async (o) => {
|
|
1643
|
+
const emit = (x) => {
|
|
1644
|
+
process.stdout.write(`${JSON.stringify(x)}
|
|
1645
|
+
`);
|
|
1646
|
+
};
|
|
1647
|
+
const spillDir = join2(tmpdir(), "channel", o.channel);
|
|
1648
|
+
mkdirSync(spillDir, { recursive: true });
|
|
1649
|
+
const surface = (m) => {
|
|
1650
|
+
const text = typeof m.text === "string" ? m.text : "";
|
|
1651
|
+
const file = join2(spillDir, `${m.seq}.txt`);
|
|
1652
|
+
writeFileSync3(file, text);
|
|
1653
|
+
const truncated = text.length > PREVIEW;
|
|
1654
|
+
emit({
|
|
1655
|
+
type: "channel.message",
|
|
1656
|
+
seq: m.seq,
|
|
1657
|
+
from: m.from,
|
|
1658
|
+
senderKind: m.senderKind,
|
|
1659
|
+
to: m.to,
|
|
1660
|
+
mine: o.from ? isMessageFor(m, o.from) : void 0,
|
|
1661
|
+
ts: m.ts,
|
|
1662
|
+
chars: text.length,
|
|
1663
|
+
truncated,
|
|
1664
|
+
preview: truncated ? `${text.slice(0, PREVIEW)} \u2026` : text,
|
|
1665
|
+
// BASE-prefixed urls so the subscribing agent can fetch directly.
|
|
1666
|
+
attachments: m.attachments?.length ? m.attachments.map((a) => ({
|
|
1667
|
+
filename: a.filename,
|
|
1668
|
+
contentType: a.contentType,
|
|
1669
|
+
size: a.size,
|
|
1670
|
+
url: `${o.url}${a.url}`
|
|
1671
|
+
})) : void 0,
|
|
1672
|
+
file
|
|
1673
|
+
});
|
|
1674
|
+
};
|
|
1675
|
+
const close = channelClient(o.url).listen(o.channel, o.token, {
|
|
1676
|
+
since: o.since,
|
|
1677
|
+
for: o.for,
|
|
1678
|
+
as: o.from,
|
|
1679
|
+
// Skip our own messages (they echo back over the same channel).
|
|
1680
|
+
onMessage: (m) => {
|
|
1681
|
+
if (m.from !== o.from) surface(m);
|
|
1682
|
+
},
|
|
1683
|
+
onError: (e) => emit({ type: "channel.error", error: describe(e) })
|
|
1684
|
+
});
|
|
1685
|
+
emit({ type: "channel.listening", channel: o.channel, from: o.from, url: o.url });
|
|
1686
|
+
await new Promise((resolve2) => {
|
|
1687
|
+
const stop = () => {
|
|
1688
|
+
close();
|
|
1689
|
+
resolve2();
|
|
1690
|
+
};
|
|
1691
|
+
process.on("SIGINT", stop);
|
|
1692
|
+
process.on("SIGTERM", stop);
|
|
1693
|
+
});
|
|
1694
|
+
};
|
|
1695
|
+
var listenCommand = defineCommand({
|
|
1696
|
+
meta: {
|
|
1697
|
+
name: "listen",
|
|
1698
|
+
description: "stream a channel: one JSON line per message (for a background subscriber)"
|
|
1699
|
+
},
|
|
1700
|
+
args: {
|
|
1701
|
+
channel: { type: "positional", required: true, description: "channel id" },
|
|
1702
|
+
token: { type: "string", required: true, description: "channel token" },
|
|
1703
|
+
from: { type: "string", description: "your name; your own messages skipped, presence kept fresh" },
|
|
1704
|
+
since: { type: "string", description: "replay messages after this seq (default 0 = full)" },
|
|
1705
|
+
for: { type: "string", description: "only broadcasts + messages addressed to this name" },
|
|
1706
|
+
...common
|
|
1707
|
+
},
|
|
1708
|
+
run: async ({ args }) => {
|
|
1709
|
+
await runListen({
|
|
1710
|
+
url: resolveBaseUrl(args.url),
|
|
1711
|
+
channel: args.channel,
|
|
1712
|
+
token: args.token,
|
|
1713
|
+
from: args.from ?? "",
|
|
1714
|
+
since: args.since ? Number(args.since) : 0,
|
|
1715
|
+
for: args.for
|
|
1716
|
+
});
|
|
1336
1717
|
}
|
|
1337
|
-
|
|
1338
|
-
|
|
1718
|
+
});
|
|
1719
|
+
|
|
1720
|
+
// src/commands/channel/join.ts
|
|
1721
|
+
var joinCommand = defineCommand({
|
|
1722
|
+
meta: { name: "join", description: "join a channel (register presence); --listen to also stream" },
|
|
1723
|
+
args: {
|
|
1724
|
+
channel: { type: "positional", required: true, description: "channel id" },
|
|
1725
|
+
token: { type: "string", required: true, description: "channel token" },
|
|
1726
|
+
from: { type: "string", required: true, description: "your participant name" },
|
|
1727
|
+
kind: { type: "string", description: "your kind: agent (default) | human" },
|
|
1728
|
+
listen: { type: "boolean", description: "after joining, stream messages (background subscriber)" },
|
|
1729
|
+
since: { type: "string", description: "with --listen: replay after this seq (default 0)" },
|
|
1730
|
+
...common
|
|
1731
|
+
},
|
|
1732
|
+
run: async ({ args }) => {
|
|
1733
|
+
const url = resolveBaseUrl(args.url);
|
|
1734
|
+
const kind = args.kind === "human" ? "human" : "agent";
|
|
1735
|
+
const members = await channelClient(url).join(args.channel, args.token, args.from, kind);
|
|
1736
|
+
if (!args.listen) {
|
|
1737
|
+
if (args.json) console.log(toJson({ joined: args.from, members }));
|
|
1738
|
+
else console.log(`joined as ${args.from} (${members.length} online)
|
|
1739
|
+
${renderRoster(members)}`);
|
|
1740
|
+
return;
|
|
1741
|
+
}
|
|
1742
|
+
await runListen({
|
|
1743
|
+
url,
|
|
1744
|
+
channel: args.channel,
|
|
1745
|
+
token: args.token,
|
|
1746
|
+
from: args.from,
|
|
1747
|
+
since: args.since ? Number(args.since) : 0
|
|
1748
|
+
});
|
|
1339
1749
|
}
|
|
1340
|
-
|
|
1341
|
-
|
|
1342
|
-
|
|
1750
|
+
});
|
|
1751
|
+
|
|
1752
|
+
// src/commands/channel/read.ts
|
|
1753
|
+
var fmtMessage = (m, base) => {
|
|
1754
|
+
const head = `${m.seq} ${m.from} ${m.text}`;
|
|
1755
|
+
const atts = (m.attachments ?? []).map((a) => `
|
|
1756
|
+
\u{1F4CE} ${a.filename} \u2192 ${base}${a.url}`).join("");
|
|
1757
|
+
return head + atts;
|
|
1758
|
+
};
|
|
1759
|
+
var readCommand = defineCommand({
|
|
1760
|
+
meta: { name: "read", description: "poll channel messages once (curl-style, since a cursor)" },
|
|
1761
|
+
args: {
|
|
1762
|
+
channel: { type: "positional", required: true, description: "channel id" },
|
|
1763
|
+
token: { type: "string", required: true, description: "channel token" },
|
|
1764
|
+
since: { type: "string", description: "only messages after this seq (default 0)" },
|
|
1765
|
+
from: { type: "string", description: "skip messages from this name (no echo)" },
|
|
1766
|
+
for: { type: "string", description: "only broadcasts + messages addressed to this name" },
|
|
1767
|
+
...common
|
|
1768
|
+
},
|
|
1769
|
+
run: async ({ args }) => {
|
|
1770
|
+
const url = resolveBaseUrl(args.url);
|
|
1771
|
+
const msgs = await channelClient(url).read(args.channel, args.token, {
|
|
1772
|
+
since: args.since ? Number(args.since) : 0,
|
|
1773
|
+
for: args.for
|
|
1774
|
+
});
|
|
1775
|
+
const out = args.from ? msgs.filter((m) => m.from !== args.from) : msgs;
|
|
1776
|
+
if (args.json) console.log(toJson(out));
|
|
1777
|
+
else console.log(out.length ? out.map((m) => fmtMessage(m, url)).join("\n") : "(none)");
|
|
1343
1778
|
}
|
|
1344
|
-
|
|
1345
|
-
|
|
1779
|
+
});
|
|
1780
|
+
|
|
1781
|
+
// src/commands/channel/send.ts
|
|
1782
|
+
import { openAsBlob as openAsBlob2, readFileSync as readFileSync2 } from "node:fs";
|
|
1783
|
+
import { basename as basename2 } from "node:path";
|
|
1784
|
+
|
|
1785
|
+
// src/mime.ts
|
|
1786
|
+
import { extname } from "node:path";
|
|
1787
|
+
var BY_EXT = {
|
|
1788
|
+
".png": "image/png",
|
|
1789
|
+
".jpg": "image/jpeg",
|
|
1790
|
+
".jpeg": "image/jpeg",
|
|
1791
|
+
".gif": "image/gif",
|
|
1792
|
+
".webp": "image/webp",
|
|
1793
|
+
".svg": "image/svg+xml",
|
|
1794
|
+
".pdf": "application/pdf",
|
|
1795
|
+
".txt": "text/plain",
|
|
1796
|
+
".md": "text/markdown",
|
|
1797
|
+
".json": "application/json",
|
|
1798
|
+
".csv": "text/csv"
|
|
1799
|
+
};
|
|
1800
|
+
var contentTypeForPath = (path) => BY_EXT[extname(path).toLowerCase()] ?? "application/octet-stream";
|
|
1801
|
+
|
|
1802
|
+
// src/commands/attach.ts
|
|
1803
|
+
import { openAsBlob } from "node:fs";
|
|
1804
|
+
import { basename } from "node:path";
|
|
1805
|
+
var attachPaths = (raw) => (raw === void 0 ? [] : Array.isArray(raw) ? raw : [raw]).flatMap((p) => p.split(",")).map((p) => p.trim()).filter(Boolean);
|
|
1806
|
+
var uploadAttachments = async (client, sessionId, paths) => {
|
|
1807
|
+
const out = [];
|
|
1808
|
+
for (const path of paths) {
|
|
1809
|
+
const body = await openAsBlob(path, { type: contentTypeForPath(path) });
|
|
1810
|
+
out.push(
|
|
1811
|
+
await client.sessions.uploadAttachment(sessionId, {
|
|
1812
|
+
filename: basename(path),
|
|
1813
|
+
contentType: contentTypeForPath(path),
|
|
1814
|
+
body
|
|
1815
|
+
})
|
|
1816
|
+
);
|
|
1346
1817
|
}
|
|
1347
|
-
|
|
1348
|
-
|
|
1349
|
-
|
|
1818
|
+
return out;
|
|
1819
|
+
};
|
|
1820
|
+
|
|
1821
|
+
// src/commands/channel/send.ts
|
|
1822
|
+
var sendCommand = defineCommand({
|
|
1823
|
+
meta: { name: "send", description: "post one message to a channel" },
|
|
1824
|
+
args: {
|
|
1825
|
+
channel: { type: "positional", required: true, description: "channel id" },
|
|
1826
|
+
text: { type: "positional", required: false, description: "message text (short one-liner)" },
|
|
1827
|
+
token: { type: "string", required: true, description: "channel token" },
|
|
1828
|
+
from: { type: "string", description: "your participant name (default: peer)" },
|
|
1829
|
+
to: { type: "string", description: "direct it at these names (comma-separated); omit = broadcast" },
|
|
1830
|
+
file: { type: "string", description: "read message body from this file (for large content)" },
|
|
1831
|
+
attach: { type: "string", description: "attach file(s) (comma-separated paths); uploaded + carried on the message" },
|
|
1832
|
+
...common
|
|
1833
|
+
},
|
|
1834
|
+
run: async ({ args }) => {
|
|
1835
|
+
const url = resolveBaseUrl(args.url);
|
|
1836
|
+
const client = channelClient(url);
|
|
1837
|
+
let text = args.text;
|
|
1838
|
+
if (text === void 0 && args.file) text = readFileSync2(args.file, "utf8");
|
|
1839
|
+
if (text === void 0 && !process.stdin.isTTY) text = await readStdin();
|
|
1840
|
+
const attachments = [];
|
|
1841
|
+
for (const path of attachPaths(args.attach)) {
|
|
1842
|
+
attachments.push(
|
|
1843
|
+
await client.uploadAttachment(args.channel, args.token, {
|
|
1844
|
+
filename: basename2(path),
|
|
1845
|
+
contentType: contentTypeForPath(path),
|
|
1846
|
+
body: await openAsBlob2(path, { type: contentTypeForPath(path) })
|
|
1847
|
+
})
|
|
1848
|
+
);
|
|
1849
|
+
}
|
|
1850
|
+
if (!text && attachments.length === 0)
|
|
1851
|
+
throw new Error("nothing to send: provide text, --file <path>, --attach <file>, or pipe stdin");
|
|
1852
|
+
const msg = await client.send(args.channel, args.token, {
|
|
1853
|
+
from: args.from ?? "peer",
|
|
1854
|
+
text: text ?? "",
|
|
1855
|
+
to: splitCsv(args.to),
|
|
1856
|
+
attachments: attachments.length ? attachments : void 0
|
|
1857
|
+
});
|
|
1858
|
+
if (args.json) console.log(toJson(msg));
|
|
1859
|
+
else console.log(`sent (seq ${msg.seq})`);
|
|
1350
1860
|
}
|
|
1351
|
-
|
|
1352
|
-
|
|
1353
|
-
|
|
1861
|
+
});
|
|
1862
|
+
|
|
1863
|
+
// src/commands/channel.ts
|
|
1864
|
+
var channel = defineCommand({
|
|
1865
|
+
meta: {
|
|
1866
|
+
name: "channel",
|
|
1867
|
+
description: "multi-agent chat room: create / about / update / help / join / members / send / read / listen / download / close"
|
|
1868
|
+
},
|
|
1869
|
+
subCommands: {
|
|
1870
|
+
create: createCommand,
|
|
1871
|
+
about: aboutCommand,
|
|
1872
|
+
update: updateCommand,
|
|
1873
|
+
help: helpCommand,
|
|
1874
|
+
join: joinCommand,
|
|
1875
|
+
members: membersCommand,
|
|
1876
|
+
send: sendCommand,
|
|
1877
|
+
read: readCommand,
|
|
1878
|
+
listen: listenCommand,
|
|
1879
|
+
download: downloadCommand,
|
|
1880
|
+
close: closeCommand
|
|
1881
|
+
}
|
|
1882
|
+
});
|
|
1883
|
+
|
|
1884
|
+
// src/commands/init.ts
|
|
1885
|
+
import { existsSync as existsSync2 } from "node:fs";
|
|
1886
|
+
import * as readline from "node:readline/promises";
|
|
1887
|
+
var promptPick = async (label, items) => {
|
|
1888
|
+
if (items.length === 0) throw new Error(`no ${label}s found on server`);
|
|
1889
|
+
console.log(`${label}s:`);
|
|
1890
|
+
items.forEach((it, i) => {
|
|
1891
|
+
console.log(` [${i + 1}] #${it.id} ${it.name}`);
|
|
1892
|
+
});
|
|
1893
|
+
const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
|
|
1894
|
+
try {
|
|
1895
|
+
const ans = (await rl.question(`pick a ${label} (1-${items.length}): `)).trim();
|
|
1896
|
+
const idx = Number(ans) - 1;
|
|
1897
|
+
const picked = items[idx];
|
|
1898
|
+
if (!picked) throw new Error(`invalid choice: ${ans}`);
|
|
1899
|
+
return picked;
|
|
1900
|
+
} finally {
|
|
1901
|
+
rl.close();
|
|
1902
|
+
}
|
|
1903
|
+
};
|
|
1904
|
+
var init = defineCommand({
|
|
1905
|
+
meta: {
|
|
1906
|
+
name: "init",
|
|
1907
|
+
description: `write ${PROJECT_CONFIG_NAME} in the current directory (local state, gitignored)`
|
|
1908
|
+
},
|
|
1909
|
+
args: {
|
|
1910
|
+
workspace: { type: "string", description: "workspace id (skip prompt)" },
|
|
1911
|
+
project: { type: "string", description: "project id (skip prompt)" },
|
|
1912
|
+
force: { type: "boolean", description: `overwrite existing ${PROJECT_CONFIG_NAME}` },
|
|
1913
|
+
...common
|
|
1914
|
+
},
|
|
1915
|
+
run: async ({ args }) => {
|
|
1916
|
+
const server = resolveBaseUrl(args.url);
|
|
1917
|
+
const cfgPath = projectConfigPath();
|
|
1918
|
+
if (existsSync2(cfgPath) && !args.force)
|
|
1919
|
+
throw new Error(`${PROJECT_CONFIG_NAME} already exists. use --force to overwrite.`);
|
|
1920
|
+
const c = createClient(server);
|
|
1921
|
+
let project2;
|
|
1922
|
+
let workspace2;
|
|
1923
|
+
if (args.project) {
|
|
1924
|
+
project2 = await c.projects.get(Number(args.project));
|
|
1925
|
+
workspace2 = await c.workspaces.get(project2.workspaceId);
|
|
1926
|
+
} else {
|
|
1927
|
+
const wsList = await c.workspaces.list();
|
|
1928
|
+
workspace2 = args.workspace ? wsList.find((w) => w.id === Number(args.workspace)) ?? (() => {
|
|
1929
|
+
throw new Error(`workspace ${args.workspace} not found`);
|
|
1930
|
+
})() : await promptPick("workspace", wsList);
|
|
1931
|
+
const projects = await c.projects.listByWorkspace(workspace2.id);
|
|
1932
|
+
project2 = await promptPick("project", projects);
|
|
1933
|
+
}
|
|
1934
|
+
const cfg = {
|
|
1935
|
+
server,
|
|
1936
|
+
workspace: workspace2.id,
|
|
1937
|
+
project: project2.id,
|
|
1938
|
+
name: project2.name
|
|
1939
|
+
};
|
|
1940
|
+
saveProjectConfig(cfgPath, cfg);
|
|
1941
|
+
console.log(`wrote ${cfgPath}`);
|
|
1942
|
+
console.log(` server: ${server}`);
|
|
1943
|
+
console.log(` workspace: #${workspace2.id} ${workspace2.name}`);
|
|
1944
|
+
console.log(` project: #${project2.id} ${project2.name}`);
|
|
1354
1945
|
}
|
|
1355
|
-
|
|
1356
|
-
|
|
1357
|
-
|
|
1358
|
-
|
|
1359
|
-
|
|
1360
|
-
|
|
1361
|
-
|
|
1362
|
-
|
|
1363
|
-
|
|
1946
|
+
});
|
|
1947
|
+
|
|
1948
|
+
// src/commands/project.ts
|
|
1949
|
+
var createProject = (c, input, json) => c.projects.create(input).then((p) => renderOne(p, fmtProject, json));
|
|
1950
|
+
var listProjects = (c, workspaceId, json) => c.projects.listByWorkspace(workspaceId).then((ps) => renderList(ps, fmtProject, json));
|
|
1951
|
+
var getProject = (c, id, json) => c.projects.get(id).then((p) => renderOne(p, fmtProject, json));
|
|
1952
|
+
var updateProject = (c, id, patch2, json) => c.projects.update(id, patch2).then((p) => renderOne(p, fmtProject, json));
|
|
1953
|
+
var removeProject = (c, id, json) => c.projects.remove(id).then(() => removed("project", id, json));
|
|
1954
|
+
var project = defineCommand({
|
|
1955
|
+
meta: { name: "project", description: "manage projects" },
|
|
1956
|
+
subCommands: {
|
|
1957
|
+
create: defineCommand({
|
|
1958
|
+
meta: { name: "create", description: "create a project" },
|
|
1959
|
+
args: {
|
|
1960
|
+
name: { type: "positional", required: true },
|
|
1961
|
+
workspace: { type: "string", description: "workspace id (overrides .baton.json)" },
|
|
1962
|
+
desc: { type: "string", description: "description" },
|
|
1963
|
+
...common
|
|
1964
|
+
},
|
|
1965
|
+
run: async ({ args }) => {
|
|
1966
|
+
const out = await createProject(
|
|
1967
|
+
clientFor(args),
|
|
1968
|
+
{ workspaceId: resolveWorkspaceId(args), name: args.name, description: args.desc },
|
|
1969
|
+
Boolean(args.json)
|
|
1970
|
+
);
|
|
1971
|
+
console.log(out);
|
|
1972
|
+
}
|
|
1973
|
+
}),
|
|
1974
|
+
ls: defineCommand({
|
|
1975
|
+
meta: { name: "ls", description: "list projects in a workspace" },
|
|
1976
|
+
args: {
|
|
1977
|
+
workspace: { type: "string", description: "workspace id (overrides .baton.json)" },
|
|
1978
|
+
...common
|
|
1979
|
+
},
|
|
1980
|
+
run: async ({ args }) => {
|
|
1981
|
+
console.log(
|
|
1982
|
+
await listProjects(clientFor(args), resolveWorkspaceId(args), Boolean(args.json))
|
|
1983
|
+
);
|
|
1984
|
+
}
|
|
1985
|
+
}),
|
|
1986
|
+
get: defineCommand({
|
|
1987
|
+
meta: { name: "get", description: "get a project" },
|
|
1988
|
+
args: { id: { type: "positional", required: true }, ...common },
|
|
1989
|
+
run: async ({ args }) => {
|
|
1990
|
+
console.log(await getProject(clientFor(args), Number(args.id), Boolean(args.json)));
|
|
1991
|
+
}
|
|
1992
|
+
}),
|
|
1993
|
+
update: defineCommand({
|
|
1994
|
+
meta: { name: "update", description: "rename a project / set its description" },
|
|
1995
|
+
args: {
|
|
1996
|
+
id: { type: "positional", required: true },
|
|
1997
|
+
name: { type: "string", description: "new name" },
|
|
1998
|
+
desc: { type: "string", description: "new description" },
|
|
1999
|
+
...common
|
|
2000
|
+
},
|
|
2001
|
+
run: async ({ args }) => {
|
|
2002
|
+
const patch2 = {
|
|
2003
|
+
...args.name !== void 0 ? { name: args.name } : {},
|
|
2004
|
+
...args.desc !== void 0 ? { description: args.desc } : {}
|
|
2005
|
+
};
|
|
2006
|
+
if (Object.keys(patch2).length === 0) throw new Error("pass --name and/or --desc");
|
|
2007
|
+
console.log(
|
|
2008
|
+
await updateProject(clientFor(args), Number(args.id), patch2, Boolean(args.json))
|
|
2009
|
+
);
|
|
2010
|
+
}
|
|
2011
|
+
}),
|
|
2012
|
+
rm: defineCommand({
|
|
2013
|
+
meta: { name: "rm", description: "delete a project" },
|
|
2014
|
+
args: { id: { type: "positional", required: true }, ...common },
|
|
2015
|
+
run: async ({ args }) => {
|
|
2016
|
+
console.log(await removeProject(clientFor(args), Number(args.id), Boolean(args.json)));
|
|
2017
|
+
}
|
|
2018
|
+
})
|
|
1364
2019
|
}
|
|
1365
|
-
};
|
|
1366
|
-
_readyState = /* @__PURE__ */ new WeakMap(), _url = /* @__PURE__ */ new WeakMap(), _redirectUrl = /* @__PURE__ */ new WeakMap(), _withCredentials = /* @__PURE__ */ new WeakMap(), _fetch = /* @__PURE__ */ new WeakMap(), _reconnectInterval = /* @__PURE__ */ new WeakMap(), _reconnectTimer = /* @__PURE__ */ new WeakMap(), _lastEventId = /* @__PURE__ */ new WeakMap(), _controller = /* @__PURE__ */ new WeakMap(), _parser = /* @__PURE__ */ new WeakMap(), _onError = /* @__PURE__ */ new WeakMap(), _onMessage = /* @__PURE__ */ new WeakMap(), _onOpen = /* @__PURE__ */ new WeakMap(), _EventSource_instances = /* @__PURE__ */ new WeakSet(), /**
|
|
1367
|
-
* Connect to the given URL and start receiving events
|
|
1368
|
-
*
|
|
1369
|
-
* @internal
|
|
1370
|
-
*/
|
|
1371
|
-
connect_fn = function() {
|
|
1372
|
-
__privateSet(this, _readyState, this.CONNECTING), __privateSet(this, _controller, new AbortController()), __privateGet(this, _fetch)(__privateGet(this, _url), __privateMethod(this, _EventSource_instances, getRequestOptions_fn).call(this)).then(__privateGet(this, _onFetchResponse)).catch(__privateGet(this, _onFetchError));
|
|
1373
|
-
}, _onFetchResponse = /* @__PURE__ */ new WeakMap(), _onFetchError = /* @__PURE__ */ new WeakMap(), /**
|
|
1374
|
-
* Get request options for the `fetch()` request
|
|
1375
|
-
*
|
|
1376
|
-
* @returns The request options
|
|
1377
|
-
* @internal
|
|
1378
|
-
*/
|
|
1379
|
-
getRequestOptions_fn = function() {
|
|
1380
|
-
var _a;
|
|
1381
|
-
const init2 = {
|
|
1382
|
-
// [spec] Let `corsAttributeState` be `Anonymous`…
|
|
1383
|
-
// [spec] …will have their mode set to "cors"…
|
|
1384
|
-
mode: "cors",
|
|
1385
|
-
redirect: "follow",
|
|
1386
|
-
headers: { Accept: "text/event-stream", ...__privateGet(this, _lastEventId) ? { "Last-Event-ID": __privateGet(this, _lastEventId) } : void 0 },
|
|
1387
|
-
cache: "no-store",
|
|
1388
|
-
signal: (_a = __privateGet(this, _controller)) == null ? void 0 : _a.signal
|
|
1389
|
-
};
|
|
1390
|
-
return "window" in globalThis && (init2.credentials = this.withCredentials ? "include" : "same-origin"), init2;
|
|
1391
|
-
}, _onEvent = /* @__PURE__ */ new WeakMap(), _onRetryChange = /* @__PURE__ */ new WeakMap(), /**
|
|
1392
|
-
* Handles the process referred to in the EventSource specification as "failing a connection".
|
|
1393
|
-
*
|
|
1394
|
-
* @param error - The error causing the connection to fail
|
|
1395
|
-
* @param code - The HTTP status code, if available
|
|
1396
|
-
* @internal
|
|
1397
|
-
*/
|
|
1398
|
-
failConnection_fn = function(message, code) {
|
|
1399
|
-
var _a;
|
|
1400
|
-
__privateGet(this, _readyState) !== this.CLOSED && __privateSet(this, _readyState, this.CLOSED);
|
|
1401
|
-
const errorEvent = new ErrorEvent("error", { code, message });
|
|
1402
|
-
(_a = __privateGet(this, _onError)) == null || _a.call(this, errorEvent), this.dispatchEvent(errorEvent);
|
|
1403
|
-
}, /**
|
|
1404
|
-
* Schedules a reconnection attempt against the EventSource endpoint.
|
|
1405
|
-
*
|
|
1406
|
-
* @param message - The error causing the connection to fail
|
|
1407
|
-
* @param code - The HTTP status code, if available
|
|
1408
|
-
* @internal
|
|
1409
|
-
*/
|
|
1410
|
-
scheduleReconnect_fn = function(message, code) {
|
|
1411
|
-
var _a;
|
|
1412
|
-
if (__privateGet(this, _readyState) === this.CLOSED)
|
|
1413
|
-
return;
|
|
1414
|
-
__privateSet(this, _readyState, this.CONNECTING);
|
|
1415
|
-
const errorEvent = new ErrorEvent("error", { code, message });
|
|
1416
|
-
(_a = __privateGet(this, _onError)) == null || _a.call(this, errorEvent), this.dispatchEvent(errorEvent), __privateSet(this, _reconnectTimer, setTimeout(__privateGet(this, _reconnect), __privateGet(this, _reconnectInterval)));
|
|
1417
|
-
}, _reconnect = /* @__PURE__ */ new WeakMap(), /**
|
|
1418
|
-
* ReadyState representing an EventSource currently trying to connect
|
|
1419
|
-
*
|
|
1420
|
-
* @public
|
|
1421
|
-
*/
|
|
1422
|
-
EventSource.CONNECTING = 0, /**
|
|
1423
|
-
* ReadyState representing an EventSource connection that is open (eg connected)
|
|
1424
|
-
*
|
|
1425
|
-
* @public
|
|
1426
|
-
*/
|
|
1427
|
-
EventSource.OPEN = 1, /**
|
|
1428
|
-
* ReadyState representing an EventSource connection that is closed (eg disconnected)
|
|
1429
|
-
*
|
|
1430
|
-
* @public
|
|
1431
|
-
*/
|
|
1432
|
-
EventSource.CLOSED = 2;
|
|
1433
|
-
Object.defineProperty(EventSource, /* @__PURE__ */ Symbol.for("eventsource.supports-fetch-override"), {
|
|
1434
|
-
value: true,
|
|
1435
|
-
writable: false,
|
|
1436
|
-
configurable: false,
|
|
1437
|
-
enumerable: false
|
|
1438
2020
|
});
|
|
1439
|
-
|
|
1440
|
-
|
|
1441
|
-
|
|
1442
|
-
}
|
|
2021
|
+
|
|
2022
|
+
// src/commands/relay.ts
|
|
2023
|
+
import { mkdirSync as mkdirSync2, readFileSync as readFileSync3, writeFileSync as writeFileSync4 } from "node:fs";
|
|
2024
|
+
import { tmpdir as tmpdir2 } from "node:os";
|
|
2025
|
+
import { join as join3 } from "node:path";
|
|
1443
2026
|
|
|
1444
2027
|
// src/client/relay.ts
|
|
1445
2028
|
var relayClient = (baseUrl) => {
|
|
@@ -1485,13 +2068,13 @@ var relayClient = (baseUrl) => {
|
|
|
1485
2068
|
};
|
|
1486
2069
|
|
|
1487
2070
|
// src/commands/relay.ts
|
|
1488
|
-
var
|
|
1489
|
-
var
|
|
2071
|
+
var PREVIEW2 = 280;
|
|
2072
|
+
var readStdin2 = async () => {
|
|
1490
2073
|
const chunks = [];
|
|
1491
2074
|
for await (const c of process.stdin) chunks.push(c);
|
|
1492
2075
|
return Buffer.concat(chunks).toString("utf8");
|
|
1493
2076
|
};
|
|
1494
|
-
var
|
|
2077
|
+
var inviteBlock2 = (url, channelId, token) => [
|
|
1495
2078
|
"\u2500\u2500 Copy everything below to your peer \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500",
|
|
1496
2079
|
"You're invited to a live Claude\u2194Claude channel. Use the `hotline` skill in",
|
|
1497
2080
|
"join mode, or run these two commands directly (pick your own NAME):",
|
|
@@ -1517,10 +2100,10 @@ var hostCommand = defineCommand({
|
|
|
1517
2100
|
}
|
|
1518
2101
|
console.log(`channel ${channelId} opened
|
|
1519
2102
|
`);
|
|
1520
|
-
console.log(
|
|
2103
|
+
console.log(inviteBlock2(url, channelId, token));
|
|
1521
2104
|
}
|
|
1522
2105
|
});
|
|
1523
|
-
var
|
|
2106
|
+
var sendCommand2 = defineCommand({
|
|
1524
2107
|
meta: { name: "send", description: "post one message to a relay channel" },
|
|
1525
2108
|
args: {
|
|
1526
2109
|
channel: { type: "positional", required: true, description: "channel id" },
|
|
@@ -1533,8 +2116,8 @@ var sendCommand = defineCommand({
|
|
|
1533
2116
|
run: async ({ args }) => {
|
|
1534
2117
|
const url = resolveBaseUrl(args.url);
|
|
1535
2118
|
let text = args.text;
|
|
1536
|
-
if (text === void 0 && args.file) text =
|
|
1537
|
-
if (text === void 0 && !process.stdin.isTTY) text = await
|
|
2119
|
+
if (text === void 0 && args.file) text = readFileSync3(args.file, "utf8");
|
|
2120
|
+
if (text === void 0 && !process.stdin.isTTY) text = await readStdin2();
|
|
1538
2121
|
if (text === void 0 || text === "")
|
|
1539
2122
|
throw new Error("nothing to send: provide text, --file <path>, or pipe stdin");
|
|
1540
2123
|
const msg = await relayClient(url).send(args.channel, args.token, {
|
|
@@ -1545,7 +2128,7 @@ var sendCommand = defineCommand({
|
|
|
1545
2128
|
else console.log(`sent (seq ${msg.seq})`);
|
|
1546
2129
|
}
|
|
1547
2130
|
});
|
|
1548
|
-
var
|
|
2131
|
+
var listenCommand2 = defineCommand({
|
|
1549
2132
|
meta: {
|
|
1550
2133
|
name: "listen",
|
|
1551
2134
|
description: "stream a channel: one JSON line per peer message (for a background subscriber)"
|
|
@@ -1567,13 +2150,13 @@ var listenCommand = defineCommand({
|
|
|
1567
2150
|
process.stdout.write(`${JSON.stringify(o)}
|
|
1568
2151
|
`);
|
|
1569
2152
|
};
|
|
1570
|
-
const spillDir =
|
|
1571
|
-
|
|
2153
|
+
const spillDir = join3(tmpdir2(), "hotline", args.channel);
|
|
2154
|
+
mkdirSync2(spillDir, { recursive: true });
|
|
1572
2155
|
const surface = (m) => {
|
|
1573
2156
|
const text = typeof m.text === "string" ? m.text : "";
|
|
1574
|
-
const file =
|
|
1575
|
-
|
|
1576
|
-
const truncated = text.length >
|
|
2157
|
+
const file = join3(spillDir, `${m.seq}.txt`);
|
|
2158
|
+
writeFileSync4(file, text);
|
|
2159
|
+
const truncated = text.length > PREVIEW2;
|
|
1577
2160
|
emit({
|
|
1578
2161
|
type: "relay.message",
|
|
1579
2162
|
seq: m.seq,
|
|
@@ -1581,11 +2164,11 @@ var listenCommand = defineCommand({
|
|
|
1581
2164
|
ts: m.ts,
|
|
1582
2165
|
chars: text.length,
|
|
1583
2166
|
truncated,
|
|
1584
|
-
preview: truncated ? `${text.slice(0,
|
|
2167
|
+
preview: truncated ? `${text.slice(0, PREVIEW2)} \u2026` : text,
|
|
1585
2168
|
file
|
|
1586
2169
|
});
|
|
1587
2170
|
};
|
|
1588
|
-
const
|
|
2171
|
+
const describe2 = (e) => {
|
|
1589
2172
|
const ev = e;
|
|
1590
2173
|
return ev?.code ? `${ev.code}${ev.message ? ` ${ev.message}` : ""}` : String(e);
|
|
1591
2174
|
};
|
|
@@ -1595,7 +2178,7 @@ var listenCommand = defineCommand({
|
|
|
1595
2178
|
onMessage: (m) => {
|
|
1596
2179
|
if (m.from !== me) surface(m);
|
|
1597
2180
|
},
|
|
1598
|
-
onError: (e) => emit({ type: "relay.error", error:
|
|
2181
|
+
onError: (e) => emit({ type: "relay.error", error: describe2(e) })
|
|
1599
2182
|
});
|
|
1600
2183
|
emit({ type: "relay.listening", channel: args.channel, from: me, url });
|
|
1601
2184
|
await new Promise((resolve2) => {
|
|
@@ -1610,7 +2193,7 @@ var listenCommand = defineCommand({
|
|
|
1610
2193
|
});
|
|
1611
2194
|
var relay = defineCommand({
|
|
1612
2195
|
meta: { name: "relay", description: "Claude\u2194Claude live channel: host / listen / send" },
|
|
1613
|
-
subCommands: { host: hostCommand, listen:
|
|
2196
|
+
subCommands: { host: hostCommand, listen: listenCommand2, send: sendCommand2 }
|
|
1614
2197
|
});
|
|
1615
2198
|
|
|
1616
2199
|
// src/commands/requirement.ts
|
|
@@ -1727,8 +2310,8 @@ var requirement = defineCommand({
|
|
|
1727
2310
|
|
|
1728
2311
|
// src/commands/session/shared.ts
|
|
1729
2312
|
import { homedir } from "node:os";
|
|
1730
|
-
import { join as
|
|
1731
|
-
var defaultWorktreeDir = (env = process.env) => env.BATON_WORKTREE_DIR ??
|
|
2313
|
+
import { join as join4 } from "node:path";
|
|
2314
|
+
var defaultWorktreeDir = (env = process.env) => env.BATON_WORKTREE_DIR ?? join4(env.XDG_DATA_HOME ?? join4(env.HOME ?? homedir(), ".local/share"), "baton", "worktrees");
|
|
1732
2315
|
var slug = (s) => s.toLowerCase().replace(/[^a-z0-9_-]+/g, "-");
|
|
1733
2316
|
var resolveSession = async (client, projectId, handle) => {
|
|
1734
2317
|
const asInt = Number(handle);
|
|
@@ -1897,32 +2480,6 @@ var sessionRmCommand = defineCommand({
|
|
|
1897
2480
|
import { spawnSync } from "node:child_process";
|
|
1898
2481
|
import { query } from "@anthropic-ai/claude-agent-sdk";
|
|
1899
2482
|
|
|
1900
|
-
// ../shared/src/domain/attachment.ts
|
|
1901
|
-
var isImageAttachment = (att) => att.contentType.startsWith("image/");
|
|
1902
|
-
var labelAttachments = (attachments) => {
|
|
1903
|
-
const counters = { image: 0, file: 0 };
|
|
1904
|
-
return attachments.map((att) => {
|
|
1905
|
-
const kind = isImageAttachment(att) ? "image" : "file";
|
|
1906
|
-
counters[kind] += 1;
|
|
1907
|
-
return `${kind}-${counters[kind]}`;
|
|
1908
|
-
});
|
|
1909
|
-
};
|
|
1910
|
-
|
|
1911
|
-
// ../shared/src/domain/session-event.ts
|
|
1912
|
-
var startedMessageIds = (events) => {
|
|
1913
|
-
const ids = /* @__PURE__ */ new Set();
|
|
1914
|
-
for (const e of events) {
|
|
1915
|
-
if (e.type !== "turn_start") continue;
|
|
1916
|
-
const id = e.payload?.messageId;
|
|
1917
|
-
if (typeof id === "number") ids.add(id);
|
|
1918
|
-
}
|
|
1919
|
-
return ids;
|
|
1920
|
-
};
|
|
1921
|
-
var unstartedUserMessages = (events) => {
|
|
1922
|
-
const started = startedMessageIds(events);
|
|
1923
|
-
return events.filter((e) => e.type === "user_message" && !started.has(e.id));
|
|
1924
|
-
};
|
|
1925
|
-
|
|
1926
2483
|
// src/session/runner/log.ts
|
|
1927
2484
|
var maskedEnvKeys = (env) => env ? Object.keys(env).sort().join(", ") : "(none)";
|
|
1928
2485
|
|
|
@@ -1939,14 +2496,14 @@ var additionalDirs = () => {
|
|
|
1939
2496
|
};
|
|
1940
2497
|
|
|
1941
2498
|
// src/session/runner/transcript.ts
|
|
1942
|
-
import { readdirSync, readFileSync as
|
|
2499
|
+
import { readdirSync, readFileSync as readFileSync4, statSync } from "node:fs";
|
|
1943
2500
|
import { homedir as homedir2 } from "node:os";
|
|
1944
|
-
import { join as
|
|
2501
|
+
import { join as join5 } from "node:path";
|
|
1945
2502
|
var findTranscriptPath = (agentSessionId) => {
|
|
1946
|
-
const root =
|
|
2503
|
+
const root = join5(homedir2(), ".claude", "projects");
|
|
1947
2504
|
try {
|
|
1948
2505
|
for (const dir of readdirSync(root)) {
|
|
1949
|
-
const candidate =
|
|
2506
|
+
const candidate = join5(root, dir, `${agentSessionId}.jsonl`);
|
|
1950
2507
|
try {
|
|
1951
2508
|
if (statSync(candidate).isFile()) return candidate;
|
|
1952
2509
|
} catch {
|
|
@@ -1992,7 +2549,7 @@ var readFirstExchange = (agentSessionId) => {
|
|
|
1992
2549
|
const path = findTranscriptPath(agentSessionId);
|
|
1993
2550
|
if (!path) return null;
|
|
1994
2551
|
try {
|
|
1995
|
-
return parseFirstExchange(
|
|
2552
|
+
return parseFirstExchange(readFileSync4(path, "utf8"));
|
|
1996
2553
|
} catch {
|
|
1997
2554
|
return null;
|
|
1998
2555
|
}
|
|
@@ -2001,7 +2558,7 @@ var readFirstExchange = (agentSessionId) => {
|
|
|
2001
2558
|
// src/session/runner/attachments.ts
|
|
2002
2559
|
import { createWriteStream } from "node:fs";
|
|
2003
2560
|
import { mkdir, writeFile } from "node:fs/promises";
|
|
2004
|
-
import { join as
|
|
2561
|
+
import { join as join6 } from "node:path";
|
|
2005
2562
|
import { Readable } from "node:stream";
|
|
2006
2563
|
import { pipeline } from "node:stream/promises";
|
|
2007
2564
|
var ATTACH_DIR = "attachments";
|
|
@@ -2024,16 +2581,16 @@ var dedupe = (name, taken) => {
|
|
|
2024
2581
|
};
|
|
2025
2582
|
var materializeAttachments = async (opts) => {
|
|
2026
2583
|
const fetchImpl = opts.fetchImpl ?? fetch;
|
|
2027
|
-
const dir =
|
|
2584
|
+
const dir = join6(opts.worktreePath, ATTACH_DIR);
|
|
2028
2585
|
await mkdir(dir, { recursive: true });
|
|
2029
|
-
await writeFile(
|
|
2586
|
+
await writeFile(join6(dir, ".gitignore"), "*\n", "utf8");
|
|
2030
2587
|
const taken = /* @__PURE__ */ new Set([".gitignore"]);
|
|
2031
2588
|
const relPaths = [];
|
|
2032
2589
|
for (const att of opts.attachments) {
|
|
2033
2590
|
const name = dedupe(att.filename, taken);
|
|
2034
2591
|
const res = await fetchImpl(`${opts.serverBase}${att.url}`);
|
|
2035
2592
|
if (!res.ok || !res.body) throw new Error(`attachment ${att.id} \u2192 ${res.status}`);
|
|
2036
|
-
await pipeline(Readable.fromWeb(res.body), createWriteStream(
|
|
2593
|
+
await pipeline(Readable.fromWeb(res.body), createWriteStream(join6(dir, name)));
|
|
2037
2594
|
relPaths.push(`${ATTACH_DIR}/${name}`);
|
|
2038
2595
|
}
|
|
2039
2596
|
return relPaths;
|
|
@@ -2095,6 +2652,7 @@ var toTurnResult = (message) => {
|
|
|
2095
2652
|
|
|
2096
2653
|
// src/session/runner/turn.ts
|
|
2097
2654
|
var turnTimeoutMs = () => Number(process.env.BATON_TURN_TIMEOUT_MS) || 30 * 6e4;
|
|
2655
|
+
var heartbeatMs = () => Number(process.env.BATON_TURN_HEARTBEAT_MS) || 3e4;
|
|
2098
2656
|
var TIMEOUT = /* @__PURE__ */ Symbol("turn-timeout");
|
|
2099
2657
|
var ABORTED = /* @__PURE__ */ Symbol("turn-aborted");
|
|
2100
2658
|
var finalizeTurn = async (result, worker2, log) => {
|
|
@@ -2147,6 +2705,7 @@ var runTurn = async (config, worker2, msg, resuming, queryFn, log = (m) => conso
|
|
|
2147
2705
|
const abort = new AbortController();
|
|
2148
2706
|
const ceiling = turnTimeoutMs();
|
|
2149
2707
|
let timer;
|
|
2708
|
+
let heartbeat;
|
|
2150
2709
|
const timeout = new Promise((resolve2) => {
|
|
2151
2710
|
timer = setTimeout(() => resolve2(TIMEOUT), ceiling);
|
|
2152
2711
|
});
|
|
@@ -2155,6 +2714,9 @@ var runTurn = async (config, worker2, msg, resuming, queryFn, log = (m) => conso
|
|
|
2155
2714
|
else externalSignal?.addEventListener("abort", () => resolve2(ABORTED), { once: true });
|
|
2156
2715
|
});
|
|
2157
2716
|
try {
|
|
2717
|
+
heartbeat = setInterval(() => {
|
|
2718
|
+
void worker2.emitEvent("turn_heartbeat", {}).catch((e) => log(`[heartbeat] ${String(e)}`));
|
|
2719
|
+
}, heartbeatMs());
|
|
2158
2720
|
const messages = startQuery(config, text, resuming, queryFn, abort, log, {
|
|
2159
2721
|
envOverlay,
|
|
2160
2722
|
planMode,
|
|
@@ -2189,6 +2751,7 @@ var runTurn = async (config, worker2, msg, resuming, queryFn, log = (m) => conso
|
|
|
2189
2751
|
return -1;
|
|
2190
2752
|
} finally {
|
|
2191
2753
|
clearTimeout(timer);
|
|
2754
|
+
clearInterval(heartbeat);
|
|
2192
2755
|
}
|
|
2193
2756
|
};
|
|
2194
2757
|
|
|
@@ -2269,10 +2832,17 @@ var runDaemon = async (config, deps, signal) => {
|
|
|
2269
2832
|
busy = false;
|
|
2270
2833
|
}
|
|
2271
2834
|
};
|
|
2835
|
+
const closeOrphanedTurn = async (reason) => {
|
|
2836
|
+
const events = await deps.worker.listEvents();
|
|
2837
|
+
if (!isAgentWorking(events)) return;
|
|
2838
|
+
await deps.worker.emitEvent("turn_error", { message: reason, synthetic: true });
|
|
2839
|
+
log(`closed orphaned open turn (${reason})`);
|
|
2840
|
+
};
|
|
2272
2841
|
const reconcile = async () => {
|
|
2273
2842
|
reconciling = true;
|
|
2274
2843
|
try {
|
|
2275
|
-
const
|
|
2844
|
+
const events = await deps.worker.listEvents();
|
|
2845
|
+
const pending = unstartedUserMessages(events);
|
|
2276
2846
|
let added = 0;
|
|
2277
2847
|
for (const ev of pending) {
|
|
2278
2848
|
if (state.seen.has(ev.sequence)) continue;
|
|
@@ -2284,6 +2854,12 @@ var runDaemon = async (config, deps, signal) => {
|
|
|
2284
2854
|
log(`reconciled ${added} queued message(s) from transcript`);
|
|
2285
2855
|
lastActivity = Date.now();
|
|
2286
2856
|
void drain();
|
|
2857
|
+
} else if (pendingQueue.length === 0 && !busy && !currentTurn && isAgentWorking(events)) {
|
|
2858
|
+
await deps.worker.emitEvent("turn_error", {
|
|
2859
|
+
message: "turn abandoned \u2014 runner restarted",
|
|
2860
|
+
synthetic: true
|
|
2861
|
+
});
|
|
2862
|
+
log("reconcile: closed orphaned open turn from a prior child");
|
|
2287
2863
|
}
|
|
2288
2864
|
} catch (e) {
|
|
2289
2865
|
log(`reconcile failed: ${String(e)}`);
|
|
@@ -2308,6 +2884,11 @@ var runDaemon = async (config, deps, signal) => {
|
|
|
2308
2884
|
if (currentTurn) {
|
|
2309
2885
|
log("interrupt \u2014 aborting current turn");
|
|
2310
2886
|
currentTurn.abort();
|
|
2887
|
+
} else {
|
|
2888
|
+
log("interrupt \u2014 no live turn; closing any orphaned open turn");
|
|
2889
|
+
void closeOrphanedTurn("interrupted by user").catch(
|
|
2890
|
+
(e) => log(`orphan close failed: ${String(e)}`)
|
|
2891
|
+
);
|
|
2311
2892
|
}
|
|
2312
2893
|
},
|
|
2313
2894
|
// Report active only now that we're subscribed — before this, a message
|
|
@@ -2400,44 +2981,6 @@ var sessionRunCommand = defineCommand({
|
|
|
2400
2981
|
}
|
|
2401
2982
|
});
|
|
2402
2983
|
|
|
2403
|
-
// src/commands/attach.ts
|
|
2404
|
-
import { openAsBlob } from "node:fs";
|
|
2405
|
-
import { basename } from "node:path";
|
|
2406
|
-
|
|
2407
|
-
// src/mime.ts
|
|
2408
|
-
import { extname } from "node:path";
|
|
2409
|
-
var BY_EXT = {
|
|
2410
|
-
".png": "image/png",
|
|
2411
|
-
".jpg": "image/jpeg",
|
|
2412
|
-
".jpeg": "image/jpeg",
|
|
2413
|
-
".gif": "image/gif",
|
|
2414
|
-
".webp": "image/webp",
|
|
2415
|
-
".svg": "image/svg+xml",
|
|
2416
|
-
".pdf": "application/pdf",
|
|
2417
|
-
".txt": "text/plain",
|
|
2418
|
-
".md": "text/markdown",
|
|
2419
|
-
".json": "application/json",
|
|
2420
|
-
".csv": "text/csv"
|
|
2421
|
-
};
|
|
2422
|
-
var contentTypeForPath = (path) => BY_EXT[extname(path).toLowerCase()] ?? "application/octet-stream";
|
|
2423
|
-
|
|
2424
|
-
// src/commands/attach.ts
|
|
2425
|
-
var attachPaths = (raw) => (raw === void 0 ? [] : Array.isArray(raw) ? raw : [raw]).flatMap((p) => p.split(",")).map((p) => p.trim()).filter(Boolean);
|
|
2426
|
-
var uploadAttachments = async (client, sessionId, paths) => {
|
|
2427
|
-
const out = [];
|
|
2428
|
-
for (const path of paths) {
|
|
2429
|
-
const body = await openAsBlob(path, { type: contentTypeForPath(path) });
|
|
2430
|
-
out.push(
|
|
2431
|
-
await client.sessions.uploadAttachment(sessionId, {
|
|
2432
|
-
filename: basename(path),
|
|
2433
|
-
contentType: contentTypeForPath(path),
|
|
2434
|
-
body
|
|
2435
|
-
})
|
|
2436
|
-
);
|
|
2437
|
-
}
|
|
2438
|
-
return out;
|
|
2439
|
-
};
|
|
2440
|
-
|
|
2441
2984
|
// src/commands/session/send.ts
|
|
2442
2985
|
var sessionSendCommand = defineCommand({
|
|
2443
2986
|
meta: { name: "send", description: "post a chat message into a session (no streaming reply)" },
|
|
@@ -2669,7 +3212,7 @@ import { hostname as osHostname } from "node:os";
|
|
|
2669
3212
|
import { spawn } from "node:child_process";
|
|
2670
3213
|
import { randomUUID } from "node:crypto";
|
|
2671
3214
|
import { existsSync as existsSync5 } from "node:fs";
|
|
2672
|
-
import { dirname as dirname2, join as
|
|
3215
|
+
import { dirname as dirname2, join as join7 } from "node:path";
|
|
2673
3216
|
import { fileURLToPath } from "node:url";
|
|
2674
3217
|
import { query as query2 } from "@anthropic-ai/claude-agent-sdk";
|
|
2675
3218
|
|
|
@@ -2759,7 +3302,7 @@ var generateTitle = async (input) => {
|
|
|
2759
3302
|
|
|
2760
3303
|
// src/session/worktree.ts
|
|
2761
3304
|
import { execFileSync, spawnSync as spawnSync2 } from "node:child_process";
|
|
2762
|
-
import { appendFileSync, existsSync as existsSync4, mkdirSync as
|
|
3305
|
+
import { appendFileSync, existsSync as existsSync4, mkdirSync as mkdirSync3, readFileSync as readFileSync5 } from "node:fs";
|
|
2763
3306
|
import { dirname, isAbsolute as isAbsolute2, resolve } from "node:path";
|
|
2764
3307
|
var createWorktree = (input) => {
|
|
2765
3308
|
if (existsSync4(input.worktreePath))
|
|
@@ -2772,7 +3315,7 @@ var createWorktree = (input) => {
|
|
|
2772
3315
|
throw new Error(
|
|
2773
3316
|
`repo has no commits (unborn HEAD) \u2014 create an initial commit before starting sessions`
|
|
2774
3317
|
);
|
|
2775
|
-
|
|
3318
|
+
mkdirSync3(dirname(input.worktreePath), { recursive: true });
|
|
2776
3319
|
const branch = `baton/${input.sessionCode}`;
|
|
2777
3320
|
const r = spawnSync2(
|
|
2778
3321
|
"git",
|
|
@@ -2800,9 +3343,9 @@ var ensureExcluded = (repo, pattern) => {
|
|
|
2800
3343
|
if (r.status !== 0) return;
|
|
2801
3344
|
const rel = r.stdout.trim();
|
|
2802
3345
|
const path = isAbsolute2(rel) ? rel : resolve(repo, rel);
|
|
2803
|
-
const current = existsSync4(path) ?
|
|
3346
|
+
const current = existsSync4(path) ? readFileSync5(path, "utf8") : "";
|
|
2804
3347
|
if (current.split("\n").includes(pattern)) return;
|
|
2805
|
-
|
|
3348
|
+
mkdirSync3(dirname(path), { recursive: true });
|
|
2806
3349
|
const sep = current === "" || current.endsWith("\n") ? "" : "\n";
|
|
2807
3350
|
appendFileSync(path, `${sep}${pattern}
|
|
2808
3351
|
`, "utf8");
|
|
@@ -2826,7 +3369,7 @@ var streamWedged = (isOpen, okAt, now, thresholdMs) => !isOpen && stale(okAt, no
|
|
|
2826
3369
|
// src/worker/daemon.ts
|
|
2827
3370
|
var binPath = () => {
|
|
2828
3371
|
const here = dirname2(fileURLToPath(import.meta.url));
|
|
2829
|
-
const devShim =
|
|
3372
|
+
const devShim = join7(here, "..", "..", "bin", "baton.mjs");
|
|
2830
3373
|
return existsSync5(devShim) ? devShim : fileURLToPath(import.meta.url);
|
|
2831
3374
|
};
|
|
2832
3375
|
var runWorkerDaemon = async (cfg, client, signal) => {
|
|
@@ -2896,7 +3439,7 @@ var runWorkerDaemon = async (cfg, client, signal) => {
|
|
|
2896
3439
|
let worktreePath = session2.worktreePath;
|
|
2897
3440
|
if (!session2.agentSessionId || !worktreePath) {
|
|
2898
3441
|
const agentSessionId = randomUUID();
|
|
2899
|
-
worktreePath =
|
|
3442
|
+
worktreePath = join7(worktreeDir, slug(`${name}-${agentSessionId.slice(0, 8)}`));
|
|
2900
3443
|
createWorktree({
|
|
2901
3444
|
repo,
|
|
2902
3445
|
worktreePath,
|
|
@@ -2907,7 +3450,7 @@ var runWorkerDaemon = async (cfg, client, signal) => {
|
|
|
2907
3450
|
log(`materialized session #${sessionId} \u2192 ${worktreePath}`);
|
|
2908
3451
|
}
|
|
2909
3452
|
ensureExcluded(repo, PROJECT_CONFIG_NAME);
|
|
2910
|
-
saveProjectConfig(
|
|
3453
|
+
saveProjectConfig(join7(worktreePath, PROJECT_CONFIG_NAME), worktreeConfig(cfg));
|
|
2911
3454
|
spawnChild(sessionId, worktreePath);
|
|
2912
3455
|
};
|
|
2913
3456
|
const onStop = (sessionId) => {
|
|
@@ -3010,18 +3553,18 @@ var runWorkerDaemon = async (cfg, client, signal) => {
|
|
|
3010
3553
|
|
|
3011
3554
|
// src/worker/machine-id.ts
|
|
3012
3555
|
import { randomUUID as randomUUID2 } from "node:crypto";
|
|
3013
|
-
import { existsSync as existsSync6, mkdirSync as
|
|
3556
|
+
import { existsSync as existsSync6, mkdirSync as mkdirSync4, readFileSync as readFileSync6, writeFileSync as writeFileSync5 } from "node:fs";
|
|
3014
3557
|
import { homedir as homedir3 } from "node:os";
|
|
3015
|
-
import { dirname as dirname3, join as
|
|
3016
|
-
var machineIdPath = (env = process.env) =>
|
|
3558
|
+
import { dirname as dirname3, join as join8 } from "node:path";
|
|
3559
|
+
var machineIdPath = (env = process.env) => join8(env.XDG_DATA_HOME ?? join8(env.HOME ?? homedir3(), ".local/share"), "baton", "machine-id");
|
|
3017
3560
|
var readOrCreateMachineId = (path = machineIdPath()) => {
|
|
3018
3561
|
if (existsSync6(path)) {
|
|
3019
|
-
const s =
|
|
3562
|
+
const s = readFileSync6(path, "utf8").trim();
|
|
3020
3563
|
if (s) return s;
|
|
3021
3564
|
}
|
|
3022
3565
|
const id = randomUUID2();
|
|
3023
|
-
|
|
3024
|
-
|
|
3566
|
+
mkdirSync4(dirname3(path), { recursive: true });
|
|
3567
|
+
writeFileSync5(path, `${id}
|
|
3025
3568
|
`, "utf8");
|
|
3026
3569
|
return id;
|
|
3027
3570
|
};
|
|
@@ -3290,6 +3833,7 @@ var main = defineCommand({
|
|
|
3290
3833
|
worker,
|
|
3291
3834
|
session,
|
|
3292
3835
|
relay,
|
|
3836
|
+
channel,
|
|
3293
3837
|
workspace,
|
|
3294
3838
|
project,
|
|
3295
3839
|
requirement,
|