agents-united 1.2.0 → 1.4.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/README.md +5 -4
- package/dist/cli.js +210 -46
- package/dist/cli.js.map +1 -1
- package/package.json +1 -1
- package/registry/agents/orchestrator-universal.md +144 -0
- package/registry/bundles.json +17 -0
package/README.md
CHANGED
|
@@ -107,11 +107,11 @@ This model gives you:
|
|
|
107
107
|
---
|
|
108
108
|
|
|
109
109
|
|
|
110
|
-
Agents United provides **
|
|
110
|
+
Agents United provides **24 curated bundles**, **46 specialized agents** (8 Orchestrators — 7 Lead + 1 Prime + 38 Sub-Agents), **90 skills**, and **63 workflows** across 8 department domains:
|
|
111
111
|
|
|
112
112
|
| Department Domain | Essentials Base | Specialized Addon Bundles | Lead Orchestrator |
|
|
113
113
|
| :--- | :--- | :--- | :--- |
|
|
114
|
-
| **🌐 Universal Department** | `universal-skills` ⭐ | `full` (Universal Suite) |
|
|
114
|
+
| **🌐 Universal Department** | `universal-skills` ⭐ | `universal-orchestration` (guided routing), `full` (Universal Suite) | `orchestrator-universal` (Prime) |
|
|
115
115
|
| **🛠️ Software Engineering & Delivery** | `software-engineering` | `ai-ml-engineering`, `mobile-development`, `frontend-engineering`, `backend-distributed-systems`, `qa-automation`, `devops-engineering` | `orchestrator-engineering` |
|
|
116
116
|
| **🏛️ System Architecture & SRE** | `system-architecture` | `sysops-sre` | `orchestrator-system-architecture` |
|
|
117
117
|
| **🎨 Product Design & UI/UX** | `product-design` | `design-systems-ops`, `design-research-testing` | `orchestrator-design` |
|
|
@@ -128,7 +128,8 @@ Agents United provides **22 curated bundles**, **45 specialized agents** (7 Lead
|
|
|
128
128
|
|
|
129
129
|
#### 🌐 Universal Autonomous Department
|
|
130
130
|
- **Baseline**: `universal-skills` ⭐ *(Recommended Baseline — Socratic grilling, PRD generation, ADRs, session handoff)*
|
|
131
|
-
- **
|
|
131
|
+
- **Guided Routing (optional)**: `universal-orchestration` *(Prime Orchestrator front door — grills ambiguous requests, routes to the correct department Essentials bundle via its Domain Atlas, installs with consent, and hands off. An optional way to use Agents United without the full suite.)*
|
|
132
|
+
- **Universal Suite**: `full` *(Complete enterprise suite containing all bundles, agents, skills, workflows)*
|
|
132
133
|
|
|
133
134
|
#### 🛠️ Software Engineering & Delivery
|
|
134
135
|
- **Lead Orchestrator**: `orchestrator-engineering`
|
|
@@ -368,7 +369,7 @@ agents doctor --host cline
|
|
|
368
369
|
---
|
|
369
370
|
## 🌐 One Library, Every Assistant
|
|
370
371
|
|
|
371
|
-
The `.agents/` folder is the **main library** — the *one* folder you edit. **Antigravity reads it directly
|
|
372
|
+
The `.agents/` folder is the **main library** — the *one* folder you edit. **Antigravity reads it directly** for interactive sessions (CLI TUI and desktop); see [ADR 0009](./docs/adr/0009-host-conformance-targets.md). Every other assistant (Claude Code, Cursor, Cline, OpenCode, Codex) can't read it natively, so Agents United writes **translated copies** it keeps in sync for you.
|
|
372
373
|
|
|
373
374
|
- **Edit only `.agents/`.** That's your source of truth — the `agents-united.json` lockfile tracks it.
|
|
374
375
|
- **Other assistants get their own translated copies**, in their own folders (`.claude/agents/`, `.cline/agents/`, …). Don't edit those — they're machine-managed and rewritten on every `agents update`.
|
package/dist/cli.js
CHANGED
|
@@ -419,8 +419,10 @@ ${bodyStr}
|
|
|
419
419
|
}
|
|
420
420
|
/**
|
|
421
421
|
* Render Team Manifest YAML matching ClineTeamManifest schema.
|
|
422
|
+
* @param excludeAddons optional addon names to omit from `recommendedAddons`
|
|
423
|
+
* (used to stop advertising bundles already present in the workspace).
|
|
422
424
|
*/
|
|
423
|
-
static renderTeamManifest(bundle, scope) {
|
|
425
|
+
static renderTeamManifest(bundle, scope, excludeAddons = []) {
|
|
424
426
|
const coordinatorFile = bundle.orchestrator || `${bundle.name}.md`;
|
|
425
427
|
const coordinatorName = coordinatorFile.replace(/\.md$/, "");
|
|
426
428
|
const coordinatorCanonical = `agents/${coordinatorFile}`;
|
|
@@ -430,7 +432,7 @@ ${bodyStr}
|
|
|
430
432
|
}));
|
|
431
433
|
const sortedSkills = [...bundle.skills || []].sort();
|
|
432
434
|
const sortedWorkflows = [...bundle.workflows || []].sort();
|
|
433
|
-
const recommendedAddons = bundle.recommendedAddons || [];
|
|
435
|
+
const recommendedAddons = (bundle.recommendedAddons || []).filter((a) => !excludeAddons.includes(a));
|
|
434
436
|
const manifest = {
|
|
435
437
|
schemaVersion: 1,
|
|
436
438
|
bundle: bundle.name,
|
|
@@ -452,8 +454,10 @@ ${bodyStr}
|
|
|
452
454
|
}
|
|
453
455
|
/**
|
|
454
456
|
* Render the coordinator rule file (.cline/rules/agents-united-<bundle>.md).
|
|
457
|
+
* @param excludeAddons optional addon names to omit from the "Recommended Addon
|
|
458
|
+
* Policy" list (used to stop advertising bundles already installed).
|
|
455
459
|
*/
|
|
456
|
-
static renderCoordinatorRule(bundle, scope) {
|
|
460
|
+
static renderCoordinatorRule(bundle, scope, excludeAddons = []) {
|
|
457
461
|
const marker = `<!-- managed-by: agents-united | profile: cline | bundle: ${bundle.name} | do not edit -->`;
|
|
458
462
|
const manifestRelPath = scope === "global" ? `~/.cline/agents-united/teams/${bundle.name}.yaml` : `.cline/agents-united/teams/${bundle.name}.yaml`;
|
|
459
463
|
const coordinatorFile = bundle.orchestrator || `${bundle.name}.md`;
|
|
@@ -463,7 +467,7 @@ ${bodyStr}
|
|
|
463
467
|
const name = agentFile.replace(/\.md$/, "");
|
|
464
468
|
return `- **${name}**: \`.agents/agents/${agentFile}\``;
|
|
465
469
|
});
|
|
466
|
-
const addons = bundle.recommendedAddons || [];
|
|
470
|
+
const addons = (bundle.recommendedAddons || []).filter((a) => !excludeAddons.includes(a));
|
|
467
471
|
const addonSection = addons.length > 0 ? `
|
|
468
472
|
### Recommended Addon Policy
|
|
469
473
|
When user tasks require capabilities from: ${addons.join(", ")}, explain the capability and request user confirmation to install via \`agents add <addon> -t cline -y\` before running the installation.` : "";
|
|
@@ -487,8 +491,10 @@ ${addonSection}
|
|
|
487
491
|
}
|
|
488
492
|
/**
|
|
489
493
|
* Plan all compound artifacts for a bundle installation into Cline.
|
|
494
|
+
* @param excludeAddons optional addon names forwarded to the coordinator rule and
|
|
495
|
+
* team manifest renderers so already-installed bundles are not advertised.
|
|
490
496
|
*/
|
|
491
|
-
static async planCompoundProjection(bundle, scope, resolved, registryDir) {
|
|
497
|
+
static async planCompoundProjection(bundle, scope, resolved, registryDir, excludeAddons = []) {
|
|
492
498
|
const artifacts = [];
|
|
493
499
|
const baseDir = scope === "global" ? ".cline" : ".cline";
|
|
494
500
|
for (const agentFile of resolved.agents) {
|
|
@@ -539,14 +545,14 @@ ${addonSection}
|
|
|
539
545
|
}
|
|
540
546
|
}
|
|
541
547
|
}
|
|
542
|
-
const ruleContent = this.renderCoordinatorRule(bundle, scope);
|
|
548
|
+
const ruleContent = this.renderCoordinatorRule(bundle, scope, excludeAddons);
|
|
543
549
|
artifacts.push({
|
|
544
550
|
kind: "rule",
|
|
545
551
|
relPath: `${baseDir}/rules/agents-united-${bundle.name}.md`.replace(/\\/g, "/"),
|
|
546
552
|
content: ruleContent,
|
|
547
553
|
managedMarker: true
|
|
548
554
|
});
|
|
549
|
-
const manifestContent = this.renderTeamManifest(bundle, scope);
|
|
555
|
+
const manifestContent = this.renderTeamManifest(bundle, scope, excludeAddons);
|
|
550
556
|
artifacts.push({
|
|
551
557
|
kind: "team-manifest",
|
|
552
558
|
relPath: `${baseDir}/agents-united/teams/${bundle.name}.yaml`.replace(/\\/g, "/"),
|
|
@@ -948,6 +954,11 @@ var InstallEngine = class _InstallEngine {
|
|
|
948
954
|
if (host === "cline") {
|
|
949
955
|
const bundleDef = resolved.targetBundle ? await this.registry.getBundle(resolved.targetBundle) : void 0;
|
|
950
956
|
if (bundleDef) {
|
|
957
|
+
const declared = /* @__PURE__ */ new Set();
|
|
958
|
+
if (bundleDef.orchestrator) declared.add(`agents/${bundleDef.orchestrator}`);
|
|
959
|
+
(bundleDef.agents || []).forEach((a) => declared.add(`agents/${a}`));
|
|
960
|
+
(bundleDef.skills || []).forEach((s) => declared.add(`skills/${s}/SKILL.md`));
|
|
961
|
+
(bundleDef.workflows || []).forEach((w) => declared.add(`workflows/${w}`));
|
|
951
962
|
const artifacts = await ClineProjector.planCompoundProjection(bundleDef, scope, resolved, registryDir);
|
|
952
963
|
for (const artifact of artifacts) {
|
|
953
964
|
const dest = path5.join(root, artifact.relPath);
|
|
@@ -978,14 +989,16 @@ var InstallEngine = class _InstallEngine {
|
|
|
978
989
|
lockfile.projections = lockfile.projections || {};
|
|
979
990
|
const existingProj = lockfile.projections[artifact.relPath];
|
|
980
991
|
const bundleName = bundleDef.name;
|
|
981
|
-
const
|
|
992
|
+
const declares = artifact.kind === "rule" || artifact.kind === "team-manifest" || (artifact.canonical ? declared.has(artifact.canonical) : false);
|
|
993
|
+
const priorOwners = existingProj?.owners ?? [];
|
|
994
|
+
const owners = declares ? Array.from(/* @__PURE__ */ new Set([...priorOwners, bundleName])) : priorOwners;
|
|
982
995
|
lockfile.projections[artifact.relPath] = {
|
|
983
996
|
host: "cline",
|
|
984
997
|
kind: artifact.kind,
|
|
985
998
|
canonical: artifact.canonical,
|
|
986
999
|
owners,
|
|
987
1000
|
hash: deployedHash,
|
|
988
|
-
installedAt: now,
|
|
1001
|
+
installedAt: existingProj?.installedAt ?? now,
|
|
989
1002
|
managedMarker: artifact.managedMarker
|
|
990
1003
|
};
|
|
991
1004
|
projections.push({ host, path: artifact.relPath, kind: artifact.kind, warnings: [] });
|
|
@@ -993,6 +1006,38 @@ var InstallEngine = class _InstallEngine {
|
|
|
993
1006
|
this.recordProjectedTo(lockfile, artifact.canonical, artifact.relPath);
|
|
994
1007
|
}
|
|
995
1008
|
}
|
|
1009
|
+
if (bundleDef.parentBundle) {
|
|
1010
|
+
const parentDef = await this.registry.getBundle(bundleDef.parentBundle);
|
|
1011
|
+
if (parentDef) {
|
|
1012
|
+
const parentProjection = await ClineProjector.planCompoundProjection(
|
|
1013
|
+
parentDef,
|
|
1014
|
+
scope,
|
|
1015
|
+
resolved,
|
|
1016
|
+
registryDir,
|
|
1017
|
+
lockfile.installed.bundles
|
|
1018
|
+
);
|
|
1019
|
+
for (const artifact of parentProjection) {
|
|
1020
|
+
if (artifact.kind !== "rule" && artifact.kind !== "team-manifest") continue;
|
|
1021
|
+
if (artifact.content === void 0) continue;
|
|
1022
|
+
const dest = path5.join(root, artifact.relPath);
|
|
1023
|
+
if (!await fs3.pathExists(dest)) continue;
|
|
1024
|
+
await this.deployProjection(dest, artifact.content);
|
|
1025
|
+
const deployedHash = await this.calculateHash(dest);
|
|
1026
|
+
lockfile.projections = lockfile.projections || {};
|
|
1027
|
+
const existingProj = lockfile.projections[artifact.relPath];
|
|
1028
|
+
lockfile.projections[artifact.relPath] = {
|
|
1029
|
+
host: "cline",
|
|
1030
|
+
kind: artifact.kind,
|
|
1031
|
+
canonical: artifact.canonical,
|
|
1032
|
+
// Preserve existing ownership; the parent remains the sole owner.
|
|
1033
|
+
owners: existingProj?.owners ?? [],
|
|
1034
|
+
hash: deployedHash,
|
|
1035
|
+
installedAt: existingProj?.installedAt ?? now,
|
|
1036
|
+
managedMarker: artifact.managedMarker
|
|
1037
|
+
};
|
|
1038
|
+
}
|
|
1039
|
+
}
|
|
1040
|
+
}
|
|
996
1041
|
continue;
|
|
997
1042
|
}
|
|
998
1043
|
}
|
|
@@ -1048,6 +1093,16 @@ var InstallEngine = class _InstallEngine {
|
|
|
1048
1093
|
if (options.fanout !== void 0) {
|
|
1049
1094
|
lockfile.fanout = effectiveFanout;
|
|
1050
1095
|
}
|
|
1096
|
+
const declared = /* @__PURE__ */ new Set();
|
|
1097
|
+
if (resolved.targetBundle) {
|
|
1098
|
+
const bundleDef = await this.registry.getBundle(resolved.targetBundle);
|
|
1099
|
+
if (bundleDef) {
|
|
1100
|
+
if (bundleDef.orchestrator) declared.add(`agents/${bundleDef.orchestrator}`);
|
|
1101
|
+
(bundleDef.agents || []).forEach((a) => declared.add(`agents/${a}`));
|
|
1102
|
+
(bundleDef.skills || []).forEach((s) => declared.add(`skills/${s}/SKILL.md`));
|
|
1103
|
+
(bundleDef.workflows || []).forEach((w) => declared.add(`workflows/${w}`));
|
|
1104
|
+
}
|
|
1105
|
+
}
|
|
1051
1106
|
for (const agentFile of resolved.agents) {
|
|
1052
1107
|
const src = path5.join(registryDir, "agents", agentFile);
|
|
1053
1108
|
const dest = path5.join(subPaths.agentsDir, agentFile);
|
|
@@ -1060,14 +1115,18 @@ var InstallEngine = class _InstallEngine {
|
|
|
1060
1115
|
}
|
|
1061
1116
|
const actualMethod = await this.deployFile(src, dest, method, options.force);
|
|
1062
1117
|
const hash = await this.calculateHash(src);
|
|
1063
|
-
const relPath = path5.relative(targetDir, dest);
|
|
1064
|
-
const
|
|
1118
|
+
const relPath = this.toPosix(path5.relative(targetDir, dest));
|
|
1119
|
+
const existing = lockfile.files[relPath];
|
|
1120
|
+
const existingOwners = existing?.owners ?? (existing?.bundle ? [existing.bundle] : []);
|
|
1121
|
+
const declaresAsset = declared.has(`agents/${agentFile}`);
|
|
1122
|
+
const owners = resolved.targetBundle && declaresAsset ? Array.from(/* @__PURE__ */ new Set([...existingOwners, resolved.targetBundle])) : existingOwners;
|
|
1065
1123
|
lockfile.files[relPath] = {
|
|
1066
1124
|
hash,
|
|
1067
|
-
bundle: resolved.targetBundle,
|
|
1125
|
+
bundle: existing?.bundle ?? resolved.targetBundle,
|
|
1126
|
+
owners,
|
|
1068
1127
|
method: actualMethod,
|
|
1069
|
-
installedAt: now,
|
|
1070
|
-
...
|
|
1128
|
+
installedAt: existing?.installedAt ?? now,
|
|
1129
|
+
...existing?.projectedTo ? { projectedTo: existing.projectedTo } : {}
|
|
1071
1130
|
};
|
|
1072
1131
|
if (!lockfile.installed.agents.includes(agentFile)) {
|
|
1073
1132
|
lockfile.installed.agents.push(agentFile);
|
|
@@ -1080,14 +1139,18 @@ var InstallEngine = class _InstallEngine {
|
|
|
1080
1139
|
const skillFile = path5.join(src, "SKILL.md");
|
|
1081
1140
|
if (await fs3.pathExists(skillFile)) {
|
|
1082
1141
|
const hash = await this.calculateHash(skillFile);
|
|
1083
|
-
const relPath = path5.relative(targetDir, path5.join(subPaths.skillsDir, skillName, "SKILL.md"));
|
|
1084
|
-
const
|
|
1142
|
+
const relPath = this.toPosix(path5.relative(targetDir, path5.join(subPaths.skillsDir, skillName, "SKILL.md")));
|
|
1143
|
+
const existing = lockfile.files[relPath];
|
|
1144
|
+
const existingOwners = existing?.owners ?? (existing?.bundle ? [existing.bundle] : []);
|
|
1145
|
+
const declaresAsset = declared.has(`skills/${skillName}/SKILL.md`);
|
|
1146
|
+
const owners = resolved.targetBundle && declaresAsset ? Array.from(/* @__PURE__ */ new Set([...existingOwners, resolved.targetBundle])) : existingOwners;
|
|
1085
1147
|
lockfile.files[relPath] = {
|
|
1086
1148
|
hash,
|
|
1087
|
-
bundle: resolved.targetBundle,
|
|
1149
|
+
bundle: existing?.bundle ?? resolved.targetBundle,
|
|
1150
|
+
owners,
|
|
1088
1151
|
method: actualMethod,
|
|
1089
|
-
installedAt: now,
|
|
1090
|
-
...
|
|
1152
|
+
installedAt: existing?.installedAt ?? now,
|
|
1153
|
+
...existing?.projectedTo ? { projectedTo: existing.projectedTo } : {}
|
|
1091
1154
|
};
|
|
1092
1155
|
}
|
|
1093
1156
|
if (!lockfile.installed.skills.includes(skillName)) {
|
|
@@ -1099,14 +1162,18 @@ var InstallEngine = class _InstallEngine {
|
|
|
1099
1162
|
const dest = path5.join(subPaths.workflowsDir, workflowFile);
|
|
1100
1163
|
const actualMethod = await this.deployFile(src, dest, method, options.force);
|
|
1101
1164
|
const hash = await this.calculateHash(src);
|
|
1102
|
-
const relPath = path5.relative(targetDir, dest);
|
|
1103
|
-
const
|
|
1165
|
+
const relPath = this.toPosix(path5.relative(targetDir, dest));
|
|
1166
|
+
const existing = lockfile.files[relPath];
|
|
1167
|
+
const existingOwners = existing?.owners ?? (existing?.bundle ? [existing.bundle] : []);
|
|
1168
|
+
const declaresAsset = declared.has(`workflows/${workflowFile}`);
|
|
1169
|
+
const owners = resolved.targetBundle && declaresAsset ? Array.from(/* @__PURE__ */ new Set([...existingOwners, resolved.targetBundle])) : existingOwners;
|
|
1104
1170
|
lockfile.files[relPath] = {
|
|
1105
1171
|
hash,
|
|
1106
|
-
bundle: resolved.targetBundle,
|
|
1172
|
+
bundle: existing?.bundle ?? resolved.targetBundle,
|
|
1173
|
+
owners,
|
|
1107
1174
|
method: actualMethod,
|
|
1108
|
-
installedAt: now,
|
|
1109
|
-
...
|
|
1175
|
+
installedAt: existing?.installedAt ?? now,
|
|
1176
|
+
...existing?.projectedTo ? { projectedTo: existing.projectedTo } : {}
|
|
1110
1177
|
};
|
|
1111
1178
|
if (!lockfile.installed.workflows.includes(workflowFile)) {
|
|
1112
1179
|
lockfile.installed.workflows.push(workflowFile);
|
|
@@ -1118,12 +1185,18 @@ var InstallEngine = class _InstallEngine {
|
|
|
1118
1185
|
if (await fs3.pathExists(src)) {
|
|
1119
1186
|
const actualMethod = await this.deployFile(src, dest, method, options.force);
|
|
1120
1187
|
const hash = await this.calculateHash(src);
|
|
1121
|
-
const relPath = path5.relative(targetDir, dest);
|
|
1188
|
+
const relPath = this.toPosix(path5.relative(targetDir, dest));
|
|
1189
|
+
const existing = lockfile.files[relPath];
|
|
1190
|
+
const existingOwners = existing?.owners ?? (existing?.bundle ? [existing.bundle] : []);
|
|
1191
|
+
const declaresAsset = true;
|
|
1192
|
+
const owners = resolved.targetBundle && declaresAsset ? Array.from(/* @__PURE__ */ new Set([...existingOwners, resolved.targetBundle])) : existingOwners;
|
|
1122
1193
|
lockfile.files[relPath] = {
|
|
1123
1194
|
hash,
|
|
1124
|
-
bundle: resolved.targetBundle,
|
|
1195
|
+
bundle: existing?.bundle ?? resolved.targetBundle,
|
|
1196
|
+
owners,
|
|
1125
1197
|
method: actualMethod,
|
|
1126
|
-
installedAt: now
|
|
1198
|
+
installedAt: existing?.installedAt ?? now,
|
|
1199
|
+
...existing?.projectedTo ? { projectedTo: existing.projectedTo } : {}
|
|
1127
1200
|
};
|
|
1128
1201
|
}
|
|
1129
1202
|
}
|
|
@@ -1223,6 +1296,42 @@ var UninstallEngine = class {
|
|
|
1223
1296
|
}
|
|
1224
1297
|
await fs4.remove(absPath);
|
|
1225
1298
|
}
|
|
1299
|
+
/**
|
|
1300
|
+
* Installed-addon freshness (plan 003): after a child bundle (one with a
|
|
1301
|
+
* `parentBundle`) is removed, re-render the parent's coordinator rule + team
|
|
1302
|
+
* manifest excluding every remaining installed bundle in the lockfile, so the
|
|
1303
|
+
* removed addon returns to the parent's recommendedAddons. Presentation-free:
|
|
1304
|
+
* the two projection files carry the managed marker trustees inside (rule) and
|
|
1305
|
+
* are overwritten directly via fs-extra. If a parent artifact does not exist in
|
|
1306
|
+
* the workspace (parent not installed as its own bundle), it is skipped.
|
|
1307
|
+
*/
|
|
1308
|
+
async refreshParentCoordination(bundleName, workspaceRoot, lockfile, scope) {
|
|
1309
|
+
const bundleDef = await this.registry.getBundle(bundleName);
|
|
1310
|
+
if (!bundleDef?.parentBundle) return;
|
|
1311
|
+
const parentDef = await this.registry.getBundle(bundleDef.parentBundle);
|
|
1312
|
+
if (!parentDef) return;
|
|
1313
|
+
const parentResolved = await this.registry.resolve(parentDef.name).catch(() => null);
|
|
1314
|
+
if (!parentResolved) return;
|
|
1315
|
+
const registryDir = this.registry.getRegistryDir();
|
|
1316
|
+
const projection = await ClineProjector.planCompoundProjection(
|
|
1317
|
+
parentDef,
|
|
1318
|
+
scope,
|
|
1319
|
+
parentResolved,
|
|
1320
|
+
registryDir,
|
|
1321
|
+
lockfile.installed.bundles
|
|
1322
|
+
);
|
|
1323
|
+
for (const artifact of projection) {
|
|
1324
|
+
if (artifact.kind !== "rule" && artifact.kind !== "team-manifest") continue;
|
|
1325
|
+
if (artifact.content === void 0) continue;
|
|
1326
|
+
const dest = path6.join(workspaceRoot, artifact.relPath);
|
|
1327
|
+
if (!await fs4.pathExists(dest)) continue;
|
|
1328
|
+
await fs4.writeFile(dest, artifact.content, "utf8");
|
|
1329
|
+
const hash = await this.calculateHash(dest);
|
|
1330
|
+
if (lockfile.projections?.[artifact.relPath]) {
|
|
1331
|
+
lockfile.projections[artifact.relPath].hash = hash;
|
|
1332
|
+
}
|
|
1333
|
+
}
|
|
1334
|
+
}
|
|
1226
1335
|
parseHosts(options) {
|
|
1227
1336
|
if (options.hosts && options.hosts.length > 0) return options.hosts;
|
|
1228
1337
|
if (options.target) {
|
|
@@ -1281,6 +1390,11 @@ var UninstallEngine = class {
|
|
|
1281
1390
|
if (lockfile.installed.bundles.includes(bundleName)) {
|
|
1282
1391
|
if (!options.dryRun) {
|
|
1283
1392
|
const workspaceRoot = path6.resolve(path6.dirname(targetDir));
|
|
1393
|
+
const ownedFiles = Object.entries(lockfile.files).filter(([, m]) => (m.owners ?? (m.bundle ? [m.bundle] : [])).includes(bundleName));
|
|
1394
|
+
const ownedProjections = lockfile.projections ? Object.values(lockfile.projections).filter((p) => p.owners.includes(bundleName)).length : 0;
|
|
1395
|
+
if (ownedFiles.length === 0 && ownedProjections === 0) {
|
|
1396
|
+
throw new Error(`No installed assets found matching "${bundleName}".`);
|
|
1397
|
+
}
|
|
1284
1398
|
if (lockfile.projections) {
|
|
1285
1399
|
for (const [projRelPath, proj] of Object.entries(lockfile.projections)) {
|
|
1286
1400
|
if (proj.owners.includes(bundleName)) {
|
|
@@ -1308,7 +1422,10 @@ var UninstallEngine = class {
|
|
|
1308
1422
|
}
|
|
1309
1423
|
}
|
|
1310
1424
|
for (const [relPath, assetMeta] of Object.entries(lockfile.files)) {
|
|
1311
|
-
|
|
1425
|
+
const assetOwners = assetMeta.owners ?? (assetMeta.bundle ? [assetMeta.bundle] : []);
|
|
1426
|
+
if (!assetOwners.includes(bundleName)) continue;
|
|
1427
|
+
const newOwners = assetOwners.filter((o) => o !== bundleName);
|
|
1428
|
+
if (newOwners.length === 0) {
|
|
1312
1429
|
if (assetMeta.projectedTo && assetMeta.projectedTo.length > 0) {
|
|
1313
1430
|
await this.removeProjections(workspaceRoot, assetMeta.projectedTo, options.force);
|
|
1314
1431
|
}
|
|
@@ -1324,21 +1441,28 @@ var UninstallEngine = class {
|
|
|
1324
1441
|
removedFiles.push(relPath);
|
|
1325
1442
|
}
|
|
1326
1443
|
delete lockfile.files[relPath];
|
|
1444
|
+
} else {
|
|
1445
|
+
lockfile.files[relPath] = { ...assetMeta, owners: newOwners };
|
|
1327
1446
|
}
|
|
1328
1447
|
}
|
|
1329
1448
|
lockfile.installed.bundles = lockfile.installed.bundles.filter((b) => b !== bundleName);
|
|
1330
1449
|
if (lockfile.bundleVersions) {
|
|
1331
1450
|
delete lockfile.bundleVersions[bundleName];
|
|
1332
1451
|
}
|
|
1333
|
-
|
|
1334
|
-
|
|
1335
|
-
|
|
1336
|
-
|
|
1337
|
-
|
|
1338
|
-
|
|
1339
|
-
|
|
1340
|
-
|
|
1452
|
+
const surviving = lockfile.installed.bundles.filter((b) => b !== bundleName);
|
|
1453
|
+
const survival = /* @__PURE__ */ new Set();
|
|
1454
|
+
for (const b of surviving) {
|
|
1455
|
+
const bdef = await this.registry.getBundle(b);
|
|
1456
|
+
if (!bdef) continue;
|
|
1457
|
+
if (bdef.orchestrator) survival.add(`agents/${bdef.orchestrator}`);
|
|
1458
|
+
(bdef.agents || []).forEach((a) => survival.add(`agents/${a}`));
|
|
1459
|
+
(bdef.skills || []).forEach((s) => survival.add(`skills/${s}/SKILL.md`));
|
|
1460
|
+
(bdef.workflows || []).forEach((w) => survival.add(`workflows/${w}`));
|
|
1341
1461
|
}
|
|
1462
|
+
lockfile.installed.agents = lockfile.installed.agents.filter((a) => survival.has(`agents/${a}`));
|
|
1463
|
+
lockfile.installed.skills = lockfile.installed.skills.filter((s) => survival.has(`skills/${s}/SKILL.md`));
|
|
1464
|
+
lockfile.installed.workflows = lockfile.installed.workflows.filter((w) => survival.has(`workflows/${w}`));
|
|
1465
|
+
await this.refreshParentCoordination(bundleName, workspaceRoot, lockfile, scope);
|
|
1342
1466
|
await fs4.writeJson(subPaths.lockfile, lockfile, { spaces: 2 });
|
|
1343
1467
|
} else {
|
|
1344
1468
|
removedFiles.push(...resolved.agents, ...resolved.skills, ...resolved.workflows);
|
|
@@ -2020,6 +2144,30 @@ var DoctorEngine = class {
|
|
|
2020
2144
|
}
|
|
2021
2145
|
}
|
|
2022
2146
|
}
|
|
2147
|
+
const installedBundles = manifest.installed?.bundles ?? [];
|
|
2148
|
+
const fileOwnersOf = (rec) => rec.owners ?? (rec.bundle ? [rec.bundle] : []);
|
|
2149
|
+
if (manifest.projections) {
|
|
2150
|
+
for (const [projRelPath, proj] of Object.entries(manifest.projections)) {
|
|
2151
|
+
for (const owner of proj.owners) {
|
|
2152
|
+
if (!installedBundles.includes(owner)) {
|
|
2153
|
+
warnings.push(`Projection ${projRelPath} is owned by bundle "${owner}" which is not in installed.bundles.`);
|
|
2154
|
+
}
|
|
2155
|
+
}
|
|
2156
|
+
}
|
|
2157
|
+
}
|
|
2158
|
+
for (const [relPath, rec] of Object.entries(manifest.files)) {
|
|
2159
|
+
for (const owner of fileOwnersOf(rec)) {
|
|
2160
|
+
if (!installedBundles.includes(owner)) {
|
|
2161
|
+
warnings.push(`File record ${relPath} is owned by bundle "${owner}" which is not in installed.bundles.`);
|
|
2162
|
+
}
|
|
2163
|
+
}
|
|
2164
|
+
}
|
|
2165
|
+
for (const bundleName of installedBundles) {
|
|
2166
|
+
const fileCount = Object.values(manifest.files).filter((m) => fileOwnersOf(m).includes(bundleName)).length;
|
|
2167
|
+
if (fileCount === 0) {
|
|
2168
|
+
warnings.push(`Installed bundle "${bundleName}" owns zero file records.`);
|
|
2169
|
+
}
|
|
2170
|
+
}
|
|
2023
2171
|
}
|
|
2024
2172
|
if (host === "cline") {
|
|
2025
2173
|
const probe = new ClineCapabilityProbe();
|
|
@@ -2134,7 +2282,8 @@ var ClineLauncher = class _ClineLauncher {
|
|
|
2134
2282
|
prompt,
|
|
2135
2283
|
teamName: customTeamName,
|
|
2136
2284
|
allowAddons,
|
|
2137
|
-
headless
|
|
2285
|
+
headless,
|
|
2286
|
+
orchestrator
|
|
2138
2287
|
} = options;
|
|
2139
2288
|
const command = report.command || {
|
|
2140
2289
|
executable: "cline",
|
|
@@ -2152,7 +2301,8 @@ var ClineLauncher = class _ClineLauncher {
|
|
|
2152
2301
|
}
|
|
2153
2302
|
const strategy = report.namedTeams ? "named-team" : "adaptive-session";
|
|
2154
2303
|
const manifestRel = scope === "global" ? `~/.cline/agents-united/teams/${bundleName}.yaml` : `.cline/agents-united/teams/${bundleName}.yaml`;
|
|
2155
|
-
const
|
|
2304
|
+
const coordinatorFile = (orchestrator || "orchestrator-engineering.md").replace(/\.md$/, "");
|
|
2305
|
+
const coordinatorCanonical = `.agents/agents/${coordinatorFile}.md`;
|
|
2156
2306
|
const addonPolicyText = allowAddons ? "Addon auto-installation is pre-authorized for this session." : `Before installing any recommended addon, explain the requirement to the user and request explicit confirmation to run: agents add <addon> -t cline ${scope === "global" ? "-g " : ""}-y.`;
|
|
2157
2307
|
const taskText = prompt && prompt.trim().length > 0 ? `User task: ${prompt.trim()}` : "Please introduce your coordinator role to the user and ask for their first task.";
|
|
2158
2308
|
const bootstrapPrompt = [
|
|
@@ -2568,6 +2718,10 @@ var BUNDLE_DISPLAY_NAMES = {
|
|
|
2568
2718
|
title: "Digital Agency (TBA soon)",
|
|
2569
2719
|
summary: "Full-service digital product agency with web dev, mobile, design, SEO, and growth marketing"
|
|
2570
2720
|
},
|
|
2721
|
+
"universal-orchestration": {
|
|
2722
|
+
title: "Universal Orchestration",
|
|
2723
|
+
summary: "Prime Orchestrator front door: routes to the correct department Essentials bundle and hands off"
|
|
2724
|
+
},
|
|
2571
2725
|
"universal-skills": {
|
|
2572
2726
|
title: "Universal Meta-Skills",
|
|
2573
2727
|
summary: "Domain-agnostic Socratic grilling, spec generation, handoff, and domain modeling"
|
|
@@ -2815,6 +2969,8 @@ cli.command("add [identifier]", "Add a bundle, agent, skill, or workflow to proj
|
|
|
2815
2969
|
});
|
|
2816
2970
|
}
|
|
2817
2971
|
const sortedBundles = [...domainBundles].sort((a, b) => {
|
|
2972
|
+
if (a.name === "universal-orchestration") return -1;
|
|
2973
|
+
if (b.name === "universal-orchestration") return 1;
|
|
2818
2974
|
if (a.name === "universal-skills") return -1;
|
|
2819
2975
|
if (b.name === "universal-skills") return 1;
|
|
2820
2976
|
if (!a.parentBundle && b.parentBundle) return -1;
|
|
@@ -2825,7 +2981,7 @@ cli.command("add [identifier]", "Add a bundle, agent, skill, or workflow to proj
|
|
|
2825
2981
|
const isLast = idx === sortedBundles.length - 1;
|
|
2826
2982
|
const branch = sortedBundles.length > 1 ? isLast ? "\u2514\u2500\u2500 " : "\u251C\u2500\u2500 " : "";
|
|
2827
2983
|
const meta = BUNDLE_DISPLAY_NAMES[b.name];
|
|
2828
|
-
const isEssentials = !b.parentBundle && b.name !== "full" && b.tier !== "organization" && b.name !== "universal-skills";
|
|
2984
|
+
const isEssentials = !b.parentBundle && b.name !== "full" && b.tier !== "organization" && b.name !== "universal-skills" && b.name !== "universal-orchestration";
|
|
2829
2985
|
const title = meta ? meta.title : b.name;
|
|
2830
2986
|
let statusBadge = "";
|
|
2831
2987
|
if (b.name === "universal-skills") statusBadge = pc.green(" \u2B50 [Recommended Baseline]");
|
|
@@ -3048,11 +3204,13 @@ ${renderProjections(result.projections)}` : ""),
|
|
|
3048
3204
|
const probe = new ClineCapabilityProbe();
|
|
3049
3205
|
const probeReport = await probe.probe();
|
|
3050
3206
|
if (probeReport.installed) {
|
|
3207
|
+
const targetBundleDef2 = await registry.getBundle(bundleName);
|
|
3051
3208
|
const plan = launcher.planActivation({
|
|
3052
3209
|
bundleName,
|
|
3053
3210
|
workspace: process.cwd(),
|
|
3054
3211
|
scope,
|
|
3055
|
-
report: probeReport
|
|
3212
|
+
report: probeReport,
|
|
3213
|
+
orchestrator: targetBundleDef2?.orchestrator
|
|
3056
3214
|
});
|
|
3057
3215
|
await launcher.launch(plan);
|
|
3058
3216
|
} else {
|
|
@@ -3073,11 +3231,13 @@ ${renderProjections(result.projections)}` : ""),
|
|
|
3073
3231
|
const probe = new ClineCapabilityProbe();
|
|
3074
3232
|
const probeReport = await probe.probe();
|
|
3075
3233
|
if (probeReport.installed) {
|
|
3234
|
+
const targetBundleDef2 = await registry.getBundle(bundleName);
|
|
3076
3235
|
const plan = launcher.planActivation({
|
|
3077
3236
|
bundleName,
|
|
3078
3237
|
workspace: process.cwd(),
|
|
3079
3238
|
scope,
|
|
3080
|
-
report: probeReport
|
|
3239
|
+
report: probeReport,
|
|
3240
|
+
orchestrator: targetBundleDef2?.orchestrator
|
|
3081
3241
|
});
|
|
3082
3242
|
await launcher.launch(plan);
|
|
3083
3243
|
} else {
|
|
@@ -3343,7 +3503,7 @@ function renderBundleDetailTree(bundle) {
|
|
|
3343
3503
|
return lines2.join("\n");
|
|
3344
3504
|
}
|
|
3345
3505
|
const meta = BUNDLE_DISPLAY_NAMES[bundle.name];
|
|
3346
|
-
const isEssentials = !bundle.parentBundle && bundle.name !== "full" && bundle.name !== "universal-skills" && bundle.tier !== "organization";
|
|
3506
|
+
const isEssentials = !bundle.parentBundle && bundle.name !== "full" && bundle.name !== "universal-skills" && bundle.name !== "universal-orchestration" && bundle.tier !== "organization";
|
|
3347
3507
|
const titleSuffix = isEssentials ? pc.cyan(" (Essentials Base)") : "";
|
|
3348
3508
|
const parentTag = bundle.parentBundle ? pc.gray(` [inherits: ${bundle.parentBundle}]`) : "";
|
|
3349
3509
|
const aliasesTag = bundle.aliases && bundle.aliases.length > 0 ? pc.gray(` [alias: ${bundle.aliases.join(", ")}]`) : "";
|
|
@@ -3473,7 +3633,7 @@ ${pc.bold(pc.magenta(header))} ${pc.dim(`(${items.length} bundle${items.length >
|
|
|
3473
3633
|
const bBranch = isLastBundle ? "\u2514\u2500\u2500" : "\u251C\u2500\u2500";
|
|
3474
3634
|
const subIndent = isLastBundle ? " " : "\u2502 ";
|
|
3475
3635
|
const meta = BUNDLE_DISPLAY_NAMES[b.name];
|
|
3476
|
-
const isEssentials = !b.parentBundle && b.name !== "full" && b.name !== "universal-skills";
|
|
3636
|
+
const isEssentials = !b.parentBundle && b.name !== "full" && b.name !== "universal-skills" && b.name !== "universal-orchestration";
|
|
3477
3637
|
const titleSuffix = isEssentials ? pc.cyan(" (Essentials)") : "";
|
|
3478
3638
|
const parentTag = b.parentBundle ? pc.gray(` [inherits: ${b.parentBundle}]`) : "";
|
|
3479
3639
|
const aliasesTag = b.aliases && b.aliases.length > 0 ? pc.gray(` [alias: ${b.aliases.join(", ")}]`) : "";
|
|
@@ -3840,6 +4000,8 @@ cli.command("list", "List available bundles grouped by department domain").alias
|
|
|
3840
4000
|
}
|
|
3841
4001
|
const domainBundles = bundles.filter((b) => b.domain === activeDomain || activeDomain === "organization" && b.tier === "organization");
|
|
3842
4002
|
const sortedBundles = [...domainBundles].sort((a, b) => {
|
|
4003
|
+
if (a.name === "universal-orchestration") return -1;
|
|
4004
|
+
if (b.name === "universal-orchestration") return 1;
|
|
3843
4005
|
if (a.name === "universal-skills") return -1;
|
|
3844
4006
|
if (b.name === "universal-skills") return 1;
|
|
3845
4007
|
if (!a.parentBundle && b.parentBundle) return -1;
|
|
@@ -3850,7 +4012,7 @@ cli.command("list", "List available bundles grouped by department domain").alias
|
|
|
3850
4012
|
const isLast = idx === sortedBundles.length - 1;
|
|
3851
4013
|
const branch = sortedBundles.length > 1 ? isLast ? "\u2514\u2500\u2500 " : "\u251C\u2500\u2500 " : "";
|
|
3852
4014
|
const meta = BUNDLE_DISPLAY_NAMES[b.name];
|
|
3853
|
-
const isEssentials = !b.parentBundle && b.name !== "full" && b.name !== "universal-skills" && b.tier !== "organization";
|
|
4015
|
+
const isEssentials = !b.parentBundle && b.name !== "full" && b.name !== "universal-skills" && b.name !== "universal-orchestration" && b.tier !== "organization";
|
|
3854
4016
|
const titleSuffix = isEssentials ? pc.cyan(" (Essentials Base)") : "";
|
|
3855
4017
|
const parentTag = b.parentBundle ? pc.gray(` [inherits: ${b.parentBundle}]`) : "";
|
|
3856
4018
|
let badge = "";
|
|
@@ -4002,6 +4164,7 @@ cli.command("start <bundle> [prompt]", "Start an installed bundle team in its ho
|
|
|
4002
4164
|
outro(pc.red(`Cline executable was not found on PATH or via CLINE_BIN_PATH. Please install Cline CLI or ensure it is accessible.`));
|
|
4003
4165
|
process.exit(1);
|
|
4004
4166
|
}
|
|
4167
|
+
const bundleDef = await registry.getBundle(bundle);
|
|
4005
4168
|
const plan = launcher.planActivation({
|
|
4006
4169
|
bundleName: bundle,
|
|
4007
4170
|
workspace: resolution.workspace,
|
|
@@ -4010,7 +4173,8 @@ cli.command("start <bundle> [prompt]", "Start an installed bundle team in its ho
|
|
|
4010
4173
|
prompt,
|
|
4011
4174
|
teamName: options.team,
|
|
4012
4175
|
allowAddons: options.allowAddons,
|
|
4013
|
-
headless: options.headless
|
|
4176
|
+
headless: options.headless,
|
|
4177
|
+
orchestrator: bundleDef?.orchestrator
|
|
4014
4178
|
});
|
|
4015
4179
|
if (options.dryRun) {
|
|
4016
4180
|
note(
|
|
@@ -4049,7 +4213,7 @@ cli.command("doctor", "Verify health of installed agents, frontmatter schemas, a
|
|
|
4049
4213
|
console.log(pc.bold(pc.cyan("\u{1F4A1} Get Started:")));
|
|
4050
4214
|
console.log(` \u{1F449} ${pc.bold("agents add")} Launch the interactive installation wizard`);
|
|
4051
4215
|
console.log(` \u{1F449} ${pc.bold("agents add software-engineering")} Install the engineering essentials team`);
|
|
4052
|
-
console.log(` \u{1F449} ${pc.bold("agents list")} Browse all
|
|
4216
|
+
console.log(` \u{1F449} ${pc.bold("agents list")} Browse all 23 bundles and 8 departments
|
|
4053
4217
|
`);
|
|
4054
4218
|
if (report.clineCapability) {
|
|
4055
4219
|
console.log(pc.bold(pc.cyan("Cline Runtime & Compound Projection Audit:")));
|