@agent-team-foundation/first-tree-hub 0.3.4 → 0.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/dist/{bootstrap-CPdLNPme.mjs → bootstrap-uyPaaI05.mjs} +24 -14
- package/dist/cli/index.mjs +39 -34
- package/dist/{core-CZjUVAU-.mjs → core-CMeOAZmx.mjs} +504 -812
- package/dist/drizzle/0007_decouple_context_tree.sql +2 -0
- package/dist/drizzle/meta/_journal.json +7 -0
- package/dist/index.mjs +3 -3
- package/dist/web/assets/index-C4J9gHaF.js +280 -0
- package/dist/web/assets/index-vo2Sa6IQ.css +1 -0
- package/dist/web/index.html +2 -2
- package/package.json +1 -1
- package/dist/web/assets/index-BHn3RVzY.js +0 -272
- package/dist/web/assets/index-BURu6jt9.css +0 -1
|
@@ -72,7 +72,7 @@ const clientConfigSchema = defineConfig({
|
|
|
72
72
|
function getClientConfig() {
|
|
73
73
|
return getConfig();
|
|
74
74
|
}
|
|
75
|
-
const DEFAULT_HOME_DIR = join(homedir(), ".first-tree-hub");
|
|
75
|
+
const DEFAULT_HOME_DIR = process.env.FIRST_TREE_HUB_HOME ?? join(homedir(), ".first-tree-hub");
|
|
76
76
|
const DEFAULT_CONFIG_DIR = join(DEFAULT_HOME_DIR, "config");
|
|
77
77
|
const DEFAULT_DATA_DIR = join(DEFAULT_HOME_DIR, "data");
|
|
78
78
|
function isFieldDef(value) {
|
|
@@ -450,33 +450,37 @@ const serverConfigSchema = defineConfig({
|
|
|
450
450
|
secret: true
|
|
451
451
|
})
|
|
452
452
|
},
|
|
453
|
-
contextTree: {
|
|
453
|
+
contextTree: optional({
|
|
454
454
|
repo: field(z.string(), {
|
|
455
455
|
env: "FIRST_TREE_HUB_CONTEXT_TREE_REPO",
|
|
456
456
|
prompt: { message: "Context Tree repo URL (e.g. https://github.com/org/first-tree):" }
|
|
457
457
|
}),
|
|
458
|
-
branch: field(z.string().default("main"))
|
|
459
|
-
|
|
460
|
-
},
|
|
458
|
+
branch: field(z.string().default("main"))
|
|
459
|
+
}),
|
|
461
460
|
github: {
|
|
462
|
-
token: field(z.string(), {
|
|
461
|
+
token: field(z.string().optional(), {
|
|
463
462
|
env: "FIRST_TREE_HUB_GITHUB_TOKEN",
|
|
464
|
-
secret: true
|
|
465
|
-
prompt: {
|
|
466
|
-
message: "GitHub token (create at https://github.com/settings/tokens → repo scope):",
|
|
467
|
-
type: "password"
|
|
468
|
-
}
|
|
463
|
+
secret: true
|
|
469
464
|
}),
|
|
470
465
|
webhookSecret: field(z.string().optional(), {
|
|
471
466
|
env: "FIRST_TREE_HUB_GITHUB_WEBHOOK_SECRET",
|
|
472
467
|
secret: true
|
|
473
|
-
})
|
|
468
|
+
}),
|
|
469
|
+
allowedOrg: field(z.string().optional(), { env: "FIRST_TREE_HUB_GITHUB_ALLOWED_ORG" })
|
|
474
470
|
},
|
|
475
471
|
cors: optional({ origin: field(z.string(), { env: "FIRST_TREE_HUB_CORS_ORIGIN" }) }),
|
|
476
472
|
rateLimit: optional({
|
|
477
473
|
max: field(z.number().default(100), { env: "FIRST_TREE_HUB_RATE_LIMIT_MAX" }),
|
|
478
474
|
loginMax: field(z.number().default(5), { env: "FIRST_TREE_HUB_RATE_LIMIT_LOGIN_MAX" }),
|
|
479
475
|
webhookMax: field(z.number().default(60), { env: "FIRST_TREE_HUB_RATE_LIMIT_WEBHOOK_MAX" })
|
|
476
|
+
}),
|
|
477
|
+
kael: optional({
|
|
478
|
+
endpoint: field(z.string(), { env: "KAEL_ENDPOINT" }),
|
|
479
|
+
apiKey: field(z.string(), {
|
|
480
|
+
env: "KAEL_API_KEY",
|
|
481
|
+
secret: true
|
|
482
|
+
}),
|
|
483
|
+
hubPublicUrl: field(z.string(), { env: "FIRST_TREE_HUB_PUBLIC_URL" })
|
|
480
484
|
})
|
|
481
485
|
});
|
|
482
486
|
//#endregion
|
|
@@ -530,13 +534,19 @@ function resolveServerUrl(flagValue) {
|
|
|
530
534
|
*/
|
|
531
535
|
async function bootstrapToken(serverUrl, agentId, options = {}) {
|
|
532
536
|
const githubToken = getGitHubToken();
|
|
537
|
+
const body = { name: "bootstrap" };
|
|
538
|
+
if (options.type) body.type = options.type;
|
|
539
|
+
if (options.displayName) body.displayName = options.displayName;
|
|
540
|
+
if (options.delegateMention) body.delegateMention = options.delegateMention;
|
|
541
|
+
if (options.profile) body.profile = options.profile;
|
|
542
|
+
if (options.metadata) body.metadata = options.metadata;
|
|
533
543
|
const res = await fetch(`${serverUrl}/api/v1/bootstrap/${encodeURIComponent(agentId)}/token`, {
|
|
534
544
|
method: "POST",
|
|
535
545
|
headers: {
|
|
536
546
|
"X-GitHub-Token": githubToken,
|
|
537
547
|
"Content-Type": "application/json"
|
|
538
548
|
},
|
|
539
|
-
body: JSON.stringify(
|
|
549
|
+
body: JSON.stringify(body)
|
|
540
550
|
});
|
|
541
551
|
if (!res.ok) {
|
|
542
552
|
const msg = (await res.json().catch(() => ({}))).error ?? `HTTP ${res.status}`;
|
|
@@ -580,4 +590,4 @@ async function checkBootstrapStatus(serverUrl, agentId) {
|
|
|
580
590
|
return await res.json();
|
|
581
591
|
}
|
|
582
592
|
//#endregion
|
|
583
|
-
export {
|
|
593
|
+
export { setConfigValue as S, readConfigFile as _, getGitHubUsername as a, resolveConfigReadonly as b, DEFAULT_CONFIG_DIR as c, agentConfigSchema as d, clientConfigSchema as f, loadAgents as g, initConfig as h, getGitHubToken as i, DEFAULT_DATA_DIR as l, getConfigValue as m, bootstrap_exports as n, resolveAgentToken as o, collectMissingPrompts as p, checkBootstrapStatus as r, resolveServerUrl as s, bootstrapToken as t, DEFAULT_HOME_DIR as u, resetConfig as v, serverConfigSchema as x, resetConfigMeta as y };
|
package/dist/cli/index.mjs
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import { A as
|
|
3
|
-
import {
|
|
2
|
+
import { A as createAdminUser, C as printResults, F as cleanWorkspaces, M as FirstTreeHubSDK, N as SdkError, O as stopPostgres, P as SessionRegistry, S as checkWebSocket, _ as checkGitHubToken, a as formatCheckReport, b as checkServerHealth, c as onboardCreate, d as checkAgentConfigs, f as checkAgentTokens, g as checkDocker, h as checkDatabase, i as promptMissingFields, k as ClientRuntime, l as saveOnboardState, m as checkContextTreeRepo, n as isInteractive, o as loadOnboardState, p as checkClientConfig, r as promptAddAgent, s as onboardCheck, t as startServer, u as runMigrations, v as checkNodeVersion, x as checkServerReachable, y as checkServerConfig } from "../core-CMeOAZmx.mjs";
|
|
3
|
+
import { S as setConfigValue, _ as readConfigFile, c as DEFAULT_CONFIG_DIR, d as agentConfigSchema, f as clientConfigSchema, g as loadAgents, h as initConfig, l as DEFAULT_DATA_DIR, m as getConfigValue, o as resolveAgentToken, s as resolveServerUrl, t as bootstrapToken, u as DEFAULT_HOME_DIR, v as resetConfig, x as serverConfigSchema, y as resetConfigMeta } from "../bootstrap-uyPaaI05.mjs";
|
|
4
4
|
import { n as bindFeishuUser, t as bindFeishuBot } from "../feishu-Y4m2zFc3.mjs";
|
|
5
5
|
import { createRequire } from "node:module";
|
|
6
6
|
import { Command } from "commander";
|
|
@@ -168,7 +168,7 @@ function registerAgentCommands(program) {
|
|
|
168
168
|
agent.command("token").description("Agent token management").command("bootstrap <agentId>").description("Bootstrap a token using GitHub identity (requires gh CLI)").option("--save-to <target>", "Save token to: \"agent\" (default) or a file path", "agent").option("--server <url>", "Hub server URL").action(async (agentId, options) => {
|
|
169
169
|
try {
|
|
170
170
|
const result = await bootstrapToken(resolveServerUrl(options.server), agentId, { saveTo: options.saveTo });
|
|
171
|
-
if (options.saveTo === "agent") process.stderr.write(`Token saved to
|
|
171
|
+
if (options.saveTo === "agent") process.stderr.write(`Token saved to ${DEFAULT_HOME_DIR}/config/agents/${agentId}/agent.yaml\n`);
|
|
172
172
|
else process.stderr.write(`Token saved to ${options.saveTo}\n`);
|
|
173
173
|
success({
|
|
174
174
|
agentId: result.agentId,
|
|
@@ -455,14 +455,31 @@ function isSecretField(schema, dotPath) {
|
|
|
455
455
|
//#endregion
|
|
456
456
|
//#region src/commands/onboard.ts
|
|
457
457
|
async function promptMissing(args) {
|
|
458
|
+
if (!args.server) try {
|
|
459
|
+
const { resolveServerUrl } = await import("../bootstrap-uyPaaI05.mjs").then((n) => n.n);
|
|
460
|
+
resolveServerUrl();
|
|
461
|
+
} catch {
|
|
462
|
+
args.server = await input({ message: "Hub server URL:" });
|
|
463
|
+
saveOnboardState(args);
|
|
464
|
+
}
|
|
465
|
+
const { resolveServerUrl } = await import("../bootstrap-uyPaaI05.mjs").then((n) => n.n);
|
|
466
|
+
const serverUrl = resolveServerUrl(args.server).replace(/\/+$/, "");
|
|
467
|
+
try {
|
|
468
|
+
const res = await fetch(`${serverUrl}/api/v1/bootstrap/config`);
|
|
469
|
+
if (res.ok) {
|
|
470
|
+
if (!(await res.json()).allowedOrg) throw new Error("Server does not have FIRST_TREE_HUB_GITHUB_ALLOWED_ORG configured.\n Ask the server admin to set this before onboarding.");
|
|
471
|
+
}
|
|
472
|
+
} catch (err) {
|
|
473
|
+
if (err instanceof Error && err.message.includes("FIRST_TREE_HUB_GITHUB_ALLOWED_ORG")) throw err;
|
|
474
|
+
}
|
|
458
475
|
let ghUsername = null;
|
|
459
476
|
try {
|
|
460
|
-
const { getGitHubUsername } = await import("../bootstrap-
|
|
477
|
+
const { getGitHubUsername } = await import("../bootstrap-uyPaaI05.mjs").then((n) => n.n);
|
|
461
478
|
ghUsername = getGitHubUsername();
|
|
462
479
|
} catch {}
|
|
463
480
|
if (!args.id) {
|
|
464
481
|
args.id = await input({
|
|
465
|
-
message: "
|
|
482
|
+
message: "Agent ID:",
|
|
466
483
|
default: ghUsername ?? void 0
|
|
467
484
|
});
|
|
468
485
|
saveOnboardState(args);
|
|
@@ -488,12 +505,18 @@ async function promptMissing(args) {
|
|
|
488
505
|
saveOnboardState(args);
|
|
489
506
|
}
|
|
490
507
|
if (!args.role) {
|
|
491
|
-
|
|
492
|
-
|
|
508
|
+
const role = await input({ message: "Role (optional, Enter to skip):" });
|
|
509
|
+
if (role) {
|
|
510
|
+
args.role = role;
|
|
511
|
+
saveOnboardState(args);
|
|
512
|
+
}
|
|
493
513
|
}
|
|
494
514
|
if (!args.domains) {
|
|
495
|
-
|
|
496
|
-
|
|
515
|
+
const domains = await input({ message: "Domains (comma-separated, optional, Enter to skip):" });
|
|
516
|
+
if (domains) {
|
|
517
|
+
args.domains = domains;
|
|
518
|
+
saveOnboardState(args);
|
|
519
|
+
}
|
|
497
520
|
}
|
|
498
521
|
if (!args.displayName) {
|
|
499
522
|
const name = await input({ message: `Display name (Enter to use "${args.id}"):` });
|
|
@@ -502,7 +525,7 @@ async function promptMissing(args) {
|
|
|
502
525
|
saveOnboardState(args);
|
|
503
526
|
}
|
|
504
527
|
}
|
|
505
|
-
if (!args.assistant) {
|
|
528
|
+
if (!args.assistant && args.type === "human") {
|
|
506
529
|
if (await confirm({
|
|
507
530
|
message: "Create a personal assistant?",
|
|
508
531
|
default: false
|
|
@@ -514,14 +537,7 @@ async function promptMissing(args) {
|
|
|
514
537
|
saveOnboardState(args);
|
|
515
538
|
}
|
|
516
539
|
}
|
|
517
|
-
if (!args.
|
|
518
|
-
const { resolveServerUrl } = await import("../bootstrap-CPdLNPme.mjs").then((n) => n.n);
|
|
519
|
-
resolveServerUrl();
|
|
520
|
-
} catch {
|
|
521
|
-
args.server = await input({ message: "Hub server URL:" });
|
|
522
|
-
saveOnboardState(args);
|
|
523
|
-
}
|
|
524
|
-
if (!args.feishuBotAppId) {
|
|
540
|
+
if (!args.feishuBotAppId && (args.type !== "human" || args.assistant)) {
|
|
525
541
|
if (await confirm({
|
|
526
542
|
message: "Bind Feishu bot?",
|
|
527
543
|
default: false
|
|
@@ -533,7 +549,7 @@ async function promptMissing(args) {
|
|
|
533
549
|
}
|
|
534
550
|
}
|
|
535
551
|
function registerOnboardCommand(program) {
|
|
536
|
-
program.command("onboard").description("Onboard a new
|
|
552
|
+
program.command("onboard").description("Onboard a new agent to First Tree Hub").option("--id <id>", "Agent ID").option("--type <type>", "Agent type: human | personal_assistant | autonomous_agent").option("--display-name <name>", "Display name (defaults to id)").option("--role <role>", "Role description").option("--domains <domains>", "Comma-separated domains").option("--profile <text>", "Agent profile (markdown)").option("--assistant <id>", "Also create a personal_assistant with this ID").option("--delegate-mention <id>", "Set delegate_mention field").option("--server <url>", "Hub server URL").option("--feishu-bot-app-id <id>", "Feishu bot App ID").option("--feishu-bot-app-secret <secret>", "Feishu bot App Secret").option("--check", "Dry-run: show readiness checklist without executing").action(async (options) => {
|
|
537
553
|
try {
|
|
538
554
|
const args = {
|
|
539
555
|
...loadOnboardState() ?? {},
|
|
@@ -542,20 +558,16 @@ function registerOnboardCommand(program) {
|
|
|
542
558
|
...options.displayName && { displayName: options.displayName },
|
|
543
559
|
...options.role && { role: options.role },
|
|
544
560
|
...options.domains && { domains: options.domains },
|
|
561
|
+
...options.profile && { profile: options.profile },
|
|
545
562
|
...options.assistant && { assistant: options.assistant },
|
|
546
563
|
...options.delegateMention && { delegateMention: options.delegateMention },
|
|
547
564
|
...options.server && { server: options.server },
|
|
548
565
|
...options.feishuBotAppId && { feishuBotAppId: options.feishuBotAppId },
|
|
549
566
|
...options.feishuBotAppSecret && { feishuBotAppSecret: options.feishuBotAppSecret },
|
|
550
|
-
check: options.check
|
|
551
|
-
continue: options.continue
|
|
567
|
+
check: options.check
|
|
552
568
|
};
|
|
553
569
|
if (!args.feishuBotAppId && process.env.FEISHU_APP_ID) args.feishuBotAppId = process.env.FEISHU_APP_ID;
|
|
554
570
|
if (!args.feishuBotAppSecret && process.env.FEISHU_APP_SECRET) args.feishuBotAppSecret = process.env.FEISHU_APP_SECRET;
|
|
555
|
-
if (args.continue) {
|
|
556
|
-
await onboardContinue(args);
|
|
557
|
-
return;
|
|
558
|
-
}
|
|
559
571
|
if (args.check) {
|
|
560
572
|
const items = await onboardCheck(args);
|
|
561
573
|
const report = formatCheckReport(items);
|
|
@@ -570,18 +582,11 @@ function registerOnboardCommand(program) {
|
|
|
570
582
|
process.stderr.write(`\nOnboard Check: ${args.id ?? "(no id)"}\n\n${report}\n\n`);
|
|
571
583
|
fail("MISSING_PARAMS", "Required parameters are missing. See checklist above.");
|
|
572
584
|
}
|
|
573
|
-
|
|
574
|
-
process.stderr.write(`\nPR created: ${result.prUrl}\n`);
|
|
575
|
-
process.stderr.write("Review and merge the PR, then run:\n");
|
|
576
|
-
process.stderr.write(" first-tree-hub onboard --continue\n\n");
|
|
577
|
-
success({
|
|
578
|
-
phase: "create",
|
|
579
|
-
prUrl: result.prUrl
|
|
580
|
-
});
|
|
585
|
+
await onboardCreate(args);
|
|
581
586
|
} catch (error) {
|
|
582
587
|
const msg = error instanceof Error ? error.message : String(error);
|
|
583
588
|
if (isInteractive()) {
|
|
584
|
-
process.stderr.write(`\n
|
|
589
|
+
process.stderr.write(`\n\u274C ${msg}\n\n`);
|
|
585
590
|
process.exit(1);
|
|
586
591
|
}
|
|
587
592
|
fail("ONBOARD_ERROR", msg);
|