@agent-team-foundation/first-tree-hub 0.10.7 → 0.10.8
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/cli/index.mjs +101 -14
- package/dist/{dist-CbX9mUVH.mjs → dist-DSr_I5Ia.mjs} +12 -0
- package/dist/{feishu-DvjRZMdZ.mjs → feishu-eynC54km.mjs} +1 -1
- package/dist/index.mjs +4 -4
- package/dist/{invitation-BljIolbO-DLeHfURd.mjs → invitation-B1pjAyOz-BaCA9PII.mjs} +20 -6
- package/dist/invitation-CBnQyB7o-DVOpS_Ts.mjs +3 -0
- package/dist/{saas-connect-vLyx73kJ.mjs → saas-connect-D-fy3xu-.mjs} +470 -172
- package/dist/web/assets/{index-CKiF80RI.js → index-B33n1w2k.js} +86 -86
- package/dist/web/assets/{index-BADzOlHO.js → index-DIgiOalZ.js} +1 -1
- package/dist/web/index.html +1 -1
- package/package.json +1 -1
- package/dist/invitation-D3feYxet-366MNOor.mjs +0 -3
package/dist/cli/index.mjs
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import "../observability-DPyf745N-BSc8QNcR.mjs";
|
|
3
|
-
import { A as checkServerHealth, C as checkAgentConfigs, D as checkDocker, E as checkDatabase, F as installClientService, G as createOwner, H as ClientRuntime, I as isServiceSupported, J as fail, M as checkWebSocket, N as printResults, O as checkNodeVersion, P as getClientServiceStatus, Q as setJsonMode, S as runMigrations, T as checkClientConfig, U as handleClientOrgMismatch, V as stopPostgres, Y as success, Z as print, _ as onboardCreate, a as declineUpdate, at as
|
|
3
|
+
import { A as checkServerHealth, C as checkAgentConfigs, D as checkDocker, E as checkDatabase, F as installClientService, G as createOwner, H as ClientRuntime, I as isServiceSupported, J as fail, M as checkWebSocket, N as printResults, O as checkNodeVersion, P as getClientServiceStatus, Q as setJsonMode, S as runMigrations, T as checkClientConfig, U as handleClientOrgMismatch, V as stopPostgres, Y as success, Z as print, _ as onboardCreate, a as declineUpdate, at as cleanWorkspaces, b as createApiNameResolver, c as COMMAND_VERSION, ct as configureClientLoggerForService, d as isInteractive, et as ClientOrgMismatchError, f as promptAddAgent, g as onboardCheck, h as loadOnboardState, i as createExecuteUpdate, it as SessionRegistry, j as checkServerReachable, k as checkServerConfig, l as reconcileLocalRuntimeProviders, m as formatCheckReport, nt as FirstTreeHubSDK, o as promptUpdate, ot as probeCapabilities, p as promptMissingFields, q as resolveReplyToFromEnv, r as registerSaaSConnectCommand, rt as SdkError, s as startServer, st as applyClientLoggerConfig, tt as ClientUserMismatchError, u as uploadClientCapabilities, v as saveOnboardState, w as checkBackgroundService, x as migrateLocalAgentDirs, y as runHomeMigration } from "../saas-connect-D-fy3xu-.mjs";
|
|
4
4
|
import "../logger-core-BTmvdflj-DjW8FM4T.mjs";
|
|
5
5
|
import { C as serverConfigSchema, _ as loadAgents, b as resetConfig, c as saveCredentials, d as DEFAULT_HOME_DIR, f as agentConfigSchema, g as initConfig, h as getConfigValue, i as loadCredentials, l as DEFAULT_CONFIG_DIR, n as ensureFreshAccessToken, o as resolveServerUrl, p as clientConfigSchema, r as ensureFreshAdminToken, s as saveAgentConfig, u as DEFAULT_DATA_DIR, w as setConfigValue, x as resetConfigMeta, y as readConfigFile } from "../bootstrap-jx5nN1qZ.mjs";
|
|
6
|
-
import "../dist-
|
|
7
|
-
import { n as bindFeishuUser, t as bindFeishuBot } from "../feishu-
|
|
8
|
-
import "../invitation-
|
|
6
|
+
import "../dist-DSr_I5Ia.mjs";
|
|
7
|
+
import { n as bindFeishuUser, t as bindFeishuBot } from "../feishu-eynC54km.mjs";
|
|
8
|
+
import "../invitation-B1pjAyOz-BaCA9PII.mjs";
|
|
9
9
|
import { join } from "node:path";
|
|
10
10
|
import { existsSync, mkdirSync, readFileSync, readdirSync, rmSync } from "node:fs";
|
|
11
11
|
import { Command } from "commander";
|
|
@@ -323,20 +323,44 @@ function registerAgentCommands(program) {
|
|
|
323
323
|
rmSync(join(DEFAULT_DATA_DIR, "sessions", `${name}.json`), { force: true });
|
|
324
324
|
print.line(` Agent "${name}" removed.\n`);
|
|
325
325
|
});
|
|
326
|
-
agent.command("list").description("List locally-configured
|
|
327
|
-
|
|
326
|
+
agent.command("list").description("List agents — locally-configured by default, or every agent you manage with --remote").option("--remote", "List every agent you manage on the Hub server (cross-org)").option("--org <id>", "When listing remote, restrict to a single organization id").option("--server <url>", "Hub server URL").action(async (options) => {
|
|
327
|
+
if (!(options.remote === true || typeof options.org === "string")) {
|
|
328
|
+
const agentsDir = join(DEFAULT_CONFIG_DIR, "agents");
|
|
329
|
+
try {
|
|
330
|
+
const agents = loadAgents({
|
|
331
|
+
schema: agentConfigSchema,
|
|
332
|
+
agentsDir
|
|
333
|
+
});
|
|
334
|
+
if (agents.size === 0) {
|
|
335
|
+
print.line(" No agents configured.\n");
|
|
336
|
+
return;
|
|
337
|
+
}
|
|
338
|
+
for (const [name, config] of agents) print.line(` ${name.padEnd(20)} runtime: ${config.runtime.padEnd(14)} uuid: ${config.agentId}\n`);
|
|
339
|
+
} catch {
|
|
340
|
+
print.line(" No agents configured.\n");
|
|
341
|
+
}
|
|
342
|
+
return;
|
|
343
|
+
}
|
|
328
344
|
try {
|
|
329
|
-
const
|
|
330
|
-
|
|
331
|
-
|
|
345
|
+
const serverUrl = resolveServerUrl(options.server);
|
|
346
|
+
const token = await ensureFreshAccessToken();
|
|
347
|
+
const res = await fetch(`${serverUrl}/api/v1/me/managed-agents`, {
|
|
348
|
+
headers: { Authorization: `Bearer ${token}` },
|
|
349
|
+
signal: AbortSignal.timeout(1e4)
|
|
332
350
|
});
|
|
333
|
-
if (
|
|
334
|
-
|
|
351
|
+
if (!res.ok) fail("LIST_ERROR", `Server returned ${res.status}`, 1);
|
|
352
|
+
const agents = await res.json();
|
|
353
|
+
const filtered = options.org ? agents.filter((a) => a.organizationId === options.org) : agents;
|
|
354
|
+
if (filtered.length === 0) {
|
|
355
|
+
print.line(" No agents found.\n");
|
|
335
356
|
return;
|
|
336
357
|
}
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
print.line("
|
|
358
|
+
const header = ` ${"NAME".padEnd(24)} ${"TYPE".padEnd(20)} ${"RUNTIME".padEnd(14)} ${"ORG".padEnd(40)} CLIENT`;
|
|
359
|
+
print.line(`${header}\n`);
|
|
360
|
+
print.line(` ${"─".repeat(header.length - 2)}\n`);
|
|
361
|
+
for (const a of filtered) print.line(` ${(a.name ?? a.uuid).padEnd(24)} ${a.type.padEnd(20)} ${a.runtimeProvider.padEnd(14)} ${a.organizationId.padEnd(40)} ${a.clientId ?? "—"}\n`);
|
|
362
|
+
} catch (error) {
|
|
363
|
+
fail("LIST_ERROR", error instanceof Error ? error.message : String(error));
|
|
340
364
|
}
|
|
341
365
|
});
|
|
342
366
|
agent.command("create <name>").description("Create an agent on Hub and bind it locally").requiredOption("--type <type>", "Agent type (human, personal_assistant, autonomous_agent)").requiredOption("--client-id <id>", "Client (machine) that will run this agent — must be owned by you. Run `first-tree-hub client connect` on that machine first.").option("--runtime <runtime>", "Runtime handler (default: claude-code)", "claude-code").option("--display-name <name>", "Display name").option("--server <url>", "Hub server URL").action(async (name, options) => {
|
|
@@ -972,6 +996,14 @@ function registerConnectCommand(parent) {
|
|
|
972
996
|
print.line("\n Cancelled.\n");
|
|
973
997
|
return;
|
|
974
998
|
}
|
|
999
|
+
if (error instanceof ClientUserMismatchError) {
|
|
1000
|
+
print.line("\n");
|
|
1001
|
+
print.line(" ⚠️ This client.yaml is owned by a different user.\n");
|
|
1002
|
+
print.line(" Run `first-tree-hub client claim --confirm` to transfer ownership\n");
|
|
1003
|
+
print.line(" to your account. The previous owner's agents will be unpinned\n");
|
|
1004
|
+
print.line(" from this machine.\n\n");
|
|
1005
|
+
process.exit(1);
|
|
1006
|
+
}
|
|
975
1007
|
if (error instanceof ClientOrgMismatchError) await handleClientOrgMismatch(error, {
|
|
976
1008
|
managed: false,
|
|
977
1009
|
configDir: DEFAULT_CONFIG_DIR,
|
|
@@ -1069,6 +1101,14 @@ function registerClientCommands(program) {
|
|
|
1069
1101
|
process.on("SIGTERM", () => void shutdown());
|
|
1070
1102
|
await new Promise(() => {});
|
|
1071
1103
|
} catch (error) {
|
|
1104
|
+
if (error instanceof ClientUserMismatchError) {
|
|
1105
|
+
print.line("\n");
|
|
1106
|
+
print.line(" ⚠️ This client.yaml is owned by a different user.\n");
|
|
1107
|
+
print.line(" Run `first-tree-hub client claim --confirm` to transfer ownership\n");
|
|
1108
|
+
print.line(" to your account. The previous owner's agents will be unpinned\n");
|
|
1109
|
+
print.line(" from this machine.\n\n");
|
|
1110
|
+
process.exit(1);
|
|
1111
|
+
}
|
|
1072
1112
|
if (error instanceof ClientOrgMismatchError) await handleClientOrgMismatch(error, {
|
|
1073
1113
|
managed: options.interactive === false,
|
|
1074
1114
|
configDir: DEFAULT_CONFIG_DIR,
|
|
@@ -1142,6 +1182,53 @@ function registerClientCommands(program) {
|
|
|
1142
1182
|
fail("CLIENT_LIST_ERROR", error instanceof Error ? error.message : String(error));
|
|
1143
1183
|
}
|
|
1144
1184
|
});
|
|
1185
|
+
client.command("claim").description("Transfer ownership of this machine to your account (unpins the previous owner's agents from this machine)").option("--confirm", "Skip the interactive confirmation prompt").option("--server <url>", "Hub server URL").action(async (options) => {
|
|
1186
|
+
try {
|
|
1187
|
+
const config = await initConfig({
|
|
1188
|
+
schema: clientConfigSchema,
|
|
1189
|
+
role: "client"
|
|
1190
|
+
});
|
|
1191
|
+
const serverUrl = resolveServerUrl(options.server) ?? config.server.url;
|
|
1192
|
+
const clientId = config.client.id;
|
|
1193
|
+
print.line("\n");
|
|
1194
|
+
print.line(" Transferring ownership of this machine to your account.\n");
|
|
1195
|
+
print.line(" This will unpin the previous owner's agents from this client.\n\n");
|
|
1196
|
+
print.status("client.id", clientId);
|
|
1197
|
+
print.status("server", serverUrl);
|
|
1198
|
+
print.line("\n");
|
|
1199
|
+
if (!options.confirm) {
|
|
1200
|
+
if (!await confirm({
|
|
1201
|
+
message: "Proceed with ownership transfer?",
|
|
1202
|
+
default: false
|
|
1203
|
+
}).catch(() => false)) {
|
|
1204
|
+
print.line(" Cancelled.\n\n");
|
|
1205
|
+
return;
|
|
1206
|
+
}
|
|
1207
|
+
}
|
|
1208
|
+
const token = await ensureFreshAccessToken();
|
|
1209
|
+
const response = await fetch(`${serverUrl}/api/v1/me/clients/${clientId}/claim`, {
|
|
1210
|
+
method: "POST",
|
|
1211
|
+
headers: {
|
|
1212
|
+
Authorization: `Bearer ${token}`,
|
|
1213
|
+
"Content-Type": "application/json"
|
|
1214
|
+
},
|
|
1215
|
+
body: "{}",
|
|
1216
|
+
signal: AbortSignal.timeout(1e4)
|
|
1217
|
+
});
|
|
1218
|
+
if (!response.ok) {
|
|
1219
|
+
const body = await response.text();
|
|
1220
|
+
fail("CLAIM_ERROR", `Server returned ${response.status}: ${body}`, 1);
|
|
1221
|
+
}
|
|
1222
|
+
const result = await response.json();
|
|
1223
|
+
print.line(` ✓ Ownership transferred. ${result.unpinnedAgentCount} agent(s) unpinned.\n`);
|
|
1224
|
+
print.line(" Run `first-tree-hub client start` to reconnect.\n\n");
|
|
1225
|
+
} catch (error) {
|
|
1226
|
+
fail("CLAIM_ERROR", error instanceof Error ? error.message : String(error));
|
|
1227
|
+
} finally {
|
|
1228
|
+
resetConfig();
|
|
1229
|
+
resetConfigMeta();
|
|
1230
|
+
}
|
|
1231
|
+
});
|
|
1145
1232
|
client.command("hub-disconnect <clientId>").description("Force-disconnect a client from the Hub server").option("--server <url>", "Hub server URL").action(async (clientId, options) => {
|
|
1146
1233
|
try {
|
|
1147
1234
|
const serverUrl = resolveServerUrl(options.server);
|
|
@@ -613,6 +613,11 @@ const clientRegisterSchema = z.object({
|
|
|
613
613
|
sdkVersion: z.string().max(50).optional(),
|
|
614
614
|
wireCapabilities: clientWireCapabilitiesSchema.optional()
|
|
615
615
|
});
|
|
616
|
+
z.object({
|
|
617
|
+
clientId: z.string(),
|
|
618
|
+
previousUserId: z.string().nullable(),
|
|
619
|
+
unpinnedAgentCount: z.number().int().nonnegative()
|
|
620
|
+
});
|
|
616
621
|
const capabilityStateSchema = z.enum([
|
|
617
622
|
"ok",
|
|
618
623
|
"missing",
|
|
@@ -874,6 +879,13 @@ const createOrgFromMeSchema = z.object({
|
|
|
874
879
|
});
|
|
875
880
|
/** Body for `POST /auth/switch-org`. */
|
|
876
881
|
const switchOrgSchema = z.object({ organizationId: z.string().min(1) });
|
|
882
|
+
z.object({
|
|
883
|
+
id: z.string(),
|
|
884
|
+
organizationId: z.string(),
|
|
885
|
+
organizationName: z.string(),
|
|
886
|
+
role: z.enum(["admin", "member"]),
|
|
887
|
+
agentId: z.string()
|
|
888
|
+
});
|
|
877
889
|
const memberRoleSchema = z.enum(["admin", "member"]);
|
|
878
890
|
const memberSchema = z.object({
|
|
879
891
|
id: z.string(),
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { d as __exportAll } from "./esm-CYu4tXXn.mjs";
|
|
2
|
-
import { r as AGENT_SELECTOR_HEADER } from "./dist-
|
|
2
|
+
import { r as AGENT_SELECTOR_HEADER } from "./dist-DSr_I5Ia.mjs";
|
|
3
3
|
//#region src/core/feishu.ts
|
|
4
4
|
var feishu_exports = /* @__PURE__ */ __exportAll({
|
|
5
5
|
bindFeishuBot: () => bindFeishuBot,
|
package/dist/index.mjs
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import "./observability-DPyf745N-BSc8QNcR.mjs";
|
|
2
|
-
import { $ as status, A as checkServerHealth, B as isDockerAvailable, C as checkAgentConfigs, D as checkDocker, E as checkDatabase, F as installClientService, G as createOwner, H as ClientRuntime, I as isServiceSupported, K as hasUser, L as resolveCliInvocation, M as checkWebSocket, N as printResults, O as checkNodeVersion, P as getClientServiceStatus, R as uninstallClientService, S as runMigrations, T as checkClientConfig, U as handleClientOrgMismatch, V as stopPostgres, W as rotateClientIdWithBackup, X as blank, _ as onboardCreate, d as isInteractive, f as promptAddAgent, g as onboardCheck, j as checkServerReachable, k as checkServerConfig, m as formatCheckReport, n as deriveHubUrlFromToken, nt as
|
|
2
|
+
import { $ as status, A as checkServerHealth, B as isDockerAvailable, C as checkAgentConfigs, D as checkDocker, E as checkDatabase, F as installClientService, G as createOwner, H as ClientRuntime, I as isServiceSupported, K as hasUser, L as resolveCliInvocation, M as checkWebSocket, N as printResults, O as checkNodeVersion, P as getClientServiceStatus, R as uninstallClientService, S as runMigrations, T as checkClientConfig, U as handleClientOrgMismatch, V as stopPostgres, W as rotateClientIdWithBackup, X as blank, _ as onboardCreate, d as isInteractive, f as promptAddAgent, g as onboardCheck, j as checkServerReachable, k as checkServerConfig, m as formatCheckReport, n as deriveHubUrlFromToken, nt as FirstTreeHubSDK, p as promptMissingFields, rt as SdkError, s as startServer, t as HubUrlDerivationError, y as runHomeMigration, z as ensurePostgres } from "./saas-connect-D-fy3xu-.mjs";
|
|
3
3
|
import "./logger-core-BTmvdflj-DjW8FM4T.mjs";
|
|
4
4
|
import { a as resolveAccessToken, n as ensureFreshAccessToken, o as resolveServerUrl, r as ensureFreshAdminToken } from "./bootstrap-jx5nN1qZ.mjs";
|
|
5
|
-
import "./dist-
|
|
6
|
-
import { n as bindFeishuUser, t as bindFeishuBot } from "./feishu-
|
|
7
|
-
import "./invitation-
|
|
5
|
+
import "./dist-DSr_I5Ia.mjs";
|
|
6
|
+
import { n as bindFeishuUser, t as bindFeishuBot } from "./feishu-eynC54km.mjs";
|
|
7
|
+
import "./invitation-B1pjAyOz-BaCA9PII.mjs";
|
|
8
8
|
export { ClientRuntime, FirstTreeHubSDK, HubUrlDerivationError, SdkError, bindFeishuBot, bindFeishuUser, blank, checkAgentConfigs, checkClientConfig, checkDatabase, checkDocker, checkNodeVersion, checkServerConfig, checkServerHealth, checkServerReachable, checkWebSocket, createOwner, deriveHubUrlFromToken, ensureFreshAccessToken, ensureFreshAdminToken, ensurePostgres, formatCheckReport, getClientServiceStatus, handleClientOrgMismatch, hasUser, installClientService, isDockerAvailable, isInteractive, isServiceSupported, onboardCheck, onboardCreate, printResults, promptAddAgent, promptMissingFields, resolveAccessToken, resolveCliInvocation, resolveServerUrl, rotateClientIdWithBackup, runHomeMigration, runMigrations, startServer, status, stopPostgres, uninstallClientService };
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { randomBytes } from "node:crypto";
|
|
2
2
|
import { and, desc, eq, gt, isNull, or } from "drizzle-orm";
|
|
3
3
|
import { index, integer, jsonb, pgTable, text, timestamp } from "drizzle-orm/pg-core";
|
|
4
|
-
//#region ../server/dist/invitation-
|
|
4
|
+
//#region ../server/dist/invitation-B1pjAyOz.mjs
|
|
5
5
|
/** Organization entity. Agents and chats belong to exactly one organization. */
|
|
6
6
|
const organizations = pgTable("organizations", {
|
|
7
7
|
id: text("id").primaryKey(),
|
|
@@ -63,10 +63,11 @@ var BadRequestError = class extends AppError {
|
|
|
63
63
|
};
|
|
64
64
|
/**
|
|
65
65
|
* Thrown when an operation targets a client whose organization does not match
|
|
66
|
-
* the caller's authenticated organization.
|
|
67
|
-
*
|
|
68
|
-
*
|
|
69
|
-
*
|
|
66
|
+
* the caller's authenticated organization. Retained for wire compatibility:
|
|
67
|
+
* the read paths that produced this error were retired in
|
|
68
|
+
* decouple-client-from-identity §4.1, so the server itself no longer raises
|
|
69
|
+
* it. SDK consumers may still pattern-match the `code` field on legacy
|
|
70
|
+
* payloads.
|
|
70
71
|
*/
|
|
71
72
|
var ClientOrgMismatchError = class extends AppError {
|
|
72
73
|
code = "CLIENT_ORG_MISMATCH";
|
|
@@ -75,6 +76,19 @@ var ClientOrgMismatchError = class extends AppError {
|
|
|
75
76
|
this.name = "ClientOrgMismatchError";
|
|
76
77
|
}
|
|
77
78
|
};
|
|
79
|
+
/**
|
|
80
|
+
* Thrown when a client.yaml is presented with a JWT whose user_id does not
|
|
81
|
+
* match the row's owner. The CLI responds by guiding the operator through
|
|
82
|
+
* `first-tree-hub client claim --confirm` to take over ownership, which
|
|
83
|
+
* unpins the previous owner's agents from this machine.
|
|
84
|
+
*/
|
|
85
|
+
var ClientUserMismatchError = class extends AppError {
|
|
86
|
+
code = "CLIENT_USER_MISMATCH";
|
|
87
|
+
constructor(message = "Client belongs to a different user") {
|
|
88
|
+
super(403, message);
|
|
89
|
+
this.name = "ClientUserMismatchError";
|
|
90
|
+
}
|
|
91
|
+
};
|
|
78
92
|
/** Generate a UUID v7 (time-ordered). No external dependency. */
|
|
79
93
|
function uuidv7() {
|
|
80
94
|
const now = BigInt(Date.now());
|
|
@@ -256,4 +270,4 @@ function buildInviteUrl(publicUrl, token) {
|
|
|
256
270
|
return `${publicUrl.replace(/\/+$/, "")}/invite/${token}`;
|
|
257
271
|
}
|
|
258
272
|
//#endregion
|
|
259
|
-
export {
|
|
273
|
+
export { recordRedemption as _, ConflictError as a, uuidv7 as b, UnauthorizedError as c, findActiveByToken as d, getActiveInvitation as f, previewInvitation as g, organizations as h, ClientUserMismatchError as i, buildInviteUrl as l, invitations as m, BadRequestError as n, ForbiddenError as o, invitationRedemptions as p, ClientOrgMismatchError as r, NotFoundError as s, AppError as t, ensureActiveInvitation as u, rotateInvitation as v, users as y };
|