@agent-team-foundation/first-tree-hub 0.11.4 → 0.12.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.
Files changed (39) hide show
  1. package/dist/{bootstrap-D-Yf8yOc.mjs → bootstrap-C_K2CKXC.mjs} +7 -0
  2. package/dist/cli/index.mjs +73 -11
  3. package/dist/client-BPUdUaZT-CyCrpCTP.mjs +2033 -0
  4. package/dist/client-BhCtO2df-BGOu-rRN.mjs +7 -0
  5. package/dist/{dist-BQtAQNRD.mjs → dist-LgF7LHpE.mjs} +1 -1
  6. package/dist/{dist-ClFs4WMj.mjs → dist-UOZ6vMUW.mjs} +372 -197
  7. package/dist/drizzle/0033_onboarding_dismissed_at.sql +13 -0
  8. package/dist/drizzle/0034_pending_questions.sql +34 -0
  9. package/dist/drizzle/meta/_journal.json +14 -0
  10. package/dist/{errors-BmyRwN0Y-Dad3eV8F.mjs → errors-CF5evtJt-B0NTIVPt.mjs} +2 -1
  11. package/dist/{feishu-AI3pwmqN.mjs → feishu-C6qlhju2.mjs} +1 -1
  12. package/dist/{getMachineId-bsd-c2VImogj.mjs → getMachineId-bsd-BmasEOJr.mjs} +1 -1
  13. package/dist/{getMachineId-bsd-DyySs8xz.mjs → getMachineId-bsd-Dh3h0DDE.mjs} +1 -1
  14. package/dist/{getMachineId-darwin-Cl7TSzgO.mjs → getMachineId-darwin-CuhM3hfZ.mjs} +1 -1
  15. package/dist/{getMachineId-darwin-DKgI8b1d.mjs → getMachineId-darwin-D9wR0SLj.mjs} +1 -1
  16. package/dist/{getMachineId-linux-1OIMWfdh.mjs → getMachineId-linux-CYfb0oxZ.mjs} +1 -1
  17. package/dist/{getMachineId-linux-cT7EbP10.mjs → getMachineId-linux-D8ZaSjAC.mjs} +1 -1
  18. package/dist/{getMachineId-unsupported-CkX-YOG1.mjs → getMachineId-unsupported-Cu3iisaD.mjs} +1 -1
  19. package/dist/{getMachineId-unsupported-CmVlhzIo.mjs → getMachineId-unsupported-DZqI4ZT5.mjs} +1 -1
  20. package/dist/{getMachineId-win-C2cM60YT.mjs → getMachineId-win-8ZJbtrdf.mjs} +1 -1
  21. package/dist/{getMachineId-win-Chl03TYe.mjs → getMachineId-win-DT-hqwVp.mjs} +1 -1
  22. package/dist/index.mjs +9 -9
  23. package/dist/{invitation-Dnn5gGGX-DXryyvRG.mjs → invitation-Bg0TRiyx-BsZH4GCS.mjs} +2 -2
  24. package/dist/invitation-C299fxkP-KyCNax4T.mjs +4 -0
  25. package/dist/{observability-BAScT_5S-gw1ODB_o.mjs → observability-BAScT_5S-BcW9HgkG.mjs} +13 -13
  26. package/dist/{observability-CYsdAcoF.mjs → observability-eLA9iNK_.mjs} +3 -3
  27. package/dist/{saas-connect-CVoRK0Ex.mjs → saas-connect-Drn9g6cR.mjs} +1195 -1685
  28. package/dist/web/assets/index-B_Tf2I6v.css +1 -0
  29. package/dist/web/assets/{index-Bm6hgcvt.js → index-Bnyz7inW.js} +1 -1
  30. package/dist/web/assets/index-Dy3jIUX5.js +391 -0
  31. package/dist/web/index.html +2 -2
  32. package/package.json +1 -1
  33. package/dist/client-By1K4VVT-DuI6EnSh.mjs +0 -4
  34. package/dist/client-CLdRbuml-svTO0Eat.mjs +0 -524
  35. package/dist/invitation-DWlyNb8x-BvXubk24.mjs +0 -4
  36. package/dist/web/assets/index-fNb_M0nL.css +0 -1
  37. package/dist/web/assets/index-k2bWRKc-.js +0 -388
  38. /package/dist/{esm-Ci8E1Gtj.mjs → esm-iadMkGbV.mjs} +0 -0
  39. /package/dist/{src-aJMV60mR.mjs → src-DNBS5Yjj.mjs} +0 -0
@@ -0,0 +1,7 @@
1
+ import "./observability-BAScT_5S-BcW9HgkG.mjs";
2
+ import "./logger-core-BTmvdflj-DjW8FM4T.mjs";
3
+ import "./dist-UOZ6vMUW.mjs";
4
+ import "./errors-CF5evtJt-B0NTIVPt.mjs";
5
+ import "./src-DNBS5Yjj.mjs";
6
+ import { q as listMyPinnedAgents } from "./client-BPUdUaZT-CyCrpCTP.mjs";
7
+ export { listMyPinnedAgents };
@@ -1,5 +1,5 @@
1
1
  import { i as __require, t as __commonJSMin } from "./chunk-BSw8zbkd.mjs";
2
- import { t as require_src } from "./src-aJMV60mR.mjs";
2
+ import { t as require_src } from "./src-DNBS5Yjj.mjs";
3
3
  //#region ../../node_modules/.pnpm/agent-base@7.1.4/node_modules/agent-base/dist/helpers.js
