@agent-team-foundation/first-tree-hub 0.8.0 → 0.8.1
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-CRDR6NwE.mjs → bootstrap-8nCntTrK.mjs} +29 -13
- package/dist/cli/index.mjs +4 -4
- package/dist/{core-BXS5ppsG.mjs → core-BA5U1v9L.mjs} +80 -1
- package/dist/index.mjs +2 -2
- package/dist/web/assets/index-7iSpxOWW.js +333 -0
- package/dist/web/assets/index-Cze8BC63.css +1 -0
- package/dist/web/index.html +2 -2
- package/package.json +1 -1
- package/dist/web/assets/index-COlVuDVR.css +0 -1
- package/dist/web/assets/index-KhUJU9Uf.js +0 -333
|
@@ -520,6 +520,14 @@ function resolveAccessToken() {
|
|
|
520
520
|
return creds.accessToken;
|
|
521
521
|
}
|
|
522
522
|
/**
|
|
523
|
+
* In-flight refresh promise. Multiple callers (WS handshake, proactive
|
|
524
|
+
* refresh timer, every SDK request) can see an expired token within the same
|
|
525
|
+
* millisecond — without dedupe each would fire an independent `/auth/refresh`
|
|
526
|
+
* round-trip and race to write `credentials.json`. Share one in-flight
|
|
527
|
+
* promise so N concurrent callers resolve from a single HTTP call.
|
|
528
|
+
*/
|
|
529
|
+
let inflightRefresh = null;
|
|
530
|
+
/**
|
|
523
531
|
* Ensure the persisted access token is fresh. Call before any API request
|
|
524
532
|
* when using persisted credentials. Returns the (possibly refreshed) access
|
|
525
533
|
* token. Service-user API keys are out of scope for this milestone.
|
|
@@ -528,19 +536,27 @@ async function ensureFreshAccessToken() {
|
|
|
528
536
|
const creds = loadCredentials();
|
|
529
537
|
if (!creds) throw new Error("No credentials found. Run `first-tree-hub client connect <server-url>` to sign in.");
|
|
530
538
|
if (!isTokenExpired(creds.accessToken)) return creds.accessToken;
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
539
|
+
if (inflightRefresh) return inflightRefresh;
|
|
540
|
+
inflightRefresh = (async () => {
|
|
541
|
+
const res = await fetch(`${creds.serverUrl}/api/v1/auth/refresh`, {
|
|
542
|
+
method: "POST",
|
|
543
|
+
headers: { "Content-Type": "application/json" },
|
|
544
|
+
body: JSON.stringify({ refreshToken: creds.refreshToken }),
|
|
545
|
+
signal: AbortSignal.timeout(1e4)
|
|
546
|
+
});
|
|
547
|
+
if (!res.ok) throw new Error("Access token expired and refresh failed. Run `first-tree-hub client connect <server-url>`.");
|
|
548
|
+
const data = await res.json();
|
|
549
|
+
saveCredentials({
|
|
550
|
+
...creds,
|
|
551
|
+
accessToken: data.accessToken
|
|
552
|
+
});
|
|
553
|
+
return data.accessToken;
|
|
554
|
+
})();
|
|
555
|
+
try {
|
|
556
|
+
return await inflightRefresh;
|
|
557
|
+
} finally {
|
|
558
|
+
inflightRefresh = null;
|
|
559
|
+
}
|
|
544
560
|
}
|
|
545
561
|
/** Back-compat alias retained so existing call sites keep compiling. */
|
|
546
562
|
const ensureFreshAdminToken = ensureFreshAccessToken;
|
package/dist/cli/index.mjs
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import { C as setConfigValue, S as serverConfigSchema, _ as loadAgents, b as resetConfigMeta, c as saveCredentials, f as agentConfigSchema, g as initConfig, h as getConfigValue, 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, v as readConfigFile, y as resetConfig } from "../bootstrap-
|
|
3
|
-
import { A as stopPostgres, C as checkServerReachable, F as SdkError, I as SessionRegistry, L as cleanWorkspaces, M as createOwner, P as FirstTreeHubSDK, S as checkServerHealth, T as printResults, _ as checkClientConfig, a as uninstallClientService, b as checkNodeVersion, c as promptAddAgent, d as loadOnboardState, f as onboardCheck, g as checkAgentConfigs, h as runMigrations, j as ClientRuntime, l as promptMissingFields, m as saveOnboardState, n as installClientService, o as startServer, p as onboardCreate, r as isServiceSupported, s as isInteractive, t as getClientServiceStatus, u as formatCheckReport, v as checkDatabase, w as checkWebSocket, x as checkServerConfig, y as checkDocker } from "../core-
|
|
2
|
+
import { C as setConfigValue, S as serverConfigSchema, _ as loadAgents, b as resetConfigMeta, c as saveCredentials, f as agentConfigSchema, g as initConfig, h as getConfigValue, 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, v as readConfigFile, y as resetConfig } from "../bootstrap-8nCntTrK.mjs";
|
|
3
|
+
import { A as stopPostgres, C as checkServerReachable, F as SdkError, I as SessionRegistry, L as cleanWorkspaces, M as createOwner, P as FirstTreeHubSDK, S as checkServerHealth, T as printResults, _ as checkClientConfig, a as uninstallClientService, b as checkNodeVersion, c as promptAddAgent, d as loadOnboardState, f as onboardCheck, g as checkAgentConfigs, h as runMigrations, j as ClientRuntime, l as promptMissingFields, m as saveOnboardState, n as installClientService, o as startServer, p as onboardCreate, r as isServiceSupported, s as isInteractive, t as getClientServiceStatus, u as formatCheckReport, v as checkDatabase, w as checkWebSocket, x as checkServerConfig, y as checkDocker } from "../core-BA5U1v9L.mjs";
|
|
4
4
|
import { n as bindFeishuUser, t as bindFeishuBot } from "../feishu-D9JkMZnU.mjs";
|
|
5
5
|
import { createRequire } from "node:module";
|
|
6
6
|
import { Command } from "commander";
|
|
@@ -1126,13 +1126,13 @@ function isSecretField(schema, dotPath) {
|
|
|
1126
1126
|
//#region src/commands/onboard.ts
|
|
1127
1127
|
async function promptMissing(args) {
|
|
1128
1128
|
if (!args.server) try {
|
|
1129
|
-
const { resolveServerUrl } = await import("../bootstrap-
|
|
1129
|
+
const { resolveServerUrl } = await import("../bootstrap-8nCntTrK.mjs").then((n) => n.t);
|
|
1130
1130
|
resolveServerUrl();
|
|
1131
1131
|
} catch {
|
|
1132
1132
|
args.server = await input({ message: "Hub server URL:" });
|
|
1133
1133
|
saveOnboardState(args);
|
|
1134
1134
|
}
|
|
1135
|
-
const { loadCredentials } = await import("../bootstrap-
|
|
1135
|
+
const { loadCredentials } = await import("../bootstrap-8nCntTrK.mjs").then((n) => n.t);
|
|
1136
1136
|
if (!loadCredentials()) throw new Error("No saved credentials. Run `first-tree-hub client connect <server-url>` before onboarding.");
|
|
1137
1137
|
if (!args.id) {
|
|
1138
1138
|
args.id = await input({ message: "Agent ID:" });
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { C as setConfigValue, S as serverConfigSchema, _ as loadAgents, d as DEFAULT_HOME_DIR$1, f as agentConfigSchema, g as initConfig, i as loadCredentials, l as DEFAULT_CONFIG_DIR, m as collectMissingPrompts, n as ensureFreshAccessToken, o as resolveServerUrl, p as clientConfigSchema, s as saveAgentConfig, u as DEFAULT_DATA_DIR$1, x as resolveConfigReadonly } from "./bootstrap-
|
|
1
|
+
import { C as setConfigValue, S as serverConfigSchema, _ as loadAgents, d as DEFAULT_HOME_DIR$1, f as agentConfigSchema, g as initConfig, i as loadCredentials, l as DEFAULT_CONFIG_DIR, m as collectMissingPrompts, n as ensureFreshAccessToken, o as resolveServerUrl, p as clientConfigSchema, s as saveAgentConfig, u as DEFAULT_DATA_DIR$1, x as resolveConfigReadonly } from "./bootstrap-8nCntTrK.mjs";
|
|
2
2
|
import { $ as updateAgentRuntimeConfigSchema, A as createMemberSchema, B as notificationQuerySchema, C as agentTypeSchema$1, D as createAdapterMappingSchema, E as createAdapterConfigSchema, F as inboxPollQuerySchema, G as sendMessageSchema, H as refreshTokenSchema, I as isRedactedEnvValue, J as sessionEventMessageSchema, K as sendToAgentSchema, L as linkTaskChatSchema, M as createTaskSchema, N as delegateFeishuUserSchema, O as createAgentSchema, P as dryRunAgentRuntimeConfigSchema, Q as updateAdapterConfigSchema, R as loginSchema, S as agentRuntimeConfigPayloadSchema$1, T as connectTokenExchangeSchema, U as runtimeStateMessageSchema, V as paginationQuerySchema, W as selfServiceFeishuBotSchema, X as sessionStateMessageSchema, Y as sessionEventSchema$1, Z as taskListQuerySchema, _ as addParticipantSchema, a as AGENT_SELECTOR_HEADER$1, at as wsAuthFrameSchema, b as agentBindRequestSchema, c as AGENT_TYPES, d as SYSTEM_CONFIG_DEFAULTS, et as updateAgentSchema, f as TASK_CREATOR_TYPES, g as WS_AUTH_FRAME_TIMEOUT_MS, h as TASK_TERMINAL_STATUSES, i as AGENT_BIND_REJECT_REASONS, it as updateTaskStatusSchema, j as createOrganizationSchema, k as createChatSchema, l as AGENT_VISIBILITY, m as TASK_STATUSES, nt as updateOrganizationSchema, o as AGENT_SOURCES, p as TASK_HEALTH_SIGNALS, q as sessionCompletionMessageSchema, rt as updateSystemConfigSchema, s as AGENT_STATUSES, tt as updateMemberSchema, u as DEFAULT_AGENT_RUNTIME_CONFIG_PAYLOAD, v as adminCreateTaskSchema, w as clientRegisterSchema, x as agentPinnedMessageSchema$1, y as adminUpdateTaskSchema, z as messageSourceSchema$1 } from "./feishu-D9JkMZnU.mjs";
|
|
3
3
|
import { copyFileSync, existsSync, mkdirSync, readFileSync, readdirSync, realpathSync, renameSync, rmSync, statSync, watch, writeFileSync } from "node:fs";
|
|
4
4
|
import { dirname, isAbsolute, join, resolve } from "node:path";
|
|
@@ -946,6 +946,7 @@ var ClientConnection = class extends EventEmitter {
|
|
|
946
946
|
this.serverUrl = config.serverUrl.replace(/\/+$/, "");
|
|
947
947
|
this.sdkVersion = config.sdkVersion;
|
|
948
948
|
this.getAccessToken = config.getAccessToken;
|
|
949
|
+
this.on("error", () => {});
|
|
949
950
|
}
|
|
950
951
|
get isConnected() {
|
|
951
952
|
return this.ws !== null && this.ws.readyState === WebSocket.OPEN && this.registered;
|
|
@@ -1458,6 +1459,75 @@ function bootstrapWorkspace(options) {
|
|
|
1458
1459
|
}
|
|
1459
1460
|
writeFileSync(join(agentDir, "tools.md"), generateToolsDoc(), "utf-8");
|
|
1460
1461
|
}
|
|
1462
|
+
function defaultInstallExec(command, args, options) {
|
|
1463
|
+
execFileSync(command, args, {
|
|
1464
|
+
cwd: options.cwd,
|
|
1465
|
+
stdio: "pipe",
|
|
1466
|
+
timeout: options.timeout,
|
|
1467
|
+
encoding: "utf-8"
|
|
1468
|
+
});
|
|
1469
|
+
}
|
|
1470
|
+
/**
|
|
1471
|
+
* Install the first-tree skill and FIRST-TREE-SOURCE-INTEGRATION block into
|
|
1472
|
+
* the workspace by shelling out to `first-tree tree integrate`.
|
|
1473
|
+
*
|
|
1474
|
+
* Resolution order for the CLI binary:
|
|
1475
|
+
* 1. `first-tree` on PATH — preferred for runtime images that pre-install it.
|
|
1476
|
+
* 2. `npx -y first-tree@latest` — fallback that downloads on first run.
|
|
1477
|
+
*
|
|
1478
|
+
* Graceful degradation: returns false on failure and logs. The session still
|
|
1479
|
+
* starts; the agent just doesn't have the first-tree skill wired up.
|
|
1480
|
+
*/
|
|
1481
|
+
function installFirstTreeIntegration(options) {
|
|
1482
|
+
const { workspacePath, contextTreePath, workspaceId, treeRepoUrl, log } = options;
|
|
1483
|
+
const exec = options.exec ?? defaultInstallExec;
|
|
1484
|
+
const integrateArgs = [
|
|
1485
|
+
"tree",
|
|
1486
|
+
"integrate",
|
|
1487
|
+
"--source-path",
|
|
1488
|
+
workspacePath,
|
|
1489
|
+
"--tree-path",
|
|
1490
|
+
contextTreePath,
|
|
1491
|
+
"--mode",
|
|
1492
|
+
"workspace-root",
|
|
1493
|
+
"--workspace-id",
|
|
1494
|
+
workspaceId,
|
|
1495
|
+
...treeRepoUrl ? ["--tree-url", treeRepoUrl] : []
|
|
1496
|
+
];
|
|
1497
|
+
const attempts = [{
|
|
1498
|
+
command: "first-tree",
|
|
1499
|
+
args: integrateArgs,
|
|
1500
|
+
label: "first-tree (PATH)"
|
|
1501
|
+
}, {
|
|
1502
|
+
command: "npx",
|
|
1503
|
+
args: [
|
|
1504
|
+
"-y",
|
|
1505
|
+
"first-tree@latest",
|
|
1506
|
+
...integrateArgs
|
|
1507
|
+
],
|
|
1508
|
+
label: "npx first-tree@latest"
|
|
1509
|
+
}];
|
|
1510
|
+
for (let index = 0; index < attempts.length; index += 1) {
|
|
1511
|
+
const attempt = attempts[index];
|
|
1512
|
+
if (!attempt) continue;
|
|
1513
|
+
try {
|
|
1514
|
+
exec(attempt.command, attempt.args, {
|
|
1515
|
+
cwd: workspacePath,
|
|
1516
|
+
timeout: 12e4
|
|
1517
|
+
});
|
|
1518
|
+
log(`First-tree integration installed via ${attempt.label}`);
|
|
1519
|
+
return true;
|
|
1520
|
+
} catch (err) {
|
|
1521
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
1522
|
+
const binaryMissing = /ENOENT|not found|command not found/i.test(msg);
|
|
1523
|
+
const isLastAttempt = index === attempts.length - 1;
|
|
1524
|
+
if (binaryMissing && !isLastAttempt) continue;
|
|
1525
|
+
log(`First-tree integration skipped (${attempt.label}): ${msg.slice(0, 200)}`);
|
|
1526
|
+
return false;
|
|
1527
|
+
}
|
|
1528
|
+
}
|
|
1529
|
+
return false;
|
|
1530
|
+
}
|
|
1461
1531
|
function generateToolsDoc() {
|
|
1462
1532
|
return `# Agent Hub SDK
|
|
1463
1533
|
|
|
@@ -2472,6 +2542,12 @@ const createClaudeCodeHandler = (config) => {
|
|
|
2472
2542
|
chatId: sessionCtx.chatId
|
|
2473
2543
|
});
|
|
2474
2544
|
generateClaudeMd(workspace, sessionCtx.agent, contextTreePath);
|
|
2545
|
+
if (contextTreePath) installFirstTreeIntegration({
|
|
2546
|
+
workspacePath: workspace,
|
|
2547
|
+
contextTreePath,
|
|
2548
|
+
workspaceId: sessionCtx.chatId,
|
|
2549
|
+
log: (msg) => sessionCtx.log(msg)
|
|
2550
|
+
});
|
|
2475
2551
|
}
|
|
2476
2552
|
const handler = {
|
|
2477
2553
|
async start(message, sessionCtx) {
|
|
@@ -3483,6 +3559,9 @@ var ClientRuntime = class {
|
|
|
3483
3559
|
this.connection.on("auth:expired", () => {
|
|
3484
3560
|
process.stderr.write(" ⚠️ Access token expired — reconnecting after refresh...\n");
|
|
3485
3561
|
});
|
|
3562
|
+
this.connection.on("error", (err) => {
|
|
3563
|
+
process.stderr.write(` \u26A0\uFE0F Client connection error: ${err.message}\n`);
|
|
3564
|
+
});
|
|
3486
3565
|
this.connection.on("agent:pinned", (message) => {
|
|
3487
3566
|
this.handleAgentPinned(message);
|
|
3488
3567
|
});
|
package/dist/index.mjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { a as resolveAccessToken, n as ensureFreshAccessToken, o as resolveServerUrl, r as ensureFreshAdminToken } from "./bootstrap-
|
|
2
|
-
import { A as stopPostgres, C as checkServerReachable, D as status, E as blank, F as SdkError, M as createOwner, N as hasUser, O as ensurePostgres, P as FirstTreeHubSDK, S as checkServerHealth, T as printResults, _ as checkClientConfig, a as uninstallClientService, b as checkNodeVersion, c as promptAddAgent, f as onboardCheck, g as checkAgentConfigs, h as runMigrations, i as resolveCliInvocation, j as ClientRuntime, k as isDockerAvailable, l as promptMissingFields, n as installClientService, o as startServer, p as onboardCreate, r as isServiceSupported, s as isInteractive, t as getClientServiceStatus, u as formatCheckReport, v as checkDatabase, w as checkWebSocket, x as checkServerConfig, y as checkDocker } from "./core-
|
|
1
|
+
import { a as resolveAccessToken, n as ensureFreshAccessToken, o as resolveServerUrl, r as ensureFreshAdminToken } from "./bootstrap-8nCntTrK.mjs";
|
|
2
|
+
import { A as stopPostgres, C as checkServerReachable, D as status, E as blank, F as SdkError, M as createOwner, N as hasUser, O as ensurePostgres, P as FirstTreeHubSDK, S as checkServerHealth, T as printResults, _ as checkClientConfig, a as uninstallClientService, b as checkNodeVersion, c as promptAddAgent, f as onboardCheck, g as checkAgentConfigs, h as runMigrations, i as resolveCliInvocation, j as ClientRuntime, k as isDockerAvailable, l as promptMissingFields, n as installClientService, o as startServer, p as onboardCreate, r as isServiceSupported, s as isInteractive, t as getClientServiceStatus, u as formatCheckReport, v as checkDatabase, w as checkWebSocket, x as checkServerConfig, y as checkDocker } from "./core-BA5U1v9L.mjs";
|
|
3
3
|
import { n as bindFeishuUser, t as bindFeishuBot } from "./feishu-D9JkMZnU.mjs";
|
|
4
4
|
export { ClientRuntime, FirstTreeHubSDK, SdkError, bindFeishuBot, bindFeishuUser, blank, checkAgentConfigs, checkClientConfig, checkDatabase, checkDocker, checkNodeVersion, checkServerConfig, checkServerHealth, checkServerReachable, checkWebSocket, createOwner, ensureFreshAccessToken, ensureFreshAdminToken, ensurePostgres, formatCheckReport, getClientServiceStatus, hasUser, installClientService, isDockerAvailable, isInteractive, isServiceSupported, onboardCheck, onboardCreate, printResults, promptAddAgent, promptMissingFields, resolveAccessToken, resolveCliInvocation, resolveServerUrl, runMigrations, startServer, status, stopPostgres, uninstallClientService };
|