opencode-agenthub 0.1.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.
Files changed (61) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +373 -0
  3. package/dist/composer/bootstrap.js +493 -0
  4. package/dist/composer/builtin-assets.js +139 -0
  5. package/dist/composer/capabilities.js +20 -0
  6. package/dist/composer/compose.js +824 -0
  7. package/dist/composer/defaults.js +10 -0
  8. package/dist/composer/home-transfer.js +288 -0
  9. package/dist/composer/install-home.js +5 -0
  10. package/dist/composer/library/README.md +93 -0
  11. package/dist/composer/library/bundles/auto.json +18 -0
  12. package/dist/composer/library/bundles/build.json +17 -0
  13. package/dist/composer/library/bundles/hr-adapter.json +26 -0
  14. package/dist/composer/library/bundles/hr-cto.json +24 -0
  15. package/dist/composer/library/bundles/hr-evaluator.json +26 -0
  16. package/dist/composer/library/bundles/hr-planner.json +26 -0
  17. package/dist/composer/library/bundles/hr-sourcer.json +24 -0
  18. package/dist/composer/library/bundles/hr-verifier.json +26 -0
  19. package/dist/composer/library/bundles/hr.json +35 -0
  20. package/dist/composer/library/bundles/plan.json +19 -0
  21. package/dist/composer/library/instructions/hr-boundaries.md +38 -0
  22. package/dist/composer/library/instructions/hr-protocol.md +102 -0
  23. package/dist/composer/library/profiles/auto.json +9 -0
  24. package/dist/composer/library/profiles/hr.json +9 -0
  25. package/dist/composer/library/souls/auto.md +29 -0
  26. package/dist/composer/library/souls/build.md +21 -0
  27. package/dist/composer/library/souls/hr-adapter.md +64 -0
  28. package/dist/composer/library/souls/hr-cto.md +57 -0
  29. package/dist/composer/library/souls/hr-evaluator.md +64 -0
  30. package/dist/composer/library/souls/hr-planner.md +48 -0
  31. package/dist/composer/library/souls/hr-sourcer.md +70 -0
  32. package/dist/composer/library/souls/hr-verifier.md +62 -0
  33. package/dist/composer/library/souls/hr.md +186 -0
  34. package/dist/composer/library/souls/plan.md +23 -0
  35. package/dist/composer/library/workflow/auto-mode.json +139 -0
  36. package/dist/composer/model-utils.js +39 -0
  37. package/dist/composer/opencode-profile.js +2299 -0
  38. package/dist/composer/package-manager.js +75 -0
  39. package/dist/composer/package-version.js +20 -0
  40. package/dist/composer/platform.js +48 -0
  41. package/dist/composer/query.js +133 -0
  42. package/dist/composer/settings.js +400 -0
  43. package/dist/plugins/opencode-agenthub.js +310 -0
  44. package/dist/plugins/opencode-question.js +223 -0
  45. package/dist/plugins/plan-guidance.js +263 -0
  46. package/dist/plugins/runtime-config.js +57 -0
  47. package/dist/skills/agenthub-doctor/SKILL.md +238 -0
  48. package/dist/skills/agenthub-doctor/diagnose.js +213 -0
  49. package/dist/skills/agenthub-doctor/fix.js +293 -0
  50. package/dist/skills/agenthub-doctor/index.js +30 -0
  51. package/dist/skills/agenthub-doctor/interactive.js +756 -0
  52. package/dist/skills/hr-assembly/SKILL.md +121 -0
  53. package/dist/skills/hr-final-check/SKILL.md +98 -0
  54. package/dist/skills/hr-review/SKILL.md +100 -0
  55. package/dist/skills/hr-staffing/SKILL.md +85 -0
  56. package/dist/skills/hr-support/bin/sync_sources.py +560 -0
  57. package/dist/skills/hr-support/bin/validate_staged_package.py +290 -0
  58. package/dist/skills/hr-support/bin/vendor_stage_mcps.py +234 -0
  59. package/dist/skills/hr-support/bin/vendor_stage_skills.py +104 -0
  60. package/dist/types.js +11 -0
  61. package/package.json +54 -0