4
4
  var require_helpers = /* @__PURE__ */ __commonJSMin(((exports) => {
5
5
  var __createBinding = exports && exports.__createBinding || (Object.create ? (function(o, m, k, k2) {
@@ -137,195 +137,6 @@ z.object({
137
137
  connected: z.boolean(),
138
138
  lastActiveAt: z.string().nullable()
139
139
  });
140
- const presenceStatusSchema = z.enum(["online", "offline"]);
141
- const runtimeStateSchema = z.enum([
142
- "idle",
143
- "working",
144
- "blocked",
145
- "error"
146
- ]);
147
- z.enum([
148
- "active",
149
- "suspended",
150
- "evicted"
151
- ]);
152
- /** Wire-level states a client may report. `evicted` from a stale client is rejected. */
153
- const clientSessionStateSchema = z.enum(["active", "suspended"]);
154
- const sessionStateMessageSchema = z.object({
155
- chatId: z.string().min(1),
156
- state: clientSessionStateSchema
157
- });
158
- /** Client-reported runtime state override (client → server, per-agent). */
159
- const runtimeStateMessageSchema = z.object({ runtimeState: runtimeStateSchema });
160
- const agentBindRequestSchema = z.object({
161
- agentId: z.string().min(1),
162
- runtimeType: z.string().max(50),
163
- runtimeVersion: z.string().max(50).optional()
164
- });
165
- const AGENT_BIND_REJECT_REASONS = {
166
- WRONG_CLIENT: "wrong_client",
167
- NOT_OWNED: "not_owned",
168
- AGENT_SUSPENDED: "agent_suspended",
169
- WRONG_ORG: "wrong_org",
170
- UNKNOWN_AGENT: "unknown_agent",
171
- RUNTIME_PROVIDER_MISMATCH: "runtime_provider_mismatch"
172
- };
173
- z.enum([
174
- "wrong_client",
175
- "not_owned",
176
- "agent_suspended",
177
- "wrong_org",
178
- "unknown_agent",
179
- "runtime_provider_mismatch"
180
- ]);
181
- /** Header used on agent-scoped HTTP calls to select which managed agent the JWT acts as. */
182
- const AGENT_SELECTOR_HEADER = "x-agent-id";
183
- z.object({
184
- agentId: z.string(),
185
- status: presenceStatusSchema,
186
- connectedAt: z.string().nullable(),
187
- lastSeenAt: z.string(),
188
- clientId: z.string().nullable().optional(),
189
- runtimeType: z.string().nullable().optional(),
190
- runtimeVersion: z.string().nullable().optional(),
191
- runtimeState: runtimeStateSchema.nullable().optional(),
192
- activeSessions: z.number().int().nullable().optional(),
193
- totalSessions: z.number().int().nullable().optional(),
194
- runtimeUpdatedAt: z.string().nullable().optional()
195
- });
196
- z.object({
197
- total: z.number().int(),
198
- running: z.number().int(),
199
- byState: z.object({
200
- idle: z.number().int(),
201
- working: z.number().int(),
202
- blocked: z.number().int(),
203
- error: z.number().int()
204
- }),
205
- clients: z.number().int()
206
- });
207
- const runtimeProviderSchema = z.enum(["claude-code", "codex"]);
208
- const DEFAULT_RUNTIME_PROVIDER = "claude-code";
209
- const AGENT_TYPES = {
210
- HUMAN: "human",
211
- PERSONAL_ASSISTANT: "personal_assistant",
212
- AUTONOMOUS_AGENT: "autonomous_agent"
213
- };
214
- const agentTypeSchema = z.enum([
215
- "human",
216
- "personal_assistant",
217
- "autonomous_agent"
218
- ]);
219
- const AGENT_VISIBILITY = {
220
- PRIVATE: "private",
221
- ORGANIZATION: "organization"
222
- };
223
- const agentVisibilitySchema = z.enum(["private", "organization"]);
224
- const AGENT_STATUSES = {
225
- ACTIVE: "active",
226
- SUSPENDED: "suspended",
227
- DELETED: "deleted"
228
- };
229
- const AGENT_SOURCES = {
230
- ADMIN_API: "admin-api",
231
- PORTAL: "portal"
232
- };
233
- const agentSourceSchema = z.enum(["admin-api", "portal"]);
234
- z.enum(["active", "suspended"]);
235
- /**
236
- * Agent-name rules (see docs/agent-naming-design.md §3.1):
237
- * - Lowercase ASCII slug, hyphens + underscores allowed.
238
- * - Must start with alphanumeric: `-` / `_` as first char collide with
239
- * CLI flag parsing and markdown list syntax.
240
- * - 1–64 chars — aligned with `MENTION_REGEX` so any valid name can be
241
- * @-mentioned in chat. Older rows created under the previous 1–100
242
- * regex are grandfathered; the tight rule only gates new creates.
243
- */
244
- const AGENT_NAME_REGEX = /^[a-z0-9][a-z0-9_-]{0,63}$/;
245
- const RESERVED_AGENT_NAMES_SET = new Set([
246
- "admin",
247
- "agent",
248
- "first-tree",
249
- "hub",
250
- "me",
251
- "null",
252
- "system",
253
- "undefined"
254
- ]);
255
- function isReservedAgentName(name) {
256
- return RESERVED_AGENT_NAMES_SET.has(name);
257
- }
258
- const createAgentSchema = z.object({
259
- name: z.string().min(1).max(64).regex(AGENT_NAME_REGEX, "Must start with a letter or digit and contain only lowercase letters, digits, hyphens (-), and underscores (_). Max 64 chars.").refine((n) => !isReservedAgentName(n), { message: "That agent name is reserved — pick a different one." }).optional(),
260
- type: agentTypeSchema,
261
- displayName: z.string().min(1).max(200).optional(),
262
- delegateMention: z.string().max(100).optional(),
263
- organizationId: z.string().min(1).max(100).optional(),
264
- source: agentSourceSchema.optional(),
265
- visibility: agentVisibilitySchema.optional(),
266
- metadata: z.record(z.string(), z.unknown()).optional(),
267
- managerId: z.string().optional(),
268
- clientId: z.string().min(1).max(100).optional(),
269
- runtimeProvider: runtimeProviderSchema.optional()
270
- });
271
- const updateAgentSchema = z.object({
272
- type: agentTypeSchema.optional(),
273
- displayName: z.string().min(1).max(200).optional(),
274
- delegateMention: z.string().max(100).nullable().optional(),
275
- visibility: agentVisibilitySchema.optional(),
276
- metadata: z.record(z.string(), z.unknown()).optional(),
277
- managerId: z.string().nullable().optional(),
278
- clientId: z.string().min(1).max(100).nullable().optional()
279
- });
280
- /**
281
- * Service-level rebind input. Admin / owner re-binds an agent to a new
282
- * client and/or a new runtime provider in one atomic operation.
283
- *
284
- * `force` bypasses the capability-match check (e.g. when the client is
285
- * offline and capabilities are stale).
286
- */
287
- const rebindAgentSchema = z.object({
288
- clientId: z.string().min(1).max(100),
289
- runtimeProvider: runtimeProviderSchema,
290
- force: z.boolean().optional()
291
- });
292
- z.object({
293
- uuid: z.string(),
294
- name: z.string().nullable(),
295
- organizationId: z.string(),
296
- type: agentTypeSchema,
297
- displayName: z.string(),
298
- delegateMention: z.string().nullable(),
299
- inboxId: z.string(),
300
- status: z.string(),
301
- source: z.string().nullable().optional(),
302
- visibility: agentVisibilitySchema,
303
- metadata: z.record(z.string(), z.unknown()),
304
- managerId: z.string().nullable(),
305
- clientId: z.string().nullable(),
306
- runtimeProvider: runtimeProviderSchema,
307
- presenceStatus: presenceStatusSchema.optional(),
308
- createdAt: z.string(),
309
- updatedAt: z.string()
310
- });
311
- z.object({
312
- repo: z.string().nullable(),
313
- branch: z.string().nullable()
314
- });
315
- /**
316
- * Server → client WebSocket frame announcing that an agent has just been
317
- * pinned to the connected client (either created with `clientId` or bound via
318
- * PATCH NULL → ID). The client can auto-register a local config from this so
319
- * the operator doesn't have to run `first-tree-hub agent add` manually.
320
- */
321
- const agentPinnedMessageSchema = z.object({
322
- type: z.literal("agent:pinned"),
323
- agentId: z.string(),
324
- name: z.string().nullable(),
325
- displayName: z.string(),
326
- agentType: agentTypeSchema,
327
- runtimeProvider: runtimeProviderSchema
328
- });
329
140
  /**
330
141
  * Agent runtime configuration.
331
142
  *
@@ -500,6 +311,26 @@ const agentRuntimeConfigSchema = z.object({
500
311
  updatedBy: z.string()
501
312
  });
502
313
  /**
314
+ * Write-side shape with no `.default()` per field.
315
+ *
316
+ * `agentRuntimeConfigPayloadShape` carries `.default()` on every field for the
317
+ * read path (so legacy DB rows parse cleanly). On the PATCH side those defaults
318
+ * are actively harmful: Zod 4's `.partial()` makes a field optional but keeps
319
+ * the inner `ZodDefault`, so a body like `{ mcpServers: [...] }` parses to a
320
+ * fully-populated patch where the omitted fields are filled with their
321
+ * defaults — the service layer's `patch.x ?? current.x` then sees a truthy
322
+ * default and *replaces* the user's saved value with empty. Mirroring the 5
323
+ * fields here without defaults keeps "field absent" → `undefined` in the
324
+ * parsed patch, which is what the merge logic expects.
325
+ */
326
+ const agentRuntimeConfigPatchShape = z.object({
327
+ prompt: promptConfigSchema,
328
+ model: z.string(),
329
+ mcpServers: z.array(mcpServerSchema),
330
+ env: z.array(envEntrySchema),
331
+ gitRepos: z.array(gitRepoSchema)
332
+ }).partial();
333
+ /**
503
334
  * Patch payload for PATCH /api/v1/admin/agents/:uuid/config.
504
335
  *
505
336
  * - `expectedVersion` enforces optimistic locking; mismatch → 409.
@@ -507,9 +338,9 @@ const agentRuntimeConfigSchema = z.object({
507
338
  */
508
339
  const updateAgentRuntimeConfigSchema = z.object({
509
340
  expectedVersion: z.number().int().positive(),
510
- payload: agentRuntimeConfigPayloadShape.partial()
341
+ payload: agentRuntimeConfigPatchShape
511
342
  });
512
- const dryRunAgentRuntimeConfigSchema = z.object({ payload: agentRuntimeConfigPayloadShape.partial() });
343
+ const dryRunAgentRuntimeConfigSchema = z.object({ payload: agentRuntimeConfigPatchShape });
513
344
  z.object({
514
345
  current: agentRuntimeConfigSchema,
515
346
  next: agentRuntimeConfigPayloadSchema,
@@ -538,6 +369,196 @@ function deriveRepoLocalPath(url) {
538
369
  if (!trimmed) return "";
539
370
  return ((trimmed.split(/[?#]/)[0] ?? "").split(/[/:]/).filter(Boolean).pop() ?? "").replace(/\.git$/i, "");
540
371
  }
372
+ const presenceStatusSchema = z.enum(["online", "offline"]);
373
+ const runtimeStateSchema = z.enum([
374
+ "idle",
375
+ "working",
376
+ "blocked",
377
+ "error"
378
+ ]);
379
+ z.enum([
380
+ "active",
381
+ "suspended",
382
+ "evicted"
383
+ ]);
384
+ /** Wire-level states a client may report. `evicted` from a stale client is rejected. */
385
+ const clientSessionStateSchema = z.enum(["active", "suspended"]);
386
+ const sessionStateMessageSchema = z.object({
387
+ chatId: z.string().min(1),
388
+ state: clientSessionStateSchema
389
+ });
390
+ /** Client-reported runtime state override (client → server, per-agent). */
391
+ const runtimeStateMessageSchema = z.object({ runtimeState: runtimeStateSchema });
392
+ const agentBindRequestSchema = z.object({
393
+ agentId: z.string().min(1),
394
+ runtimeType: z.string().max(50),
395
+ runtimeVersion: z.string().max(50).optional()
396
+ });
397
+ const AGENT_BIND_REJECT_REASONS = {
398
+ WRONG_CLIENT: "wrong_client",
399
+ NOT_OWNED: "not_owned",
400
+ AGENT_SUSPENDED: "agent_suspended",
401
+ WRONG_ORG: "wrong_org",
402
+ UNKNOWN_AGENT: "unknown_agent",
403
+ RUNTIME_PROVIDER_MISMATCH: "runtime_provider_mismatch"
404
+ };
405
+ z.enum([
406
+ "wrong_client",
407
+ "not_owned",
408
+ "agent_suspended",
409
+ "wrong_org",
410
+ "unknown_agent",
411
+ "runtime_provider_mismatch"
412
+ ]);
413
+ /** Header used on agent-scoped HTTP calls to select which managed agent the JWT acts as. */
414
+ const AGENT_SELECTOR_HEADER = "x-agent-id";
415
+ z.object({
416
+ agentId: z.string(),
417
+ status: presenceStatusSchema,
418
+ connectedAt: z.string().nullable(),
419
+ lastSeenAt: z.string(),
420
+ clientId: z.string().nullable().optional(),
421
+ runtimeType: z.string().nullable().optional(),
422
+ runtimeVersion: z.string().nullable().optional(),
423
+ runtimeState: runtimeStateSchema.nullable().optional(),
424
+ activeSessions: z.number().int().nullable().optional(),
425
+ totalSessions: z.number().int().nullable().optional(),
426
+ runtimeUpdatedAt: z.string().nullable().optional()
427
+ });
428
+ z.object({
429
+ total: z.number().int(),
430
+ running: z.number().int(),
431
+ byState: z.object({
432
+ idle: z.number().int(),
433
+ working: z.number().int(),
434
+ blocked: z.number().int(),
435
+ error: z.number().int()
436
+ }),
437
+ clients: z.number().int()
438
+ });
439
+ const runtimeProviderSchema = z.enum(["claude-code", "codex"]);
440
+ const DEFAULT_RUNTIME_PROVIDER = "claude-code";
441
+ const AGENT_TYPES = {
442
+ HUMAN: "human",
443
+ PERSONAL_ASSISTANT: "personal_assistant",
444
+ AUTONOMOUS_AGENT: "autonomous_agent"
445
+ };
446
+ const agentTypeSchema = z.enum([
447
+ "human",
448
+ "personal_assistant",
449
+ "autonomous_agent"
450
+ ]);
451
+ const AGENT_VISIBILITY = {
452
+ PRIVATE: "private",
453
+ ORGANIZATION: "organization"
454
+ };
455
+ const agentVisibilitySchema = z.enum(["private", "organization"]);
456
+ const AGENT_STATUSES = {
457
+ ACTIVE: "active",
458
+ SUSPENDED: "suspended",
459
+ DELETED: "deleted"
460
+ };
461
+ const AGENT_SOURCES = {
462
+ ADMIN_API: "admin-api",
463
+ PORTAL: "portal"
464
+ };
465
+ const agentSourceSchema = z.enum(["admin-api", "portal"]);
466
+ z.enum(["active", "suspended"]);
467
+ /**
468
+ * Agent-name rules (see docs/agent-naming-design.md §3.1):
469
+ * - Lowercase ASCII slug, hyphens + underscores allowed.
470
+ * - Must start with alphanumeric: `-` / `_` as first char collide with
471
+ * CLI flag parsing and markdown list syntax.
472
+ * - 1–64 chars — aligned with `MENTION_REGEX` so any valid name can be
473
+ * @-mentioned in chat. Older rows created under the previous 1–100
474
+ * regex are grandfathered; the tight rule only gates new creates.
475
+ */
476
+ const AGENT_NAME_REGEX = /^[a-z0-9][a-z0-9_-]{0,63}$/;
477
+ const RESERVED_AGENT_NAMES_SET = new Set([
478
+ "admin",
479
+ "agent",
480
+ "first-tree",
481
+ "hub",
482
+ "me",
483
+ "null",
484
+ "system",
485
+ "undefined"
486
+ ]);
487
+ function isReservedAgentName(name) {
488
+ return RESERVED_AGENT_NAMES_SET.has(name);
489
+ }
490
+ const createAgentSchema = z.object({
491
+ name: z.string().min(1).max(64).regex(AGENT_NAME_REGEX, "Must start with a letter or digit and contain only lowercase letters, digits, hyphens (-), and underscores (_). Max 64 chars.").refine((n) => !isReservedAgentName(n), { message: "That agent name is reserved — pick a different one." }).optional(),
492
+ type: agentTypeSchema,
493
+ displayName: z.string().min(1).max(200).optional(),
494
+ delegateMention: z.string().max(100).optional(),
495
+ organizationId: z.string().min(1).max(100).optional(),
496
+ source: agentSourceSchema.optional(),
497
+ visibility: agentVisibilitySchema.optional(),
498
+ metadata: z.record(z.string(), z.unknown()).optional(),
499
+ managerId: z.string().optional(),
500
+ clientId: z.string().min(1).max(100).optional(),
501
+ runtimeProvider: runtimeProviderSchema.optional(),
502
+ gitRepos: z.array(gitRepoSchema).optional()
503
+ });
504
+ const updateAgentSchema = z.object({
505
+ type: agentTypeSchema.optional(),
506
+ displayName: z.string().min(1).max(200).optional(),
507
+ delegateMention: z.string().max(100).nullable().optional(),
508
+ visibility: agentVisibilitySchema.optional(),
509
+ metadata: z.record(z.string(), z.unknown()).optional(),
510
+ managerId: z.string().nullable().optional(),
511
+ clientId: z.string().min(1).max(100).nullable().optional()
512
+ });
513
+ /**
514
+ * Service-level rebind input. Admin / owner re-binds an agent to a new
515
+ * client and/or a new runtime provider in one atomic operation.
516
+ *
517
+ * `force` bypasses the capability-match check (e.g. when the client is
518
+ * offline and capabilities are stale).
519
+ */
520
+ const rebindAgentSchema = z.object({
521
+ clientId: z.string().min(1).max(100),
522
+ runtimeProvider: runtimeProviderSchema,
523
+ force: z.boolean().optional()
524
+ });
525
+ z.object({
526
+ uuid: z.string(),
527
+ name: z.string().nullable(),
528
+ organizationId: z.string(),
529
+ type: agentTypeSchema,
530
+ displayName: z.string(),
531
+ delegateMention: z.string().nullable(),
532
+ inboxId: z.string(),
533
+ status: z.string(),
534
+ source: z.string().nullable().optional(),
535
+ visibility: agentVisibilitySchema,
536
+ metadata: z.record(z.string(), z.unknown()),
537
+ managerId: z.string().nullable(),
538
+ clientId: z.string().nullable(),
539
+ runtimeProvider: runtimeProviderSchema,
540
+ presenceStatus: presenceStatusSchema.optional(),
541
+ createdAt: z.string(),
542
+ updatedAt: z.string()
543
+ });
544
+ z.object({
545
+ repo: z.string().nullable(),
546
+ branch: z.string().nullable()
547
+ });
548
+ /**
549
+ * Server → client WebSocket frame announcing that an agent has just been
550
+ * pinned to the connected client (either created with `clientId` or bound via
551
+ * PATCH NULL → ID). The client can auto-register a local config from this so
552
+ * the operator doesn't have to run `first-tree-hub agent add` manually.
553
+ */
554
+ const agentPinnedMessageSchema = z.object({
555
+ type: z.literal("agent:pinned"),
556
+ agentId: z.string(),
557
+ name: z.string().nullable(),
558
+ displayName: z.string(),
559
+ agentType: agentTypeSchema,
560
+ runtimeProvider: runtimeProviderSchema
561
+ });
541
562
  const loginSchema = z.object({
542
563
  username: z.string().min(1),
543
564
  password: z.string().min(1)
@@ -825,7 +846,9 @@ const messageFormatSchema = z.enum([
825
846
  "card",
826
847
  "reference",
827
848
  "file",
828
- "task"
849
+ "task",
850
+ "question",
851
+ "question_answer"
829
852
  ]);
830
853
  const sendMessageSchema = z.object({
831
854
  format: messageFormatSchema.default("text"),
@@ -1054,6 +1077,43 @@ const createOrgFromMeSchema = z.object({
1054
1077
  name: z.string().min(2).max(50).regex(/^[a-z0-9][a-z0-9-]*$/),
1055
1078
  displayName: z.string().min(1).max(200)
1056
1079
  });
1080
+ /**
1081
+ * Body for `PATCH /me/onboarding`. v1 only mutates `dismissed` — true to
1082
+ * hide the onboarding stepper (server stamps `users.onboarding_dismissed_at
1083
+ * = NOW()`), false to restore it. See docs/new-user-onboarding-design.md
1084
+ * §8.4.
1085
+ */
1086
+ const patchOnboardingSchema = z.object({ dismissed: z.boolean().optional() });
1087
+ /**
1088
+ * Body for `POST /me/onboarding/events`. The web SPA reports key
1089
+ * milestones so the server can log them as a single funnel-trackable
1090
+ * stream alongside server-emitted events (`team_created`, `dismissed`).
1091
+ *
1092
+ * Server emits:
1093
+ * - `team_created` — at OAuth callback when joinPath === "solo"
1094
+ * - `dismissed` — when PATCH /me/onboarding flips dismissed
1095
+ *
1096
+ * Web reports:
1097
+ * - `team_renamed` — Step 1 user changed the auto-named team
1098
+ * - `agent_created` — Step 2 successfully created the agent
1099
+ * - `tree_chat_started` — Step 3 [Yes, set it up] succeeded
1100
+ * - `tree_intro_dismissed` — Step 3 [I'll do it later] clicked
1101
+ */
1102
+ const onboardingEventNameSchema = z.enum([
1103
+ "team_renamed",
1104
+ "agent_created",
1105
+ "tree_chat_started",
1106
+ "tree_intro_dismissed"
1107
+ ]);
1108
+ const onboardingEventSchema = z.object({
1109
+ event: onboardingEventNameSchema,
1110
+ attrs: z.record(z.string(), z.union([
1111
+ z.string(),
1112
+ z.number(),
1113
+ z.boolean(),
1114
+ z.null()
1115
+ ])).optional()
1116
+ });
1057
1117
  z.object({
1058
1118
  id: z.string(),
1059
1119
  organizationId: z.string(),
@@ -1159,12 +1219,26 @@ const githubDevCallbackQuerySchema = z.object({
1159
1219
  * 2. Add a key to `ORG_SETTINGS_NAMESPACES`.
1160
1220
  * 3. Done. No DB migration, no new API route.
1161
1221
  */
1222
+ const httpsRepoUrlSchema = z.string().url().refine((value) => {
1223
+ try {
1224
+ return new URL(value).protocol === "https:";
1225
+ } catch {
1226
+ return false;
1227
+ }
1228
+ }, { message: "Repo URL must use HTTPS." }).refine((value) => {
1229
+ try {
1230
+ const url = new URL(value);
1231
+ return url.username.length === 0 && url.password.length === 0;
1232
+ } catch {
1233
+ return false;
1234
+ }
1235
+ }, { message: "Repo URL must not include credentials." });
1162
1236
  const orgContextTreeStorageSchema = z.object({
1163
- repo: z.string().url().optional(),
1237
+ repo: httpsRepoUrlSchema.optional(),
1164
1238
  branch: z.string().default("main")
1165
1239
  });
1166
1240
  const orgContextTreeInputSchema = z.object({
1167
- repo: z.string().url().min(1).nullish(),
1241
+ repo: httpsRepoUrlSchema.nullish(),
1168
1242
  branch: z.string().min(1).nullish()
1169
1243
  });
1170
1244
  const orgContextTreeOutputSchema = z.object({
@@ -1177,16 +1251,36 @@ const orgGithubIntegrationOutputSchema = z.object({
1177
1251
  webhookSecretConfigured: z.boolean(),
1178
1252
  webhookUrl: z.string()
1179
1253
  });
1254
+ const orgSourceReposStorageSchema = z.object({ repos: z.array(z.object({
1255
+ url: httpsRepoUrlSchema,
1256
+ defaultBranch: z.string().optional()
1257
+ })).default([]) });
1258
+ const orgSourceReposInputSchema = z.object({ repos: z.array(z.object({
1259
+ url: httpsRepoUrlSchema,
1260
+ defaultBranch: z.string().min(1).optional()
1261
+ })).optional() });
1262
+ const orgSourceReposOutputSchema = z.object({ repos: z.array(z.object({
1263
+ url: z.string(),
1264
+ defaultBranch: z.string().optional()
1265
+ })) });
1180
1266
  const ORG_SETTINGS_NAMESPACES = {
1181
1267
  context_tree: {
1182
1268
  storage: orgContextTreeStorageSchema,
1183
1269
  input: orgContextTreeInputSchema,
1184
- output: orgContextTreeOutputSchema
1270
+ output: orgContextTreeOutputSchema,
1271
+ readPolicy: "member"
1185
1272
  },
1186
1273
  github_integration: {
1187
1274
  storage: orgGithubIntegrationStorageSchema,
1188
1275
  input: orgGithubIntegrationInputSchema,
1189
- output: orgGithubIntegrationOutputSchema
1276
+ output: orgGithubIntegrationOutputSchema,
1277
+ readPolicy: "admin"
1278
+ },
1279
+ source_repos: {
1280
+ storage: orgSourceReposStorageSchema,
1281
+ input: orgSourceReposInputSchema,
1282
+ output: orgSourceReposOutputSchema,
1283
+ readPolicy: "member"
1190
1284
  }
1191
1285
  };
1192
1286
  const ORG_SETTINGS_NAMESPACE_KEYS = Object.keys(ORG_SETTINGS_NAMESPACES);
@@ -1228,6 +1322,87 @@ z.object({
1228
1322
  organizationId: z.string(),
1229
1323
  agents: z.record(z.string(), z.array(pulseBucketSchema).length(32))
1230
1324
  });
1325
+ /**
1326
+ * Structured ask-user payloads bridged from the Claude Agent SDK
1327
+ * `AskUserQuestion` tool to Hub messages.
1328
+ *
1329
+ * Shape mirrors the SDK 0.2.84 input/output verbatim so the client
1330
+ * runtime adapter can pass `updatedInput` straight through. See
1331
+ * verify scripts under `packages/client/tmp-verify/` for the live
1332
+ * matrix this was validated against.
1333
+ *
1334
+ * Lifecycle:
1335
+ * 1. Agent emits a `format: "question"` message — its `content` is a
1336
+ * `QuestionMessageContent` carrying `correlationId` + `questions[]`.
1337
+ * 2. User picks options in the Web UI and POSTs answers; server writes
1338
+ * a `format: "question_answer"` message — its `content` is a
1339
+ * `QuestionAnswerMessageContent` referencing the same `correlationId`.
1340
+ * 3. Client runtime resolves the in-flight `canUseTool` promise with the
1341
+ * answers, and the SDK feeds them back to the model.
1342
+ *
1343
+ * `pending → answered → superseded` runtime status lives in a separate
1344
+ * server table (`pending_questions`) and is not part of the message —
1345
+ * messages are immutable once written.
1346
+ */
1347
+ /**
1348
+ * Single option inside a question. `preview` is rich content rendered above
1349
+ * the label — the SDK's tool input emits it as `string | undefined` (the
1350
+ * field is omitted when the model didn't generate any preview content), so
1351
+ * we accept undefined / null / string and normalise downstream renderers
1352
+ * to treat all three the same way.
1353
+ */
1354
+ const questionOptionSchema = z.object({
1355
+ label: z.string().min(1),
1356
+ description: z.string(),
1357
+ preview: z.string().nullable().optional()
1358
+ });
1359
+ /**
1360
+ * One question. `header` is a chip-style short tag. The SDK schema docs
1361
+ * describe ≤12 chars but in practice the model occasionally emits
1362
+ * slightly longer headers; we keep the rule loose (≤24) so a stylistic
1363
+ * regression doesn't fail-closed at canUseTool and abandon the entire
1364
+ * tool call. The UI truncates visually if needed.
1365
+ */
1366
+ const questionItemSchema = z.object({
1367
+ question: z.string().min(1),
1368
+ header: z.string().min(1).max(24),
1369
+ options: z.array(questionOptionSchema).min(2).max(4),
1370
+ multiSelect: z.boolean()
1371
+ });
1372
+ /** Session-level preview format hint. Mirrors `toolConfig.askUserQuestion.previewFormat`. */
1373
+ const questionPreviewFormatSchema = z.enum(["html", "markdown"]).nullable();
1374
+ /**
1375
+ * Content payload for a message whose `format === "question"`.
1376
+ *
1377
+ * `correlationId` ties the question to its eventual answer message AND to the
1378
+ * server-side `pending_questions` row; client runtime uses it to resolve the
1379
+ * waiting `canUseTool` promise. Reuse the SDK `tool_use_id` when available so
1380
+ * a single id flows end-to-end.
1381
+ */
1382
+ const questionMessageContentSchema = z.object({
1383
+ correlationId: z.string().min(1),
1384
+ questions: z.array(questionItemSchema).min(1).max(4),
1385
+ previewFormat: questionPreviewFormatSchema,
1386
+ allowFreeText: z.boolean()
1387
+ });
1388
+ /**
1389
+ * Content payload for a message whose `format === "question_answer"`.
1390
+ *
1391
+ * `answers` is keyed by `QuestionItem.question` text. For `multiSelect` questions
1392
+ * the value is a `, `-joined string of selected labels (matches SDK convention).
1393
+ * For free-text answers the value is the user's raw input.
1394
+ */
1395
+ const questionAnswerMessageContentSchema = z.object({
1396
+ correlationId: z.string().min(1),
1397
+ answers: z.record(z.string().min(1), z.string())
1398
+ });
1399
+ /** Submit-answer request body for `POST /api/admin/questions/:correlationId/answer`. */
1400
+ const submitQuestionAnswerSchema = z.object({ answers: z.record(z.string().min(1), z.string()) });
1401
+ z.enum([
1402
+ "pending",
1403
+ "answered",
1404
+ "superseded"
1405
+ ]);
1231
1406
  const sessionEventKind = z.enum([
1232
1407
  "tool_call",
1233
1408
  "error",
@@ -1521,4 +1696,4 @@ z.object({
1521
1696
  capabilities: serverCapabilitiesSchema.optional()
1522
1697
  }).passthrough();
1523
1698
  //#endregion
1524
- export { loginSchema as $, createAgentSchema as A, githubCallbackQuerySchema as B, agentTypeSchema as C, updateMemberSchema as Ct, contextTreeSnapshotSchema as D, connectTokenExchangeSchema as E, wsAuthFrameSchema as Et, createTaskSchema as F, inboxDeliverFrameSchema as G, githubStartQuerySchema as H, defaultRuntimeConfigPayload as I, isRedactedEnvValue as J, inboxPollQuerySchema as K, delegateFeishuUserSchema as L, createMeChatSchema as M, createMemberSchema as N, createAdapterConfigSchema as O, createOrgFromMeSchema as P, listMeChatsQuerySchema as Q, dryRunAgentRuntimeConfigSchema as R, agentRuntimeConfigPayloadSchema as S, updateClientCapabilitiesSchema as St, clientRegisterSchema as T, updateTaskStatusSchema as Tt, imageInlineContentSchema as U, githubDevCallbackQuerySchema as V, inboxAckFrameSchema as W, joinByInvitationSchema as X, isReservedAgentName as Y, linkTaskChatSchema as Z, addParticipantSchema as _, taskListQuerySchema as _t, AGENT_STATUSES as a, runtimeStateMessageSchema as at, agentBindRequestSchema as b, updateAgentSchema as bt, DEFAULT_RUNTIME_PROVIDER as c, selfServiceFeishuBotSchema as ct, TASK_CREATOR_TYPES as d, sessionCompletionMessageSchema as dt, messageSourceSchema as et, TASK_HEALTH_SIGNALS as f, sessionEventMessageSchema as ft, addMeChatParticipantsSchema as g, stripCode as gt, WS_AUTH_FRAME_TIMEOUT_MS as h, sessionStateMessageSchema as ht, AGENT_SOURCES as i, refreshTokenSchema as it, createChatSchema as j, createAdapterMappingSchema as k, MENTION_REGEX as l, sendMessageSchema as lt, TASK_TERMINAL_STATUSES as m, sessionReconcileRequestSchema as mt, AGENT_NAME_REGEX as n, paginationQuerySchema as nt, AGENT_TYPES as o, safeRedirectPath as ot, TASK_STATUSES as p, sessionEventSchema as pt, isOrgSettingNamespace as q, AGENT_SELECTOR_HEADER as r, rebindAgentSchema as rt, AGENT_VISIBILITY as s, scanMentionTokens as st, AGENT_BIND_REJECT_REASONS as t, notificationQuerySchema as tt, ORG_SETTINGS_NAMESPACES as u, sendToAgentSchema as ut, adminCreateTaskSchema as v, updateAdapterConfigSchema as vt, clientCapabilitiesSchema as w, updateOrganizationSchema as wt, agentPinnedMessageSchema as x, updateChatSchema as xt, adminUpdateTaskSchema as y, updateAgentRuntimeConfigSchema as yt, extractMentions as z };
1699
+ export { loginSchema as $, createAgentSchema as A, updateTaskStatusSchema as At, githubCallbackQuerySchema as B, agentTypeSchema as C, updateAdapterConfigSchema as Ct, contextTreeSnapshotSchema as D, updateClientCapabilitiesSchema as Dt, connectTokenExchangeSchema as E, updateChatSchema as Et, createTaskSchema as F, inboxDeliverFrameSchema as G, githubStartQuerySchema as H, defaultRuntimeConfigPayload as I, isRedactedEnvValue as J, inboxPollQuerySchema as K, delegateFeishuUserSchema as L, createMeChatSchema as M, createMemberSchema as N, createAdapterConfigSchema as O, updateMemberSchema as Ot, createOrgFromMeSchema as P, listMeChatsQuerySchema as Q, dryRunAgentRuntimeConfigSchema as R, agentRuntimeConfigPayloadSchema as S, taskListQuerySchema as St, clientRegisterSchema as T, updateAgentSchema as Tt, imageInlineContentSchema as U, githubDevCallbackQuerySchema as V, inboxAckFrameSchema as W, joinByInvitationSchema as X, isReservedAgentName as Y, linkTaskChatSchema as Z, addParticipantSchema as _, sessionEventSchema as _t, AGENT_STATUSES as a, questionAnswerMessageContentSchema as at, agentBindRequestSchema as b, stripCode as bt, DEFAULT_RUNTIME_PROVIDER as c, refreshTokenSchema as ct, TASK_CREATOR_TYPES as d, scanMentionTokens as dt, messageSourceSchema as et, TASK_HEALTH_SIGNALS as f, selfServiceFeishuBotSchema as ft, addMeChatParticipantsSchema as g, sessionEventMessageSchema as gt, WS_AUTH_FRAME_TIMEOUT_MS as h, sessionCompletionMessageSchema as ht, AGENT_SOURCES as i, patchOnboardingSchema as it, createChatSchema as j, wsAuthFrameSchema as jt, createAdapterMappingSchema as k, updateOrganizationSchema as kt, MENTION_REGEX as l, runtimeStateMessageSchema as lt, TASK_TERMINAL_STATUSES as m, sendToAgentSchema as mt, AGENT_NAME_REGEX as n, onboardingEventSchema as nt, AGENT_TYPES as o, questionMessageContentSchema as ot, TASK_STATUSES as p, sendMessageSchema as pt, isOrgSettingNamespace as q, AGENT_SELECTOR_HEADER as r, paginationQuerySchema as rt, AGENT_VISIBILITY as s, rebindAgentSchema as st, AGENT_BIND_REJECT_REASONS as t, notificationQuerySchema as tt, ORG_SETTINGS_NAMESPACES as u, safeRedirectPath as ut, adminCreateTaskSchema as v, sessionReconcileRequestSchema as vt, clientCapabilitiesSchema as w, updateAgentRuntimeConfigSchema as wt, agentPinnedMessageSchema as x, submitQuestionAnswerSchema as xt, adminUpdateTaskSchema as y, sessionStateMessageSchema as yt, extractMentions as z };
@@ -0,0 +1,13 @@
1
+ -- Onboarding stepper dismissal flag. Decoupled from the server-side
2
+ -- `onboardingStep` enum so the stepper keeps rendering across all three
3
+ -- UI steps (server-side onboardingStep flips to `completed` at the end of
4
+ -- Step 2; Step 3 is purely client-driven and the stepper must keep
5
+ -- showing during the tree-init chat).
6
+ --
7
+ -- See docs/new-user-onboarding-design.md §8.
8
+ --
9
+ -- NULL → stepper renders
10
+ -- value → user clicked the `✕`; stepper unmounts. Irreversible from UI v1.
11
+
12
+ ALTER TABLE "users"
13
+ ADD COLUMN IF NOT EXISTS "onboarding_dismissed_at" timestamp with time zone;