@damn-dev/cli 0.14.0 → 0.15.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/runtime/apps/backend/dist/resources/coo/WORKSPACE_GUIDE.md +73 -5
- package/runtime/apps/backend/dist/server.cjs +607 -139
- package/runtime/apps/frontend/dist/assets/index-By3Unk5U.css +1 -0
- package/runtime/apps/frontend/dist/assets/{index-P5Y8gibn.js → index-DSfZKjOi.js} +66 -66
- package/runtime/apps/frontend/dist/index.html +2 -2
- package/runtime/apps/frontend/dist/sw.js +1 -1
- package/runtime/apps/frontend/dist/assets/index-BREM8YXG.css +0 -1
|
@@ -5579,6 +5579,31 @@ var require_openclawBindings = __commonJS({
|
|
|
5579
5579
|
}
|
|
5580
5580
|
});
|
|
5581
5581
|
|
|
5582
|
+
// apps/backend/dist/lib/organigramUpdate.js
|
|
5583
|
+
var require_organigramUpdate = __commonJS({
|
|
5584
|
+
"apps/backend/dist/lib/organigramUpdate.js"(exports2) {
|
|
5585
|
+
"use strict";
|
|
5586
|
+
Object.defineProperty(exports2, "__esModule", { value: true });
|
|
5587
|
+
exports2.OrganigramUpdateSchema = void 0;
|
|
5588
|
+
var zod_12 = require("zod");
|
|
5589
|
+
var ReparentOpSchema = zod_12.z.object({
|
|
5590
|
+
op: zod_12.z.literal("reparent"),
|
|
5591
|
+
child: zod_12.z.string().min(1),
|
|
5592
|
+
// null = make child a root (reports to no one)
|
|
5593
|
+
parent: zod_12.z.string().min(1).nullable()
|
|
5594
|
+
});
|
|
5595
|
+
var SetRoleOpSchema = zod_12.z.object({
|
|
5596
|
+
op: zod_12.z.literal("set-role"),
|
|
5597
|
+
agentId: zod_12.z.string().min(1),
|
|
5598
|
+
role: zod_12.z.string().min(1).max(140)
|
|
5599
|
+
});
|
|
5600
|
+
exports2.OrganigramUpdateSchema = zod_12.z.object({
|
|
5601
|
+
operations: zod_12.z.array(zod_12.z.union([ReparentOpSchema, SetRoleOpSchema])).min(1),
|
|
5602
|
+
reason: zod_12.z.string().max(280).optional()
|
|
5603
|
+
});
|
|
5604
|
+
}
|
|
5605
|
+
});
|
|
5606
|
+
|
|
5582
5607
|
// apps/backend/dist/lib/delegationSecurity.js
|
|
5583
5608
|
var require_delegationSecurity = __commonJS({
|
|
5584
5609
|
"apps/backend/dist/lib/delegationSecurity.js"(exports2) {
|
|
@@ -7742,7 +7767,8 @@ var require_approvalRules = __commonJS({
|
|
|
7742
7767
|
"git_pr",
|
|
7743
7768
|
"cron_config",
|
|
7744
7769
|
"workspace_guide",
|
|
7745
|
-
"channel_binding"
|
|
7770
|
+
"channel_binding",
|
|
7771
|
+
"organigram_update"
|
|
7746
7772
|
]);
|
|
7747
7773
|
function derivePattern(type, payloadRaw) {
|
|
7748
7774
|
if (exports2.BLOCKED_TYPES.has(type))
|
|
@@ -7785,6 +7811,10 @@ var require_approvalRules = __commonJS({
|
|
|
7785
7811
|
const bindingAgentId = typeof payload.bindingAgentId === "string" ? payload.bindingAgentId : "*";
|
|
7786
7812
|
return { pattern: `binding:${plugin}:${bindingAgentId}`, ruleType: "channel_binding" };
|
|
7787
7813
|
}
|
|
7814
|
+
case "organigram_update": {
|
|
7815
|
+
const op = typeof payload.op === "string" ? payload.op : "*";
|
|
7816
|
+
return { pattern: `organigram:${op}`, ruleType: "organigram_update" };
|
|
7817
|
+
}
|
|
7788
7818
|
default:
|
|
7789
7819
|
return null;
|
|
7790
7820
|
}
|
|
@@ -9686,6 +9716,340 @@ ${conflictDiffs}`,
|
|
|
9686
9716
|
}
|
|
9687
9717
|
});
|
|
9688
9718
|
|
|
9719
|
+
// apps/backend/dist/lib/organigramParse.js
|
|
9720
|
+
var require_organigramParse = __commonJS({
|
|
9721
|
+
"apps/backend/dist/lib/organigramParse.js"(exports2) {
|
|
9722
|
+
"use strict";
|
|
9723
|
+
Object.defineProperty(exports2, "__esModule", { value: true });
|
|
9724
|
+
exports2.parseOrganigram = parseOrganigram;
|
|
9725
|
+
var SECTION_TITLE_RE = /^(reporting|org\s*chart|structure|reporting\s+structure|hierarchy)\b/i;
|
|
9726
|
+
function extractSection(md, title) {
|
|
9727
|
+
const lines = md.split("\n");
|
|
9728
|
+
let start = -1;
|
|
9729
|
+
let end = lines.length;
|
|
9730
|
+
for (let i = 0; i < lines.length; i++) {
|
|
9731
|
+
const m = /^##\s+(.+?)\s*$/.exec(lines[i]);
|
|
9732
|
+
if (!m)
|
|
9733
|
+
continue;
|
|
9734
|
+
if (start === -1 && title.test(m[1])) {
|
|
9735
|
+
start = i + 1;
|
|
9736
|
+
continue;
|
|
9737
|
+
}
|
|
9738
|
+
if (start !== -1) {
|
|
9739
|
+
end = i;
|
|
9740
|
+
break;
|
|
9741
|
+
}
|
|
9742
|
+
}
|
|
9743
|
+
if (start === -1)
|
|
9744
|
+
return null;
|
|
9745
|
+
return lines.slice(start, end).join("\n");
|
|
9746
|
+
}
|
|
9747
|
+
function extractRef(rawLine) {
|
|
9748
|
+
let s = rawLine.replace(/[│├└─]/g, " ").replace(/^[\s\-*•◦]+/, "").replace(/[\[\]]/g, "").trim();
|
|
9749
|
+
if (!s)
|
|
9750
|
+
return null;
|
|
9751
|
+
const asciiStart = s.search(/[A-Za-z]/);
|
|
9752
|
+
if (asciiStart > 0)
|
|
9753
|
+
s = s.slice(asciiStart).trim();
|
|
9754
|
+
const idMatch = /\(([A-Za-z0-9][A-Za-z0-9_-]*)\)\s*$/.exec(s);
|
|
9755
|
+
const idHint = idMatch ? idMatch[1].toLowerCase() : null;
|
|
9756
|
+
const display = (idMatch ? s.slice(0, idMatch.index) : s).trim();
|
|
9757
|
+
if (!display && !idHint)
|
|
9758
|
+
return null;
|
|
9759
|
+
return { display, idHint };
|
|
9760
|
+
}
|
|
9761
|
+
function resolveAgent(ref, agents) {
|
|
9762
|
+
if (!ref)
|
|
9763
|
+
return null;
|
|
9764
|
+
if (ref.idHint) {
|
|
9765
|
+
const byId = agents.find((a) => a.id.toLowerCase() === ref.idHint);
|
|
9766
|
+
if (byId)
|
|
9767
|
+
return byId.id;
|
|
9768
|
+
}
|
|
9769
|
+
if (/^(human|user|owner|you|me)$/i.test(ref.display))
|
|
9770
|
+
return null;
|
|
9771
|
+
const norm = ref.display.toLowerCase().replace(/\s+/g, " ").trim();
|
|
9772
|
+
if (!norm)
|
|
9773
|
+
return null;
|
|
9774
|
+
const byName = agents.find((a) => a.name.toLowerCase() === norm);
|
|
9775
|
+
if (byName)
|
|
9776
|
+
return byName.id;
|
|
9777
|
+
const byPrefix = agents.find((a) => a.name.toLowerCase().startsWith(norm) || norm.startsWith(a.name.toLowerCase()));
|
|
9778
|
+
return byPrefix?.id ?? null;
|
|
9779
|
+
}
|
|
9780
|
+
function indentLevel(line) {
|
|
9781
|
+
const m = /^([\s│├└─]*)/.exec(line);
|
|
9782
|
+
if (!m)
|
|
9783
|
+
return 0;
|
|
9784
|
+
return Math.floor(m[1].length / 2);
|
|
9785
|
+
}
|
|
9786
|
+
function buildFlatFallback(agents) {
|
|
9787
|
+
const coo = agents.find((a) => a.id === "coo" || a.name.toLowerCase() === "coo");
|
|
9788
|
+
if (!coo)
|
|
9789
|
+
return [];
|
|
9790
|
+
const out = [{ parent: null, child: coo.id }];
|
|
9791
|
+
for (const a of agents) {
|
|
9792
|
+
if (a.id === coo.id)
|
|
9793
|
+
continue;
|
|
9794
|
+
out.push({ parent: coo.id, child: a.id });
|
|
9795
|
+
}
|
|
9796
|
+
return out;
|
|
9797
|
+
}
|
|
9798
|
+
function parseOrganigram(md, agents) {
|
|
9799
|
+
if (agents.length === 0)
|
|
9800
|
+
return [];
|
|
9801
|
+
const section = md ? extractSection(md, SECTION_TITLE_RE) : null;
|
|
9802
|
+
if (!section)
|
|
9803
|
+
return buildFlatFallback(agents);
|
|
9804
|
+
const lines = section.split("\n").filter((l) => l.trim().length > 0);
|
|
9805
|
+
if (lines.length === 0)
|
|
9806
|
+
return buildFlatFallback(agents);
|
|
9807
|
+
const edges = [];
|
|
9808
|
+
const stack = [];
|
|
9809
|
+
const seenChildren = /* @__PURE__ */ new Set();
|
|
9810
|
+
for (const raw of lines) {
|
|
9811
|
+
const level = indentLevel(raw);
|
|
9812
|
+
const ref = extractRef(raw);
|
|
9813
|
+
if (!ref)
|
|
9814
|
+
continue;
|
|
9815
|
+
const id = resolveAgent(ref, agents);
|
|
9816
|
+
const isHumanRoot = /^(human|user|owner|you|me)$/i.test(ref.display) && !ref.idHint;
|
|
9817
|
+
if (!id && !isHumanRoot)
|
|
9818
|
+
continue;
|
|
9819
|
+
while (stack.length > 0 && stack[stack.length - 1].level >= level)
|
|
9820
|
+
stack.pop();
|
|
9821
|
+
const parentNode = stack[stack.length - 1] ?? null;
|
|
9822
|
+
const parent = parentNode?.id ?? null;
|
|
9823
|
+
if (id) {
|
|
9824
|
+
if (!seenChildren.has(id)) {
|
|
9825
|
+
edges.push({ parent, child: id });
|
|
9826
|
+
seenChildren.add(id);
|
|
9827
|
+
}
|
|
9828
|
+
stack.push({ id, level });
|
|
9829
|
+
} else {
|
|
9830
|
+
stack.push({ id: null, level });
|
|
9831
|
+
}
|
|
9832
|
+
}
|
|
9833
|
+
if (edges.length === 0)
|
|
9834
|
+
return buildFlatFallback(agents);
|
|
9835
|
+
const flatHintMatch = /flat\s+delegation|all\s+(workspace\s+)?agents/i.test(section);
|
|
9836
|
+
if (flatHintMatch) {
|
|
9837
|
+
const rootAgentId = edges.find((e) => e.parent === null)?.child ?? (agents.find((a) => a.id === "coo")?.id ?? null);
|
|
9838
|
+
if (rootAgentId) {
|
|
9839
|
+
for (const a of agents) {
|
|
9840
|
+
if (seenChildren.has(a.id) || a.id === rootAgentId)
|
|
9841
|
+
continue;
|
|
9842
|
+
edges.push({ parent: rootAgentId, child: a.id });
|
|
9843
|
+
seenChildren.add(a.id);
|
|
9844
|
+
}
|
|
9845
|
+
}
|
|
9846
|
+
}
|
|
9847
|
+
return edges;
|
|
9848
|
+
}
|
|
9849
|
+
}
|
|
9850
|
+
});
|
|
9851
|
+
|
|
9852
|
+
// apps/backend/dist/lib/organigramWrite.js
|
|
9853
|
+
var require_organigramWrite = __commonJS({
|
|
9854
|
+
"apps/backend/dist/lib/organigramWrite.js"(exports2) {
|
|
9855
|
+
"use strict";
|
|
9856
|
+
Object.defineProperty(exports2, "__esModule", { value: true });
|
|
9857
|
+
exports2.applyOrganigramOperations = applyOrganigramOperations;
|
|
9858
|
+
exports2.applyReparent = applyReparent;
|
|
9859
|
+
var promises_12 = require("fs/promises");
|
|
9860
|
+
var path_12 = require("path");
|
|
9861
|
+
var os_12 = require("os");
|
|
9862
|
+
var intelligence_12 = require_intelligence();
|
|
9863
|
+
var organigramParse_1 = require_organigramParse();
|
|
9864
|
+
var db_12 = require_db();
|
|
9865
|
+
var ORGANIGRAM_PATH = (0, path_12.join)((0, os_12.homedir)(), ".openclaw", "agents", "coo", "ORGANIGRAM.md");
|
|
9866
|
+
var SECTION_TITLE_RE = /^##\s+(reporting|org\s*chart|structure|reporting\s+structure|hierarchy)\s*$/i;
|
|
9867
|
+
function splitOnReportingSection(md) {
|
|
9868
|
+
const lines = md.split("\n");
|
|
9869
|
+
let sectionStart = -1;
|
|
9870
|
+
let sectionEnd = lines.length;
|
|
9871
|
+
for (let i = 0; i < lines.length; i++) {
|
|
9872
|
+
if (sectionStart === -1) {
|
|
9873
|
+
if (SECTION_TITLE_RE.test(lines[i])) {
|
|
9874
|
+
sectionStart = i;
|
|
9875
|
+
continue;
|
|
9876
|
+
}
|
|
9877
|
+
} else {
|
|
9878
|
+
if (/^##\s+/.test(lines[i])) {
|
|
9879
|
+
sectionEnd = i;
|
|
9880
|
+
break;
|
|
9881
|
+
}
|
|
9882
|
+
}
|
|
9883
|
+
}
|
|
9884
|
+
if (sectionStart === -1) {
|
|
9885
|
+
return { prefix: lines, body: [], suffix: [], synthesised: true };
|
|
9886
|
+
}
|
|
9887
|
+
return {
|
|
9888
|
+
prefix: lines.slice(0, sectionStart),
|
|
9889
|
+
body: lines.slice(sectionStart + 1, sectionEnd),
|
|
9890
|
+
suffix: lines.slice(sectionEnd),
|
|
9891
|
+
synthesised: false
|
|
9892
|
+
};
|
|
9893
|
+
}
|
|
9894
|
+
function applyReparentOps(current, ops) {
|
|
9895
|
+
const byChild = /* @__PURE__ */ new Map();
|
|
9896
|
+
for (const e of current)
|
|
9897
|
+
byChild.set(e.child, e.parent);
|
|
9898
|
+
const rejected = [];
|
|
9899
|
+
for (const op of ops) {
|
|
9900
|
+
if (op.child === op.parent) {
|
|
9901
|
+
rejected.push(op);
|
|
9902
|
+
continue;
|
|
9903
|
+
}
|
|
9904
|
+
if (op.parent !== null) {
|
|
9905
|
+
let cur = op.parent;
|
|
9906
|
+
const seen = /* @__PURE__ */ new Set();
|
|
9907
|
+
let cycle = false;
|
|
9908
|
+
while (cur !== null && cur !== void 0 && !seen.has(cur)) {
|
|
9909
|
+
if (cur === op.child) {
|
|
9910
|
+
cycle = true;
|
|
9911
|
+
break;
|
|
9912
|
+
}
|
|
9913
|
+
seen.add(cur);
|
|
9914
|
+
cur = byChild.get(cur) ?? null;
|
|
9915
|
+
}
|
|
9916
|
+
if (cycle) {
|
|
9917
|
+
rejected.push(op);
|
|
9918
|
+
continue;
|
|
9919
|
+
}
|
|
9920
|
+
}
|
|
9921
|
+
byChild.set(op.child, op.parent);
|
|
9922
|
+
}
|
|
9923
|
+
return {
|
|
9924
|
+
edges: Array.from(byChild.entries()).map(([child, parent]) => ({ parent, child })),
|
|
9925
|
+
rejected
|
|
9926
|
+
};
|
|
9927
|
+
}
|
|
9928
|
+
function renderReportingSection(edges, agents) {
|
|
9929
|
+
const childrenOf = /* @__PURE__ */ new Map();
|
|
9930
|
+
for (const e of edges) {
|
|
9931
|
+
if (e.parent === null)
|
|
9932
|
+
continue;
|
|
9933
|
+
const arr = childrenOf.get(e.parent) ?? [];
|
|
9934
|
+
arr.push(e.child);
|
|
9935
|
+
childrenOf.set(e.parent, arr);
|
|
9936
|
+
}
|
|
9937
|
+
const nameById = new Map(agents.map((a) => [a.id, a.name]));
|
|
9938
|
+
for (const arr of childrenOf.values()) {
|
|
9939
|
+
arr.sort((a, b) => (nameById.get(a) ?? a).localeCompare(nameById.get(b) ?? b));
|
|
9940
|
+
}
|
|
9941
|
+
const roots = edges.filter((e) => e.parent === null).map((e) => e.child);
|
|
9942
|
+
roots.sort((a, b) => (nameById.get(a) ?? a).localeCompare(nameById.get(b) ?? b));
|
|
9943
|
+
const out = [];
|
|
9944
|
+
function emit(id, depth) {
|
|
9945
|
+
const indent = " ".repeat(depth);
|
|
9946
|
+
const a = agents.find((x) => x.id === id);
|
|
9947
|
+
const label = a ? `${a.emoji} ${a.name} (${a.id})` : id;
|
|
9948
|
+
out.push(`${indent}- ${label}`);
|
|
9949
|
+
const kids = childrenOf.get(id) ?? [];
|
|
9950
|
+
for (const k of kids)
|
|
9951
|
+
emit(k, depth + 1);
|
|
9952
|
+
}
|
|
9953
|
+
for (const r of roots)
|
|
9954
|
+
emit(r, 0);
|
|
9955
|
+
return out;
|
|
9956
|
+
}
|
|
9957
|
+
function reassemble(split, renderedBody) {
|
|
9958
|
+
if (split.synthesised) {
|
|
9959
|
+
const out2 = [...split.prefix];
|
|
9960
|
+
if (out2.length > 0 && out2[out2.length - 1].trim() !== "")
|
|
9961
|
+
out2.push("");
|
|
9962
|
+
out2.push("## Reporting Structure", ...renderedBody);
|
|
9963
|
+
return out2.join("\n");
|
|
9964
|
+
}
|
|
9965
|
+
const out = [...split.prefix, "## Reporting Structure", ...renderedBody, ...split.suffix];
|
|
9966
|
+
return out.join("\n");
|
|
9967
|
+
}
|
|
9968
|
+
async function archivePrevious() {
|
|
9969
|
+
try {
|
|
9970
|
+
const prev = await (0, promises_12.readFile)(ORGANIGRAM_PATH, "utf-8");
|
|
9971
|
+
if (prev.trim().length === 0)
|
|
9972
|
+
return;
|
|
9973
|
+
await (0, intelligence_12.atomicWrite)((0, path_12.join)((0, path_12.dirname)(ORGANIGRAM_PATH), "ORGANIGRAM.prev.md"), prev);
|
|
9974
|
+
} catch {
|
|
9975
|
+
}
|
|
9976
|
+
}
|
|
9977
|
+
async function applyOrganigramOperations(ops, workspaceId) {
|
|
9978
|
+
if (ops.length === 0)
|
|
9979
|
+
return { ok: false, error: "no operations" };
|
|
9980
|
+
const agents = await db_12.db.agent.findMany({
|
|
9981
|
+
where: { workspaceId },
|
|
9982
|
+
select: { id: true, name: true, emoji: true }
|
|
9983
|
+
});
|
|
9984
|
+
const agentRefs = agents.map((a) => ({ id: a.id, name: a.name, emoji: a.emoji }));
|
|
9985
|
+
const agentIds = new Set(agents.map((a) => a.id));
|
|
9986
|
+
for (const op of ops) {
|
|
9987
|
+
if (op.op === "reparent") {
|
|
9988
|
+
if (!agentIds.has(op.child))
|
|
9989
|
+
return { ok: false, error: `unknown agent: ${op.child}` };
|
|
9990
|
+
if (op.parent !== null && !agentIds.has(op.parent))
|
|
9991
|
+
return { ok: false, error: `unknown agent: ${op.parent}` };
|
|
9992
|
+
} else if (op.op === "set-role") {
|
|
9993
|
+
if (!agentIds.has(op.agentId))
|
|
9994
|
+
return { ok: false, error: `unknown agent: ${op.agentId}` };
|
|
9995
|
+
}
|
|
9996
|
+
}
|
|
9997
|
+
let md = "";
|
|
9998
|
+
try {
|
|
9999
|
+
md = await (0, promises_12.readFile)(ORGANIGRAM_PATH, "utf-8");
|
|
10000
|
+
} catch {
|
|
10001
|
+
md = "";
|
|
10002
|
+
}
|
|
10003
|
+
const split = splitOnReportingSection(md);
|
|
10004
|
+
const currentEdges = (0, organigramParse_1.parseOrganigram)(md, agentRefs);
|
|
10005
|
+
const reparentOps = ops.filter((o) => o.op === "reparent");
|
|
10006
|
+
const { edges: mutatedEdges, rejected: rejectedReparent } = applyReparentOps(currentEdges, reparentOps);
|
|
10007
|
+
let prefixLines = [...split.prefix];
|
|
10008
|
+
const setRoleRejected = [];
|
|
10009
|
+
for (const op of ops) {
|
|
10010
|
+
if (op.op !== "set-role")
|
|
10011
|
+
continue;
|
|
10012
|
+
const agent = agents.find((a) => a.id === op.agentId);
|
|
10013
|
+
if (!agent) {
|
|
10014
|
+
setRoleRejected.push(op);
|
|
10015
|
+
continue;
|
|
10016
|
+
}
|
|
10017
|
+
const heading = new RegExp(`^####\\s+.*\\(${op.agentId}\\)\\s*$`);
|
|
10018
|
+
let i = prefixLines.findIndex((l) => heading.test(l));
|
|
10019
|
+
if (i < 0) {
|
|
10020
|
+
setRoleRejected.push(op);
|
|
10021
|
+
continue;
|
|
10022
|
+
}
|
|
10023
|
+
let replaced = false;
|
|
10024
|
+
for (let j = i + 1; j < Math.min(i + 7, prefixLines.length); j++) {
|
|
10025
|
+
if (/^Role:\s*/i.test(prefixLines[j])) {
|
|
10026
|
+
prefixLines[j] = `Role: ${op.role}`;
|
|
10027
|
+
replaced = true;
|
|
10028
|
+
break;
|
|
10029
|
+
}
|
|
10030
|
+
if (/^####?\s+/.test(prefixLines[j]) || /^##\s+/.test(prefixLines[j]))
|
|
10031
|
+
break;
|
|
10032
|
+
}
|
|
10033
|
+
if (!replaced)
|
|
10034
|
+
prefixLines.splice(i + 1, 0, `Role: ${op.role}`);
|
|
10035
|
+
}
|
|
10036
|
+
const renderedBody = renderReportingSection(mutatedEdges, agentRefs);
|
|
10037
|
+
const newMd = reassemble({ ...split, prefix: prefixLines }, renderedBody);
|
|
10038
|
+
await archivePrevious();
|
|
10039
|
+
await (0, intelligence_12.atomicWrite)(ORGANIGRAM_PATH, newMd);
|
|
10040
|
+
return { ok: true, content: newMd, rejected: [...rejectedReparent, ...setRoleRejected] };
|
|
10041
|
+
}
|
|
10042
|
+
async function applyReparent(child, parent, workspaceId) {
|
|
10043
|
+
const r = await applyOrganigramOperations([{ op: "reparent", child, parent }], workspaceId);
|
|
10044
|
+
if (!r.ok)
|
|
10045
|
+
return r;
|
|
10046
|
+
if (r.rejected.length > 0)
|
|
10047
|
+
return { ok: false, error: "cycle would be created \u2014 reparent refused" };
|
|
10048
|
+
return { ok: true, content: r.content };
|
|
10049
|
+
}
|
|
10050
|
+
}
|
|
10051
|
+
});
|
|
10052
|
+
|
|
9689
10053
|
// apps/backend/dist/routers/approvals.js
|
|
9690
10054
|
var require_approvals = __commonJS({
|
|
9691
10055
|
"apps/backend/dist/routers/approvals.js"(exports2) {
|
|
@@ -10065,6 +10429,32 @@ var require_approvals = __commonJS({
|
|
|
10065
10429
|
console.error("[channel_binding approval] apply error:", err);
|
|
10066
10430
|
}
|
|
10067
10431
|
})();
|
|
10432
|
+
} else if (decision === "approved" && message.approval?.type === "organigram_update" && message.approval.payload) {
|
|
10433
|
+
const orgPayload = JSON.parse(message.approval.payload);
|
|
10434
|
+
void (async () => {
|
|
10435
|
+
try {
|
|
10436
|
+
const { applyOrganigramOperations } = await Promise.resolve().then(() => __importStar2(require_organigramWrite()));
|
|
10437
|
+
const result = await applyOrganigramOperations(orgPayload.operations, workspace.id);
|
|
10438
|
+
const ok = result.ok;
|
|
10439
|
+
const summaryLine = ok ? `Organigram updated (${orgPayload.operations.length} op${orgPayload.operations.length === 1 ? "" : "s"}).${result.rejected.length > 0 ? ` ${result.rejected.length} rejected (cycle).` : ""}` : `Organigram update failed: ${result.error}`;
|
|
10440
|
+
const sysMsg = await db_12.db.message.create({
|
|
10441
|
+
data: {
|
|
10442
|
+
channelId: message.channelId,
|
|
10443
|
+
senderType: "system",
|
|
10444
|
+
senderId: "system",
|
|
10445
|
+
senderName: "System",
|
|
10446
|
+
senderColor: null,
|
|
10447
|
+
content: summaryLine
|
|
10448
|
+
},
|
|
10449
|
+
include: messages_12.messageInclude
|
|
10450
|
+
});
|
|
10451
|
+
(0, ws_12.broadcastToChannel)(message.channelId, { type: "message.new", payload: (0, messages_12.toMessage)(sysMsg) });
|
|
10452
|
+
(0, ws_12.broadcastToWorkspace)(workspace.id, { type: "delegationGraph.changed", payload: { workspaceId: workspace.id } });
|
|
10453
|
+
await (0, triggerAgent_12.triggerAgentDm)(agentId, message.channelId, ok ? `[Approval granted] ${summaryLine}` : `[Approval granted but apply failed] ${result.error}`, workspace.id);
|
|
10454
|
+
} catch (err) {
|
|
10455
|
+
console.error("[organigram_update approval] apply error:", err);
|
|
10456
|
+
}
|
|
10457
|
+
})();
|
|
10068
10458
|
} else if (decision === "approved" && message.approval?.type !== "shell_exec") {
|
|
10069
10459
|
await (0, triggerAgent_12.triggerAgentDm)(agentId, message.channelId, "[Approval granted] Your pending action has been approved. Proceed.", workspace.id);
|
|
10070
10460
|
} else if (decision === "rejected") {
|
|
@@ -13433,7 +13823,7 @@ var require_governance = __commonJS({
|
|
|
13433
13823
|
const approvalsCreated = [];
|
|
13434
13824
|
const delegationsInitiated = [];
|
|
13435
13825
|
let memoryWritten = false;
|
|
13436
|
-
const { extractMemoryUpdate, extractContextUpdate, extractSoulUpdate, extractHeartbeatUpdate, extractIdentityUpdate, extractSkillInstallProposal, extractSkillWriteProposal, extractCronWriteProposal, extractWorkspaceGuideUpdate, extractChannelBinding, extractDelegationRules, extractTaskInput, extractGitCommit, extractGitPR, extractGitMerge, extractDelegateBlock, extractDelegateChain, extractDelegateParallel, extractChannelPost, extractChannelUpdate, extractSkillToolCall, applyContextUpdate, applyHeartbeatUpdate, createFileEditApproval, executeSkillToolCall } = await Promise.resolve().then(() => __importStar2(require_triggerAgent()));
|
|
13826
|
+
const { extractMemoryUpdate, extractContextUpdate, extractSoulUpdate, extractHeartbeatUpdate, extractIdentityUpdate, extractSkillInstallProposal, extractSkillWriteProposal, extractCronWriteProposal, extractWorkspaceGuideUpdate, extractChannelBinding, extractDelegationRules, extractOrganigramUpdate, extractTaskInput, extractGitCommit, extractGitPR, extractGitMerge, extractDelegateBlock, extractDelegateChain, extractDelegateParallel, extractChannelPost, extractChannelUpdate, extractSkillToolCall, applyContextUpdate, applyHeartbeatUpdate, createFileEditApproval, executeSkillToolCall } = await Promise.resolve().then(() => __importStar2(require_triggerAgent()));
|
|
13437
13827
|
const { content: afterMemory, memoryAppend } = extractMemoryUpdate(responseText);
|
|
13438
13828
|
if (memoryAppend) {
|
|
13439
13829
|
blocksFound.push("memory-update");
|
|
@@ -13533,7 +13923,20 @@ var require_governance = __commonJS({
|
|
|
13533
13923
|
});
|
|
13534
13924
|
}
|
|
13535
13925
|
}
|
|
13536
|
-
const { content:
|
|
13926
|
+
const { content: afterOrganigramUpdate, organigramUpdate } = extractOrganigramUpdate(afterDelegationRules);
|
|
13927
|
+
if (organigramUpdate) {
|
|
13928
|
+
blocksFound.push("organigram-update");
|
|
13929
|
+
void createOrganigramUpdateApproval({
|
|
13930
|
+
agentId,
|
|
13931
|
+
channelId,
|
|
13932
|
+
workspaceId,
|
|
13933
|
+
update: organigramUpdate,
|
|
13934
|
+
agentName: agentName ?? agentId,
|
|
13935
|
+
agentColor: agentColor ?? null,
|
|
13936
|
+
externalSource
|
|
13937
|
+
});
|
|
13938
|
+
}
|
|
13939
|
+
const { content: afterTaskInput, taskInput } = extractTaskInput(afterOrganigramUpdate);
|
|
13537
13940
|
if (taskInput) {
|
|
13538
13941
|
blocksFound.push("task-input");
|
|
13539
13942
|
const { handleTaskInput } = await Promise.resolve().then(() => __importStar2(require_delegation()));
|
|
@@ -14046,6 +14449,86 @@ _${binding.reason}_`,
|
|
|
14046
14449
|
console.error("[channel-binding] approval creation failed:", err);
|
|
14047
14450
|
}
|
|
14048
14451
|
}
|
|
14452
|
+
async function createOrganigramUpdateApproval(opts) {
|
|
14453
|
+
const { agentId, channelId, workspaceId, update, agentName, agentColor, externalSource } = opts;
|
|
14454
|
+
try {
|
|
14455
|
+
const { toMessage, messageInclude } = await Promise.resolve().then(() => __importStar2(require_messages()));
|
|
14456
|
+
const { broadcastToChannel } = await Promise.resolve().then(() => __importStar2(require_ws()));
|
|
14457
|
+
const { getActiveModel } = await Promise.resolve().then(() => __importStar2(require_triggerAgent()));
|
|
14458
|
+
const { maybeAutoApprove } = await Promise.resolve().then(() => __importStar2(require_approvals()));
|
|
14459
|
+
const agent = await db_12.db.agent.findUnique({ where: { id: agentId }, select: { defaultModel: true } });
|
|
14460
|
+
const opCounts = {};
|
|
14461
|
+
for (const op of update.operations)
|
|
14462
|
+
opCounts[op.op] = (opCounts[op.op] ?? 0) + 1;
|
|
14463
|
+
const summary = `Organigram update: ${Object.entries(opCounts).map(([op, n]) => `${n}\xD7 ${op}`).join(", ")}`;
|
|
14464
|
+
const approvalMsg = await db_12.db.message.create({
|
|
14465
|
+
data: {
|
|
14466
|
+
channelId,
|
|
14467
|
+
senderType: "agent",
|
|
14468
|
+
senderId: agentId,
|
|
14469
|
+
senderName: agentName,
|
|
14470
|
+
senderColor: agentColor,
|
|
14471
|
+
content: `${summary}${update.reason ? `
|
|
14472
|
+
|
|
14473
|
+
_${update.reason}_` : ""}`,
|
|
14474
|
+
status: "pending_approval",
|
|
14475
|
+
modelUsed: await getActiveModel(agentId, agent?.defaultModel ?? "unknown"),
|
|
14476
|
+
metadata: JSON.stringify({ organigramUpdate: update })
|
|
14477
|
+
},
|
|
14478
|
+
include: messageInclude
|
|
14479
|
+
});
|
|
14480
|
+
const firstOp = update.operations[0];
|
|
14481
|
+
const approvalPayload = {
|
|
14482
|
+
operations: update.operations,
|
|
14483
|
+
reason: update.reason ?? "",
|
|
14484
|
+
// surface a stable pattern for derivePattern
|
|
14485
|
+
op: firstOp.op
|
|
14486
|
+
};
|
|
14487
|
+
await db_12.db.approval.create({
|
|
14488
|
+
data: {
|
|
14489
|
+
messageId: approvalMsg.id,
|
|
14490
|
+
type: "organigram_update",
|
|
14491
|
+
payload: JSON.stringify(approvalPayload)
|
|
14492
|
+
}
|
|
14493
|
+
});
|
|
14494
|
+
const msgForBroadcast = await db_12.db.message.findUnique({ where: { id: approvalMsg.id }, include: messageInclude });
|
|
14495
|
+
broadcastToChannel(channelId, { type: "message.new", payload: toMessage(msgForBroadcast) });
|
|
14496
|
+
const autoApproved = await maybeAutoApprove({
|
|
14497
|
+
messageId: approvalMsg.id,
|
|
14498
|
+
agentId,
|
|
14499
|
+
workspaceId,
|
|
14500
|
+
approvalType: "organigram_update",
|
|
14501
|
+
payload: approvalPayload
|
|
14502
|
+
});
|
|
14503
|
+
if (autoApproved)
|
|
14504
|
+
return;
|
|
14505
|
+
if (externalSource) {
|
|
14506
|
+
const { sendTelegramApprovalNotification } = await Promise.resolve().then(() => __importStar2(require_telegramBridge()));
|
|
14507
|
+
void sendTelegramApprovalNotification({
|
|
14508
|
+
agentId,
|
|
14509
|
+
chatId: externalSource.externalChatId,
|
|
14510
|
+
approvalId: approvalMsg.id,
|
|
14511
|
+
messageId: approvalMsg.id,
|
|
14512
|
+
approvalType: "organigram_update",
|
|
14513
|
+
description: summary
|
|
14514
|
+
});
|
|
14515
|
+
}
|
|
14516
|
+
const admins = await db_12.db.workspaceMember.findMany({
|
|
14517
|
+
where: { workspaceId, role: { in: ["owner", "admin"] } },
|
|
14518
|
+
select: { userId: true }
|
|
14519
|
+
});
|
|
14520
|
+
const { sendPush } = await Promise.resolve().then(() => __importStar2(require_pushNotifications()));
|
|
14521
|
+
for (const a of admins) {
|
|
14522
|
+
void sendPush(a.userId, {
|
|
14523
|
+
title: "Action requires approval",
|
|
14524
|
+
body: summary.slice(0, 100),
|
|
14525
|
+
data: { type: "approval", approvalId: approvalMsg.id, channelId }
|
|
14526
|
+
});
|
|
14527
|
+
}
|
|
14528
|
+
} catch (err) {
|
|
14529
|
+
console.error("[organigram-update] approval creation failed:", err);
|
|
14530
|
+
}
|
|
14531
|
+
}
|
|
14049
14532
|
async function createDelegationRuleApproval(opts) {
|
|
14050
14533
|
const { agentId, channelId, workspaceId, rule, agentName, agentColor, externalSource } = opts;
|
|
14051
14534
|
try {
|
|
@@ -14196,6 +14679,7 @@ var require_triggerAgent = __commonJS({
|
|
|
14196
14679
|
exports2.extractCronWriteProposal = extractCronWriteProposal;
|
|
14197
14680
|
exports2.extractWorkspaceGuideUpdate = extractWorkspaceGuideUpdate;
|
|
14198
14681
|
exports2.extractChannelBinding = extractChannelBinding;
|
|
14682
|
+
exports2.extractOrganigramUpdate = extractOrganigramUpdate;
|
|
14199
14683
|
exports2.applyMemoryUpdate = applyMemoryUpdate;
|
|
14200
14684
|
exports2.applyContextUpdate = applyContextUpdate;
|
|
14201
14685
|
exports2.extractHeartbeatUpdate = extractHeartbeatUpdate;
|
|
@@ -14233,6 +14717,7 @@ var require_triggerAgent = __commonJS({
|
|
|
14233
14717
|
var cronStore_1 = require_cronStore();
|
|
14234
14718
|
var workspaceGuide_1 = require_workspaceGuide();
|
|
14235
14719
|
var openclawBindings_1 = require_openclawBindings();
|
|
14720
|
+
var organigramUpdate_1 = require_organigramUpdate();
|
|
14236
14721
|
var execFileAsync2 = (0, util_12.promisify)(child_process_12.execFile);
|
|
14237
14722
|
function isFenceLine(line) {
|
|
14238
14723
|
if (line.startsWith("````"))
|
|
@@ -14379,6 +14864,7 @@ ${newBlock}`;
|
|
|
14379
14864
|
var CRON_WRITE_RE = /````cron-write\n([\s\S]*?)````|```cron-write\n([\s\S]*?)```/;
|
|
14380
14865
|
var WORKSPACE_GUIDE_UPDATE_RE = /````workspace-guide-update\n([\s\S]*?)````|```workspace-guide-update\n([\s\S]*?)```/;
|
|
14381
14866
|
var CHANNEL_BINDING_RE = /````channel-binding\n([\s\S]*?)````|```channel-binding\n([\s\S]*?)```/;
|
|
14867
|
+
var ORGANIGRAM_UPDATE_RE = /````organigram-update\n([\s\S]*?)````|```organigram-update\n([\s\S]*?)```/;
|
|
14382
14868
|
function extractGitPR(raw) {
|
|
14383
14869
|
const match = raw.match(GIT_PR_RE);
|
|
14384
14870
|
if (!match)
|
|
@@ -15031,6 +15517,10 @@ ${sectionHeader}`);
|
|
|
15031
15517
|
const { content, proposal } = extractJsonBlock(raw, CHANNEL_BINDING_RE, openclawBindings_1.ChannelBindingSchema, "channel-binding");
|
|
15032
15518
|
return { content, channelBinding: proposal };
|
|
15033
15519
|
}
|
|
15520
|
+
function extractOrganigramUpdate(raw) {
|
|
15521
|
+
const { content, proposal } = extractJsonBlock(raw, ORGANIGRAM_UPDATE_RE, organigramUpdate_1.OrganigramUpdateSchema, "organigram-update");
|
|
15522
|
+
return { content, organigramUpdate: proposal };
|
|
15523
|
+
}
|
|
15034
15524
|
async function applyMemoryUpdate(agentId, memoryAppend, source = "gateway") {
|
|
15035
15525
|
const memoryDir = path_12.default.join(OPENCLAW_AGENTS_DIR, agentId, "memory");
|
|
15036
15526
|
try {
|
|
@@ -15462,6 +15952,31 @@ Pattern syntax: \`shell:<argv0>\` (or \`shell:<argv0> <subcommand>\`), \`delegat
|
|
|
15462
15952
|
You may emit MULTIPLE \`delegation-rule\` blocks in a single message (one per pattern). Each becomes its own approval card.
|
|
15463
15953
|
|
|
15464
15954
|
Each rule requires human approval before it takes effect. Never propose delegation rules for: delete, publish, send, transfer, post (public write), or any destructive action without explicit user instruction. Never propose auto-approve for items in \`BLOCKED_TYPES\` (file_edit, skill_install, trust_config, git_merge, delegation_rule itself) \u2014 those are principled "always human-in-the-loop" types.`;
|
|
15955
|
+
var ORGANIGRAM_UPDATE_PATCH = `
|
|
15956
|
+
|
|
15957
|
+
## Organigram Update Protocol
|
|
15958
|
+
You can mutate the workspace organigram (reporting structure + role labels) via the structured \`organigram-update\` block. Prefer this over rewriting Organigram.md prose directly \u2014 the structured block is parser-stable, atomic, and the canvas reflects changes within ~1s.
|
|
15959
|
+
|
|
15960
|
+
**Cardinal rule:** the fenced \`\`\`organigram-update\`\`\` block IS the proposal. Narrating "I've moved Birdie under Marketing" / "Reporting updated" without the fenced block does nothing.
|
|
15961
|
+
|
|
15962
|
+
Operations:
|
|
15963
|
+
- \`reparent\` \u2014 change who an agent reports to. \`parent\` is an agent slug, OR \`null\` to make the child a root (reports to no one).
|
|
15964
|
+
- \`set-role\` \u2014 change an agent's role label in the Agent Directory section.
|
|
15965
|
+
|
|
15966
|
+
Example: move Birdie under Marketing Lead and update Claw's role:
|
|
15967
|
+
\`\`\`organigram-update
|
|
15968
|
+
{
|
|
15969
|
+
"operations": [
|
|
15970
|
+
{"op": "reparent", "child": "birdie", "parent": "marketing-lead"},
|
|
15971
|
+
{"op": "set-role", "agentId": "claw", "role": "Brand Voice Lead"}
|
|
15972
|
+
],
|
|
15973
|
+
"reason": "Birdie now reports to the new Marketing Lead; Claw's title shortened for clarity on the canvas."
|
|
15974
|
+
}
|
|
15975
|
+
\`\`\`
|
|
15976
|
+
|
|
15977
|
+
Cycle protection is enforced server-side \u2014 proposing a reparent that would create a loop (X under one of X's descendants) is rejected at apply time; safe to attempt. The COO retains full freedom to edit Organigram.md prose (Agent Directory descriptions, narrative sections) via the workspace dialog or the existing setOrganigram flow; only structural mutations should flow through this block.
|
|
15978
|
+
|
|
15979
|
+
\`organigram-update\` is auto-approvable by default (low risk \u2014 metadata only). The owner can gate it via the rule pattern \`organigram:reparent\` / \`organigram:set-role\` / \`organigram:*\`.`;
|
|
15465
15980
|
var OPS_PROTOCOL_PATCH = `
|
|
15466
15981
|
|
|
15467
15982
|
## Workspace Operations Protocol
|
|
@@ -15654,9 +16169,11 @@ You have three coordination mechanisms:
|
|
|
15654
16169
|
out = patchSection(out, "## Channel Update Protocol", CHANNEL_UPDATE_PATCH.trim());
|
|
15655
16170
|
out = patchSection(out, "## Delegation Rule Protocol", DELEGATION_RULE_PATCH.trim());
|
|
15656
16171
|
out = patchSection(out, "## Workspace Operations Protocol", OPS_PROTOCOL_PATCH.trim());
|
|
16172
|
+
out = patchSection(out, "## Organigram Update Protocol", ORGANIGRAM_UPDATE_PATCH.trim());
|
|
15657
16173
|
} else {
|
|
15658
16174
|
out = out.replace(/\n*## Delegation Rule Protocol\n[\s\S]*?(?=\n## |\n# |$)/, "");
|
|
15659
16175
|
out = out.replace(/\n*## Workspace Operations Protocol\n[\s\S]*?(?=\n## |\n# |$)/, "");
|
|
16176
|
+
out = out.replace(/\n*## Organigram Update Protocol\n[\s\S]*?(?=\n## |\n# |$)/, "");
|
|
15660
16177
|
}
|
|
15661
16178
|
if (flags.heartbeatChecklist) {
|
|
15662
16179
|
const block = `## Heartbeat Checklist
|
|
@@ -20538,6 +21055,7 @@ var require_onboarding = __commonJS({
|
|
|
20538
21055
|
var modelId_1 = require_modelId();
|
|
20539
21056
|
var skills_12 = require_skills();
|
|
20540
21057
|
var gateways_12 = require_gateways();
|
|
21058
|
+
var ws_12 = require_ws();
|
|
20541
21059
|
var triggerAgent_2 = require_triggerAgent();
|
|
20542
21060
|
var execAsync = (0, util_12.promisify)(child_process_12.exec);
|
|
20543
21061
|
var OPENROUTER_URL = "https://openrouter.ai/api/v1";
|
|
@@ -21436,7 +21954,7 @@ Or just tell me what you're working on \u2014 I'll figure out the rest.`
|
|
|
21436
21954
|
return "";
|
|
21437
21955
|
}
|
|
21438
21956
|
}),
|
|
21439
|
-
setOrganigram: trpc_12.protectedProcedure.input(zod_12.z.object({ content: zod_12.z.string() })).mutation(async ({ input }) => {
|
|
21957
|
+
setOrganigram: trpc_12.protectedProcedure.input(zod_12.z.object({ content: zod_12.z.string() })).mutation(async ({ ctx, input }) => {
|
|
21440
21958
|
await promises_12.default.mkdir(path_12.default.dirname(ORGANIGRAM_PATH), { recursive: true });
|
|
21441
21959
|
try {
|
|
21442
21960
|
const prev = await promises_12.default.readFile(ORGANIGRAM_PATH, "utf-8");
|
|
@@ -21447,6 +21965,7 @@ Or just tell me what you're working on \u2014 I'll figure out the rest.`
|
|
|
21447
21965
|
}
|
|
21448
21966
|
await atomicWrite(ORGANIGRAM_PATH, input.content);
|
|
21449
21967
|
reloadCoo();
|
|
21968
|
+
(0, ws_12.broadcastToWorkspace)(ctx.workspaceId, { type: "delegationGraph.changed", payload: { workspaceId: ctx.workspaceId } });
|
|
21450
21969
|
return { ok: true };
|
|
21451
21970
|
}),
|
|
21452
21971
|
hasGoogleAuth: trpc_12.publicProcedure.query(() => {
|
|
@@ -22093,6 +22612,29 @@ You may emit MULTIPLE \`delegation-rule\` blocks in a single message (one per pa
|
|
|
22093
22612
|
|
|
22094
22613
|
The human approves each rule before it takes effect. Never propose delegation rules for: delete, publish, send, transfer, post (public write), or any destructive action without explicit user instruction. Never propose auto-approve for items in \`BLOCKED_TYPES\` (file_edit, skill_install, trust_config, git_merge, delegation_rule itself) \u2014 those are principled "always human-in-the-loop" types.
|
|
22095
22614
|
|
|
22615
|
+
## Organigram Update Protocol
|
|
22616
|
+
|
|
22617
|
+
You can mutate the workspace organigram (reporting structure + role labels) via the structured \`organigram-update\` block. Prefer this over rewriting Organigram.md prose directly \u2014 the structured block is parser-stable, atomic, and the canvas reflects changes within ~1s.
|
|
22618
|
+
|
|
22619
|
+
**Cardinal rule:** the fenced \`\`\`organigram-update\`\`\` block IS the proposal. Narrating "I've moved Birdie under Marketing" / "Reporting updated" without the fenced block does nothing.
|
|
22620
|
+
|
|
22621
|
+
Operations:
|
|
22622
|
+
- \`reparent\` \u2014 change who an agent reports to. \`parent\` is an agent slug, OR \`null\` to make the child a root (reports to no one).
|
|
22623
|
+
- \`set-role\` \u2014 change an agent's role label in the Agent Directory section.
|
|
22624
|
+
|
|
22625
|
+
Example: move Birdie under Marketing Lead and update Claw's role:
|
|
22626
|
+
\`\`\`organigram-update
|
|
22627
|
+
{
|
|
22628
|
+
"operations": [
|
|
22629
|
+
{"op": "reparent", "child": "birdie", "parent": "marketing-lead"},
|
|
22630
|
+
{"op": "set-role", "agentId": "claw", "role": "Brand Voice Lead"}
|
|
22631
|
+
],
|
|
22632
|
+
"reason": "Birdie now reports to the new Marketing Lead; Claw's title shortened for clarity on the canvas."
|
|
22633
|
+
}
|
|
22634
|
+
\`\`\`
|
|
22635
|
+
|
|
22636
|
+
Cycle protection is enforced server-side \u2014 proposing a reparent that would create a loop is rejected at apply time; safe to attempt. The COO retains full freedom to edit Organigram.md prose (Agent Directory descriptions, narrative sections) via the workspace dialog or the existing setOrganigram flow; only structural mutations should flow through this block. \`organigram-update\` is auto-approvable by default (low risk \u2014 metadata only); the owner can gate it via the rule pattern \`organigram:reparent\` / \`organigram:set-role\` / \`organigram:*\`.
|
|
22637
|
+
|
|
22096
22638
|
## Federation (Cross-Instance Delegation)
|
|
22097
22639
|
|
|
22098
22640
|
This workspace may have federated nodes \u2014 separate damn.dev instances running in isolated Docker containers. They appear in the "Federation Nodes" section of your runtime context below (live state, refreshed every turn). Each node has a current \`delegationPolicy\` that governs who on THIS hub may dispatch tasks INTO it:
|
|
@@ -23165,6 +23707,9 @@ ${historyLines.join("\n\n")}
|
|
|
23165
23707
|
} catch {
|
|
23166
23708
|
}
|
|
23167
23709
|
}
|
|
23710
|
+
const { content: afterOrganigramUpdate, organigramUpdate } = (0, triggerAgent_12.extractOrganigramUpdate)(cleanContent);
|
|
23711
|
+
if (organigramUpdate)
|
|
23712
|
+
cleanContent = afterOrganigramUpdate;
|
|
23168
23713
|
const { content: afterMissionPlan, missionPlan } = extractMissionPlan(cleanContent);
|
|
23169
23714
|
if (missionPlan)
|
|
23170
23715
|
cleanContent = afterMissionPlan;
|
|
@@ -23246,6 +23791,9 @@ ${historyLines.join("\n\n")}
|
|
|
23246
23791
|
if (delegationRulePayload) {
|
|
23247
23792
|
msgMetadata.delegationRule = delegationRulePayload;
|
|
23248
23793
|
}
|
|
23794
|
+
if (organigramUpdate) {
|
|
23795
|
+
msgMetadata.organigramUpdate = organigramUpdate;
|
|
23796
|
+
}
|
|
23249
23797
|
if (missionPlan) {
|
|
23250
23798
|
msgMetadata.missionPlan = missionPlan;
|
|
23251
23799
|
}
|
|
@@ -23268,7 +23816,7 @@ ${historyLines.join("\n\n")}
|
|
|
23268
23816
|
(0, approvalPolicy_12.logDelegatedApproval)({ agentId: "coo", channelId: "chan_coo", action: skillAction });
|
|
23269
23817
|
}
|
|
23270
23818
|
}
|
|
23271
|
-
const needsApproval = !trustDelegated && !!trustUpdatePayload || !skillDelegated && !!skillWriteProposal || !!delegationRulePayload || !!missionPlan || !!nodeSpawnProposalId || remoteAgentProposals.length > 0;
|
|
23819
|
+
const needsApproval = !trustDelegated && !!trustUpdatePayload || !skillDelegated && !!skillWriteProposal || !!delegationRulePayload || !!organigramUpdate || !!missionPlan || !!nodeSpawnProposalId || remoteAgentProposals.length > 0;
|
|
23272
23820
|
const cooMsg = await db_12.db.message.create({
|
|
23273
23821
|
data: {
|
|
23274
23822
|
channelId: "chan_coo",
|
|
@@ -23335,6 +23883,26 @@ ${historyLines.join("\n\n")}
|
|
|
23335
23883
|
(0, ws_12.broadcast)({ type: "approval.created", payload: { approvalId: cooMsg.id, agentId: "coo", channelId: "chan_coo", priority: delPrio } });
|
|
23336
23884
|
(0, ws_12.broadcastToWorkspace)(ctx.workspaceId, { type: "delegationGraph.changed", payload: { workspaceId: ctx.workspaceId } });
|
|
23337
23885
|
}
|
|
23886
|
+
if (organigramUpdate) {
|
|
23887
|
+
const firstOp = organigramUpdate.operations[0];
|
|
23888
|
+
const orgPayload = {
|
|
23889
|
+
operations: organigramUpdate.operations,
|
|
23890
|
+
reason: organigramUpdate.reason ?? "",
|
|
23891
|
+
op: firstOp.op
|
|
23892
|
+
};
|
|
23893
|
+
const orgPrio = (0, approvalPolicy_12.classifyPriority)(`organigram:${firstOp.op}`, "organigram_update");
|
|
23894
|
+
const orgExpiry = (0, approvalPolicy_12.computeExpiresAt)(orgPrio);
|
|
23895
|
+
await db_12.db.approval.create({
|
|
23896
|
+
data: {
|
|
23897
|
+
messageId: cooMsg.id,
|
|
23898
|
+
type: "organigram_update",
|
|
23899
|
+
payload: JSON.stringify(orgPayload),
|
|
23900
|
+
priority: orgPrio,
|
|
23901
|
+
expiresAt: orgExpiry
|
|
23902
|
+
}
|
|
23903
|
+
});
|
|
23904
|
+
(0, ws_12.broadcast)({ type: "approval.created", payload: { approvalId: cooMsg.id, agentId: "coo", channelId: "chan_coo", priority: orgPrio } });
|
|
23905
|
+
}
|
|
23338
23906
|
(0, ws_12.broadcastToChannel)("chan_coo", { type: "message.new", payload: (0, messages_12.toMessage)(cooMsg) });
|
|
23339
23907
|
if (dispatchBlock) {
|
|
23340
23908
|
const plan = {
|
|
@@ -25219,139 +25787,6 @@ var require_shellExec2 = __commonJS({
|
|
|
25219
25787
|
}
|
|
25220
25788
|
});
|
|
25221
25789
|
|
|
25222
|
-
// apps/backend/dist/lib/organigramParse.js
|
|
25223
|
-
var require_organigramParse = __commonJS({
|
|
25224
|
-
"apps/backend/dist/lib/organigramParse.js"(exports2) {
|
|
25225
|
-
"use strict";
|
|
25226
|
-
Object.defineProperty(exports2, "__esModule", { value: true });
|
|
25227
|
-
exports2.parseOrganigram = parseOrganigram;
|
|
25228
|
-
var SECTION_TITLE_RE = /^(reporting|org\s*chart|structure|reporting\s+structure|hierarchy)\b/i;
|
|
25229
|
-
function extractSection(md, title) {
|
|
25230
|
-
const lines = md.split("\n");
|
|
25231
|
-
let start = -1;
|
|
25232
|
-
let end = lines.length;
|
|
25233
|
-
for (let i = 0; i < lines.length; i++) {
|
|
25234
|
-
const m = /^##\s+(.+?)\s*$/.exec(lines[i]);
|
|
25235
|
-
if (!m)
|
|
25236
|
-
continue;
|
|
25237
|
-
if (start === -1 && title.test(m[1])) {
|
|
25238
|
-
start = i + 1;
|
|
25239
|
-
continue;
|
|
25240
|
-
}
|
|
25241
|
-
if (start !== -1) {
|
|
25242
|
-
end = i;
|
|
25243
|
-
break;
|
|
25244
|
-
}
|
|
25245
|
-
}
|
|
25246
|
-
if (start === -1)
|
|
25247
|
-
return null;
|
|
25248
|
-
return lines.slice(start, end).join("\n");
|
|
25249
|
-
}
|
|
25250
|
-
function extractRef(rawLine) {
|
|
25251
|
-
let s = rawLine.replace(/[│├└─]/g, " ").replace(/^[\s\-*•◦]+/, "").replace(/[\[\]]/g, "").trim();
|
|
25252
|
-
if (!s)
|
|
25253
|
-
return null;
|
|
25254
|
-
const asciiStart = s.search(/[A-Za-z]/);
|
|
25255
|
-
if (asciiStart > 0)
|
|
25256
|
-
s = s.slice(asciiStart).trim();
|
|
25257
|
-
const idMatch = /\(([A-Za-z0-9][A-Za-z0-9_-]*)\)\s*$/.exec(s);
|
|
25258
|
-
const idHint = idMatch ? idMatch[1].toLowerCase() : null;
|
|
25259
|
-
const display = (idMatch ? s.slice(0, idMatch.index) : s).trim();
|
|
25260
|
-
if (!display && !idHint)
|
|
25261
|
-
return null;
|
|
25262
|
-
return { display, idHint };
|
|
25263
|
-
}
|
|
25264
|
-
function resolveAgent(ref, agents) {
|
|
25265
|
-
if (!ref)
|
|
25266
|
-
return null;
|
|
25267
|
-
if (ref.idHint) {
|
|
25268
|
-
const byId = agents.find((a) => a.id.toLowerCase() === ref.idHint);
|
|
25269
|
-
if (byId)
|
|
25270
|
-
return byId.id;
|
|
25271
|
-
}
|
|
25272
|
-
if (/^(human|user|owner|you|me)$/i.test(ref.display))
|
|
25273
|
-
return null;
|
|
25274
|
-
const norm = ref.display.toLowerCase().replace(/\s+/g, " ").trim();
|
|
25275
|
-
if (!norm)
|
|
25276
|
-
return null;
|
|
25277
|
-
const byName = agents.find((a) => a.name.toLowerCase() === norm);
|
|
25278
|
-
if (byName)
|
|
25279
|
-
return byName.id;
|
|
25280
|
-
const byPrefix = agents.find((a) => a.name.toLowerCase().startsWith(norm) || norm.startsWith(a.name.toLowerCase()));
|
|
25281
|
-
return byPrefix?.id ?? null;
|
|
25282
|
-
}
|
|
25283
|
-
function indentLevel(line) {
|
|
25284
|
-
const m = /^([\s│├└─]*)/.exec(line);
|
|
25285
|
-
if (!m)
|
|
25286
|
-
return 0;
|
|
25287
|
-
return Math.floor(m[1].length / 2);
|
|
25288
|
-
}
|
|
25289
|
-
function buildFlatFallback(agents) {
|
|
25290
|
-
const coo = agents.find((a) => a.id === "coo" || a.name.toLowerCase() === "coo");
|
|
25291
|
-
if (!coo)
|
|
25292
|
-
return [];
|
|
25293
|
-
const out = [{ parent: null, child: coo.id }];
|
|
25294
|
-
for (const a of agents) {
|
|
25295
|
-
if (a.id === coo.id)
|
|
25296
|
-
continue;
|
|
25297
|
-
out.push({ parent: coo.id, child: a.id });
|
|
25298
|
-
}
|
|
25299
|
-
return out;
|
|
25300
|
-
}
|
|
25301
|
-
function parseOrganigram(md, agents) {
|
|
25302
|
-
if (agents.length === 0)
|
|
25303
|
-
return [];
|
|
25304
|
-
const section = md ? extractSection(md, SECTION_TITLE_RE) : null;
|
|
25305
|
-
if (!section)
|
|
25306
|
-
return buildFlatFallback(agents);
|
|
25307
|
-
const lines = section.split("\n").filter((l) => l.trim().length > 0);
|
|
25308
|
-
if (lines.length === 0)
|
|
25309
|
-
return buildFlatFallback(agents);
|
|
25310
|
-
const edges = [];
|
|
25311
|
-
const stack = [];
|
|
25312
|
-
const seenChildren = /* @__PURE__ */ new Set();
|
|
25313
|
-
for (const raw of lines) {
|
|
25314
|
-
const level = indentLevel(raw);
|
|
25315
|
-
const ref = extractRef(raw);
|
|
25316
|
-
if (!ref)
|
|
25317
|
-
continue;
|
|
25318
|
-
const id = resolveAgent(ref, agents);
|
|
25319
|
-
const isHumanRoot = /^(human|user|owner|you|me)$/i.test(ref.display) && !ref.idHint;
|
|
25320
|
-
if (!id && !isHumanRoot)
|
|
25321
|
-
continue;
|
|
25322
|
-
while (stack.length > 0 && stack[stack.length - 1].level >= level)
|
|
25323
|
-
stack.pop();
|
|
25324
|
-
const parentNode = stack[stack.length - 1] ?? null;
|
|
25325
|
-
const parent = parentNode?.id ?? null;
|
|
25326
|
-
if (id) {
|
|
25327
|
-
if (!seenChildren.has(id)) {
|
|
25328
|
-
edges.push({ parent, child: id });
|
|
25329
|
-
seenChildren.add(id);
|
|
25330
|
-
}
|
|
25331
|
-
stack.push({ id, level });
|
|
25332
|
-
} else {
|
|
25333
|
-
stack.push({ id: null, level });
|
|
25334
|
-
}
|
|
25335
|
-
}
|
|
25336
|
-
if (edges.length === 0)
|
|
25337
|
-
return buildFlatFallback(agents);
|
|
25338
|
-
const flatHintMatch = /flat\s+delegation|all\s+(workspace\s+)?agents/i.test(section);
|
|
25339
|
-
if (flatHintMatch) {
|
|
25340
|
-
const rootAgentId = edges.find((e) => e.parent === null)?.child ?? (agents.find((a) => a.id === "coo")?.id ?? null);
|
|
25341
|
-
if (rootAgentId) {
|
|
25342
|
-
for (const a of agents) {
|
|
25343
|
-
if (seenChildren.has(a.id) || a.id === rootAgentId)
|
|
25344
|
-
continue;
|
|
25345
|
-
edges.push({ parent: rootAgentId, child: a.id });
|
|
25346
|
-
seenChildren.add(a.id);
|
|
25347
|
-
}
|
|
25348
|
-
}
|
|
25349
|
-
}
|
|
25350
|
-
return edges;
|
|
25351
|
-
}
|
|
25352
|
-
}
|
|
25353
|
-
});
|
|
25354
|
-
|
|
25355
25790
|
// apps/backend/dist/routers/delegations.js
|
|
25356
25791
|
var require_delegations = __commonJS({
|
|
25357
25792
|
"apps/backend/dist/routers/delegations.js"(exports2) {
|
|
@@ -25366,6 +25801,7 @@ var require_delegations = __commonJS({
|
|
|
25366
25801
|
var path_12 = require("path");
|
|
25367
25802
|
var os_12 = require("os");
|
|
25368
25803
|
var organigramParse_1 = require_organigramParse();
|
|
25804
|
+
var organigramWrite_1 = require_organigramWrite();
|
|
25369
25805
|
var ORGANIGRAM_PATH = (0, path_12.join)((0, os_12.homedir)(), ".openclaw", "agents", "coo", "ORGANIGRAM.md");
|
|
25370
25806
|
async function readOrganigramSafe() {
|
|
25371
25807
|
try {
|
|
@@ -25479,6 +25915,38 @@ var require_delegations = __commonJS({
|
|
|
25479
25915
|
await db_12.db.delegationRule.delete({ where: { id: input.id } });
|
|
25480
25916
|
(0, ws_12.broadcastToWorkspace)(ctx.workspaceId, { type: "delegationGraph.changed", payload: { workspaceId: ctx.workspaceId } });
|
|
25481
25917
|
}),
|
|
25918
|
+
// Canvas drag-to-reparent — the human IS the approver, so this is a
|
|
25919
|
+
// plain `protectedProcedure` mutation. Atomic-rewrites ORGANIGRAM.md's
|
|
25920
|
+
// `## Reporting Structure` section; preserves the rest of the file
|
|
25921
|
+
// verbatim. Broadcasts so all canvases refetch.
|
|
25922
|
+
reparent: trpc_12.protectedProcedure.input(zod_12.z.object({
|
|
25923
|
+
childAgentId: zod_12.z.string().min(1),
|
|
25924
|
+
// null = make child a root (reports to no one). Useful to demote a
|
|
25925
|
+
// sub-tree to root level or remove a reporting relationship.
|
|
25926
|
+
parentAgentId: zod_12.z.string().nullable()
|
|
25927
|
+
})).mutation(async ({ ctx, input }) => {
|
|
25928
|
+
const childAgent = await db_12.db.agent.findFirst({
|
|
25929
|
+
where: { id: input.childAgentId, workspaceId: ctx.workspaceId },
|
|
25930
|
+
select: { id: true }
|
|
25931
|
+
});
|
|
25932
|
+
if (!childAgent)
|
|
25933
|
+
throw new Error("Child agent not in this workspace");
|
|
25934
|
+
if (input.parentAgentId) {
|
|
25935
|
+
const parentAgent = await db_12.db.agent.findFirst({
|
|
25936
|
+
where: { id: input.parentAgentId, workspaceId: ctx.workspaceId },
|
|
25937
|
+
select: { id: true }
|
|
25938
|
+
});
|
|
25939
|
+
if (!parentAgent)
|
|
25940
|
+
throw new Error("Parent agent not in this workspace");
|
|
25941
|
+
if (input.parentAgentId === input.childAgentId)
|
|
25942
|
+
throw new Error("An agent cannot report to itself");
|
|
25943
|
+
}
|
|
25944
|
+
const result = await (0, organigramWrite_1.applyReparent)(input.childAgentId, input.parentAgentId, ctx.workspaceId);
|
|
25945
|
+
if (!result.ok)
|
|
25946
|
+
throw new Error(result.error);
|
|
25947
|
+
(0, ws_12.broadcastToWorkspace)(ctx.workspaceId, { type: "delegationGraph.changed", payload: { workspaceId: ctx.workspaceId } });
|
|
25948
|
+
return { ok: true };
|
|
25949
|
+
}),
|
|
25482
25950
|
// Team Canvas projection. Workspace-scoped read of the delegation/trust
|
|
25483
25951
|
// topology. Parses `delegate:*` patterns into edge / starburst / halo /
|
|
25484
25952
|
// full-mesh shapes server-side — the canvas layer never sees raw patterns.
|
|
@@ -31285,7 +31753,7 @@ var require_package = __commonJS({
|
|
|
31285
31753
|
module2.exports = {
|
|
31286
31754
|
name: "backend",
|
|
31287
31755
|
private: true,
|
|
31288
|
-
version: "0.
|
|
31756
|
+
version: "0.15.0",
|
|
31289
31757
|
scripts: {
|
|
31290
31758
|
dev: "tsx watch src/server.ts",
|
|
31291
31759
|
build: "tsc && rm -rf dist/resources && cp -r resources dist/resources",
|