@@ -0,0 +1,493 @@
1
+ import { chmod, cp, mkdir, readdir, stat, writeFile } from "node:fs/promises";
2
+ import os from "node:os";
3
+ import path from "node:path";
4
+ import { stdin as input, stdout as output } from "node:process";
5
+ import readline from "node:readline/promises";
6
+ import { fileURLToPath } from "node:url";
7
+ import { installPackageDependencies } from "./package-manager.js";
8
+ import {
9
+ buildBuiltinVersionManifest,
10
+ getManagedCodingHrHubAssetSpecs
11
+ } from "./builtin-assets.js";
12
+ import { readPackageVersion } from "./package-version.js";
13
+ import { resolveHomeConfigRoot, shouldChmod } from "./platform.js";
14
+ import {
15
+ buildInitialAgentHubSettings,
16
+ resolveHrBootstrapAgentModels,
17
+ mergeAgentHubSettingsDefaults,
18
+ readAgentHubSettings,
19
+ writeAgentHubSettings
20
+ } from "./settings.js";
21
+ const currentDir = path.dirname(fileURLToPath(import.meta.url));
22
+ const libraryRoot = path.join(currentDir, "library");
23
+ const sourceRoot = path.dirname(currentDir);
24
+ const defaultHrGithubSources = [
25
+ "garrytan/gstack",
26
+ "anthropics/skills",
27
+ "msitarzewski/agency-agents",
28
+ "obra/superpowers"
29
+ ];
30
+ const syncManagedAssetSpecs = async (specs, version, options = {}) => {
31
+ const added = [];
32
+ const updated = [];
33
+ const skipped = [];
34
+ const manifest = {};
35
+ for (const spec of specs) {
36
+ const exists = await pathExists(spec.target);
37
+ manifest[spec.manifestKey] = version;
38
+ if (exists && !options.force) {
39
+ skipped.push(spec.manifestKey);
40
+ continue;
41
+ }
42
+ if (!options.dryRun) {
43
+ await mkdir(path.dirname(spec.target), { recursive: true });
44
+ await cp(spec.source, spec.target, {
45
+ recursive: Boolean(spec.recursive),
46
+ force: true
47
+ });
48
+ if (spec.executable && shouldChmod()) {
49
+ await chmod(spec.target, 493);
50
+ }
51
+ }
52
+ (exists ? updated : added).push(spec.manifestKey);
53
+ }
54
+ return { added, updated, skipped, manifest };
55
+ };
56
+ const mergeBuiltinManifest = (existing, next) => ({
57
+ ...existing || {},
58
+ ...next
59
+ });
60
+ const pruneBuiltinManifest = (existing, allowedKeys) => {
61
+ if (!existing) return void 0;
62
+ const allowed = new Set(allowedKeys);
63
+ const pruned = Object.fromEntries(
64
+ Object.entries(existing).filter(([key]) => allowed.has(key))
65
+ );
66
+ return Object.keys(pruned).length > 0 ? pruned : void 0;
67
+ };
68
+ const withBuiltinManifest = (settings, manifest) => ({
69
+ ...settings,
70
+ meta: {
71
+ ...settings.meta,
72
+ builtinVersion: mergeBuiltinManifest(settings.meta?.builtinVersion, manifest)
73
+ }
74
+ });
75
+ const withBuiltinManifestForMode = (settings, manifest, mode) => ({
76
+ ...settings,
77
+ meta: {
78
+ ...settings.meta,
79
+ builtinVersion: mergeBuiltinManifest(
80
+ pruneBuiltinManifest(
81
+ settings.meta?.builtinVersion,
82
+ Object.keys(buildBuiltinVersionManifest(mode, readPackageVersion()))
83
+ ),
84
+ manifest
85
+ )
86
+ }
87
+ });
88
+ const installCodingStarter = async (targetRoot, version) => syncManagedAssetSpecs(
89
+ getManagedCodingHrHubAssetSpecs(targetRoot, "auto"),
90
+ version
91
+ );
92
+ const installHrOfficeStarter = async (targetRoot, version) => syncManagedAssetSpecs(
93
+ getManagedCodingHrHubAssetSpecs(targetRoot, "hr-office"),
94
+ version
95
+ );
96
+ const installHrHelperScripts = async (hrRoot) => {
97
+ const scriptsRoot = path.join(sourceRoot, "skills", "hr-support", "bin");
98
+ const targetBinRoot = path.join(hrRoot, "bin");
99
+ await mkdir(targetBinRoot, { recursive: true });
100
+ for (const scriptName of [
101
+ "sync_sources.py",
102
+ "vendor_stage_skills.py",
103
+ "validate_staged_package.py"
104
+ ]) {
105
+ const source = path.join(scriptsRoot, scriptName);
106
+ const target = path.join(targetBinRoot, scriptName);
107
+ if (!await pathExists(target)) {
108
+ await cp(source, target, { force: true });
109
+ if (shouldChmod()) {
110
+ await chmod(target, 493);
111
+ }
112
+ }
113
+ }
114
+ };
115
+ const defaultAgentHubHome = () => process.env.OPENCODE_AGENTHUB_HOME || resolveHomeConfigRoot(os.homedir(), "opencode-agenthub");
116
+ const defaultHrHome = () => process.env.OPENCODE_AGENTHUB_HR_HOME || resolveHomeConfigRoot(os.homedir(), "opencode-agenthub-hr");
117
+ const pathExists = async (target) => {
118
+ try {
119
+ await stat(target);
120
+ return true;
121
+ } catch {
122
+ return false;
123
+ }
124
+ };
125
+ const ensureAgentHubSkeleton = async (targetRoot) => {
126
+ await mkdir(targetRoot, { recursive: true });
127
+ await mkdir(path.join(targetRoot, "souls"), { recursive: true });
128
+ await mkdir(path.join(targetRoot, "skills"), { recursive: true });
129
+ await mkdir(path.join(targetRoot, "bundles"), { recursive: true });
130
+ await mkdir(path.join(targetRoot, "profiles"), { recursive: true });
131
+ };
132
+ const ensureHrHomeSkeleton = async (hrRoot) => {
133
+ await mkdir(hrRoot, { recursive: true });
134
+ await mkdir(path.join(hrRoot, "bin"), { recursive: true });
135
+ await mkdir(path.join(hrRoot, "inventory", "workers"), { recursive: true });
136
+ await mkdir(path.join(hrRoot, "inventory", "models"), { recursive: true });
137
+ await mkdir(path.join(hrRoot, "sources", "github"), { recursive: true });
138
+ await mkdir(path.join(hrRoot, "staging"), { recursive: true });
139
+ await mkdir(path.join(hrRoot, "output"), { recursive: true });
140
+ await mkdir(path.join(hrRoot, "logs"), { recursive: true });
141
+ await mkdir(path.join(hrRoot, "state", "staffing-plans"), { recursive: true });
142
+ await mkdir(path.join(hrRoot, "state", "architecture-reviews"), { recursive: true });
143
+ const configPath = path.join(hrRoot, "hr-config.json");
144
+ if (!await pathExists(configPath)) {
145
+ const defaultConfig = {
146
+ schema_version: "1.1",
147
+ sources: {
148
+ github: defaultHrGithubSources,
149
+ models: [
150
+ {
151
+ source_id: "models-dev",
152
+ url: "https://models.dev/api.json",
153
+ format: "models.dev"
154
+ }
155
+ ]
156
+ },
157
+ settings: {
158
+ auto_sync: false,
159
+ sync_depth: 1
160
+ }
161
+ };
162
+ await writeFile(configPath, `${JSON.stringify(defaultConfig, null, 2)}
163
+ `, "utf-8");
164
+ }
165
+ await installHrHelperScripts(hrRoot);
166
+ };
167
+ const ensureHrOfficeSkeleton = async (hrRoot) => {
168
+ await ensureHrHomeSkeleton(hrRoot);
169
+ await ensureAgentHubSkeleton(hrRoot);
170
+ };
171
+ const hrHomeInitialized = async (hrRoot = defaultHrHome()) => {
172
+ const [libraryOk, configOk, profileOk, bundleOk, settingsOk] = await Promise.all([
173
+ agentHubHomeInitialized(hrRoot),
174
+ pathExists(path.join(hrRoot, "hr-config.json")),
175
+ pathExists(path.join(hrRoot, "profiles", "hr.json")),
176
+ pathExists(path.join(hrRoot, "bundles", "hr.json")),
177
+ pathExists(path.join(hrRoot, "settings.json"))
178
+ ]);
179
+ return libraryOk && configOk && profileOk && bundleOk && settingsOk;
180
+ };
181
+ const installHrOfficeHome = async (hrRoot = defaultHrHome()) => {
182
+ return installHrOfficeHomeWithOptions({ hrRoot });
183
+ };
184
+ const installHrOfficeHomeWithOptions = async ({
185
+ hrRoot = defaultHrHome(),
186
+ hrModelSelection
187
+ }) => {
188
+ const packageVersion = readPackageVersion();
189
+ await ensureHrOfficeSkeleton(hrRoot);
190
+ await copyLibraryReadme(hrRoot);
191
+ await installHrOfficeStarter(hrRoot, packageVersion);
192
+ const resolvedHrModels = await resolveHrBootstrapAgentModels({
193
+ targetRoot: hrRoot,
194
+ selection: hrModelSelection
195
+ });
196
+ const existingSettings = await readAgentHubSettings(hrRoot);
197
+ if (!existingSettings) {
198
+ const initialSettings = await buildInitialAgentHubSettings({
199
+ targetRoot: hrRoot,
200
+ mode: "hr-office",
201
+ hrResolvedModels: resolvedHrModels
202
+ });
203
+ await writeAgentHubSettings(
204
+ hrRoot,
205
+ initialSettings
206
+ );
207
+ } else {
208
+ const mergedSettings = mergeAgentHubSettingsDefaults(existingSettings);
209
+ const builtinVersion = buildBuiltinVersionManifest("hr-office", packageVersion);
210
+ mergedSettings.agents = mergedSettings.agents || {};
211
+ for (const [agentName, modelSelection] of Object.entries(resolvedHrModels.agentModels)) {
212
+ const existingAgentSettings = mergedSettings.agents[agentName] || {};
213
+ if (!existingAgentSettings.model || !existingAgentSettings.variant) {
214
+ mergedSettings.agents[agentName] = {
215
+ ...existingAgentSettings,
216
+ ...existingAgentSettings.model ? {} : { model: modelSelection.model },
217
+ ...existingAgentSettings.variant || !modelSelection.variant ? {} : { variant: modelSelection.variant }
218
+ };
219
+ }
220
+ }
221
+ mergedSettings.meta = {
222
+ ...mergedSettings.meta,
223
+ onboarding: {
224
+ ...mergedSettings.meta?.onboarding,
225
+ modelStrategy: mergedSettings.meta?.onboarding?.modelStrategy || resolvedHrModels.strategy
226
+ }
227
+ };
228
+ await writeAgentHubSettings(
229
+ hrRoot,
230
+ withBuiltinManifestForMode(mergedSettings, builtinVersion, "hr-office")
231
+ );
232
+ }
233
+ return hrRoot;
234
+ };
235
+ const copyLibraryReadme = async (targetRoot) => {
236
+ const source = path.join(libraryRoot, "README.md");
237
+ const target = path.join(targetRoot, "README.md");
238
+ if (await pathExists(target)) return;
239
+ await cp(source, target);
240
+ };
241
+ const copySkillsFrom = async (sourceRoot2, targetRoot) => {
242
+ const targetSkillsRoot = path.join(targetRoot, "skills");
243
+ await mkdir(targetSkillsRoot, { recursive: true });
244
+ for (const entry of await readdir(sourceRoot2, { withFileTypes: true })) {
245
+ if (!entry.isDirectory()) continue;
246
+ const source = path.join(sourceRoot2, entry.name);
247
+ const target = path.join(targetSkillsRoot, entry.name);
248
+ if (await pathExists(target)) continue;
249
+ await cp(source, target, { recursive: true });
250
+ }
251
+ };
252
+ const copySoulsFrom = async (sourceRoot2, targetRoot) => {
253
+ const targetSoulsRoot = path.join(targetRoot, "souls");
254
+ await mkdir(targetSoulsRoot, { recursive: true });
255
+ for (const entry of await readdir(sourceRoot2, { withFileTypes: true })) {
256
+ if (!entry.isFile() || path.extname(entry.name) !== ".md") continue;
257
+ const source = path.join(sourceRoot2, entry.name);
258
+ const target = path.join(targetSoulsRoot, entry.name);
259
+ if (await pathExists(target)) continue;
260
+ await cp(source, target);
261
+ }
262
+ };
263
+ const copyInstructionsFrom = async (sourceRoot2, targetRoot) => {
264
+ const targetInstructionsRoot = path.join(targetRoot, "instructions");
265
+ await mkdir(targetInstructionsRoot, { recursive: true });
266
+ for (const entry of await readdir(sourceRoot2, { withFileTypes: true })) {
267
+ if (!entry.isFile() || path.extname(entry.name) !== ".md") continue;
268
+ const source = path.join(sourceRoot2, entry.name);
269
+ const target = path.join(targetInstructionsRoot, entry.name);
270
+ if (await pathExists(target)) continue;
271
+ await cp(source, target);
272
+ }
273
+ };
274
+ const supportedMcpServerExtensions = /* @__PURE__ */ new Set([".ts", ".js", ".mjs", ".cjs"]);
275
+ const mcpServerPackageManifest = "package.json";
276
+ const copyMcpServersFrom = async (sourceRoot2, targetRoot) => {
277
+ const targetMcpServersRoot = path.join(targetRoot, "mcp-servers");
278
+ await mkdir(targetMcpServersRoot, { recursive: true });
279
+ const importedServers = [];
280
+ const sourcePackageManifest = path.join(sourceRoot2, mcpServerPackageManifest);
281
+ const targetPackageManifest = path.join(
282
+ targetMcpServersRoot,
283
+ mcpServerPackageManifest
284
+ );
285
+ if (await pathExists(sourcePackageManifest)) {
286
+ await cp(sourcePackageManifest, targetPackageManifest, { force: true });
287
+ }
288
+ for (const entry of await readdir(sourceRoot2, { withFileTypes: true })) {
289
+ if (!entry.isFile()) continue;
290
+ const extension = path.extname(entry.name);
291
+ if (!supportedMcpServerExtensions.has(extension)) continue;
292
+ const source = path.join(sourceRoot2, entry.name);
293
+ const target = path.join(targetMcpServersRoot, entry.name);
294
+ if (!await pathExists(target)) {
295
+ await cp(source, target);
296
+ }
297
+ importedServers.push({
298
+ name: path.basename(entry.name, extension),
299
+ fileName: entry.name
300
+ });
301
+ }
302
+ return importedServers;
303
+ };
304
+ const registerImportedMcpServers = async (servers, targetRoot) => {
305
+ const targetMcpRoot = path.join(targetRoot, "mcp");
306
+ await mkdir(targetMcpRoot, { recursive: true });
307
+ for (const server of servers) {
308
+ const target = path.join(targetMcpRoot, `${server.name}.json`);
309
+ if (await pathExists(target)) continue;
310
+ const extension = path.extname(server.fileName);
311
+ const scriptPath = `${"$"}{LIBRARY_ROOT}/mcp-servers/${server.fileName}`;
312
+ const payload = {
313
+ type: "local",
314
+ command: extension === ".ts" ? [
315
+ "node",
316
+ "--import",
317
+ `${"$"}{LIBRARY_ROOT}/mcp-servers/node_modules/tsx/dist/loader.mjs`,
318
+ scriptPath
319
+ ] : ["node", scriptPath],
320
+ timeout: 3e4
321
+ };
322
+ await writeFile(target, `${JSON.stringify(payload, null, 2)}
323
+ `, "utf-8");
324
+ }
325
+ };
326
+ const installMcpServerDependencies = async (targetRoot) => {
327
+ const targetMcpServersRoot = path.join(targetRoot, "mcp-servers");
328
+ const packageManifest = path.join(
329
+ targetMcpServersRoot,
330
+ mcpServerPackageManifest
331
+ );
332
+ if (!await pathExists(packageManifest)) return;
333
+ await installPackageDependencies(targetMcpServersRoot);
334
+ };
335
+ const installAgentHubHome = async ({
336
+ targetRoot = defaultAgentHubHome(),
337
+ importSoulsPath,
338
+ importInstructionsPath,
339
+ importSkillsPath,
340
+ importMcpServersPath,
341
+ mode = "auto"
342
+ } = {}) => {
343
+ let importedServers = [];
344
+ const packageVersion = readPackageVersion();
345
+ await ensureAgentHubSkeleton(targetRoot);
346
+ await copyLibraryReadme(targetRoot);
347
+ if (mode === "auto") {
348
+ await installCodingStarter(targetRoot, packageVersion);
349
+ }
350
+ if (importSoulsPath) {
351
+ await copySoulsFrom(importSoulsPath, targetRoot);
352
+ }
353
+ if (importInstructionsPath) {
354
+ await copyInstructionsFrom(importInstructionsPath, targetRoot);
355
+ }
356
+ if (importSkillsPath) {
357
+ await copySkillsFrom(importSkillsPath, targetRoot);
358
+ }
359
+ if (importMcpServersPath) {
360
+ importedServers = await copyMcpServersFrom(
361
+ importMcpServersPath,
362
+ targetRoot
363
+ );
364
+ await registerImportedMcpServers(importedServers, targetRoot);
365
+ await installMcpServerDependencies(targetRoot);
366
+ }
367
+ const existingSettings = await readAgentHubSettings(targetRoot);
368
+ if (!existingSettings) {
369
+ await writeAgentHubSettings(
370
+ targetRoot,
371
+ await buildInitialAgentHubSettings({ targetRoot, mode })
372
+ );
373
+ } else {
374
+ const mergedSettings = mergeAgentHubSettingsDefaults(existingSettings);
375
+ const builtinVersion = buildBuiltinVersionManifest(mode, packageVersion);
376
+ await writeAgentHubSettings(
377
+ targetRoot,
378
+ withBuiltinManifestForMode(mergedSettings, builtinVersion, mode)
379
+ );
380
+ }
381
+ return targetRoot;
382
+ };
383
+ const syncBuiltInAgentHubAssets = async ({
384
+ targetRoot = defaultAgentHubHome(),
385
+ mode = "auto",
386
+ force = false,
387
+ dryRun = false
388
+ }) => {
389
+ if (!dryRun) {
390
+ await ensureAgentHubSkeleton(targetRoot);
391
+ }
392
+ const report = await syncManagedAssetSpecs(
393
+ getManagedCodingHrHubAssetSpecs(targetRoot, mode),
394
+ readPackageVersion(),
395
+ { force, dryRun }
396
+ );
397
+ if (!dryRun) {
398
+ const existingSettings = await readAgentHubSettings(targetRoot);
399
+ if (existingSettings) {
400
+ await writeAgentHubSettings(targetRoot, withBuiltinManifestForMode(existingSettings, report.manifest, mode));
401
+ }
402
+ }
403
+ return report;
404
+ };
405
+ const agentHubHomeInitialized = async (targetRoot = defaultAgentHubHome()) => {
406
+ const [soulsOk, skillsOk, bundlesOk, profilesOk] = await Promise.all([
407
+ pathExists(path.join(targetRoot, "souls")),
408
+ pathExists(path.join(targetRoot, "skills")),
409
+ pathExists(path.join(targetRoot, "bundles")),
410
+ pathExists(path.join(targetRoot, "profiles"))
411
+ ]);
412
+ return soulsOk && skillsOk && bundlesOk && profilesOk;
413
+ };
414
+ const normalizeOptionalPath = (value) => {
415
+ const trimmed = value.trim();
416
+ if (!trimmed) return void 0;
417
+ return path.resolve(trimmed);
418
+ };
419
+ const promptSetupMode = async (rl) => {
420
+ while (true) {
421
+ process.stdout.write("\nSetup options:\n");
422
+ process.stdout.write(" auto - Full setup with built-in Auto + Plan + Build\n");
423
+ process.stdout.write(" minimal - Structure only\n\n");
424
+ const modeAnswer = await rl.question(
425
+ "Setup [auto/minimal] (recommended: auto): "
426
+ );
427
+ const normalizedMode = modeAnswer.trim().toLowerCase();
428
+ if (!normalizedMode) return "auto";
429
+ if (normalizedMode === "minimal" || normalizedMode === "auto") {
430
+ return normalizedMode;
431
+ }
432
+ process.stdout.write(
433
+ "Invalid setup choice. Type 'auto', 'minimal', or press Enter for the recommended default.\n"
434
+ );
435
+ }
436
+ };
437
+ const promptHubInitAnswers = async () => {
438
+ const rl = readline.createInterface({ input, output });
439
+ try {
440
+ const suggestedRoot = defaultAgentHubHome();
441
+ const locationAnswer = await rl.question(
442
+ `Agent Hub home location [${suggestedRoot}]: `
443
+ );
444
+ const targetRoot = normalizeOptionalPath(locationAnswer) || suggestedRoot;
445
+ const mode = await promptSetupMode(rl);
446
+ let importSoulsPath;
447
+ let importInstructionsPath;
448
+ let importSkillsPath;
449
+ let importMcpServersPath;
450
+ if (mode === "minimal") {
451
+ const importSoulsAnswer = await rl.question(
452
+ "Existing soul/agent prompt folder to import (leave blank to skip): "
453
+ );
454
+ importSoulsPath = normalizeOptionalPath(importSoulsAnswer);
455
+ const importInstructionsAnswer = await rl.question(
456
+ "Existing instructions folder to import (leave blank to skip): "
457
+ );
458
+ importInstructionsPath = normalizeOptionalPath(importInstructionsAnswer);
459
+ const importAnswer = await rl.question(
460
+ "Existing skills folder to import (leave blank to skip): "
461
+ );
462
+ importSkillsPath = normalizeOptionalPath(importAnswer);
463
+ const importMcpAnswer = await rl.question(
464
+ "Existing MCP server folder to import (leave blank to skip): "
465
+ );
466
+ importMcpServersPath = normalizeOptionalPath(importMcpAnswer);
467
+ }
468
+ return {
469
+ targetRoot,
470
+ importSoulsPath,
471
+ importInstructionsPath,
472
+ importSkillsPath,
473
+ importMcpServersPath,
474
+ mode
475
+ };
476
+ } finally {
477
+ rl.close();
478
+ }
479
+ };
480
+ export {
481
+ agentHubHomeInitialized,
482
+ defaultAgentHubHome,
483
+ defaultHrHome,
484
+ ensureAgentHubSkeleton,
485
+ ensureHrHomeSkeleton,
486
+ ensureHrOfficeSkeleton,
487
+ hrHomeInitialized,
488
+ installAgentHubHome,
489
+ installHrOfficeHome,
490
+ installHrOfficeHomeWithOptions,
491
+ promptHubInitAnswers,
492
+ syncBuiltInAgentHubAssets
493
+ };
@@ -0,0 +1,139 @@
1
+ import { readdir } from "node:fs/promises";
2
+ import path from "node:path";
3
+ import { fileURLToPath } from "node:url";
4
+ const currentDir = path.dirname(fileURLToPath(import.meta.url));
5
+ const builtInLibraryRoot = path.join(currentDir, "library");
6
+ const builtInSkillsRoot = path.resolve(currentDir, "..", "skills");
7
+ const hrSupportBinRoot = path.join(builtInSkillsRoot, "hr-support", "bin");
8
+ const codingLibraryFiles = [
9
+ "bundles/auto.json",
10
+ "bundles/plan.json",
11
+ "bundles/build.json",
12
+ "profiles/auto.json",
13
+ "souls/auto.md",
14
+ "souls/plan.md",
15
+ "souls/build.md"
16
+ ];
17
+ const hrLibraryFiles = [
18
+ "bundles/hr.json",
19
+ "bundles/hr-planner.json",
20
+ "bundles/hr-sourcer.json",
21
+ "bundles/hr-evaluator.json",
22
+ "bundles/hr-cto.json",
23
+ "bundles/hr-adapter.json",
24
+ "bundles/hr-verifier.json",
25
+ "instructions/hr-boundaries.md",
26
+ "instructions/hr-protocol.md",
27
+ "profiles/hr.json",
28
+ "souls/hr.md",
29
+ "souls/hr-planner.md",
30
+ "souls/hr-sourcer.md",
31
+ "souls/hr-evaluator.md",
32
+ "souls/hr-cto.md",
33
+ "souls/hr-adapter.md",
34
+ "souls/hr-verifier.md"
35
+ ];
36
+ const hrSkillDirectories = [
37
+ "hr-staffing",
38
+ "hr-review",
39
+ "hr-assembly",
40
+ "hr-final-check"
41
+ ];
42
+ const hrHelperScripts = [
43
+ "sync_sources.py",
44
+ "vendor_stage_skills.py",
45
+ "vendor_stage_mcps.py",
46
+ "validate_staged_package.py"
47
+ ];
48
+ const listNamesByExtension = async (root, extension) => {
49
+ try {
50
+ const entries = await readdir(root, { withFileTypes: true });
51
+ return new Set(
52
+ entries.filter((entry) => entry.isFile() && entry.name.endsWith(extension)).map((entry) => entry.name.slice(0, -extension.length))
53
+ );
54
+ } catch {
55
+ return /* @__PURE__ */ new Set();
56
+ }
57
+ };
58
+ const listDirectoryNames = async (root) => {
59
+ try {
60
+ const entries = await readdir(root, { withFileTypes: true });
61
+ return new Set(entries.filter((entry) => entry.isDirectory()).map((entry) => entry.name));
62
+ } catch {
63
+ return /* @__PURE__ */ new Set();
64
+ }
65
+ };
66
+ const listBuiltInAssetNames = async (kind) => {
67
+ if (kind === "bundle") {
68
+ return listNamesByExtension(path.join(builtInLibraryRoot, "bundles"), ".json");
69
+ }
70
+ if (kind === "profile") {
71
+ return listNamesByExtension(path.join(builtInLibraryRoot, "profiles"), ".json");
72
+ }
73
+ if (kind === "soul") {
74
+ return listNamesByExtension(path.join(builtInLibraryRoot, "souls"), ".md");
75
+ }
76
+ if (kind === "instruction") {
77
+ return listNamesByExtension(path.join(builtInLibraryRoot, "instructions"), ".md");
78
+ }
79
+ return listDirectoryNames(builtInSkillsRoot);
80
+ };
81
+ const manifestScopeForMode = (mode) => {
82
+ if (mode === "auto") {
83
+ return codingLibraryFiles;
84
+ }
85
+ if (mode === "hr-office") {
86
+ return [
87
+ ...hrLibraryFiles,
88
+ ...hrSkillDirectories.map((name) => `skills/${name}`),
89
+ ...hrHelperScripts.map((name) => `hr-home/bin/${name}`)
90
+ ];
91
+ }
92
+ return [];
93
+ };
94
+ const getBuiltInManifestKeysForMode = (mode) => manifestScopeForMode(mode);
95
+ const buildBuiltinVersionManifest = (mode, version) => Object.fromEntries(
96
+ getBuiltInManifestKeysForMode(mode).map((manifestKey) => [manifestKey, version])
97
+ );
98
+ const getManagedHubAssetSpecs = (targetRoot, mode) => {
99
+ const manifestKeys = manifestScopeForMode(mode).filter(
100
+ (key) => !key.startsWith("hr-home/") && !key.startsWith("skills/")
101
+ );
102
+ return manifestKeys.map((manifestKey) => ({
103
+ manifestKey,
104
+ source: path.join(builtInLibraryRoot, ...manifestKey.split("/")),
105
+ target: path.join(targetRoot, ...manifestKey.split("/")),
106
+ recursive: false
107
+ }));
108
+ };
109
+ const getManagedCodingHrHubAssetSpecs = (targetRoot, mode) => {
110
+ const specs = getManagedHubAssetSpecs(targetRoot, mode);
111
+ if (mode !== "hr-office") return specs;
112
+ return [
113
+ ...specs,
114
+ ...hrSkillDirectories.map((name) => ({
115
+ manifestKey: `skills/${name}`,
116
+ source: path.join(builtInSkillsRoot, name),
117
+ target: path.join(targetRoot, "skills", name),
118
+ recursive: true
119
+ }))
120
+ ];
121
+ };
122
+ const getManagedHrHomeAssetSpecs = (hrRoot, mode) => {
123
+ if (mode !== "hr-office") return [];
124
+ return hrHelperScripts.map((name) => ({
125
+ manifestKey: `hr-home/bin/${name}`,
126
+ source: path.join(hrSupportBinRoot, name),
127
+ target: path.join(hrRoot, "bin", name),
128
+ recursive: false,
129
+ executable: true
130
+ }));
131
+ };
132
+ export {
133
+ buildBuiltinVersionManifest,
134
+ getBuiltInManifestKeysForMode,
135
+ getManagedCodingHrHubAssetSpecs,
136
+ getManagedHrHomeAssetSpecs,
137
+ getManagedHubAssetSpecs,
138
+ listBuiltInAssetNames
139
+ };
@@ -0,0 +1,20 @@
1
+ const PROFILE_ADD_CAPABILITY_REGISTRY = {
2
+ "hr-suite": [
3
+ "hr",
4
+ "hr-planner",
5
+ "hr-sourcer",
6
+ "hr-evaluator",
7
+ "hr-cto",
8
+ "hr-adapter",
9
+ "hr-verifier"
10
+ ]
11
+ };
12
+ const expandProfileAddSelections = (selections) => selections.flatMap(
13
+ (selection) => PROFILE_ADD_CAPABILITY_REGISTRY[selection] ?? [selection]
14
+ );
15
+ const listProfileAddCapabilityNames = () => Object.keys(PROFILE_ADD_CAPABILITY_REGISTRY).sort();
16
+ export {
17
+ PROFILE_ADD_CAPABILITY_REGISTRY,
18
+ expandProfileAddSelections,
19
+ listProfileAddCapabilityNames
20
+ };