@agent-team-foundation/first-tree-hub 0.3.5 → 0.5.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-mhkpeOEc.mjs → bootstrap-BU_7B03u.mjs} +20 -18
- package/dist/cli/index.mjs +39 -34
- package/dist/{core-CHL_dgzu.mjs → core-jjk1xFW_.mjs} +463 -965
- package/dist/drizzle/0007_decouple_context_tree.sql +2 -0
- package/dist/drizzle/0008_uuid_identity.sql +12 -0
- package/dist/drizzle/meta/_journal.json +14 -0
- package/dist/index.mjs +3 -3
- package/dist/web/assets/index-LFh6j4ki.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-BURu6jt9.css +0 -1
- package/dist/web/assets/index-DhpjUi0Y.js +0 -272
|
@@ -450,27 +450,23 @@ 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({
|
|
@@ -536,23 +532,29 @@ function resolveServerUrl(flagValue) {
|
|
|
536
532
|
/**
|
|
537
533
|
* Bootstrap a token for an agent using GitHub identity.
|
|
538
534
|
*/
|
|
539
|
-
async function bootstrapToken(serverUrl,
|
|
535
|
+
async function bootstrapToken(serverUrl, agentName, options = {}) {
|
|
540
536
|
const githubToken = getGitHubToken();
|
|
541
|
-
const
|
|
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;
|
|
543
|
+
const res = await fetch(`${serverUrl}/api/v1/bootstrap/${encodeURIComponent(agentName)}/token`, {
|
|
542
544
|
method: "POST",
|
|
543
545
|
headers: {
|
|
544
546
|
"X-GitHub-Token": githubToken,
|
|
545
547
|
"Content-Type": "application/json"
|
|
546
548
|
},
|
|
547
|
-
body: JSON.stringify(
|
|
549
|
+
body: JSON.stringify(body)
|
|
548
550
|
});
|
|
549
551
|
if (!res.ok) {
|
|
550
552
|
const msg = (await res.json().catch(() => ({}))).error ?? `HTTP ${res.status}`;
|
|
551
|
-
throw new Error(`Bootstrap failed for "${
|
|
553
|
+
throw new Error(`Bootstrap failed for "${agentName}": ${msg}`);
|
|
552
554
|
}
|
|
553
555
|
const data = await res.json();
|
|
554
556
|
if (options.saveTo === "agent" || !options.saveTo) {
|
|
555
|
-
const configDir = join(DEFAULT_CONFIG_DIR, "agents",
|
|
557
|
+
const configDir = join(DEFAULT_CONFIG_DIR, "agents", agentName);
|
|
556
558
|
const configPath = `${configDir}/agent.yaml`;
|
|
557
559
|
mkdirSync(configDir, {
|
|
558
560
|
recursive: true,
|
|
@@ -578,9 +580,9 @@ function resolveAgentToken() {
|
|
|
578
580
|
/**
|
|
579
581
|
* Check if an agent exists and is synced.
|
|
580
582
|
*/
|
|
581
|
-
async function checkBootstrapStatus(serverUrl,
|
|
583
|
+
async function checkBootstrapStatus(serverUrl, agentName) {
|
|
582
584
|
const githubToken = getGitHubToken();
|
|
583
|
-
const res = await fetch(`${serverUrl}/api/v1/bootstrap/${encodeURIComponent(
|
|
585
|
+
const res = await fetch(`${serverUrl}/api/v1/bootstrap/${encodeURIComponent(agentName)}/status`, { headers: { "X-GitHub-Token": githubToken } });
|
|
584
586
|
if (!res.ok) {
|
|
585
587
|
const body = await res.json().catch(() => ({}));
|
|
586
588
|
throw new Error(body.error ?? `HTTP ${res.status}`);
|
package/dist/cli/index.mjs
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import { A as
|
|
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-
|
|
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-jjk1xFW_.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-BU_7B03u.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";
|
|
@@ -165,10 +165,10 @@ function registerAgentCommands(program) {
|
|
|
165
165
|
}
|
|
166
166
|
process.stderr.write(` ${totalRemoved} workspace(s) cleaned.\n`);
|
|
167
167
|
});
|
|
168
|
-
agent.command("token").description("Agent token management").command("bootstrap <
|
|
168
|
+
agent.command("token").description("Agent token management").command("bootstrap <agentName>").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 (agentName, options) => {
|
|
169
169
|
try {
|
|
170
|
-
const result = await bootstrapToken(resolveServerUrl(options.server),
|
|
171
|
-
if (options.saveTo === "agent") process.stderr.write(`Token saved to ${DEFAULT_HOME_DIR}/config/agents/${
|
|
170
|
+
const result = await bootstrapToken(resolveServerUrl(options.server), agentName, { saveTo: options.saveTo });
|
|
171
|
+
if (options.saveTo === "agent") process.stderr.write(`Token saved to ${DEFAULT_HOME_DIR}/config/agents/${agentName}/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-BU_7B03u.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-BU_7B03u.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-BU_7B03u.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}"):` });
|
|
@@ -514,13 +537,6 @@ async function promptMissing(args) {
|
|
|
514
537
|
saveOnboardState(args);
|
|
515
538
|
}
|
|
516
539
|
}
|
|
517
|
-
if (!args.server) try {
|
|
518
|
-
const { resolveServerUrl } = await import("../bootstrap-mhkpeOEc.mjs").then((n) => n.n);
|
|
519
|
-
resolveServerUrl();
|
|
520
|
-
} catch {
|
|
521
|
-
args.server = await input({ message: "Hub server URL:" });
|
|
522
|
-
saveOnboardState(args);
|
|
523
|
-
}
|
|
524
540
|
if (!args.feishuBotAppId && (args.type !== "human" || args.assistant)) {
|
|
525
541
|
if (await confirm({
|
|
526
542
|
message: "Bind Feishu bot?",
|
|
@@ -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);
|