@agent-team-foundation/first-tree-hub 0.10.7 → 0.10.9
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 +233 -27
- 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-CKQ15VLz.mjs} +664 -173
- 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,13 +1,13 @@
|
|
|
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
|
|
3
|
+
import { $ as success, A as checkServerHealth, C as checkAgentConfigs, D as checkDocker, E as checkDatabase, F as getClientServiceStatus, H as stopPostgres, I as installClientService, J as removeLocalAgent, K as findStaleAliases, L as isServiceSupported, M as checkWebSocket, N as printResults, O as checkNodeVersion, P as reconcileAgentConfigs, Q as fail, S as runMigrations, T as checkClientConfig, U as ClientRuntime, W as handleClientOrgMismatch, Y as createOwner, Z as resolveReplyToFromEnv, _ as onboardCreate, a as declineUpdate, at as ClientUserMismatchError, b as createApiNameResolver, c as COMMAND_VERSION, ct as SessionRegistry, d as isInteractive, dt as applyClientLoggerConfig, f as promptAddAgent, ft as configureClientLoggerForService, g as onboardCheck, h as loadOnboardState, i as createExecuteUpdate, it as ClientOrgMismatchError, j as checkServerReachable, k as checkServerConfig, l as reconcileLocalRuntimeProviders, lt as cleanWorkspaces, m as formatCheckReport, nt as setJsonMode, o as promptUpdate, ot as FirstTreeHubSDK, p as promptMissingFields, q as formatStaleReason, r as registerSaaSConnectCommand, s as startServer, st as SdkError, tt as print, u as uploadClientCapabilities, ut as probeCapabilities, v as saveOnboardState, w as checkBackgroundService, x as migrateLocalAgentDirs, y as runHomeMigration } from "../saas-connect-CKQ15VLz.mjs";
|
|
4
4
|
import "../logger-core-BTmvdflj-DjW8FM4T.mjs";
|
|
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-
|
|
5
|
+
import { C as serverConfigSchema, S as resolveConfigReadonly, _ 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-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
|
-
import { existsSync, mkdirSync, readFileSync, readdirSync
|
|
10
|
+
import { existsSync, mkdirSync, readFileSync, readdirSync } from "node:fs";
|
|
11
11
|
import { Command } from "commander";
|
|
12
12
|
import { confirm, input, password, select } from "@inquirer/prompts";
|
|
13
13
|
//#region src/commands/agent-config.ts
|
|
@@ -281,6 +281,21 @@ async function resolveAgent(serverUrl, adminToken, agentName) {
|
|
|
281
281
|
if (!found) fail("NOT_FOUND", `Agent "${agentName}" not found`, 1);
|
|
282
282
|
return found;
|
|
283
283
|
}
|
|
284
|
+
/**
|
|
285
|
+
* Read the persisted `client.id` from `client.yaml`. Required by `agent
|
|
286
|
+
* prune` to filter the user-scoped `listMyAgents` response down to "what
|
|
287
|
+
* actually binds on THIS machine". `fail()` instead of throwing so the
|
|
288
|
+
* "no client.yaml — run client connect first" path renders as a clean
|
|
289
|
+
* CLI error rather than a stack trace.
|
|
290
|
+
*/
|
|
291
|
+
function readClientId() {
|
|
292
|
+
const id = resolveConfigReadonly({
|
|
293
|
+
schema: clientConfigSchema,
|
|
294
|
+
role: "client"
|
|
295
|
+
}).client?.id;
|
|
296
|
+
if (typeof id !== "string" || id.length === 0) fail("MISSING_CLIENT_ID", "No client.id found in client.yaml. Run `first-tree-hub connect <token>` first.", 2);
|
|
297
|
+
return id;
|
|
298
|
+
}
|
|
284
299
|
function registerAgentCommands(program) {
|
|
285
300
|
const agent = program.command("agent").description("Agent management — config, bindings, messaging");
|
|
286
301
|
registerAgentConfigCommands(agent);
|
|
@@ -307,36 +322,103 @@ function registerAgentCommands(program) {
|
|
|
307
322
|
}
|
|
308
323
|
});
|
|
309
324
|
agent.command("remove <name>").description("Remove an agent from this client and delete its local runtime data (config dir, workspace, session state)").action((name) => {
|
|
310
|
-
|
|
311
|
-
if (!existsSync(agentDir)) {
|
|
325
|
+
if (!existsSync(join(DEFAULT_CONFIG_DIR, "agents", name))) {
|
|
312
326
|
print.line(` Agent "${name}" not found.\n`);
|
|
313
327
|
process.exit(1);
|
|
314
328
|
}
|
|
315
|
-
|
|
316
|
-
recursive: true,
|
|
317
|
-
force: true
|
|
318
|
-
});
|
|
319
|
-
rmSync(join(DEFAULT_DATA_DIR, "workspaces", name), {
|
|
320
|
-
recursive: true,
|
|
321
|
-
force: true
|
|
322
|
-
});
|
|
323
|
-
rmSync(join(DEFAULT_DATA_DIR, "sessions", `${name}.json`), { force: true });
|
|
329
|
+
removeLocalAgent(name);
|
|
324
330
|
print.line(` Agent "${name}" removed.\n`);
|
|
325
331
|
});
|
|
326
|
-
agent.command("
|
|
327
|
-
const agentsDir = join(DEFAULT_CONFIG_DIR, "agents");
|
|
332
|
+
agent.command("prune").description("Remove local agent aliases that won't bind on this client (unowned, pinned elsewhere, or unreadable)").option("--yes", "Skip the interactive confirmation prompt").option("--dry-run", "Only list what would be removed; don't touch the filesystem").option("--server <url>", "Hub server URL").action(async (options) => {
|
|
328
333
|
try {
|
|
329
|
-
const
|
|
330
|
-
|
|
331
|
-
|
|
334
|
+
const serverUrl = resolveServerUrl(options.server);
|
|
335
|
+
const clientId = readClientId();
|
|
336
|
+
const sdk = new FirstTreeHubSDK({
|
|
337
|
+
serverUrl,
|
|
338
|
+
getAccessToken: () => ensureFreshAccessToken()
|
|
332
339
|
});
|
|
333
|
-
|
|
340
|
+
const stale = await findStaleAliases({
|
|
341
|
+
clientId,
|
|
342
|
+
listPinnedAgents: () => sdk.listMyAgents()
|
|
343
|
+
});
|
|
344
|
+
if (stale.length === 0) {
|
|
345
|
+
print.line("\n ✓ No stale agent aliases. Local config matches the server.\n\n");
|
|
346
|
+
return;
|
|
347
|
+
}
|
|
348
|
+
print.line(`\n ${stale.length} stale ${stale.length === 1 ? "alias" : "aliases"}:\n\n`);
|
|
349
|
+
for (const s of stale) {
|
|
350
|
+
const id = s.agentId ?? "—";
|
|
351
|
+
print.line(` - ${s.name.padEnd(30)} ${id.padEnd(38)} ${formatStaleReason(s.reason)}\n`);
|
|
352
|
+
}
|
|
353
|
+
print.line("\n");
|
|
354
|
+
if (options.dryRun) {
|
|
355
|
+
print.line(" Dry run — no files removed. Re-run without --dry-run to delete.\n\n");
|
|
356
|
+
return;
|
|
357
|
+
}
|
|
358
|
+
if (!options.yes) {
|
|
359
|
+
if (!await confirm({
|
|
360
|
+
message: `Remove the ${stale.length} stale ${stale.length === 1 ? "alias" : "aliases"} above (config + workspace + session state)?`,
|
|
361
|
+
default: false
|
|
362
|
+
}).catch(() => false)) {
|
|
363
|
+
print.line(" Cancelled.\n\n");
|
|
364
|
+
return;
|
|
365
|
+
}
|
|
366
|
+
}
|
|
367
|
+
let removed = 0;
|
|
368
|
+
let failed = 0;
|
|
369
|
+
for (const s of stale) try {
|
|
370
|
+
removeLocalAgent(s.name);
|
|
371
|
+
print.line(` ✓ removed ${s.name}\n`);
|
|
372
|
+
removed++;
|
|
373
|
+
} catch (err) {
|
|
374
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
375
|
+
print.line(` ✗ ${s.name} (${msg.slice(0, 80)})\n`);
|
|
376
|
+
failed++;
|
|
377
|
+
}
|
|
378
|
+
print.line(`\n ${removed} pruned${failed > 0 ? `, ${failed} failed (re-run to retry)` : ""}.\n\n`);
|
|
379
|
+
if (failed > 0) process.exitCode = 1;
|
|
380
|
+
} catch (error) {
|
|
381
|
+
fail("PRUNE_ERROR", error instanceof Error ? error.message : String(error));
|
|
382
|
+
}
|
|
383
|
+
});
|
|
384
|
+
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) => {
|
|
385
|
+
if (!(options.remote === true || typeof options.org === "string")) {
|
|
386
|
+
const agentsDir = join(DEFAULT_CONFIG_DIR, "agents");
|
|
387
|
+
try {
|
|
388
|
+
const agents = loadAgents({
|
|
389
|
+
schema: agentConfigSchema,
|
|
390
|
+
agentsDir
|
|
391
|
+
});
|
|
392
|
+
if (agents.size === 0) {
|
|
393
|
+
print.line(" No agents configured.\n");
|
|
394
|
+
return;
|
|
395
|
+
}
|
|
396
|
+
for (const [name, config] of agents) print.line(` ${name.padEnd(20)} runtime: ${config.runtime.padEnd(14)} uuid: ${config.agentId}\n`);
|
|
397
|
+
} catch {
|
|
334
398
|
print.line(" No agents configured.\n");
|
|
399
|
+
}
|
|
400
|
+
return;
|
|
401
|
+
}
|
|
402
|
+
try {
|
|
403
|
+
const serverUrl = resolveServerUrl(options.server);
|
|
404
|
+
const token = await ensureFreshAccessToken();
|
|
405
|
+
const res = await fetch(`${serverUrl}/api/v1/me/managed-agents`, {
|
|
406
|
+
headers: { Authorization: `Bearer ${token}` },
|
|
407
|
+
signal: AbortSignal.timeout(1e4)
|
|
408
|
+
});
|
|
409
|
+
if (!res.ok) fail("LIST_ERROR", `Server returned ${res.status}`, 1);
|
|
410
|
+
const agents = await res.json();
|
|
411
|
+
const filtered = options.org ? agents.filter((a) => a.organizationId === options.org) : agents;
|
|
412
|
+
if (filtered.length === 0) {
|
|
413
|
+
print.line(" No agents found.\n");
|
|
335
414
|
return;
|
|
336
415
|
}
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
print.line("
|
|
416
|
+
const header = ` ${"NAME".padEnd(24)} ${"TYPE".padEnd(20)} ${"RUNTIME".padEnd(14)} ${"ORG".padEnd(40)} CLIENT`;
|
|
417
|
+
print.line(`${header}\n`);
|
|
418
|
+
print.line(` ${"─".repeat(header.length - 2)}\n`);
|
|
419
|
+
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`);
|
|
420
|
+
} catch (error) {
|
|
421
|
+
fail("LIST_ERROR", error instanceof Error ? error.message : String(error));
|
|
340
422
|
}
|
|
341
423
|
});
|
|
342
424
|
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 +1054,14 @@ function registerConnectCommand(parent) {
|
|
|
972
1054
|
print.line("\n Cancelled.\n");
|
|
973
1055
|
return;
|
|
974
1056
|
}
|
|
1057
|
+
if (error instanceof ClientUserMismatchError) {
|
|
1058
|
+
print.line("\n");
|
|
1059
|
+
print.line(" ⚠️ This client.yaml is owned by a different user.\n");
|
|
1060
|
+
print.line(" Run `first-tree-hub client claim --confirm` to transfer ownership\n");
|
|
1061
|
+
print.line(" to your account. The previous owner's agents will be unpinned\n");
|
|
1062
|
+
print.line(" from this machine.\n\n");
|
|
1063
|
+
process.exit(1);
|
|
1064
|
+
}
|
|
975
1065
|
if (error instanceof ClientOrgMismatchError) await handleClientOrgMismatch(error, {
|
|
976
1066
|
managed: false,
|
|
977
1067
|
configDir: DEFAULT_CONFIG_DIR,
|
|
@@ -1069,6 +1159,14 @@ function registerClientCommands(program) {
|
|
|
1069
1159
|
process.on("SIGTERM", () => void shutdown());
|
|
1070
1160
|
await new Promise(() => {});
|
|
1071
1161
|
} catch (error) {
|
|
1162
|
+
if (error instanceof ClientUserMismatchError) {
|
|
1163
|
+
print.line("\n");
|
|
1164
|
+
print.line(" ⚠️ This client.yaml is owned by a different user.\n");
|
|
1165
|
+
print.line(" Run `first-tree-hub client claim --confirm` to transfer ownership\n");
|
|
1166
|
+
print.line(" to your account. The previous owner's agents will be unpinned\n");
|
|
1167
|
+
print.line(" from this machine.\n\n");
|
|
1168
|
+
process.exit(1);
|
|
1169
|
+
}
|
|
1072
1170
|
if (error instanceof ClientOrgMismatchError) await handleClientOrgMismatch(error, {
|
|
1073
1171
|
managed: options.interactive === false,
|
|
1074
1172
|
configDir: DEFAULT_CONFIG_DIR,
|
|
@@ -1084,11 +1182,32 @@ function registerClientCommands(program) {
|
|
|
1084
1182
|
});
|
|
1085
1183
|
client.command("doctor").description("Check client environment readiness").action(async () => {
|
|
1086
1184
|
print.line("\n First Tree Hub Client Doctor\n\n");
|
|
1185
|
+
let agentCheck;
|
|
1186
|
+
try {
|
|
1187
|
+
const serverUrl = resolveServerUrl();
|
|
1188
|
+
const cfg = await initConfig({
|
|
1189
|
+
schema: clientConfigSchema,
|
|
1190
|
+
role: "client"
|
|
1191
|
+
});
|
|
1192
|
+
const sdk = new FirstTreeHubSDK({
|
|
1193
|
+
serverUrl,
|
|
1194
|
+
getAccessToken: () => ensureFreshAccessToken()
|
|
1195
|
+
});
|
|
1196
|
+
agentCheck = await reconcileAgentConfigs({
|
|
1197
|
+
clientId: cfg.client.id,
|
|
1198
|
+
listPinnedAgents: () => sdk.listMyAgents()
|
|
1199
|
+
});
|
|
1200
|
+
} catch {
|
|
1201
|
+
agentCheck = checkAgentConfigs();
|
|
1202
|
+
} finally {
|
|
1203
|
+
resetConfig();
|
|
1204
|
+
resetConfigMeta();
|
|
1205
|
+
}
|
|
1087
1206
|
printResults([
|
|
1088
1207
|
checkNodeVersion(),
|
|
1089
1208
|
checkClientConfig(),
|
|
1090
1209
|
await checkServerReachable(),
|
|
1091
|
-
|
|
1210
|
+
agentCheck,
|
|
1092
1211
|
await checkWebSocket(),
|
|
1093
1212
|
checkBackgroundService()
|
|
1094
1213
|
]);
|
|
@@ -1142,6 +1261,93 @@ function registerClientCommands(program) {
|
|
|
1142
1261
|
fail("CLIENT_LIST_ERROR", error instanceof Error ? error.message : String(error));
|
|
1143
1262
|
}
|
|
1144
1263
|
});
|
|
1264
|
+
client.command("claim").description("Transfer ownership of this machine to your account (unpins the previous owner's agents from this machine)").option("--confirm", "Skip confirmation prompts (claim + auto-prune stale aliases)").option("--server <url>", "Hub server URL").action(async (options) => {
|
|
1265
|
+
try {
|
|
1266
|
+
const config = await initConfig({
|
|
1267
|
+
schema: clientConfigSchema,
|
|
1268
|
+
role: "client"
|
|
1269
|
+
});
|
|
1270
|
+
const serverUrl = resolveServerUrl(options.server) ?? config.server.url;
|
|
1271
|
+
const clientId = config.client.id;
|
|
1272
|
+
print.line("\n");
|
|
1273
|
+
print.line(" Transferring ownership of this machine to your account.\n");
|
|
1274
|
+
print.line(" This will unpin the previous owner's agents from this client.\n\n");
|
|
1275
|
+
print.status("client.id", clientId);
|
|
1276
|
+
print.status("server", serverUrl);
|
|
1277
|
+
print.line("\n");
|
|
1278
|
+
if (!options.confirm) {
|
|
1279
|
+
if (!await confirm({
|
|
1280
|
+
message: "Proceed with ownership transfer?",
|
|
1281
|
+
default: false
|
|
1282
|
+
}).catch(() => false)) {
|
|
1283
|
+
print.line(" Cancelled.\n\n");
|
|
1284
|
+
return;
|
|
1285
|
+
}
|
|
1286
|
+
}
|
|
1287
|
+
const token = await ensureFreshAccessToken();
|
|
1288
|
+
const response = await fetch(`${serverUrl}/api/v1/me/clients/${clientId}/claim`, {
|
|
1289
|
+
method: "POST",
|
|
1290
|
+
headers: {
|
|
1291
|
+
Authorization: `Bearer ${token}`,
|
|
1292
|
+
"Content-Type": "application/json"
|
|
1293
|
+
},
|
|
1294
|
+
body: "{}",
|
|
1295
|
+
signal: AbortSignal.timeout(1e4)
|
|
1296
|
+
});
|
|
1297
|
+
if (!response.ok) {
|
|
1298
|
+
const body = await response.text();
|
|
1299
|
+
fail("CLAIM_ERROR", `Server returned ${response.status}: ${body}`, 1);
|
|
1300
|
+
}
|
|
1301
|
+
const result = await response.json();
|
|
1302
|
+
print.line(` ✓ Ownership transferred. ${result.unpinnedAgentCount} agent(s) unpinned.\n`);
|
|
1303
|
+
try {
|
|
1304
|
+
const sdk = new FirstTreeHubSDK({
|
|
1305
|
+
serverUrl,
|
|
1306
|
+
getAccessToken: () => ensureFreshAccessToken()
|
|
1307
|
+
});
|
|
1308
|
+
const stale = await findStaleAliases({
|
|
1309
|
+
clientId,
|
|
1310
|
+
listPinnedAgents: () => sdk.listMyAgents()
|
|
1311
|
+
});
|
|
1312
|
+
if (stale.length === 0) print.line(" No stale local aliases — local config already matches the server.\n");
|
|
1313
|
+
else {
|
|
1314
|
+
print.line(`\n ${stale.length} local ${stale.length === 1 ? "alias" : "aliases"} won't bind on this client:\n\n`);
|
|
1315
|
+
for (const s of stale) {
|
|
1316
|
+
const id = s.agentId ?? "—";
|
|
1317
|
+
print.line(` - ${s.name.padEnd(30)} ${id.padEnd(38)} ${formatStaleReason(s.reason)}\n`);
|
|
1318
|
+
}
|
|
1319
|
+
print.line("\n");
|
|
1320
|
+
if (options.confirm === true ? true : await confirm({
|
|
1321
|
+
message: `Remove the ${stale.length} stale ${stale.length === 1 ? "alias" : "aliases"} above (config + workspace + session state)?`,
|
|
1322
|
+
default: true
|
|
1323
|
+
}).catch(() => false)) {
|
|
1324
|
+
let removed = 0;
|
|
1325
|
+
let failed = 0;
|
|
1326
|
+
for (const s of stale) try {
|
|
1327
|
+
removeLocalAgent(s.name);
|
|
1328
|
+
print.line(` ✓ removed ${s.name}\n`);
|
|
1329
|
+
removed++;
|
|
1330
|
+
} catch (err) {
|
|
1331
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
1332
|
+
print.line(` ✗ ${s.name} (${msg.slice(0, 80)})\n`);
|
|
1333
|
+
failed++;
|
|
1334
|
+
}
|
|
1335
|
+
print.line(`\n ${removed} pruned${failed > 0 ? `, ${failed} failed (re-run \`agent prune\` to retry)` : ""}.\n`);
|
|
1336
|
+
} else print.line(" Skipped. Run `first-tree-hub agent prune` later to clean up.\n");
|
|
1337
|
+
}
|
|
1338
|
+
} catch (err) {
|
|
1339
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
1340
|
+
print.line(` (Could not check for stale aliases: ${msg.slice(0, 100)})\n`);
|
|
1341
|
+
print.line(" Run `first-tree-hub agent prune` after reconnecting.\n");
|
|
1342
|
+
}
|
|
1343
|
+
print.line("\n Run `first-tree-hub client start` to reconnect.\n\n");
|
|
1344
|
+
} catch (error) {
|
|
1345
|
+
fail("CLAIM_ERROR", error instanceof Error ? error.message : String(error));
|
|
1346
|
+
} finally {
|
|
1347
|
+
resetConfig();
|
|
1348
|
+
resetConfigMeta();
|
|
1349
|
+
}
|
|
1350
|
+
});
|
|
1145
1351
|
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
1352
|
try {
|
|
1147
1353
|
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 {
|
|
2
|
+
import { A as checkServerHealth, B as ensurePostgres, C as checkAgentConfigs, D as checkDocker, E as checkDatabase, F as getClientServiceStatus, G as rotateClientIdWithBackup, H as stopPostgres, I as installClientService, L as isServiceSupported, M as checkWebSocket, N as printResults, O as checkNodeVersion, R as resolveCliInvocation, S as runMigrations, T as checkClientConfig, U as ClientRuntime, V as isDockerAvailable, W as handleClientOrgMismatch, X as hasUser, Y as createOwner, _ as onboardCreate, d as isInteractive, et as blank, f as promptAddAgent, g as onboardCheck, j as checkServerReachable, k as checkServerConfig, m as formatCheckReport, n as deriveHubUrlFromToken, ot as FirstTreeHubSDK, p as promptMissingFields, rt as status, s as startServer, st as SdkError, t as HubUrlDerivationError, y as runHomeMigration, z as uninstallClientService } from "./saas-connect-CKQ15VLz.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 };
|