@markus-global/cli 0.4.21 → 0.4.22
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/markus.mjs +220 -60
- package/dist/web-ui/assets/index-DEkXd9d7.css +1 -0
- package/dist/web-ui/assets/{index-BWjiUsem.js → index-HAWGXtTM.js} +40 -40
- package/dist/web-ui/index.html +2 -2
- package/package.json +1 -1
- package/templates/skills/agent-building/SKILL.md +5 -5
- package/templates/skills/self-evolution/SKILL.md +43 -7
- package/templates/skills/team-building/SKILL.md +4 -5
- package/dist/web-ui/assets/index-BgcwiZ1h.css +0 -1
package/dist/markus.mjs
CHANGED
|
@@ -3566,7 +3566,7 @@ function buildManifest(type, raw) {
|
|
|
3566
3566
|
if (type === "agent") {
|
|
3567
3567
|
const agentRaw = raw.agent ?? raw;
|
|
3568
3568
|
base.agent = {
|
|
3569
|
-
roleName: agentRaw.roleName
|
|
3569
|
+
roleName: agentRaw.roleName || raw.roleName || void 0,
|
|
3570
3570
|
agentRole: agentRaw.agentRole ?? raw.agentRole ?? "worker",
|
|
3571
3571
|
llmProvider: agentRaw.llmProvider || raw.llmProvider || void 0,
|
|
3572
3572
|
llmModel: agentRaw.llmModel || raw.llmModel || void 0,
|
|
@@ -3585,7 +3585,7 @@ function buildManifest(type, raw) {
|
|
|
3585
3585
|
members: rawMembers.map((m) => ({
|
|
3586
3586
|
name: m.name ?? "Agent",
|
|
3587
3587
|
role: m.role ?? "worker",
|
|
3588
|
-
roleName: m.roleName
|
|
3588
|
+
roleName: m.roleName || void 0,
|
|
3589
3589
|
count: m.count ?? 1,
|
|
3590
3590
|
skills: toArr(m.skills).length > 0 ? toArr(m.skills) : void 0
|
|
3591
3591
|
}))
|
|
@@ -3652,8 +3652,8 @@ function validateManifest(m) {
|
|
|
3652
3652
|
errors.push("version must be semver (e.g. 1.0.0)");
|
|
3653
3653
|
if (o.type === "agent" && o.agent) {
|
|
3654
3654
|
const a = o.agent;
|
|
3655
|
-
if (
|
|
3656
|
-
errors.push("agent.roleName
|
|
3655
|
+
if (a.roleName !== void 0 && typeof a.roleName !== "string")
|
|
3656
|
+
errors.push("agent.roleName must be a string if provided");
|
|
3657
3657
|
}
|
|
3658
3658
|
if (o.type === "team" && o.team) {
|
|
3659
3659
|
const t = o.team;
|
|
@@ -3662,10 +3662,12 @@ function validateManifest(m) {
|
|
|
3662
3662
|
}
|
|
3663
3663
|
return errors;
|
|
3664
3664
|
}
|
|
3665
|
-
function kebab(s) {
|
|
3665
|
+
function kebab(s, fallback) {
|
|
3666
3666
|
const result = s.toLowerCase().replace(/\s+/g, "-").replace(/[^a-z0-9-]/g, "").replace(/^-+|-+$/g, "");
|
|
3667
3667
|
if (result)
|
|
3668
3668
|
return result;
|
|
3669
|
+
if (fallback)
|
|
3670
|
+
return fallback;
|
|
3669
3671
|
let hash = 0;
|
|
3670
3672
|
for (let i = 0; i < s.length; i++)
|
|
3671
3673
|
hash = (hash << 5) - hash + s.charCodeAt(i) | 0;
|
|
@@ -4409,6 +4411,7 @@ __export(dist_exports, {
|
|
|
4409
4411
|
getTextContent: () => getTextContent,
|
|
4410
4412
|
isPlaceholder: () => isPlaceholder,
|
|
4411
4413
|
isValidTaskTransition: () => isValidTaskTransition,
|
|
4414
|
+
kebab: () => kebab,
|
|
4412
4415
|
loadConfig: () => loadConfig,
|
|
4413
4416
|
manifestFilename: () => manifestFilename,
|
|
4414
4417
|
msgId: () => msgId,
|
|
@@ -45193,6 +45196,7 @@ ${notification.stdoutTail}`);
|
|
|
45193
45196
|
});
|
|
45194
45197
|
});
|
|
45195
45198
|
const roleFilePath = join10(this.dataDir, "role", "ROLE.md");
|
|
45199
|
+
const heartbeatFilePath = join10(this.dataDir, "role", "HEARTBEAT.md");
|
|
45196
45200
|
this.toolHooks.register({
|
|
45197
45201
|
name: "role-auto-reload",
|
|
45198
45202
|
after: async (ctx) => {
|
|
@@ -45202,6 +45206,10 @@ ${notification.stdoutTail}`);
|
|
|
45202
45206
|
log17.info("Agent modified its own ROLE.md \u2014 reloading role definition");
|
|
45203
45207
|
this.reloadRole();
|
|
45204
45208
|
}
|
|
45209
|
+
if (targetPath === heartbeatFilePath || targetPath.endsWith("/role/HEARTBEAT.md")) {
|
|
45210
|
+
log17.info("Agent modified its own HEARTBEAT.md \u2014 reloading heartbeat checklist");
|
|
45211
|
+
this.reloadHeartbeat();
|
|
45212
|
+
}
|
|
45205
45213
|
}
|
|
45206
45214
|
}
|
|
45207
45215
|
});
|
|
@@ -45710,6 +45718,25 @@ ${notification.stdoutTail}`);
|
|
|
45710
45718
|
log17.warn(`Failed to reload role for agent ${this.config.name}`, { error: String(err) });
|
|
45711
45719
|
}
|
|
45712
45720
|
}
|
|
45721
|
+
/**
|
|
45722
|
+
* Reload the agent's heartbeat checklist from its HEARTBEAT.md file on disk.
|
|
45723
|
+
* Called when the agent modifies its own HEARTBEAT.md via file_edit/file_write.
|
|
45724
|
+
*/
|
|
45725
|
+
reloadHeartbeat() {
|
|
45726
|
+
const heartbeatFile = join10(this.dataDir, "role", "HEARTBEAT.md");
|
|
45727
|
+
if (!existsSync15(heartbeatFile))
|
|
45728
|
+
return;
|
|
45729
|
+
try {
|
|
45730
|
+
const content = readFileSync10(heartbeatFile, "utf-8");
|
|
45731
|
+
this.role = {
|
|
45732
|
+
...this.role,
|
|
45733
|
+
heartbeatChecklist: content
|
|
45734
|
+
};
|
|
45735
|
+
log17.info(`Heartbeat checklist reloaded from disk for agent ${this.config.name}`);
|
|
45736
|
+
} catch (err) {
|
|
45737
|
+
log17.warn(`Failed to reload heartbeat for agent ${this.config.name}`, { error: String(err) });
|
|
45738
|
+
}
|
|
45739
|
+
}
|
|
45713
45740
|
/**
|
|
45714
45741
|
* Start a fresh conversation session, discarding the current in-memory session context.
|
|
45715
45742
|
* Called when the user explicitly starts a "New Chat".
|
|
@@ -48627,6 +48654,10 @@ ${todayLog.slice(0, HEARTBEAT_DAILY_LOG_CHARS)}
|
|
|
48627
48654
|
'- Check existing skills first: `discover_tools({ mode: "list_skills" })` and `builder_list`.',
|
|
48628
48655
|
"- To update an existing skill: edit files in `~/.markus/builder-artifacts/skills/{name}/`, bump version, re-install with `builder_install`.",
|
|
48629
48656
|
"",
|
|
48657
|
+
"**Direct self-evolution** (simplest and most impactful):",
|
|
48658
|
+
"- **Update ROLE.md** \u2014 When you discover a behavioral rule, working style, or guiding principle that should always apply, append it to your ROLE.md via `file_edit`. ROLE.md is loaded into every conversation, so changes take effect immediately. Read first, then append. No need to accumulate 3 insights \u2014 even a single validated lesson can warrant a role update if it is fundamental.",
|
|
48659
|
+
"- **Update HEARTBEAT.md** \u2014 When you realize your patrol routine should include a new recurring check (or remove an obsolete one), modify your HEARTBEAT.md via `file_edit`. This is your personal checklist \u2014 customize it to match your actual responsibilities. Changes take effect at the next heartbeat.",
|
|
48660
|
+
"",
|
|
48630
48661
|
"**Decision guide \u2014 where does this insight go?**",
|
|
48631
48662
|
"| Observation type | Action |",
|
|
48632
48663
|
"|---|---|",
|
|
@@ -48634,7 +48665,8 @@ ${todayLog.slice(0, HEARTBEAT_DAILY_LOG_CHARS)}
|
|
|
48634
48665
|
'| Tool tip or preference | `memory_save` with tags: `["insight", "tool:<name>"]` |',
|
|
48635
48666
|
'| Multi-step repeatable workflow | `memory_update_longterm({ section: "procedures", mode: "patch" })` |',
|
|
48636
48667
|
"| Practice worth sharing with the team | Create skill via **skill-building**, then install with `builder_install` |",
|
|
48637
|
-
"|
|
|
48668
|
+
"| Behavioral rule or guiding principle | Update ROLE.md (`file_read` \u2192 `file_edit` to append) |",
|
|
48669
|
+
"| New recurring check for your patrol | Update HEARTBEAT.md (`file_read` \u2192 `file_edit`) |",
|
|
48638
48670
|
"",
|
|
48639
48671
|
"Quality bar: Only record insights that are **specific**, **actionable**, and **non-obvious**.",
|
|
48640
48672
|
"Skip if nothing meaningful happened since last heartbeat."
|
|
@@ -48662,7 +48694,8 @@ ${todayLog.slice(0, HEARTBEAT_DAILY_LOG_CHARS)}
|
|
|
48662
48694
|
"- Tasks with `executionRound > 1` required revision \u2014 your initial approach had issues.",
|
|
48663
48695
|
"- A high revision rate (>30%) suggests your knowledge is not being applied effectively.",
|
|
48664
48696
|
"- Check: does your MEMORY.md knowledge actually cover the failure patterns you see?",
|
|
48665
|
-
"- If you keep making the same type of mistake, escalate: save as insight \u2192 add to MEMORY.md \u2192 update ROLE.md."
|
|
48697
|
+
"- If you keep making the same type of mistake, escalate: save as insight \u2192 add to MEMORY.md \u2192 update ROLE.md or HEARTBEAT.md.",
|
|
48698
|
+
"- Consider: would a ROLE.md rule or a HEARTBEAT.md check have prevented any recent failures?"
|
|
48666
48699
|
].join("\n");
|
|
48667
48700
|
const prompt = [
|
|
48668
48701
|
"[HEARTBEAT CHECK-IN]",
|
|
@@ -53209,24 +53242,39 @@ Priority: ${delegation.priority}`, envelope.from, { name: envelope.from, role: "
|
|
|
53209
53242
|
if (!request.name?.trim())
|
|
53210
53243
|
throw new Error("Agent name is required");
|
|
53211
53244
|
const id = agentId();
|
|
53212
|
-
const
|
|
53245
|
+
const roleName = request.roleName || "custom";
|
|
53246
|
+
const isCustomRole = roleName === "custom";
|
|
53247
|
+
const role = isCustomRole ? {
|
|
53248
|
+
id: generateId("role"),
|
|
53249
|
+
name: request.name,
|
|
53250
|
+
description: "",
|
|
53251
|
+
category: "custom",
|
|
53252
|
+
systemPrompt: `# ${request.name}
|
|
53253
|
+
|
|
53254
|
+
You are ${request.name}.`,
|
|
53255
|
+
defaultSkills: [],
|
|
53256
|
+
heartbeatChecklist: "",
|
|
53257
|
+
defaultPolicies: [],
|
|
53258
|
+
builtIn: false
|
|
53259
|
+
} : this.roleLoader.loadRole(roleName);
|
|
53213
53260
|
const agentDataDir = join13(this.dataDir, id);
|
|
53214
53261
|
mkdirSync12(agentDataDir, { recursive: true });
|
|
53215
53262
|
const agentRoleDir = join13(agentDataDir, "role");
|
|
53216
53263
|
mkdirSync12(agentRoleDir, { recursive: true });
|
|
53217
|
-
|
|
53218
|
-
|
|
53219
|
-
|
|
53220
|
-
const
|
|
53221
|
-
|
|
53222
|
-
|
|
53264
|
+
if (!isCustomRole && !request.skipTemplateCopy) {
|
|
53265
|
+
const templateDir = this.roleLoader.resolveTemplateDir(roleName);
|
|
53266
|
+
if (templateDir) {
|
|
53267
|
+
for (const file of ["ROLE.md", "HEARTBEAT.md", "POLICIES.md", "CONTEXT.md"]) {
|
|
53268
|
+
const src = join13(templateDir, file);
|
|
53269
|
+
if (existsSync18(src))
|
|
53270
|
+
copyFileSync(src, join13(agentRoleDir, file));
|
|
53271
|
+
}
|
|
53223
53272
|
}
|
|
53224
53273
|
}
|
|
53225
53274
|
const config = {
|
|
53226
53275
|
id,
|
|
53227
53276
|
name: request.name,
|
|
53228
|
-
|
|
53229
|
-
roleId: request.roleName,
|
|
53277
|
+
roleId: roleName,
|
|
53230
53278
|
orgId: request.orgId ?? "default",
|
|
53231
53279
|
teamId: request.teamId,
|
|
53232
53280
|
agentRole: request.agentRole ?? "worker",
|
|
@@ -53742,6 +53790,20 @@ Known issues: ${knownIssues}` : ""}`
|
|
|
53742
53790
|
let role;
|
|
53743
53791
|
if (existsSync18(join13(agentRoleDir, "ROLE.md"))) {
|
|
53744
53792
|
role = this.roleLoader.loadRole(agentRoleDir);
|
|
53793
|
+
} else if (row.roleId === "custom") {
|
|
53794
|
+
role = {
|
|
53795
|
+
id: generateId("role"),
|
|
53796
|
+
name: row.name,
|
|
53797
|
+
description: "",
|
|
53798
|
+
category: "custom",
|
|
53799
|
+
systemPrompt: `# ${row.name}
|
|
53800
|
+
|
|
53801
|
+
You are ${row.name}.`,
|
|
53802
|
+
defaultSkills: [],
|
|
53803
|
+
heartbeatChecklist: "",
|
|
53804
|
+
defaultPolicies: [],
|
|
53805
|
+
builtIn: false
|
|
53806
|
+
};
|
|
53745
53807
|
} else {
|
|
53746
53808
|
role = (() => {
|
|
53747
53809
|
try {
|
|
@@ -58049,7 +58111,7 @@ var init_registry = __esm({
|
|
|
58049
58111
|
skills = /* @__PURE__ */ new Map();
|
|
58050
58112
|
aliases = /* @__PURE__ */ new Map();
|
|
58051
58113
|
static normalize(s) {
|
|
58052
|
-
return
|
|
58114
|
+
return kebab(s);
|
|
58053
58115
|
}
|
|
58054
58116
|
register(skill) {
|
|
58055
58117
|
const name = skill.manifest.name;
|
|
@@ -59794,15 +59856,17 @@ var init_org_service = __esm({
|
|
|
59794
59856
|
}
|
|
59795
59857
|
}
|
|
59796
59858
|
this.refreshIdentityContextsForOrg(request.orgId);
|
|
59797
|
-
|
|
59798
|
-
|
|
59799
|
-
|
|
59800
|
-
|
|
59801
|
-
|
|
59802
|
-
|
|
59803
|
-
|
|
59804
|
-
|
|
59805
|
-
|
|
59859
|
+
if (!request.skipAutoStart) {
|
|
59860
|
+
try {
|
|
59861
|
+
await this.agentManager.startAgent(agent.id);
|
|
59862
|
+
log50.info(`Agent onboarded: ${request.name} (auto-started)`, {
|
|
59863
|
+
orgId: request.orgId,
|
|
59864
|
+
agentId: agent.id,
|
|
59865
|
+
agentRole: request.agentRole ?? "worker"
|
|
59866
|
+
});
|
|
59867
|
+
} catch (error) {
|
|
59868
|
+
log50.warn(`Agent created but auto-start failed: ${request.name}`, { error: String(error) });
|
|
59869
|
+
}
|
|
59806
59870
|
}
|
|
59807
59871
|
return agent;
|
|
59808
59872
|
}
|
|
@@ -60125,9 +60189,9 @@ var init_org_service = __esm({
|
|
|
60125
60189
|
const roleNames = this.listAvailableRoles();
|
|
60126
60190
|
if (roleNames.length > 0) {
|
|
60127
60191
|
parts.push("");
|
|
60128
|
-
parts.push("##
|
|
60192
|
+
parts.push("## Built-in Role Templates (for reference only)");
|
|
60129
60193
|
parts.push("");
|
|
60130
|
-
parts.push("
|
|
60194
|
+
parts.push("These templates are available for reading as **reference** when writing custom ROLE.md files. You do NOT need to set `roleName` \u2014 the agent's identity is fully defined by its ROLE.md.");
|
|
60131
60195
|
parts.push("");
|
|
60132
60196
|
for (const r of roleNames) {
|
|
60133
60197
|
parts.push(`- \`${r}\``);
|
|
@@ -60135,9 +60199,9 @@ var init_org_service = __esm({
|
|
|
60135
60199
|
const templateDirs = this.roleLoader.getTemplateDirs();
|
|
60136
60200
|
if (templateDirs.length > 0) {
|
|
60137
60201
|
parts.push("");
|
|
60138
|
-
parts.push("**Tip**:
|
|
60202
|
+
parts.push("**Tip**: Read existing templates for inspiration when writing custom ROLE.md files.");
|
|
60139
60203
|
parts.push(`Use \`file_read\` to inspect any template, e.g.: \`file_read("${templateDirs[0]}/developer/ROLE.md")\``);
|
|
60140
|
-
parts.push("This is
|
|
60204
|
+
parts.push("This is useful for understanding the level of detail and workflow guidance expected in a good ROLE.md.");
|
|
60141
60205
|
}
|
|
60142
60206
|
}
|
|
60143
60207
|
parts.push("");
|
|
@@ -62714,7 +62778,11 @@ Action: ${guidance}` : ""
|
|
|
62714
62778
|
"",
|
|
62715
62779
|
'Save each lesson using `memory_save` with tags `["lesson", ...]`.',
|
|
62716
62780
|
'If it is a repeatable multi-step procedure, promote to SOP via `memory_update_longterm({ section: "sops", mode: "patch" })`.',
|
|
62717
|
-
"If the best practice would benefit other agents on the team, create a shareable skill via **skill-building** and install it with `builder_install`."
|
|
62781
|
+
"If the best practice would benefit other agents on the team, create a shareable skill via **skill-building** and install it with `builder_install`.",
|
|
62782
|
+
"",
|
|
62783
|
+
"**Direct self-evolution** \u2014 consider the simplest, most impactful options:",
|
|
62784
|
+
"- If this lesson reveals a behavioral rule that should always guide your work, append it to your ROLE.md via `file_edit`.",
|
|
62785
|
+
"- If you should be checking for this class of issue regularly, add a check to your HEARTBEAT.md via `file_edit`."
|
|
62718
62786
|
].join("\n") : [
|
|
62719
62787
|
"[SELF-EVOLUTION \u2014 Post-Task Reflection (Success)]",
|
|
62720
62788
|
"",
|
|
@@ -62731,6 +62799,11 @@ Action: ${guidance}` : ""
|
|
|
62731
62799
|
'If you identify a meaningful insight, save it using `memory_save` with tags `["lesson", "best-practice", ...]`.',
|
|
62732
62800
|
'If it is a multi-step workflow, promote to SOP via `memory_update_longterm({ section: "sops", mode: "patch" })`.',
|
|
62733
62801
|
"If worth sharing with the team, create a skill via **skill-building** and install with `builder_install`.",
|
|
62802
|
+
"",
|
|
62803
|
+
"**Direct self-evolution** \u2014 consider the simplest, most impactful options:",
|
|
62804
|
+
"- If this success reveals a guiding principle or working style worth keeping, append it to your ROLE.md via `file_edit`.",
|
|
62805
|
+
"- If there is a periodic check that would help maintain this quality, add it to your HEARTBEAT.md via `file_edit`.",
|
|
62806
|
+
"",
|
|
62734
62807
|
"If nothing noteworthy stands out, it is fine to skip saving."
|
|
62735
62808
|
].join("\n");
|
|
62736
62809
|
void agent.sendMessage(prompt, void 0, void 0, {
|
|
@@ -63413,7 +63486,7 @@ ${task.description}`;
|
|
|
63413
63486
|
|
|
63414
63487
|
// ../org-manager/dist/builder-service.js
|
|
63415
63488
|
import { join as join21 } from "node:path";
|
|
63416
|
-
import { readdirSync as readdirSync8, readFileSync as readFileSync19, existsSync as existsSync25, writeFileSync as writeFileSync14, mkdirSync as mkdirSync17, copyFileSync as copyFileSync2, statSync as statSync4 } from "node:fs";
|
|
63489
|
+
import { readdirSync as readdirSync8, readFileSync as readFileSync19, existsSync as existsSync25, writeFileSync as writeFileSync14, mkdirSync as mkdirSync17, copyFileSync as copyFileSync2, statSync as statSync4, cpSync as cpSync2 } from "node:fs";
|
|
63417
63490
|
import { homedir as homedir12 } from "node:os";
|
|
63418
63491
|
var log52, FS_HELPER, BuilderService;
|
|
63419
63492
|
var init_builder_service = __esm({
|
|
@@ -63497,17 +63570,17 @@ var init_builder_service = __esm({
|
|
|
63497
63570
|
async installAgent(artDir, manifest, mfName, artifactName) {
|
|
63498
63571
|
const agentManager = this.orgService.getAgentManager();
|
|
63499
63572
|
const agentName = manifest.displayName ?? manifest.name ?? artifactName;
|
|
63500
|
-
const
|
|
63501
|
-
const requestedRole = manifest.agent?.roleName ?? "developer";
|
|
63502
|
-
const roleName = knownRoles.includes(requestedRole) ? requestedRole : "developer";
|
|
63573
|
+
const hasCustomRole = existsSync25(join21(artDir, "ROLE.md"));
|
|
63503
63574
|
const skills = manifest.dependencies?.skills ?? [];
|
|
63504
63575
|
const agentRole = manifest.agent?.agentRole ?? "worker";
|
|
63505
63576
|
const agent = await this.orgService.hireAgent({
|
|
63506
63577
|
name: agentName,
|
|
63507
|
-
roleName,
|
|
63578
|
+
roleName: manifest.agent?.roleName || (hasCustomRole ? "custom" : "developer"),
|
|
63508
63579
|
orgId: "default",
|
|
63509
63580
|
agentRole,
|
|
63510
|
-
skills
|
|
63581
|
+
skills,
|
|
63582
|
+
skipAutoStart: true,
|
|
63583
|
+
skipTemplateCopy: hasCustomRole
|
|
63511
63584
|
});
|
|
63512
63585
|
const agentRoleDir = join21(agentManager.getDataDir(), agent.id, "role");
|
|
63513
63586
|
mkdirSync17(agentRoleDir, { recursive: true });
|
|
@@ -63547,38 +63620,42 @@ var init_builder_service = __esm({
|
|
|
63547
63620
|
const norms = existsSync25(normsPath) ? readFileSync19(normsPath, "utf-8") : "";
|
|
63548
63621
|
this.orgService.ensureTeamDataDir(team.id, announcements, norms);
|
|
63549
63622
|
const members = manifest.team?.members ?? [];
|
|
63550
|
-
const knownRoles = this.orgService.listAvailableRoles();
|
|
63551
63623
|
const createdAgents = [];
|
|
63624
|
+
const usedMemberDirs = /* @__PURE__ */ new Set();
|
|
63552
63625
|
for (const member of members) {
|
|
63553
63626
|
const count = member.count ?? 1;
|
|
63554
63627
|
const memberRole = member.role ?? "worker";
|
|
63555
63628
|
const memberName = member.name ?? "Agent";
|
|
63556
|
-
const roleName = knownRoles.includes(member.roleName) ? member.roleName : "developer";
|
|
63557
63629
|
const memberSkills = member.skills ?? [];
|
|
63558
|
-
const
|
|
63559
|
-
const
|
|
63630
|
+
const memberFilesDir = this.findMemberDir(artDir, memberName, usedMemberDirs);
|
|
63631
|
+
const hasCustomRole = !!memberFilesDir && existsSync25(join21(memberFilesDir, "ROLE.md"));
|
|
63632
|
+
if (memberFilesDir)
|
|
63633
|
+
usedMemberDirs.add(memberFilesDir);
|
|
63634
|
+
log52.info("installTeam: member lookup", { memberName, memberFilesDir, hasCustomRole });
|
|
63560
63635
|
for (let i = 0; i < count; i++) {
|
|
63561
63636
|
const displayName = count > 1 ? `${memberName} ${i + 1}` : memberName;
|
|
63562
63637
|
const agent = await this.orgService.hireAgent({
|
|
63563
63638
|
name: displayName,
|
|
63564
|
-
roleName,
|
|
63639
|
+
roleName: member.roleName || (hasCustomRole ? "custom" : "developer"),
|
|
63565
63640
|
orgId: "default",
|
|
63566
63641
|
teamId: team.id,
|
|
63567
63642
|
agentRole: memberRole,
|
|
63568
|
-
skills: memberSkills.length > 0 ? memberSkills : void 0
|
|
63643
|
+
skills: memberSkills.length > 0 ? memberSkills : void 0,
|
|
63644
|
+
skipAutoStart: true,
|
|
63645
|
+
skipTemplateCopy: hasCustomRole
|
|
63569
63646
|
});
|
|
63570
63647
|
const agentRoleDir = join21(agentManager.getDataDir(), agent.id, "role");
|
|
63571
63648
|
mkdirSync17(agentRoleDir, { recursive: true });
|
|
63572
|
-
if (existsSync25(memberFilesDir)) {
|
|
63649
|
+
if (memberFilesDir && existsSync25(memberFilesDir)) {
|
|
63573
63650
|
for (const fname of readdirSync8(memberFilesDir)) {
|
|
63574
63651
|
const srcFile = join21(memberFilesDir, fname);
|
|
63575
63652
|
if (statSync4(srcFile).isFile()) {
|
|
63576
63653
|
copyFileSync2(srcFile, join21(agentRoleDir, fname));
|
|
63577
63654
|
}
|
|
63578
63655
|
}
|
|
63579
|
-
agent.reloadRole();
|
|
63580
63656
|
}
|
|
63581
63657
|
writeFileSync14(join21(agentRoleDir, ".role-origin.json"), JSON.stringify({ customRole: true, source: "builder-artifact", artifact: artifactName, artifactType: "team" }));
|
|
63658
|
+
agent.reloadRole();
|
|
63582
63659
|
if (memberRole === "manager") {
|
|
63583
63660
|
await this.orgService.updateTeam(team.id, { managerId: agent.id, managerType: "agent" });
|
|
63584
63661
|
}
|
|
@@ -63591,13 +63668,56 @@ var init_builder_service = __esm({
|
|
|
63591
63668
|
installed: { team: { id: team.id, name: teamName }, agents: createdAgents }
|
|
63592
63669
|
};
|
|
63593
63670
|
}
|
|
63671
|
+
/**
|
|
63672
|
+
* Find the member directory under artDir/members/ by trying multiple slug strategies.
|
|
63673
|
+
* Returns the absolute path to the member directory, or null if not found.
|
|
63674
|
+
*/
|
|
63675
|
+
findMemberDir(artDir, memberName, usedDirs) {
|
|
63676
|
+
const membersBase = join21(artDir, "members");
|
|
63677
|
+
if (!existsSync25(membersBase))
|
|
63678
|
+
return null;
|
|
63679
|
+
const slug = kebab(memberName, "agent");
|
|
63680
|
+
const exact = join21(membersBase, slug);
|
|
63681
|
+
if (existsSync25(exact) && !usedDirs.has(exact))
|
|
63682
|
+
return exact;
|
|
63683
|
+
try {
|
|
63684
|
+
for (const entry of readdirSync8(membersBase, { withFileTypes: true })) {
|
|
63685
|
+
if (!entry.isDirectory())
|
|
63686
|
+
continue;
|
|
63687
|
+
const candidateDir = join21(membersBase, entry.name);
|
|
63688
|
+
if (usedDirs.has(candidateDir))
|
|
63689
|
+
continue;
|
|
63690
|
+
const rolePath = join21(candidateDir, "ROLE.md");
|
|
63691
|
+
if (!existsSync25(rolePath))
|
|
63692
|
+
continue;
|
|
63693
|
+
try {
|
|
63694
|
+
const content = readFileSync19(rolePath, "utf-8");
|
|
63695
|
+
const title = content.match(/^#\s+(.+)$/m)?.[1]?.trim();
|
|
63696
|
+
if (title && title.toLowerCase() === memberName.toLowerCase())
|
|
63697
|
+
return candidateDir;
|
|
63698
|
+
} catch {
|
|
63699
|
+
}
|
|
63700
|
+
}
|
|
63701
|
+
} catch {
|
|
63702
|
+
}
|
|
63703
|
+
try {
|
|
63704
|
+
const remaining = readdirSync8(membersBase, { withFileTypes: true }).filter((e) => e.isDirectory() && !usedDirs.has(join21(membersBase, e.name)));
|
|
63705
|
+
if (remaining.length === 1)
|
|
63706
|
+
return join21(membersBase, remaining[0].name);
|
|
63707
|
+
} catch {
|
|
63708
|
+
}
|
|
63709
|
+
return null;
|
|
63710
|
+
}
|
|
63594
63711
|
async installSkill(artDir, manifest, artifactName) {
|
|
63595
63712
|
const skillDir = join21(homedir12(), ".markus", "skills", artifactName);
|
|
63596
63713
|
mkdirSync17(skillDir, { recursive: true });
|
|
63597
63714
|
for (const fname of readdirSync8(artDir)) {
|
|
63598
63715
|
const srcFile = join21(artDir, fname);
|
|
63716
|
+
const destFile = join21(skillDir, fname);
|
|
63599
63717
|
if (statSync4(srcFile).isFile()) {
|
|
63600
|
-
copyFileSync2(srcFile,
|
|
63718
|
+
copyFileSync2(srcFile, destFile);
|
|
63719
|
+
} else if (statSync4(srcFile).isDirectory()) {
|
|
63720
|
+
cpSync2(srcFile, destFile, { recursive: true });
|
|
63601
63721
|
}
|
|
63602
63722
|
}
|
|
63603
63723
|
if (this.skillRegistry) {
|
|
@@ -64876,7 +64996,7 @@ var init_api_server = __esm({
|
|
|
64876
64996
|
throw new Error(`Hub download failed: ${res.status}`);
|
|
64877
64997
|
const data = await res.json();
|
|
64878
64998
|
const name = data.name;
|
|
64879
|
-
const slug = name
|
|
64999
|
+
const slug = kebab(name, "hub-pkg");
|
|
64880
65000
|
const mode = data.itemType === "team" ? "team" : data.itemType === "skill" ? "skill" : "agent";
|
|
64881
65001
|
const typeDir = mode === "agent" ? "agents" : mode === "team" ? "teams" : "skills";
|
|
64882
65002
|
const artDir = join23(homedir14(), ".markus", "builder-artifacts", typeDir, slug);
|
|
@@ -65705,13 +65825,9 @@ var init_api_server = __esm({
|
|
|
65705
65825
|
this.json(res, 400, { error: "name is required" });
|
|
65706
65826
|
return;
|
|
65707
65827
|
}
|
|
65708
|
-
if (!roleName?.trim()) {
|
|
65709
|
-
this.json(res, 400, { error: "roleName is required" });
|
|
65710
|
-
return;
|
|
65711
|
-
}
|
|
65712
65828
|
const agent = await this.orgService.hireAgent({
|
|
65713
65829
|
name: agentName,
|
|
65714
|
-
roleName,
|
|
65830
|
+
roleName: roleName?.trim() || void 0,
|
|
65715
65831
|
orgId: body["orgId"] ?? "default",
|
|
65716
65832
|
teamId: body["teamId"],
|
|
65717
65833
|
skills: body["skills"],
|
|
@@ -66685,7 +66801,7 @@ var init_api_server = __esm({
|
|
|
66685
66801
|
const roleDir = this.resolveAgentRoleDir(agent);
|
|
66686
66802
|
if (!roleDir)
|
|
66687
66803
|
continue;
|
|
66688
|
-
const slug = agent.config.name
|
|
66804
|
+
const slug = kebab(agent.config.name, agentId2);
|
|
66689
66805
|
for (const fname of roleFileNames) {
|
|
66690
66806
|
const fpath = join23(roleDir, fname);
|
|
66691
66807
|
if (existsSync27(fpath)) {
|
|
@@ -68363,7 +68479,7 @@ EXPLANATION_END`;
|
|
|
68363
68479
|
const rawMembers = Array.isArray(artifact.team?.members) ? artifact.team.members : Array.isArray(artifact.members) ? artifact.members : [];
|
|
68364
68480
|
for (const m of rawMembers) {
|
|
68365
68481
|
const mName = m.name ?? "Agent";
|
|
68366
|
-
const slug = mName
|
|
68482
|
+
const slug = kebab(mName, "agent");
|
|
68367
68483
|
const memberDir = join23(artDir, "members", slug);
|
|
68368
68484
|
const roleContent = m.roleContent || m.role_md;
|
|
68369
68485
|
const policiesContent = m.policiesContent || m.policies_md;
|
|
@@ -69168,11 +69284,18 @@ EXPLANATION_END`;
|
|
|
69168
69284
|
"Content-Type": "application/json",
|
|
69169
69285
|
"Authorization": `Bearer ${hubToken}`
|
|
69170
69286
|
};
|
|
69171
|
-
|
|
69287
|
+
let hubRes = await fetch(`${hubUrl}/api/items`, {
|
|
69172
69288
|
method: "POST",
|
|
69173
69289
|
headers,
|
|
69174
|
-
body: JSON.stringify(body["payload"])
|
|
69290
|
+
body: JSON.stringify(body["payload"]),
|
|
69291
|
+
redirect: "manual"
|
|
69175
69292
|
});
|
|
69293
|
+
if (hubRes.status >= 300 && hubRes.status < 400) {
|
|
69294
|
+
const location = hubRes.headers.get("location");
|
|
69295
|
+
if (location) {
|
|
69296
|
+
hubRes = await fetch(location, { method: "POST", headers, body: JSON.stringify(body["payload"]), redirect: "manual" });
|
|
69297
|
+
}
|
|
69298
|
+
}
|
|
69176
69299
|
const hubData = await hubRes.json();
|
|
69177
69300
|
this.json(res, hubRes.status, hubData);
|
|
69178
69301
|
} catch (err) {
|
|
@@ -69180,6 +69303,43 @@ EXPLANATION_END`;
|
|
|
69180
69303
|
}
|
|
69181
69304
|
return;
|
|
69182
69305
|
}
|
|
69306
|
+
if (path.startsWith("/api/hub/")) {
|
|
69307
|
+
const hubPath = path.slice("/api/hub".length);
|
|
69308
|
+
const reqUrl = new URL(req.url, `http://${req.headers.host}`);
|
|
69309
|
+
const hubTargetUrl = `${this.hubUrl}/api${hubPath}${reqUrl.search}`;
|
|
69310
|
+
const proxyHeaders = { "Content-Type": "application/json" };
|
|
69311
|
+
const authHeader = req.headers["authorization"];
|
|
69312
|
+
if (authHeader)
|
|
69313
|
+
proxyHeaders["Authorization"] = authHeader;
|
|
69314
|
+
try {
|
|
69315
|
+
let body;
|
|
69316
|
+
if (req.method === "POST" || req.method === "PUT" || req.method === "PATCH") {
|
|
69317
|
+
body = JSON.stringify(await this.readBody(req));
|
|
69318
|
+
}
|
|
69319
|
+
let hubRes = await fetch(hubTargetUrl, {
|
|
69320
|
+
method: req.method,
|
|
69321
|
+
headers: proxyHeaders,
|
|
69322
|
+
body,
|
|
69323
|
+
redirect: "manual"
|
|
69324
|
+
});
|
|
69325
|
+
if (hubRes.status >= 300 && hubRes.status < 400) {
|
|
69326
|
+
const location = hubRes.headers.get("location");
|
|
69327
|
+
if (location) {
|
|
69328
|
+
hubRes = await fetch(location, {
|
|
69329
|
+
method: req.method,
|
|
69330
|
+
headers: proxyHeaders,
|
|
69331
|
+
body,
|
|
69332
|
+
redirect: "manual"
|
|
69333
|
+
});
|
|
69334
|
+
}
|
|
69335
|
+
}
|
|
69336
|
+
const data = await hubRes.json();
|
|
69337
|
+
this.json(res, hubRes.status, data);
|
|
69338
|
+
} catch (err) {
|
|
69339
|
+
this.json(res, 502, { error: `Hub request failed: ${String(err)}` });
|
|
69340
|
+
}
|
|
69341
|
+
return;
|
|
69342
|
+
}
|
|
69183
69343
|
if (path === "/api/settings/hub" && req.method === "GET") {
|
|
69184
69344
|
this.json(res, 200, { hubUrl: this.hubUrl });
|
|
69185
69345
|
return;
|
|
@@ -77725,7 +77885,7 @@ var init_startupProgress = __esm({
|
|
|
77725
77885
|
|
|
77726
77886
|
// src/connector-service.ts
|
|
77727
77887
|
import { resolve as resolve15, join as join28, dirname as dirname8 } from "node:path";
|
|
77728
|
-
import { existsSync as existsSync31, readFileSync as readFileSync23, writeFileSync as writeFileSync18, mkdirSync as mkdirSync24, readdirSync as readdirSync12, cpSync as
|
|
77888
|
+
import { existsSync as existsSync31, readFileSync as readFileSync23, writeFileSync as writeFileSync18, mkdirSync as mkdirSync24, readdirSync as readdirSync12, cpSync as cpSync3 } from "node:fs";
|
|
77729
77889
|
import { homedir as homedir18 } from "node:os";
|
|
77730
77890
|
import { execSync as execSync4 } from "node:child_process";
|
|
77731
77891
|
import { fileURLToPath as fileURLToPath4 } from "node:url";
|
|
@@ -77856,7 +78016,7 @@ function installSkillTemplate(connector) {
|
|
|
77856
78016
|
mkdirSync24(targetDir, { recursive: true });
|
|
77857
78017
|
}
|
|
77858
78018
|
try {
|
|
77859
|
-
|
|
78019
|
+
cpSync3(sourceDir, targetDir, { recursive: true });
|
|
77860
78020
|
return true;
|
|
77861
78021
|
} catch {
|
|
77862
78022
|
return false;
|
|
@@ -77906,7 +78066,7 @@ __export(init_exports, {
|
|
|
77906
78066
|
registerInitCommand: () => registerInitCommand
|
|
77907
78067
|
});
|
|
77908
78068
|
import { resolve as resolve16 } from "node:path";
|
|
77909
|
-
import { readFileSync as readFileSync24, existsSync as existsSync32, cpSync as
|
|
78069
|
+
import { readFileSync as readFileSync24, existsSync as existsSync32, cpSync as cpSync4 } from "node:fs";
|
|
77910
78070
|
import { homedir as homedir19 } from "node:os";
|
|
77911
78071
|
function registerInitCommand(program2) {
|
|
77912
78072
|
program2.command("init").description("Setup wizard: configure LLM provider, API keys, and server settings").option("--force", "Overwrite existing configuration").option("--non-interactive", "Run without prompts (use env vars or --import-from)").option("--provider <name>", "LLM provider (anthropic/openai/google/minimax/siliconflow/zai/ollama)").option("--api-key <key>", "LLM API key").option("--port <port>", "API server port", "8056").option("--import-from <platform>", "Import LLM config from an installed agent platform (e.g. openclaw, hermes)").option("--auto-connect", "Auto-connect detected agent platforms after init").action(async (opts) => {
|
|
@@ -78195,7 +78355,7 @@ async function quickInit(options) {
|
|
|
78195
78355
|
if (builtinTemplatesDir && existsSync32(builtinTemplatesDir) && !existsSync32(userTemplatesDir)) {
|
|
78196
78356
|
const builtinRoot = resolve16(builtinTemplatesDir, "..");
|
|
78197
78357
|
mkdirSync26(userTemplatesDir, { recursive: true });
|
|
78198
|
-
|
|
78358
|
+
cpSync4(builtinRoot, userTemplatesDir, { recursive: true });
|
|
78199
78359
|
console.log(` Copied templates to ${userTemplatesDir}`);
|
|
78200
78360
|
}
|
|
78201
78361
|
const devRoleDir = pathJoin(userTemplatesDir || pathJoin(process.cwd(), "templates"), "roles", "developer");
|