@brightbeamai/chap-coordinator 0.3.3 → 0.3.4
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/dist/index.cjs +246 -61
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +245 -61
- package/dist/index.js.map +1 -1
- package/dist/patch.cjs +195 -61
- package/dist/patch.cjs.map +1 -1
- package/dist/patch.d.cts +16 -2
- package/dist/patch.d.ts +16 -2
- package/dist/patch.js +194 -61
- package/dist/patch.js.map +1 -1
- package/package.json +1 -1
package/dist/index.d.cts
CHANGED
|
@@ -5,7 +5,7 @@ import { AuditEntry, Envelope } from './types.cjs';
|
|
|
5
5
|
export { ArtefactId, ArtefactRoutingHints, AuditListener, Deliberation, DeliberationVote, Handoff, HandoffTaskItem, JsonPatchOp, Jwk, KeyRecord, Member, Mode, OverrideArtefact, ParticipantType, ParticipantUri, PauseScope, RefusalOutcome, ReviewDecision, RouteDecisionArtefact, SnapshotArtefact, Task, TaskId, TaskRoutingHints, TaskState, WhisperPrompt, Workspace, WorkspaceId, WorkspaceState, modeLE } from './types.cjs';
|
|
6
6
|
export { MemoryStore, Store, StoreChange, StoreConflictError, WorkspaceRecord } from './storage/store.cjs';
|
|
7
7
|
export { E, isValidEnvelope, rpcError } from './jsonrpc.cjs';
|
|
8
|
-
export { PatchError, applyJsonPatch, diffJsonPatch } from './patch.cjs';
|
|
8
|
+
export { DEFAULT_MAX_PATCHED_BYTES, PatchError, PatchLimits, applyJsonPatch, diffJsonPatch } from './patch.cjs';
|
|
9
9
|
import { KeyObject } from 'node:crypto';
|
|
10
10
|
|
|
11
11
|
/** The value an entry's chain link hashes. */
|
package/dist/index.d.ts
CHANGED
|
@@ -5,7 +5,7 @@ import { AuditEntry, Envelope } from './types.js';
|
|
|
5
5
|
export { ArtefactId, ArtefactRoutingHints, AuditListener, Deliberation, DeliberationVote, Handoff, HandoffTaskItem, JsonPatchOp, Jwk, KeyRecord, Member, Mode, OverrideArtefact, ParticipantType, ParticipantUri, PauseScope, RefusalOutcome, ReviewDecision, RouteDecisionArtefact, SnapshotArtefact, Task, TaskId, TaskRoutingHints, TaskState, WhisperPrompt, Workspace, WorkspaceId, WorkspaceState, modeLE } from './types.js';
|
|
6
6
|
export { MemoryStore, Store, StoreChange, StoreConflictError, WorkspaceRecord } from './storage/store.js';
|
|
7
7
|
export { E, isValidEnvelope, rpcError } from './jsonrpc.js';
|
|
8
|
-
export { PatchError, applyJsonPatch, diffJsonPatch } from './patch.js';
|
|
8
|
+
export { DEFAULT_MAX_PATCHED_BYTES, PatchError, PatchLimits, applyJsonPatch, diffJsonPatch } from './patch.js';
|
|
9
9
|
import { KeyObject } from 'node:crypto';
|
|
10
10
|
|
|
11
11
|
/** The value an entry's chain link hashes. */
|
package/dist/index.js
CHANGED
|
@@ -500,77 +500,116 @@ function deepEqual(a, b) {
|
|
|
500
500
|
}
|
|
501
501
|
return true;
|
|
502
502
|
}
|
|
503
|
-
function
|
|
503
|
+
function addAt(doc, path, value, size, copied = false, movedFrom) {
|
|
504
|
+
const parts = splitPath(path);
|
|
505
|
+
if (parts.length === 0) {
|
|
506
|
+
if (size) {
|
|
507
|
+
size.reset(value);
|
|
508
|
+
if (copied || movedFrom !== void 0) size.carry(size);
|
|
509
|
+
}
|
|
510
|
+
return value;
|
|
511
|
+
}
|
|
512
|
+
const [parent, key] = navigate(doc, parts);
|
|
513
|
+
let newKey;
|
|
514
|
+
if (Array.isArray(parent)) {
|
|
515
|
+
if (key === "-") {
|
|
516
|
+
parent.push(value);
|
|
517
|
+
} else {
|
|
518
|
+
const idx = key;
|
|
519
|
+
if (idx < 0 || idx > parent.length) {
|
|
520
|
+
throw new PatchError(`Index out of range for add: ${path}`);
|
|
521
|
+
}
|
|
522
|
+
parent.splice(idx, 0, value);
|
|
523
|
+
}
|
|
524
|
+
} else if (parent !== null && typeof parent === "object") {
|
|
525
|
+
if (Object.prototype.hasOwnProperty.call(parent, key)) size?.take(parent[key]);
|
|
526
|
+
else newKey = key;
|
|
527
|
+
parent[key] = value;
|
|
528
|
+
} else {
|
|
529
|
+
throw new PatchError(`Cannot add into ${jsonType(parent)}`);
|
|
530
|
+
}
|
|
531
|
+
if (size) {
|
|
532
|
+
if (movedFrom === void 0) {
|
|
533
|
+
const inserted = size.insert(value, parts.length, newKey);
|
|
534
|
+
if (copied) size.carry(inserted);
|
|
535
|
+
} else {
|
|
536
|
+
if (newKey !== void 0) size.bytes += utf8Length(newKey);
|
|
537
|
+
if (parts.length > movedFrom) {
|
|
538
|
+
const moved = sizeOf(value);
|
|
539
|
+
size.depth = Math.max(size.depth, parts.length + moved.depth);
|
|
540
|
+
size.carry(moved);
|
|
541
|
+
}
|
|
542
|
+
}
|
|
543
|
+
}
|
|
544
|
+
return doc;
|
|
545
|
+
}
|
|
546
|
+
function removeAt(doc, path, size, moved = false) {
|
|
547
|
+
const parts = splitPath(path);
|
|
548
|
+
if (parts.length === 0) throw new PatchError("Cannot remove root.");
|
|
549
|
+
const [parent, key] = navigate(doc, parts);
|
|
550
|
+
if (Array.isArray(parent)) {
|
|
551
|
+
const idx = key === "-" ? -1 : key;
|
|
552
|
+
if (idx < 0 || idx >= parent.length) {
|
|
553
|
+
throw new PatchError(`Index out of range for remove: ${path}`);
|
|
554
|
+
}
|
|
555
|
+
if (size && !moved) size.take(parent[idx]);
|
|
556
|
+
parent.splice(idx, 1);
|
|
557
|
+
} else if (parent !== null && typeof parent === "object") {
|
|
558
|
+
if (!Object.prototype.hasOwnProperty.call(parent, key)) {
|
|
559
|
+
throw new PatchError(`Path not found for remove: ${path}`);
|
|
560
|
+
}
|
|
561
|
+
if (size) {
|
|
562
|
+
if (moved) size.bytes -= utf8Length(key);
|
|
563
|
+
else size.take(parent[key], key);
|
|
564
|
+
}
|
|
565
|
+
delete parent[key];
|
|
566
|
+
} else {
|
|
567
|
+
throw new PatchError(`Cannot remove from ${jsonType(parent)}`);
|
|
568
|
+
}
|
|
569
|
+
return doc;
|
|
570
|
+
}
|
|
571
|
+
function applyOne(doc, op, size) {
|
|
504
572
|
const kind = op.op;
|
|
505
573
|
const path = op.path ?? "";
|
|
506
574
|
if (kind === "add") {
|
|
507
575
|
if (!("value" in op)) throw new PatchError("'add' requires 'value'");
|
|
508
|
-
|
|
509
|
-
if (parts.length === 0) return op.value;
|
|
510
|
-
const [parent, key] = navigate(doc, parts);
|
|
511
|
-
if (Array.isArray(parent)) {
|
|
512
|
-
if (key === "-") {
|
|
513
|
-
parent.push(op.value);
|
|
514
|
-
} else {
|
|
515
|
-
const idx = key;
|
|
516
|
-
if (idx < 0 || idx > parent.length) {
|
|
517
|
-
throw new PatchError(`Index out of range for add: ${path}`);
|
|
518
|
-
}
|
|
519
|
-
parent.splice(idx, 0, op.value);
|
|
520
|
-
}
|
|
521
|
-
} else if (parent !== null && typeof parent === "object") {
|
|
522
|
-
parent[key] = op.value;
|
|
523
|
-
} else {
|
|
524
|
-
throw new PatchError(`Cannot add into ${jsonType(parent)}`);
|
|
525
|
-
}
|
|
526
|
-
return doc;
|
|
576
|
+
return addAt(doc, path, clone(op.value), size);
|
|
527
577
|
}
|
|
528
578
|
if (kind === "replace") {
|
|
529
579
|
if (!("value" in op)) throw new PatchError("'replace' requires 'value'");
|
|
530
580
|
const parts = splitPath(path);
|
|
531
|
-
|
|
581
|
+
const value = clone(op.value);
|
|
582
|
+
if (parts.length === 0) {
|
|
583
|
+
size?.reset(value);
|
|
584
|
+
return value;
|
|
585
|
+
}
|
|
532
586
|
const [parent, key] = navigate(doc, parts);
|
|
533
587
|
if (Array.isArray(parent)) {
|
|
534
588
|
const idx = key === "-" ? -1 : key;
|
|
535
589
|
if (idx < 0 || idx >= parent.length) {
|
|
536
590
|
throw new PatchError(`Path not found for replace: ${path}`);
|
|
537
591
|
}
|
|
538
|
-
parent[idx]
|
|
592
|
+
size?.take(parent[idx]);
|
|
593
|
+
parent[idx] = value;
|
|
539
594
|
} else if (parent !== null && typeof parent === "object") {
|
|
540
595
|
if (!Object.prototype.hasOwnProperty.call(parent, key)) {
|
|
541
596
|
throw new PatchError(`Path not found for replace: ${path}`);
|
|
542
597
|
}
|
|
543
|
-
parent[key]
|
|
598
|
+
size?.take(parent[key]);
|
|
599
|
+
parent[key] = value;
|
|
544
600
|
} else {
|
|
545
601
|
throw new PatchError(`Cannot replace in ${jsonType(parent)}`);
|
|
546
602
|
}
|
|
603
|
+
size?.insert(value, parts.length);
|
|
547
604
|
return doc;
|
|
548
605
|
}
|
|
549
606
|
if (kind === "remove") {
|
|
550
|
-
|
|
551
|
-
if (parts.length === 0) throw new PatchError("Cannot remove root.");
|
|
552
|
-
const [parent, key] = navigate(doc, parts);
|
|
553
|
-
if (Array.isArray(parent)) {
|
|
554
|
-
const idx = key === "-" ? -1 : key;
|
|
555
|
-
if (idx < 0 || idx >= parent.length) {
|
|
556
|
-
throw new PatchError(`Index out of range for remove: ${path}`);
|
|
557
|
-
}
|
|
558
|
-
parent.splice(idx, 1);
|
|
559
|
-
} else if (parent !== null && typeof parent === "object") {
|
|
560
|
-
if (!Object.prototype.hasOwnProperty.call(parent, key)) {
|
|
561
|
-
throw new PatchError(`Path not found for remove: ${path}`);
|
|
562
|
-
}
|
|
563
|
-
delete parent[key];
|
|
564
|
-
} else {
|
|
565
|
-
throw new PatchError(`Cannot remove from ${jsonType(parent)}`);
|
|
566
|
-
}
|
|
567
|
-
return doc;
|
|
607
|
+
return removeAt(doc, path, size);
|
|
568
608
|
}
|
|
569
609
|
if (kind === "copy") {
|
|
570
610
|
const src = op.from;
|
|
571
611
|
if (src === void 0) throw new PatchError("'copy' requires 'from'");
|
|
572
|
-
|
|
573
|
-
return applyOne(doc, { op: "add", path, value });
|
|
612
|
+
return addAt(doc, path, clone(getAt(doc, src)), size, true);
|
|
574
613
|
}
|
|
575
614
|
if (kind === "move") {
|
|
576
615
|
const src = op.from;
|
|
@@ -578,9 +617,9 @@ function applyOne(doc, op) {
|
|
|
578
617
|
if (path.startsWith(src + "/")) {
|
|
579
618
|
throw new PatchError("'move' cannot move a location into its own child.");
|
|
580
619
|
}
|
|
581
|
-
const value =
|
|
582
|
-
doc =
|
|
583
|
-
return
|
|
620
|
+
const value = getAt(doc, src);
|
|
621
|
+
doc = removeAt(doc, src, size, true);
|
|
622
|
+
return addAt(doc, path, value, size, false, splitPath(src).length);
|
|
584
623
|
}
|
|
585
624
|
if (kind === "test") {
|
|
586
625
|
if (!("value" in op)) throw new PatchError("'test' requires 'value'");
|
|
@@ -592,29 +631,122 @@ function applyOne(doc, op) {
|
|
|
592
631
|
}
|
|
593
632
|
var MAX_PATCH_OPS = 1e3;
|
|
594
633
|
var MAX_DOCUMENT_NODES = 1e5;
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
634
|
+
var MAX_DOCUMENT_DEPTH = 64;
|
|
635
|
+
var MAX_CARRIED_TIMES = 3;
|
|
636
|
+
var DEFAULT_MAX_PATCHED_BYTES = 1048576;
|
|
637
|
+
function utf8Length(s) {
|
|
638
|
+
const buffer = globalThis.Buffer;
|
|
639
|
+
if (typeof buffer === "function") {
|
|
640
|
+
return buffer.byteLength(s, "utf8");
|
|
641
|
+
}
|
|
642
|
+
let n = 0;
|
|
643
|
+
for (let i = 0; i < s.length; i++) {
|
|
644
|
+
const c = s.charCodeAt(i);
|
|
645
|
+
if (c < 128) n += 1;
|
|
646
|
+
else if (c < 2048) n += 2;
|
|
647
|
+
else if (c >= 55296 && c <= 56319 && i + 1 < s.length) {
|
|
648
|
+
const d = s.charCodeAt(i + 1);
|
|
649
|
+
if (d >= 56320 && d <= 57343) {
|
|
650
|
+
n += 4;
|
|
651
|
+
i++;
|
|
652
|
+
} else n += 3;
|
|
653
|
+
} else n += 3;
|
|
654
|
+
}
|
|
655
|
+
return n;
|
|
656
|
+
}
|
|
657
|
+
function sizeOf(value) {
|
|
658
|
+
if (value === null || typeof value !== "object") {
|
|
659
|
+
return { nodes: 1, bytes: typeof value === "string" ? utf8Length(value) : 0, depth: 1 };
|
|
660
|
+
}
|
|
661
|
+
let nodes = 0;
|
|
662
|
+
let bytes = 0;
|
|
663
|
+
let depth = 0;
|
|
664
|
+
const values = [value];
|
|
665
|
+
const levels = [1];
|
|
666
|
+
const visit = (x, level) => {
|
|
667
|
+
if (x !== null && typeof x === "object") {
|
|
668
|
+
values.push(x);
|
|
669
|
+
levels.push(level);
|
|
670
|
+
return;
|
|
671
|
+
}
|
|
672
|
+
nodes += 1;
|
|
673
|
+
if (level > depth) depth = level;
|
|
674
|
+
if (typeof x === "string") bytes += utf8Length(x);
|
|
675
|
+
};
|
|
676
|
+
while (values.length > 0) {
|
|
677
|
+
const v = values.pop();
|
|
678
|
+
const level = levels.pop();
|
|
679
|
+
nodes += 1;
|
|
680
|
+
if (level > depth) depth = level;
|
|
681
|
+
if (Array.isArray(v)) {
|
|
682
|
+
for (const x of v) visit(x, level + 1);
|
|
683
|
+
} else {
|
|
684
|
+
const o = v;
|
|
685
|
+
for (const k of Object.keys(o)) {
|
|
686
|
+
bytes += utf8Length(k);
|
|
687
|
+
visit(o[k], level + 1);
|
|
688
|
+
}
|
|
689
|
+
}
|
|
605
690
|
}
|
|
606
|
-
return
|
|
691
|
+
return { nodes, bytes, depth };
|
|
607
692
|
}
|
|
608
|
-
|
|
693
|
+
var Size = class {
|
|
694
|
+
nodes = 0;
|
|
695
|
+
bytes = 0;
|
|
696
|
+
depth = 0;
|
|
697
|
+
/** What copies, and moves to a deeper place or onto the whole document, have carried. */
|
|
698
|
+
carriedNodes = 0;
|
|
699
|
+
carriedBytes = 0;
|
|
700
|
+
constructor(doc) {
|
|
701
|
+
this.reset(doc);
|
|
702
|
+
}
|
|
703
|
+
reset(doc) {
|
|
704
|
+
const s = sizeOf(doc);
|
|
705
|
+
this.nodes = s.nodes;
|
|
706
|
+
this.bytes = s.bytes;
|
|
707
|
+
this.depth = s.depth;
|
|
708
|
+
}
|
|
709
|
+
/** `value` goes in `segments` levels below the top, under a new `key`. */
|
|
710
|
+
insert(value, segments, key) {
|
|
711
|
+
const s = sizeOf(value);
|
|
712
|
+
this.nodes += s.nodes;
|
|
713
|
+
this.bytes += s.bytes + (key === void 0 ? 0 : utf8Length(key));
|
|
714
|
+
this.depth = Math.max(this.depth, segments + s.depth);
|
|
715
|
+
return s;
|
|
716
|
+
}
|
|
717
|
+
carry(s) {
|
|
718
|
+
this.carriedNodes += s.nodes;
|
|
719
|
+
this.carriedBytes += s.bytes;
|
|
720
|
+
}
|
|
721
|
+
/** `value` comes out, with its `key`. */
|
|
722
|
+
take(value, key) {
|
|
723
|
+
const s = sizeOf(value);
|
|
724
|
+
this.nodes -= s.nodes;
|
|
725
|
+
this.bytes -= s.bytes + (key === void 0 ? 0 : utf8Length(key));
|
|
726
|
+
}
|
|
727
|
+
};
|
|
728
|
+
function applyJsonPatch(doc, ops, limits = {}) {
|
|
729
|
+
const maxBytes = limits.maxStringBytes ?? DEFAULT_MAX_PATCHED_BYTES;
|
|
609
730
|
if (ops.length > MAX_PATCH_OPS) {
|
|
610
731
|
throw new PatchError(`Patch has too many operations (${ops.length} > ${MAX_PATCH_OPS})`);
|
|
611
732
|
}
|
|
612
733
|
let out = JSON.parse(JSON.stringify(doc));
|
|
734
|
+
const size = new Size(out);
|
|
613
735
|
for (const op of ops) {
|
|
614
|
-
out = applyOne(out, op);
|
|
615
|
-
if (
|
|
736
|
+
out = applyOne(out, op, size);
|
|
737
|
+
if (size.depth > MAX_DOCUMENT_DEPTH) size.depth = sizeOf(out).depth;
|
|
738
|
+
if (size.nodes > MAX_DOCUMENT_NODES) {
|
|
616
739
|
throw new PatchError(`Patched document exceeds the node limit (${MAX_DOCUMENT_NODES})`);
|
|
617
740
|
}
|
|
741
|
+
if (size.bytes > maxBytes) {
|
|
742
|
+
throw new PatchError(`Patched document exceeds the size limit (${maxBytes} bytes of strings and keys)`);
|
|
743
|
+
}
|
|
744
|
+
if (size.depth > MAX_DOCUMENT_DEPTH) {
|
|
745
|
+
throw new PatchError(`Patched document nests deeper than ${MAX_DOCUMENT_DEPTH} levels`);
|
|
746
|
+
}
|
|
747
|
+
if (size.carriedNodes > MAX_CARRIED_TIMES * MAX_DOCUMENT_NODES || size.carriedBytes > MAX_CARRIED_TIMES * maxBytes) {
|
|
748
|
+
throw new PatchError(`Patch copies or moves more than its limit (${MAX_CARRIED_TIMES * MAX_DOCUMENT_NODES} values or ${MAX_CARRIED_TIMES * maxBytes} bytes of strings and keys)`);
|
|
749
|
+
}
|
|
618
750
|
}
|
|
619
751
|
return out;
|
|
620
752
|
}
|
|
@@ -1347,6 +1479,7 @@ function registerControl(coord) {
|
|
|
1347
1479
|
}
|
|
1348
1480
|
|
|
1349
1481
|
// src/profiles/deliberation.ts
|
|
1482
|
+
var RESERVED_IDS = /* @__PURE__ */ new Set(["__proto__", "constructor", "prototype"]);
|
|
1350
1483
|
function parseRule(rule) {
|
|
1351
1484
|
if (rule.includes(":")) {
|
|
1352
1485
|
const [kind, arg] = rule.split(":", 2);
|
|
@@ -1447,6 +1580,18 @@ function registerDeliberation(coord) {
|
|
|
1447
1580
|
const msg = e instanceof Error ? e.message : String(e);
|
|
1448
1581
|
return { error: rpcError(E.DELIB_UNKNOWN_RULE, msg) };
|
|
1449
1582
|
}
|
|
1583
|
+
const suppliedDeliberationId = p.deliberation_id;
|
|
1584
|
+
if (suppliedDeliberationId !== void 0 && suppliedDeliberationId !== null && suppliedDeliberationId !== "") {
|
|
1585
|
+
if (typeof suppliedDeliberationId !== "string") {
|
|
1586
|
+
return { error: rpcError(E.PARAMS, "deliberation_id must be a string") };
|
|
1587
|
+
}
|
|
1588
|
+
if (RESERVED_IDS.has(suppliedDeliberationId)) {
|
|
1589
|
+
return { error: rpcError(E.PARAMS, `deliberation_id cannot be ${JSON.stringify(suppliedDeliberationId)}`) };
|
|
1590
|
+
}
|
|
1591
|
+
if (ws.deliberations.has(suppliedDeliberationId)) {
|
|
1592
|
+
return { error: rpcError(E.PARAMS, `deliberation_id already in use: ${suppliedDeliberationId}`) };
|
|
1593
|
+
}
|
|
1594
|
+
}
|
|
1450
1595
|
const id = p.deliberation_id || coord.ids.deliberationId();
|
|
1451
1596
|
const delib = {
|
|
1452
1597
|
id,
|
|
@@ -1529,6 +1674,7 @@ function registerDeliberation(coord) {
|
|
|
1529
1674
|
}
|
|
1530
1675
|
|
|
1531
1676
|
// src/profiles/handoff.ts
|
|
1677
|
+
var RESERVED_IDS2 = /* @__PURE__ */ new Set(["__proto__", "constructor", "prototype"]);
|
|
1532
1678
|
function registerHandoff(coord) {
|
|
1533
1679
|
coord.handlers.set("handoff.propose", (p) => {
|
|
1534
1680
|
const ws = coord.workspaces.get(p.workspace);
|
|
@@ -1571,6 +1717,18 @@ function registerHandoff(coord) {
|
|
|
1571
1717
|
blockers: t.blockers ?? []
|
|
1572
1718
|
});
|
|
1573
1719
|
}
|
|
1720
|
+
const suppliedHandoffId = p.handoff_id;
|
|
1721
|
+
if (suppliedHandoffId !== void 0 && suppliedHandoffId !== null && suppliedHandoffId !== "") {
|
|
1722
|
+
if (typeof suppliedHandoffId !== "string") {
|
|
1723
|
+
return { error: rpcError(E.PARAMS, "handoff_id must be a string") };
|
|
1724
|
+
}
|
|
1725
|
+
if (RESERVED_IDS2.has(suppliedHandoffId)) {
|
|
1726
|
+
return { error: rpcError(E.PARAMS, `handoff_id cannot be ${JSON.stringify(suppliedHandoffId)}`) };
|
|
1727
|
+
}
|
|
1728
|
+
if (ws.handoffs.has(suppliedHandoffId)) {
|
|
1729
|
+
return { error: rpcError(E.PARAMS, `handoff_id already in use: ${suppliedHandoffId}`) };
|
|
1730
|
+
}
|
|
1731
|
+
}
|
|
1574
1732
|
const id = p.handoff_id || coord.ids.handoffId();
|
|
1575
1733
|
const ho = {
|
|
1576
1734
|
id,
|
|
@@ -1961,6 +2119,7 @@ function registerSecuritySigned(coord) {
|
|
|
1961
2119
|
}
|
|
1962
2120
|
|
|
1963
2121
|
// src/profiles/whisper.ts
|
|
2122
|
+
var RESERVED_IDS3 = /* @__PURE__ */ new Set(["__proto__", "constructor", "prototype"]);
|
|
1964
2123
|
function parseIso(ts) {
|
|
1965
2124
|
return new Date(ts).getTime();
|
|
1966
2125
|
}
|
|
@@ -1985,6 +2144,18 @@ function registerWhisper(coord) {
|
|
|
1985
2144
|
}
|
|
1986
2145
|
const to = p.to;
|
|
1987
2146
|
const askee = Array.isArray(to) ? to : [to];
|
|
2147
|
+
const suppliedWhisperId = p.whisper_id;
|
|
2148
|
+
if (suppliedWhisperId !== void 0 && suppliedWhisperId !== null && suppliedWhisperId !== "") {
|
|
2149
|
+
if (typeof suppliedWhisperId !== "string") {
|
|
2150
|
+
return { error: rpcError(E.PARAMS, "whisper_id must be a string") };
|
|
2151
|
+
}
|
|
2152
|
+
if (RESERVED_IDS3.has(suppliedWhisperId)) {
|
|
2153
|
+
return { error: rpcError(E.PARAMS, `whisper_id cannot be ${JSON.stringify(suppliedWhisperId)}`) };
|
|
2154
|
+
}
|
|
2155
|
+
if (ws.whispers.has(suppliedWhisperId)) {
|
|
2156
|
+
return { error: rpcError(E.PARAMS, `whisper_id already in use: ${suppliedWhisperId}`) };
|
|
2157
|
+
}
|
|
2158
|
+
}
|
|
1988
2159
|
const id = p.whisper_id || coord.ids.artefactId();
|
|
1989
2160
|
const prompt = {
|
|
1990
2161
|
id,
|
|
@@ -3334,6 +3505,16 @@ var Coordinator = class {
|
|
|
3334
3505
|
) };
|
|
3335
3506
|
}
|
|
3336
3507
|
task.review = { requested_at: now, requested_to: eligible, rule: "any_one_approves", decisions: [] };
|
|
3508
|
+
} else {
|
|
3509
|
+
const author = p.from;
|
|
3510
|
+
const reviewers = task.review.requested_to.filter((r) => r !== author);
|
|
3511
|
+
if (reviewers.length === 0) {
|
|
3512
|
+
return { error: rpcError(
|
|
3513
|
+
E.NOT_AUTHORISED,
|
|
3514
|
+
"Task requires review but has no reviewer other than its completer"
|
|
3515
|
+
) };
|
|
3516
|
+
}
|
|
3517
|
+
task.review = { ...task.review, requested_at: now, requested_to: reviewers, decisions: [] };
|
|
3337
3518
|
}
|
|
3338
3519
|
task.pending_artefact = p.output;
|
|
3339
3520
|
task.state = "review_requested";
|
|
@@ -3549,7 +3730,9 @@ var Coordinator = class {
|
|
|
3549
3730
|
if (base === void 0) return { error: rpcError(E.PARAMS, "No base artefact for override") };
|
|
3550
3731
|
let applied;
|
|
3551
3732
|
try {
|
|
3552
|
-
applied = applyJsonPatch(base, p.diff
|
|
3733
|
+
applied = applyJsonPatch(base, p.diff, {
|
|
3734
|
+
maxStringBytes: this.options.maxEnvelopeBytes ?? DEFAULT_MAX_ENVELOPE_BYTES
|
|
3735
|
+
});
|
|
3553
3736
|
} catch (e) {
|
|
3554
3737
|
const msg = e instanceof Error ? e.message : String(e);
|
|
3555
3738
|
return { error: rpcError(E.PATCH_FAILED, msg) };
|
|
@@ -3885,6 +4068,7 @@ function wrapA2aMessageExchange(coord, workspace, options) {
|
|
|
3885
4068
|
export {
|
|
3886
4069
|
Coordinator,
|
|
3887
4070
|
CoordinatorError,
|
|
4071
|
+
DEFAULT_MAX_PATCHED_BYTES,
|
|
3888
4072
|
E,
|
|
3889
4073
|
IdFactory,
|
|
3890
4074
|
MemoryStore,
|