{"version":3,"file":"index.mjs","names":["sanitize","markdownToMarkup","sanitize","tools","tools","tools","tools","tools","tools","tools","tools","tools","tools","tools","tools","tools","tools","tools","tools","tools","tools","tools","tools","workspaceTools","projectTools","milestoneTools","taskMgmtTools","componentTools","spaceTools","snapshotTools","labelTools","tagTools","tagCategoryTools","commentTools","searchTools","deletionTools","timeTools","contactTools","documentTools","issueCoreTools","issueRelationTools","issueTemplateTools","attachmentTools","todoTools","sanitize"],"sources":["../src/version.ts","../src/config/credentials.ts","../src/config/config.ts","../src/client/errors.ts","../src/client/console-filter.ts","../src/client/client.ts","../src/client/pool.ts","../src/config/resolver.ts","../src/tools/confirm.ts","../src/tools/builder.ts","../src/tools/domains/_class-refs.ts","../src/tools/domains/_common.ts","../src/tools/domains/workspace.ts","../src/tools/domains/projects.ts","../src/tools/domains/milestones.ts","../src/tools/domains/task-management.ts","../src/tools/domains/contacts.ts","../src/tools/domains/components.ts","../src/tools/domains/spaces.ts","../src/tools/domains/document-snapshots.ts","../src/tools/domains/labels.ts","../src/tools/domains/tags.ts","../src/tools/domains/tag-categories.ts","../src/markup/markup.ts","../src/tools/domains/comments.ts","../src/tools/domains/search.ts","../src/tools/domains/deletion.ts","../src/tools/domains/time.ts","../src/tools/domains/documents.ts","../src/tools/domains/issues-hierarchy.ts","../src/tools/domains/issues-core.ts","../src/tools/domains/issues-relations.ts","../src/tools/domains/issues-templates.ts","../src/tools/domains/attachments.ts","../src/tools/domains/todos.ts","../src/tools/register.ts","../src/commands/huly.ts","../src/render/util.ts","../src/render/issue.ts","../src/render/document.ts","../src/index.ts"],"sourcesContent":["// version.ts — pi-huly version constant (single source).\n// Tách riêng khỏi index.ts để tránh circular import:\n//   index.ts (factory) ↔ commands/huly.ts (import HULY_VERSION cho /huly status).\n// Cả 2 import từ đây → KHÔNG cycle. Bump version tại đây duy nhất.\n\nexport const HULY_VERSION = \"1.0.0-beta.5\";\n","// CredentialStore — secret credentials per-workspace (global-only).\n// Design: 04-system.md §6, 01-vision.md §B.8 D8, 08-non-functional.md §A.\n//\n// Auth union: mỗi workspace entry {url, workspace} + ({token} XOR {email,password}).\n// `workspace` BẮT BUỘC (Huly workspace name truyền cho api-client connect/connectRest).\n// Same-name diff-URL → id distinct (vd `corp-prod`), `workspace` giữ tên Huly thật.\n//\n// Security (08 §A):\n// - chmod 600 verify on load (reject loose perms — Spoofing mitigation)\n// - atomic write (temp + rename — Tampering mitigation)\n// - schema validate on load + reject malformed\n// - KHÔNG log token/password values\n\nimport { existsSync } from \"node:fs\";\nimport { readFile, rename, stat, writeFile, mkdir, chmod } from \"node:fs/promises\";\nimport { homedir } from \"node:os\";\nimport { dirname, join } from \"node:path\";\n\n// Types\n\n/** Auth union: token OR email+password (XOR — không cả 2, không thiếu). */\nexport type AuthMethod = { token: string } | { email: string; password: string };\n\n/** Workspace credentials entry. `workspace` BẮT BUỘC. */\nexport type WorkspaceCreds = {\n  url: string;\n  workspace: string;\n} & AuthMethod;\n\n/** Credentials.json root shape. */\nexport type Credentials = {\n  version: 1;\n  workspaces: Record<string, WorkspaceCreds>;\n};\n\n/** Path tới credentials.json (global-only, ~/.pi/agent/huly/). */\nexport const CREDENTIALS_DIR = join(homedir(), \".pi\", \"agent\", \"huly\");\nexport const CREDENTIALS_PATH = join(CREDENTIALS_DIR, \"credentials.json\");\n\n/** File mode cho credentials.json (rw owner only — 08 §A Spoofing mitigation). */\nconst SECURE_MODE = 0o600;\n\n/**\n * Validate workspace entry schema: required fields + auth union XOR.\n * Throws error với field name (KHÔNG leak value).\n */\nfunction validateWorkspace(id: string, entry: unknown): asserts entry is WorkspaceCreds {\n  if (typeof entry !== \"object\" || entry === null) {\n    throw new Error(`credentials.json schema invalid: workspace \"${id}\" must be an object`);\n  }\n  const e = entry as Record<string, unknown>;\n  if (typeof e.url !== \"string\" || e.url.length === 0) {\n    throw new Error(`credentials.json schema invalid: workspace \"${id}\" — url required`);\n  }\n  if (typeof e.workspace !== \"string\" || e.workspace.length === 0) {\n    throw new Error(`credentials.json schema invalid: workspace \"${id}\" — workspace required`);\n  }\n  const hasToken = typeof e.token === \"string\" && e.token.length > 0;\n  const hasEmail = typeof e.email === \"string\" && e.email.length > 0;\n  const hasPassword = typeof e.password === \"string\" && e.password.length > 0;\n  const hasEmailPass = hasEmail && hasPassword;\n  const hasAnyAuthField = hasToken || hasEmail || hasPassword;\n  // XOR: exactly one complete auth method, NO extra fields (mirror TS union).\n  // Reject cases:\n  // - BOTH complete methods (token + email+password)\n  // - partial email/password (one without the other) — field leak prevention\n  // - token + any email/password field — extra field alongside valid token\n  // - NEITHER method\n  if (hasToken && hasEmailPass) {\n    throw new Error(\n      `credentials.json auth union XOR violated: workspace \"${id}\" has BOTH token and email+password`,\n    );\n  }\n  if (hasToken && (hasEmail || hasPassword)) {\n    throw new Error(\n      `credentials.json auth union XOR violated: workspace \"${id}\" has token alongside partial email/password fields`,\n    );\n  }\n  if (!hasToken && !hasEmailPass) {\n    if (hasAnyAuthField) {\n      throw new Error(\n        `credentials.json auth union XOR violated: workspace \"${id}\" has partial email/password (both required if either present)`,\n      );\n    }\n    throw new Error(\n      `credentials.json auth union XOR violated: workspace \"${id}\" has NEITHER token nor email+password`,\n    );\n  }\n}\n\n/**\n * Verify file permissions secure (mode === 0o600, owner-only).\n * Windows skip (NTFS khác, ACL-based).\n */\nasync function verifySecureMode(filePath: string, st: { mode: number }): Promise<void> {\n  if (process.platform === \"win32\") return;\n  // Mask chỉ permission bits (lower 12 bits includes file type — chỉ lấy 9 bits permission).\n  const permBits = st.mode & 0o777;\n  if (permBits !== SECURE_MODE) {\n    throw new Error(\n      `credentials.json permissions too open (mode ${permBits.toString(8)}, expected 600)`,\n    );\n  }\n}\n\n/**\n * Load credentials từ file (global path mặc định, hoặc path override cho test).\n * - File không tồn tại → trả empty Credentials (KHÔNG throw)\n * - File loose perms → throw (08 §A)\n * - File malformed JSON → throw\n * - File schema invalid → throw\n */\nexport async function loadCredentials(filePath: string = CREDENTIALS_PATH): Promise<Credentials> {\n  if (!existsSync(filePath)) {\n    return { version: 1, workspaces: {} };\n  }\n  const st = await stat(filePath);\n  await verifySecureMode(filePath, st);\n  let raw: string;\n  try {\n    raw = await readFile(filePath, \"utf8\");\n  } catch (e) {\n    throw new Error(`credentials.json read failed: ${(e as Error).message}`);\n  }\n  let parsed: unknown;\n  try {\n    parsed = JSON.parse(raw);\n  } catch (e) {\n    throw new Error(`credentials.json malformed JSON: ${(e as Error).message}`);\n  }\n  if (typeof parsed !== \"object\" || parsed === null) {\n    throw new Error(\"credentials.json schema invalid: root must be an object\");\n  }\n  const root = parsed as Record<string, unknown>;\n  if (root.version !== 1) {\n    throw new Error(`credentials.json schema invalid: version must be 1 (got ${root.version})`);\n  }\n  if (typeof root.workspaces !== \"object\" || root.workspaces === null) {\n    throw new Error(\"credentials.json schema invalid: workspaces must be an object\");\n  }\n  const workspaces = root.workspaces as Record<string, unknown>;\n  // Validate mỗi entry\n  for (const [id, entry] of Object.entries(workspaces)) {\n    validateWorkspace(id, entry);\n  }\n  return { version: 1, workspaces: workspaces as Record<string, WorkspaceCreds> };\n}\n\n/**\n * Save credentials to file atomic + chmod 600.\n * Atomic: write to temp file (same dir → same volume) + rename.\n * Tighten perms: chmod 600 sau write (cover existing file với loose perms).\n */\nexport async function saveCredentials(\n  creds: Credentials,\n  filePath: string = CREDENTIALS_PATH,\n): Promise<void> {\n  // Validate all entries trước khi write (fail fast — KHÔNG write malformed)\n  for (const [id, entry] of Object.entries(creds.workspaces)) {\n    validateWorkspace(id, entry);\n  }\n  const dir = dirname(filePath);\n  await mkdir(dir, { recursive: true });\n  const json = `${JSON.stringify(creds, null, 2)}\\n`;\n  // Atomic: temp file cùng dir (same volume) + rename\n  const tmpPath = join(dir, `.credentials.json.tmp.${process.pid}`);\n  await writeFile(tmpPath, json, \"utf8\");\n  await chmod(tmpPath, SECURE_MODE);\n  await rename(tmpPath, filePath);\n}\n\n/**\n * Add/update workspace entry (upsert). `id` default = workspace name.\n * Mutates file: load → upsert → save atomic.\n */\nexport async function addWorkspace(\n  id: string | undefined,\n  entry: WorkspaceCreds,\n  filePath: string = CREDENTIALS_PATH,\n): Promise<void> {\n  const resolvedId = id ?? entry.workspace;\n  // Validate entry trước (throws nếu invalid — KHÔNG touch file)\n  validateWorkspace(resolvedId, entry);\n  const creds = await loadCredentials(filePath);\n  creds.workspaces[resolvedId] = entry;\n  await saveCredentials(creds, filePath);\n}\n\n/**\n * Remove workspace entry by id. No-op nếu id không tồn tại.\n * KHÔNG delete file khi empty (giữ file để loadCredentials không recreate).\n */\nexport async function removeWorkspace(\n  id: string,\n  filePath: string = CREDENTIALS_PATH,\n): Promise<void> {\n  const creds = await loadCredentials(filePath);\n  if (!(id in creds.workspaces)) return;\n  delete creds.workspaces[id];\n  await saveCredentials(creds, filePath);\n}\n\n/**\n * Lookup workspace by id handle. Returns undefined nếu không tồn tại.\n */\nexport async function getWorkspace(\n  id: string,\n  filePath: string = CREDENTIALS_PATH,\n): Promise<WorkspaceCreds | undefined> {\n  const creds = await loadCredentials(filePath);\n  return creds.workspaces[id];\n}\n\n/**\n * Find workspaces by Huly workspace name. Returns Array (có thể empty).\n * Same-name diff-URL → multiple results (disambiguate per D8).\n */\nexport async function findByName(\n  name: string,\n  filePath: string = CREDENTIALS_PATH,\n): Promise<Array<WorkspaceCreds & { id: string }>> {\n  const creds = await loadCredentials(filePath);\n  return Object.entries(creds.workspaces)\n    .filter(([, entry]) => entry.workspace === name)\n    .map(([id, entry]) => ({ id, ...entry }));\n}\n","// ConfigStore — non-secret config global (transport toggle + cwd project binding).\n// Design: 04-system.md §6, 01-vision.md §B.3 D3 (transport), §B.8 D8 (config.json format).\n//\n// transport = global toggle: 'ws' (default, connect persistent + pool) | 'rest' (stateless).\n// projects = cwd (longest-prefix) → {workspace id-handle, project}.\n//\n// KHÔNG chmod 600 (non-secret, default perms OK — khác credentials.json).\n\nimport { existsSync } from \"node:fs\";\nimport { readFile, writeFile, mkdir, rename, rm } from \"node:fs/promises\";\nimport { homedir } from \"node:os\";\nimport { dirname, join, resolve, sep } from \"node:path\";\n\n// Types\n\n/** Transport global toggle (D3). */\nexport type Transport = \"ws\" | \"rest\";\n\n/** Project binding entry: cwd → {workspace id-handle, project}. */\nexport type ProjectBinding = {\n  workspace: string;\n  project: string;\n};\n\n/** config.json root shape. */\nexport type Config = {\n  version: 1;\n  /** Transport global toggle. Default 'ws' (D3). */\n  transport?: Transport;\n  /** cwd → binding map. Key = absolute path (normalized). */\n  projects: Record<string, ProjectBinding>;\n  /** Connection pool config (ws only). */\n  pool?: { maxSize?: number };\n  /**\n   * T-62 #67: Filter upstream console spam (no document found + WS error spam).\n   * Default `true` — gate `console.warn/error/log` của @hcengineering trong scope\n   * connect/warmPool. Set `false` để debug thật (xem upstream output nguyên bản).\n   */\n  quietUpstreamNoise?: boolean;\n  /**\n   * T-62 #67: Override default pattern registry. Mỗi entry là RegExp source\n   * string (case-insensitive). Match first-arg string HOẶC structured log có\n   * field `message`. Mặc định: [`/^no document found, failed to apply model transaction/i`].\n   *\n   * Empty array (`[]`) = no-op → fall về DEFAULT_UPSTREAM_NOISE_PATTERNS (KHÔNG\n   * disable filter). Để disable filter hoàn toàn, dùng `quietUpstreamNoise: false`.\n   */\n  upstreamNoisePatterns?: string[];\n};\n\n/** Path tới config.json (global-only, ~/.pi/agent/huly/). */\nexport const CONFIG_DIR = join(homedir(), \".pi\", \"agent\", \"huly\");\nexport const CONFIG_PATH = join(CONFIG_DIR, \"config.json\");\n\n/** Default config khi file không tồn tại hoặc thiếu transport field. */\nexport const DEFAULT_CONFIG: Config = {\n  version: 1,\n  transport: \"ws\",\n  projects: {},\n};\n\n/**\n * Normalize path: resolve `.`, `..`, expand `~`, strip trailing separator (except root).\n * Cross-platform qua path.resolve (auto platform separator).\n */\nexport function normalizePath(p: string): string {\n  let expanded = p;\n  if (expanded.startsWith(\"~\")) {\n    expanded = join(homedir(), expanded.slice(1));\n  }\n  const resolved = resolve(expanded);\n  // Strip trailing separator except root (vd '/a/b/' → '/a/b', '/' giữ '/')\n  if (resolved.length > 1 && resolved.endsWith(sep)) {\n    return resolved.slice(0, -1);\n  }\n  return resolved;\n}\n\n/**\n * Load config từ file (global path mặc định, hoặc path override cho test).\n * - File không tồn tại → return DEFAULT_CONFIG\n * - File malformed/schema invalid → throw\n * - transport thiếu → default 'ws'\n */\nexport async function loadConfig(filePath: string = CONFIG_PATH): Promise<Config> {\n  if (!existsSync(filePath)) {\n    return { ...DEFAULT_CONFIG, projects: {} };\n  }\n  let raw: string;\n  try {\n    raw = await readFile(filePath, \"utf8\");\n  } catch (e) {\n    throw new Error(`config.json read failed: ${(e as Error).message}`);\n  }\n  let parsed: unknown;\n  try {\n    parsed = JSON.parse(raw);\n  } catch (e) {\n    throw new Error(`config.json malformed JSON: ${(e as Error).message}`);\n  }\n  return validateConfig(parsed);\n}\n\n/** Validate + normalize parsed config object. */\nfunction validateConfig(parsed: unknown): Config {\n  if (typeof parsed !== \"object\" || parsed === null) {\n    throw new Error(\"config.json schema invalid: root must be an object\");\n  }\n  const root = parsed as Record<string, unknown>;\n  if (root.version !== 1) {\n    throw new Error(`config.json schema invalid: version must be 1 (got ${root.version})`);\n  }\n  // transport optional, default 'ws'\n  let transport: Transport | undefined;\n  if (root.transport !== undefined) {\n    if (root.transport !== \"ws\" && root.transport !== \"rest\") {\n      throw new Error(\n        `config.json schema invalid: transport must be 'ws' or 'rest' (got ${root.transport})`,\n      );\n    }\n    transport = root.transport;\n  }\n  if (typeof root.projects !== \"object\" || root.projects === null) {\n    throw new Error(\"config.json schema invalid: projects must be an object\");\n  }\n  const projects = root.projects as Record<string, unknown>;\n  const normalizedProjects: Record<string, ProjectBinding> = {};\n  for (const [cwd, binding] of Object.entries(projects)) {\n    if (typeof binding !== \"object\" || binding === null) {\n      throw new Error(`config.json schema invalid: projects[\"${cwd}\"] must be an object`);\n    }\n    const b = binding as Record<string, unknown>;\n    if (typeof b.workspace !== \"string\" || b.workspace.length === 0) {\n      throw new Error(`config.json schema invalid: projects[\"${cwd}\"].workspace required`);\n    }\n    if (typeof b.project !== \"string\" || b.project.length === 0) {\n      throw new Error(`config.json schema invalid: projects[\"${cwd}\"].project required`);\n    }\n    normalizedProjects[normalizePath(cwd)] = { workspace: b.workspace, project: b.project };\n  }\n  let pool: { maxSize?: number } | undefined;\n  if (root.pool !== undefined) {\n    if (typeof root.pool !== \"object\" || root.pool === null) {\n      throw new Error(\"config.json schema invalid: pool must be an object\");\n    }\n    const p = root.pool as Record<string, unknown>;\n    if (p.maxSize !== undefined) {\n      if (typeof p.maxSize !== \"number\" || p.maxSize < 1) {\n        throw new Error(\"config.json schema invalid: pool.maxSize must be positive number\");\n      }\n      pool = { maxSize: p.maxSize };\n    }\n  }\n  // T-62 #67: quietUpstreamNoise (boolean, default true) + upstreamNoisePatterns\n  // (string[] — RegExp source, case-insensitive).\n  let quietUpstreamNoise: boolean | undefined;\n  if (root.quietUpstreamNoise !== undefined) {\n    if (typeof root.quietUpstreamNoise !== \"boolean\") {\n      throw new Error(\n        \"config.json schema invalid: quietUpstreamNoise must be boolean (got \" +\n          `${typeof root.quietUpstreamNoise})`,\n      );\n    }\n    quietUpstreamNoise = root.quietUpstreamNoise;\n  }\n  let upstreamNoisePatterns: string[] | undefined;\n  if (root.upstreamNoisePatterns !== undefined) {\n    if (!Array.isArray(root.upstreamNoisePatterns)) {\n      throw new Error(\"config.json schema invalid: upstreamNoisePatterns must be array\");\n    }\n    for (const [i, p] of root.upstreamNoisePatterns.entries()) {\n      if (typeof p !== \"string\") {\n        throw new Error(`config.json schema invalid: upstreamNoisePatterns[${i}] must be string`);\n      }\n      // Validate RegExp compilable — KHÔNG crash sau load.\n      try {\n        new RegExp(p, \"i\");\n      } catch (e) {\n        throw new Error(\n          `config.json schema invalid: upstreamNoisePatterns[${i}] not valid RegExp: ` +\n            `${(e as Error).message}`,\n        );\n      }\n    }\n    upstreamNoisePatterns = root.upstreamNoisePatterns;\n  }\n  return {\n    version: 1,\n    transport: transport ?? \"ws\",\n    projects: normalizedProjects,\n    ...(pool !== undefined ? { pool } : {}),\n    ...(quietUpstreamNoise !== undefined ? { quietUpstreamNoise } : {}),\n    ...(upstreamNoisePatterns !== undefined ? { upstreamNoisePatterns } : {}),\n  };\n}\n\n/**\n * Save config atomic (temp + rename). KHÔNG chmod (non-secret).\n */\nexport async function saveConfig(config: Config, filePath: string = CONFIG_PATH): Promise<void> {\n  if (config.version !== 1) {\n    throw new Error(`config.json schema invalid: version must be 1 (got ${config.version})`);\n  }\n  if (config.transport !== undefined && config.transport !== \"ws\" && config.transport !== \"rest\") {\n    throw new Error(`config.json schema invalid: transport must be 'ws' or 'rest'`);\n  }\n  const dir = dirname(filePath);\n  await mkdir(dir, { recursive: true });\n  const json = `${JSON.stringify(config, null, 2)}\\n`;\n  const tmpPath = join(dir, `.config.json.tmp.${process.pid}`);\n  await writeFile(tmpPath, json, \"utf8\");\n  try {\n    await rename(tmpPath, filePath);\n  } catch (e) {\n    // Cleanup temp file nếu rename fail (cross-device, permission) — tránh leak\n    await rm(tmpPath, { force: true });\n    throw e;\n  }\n}\n\n/**\n * Bind cwd → {workspace, project} (upsert).\n */\nexport async function bindProject(\n  cwd: string,\n  binding: ProjectBinding,\n  filePath: string = CONFIG_PATH,\n): Promise<void> {\n  if (typeof binding.workspace !== \"string\" || binding.workspace.length === 0) {\n    throw new Error(\"bindProject: workspace required\");\n  }\n  if (typeof binding.project !== \"string\" || binding.project.length === 0) {\n    throw new Error(\"bindProject: project required\");\n  }\n  const config = await loadConfig(filePath);\n  config.projects[normalizePath(cwd)] = binding;\n  await saveConfig(config, filePath);\n}\n\n/**\n * Unbind cwd. No-op nếu cwd không tồn tại.\n */\nexport async function unbindProject(cwd: string, filePath: string = CONFIG_PATH): Promise<void> {\n  const config = await loadConfig(filePath);\n  const normalized = normalizePath(cwd);\n  if (!(normalized in config.projects)) return;\n  delete config.projects[normalized];\n  await saveConfig(config, filePath);\n}\n\n/**\n * Resolve cwd → binding via longest-prefix match.\n * - Sort binding paths by segment count desc\n * - Return first binding where cwd starts with binding path (segment-aligned)\n * - No match → undefined\n *\n * Segment-aligned: `/a/b` match `/a/b/c` (ok) nhưng KHÔNG match `/a/bcd` (khác segment).\n */\nexport async function resolveByCwd(\n  cwd: string,\n  filePath: string = CONFIG_PATH,\n): Promise<ProjectBinding | undefined> {\n  const config = await loadConfig(filePath);\n  const normalizedCwd = normalizePath(cwd);\n  const bindings = Object.entries(config.projects);\n  if (bindings.length === 0) return undefined;\n  // Sort by path depth desc (longest first)\n  bindings.sort((a, b) => pathDepth(b[0]) - pathDepth(a[0]));\n  for (const [bindingPath, binding] of bindings) {\n    if (isPathPrefix(bindingPath, normalizedCwd)) {\n      return binding;\n    }\n  }\n  return undefined;\n}\n\n/** Count path segments (vd '/a/b/c' = 3, '/' = 0). */\nfunction pathDepth(p: string): number {\n  if (p === \"/\" || p === \"\") return 0;\n  return p.split(sep).filter(Boolean).length;\n}\n\n/**\n * Check if `prefix` is a segment-aligned prefix of `path`.\n * - '/a/b' prefix of '/a/b/c' → true\n * - '/a/b' prefix of '/a/b' → true (exact)\n * - '/a/b' prefix of '/a/bcd' → false (segment mismatch)\n * - '/' prefix of anything → true\n */\nfunction isPathPrefix(prefix: string, path: string): boolean {\n  if (prefix === \"/\" || prefix === \"\") return true;\n  if (prefix === path) return true;\n  // path must start with prefix + separator\n  return path.startsWith(prefix + sep);\n}\n","// HulyError taxonomy — classify api-client/PlatformError + network errors.\n// Design: 04-system.md §3 (taxonomy) + §6 (client/errors.ts contract), 08 §A (no-leak NFR-04).\n//\n// PlatformError (from @hcengineering/platform, re-exported via api-client) has shape:\n//   class PlatformError extends Error { readonly status: { severity, code, params } }\n// where `status.code` is a branded IntlString like 'platform:status:Unauthorized'.\n//\n// mapError uses DUCK-TYPING (no direct @hcengineering import) to avoid coupling:\n//   - `e instanceof Error && 'status' in e` → treat as PlatformError, classify via status.code\n//   - network patterns (ECONN*/fetch failed/WebSocket) → ConnectionError\n//   - else → InternalError\n//\n// Security (08 §A): toToolResult strips token/password/stack — KHÔNG leak secrets.\n\n/**\n * Error class identifier (04 §3 taxonomy, 8 classes).\n * T-57 #61: thêm \"Unavailable\" — class ref sai runtime (domain not found),\n * distinct khỏi NotFound (entity không tồn tại) và Internal (bug pi-huly).\n */\nexport type ErrorClass =\n  | \"Auth\"\n  | \"Connection\"\n  | \"NotFound\"\n  | \"Conflict\"\n  | \"Validation\"\n  | \"Internal\"\n  | \"External\"\n  | \"Unavailable\";\n\n/** Base HulyError — all 7 subclasses extend this. */\nexport class HulyError extends Error {\n  readonly class: ErrorClass;\n  override readonly cause?: unknown;\n\n  constructor(errorClass: ErrorClass, message: string, cause?: unknown) {\n    super(message);\n    this.name = `${errorClass}Error`;\n    this.class = errorClass;\n    if (cause !== undefined) {\n      this.cause = cause;\n    }\n  }\n}\n\nexport class AuthError extends HulyError {\n  constructor(message: string, cause?: unknown) {\n    super(\"Auth\", message, cause);\n  }\n}\n\nexport class ConnectionError extends HulyError {\n  constructor(message: string, cause?: unknown) {\n    super(\"Connection\", message, cause);\n  }\n}\n\nexport class NotFoundError extends HulyError {\n  constructor(message: string, cause?: unknown) {\n    super(\"NotFound\", message, cause);\n  }\n}\n\nexport class ConflictError extends HulyError {\n  constructor(message: string, cause?: unknown) {\n    super(\"Conflict\", message, cause);\n  }\n}\n\nexport class ValidationError extends HulyError {\n  constructor(message: string, cause?: unknown) {\n    super(\"Validation\", message, cause);\n  }\n}\n\nexport class InternalError extends HulyError {\n  constructor(message: string, cause?: unknown) {\n    super(\"Internal\", message, cause);\n  }\n}\n\nexport class ExternalError extends HulyError {\n  constructor(message: string, cause?: unknown) {\n    super(\"External\", message, cause);\n  }\n}\n\n/**\n * T-57 #61: Class ref sai runtime (domain not found) — distinct từ NotFound/\n * Internal. Khi Huly throw \"domain not found: <class>\", class đích KHÔNG tồn\n * tại trong workspace (package chưa enable HOẶC pi-huly dùng sai class ref).\n * Tool không chạy được → báo honest cho LLM thay vì generic InternalError.\n */\nexport class UnavailableError extends HulyError {\n  /** Class ref bị reject (vd \"tracker:class:Document\"). */\n  readonly hulyClass?: string;\n  constructor(message: string, cause?: unknown, hulyClass?: string) {\n    super(\"Unavailable\", message, cause);\n    if (hulyClass !== undefined) {\n      this.hulyClass = hulyClass;\n    }\n  }\n}\n\n// PlatformError duck-type shape (matches @hcengineering/platform PlatformError).\ntype IntlStringObj = { _id?: string; default?: string; key?: string; value?: string };\ntype StatusLike = {\n  severity: string;\n  code: string | IntlStringObj;\n  params?: Record<string, unknown>;\n};\n\ntype PlatformErrorLike = Error & {\n  status?: StatusLike;\n};\n\n/** Extract string code from status.code (handles branded IntlString shape). */\nfunction statusCode(code: StatusLike[\"code\"]): string {\n  if (typeof code === \"string\") return code;\n  if (code && typeof code === \"object\") {\n    return code._id ?? code.default ?? code.key ?? code.value ?? \"\";\n  }\n  return \"\";\n}\n\n/** Check if error looks like a PlatformError (duck-type, no instanceof). */\nfunction isPlatformError(e: unknown): e is PlatformErrorLike {\n  return e instanceof Error && \"status\" in e && typeof e.status === \"object\";\n}\n\n/** Network error patterns (raw Error, NOT PlatformError). */\nconst NETWORK_PATTERNS = [\n  /ECONNREFUSED/i,\n  /ECONNRESET/i,\n  /ETIMEDOUT/i,\n  /ENOTFOUND/i,\n  /EAI_AGAIN/i,\n  /EHOSTUNREACH/i,\n  /ENETUNREACH/i,\n  /fetch\\s*failed/i,\n  /WebSocket/i,\n  /abnormal\\s*closure/i,\n  /socket\\s*hang\\s*up/i,\n  /network/i,\n];\n\n/** Classify PlatformError status.code → HulyError subclass. */\nfunction classifyPlatformError(e: PlatformErrorLike): HulyError {\n  const status = e.status!;\n  const code = statusCode(status.code);\n  const params = status.params ?? {};\n\n  // Auth: Unauthorized, TokenExpired, TokenNotActive, PasswordExpired,\n  //       WorkspaceNotFound, PasswordLoginLocked, InvalidPassword,\n  //       AccountNotConfirmed, SocialIdNotConfirmed, Forbidden, ReadOnlyAccount\n  if (\n    code.includes(\"Unauthorized\") ||\n    code.includes(\"TokenExpired\") ||\n    code.includes(\"TokenNotActive\") ||\n    code.includes(\"PasswordExpired\") ||\n    code.includes(\"WorkspaceNotFound\") ||\n    code.includes(\"PasswordLoginLocked\") ||\n    code.includes(\"InvalidPassword\") ||\n    code.includes(\"AccountNotConfirmed\") ||\n    code.includes(\"SocialIdNotConfirmed\") ||\n    code.includes(\"Forbidden\") ||\n    code.includes(\"ReadOnlyAccount\") ||\n    code.includes(\"AccountNotFound\") ||\n    code.includes(\"AccountMismatch\")\n  ) {\n    const hint = code.includes(\"WorkspaceNotFound\")\n      ? \" Run /huly init to bind.\"\n      : code.includes(\"PasswordLoginLocked\")\n        ? \" Account locked — try again later or re-init.\"\n        : \"\";\n    return new AuthError(`Auth failed: ${code}${hint}`, e);\n  }\n\n  // Connection: ConnectionClosed, MaintenanceWarning, WorkspaceMigration, WorkspaceRateLimit\n  if (\n    code.includes(\"ConnectionClosed\") ||\n    code.includes(\"Maintenance\") ||\n    code.includes(\"Migration\") ||\n    code.includes(\"RateLimit\")\n  ) {\n    return new ConnectionError(`Huly connection issue: ${code}`, e);\n  }\n\n  // Conflict: Conflict, AlreadyExists, AccountAlreadyExists, WorkspaceAlreadyExists\n  if (\n    code.includes(\"Conflict\") ||\n    code.includes(\"AlreadyExists\") ||\n    code.includes(\"IntegrationExists\") ||\n    code.includes(\"SecretAlreadyExists\")\n  ) {\n    return new ConflictError(`Conflict: ${code}`, e);\n  }\n\n  // Validation: BadRequest, InvalidId, ExpiredLink, SocialIdAlreadyConfirmed\n  if (\n    code.includes(\"BadRequest\") ||\n    code.includes(\"InvalidId\") ||\n    code.includes(\"ExpiredLink\") ||\n    code.includes(\"AlreadyConfirmed\")\n  ) {\n    return new ValidationError(`Validation: ${code}`, e);\n  }\n\n  // NotFound: PersonNotFound, InviteNotFound, SecretNotFound, NotFound\n  if (\n    code.includes(\"PersonNotFound\") ||\n    code.includes(\"InviteNotFound\") ||\n    code.includes(\"SecretNotFound\") ||\n    /(^|[:.])NotFound$/.test(code)\n  ) {\n    const id = typeof params.id === \"string\" ? `: ${params.id}` : \"\";\n    return new NotFoundError(`Not found: ${code}${id}`, e);\n  }\n\n  // Internal (fallback): BadError, UnknownError, InternalServerError, UnknownMethod, MailboxError\n  return new InternalError(`Internal: ${code}`, e);\n}\n\n/**\n * T-57 #61: Detect \"domain not found: <class>\" pattern trong error message.\n * Huly throw pattern này khi class ref KHÔNG tồn tại runtime (package chưa\n * enable HOẶC pi-huly dùng sai class ref). Match cả 2 dạng:\n *   - \"domain not found: tracker:class:Document\"\n *   - \"Error: domain not found: core:class:TsRelation\"\n *\n * Trả class ref thật (group 1) hoặc null nếu không match.\n */\n// Capture đến whitespace/EOL (code-review MINOR #5) — defensive nếu Huly thêm\n// class ref có ký tự lạ (vd dash). Trước đây `[\\w:]+` cắt tại ký tự không match.\nconst DOMAIN_NOT_FOUND_RE = /domain\\s+not\\s+found:\\s*(\\S+)/i;\nexport function matchDomainNotFound(message: string): string | null {\n  const m = DOMAIN_NOT_FOUND_RE.exec(message);\n  return m ? m[1] : null;\n}\n\n/**\n * Map any error (PlatformError, network Error, generic) → HulyError subclass.\n * Order:\n *   1. Already HulyError → return as-is\n *   2. PlatformError (duck-type) → classify via status.code\n *   3. Network Error (ECONNREFUSED, fetch failed, WebSocket) → ConnectionError\n *   4. Plain Error 'Workspace not found' → AuthError (run /huly init)\n *   5. ExternalError → unwrap cause, mapError recursive\n *   6. Else → InternalError (wrap)\n *\n * T-57 #61: trước InternalError fallback, check \"domain not found\" pattern\n * (xuất hiện trong cả PlatformError UnknownError + plain Error) → UnavailableError.\n */\nexport function mapError(e: unknown): HulyError {\n  // 0. Already HulyError\n  if (e instanceof HulyError) {\n    // ExternalError → unwrap cause recursively\n    if (e instanceof ExternalError && e.cause !== undefined) {\n      return mapError(e.cause);\n    }\n    return e;\n  }\n\n  // 1. PlatformError (duck-type)\n  if (isPlatformError(e)) {\n    const classified = classifyPlatformError(e);\n    // T-57: PlatformError UnknownError có thể wrap \"domain not found\" trong\n    // raw message (vd createDoc class sai → server throw UnknownError với\n    // message \"domain not found: <class>\"). classifyPlatformError build message\n    // từ status.code (chỉ \"UnknownError\") KHÔNG giữ raw text → check cả 2.\n    if (classified.class === \"Internal\") {\n      const cls = matchDomainNotFound(e.message) ?? matchDomainNotFound(classified.message);\n      if (cls !== null) {\n        return new UnavailableError(buildUnavailableMessage(cls), e, cls);\n      }\n    }\n    return classified;\n  }\n\n  // 2. Plain Error\n  if (e instanceof Error) {\n    const msg = e.message ?? \"\";\n    // Network patterns\n    if (NETWORK_PATTERNS.some((re) => re.test(msg) || re.test(e.name))) {\n      return new ConnectionError(`Huly unreachable: ${msg}`, e);\n    }\n    // T-57 #61: \"domain not found: <class>\" → UnavailableError (trước fallback\n    // generic InternalError — Huly raw error message thường chứa pattern này).\n    const cls = matchDomainNotFound(msg);\n    if (cls !== null) {\n      return new UnavailableError(buildUnavailableMessage(cls), e, cls);\n    }\n    // api-client own: 'Workspace <name> not found'\n    if (/^Workspace\\s+\\S+\\s+not\\s+found/i.test(msg)) {\n      return new AuthError(`Auth failed: ${msg} Run /huly init.`, e);\n    }\n    // Generic — include e.message cho ops debug (sanitize() ở toToolResult strip secret)\n    return new InternalError(`Internal: ${e.name}: ${e.message}`, e);\n  }\n\n  // 3. Non-Error (string, object, null, undefined) → wrap\n  const detail = typeof e === \"string\" ? e : JSON.stringify(e);\n  return new InternalError(`Internal: ${detail}`, e);\n}\n\n/**\n * T-57 #61: Build honest message cho UnavailableError — list possible causes\n * giúp LLM/user debug (package chưa enable / sai class ref / report bug).\n */\nfunction buildUnavailableMessage(cls: string): string {\n  return (\n    `Class \"${cls}\" không khả dụng trong workspace này. ` +\n    `Có thể: (1) workspace chưa enable package chứa class này ` +\n    `(vd Document/Tags feature opt-in); (2) pi-huly dùng sai class ref ` +\n    `(report bug kèm workspace Huly version); (3) class đã bị rename/deprecated ` +\n    `trong phiên bản Huly mới hơn.`\n  );\n}\n\n/**\n * Convert HulyError → pi tool result (04 §6, 08 §A no-leak).\n * Strips: token, password, stack trace, internal _class names.\n * Keeps: error class, sanitized message.\n */\nexport type ToolResult = {\n  content: Array<{ type: \"text\"; text: string }>;\n  isError: true;\n};\n\n/**\n * Patterns to strip from messages (secrets + stack) — 08 §A NFR-04 no-leak.\n * Centralized ở errors.ts để mọi consumer (toToolResult, builder sanitize path)\n * dùng chung single source of truth (tránh drift khi thêm pattern mới).\n */\nexport const LEAK_PATTERNS = [\n  // Generic key=value assignment (token / password / secret / api_key / authorization).\n  /(?:token|password|secret|api[_-]?key|authorization)\\s*[=:]\\s*['\"]?[A-Za-z0-9_.+/ -]{8,}['\"]?/gi,\n  // GitHub tokens (classic PAT, fine-grained, npm)\n  /ghp_[A-Za-z0-9]{36,}/g,\n  /npm_[A-Za-z0-9]{36,}/g,\n  /github_pat_[A-Za-z0-9_]+/g,\n  // Cloud provider access keys: AWS (AKIA...), OpenAI (sk-...)\n  /(?:AKIA|sk-)[A-Za-z0-9]{16,}/g,\n  // JWT (3 dot-separated base64url segments, each ≥10 chars)\n  /eyJ[A-Za-z0-9_-]{10,}\\.[A-Za-z0-9_-]{10,}\\.[A-Za-z0-9_-]{10,}/g,\n  // URL-embedded credentials: https://user:pass@host\n  /https?:\\/\\/[^/\\s@]+:[^/\\s@]+@/gi,\n  // Stack frame: \"at <path>:<line>:<col>\" hoặc V8 \"at fn (file.js:10:5)\"\n  /\\bat\\s+.*?:\\d+:\\d+(?::\\d+)?\\)?/g,\n];\n\n/**\n * Sanitize message — strip secrets + stack traces (08 §A NFR-04).\n * Exported để builder + domain tool reuse (single source of truth cho patterns).\n */\nexport function sanitize(message: string): string {\n  let out = message;\n  for (const re of LEAK_PATTERNS) {\n    out = out.replace(re, \"[REDACTED]\");\n  }\n  return out;\n}\n\nexport function toToolResult(err: HulyError): ToolResult {\n  const errorClass = err.class;\n  const sanitizedMsg = sanitize(err.message);\n  return {\n    content: [\n      {\n        type: \"text\",\n        text: `[${errorClass}Error] ${sanitizedMsg}`,\n      },\n    ],\n    isError: true,\n  };\n}\n","// T-62 #67: Filter framework gate upstream console spam.\n//\n// Upstream `@hcengineering` (core/memdb + core/client buildModel + client-resources\n// connection.js) in ra stderr hàng loạt `console.warn`/`console.error`/`console.log`\n// không seam, break UI pi. Verified KHÔNG có seam inject logger trong upstream\n// `connect()` (`api-client/lib/client.js:42-79` — chỉ nhận socketFactory +\n// connectionTimeout). → Filter ở ranh giới pi-huly.\n//\n// Design:\n// - `UpstreamConsoleFilter` class: install/restore `console.warn`/`.error`/`.log`.\n//   Match argument đầu tiên (string) HOẶC structured log (object có field `message`)\n//   qua danh sách pattern `RegExp[]`. Đếm per-pattern + total.\n// - `runWithConsoleFilter(patterns, fn)`: wrap async block, install → run → restore\n//   (try/finally LUÔN restore — KHÔNG leak override global dù block throw).\n// - `DEFAULT_UPSTREAM_NOISE_PATTERNS`: pattern registry. T-62 ship pattern #67.\n//   T-64 (blocked-by T-62) đăng ký thêm WS error + token leak pattern.\n// - Module-level counter: expose qua pool `health()` → `/huly status` display.\n\n/** Console method names được filter. */\ntype ConsoleMethod = \"warn\" | \"error\" | \"log\";\n\n/** Console method override target — uniform fn signature (warn/error/log interchangeable). */\ntype ConsoleFn = (...args: unknown[]) => void;\nconst CONSOLE_METHODS: readonly ConsoleMethod[] = [\"warn\", \"error\", \"log\"];\n\n/**\n * Đếm số dòng đã filter: total + per-pattern (key = pattern.source).\n * Module-level để pool `health()` aggregate cross filter instance.\n */\ninterface NoiseCounters {\n  total: number;\n  byPattern: Record<string, number>;\n}\n\nconst moduleCounters: NoiseCounters = { total: 0, byPattern: {} };\n\n/**\n * Reset module-level counters. Test-only — pool health KHÔNG reset runtime\n * (counter accumulate qua session lifetime để report cumulative).\n */\nexport function resetUpstreamNoiseCounters(): void {\n  moduleCounters.total = 0;\n  moduleCounters.byPattern = {};\n}\n\n/**\n * Read-only snapshot counters cho pool `health()` expose.\n * Return copy để caller KHÔNG mutate module state.\n */\nexport function getUpstreamNoiseCounters(): NoiseCounters {\n  return {\n    total: moduleCounters.total,\n    byPattern: { ...moduleCounters.byPattern },\n  };\n}\n\n/**\n * Trích first-arg string ra string match-able. Support 2 shape:\n * - first-arg là string → return trực tiếp\n * - first-arg là object có field `message` string → return message (structured log)\n * - KHÁC (number/null/array/...) → return undefined (KHÔNG match — guard)\n */\nfunction extractMessage(firstArg: unknown): string | undefined {\n  if (typeof firstArg === \"string\") return firstArg;\n  // Structured log: object có field `message` string. KHÔNG match Error instance\n  // (Error.message là real error — filter che là sai). Upstream warn dùng plain\n  // object {message: \"...\"} không phải Error throw.\n  if (\n    typeof firstArg === \"object\" &&\n    firstArg !== null &&\n    !Array.isArray(firstArg) &&\n    !(firstArg instanceof Error) &&\n    \"message\" in firstArg &&\n    typeof firstArg.message === \"string\"\n  ) {\n    return firstArg.message;\n  }\n  return undefined;\n}\n\n/**\n * UpstreamConsoleFilter — install/restore console.warn/error/log override.\n *\n * Match first-arg string qua `RegExp[]`. Match → swallow (KHÔNG delegate ra\n * original method) + counter +1 (per-pattern + total). Miss → delegate original\n * (log vẫn ra như cũ).\n */\nexport class UpstreamConsoleFilter {\n  private readonly patterns: RegExp[];\n  private installed = false;\n  private readonly originals: Partial<Record<ConsoleMethod, ConsoleFn>> = {};\n\n  constructor(patterns: RegExp[]) {\n    this.patterns = patterns;\n  }\n\n  /** Install override cho console.warn/error/log. Idempotent (install 2 lần no-op). */\n  install(): void {\n    if (this.installed) return;\n    this.installed = true;\n    for (const method of CONSOLE_METHODS) {\n      this.originals[method] = console[method];\n      // Arrow function giữ `this` + closure pattern. Bind original qua closure\n      // (KHÔNG dùng .bind — giữ call site debug stack chính xác).\n      const original = this.originals[method]!;\n      const patterns = this.patterns;\n      console[method] = (...args: unknown[]) => {\n        const msg = extractMessage(args[0]);\n        if (msg !== undefined) {\n          // First-match-wins: chỉ pattern đầu (theo order trong mảng) match được\n          // count — tránh double-count khi nhiều pattern cùng match 1 message.\n          const matched = patterns.find((p) => p.test(msg));\n          if (matched !== undefined) {\n            // Filter: swallow + counter +1\n            moduleCounters.total += 1;\n            const key = matched.toString();\n            moduleCounters.byPattern[key] = (moduleCounters.byPattern[key] ?? 0) + 1;\n            return;\n          }\n        }\n        // KHÔNG match → delegate original (log ra như cũ)\n        original.apply(console, args);\n      };\n    }\n  }\n\n  /** Restore original console.warn/error/log. Idempotent (restore 2 lần no-op). */\n  restore(): void {\n    if (!this.installed) return;\n    this.installed = false;\n    for (const method of CONSOLE_METHODS) {\n      const original = this.originals[method];\n      if (original !== undefined) {\n        console[method] = original;\n        delete this.originals[method];\n      }\n    }\n  }\n}\n\n/**\n * Wrap async block với console filter active. Install → run → restore (try/finally\n * LUÔN restore — KHÔNG leak override global dù block throw).\n *\n * **Scope hạn chế**: chỉ cover connect-time spam (cache-miss replay khi buildModel).\n * WS error post-connect (wsocket.onerror async callback) KHÔNG cover — dùng\n * `installGlobalConsoleFilter()` cho connection lifetime.\n *\n * @param patterns RegExp[] match first-arg string (hoặc object.message)\n * @param fn async block (vd quanh connect() / warmPool)\n * @returns giá trị fn trả về\n */\nexport async function runWithConsoleFilter<T>(\n  patterns: RegExp[],\n  fn: () => Promise<T>,\n): Promise<T> {\n  const filter = new UpstreamConsoleFilter(patterns);\n  filter.install();\n  try {\n    return await fn();\n  } finally {\n    filter.restore();\n  }\n}\n\n/**\n * T-64 #69: Global console filter — install 1 lần, active toàn session lifetime\n * (KHÔNG restore). Cần thiết vì WS error (`wsocket.onerror` async callback trong\n * `client-resources/lib/connection.js:554`) fires **post-connect** — `runWithConsoleFilter`\n * chỉ cover connect-time, restore `console.error` trước khi WS error thật sự fire.\n *\n * Token leak (URL `_transactor/<token>`) chỉ gate được nếu filter active khi WS\n * error fire (bất kỳ lúc nào post-connect: reconnect, server down, network blip).\n *\n * Install idempotent — gọi 2 lần no-op (return false nếu đã active).\n *\n * @param patterns RegExp[] match first-arg string (hoặc object.message)\n * @returns true nếu install mới, false nếu đã active (no-op)\n */\nlet globalFilterInstalled = false;\nlet globalFilter: UpstreamConsoleFilter | null = null;\n\nexport function installGlobalConsoleFilter(patterns: RegExp[]): boolean {\n  if (globalFilterInstalled) return false;\n  globalFilter = new UpstreamConsoleFilter(patterns);\n  globalFilter.install();\n  globalFilterInstalled = true;\n  return true;\n}\n\n/**\n * Restore global filter (test-only — production KHÔNG gọi, filter active toàn session).\n */\nexport function __resetGlobalFilterForTests(): void {\n  if (globalFilter !== null) {\n    globalFilter.restore();\n    globalFilter = null;\n  }\n  globalFilterInstalled = false;\n}\n\n/**\n * Default upstream noise pattern registry.\n *\n * T-62 ship #67 (cache-miss warn). T-64 (#69) đăng ký thêm WS error spam +\n * token leak + 7 dòng spam khác trong `client-resources/lib/connection.js`.\n *\n * Pattern match FIRST-arg string (case-insensitive). KHÔNG match log khác\n * (vd pi-huly tool call log `[huly_list_issues] args: ...`) — guard test có sẵn.\n *\n * **KHÔNG filter Error instance** (dòng `console.error(new Error(...))` ở\n * connection.js:329 `unknown response id` + 488/496/510/518 decompress error):\n * Error.message là real error cần debug. Filter chỉ apply cho plain string /\n * structured log {message}. Decision documented CHANGELOG.\n */\nexport const DEFAULT_UPSTREAM_NOISE_PATTERNS: RegExp[] = [\n  // #67 (T-62): cache-miss warn khi replay TxUpdateDoc/TxRemoveDoc/TxMixin cho\n  // doc không có trong local model. Vô hại (doc đã expire/removed trên server).\n  /^no document found, failed to apply model transaction/i,\n  // #69 (T-64): WS error spam + token leak. Upstream connection.js:554 in ra\n  // `client websocket error: <id> wss://.../_transactor/<token> <ws> <user>`\n  // mỗi lần WS gặp error (reconnect backoff). URL chứa api-token → NFR-04\n  // violation nếu log ra stderr/UI. Filter swallow toàn bộ (KHÔNG redact).\n  /^client websocket error/i,\n  // #69 (T-64): 6 dòng spam khác trong connection.js — session info, ping,\n  // version, upgrade, perf warning. Vô hại, break UI pi.\n  /^Generate new SessionId/i,\n  /^no ping response from server/i,\n  /^Connected to server/i,\n  /^Processing upgrade/i,\n  /^measure slow findAll/i,\n];\n","// HulyClient — thin wrapper @hcengineering/api-client (ws + rest).\n// Design: 04-system.md §6 (reconciled T-05 với api-client@0.7.423 real API).\n//\n// Transport toggle (D3):\n//   ws   = connect() persistent + full CRUD via PlatformClient\n//   rest = connectRest() + createRestTxOperations() (RestClient read-only + TxOperations cho write)\n//\n// getCurrentUser() wrap client.getAccount() (D15 FR-18 default assignee).\n// Error mapping: delegate sang T-04 HulyError qua mapError.\n\n// CJS interop: @hcengineering/* ship CommonJS (dynamic __reExport loop) → named\n// ESM imports crash at runtime (\"Named export 'connect' not found\"). Default\n// import = module.exports, destructure for values. Types stay type-only.\nimport apiClient from \"@hcengineering/api-client\";\nimport type {\n  Account,\n  ConnectOptions,\n  AttachedData,\n  AttachedDoc,\n  Class,\n  Doc,\n  DocumentQuery,\n  DocumentUpdate,\n  FindOptions,\n  FindResult,\n  Mixin,\n  MixinData,\n  PlatformClient,\n  Ref,\n  RestClient,\n  Space,\n  StorageClient,\n  TxOperations,\n  TxResult,\n  WithLookup,\n  WithMarkup,\n} from \"@hcengineering/api-client\";\n// T-103 #156 → fix interop: makeCollabId (core) + jsonToMarkup (text-core) exist\n// runtime nhưng KHÔNG trong .d.ts. @hcengineering/core là CJS, và 2 cách import\n// ESM đều gãy ở 1 môi trường: default import (`import core`) → core.makeCollabId\n// undefined dưới vitest; namespace (`import * as core`) → undefined dưới plain\n// Node/dist. createRequire(import.meta.url) trả module.exports nguyên thẳng\n// → đúng ở CẢ vitest lẫn production/dist. (textCore/textMarkdown default import\n// hiện work ở cả 2 môi trường do cấu trúc CJS khác — để nguyên, surgical.)\nimport { createRequire } from \"node:module\";\nimport textCore from \"@hcengineering/text-core\";\nimport textMarkdown from \"@hcengineering/text-markdown\";\nconst cjsRequire = createRequire(import.meta.url);\nconst core = cjsRequire(\"@hcengineering/core\") as {\n  makeCollabId: (cls: string, id: string, attr: string) => unknown;\n};\nconst { connect, connectRest, connectStorage, createRestTxOperations, getWorkspaceToken } =\n  apiClient;\nconst { markdownToMarkup } = textMarkdown;\nconst { makeCollabId } = core;\nconst jsonToMarkup = (textCore as unknown as { jsonToMarkup: (j: unknown) => string }).jsonToMarkup;\nimport { mapError } from \"./errors.js\";\nimport { DEFAULT_UPSTREAM_NOISE_PATTERNS, runWithConsoleFilter } from \"./console-filter.js\";\nimport { loadConfig } from \"../config/config.js\";\n\n/** Transport global toggle (D3). Default 'ws'. */\nexport type Transport = \"ws\" | \"rest\";\n\n/** Huly credentials: url tách + auth union (D8) + workspace BẮT BUỘC. */\nexport type HulyCredentials = {\n  url: string;\n} & ConnectOptions;\n\n/** Current user shape (mapped từ Account, D15 FR-18). */\nexport interface CurrentUser {\n  id: string;\n  name: string;\n  email: string;\n}\n\n/**\n * HulyClient — unified interface cho cả ws + rest transport.\n * Methods ủy quyền PlatformClient (ws) hoặc RestClient + TxOperations (rest).\n */\nexport interface HulyClient {\n  readonly transport: Transport;\n\n  // FindOperations\n  findOne<T extends Doc>(\n    _class: Ref<Class<T>>,\n    query: DocumentQuery<T>,\n    options?: FindOptions<T>,\n  ): Promise<WithLookup<T> | undefined>;\n  findAll<T extends Doc>(\n    _class: Ref<Class<T>>,\n    query: DocumentQuery<T>,\n    options?: FindOptions<T>,\n  ): Promise<FindResult<T>>;\n\n  // DocOperations (write)\n  createDoc<T extends Doc>(\n    _class: Ref<Class<T>>,\n    space: Ref<Space>,\n    attributes: WithMarkup<Record<string, unknown>>,\n    id?: Ref<T>,\n  ): Promise<Ref<T>>;\n  updateDoc<T extends Doc>(\n    _class: Ref<Class<T>>,\n    space: Ref<Space>,\n    objectId: Ref<T>,\n    operations: WithMarkup<DocumentUpdate<T>>,\n    retrieve?: boolean,\n  ): Promise<TxResult>;\n  removeDoc<T extends Doc>(\n    _class: Ref<Class<T>>,\n    space: Ref<Space>,\n    objectId: Ref<T>,\n  ): Promise<TxResult>;\n\n  // CollectionOperations (cho comments/labels/relations)\n  addCollection<T extends Doc, P extends AttachedDoc>(\n    _class: Ref<Class<P>>,\n    space: Ref<Space>,\n    attachedTo: Ref<T>,\n    attachedToClass: Ref<Class<T>>,\n    collection: string,\n    attributes: WithMarkup<AttachedData<P>>,\n    id?: Ref<P>,\n  ): Promise<Ref<P>>;\n\n  // MixinOperations\n  createMixin<D extends Doc, M extends D>(\n    objectId: Ref<D>,\n    objectClass: Ref<Class<D>>,\n    objectSpace: Ref<Space>,\n    mixin: Ref<Mixin<M>>,\n    attributes: WithMarkup<MixinData<D, M>>,\n  ): Promise<TxResult>;\n\n  // MarkupOperations (T-41 — fetch markup content từ MarkupBlobRef; T-66 — upload/update)\n  // Issue.description / Document.content là MarkupBlobRef (document ref), KHÔNG inline string.\n  // fetchMarkup resolve ref → markdown/html/markup string theo format.\n  // uploadMarkup/upload-save markup → trả MarkupBlobRef (create + edit document).\n  // Ref branded types bypass (string runtime, Ref compile-time).\n  fetchMarkup(\n    objectClass: string,\n    objectId: string,\n    objectAttr: string,\n    markup: unknown,\n    format: \"markdown\" | \"html\" | \"markup\",\n  ): Promise<string>;\n  uploadMarkup(\n    objectClass: string,\n    objectId: string,\n    objectAttr: string,\n    markup: string,\n    format: \"markdown\" | \"html\" | \"markup\",\n  ): Promise<unknown>;\n  // T-103 #156: updateMarkup = updateContent rpc (edit existing doc content).\n  // uploadMarkup/createMarkup (createContent rpc) chỉ tạo INITIAL version — KHÔNG\n  // update document đã tồn tại (content unchanged, 0 snapshot). updateMarkup update\n  // content in-place qua collaborator. Optional (chỉ WS transport có).\n  updateMarkup?(\n    objectClass: string,\n    objectId: string,\n    objectAttr: string,\n    markup: string,\n    format: \"markdown\" | \"html\" | \"markup\",\n  ): Promise<void>;\n  // T-77: Fulltext search API (relevance-ranked, fulltext index).\n  // Signature: searchFulltext({query, classes?, spaces?}, {limit?}) → {docs, total?}.\n  // WS PlatformClient có thể KHÔNG expose — handler fallback $like nếu throw.\n  searchFulltext?(query: unknown, options?: unknown): Promise<unknown>;\n\n  // T-75: Blob storage ops (Attachment file upload/download).\n  // uploadBlob → {blobId, size}. getBlob → Buffer. Lazy connectStorage.\n  uploadBlob?(\n    filename: string,\n    buffer: Buffer,\n    contentType: string,\n  ): Promise<{ blobId: string; size: number }>;\n  getBlob?(blobId: string): Promise<Buffer>;\n\n  // Account\n  getAccount(): Promise<Account>;\n  getCurrentUser(): Promise<CurrentUser>;\n\n  // Lifecycle\n  close(): Promise<void>;\n}\n\n/**\n * T-62 #67: Resolve console filter pattern từ config.\n *\n * - `quietUpstreamNoise === false` → return null (KHÔNG filter — debug thật)\n * - `upstreamNoisePatterns` override → compile user pattern (case-insensitive)\n * - Default → `DEFAULT_UPSTREAM_NOISE_PATTERNS` (T-62: #67 + T-64: WS spam)\n *\n * Filter scope hẹp (chỉ quanh connect()) → KHÔNG global-silent vĩnh viễn.\n * KHÔNG throw nếu config invalid (default patterns) — connect vẫn chạy.\n */\nasync function resolveFilterPatterns(): Promise<RegExp[] | null> {\n  let config;\n  try {\n    config = await loadConfig();\n  } catch {\n    // Config error KHÔNG block connect — filter dùng default patterns.\n    return DEFAULT_UPSTREAM_NOISE_PATTERNS;\n  }\n  if (config.quietUpstreamNoise === false) return null;\n  if (config.upstreamNoisePatterns !== undefined && config.upstreamNoisePatterns.length > 0) {\n    // Compile user pattern — skip invalid (KHÔNG crash connect)\n    const compiled: RegExp[] = [];\n    for (const src of config.upstreamNoisePatterns) {\n      try {\n        compiled.push(new RegExp(src, \"i\"));\n      } catch {\n        // Skip — validateConfig đã catch khi load, runtime skip cho safety.\n      }\n    }\n    return compiled.length > 0 ? compiled : DEFAULT_UPSTREAM_NOISE_PATTERNS;\n  }\n  return DEFAULT_UPSTREAM_NOISE_PATTERNS;\n}\n\n/**\n * Create HulyClient theo transport (D3):\n *   ws   → connect() + delegate PlatformClient\n *   rest → connectRest() + createRestTxOperations() + delegate RestClient (read) + TxOperations (write)\n *\n * T-62 #67: wrap `connect()` qua `runWithConsoleFilter()` — gate upstream\n * `console.warn/error/log` spam (cache-miss replay + WS error). Filter scope\n * hẹp (try/finally restore). Escape hatch: config `quietUpstreamNoise: false`.\n *\n * Throws HulyError nếu connect/connectRest/createRestTxOperations fail (mapError từ T-04).\n */\nexport async function createHulyClient(\n  creds: HulyCredentials,\n  transport: Transport = \"ws\",\n): Promise<HulyClient> {\n  const patterns = await resolveFilterPatterns();\n  try {\n    const { url, ...auth } = creds;\n    if (transport === \"ws\") {\n      const connectFn = () => connect(url, auth);\n      // T-62: wrap connect() — upstream replay tải model diff + warn cache-miss\n      // hàng loạt. Filter chỉ active trong scope connect (try/finally restore).\n      const client =\n        patterns !== null ? await runWithConsoleFilter(patterns, connectFn) : await connectFn();\n      return makeWsClient(client, () => connectStorage(url, auth));\n    }\n    // rest\n    const rest = await connectRest(url, auth);\n    const { endpoint, workspaceId, token } = await getWorkspaceToken(url, auth);\n    const tx = await createRestTxOperations(endpoint, workspaceId, token);\n    return makeRestClient(rest, tx, () => connectStorage(url, auth));\n  } catch (e) {\n    throw mapError(e);\n  }\n}\n\n/** Wrap PlatformClient (ws) thành HulyClient. */\nfunction makeWsClient(\n  client: PlatformClient,\n  getStorage: () => Promise<StorageClient>,\n): HulyClient {\n  let cachedUser: CurrentUser | undefined;\n  let cachedStorage: StorageClient | undefined;\n  return {\n    transport: \"ws\",\n    findOne: (...args) => client.findOne(...args),\n    findAll: (...args) => client.findAll(...args),\n    createDoc: (...args) => client.createDoc(...args),\n    updateDoc: (...args) => client.updateDoc(...args),\n    removeDoc: (...args) => client.removeDoc(...args),\n    addCollection: (...args) => client.addCollection(...args),\n    createMixin: (...args) => client.createMixin(...args),\n    // T-41: PlatformClient có fetchMarkup/uploadMarkup built-in (MarkupOperations).\n    // Library KHÔNG có updateMarkup — edit = uploadMarkup + updateDoc.\n    fetchMarkup: (...args) => client.fetchMarkup(...args),\n    uploadMarkup: (...args) => client.uploadMarkup(...args),\n    // T-103 #156: updateMarkup qua collaborator.updateMarkup (updateContent rpc).\n    // client.markup = MarkupOperationsImpl (public field) — hold collaborator +\n    // refUrl/imageUrl (private TS, runtime-accessible). Convert markdown→markup\n    // mirror MarkupOperationsImpl.uploadMarkup, rồi updateMarkup thay createMarkup.\n    updateMarkup: async (objectClass, objectId, objectAttr, value, format) => {\n      const mo = (\n        client as unknown as {\n          markup: {\n            collaborator: {\n              updateMarkup: (doc: unknown, markup: string) => Promise<void>;\n            };\n            refUrl?: string;\n            imageUrl?: string;\n          };\n        }\n      ).markup;\n      let markup = \"\";\n      if (format === \"markdown\") {\n        markup = jsonToMarkup(\n          markdownToMarkup(value, { refUrl: mo.refUrl, imageUrl: mo.imageUrl }),\n        );\n      } else {\n        markup = value;\n      }\n      const collabId = makeCollabId(objectClass, objectId, objectAttr);\n      await mo.collaborator.updateMarkup(collabId, markup);\n    },\n    // T-77: searchFulltext — optional trên PlatformClient. Guard runtime +\n    // helpful error nếu undefined (handler fulltext_search fallback $like).\n    searchFulltext: (...args) => {\n      const fn = client.searchFulltext;\n      if (typeof fn !== \"function\") {\n        throw new Error(\"searchFulltext not available on WS transport — fallback to $like.\");\n      }\n      return fn(...args);\n    },\n    // T-75: blob storage ops (lazy connectStorage).\n    uploadBlob: async (filename, buffer, contentType) => {\n      if (!cachedStorage) cachedStorage = await getStorage();\n      const objectName = `attachment/${Math.random().toString(36).slice(2, 14)}/${filename}`;\n      const blob = await cachedStorage.put(objectName, buffer, contentType, buffer.length);\n      return { blobId: blob._id, size: blob.size };\n    },\n    getBlob: async (blobId) => {\n      if (!cachedStorage) cachedStorage = await getStorage();\n      const stream = await cachedStorage.get(blobId);\n      const chunks: Buffer[] = [];\n      for await (const chunk of stream) {\n        chunks.push(typeof chunk === \"string\" ? Buffer.from(chunk) : chunk);\n      }\n      return Buffer.concat(chunks);\n    },\n    getAccount: () => client.getAccount(),\n    async getCurrentUser(): Promise<CurrentUser> {\n      if (cachedUser) return cachedUser;\n      const account = await client.getAccount();\n      cachedUser = accountToUser(account);\n      return cachedUser;\n    },\n    close: () => client.close(),\n  };\n}\n\n/** Wrap RestClient + TxOperations (rest) thành HulyClient. */\nfunction makeRestClient(\n  rest: RestClient,\n  tx: TxOperations,\n  getStorage: () => Promise<StorageClient>,\n): HulyClient {\n  let cachedUser: CurrentUser | undefined;\n  let cachedStorage: StorageClient | undefined;\n  return {\n    transport: \"rest\",\n    // Read ops → RestClient\n    findOne: (...args) => rest.findOne(...args),\n    findAll: (...args) => rest.findAll(...args),\n    // Write ops → TxOperations (RestClient read-only)\n    createDoc: (...args) => tx.createDoc(...args),\n    updateDoc: (...args) => tx.updateDoc(...args),\n    removeDoc: (...args) => tx.removeDoc(...args),\n    addCollection: (...args) => tx.addCollection(...args),\n    createMixin: (...args) => tx.createMixin(...args),\n    // T-41: RestClient KHÔNG có fetchMarkup built-in (chỉ PlatformClient ws có).\n    // REST transport fallback: throw rõ ràng — user đổi sang ws transport nếu cần\n    // resolve MarkupBlobRef (vd get_issue description). Default transport = ws\n    // (config.ts D3) nên path này hiếm khi hit. T-66: upload/updateMarkup cùng.\n    fetchMarkup: () => {\n      throw new Error(\n        \"fetchMarkup not supported on REST transport. Use WS transport (default) \" +\n          \"to resolve MarkupBlobRef fields like issue description.\",\n      );\n    },\n    uploadMarkup: () => {\n      throw new Error(\n        \"uploadMarkup not supported on REST transport. Use WS transport (default) \" +\n          \"to save document content (MarkupBlobRef).\",\n      );\n    },\n    // T-103 #156: updateMarkup cũng WS-only (collaborator) — throwing stub mirror.\n    updateMarkup: () => {\n      throw new Error(\n        \"updateMarkup not supported on REST transport. Use WS transport (default) \" +\n          \"to edit document content.\",\n      );\n    },\n    // T-77: REST has searchFulltext (RestClient.searchFulltext exists).\n    searchFulltext: (...args) => rest.searchFulltext(...args),\n    // T-75: blob storage ops (lazy connectStorage).\n    uploadBlob: async (filename, buffer, contentType) => {\n      if (!cachedStorage) cachedStorage = await getStorage();\n      const objectName = `attachment/${Math.random().toString(36).slice(2, 14)}/${filename}`;\n      const blob = await cachedStorage.put(objectName, buffer, contentType, buffer.length);\n      return { blobId: blob._id, size: blob.size };\n    },\n    getBlob: async (blobId) => {\n      if (!cachedStorage) cachedStorage = await getStorage();\n      const stream = await cachedStorage.get(blobId);\n      const chunks: Buffer[] = [];\n      for await (const chunk of stream) {\n        chunks.push(typeof chunk === \"string\" ? Buffer.from(chunk) : chunk);\n      }\n      return Buffer.concat(chunks);\n    },\n    getAccount: () => rest.getAccount(),\n    async getCurrentUser(): Promise<CurrentUser> {\n      if (cachedUser) return cachedUser;\n      const account = await rest.getAccount();\n      cachedUser = accountToUser(account);\n      return cachedUser;\n    },\n    // REST stateless — close no-op\n    close: async () => {},\n  };\n}\n\n/** Map Account → CurrentUser (D15 FR-18 assignee default). */\nfunction accountToUser(account: Account): CurrentUser {\n  // T-103 #157: primarySocialId có thể là numeric id (Google/huly login), KHÔNG\n  // email. Extract email THẬT từ fullSocialIds[type=email].value (fallback\n  // primarySocialId nếu không có — vd workspace chỉ có 1 social id).\n  const emailSocial = (\n    account as { fullSocialIds?: Array<{ type: string; value: string }> }\n  ).fullSocialIds?.find((s) => s.type === \"email\");\n  const email = emailSocial?.value ?? account.primarySocialId;\n  return {\n    id: account.uuid,\n    name: account.primarySocialId,\n    email,\n  };\n}\n","// ConnectionPool — module singleton, shared subagents (D14).\n// Design: 04-system.md §6 pool.ts, 01 §B.3 D3 transport, §B.14 D14 shared,\n// 08 §A NFR-11 maxSize 8 (ws), NFR-03 reconnect.\n//\n// Pool state = module-level (KHÔNG per-session) → subagent reuse.\n// WS: LRU evict khi > maxSize (default 8). REST: cached instance, no LRU (stateless).\n\nimport { getWorkspace, type WorkspaceCreds } from \"../config/credentials.js\";\nimport { loadConfig } from \"../config/config.js\";\nimport {\n  createHulyClient,\n  type HulyClient,\n  type HulyCredentials,\n  type Transport,\n} from \"./client.js\";\nimport { getUpstreamNoiseCounters } from \"./console-filter.js\";\n\n/** Pool entry: client + metadata. */\ninterface PoolEntry {\n  client: HulyClient;\n  workspaceId: string;\n  transport: Transport;\n  createdAt: number;\n  lastAccess: number;\n}\n\n/** Health status cho /huly diagnostics. */\nexport interface HealthStatus {\n  workspace: string;\n  connected: boolean;\n  transport: Transport;\n  user?: { id: string; name: string; email: string };\n  /**\n   * T-62 #67: count dòng upstream console spam đã filter (cumulative session).\n   * Total + per-pattern breakdown. Populated nếu `quietUpstreamNoise !== false`.\n   */\n  upstreamNoiseFiltered?: { total: number; byPattern: Record<string, number> };\n}\n\n/** Max WS connections in pool (NFR-11 default 8). */\nconst MAX_WS_POOL = 8;\n\n/** Module-level pool singleton (shared subagents D14). */\nconst pool = new Map<string, PoolEntry>();\n\n/**\n * Get-or-create HulyClient cho workspace.\n * WS: LRU evict khi pool > MAX_WS_POOL. REST: cached, no LRU.\n * Lazy reconnect: nếu client closed → recreate (simplified — KHÔNG backoff timing).\n */\nexport async function getClient(workspaceId: string): Promise<HulyClient> {\n  const existing = pool.get(workspaceId);\n  if (existing) {\n    existing.lastAccess = Date.now();\n    return existing.client;\n  }\n  // Cache miss → create\n  const creds = await getWorkspace(workspaceId);\n  if (!creds) {\n    throw new Error(`Workspace \"${workspaceId}\" not found in credentials. Run /huly init to add.`);\n  }\n  const config = await loadConfig();\n  const transport: Transport = config.transport ?? \"ws\";\n\n  // WS LRU evict nếu đạt maxSize\n  if (transport === \"ws\") {\n    const wsEntries = [...pool.values()].filter((e) => e.transport === \"ws\");\n    if (wsEntries.length >= MAX_WS_POOL) {\n      // Evict oldest by lastAccess\n      const oldest = wsEntries.sort((a, b) => a.lastAccess - b.lastAccess)[0];\n      if (oldest) {\n        await oldest.client.close().catch(() => {});\n        pool.delete(oldest.workspaceId);\n      }\n    }\n  }\n\n  const client = await createHulyClient(toCredentials(creds), transport);\n  // Pre-fetch currentUser để cache (D15) + verify connection healthy.\n  // Fail KHÔNG block pool — user available lazily qua client.getCurrentUser().\n  await client.getCurrentUser().catch(() => {});\n  pool.set(workspaceId, {\n    client,\n    workspaceId,\n    transport,\n    createdAt: Date.now(),\n    lastAccess: Date.now(),\n  });\n\n  return client;\n}\n\n/** Map WorkspaceCreds → HulyCredentials (url + ConnectOptions auth union). */\nfunction toCredentials(creds: WorkspaceCreds): HulyCredentials {\n  // WorkspaceCreds = {url,workspace} & AuthMethod = {url} & ConnectOptions = HulyCredentials.\n  return creds;\n}\n\n/**\n * Close all clients + clear pool. session_shutdown cleanup (FR-12).\n * Idempotent — safe to call multiple times.\n */\nexport async function closeAll(): Promise<void> {\n  const entries = [...pool.values()];\n  pool.clear();\n  await Promise.all(entries.map((entry) => entry.client.close().catch(() => {})));\n}\n\n/**\n * Health check cho /huly diagnostics.\n * - workspace given → check specific entry\n * - undefined → aggregate all entries\n */\nexport async function health(workspace?: string): Promise<HealthStatus[]> {\n  if (workspace) {\n    const entry = pool.get(workspace);\n    if (!entry) return [];\n    return [await entryHealth(entry)];\n  }\n  return Promise.all([...pool.values()].map(entryHealth));\n}\n\nasync function entryHealth(entry: PoolEntry): Promise<HealthStatus> {\n  let user: { id: string; name: string; email: string } | undefined;\n  let connected = true;\n  try {\n    user = await entry.client.getCurrentUser();\n  } catch {\n    connected = false;\n  }\n  // T-62 #67: module-level counter cross entry. Populated khi total > 0.\n  const counters = getUpstreamNoiseCounters();\n  const upstreamNoiseFiltered =\n    counters.total > 0 ? { total: counters.total, byPattern: counters.byPattern } : undefined;\n  return {\n    workspace: entry.workspaceId,\n    connected,\n    transport: entry.transport,\n    user,\n    ...(upstreamNoiseFiltered !== undefined ? { upstreamNoiseFiltered } : {}),\n  };\n}\n\n/** Test-only: clear pool without closing (cho unit test isolation). */\nexport function __clearPoolForTests(): void {\n  pool.clear();\n}\n\n/** Test-only: get pool size. */\nexport function __poolSizeForTests(): number {\n  return pool.size;\n}\n\n/** Test-only: get MAX_WS_POOL constant. */\nexport const __MAX_WS_POOL = MAX_WS_POOL;\n","// WorkspaceResolver + ProjectResolver — chain resolution (explicit > cwd-map > init).\n// Design: 04-system.md §6, 01-vision.md §B.8 D8 resolution chain.\n//\n// Resolution chain (no env vars per D8):\n//   resolveWorkspace: explicit param > cwd-map (config.resolveByCwd) > NeedsInitError\n//   resolveProject:   explicit param > cwd-map > undefined (caller prompt list_projects)\n//\n// Same-name diff-URL disambiguation: findByName returns multiple → NeedsDisambiguationError.\n\nimport { CREDENTIALS_PATH, findByName, getWorkspace } from \"./credentials.js\";\nimport { CONFIG_PATH, resolveByCwd, type ProjectBinding } from \"./config.js\";\n\n/** Context injected vào resolver (testability + tránh hard coupling). */\nexport type ResolverCtx = {\n  /** Current working directory (cwd) cho cwd-map resolution. */\n  cwd: string;\n  /** Override credentials path (test inject temp). Default: CREDENTIALS_PATH. */\n  credentialsPath?: string;\n  /** Override config path (test inject temp). Default: CONFIG_PATH. */\n  configPath?: string;\n};\n\n/**\n * Error: workspace explicit param hoặc cwd-map resolves tới same-name diff-URL.\n * Caller catch → prompt user chọn 1 trong matches.\n */\nexport class NeedsDisambiguationError extends Error {\n  readonly matches: Array<{ id: string; url: string; workspace: string }>;\n  constructor(matches: Array<{ id: string; url: string; workspace: string }>) {\n    super(\n      `Workspace name ambiguous: ${matches.length} workspaces match. ` +\n        `Specify one: ${matches.map((m) => `${m.id} (${m.url})`).join(\", \")}`,\n    );\n    this.name = \"NeedsDisambiguationError\";\n    this.matches = matches;\n  }\n}\n\n/**\n * Error: không resolve được workspace (no explicit, no cwd-map binding).\n * Caller catch → run /huly init flow.\n */\nexport class NeedsInitError extends Error {\n  constructor(message = \"No workspace resolved. Run /huly init to bind cwd.\") {\n    super(message);\n    this.name = \"NeedsInitError\";\n  }\n}\n\n/**\n * Resolve workspace id-handle cho tool call.\n * Chain:\n *   1. explicit param → lookup credentials (findByName → multi = NeedsDisambiguationError;\n *      single = return id; getWorkspace exact id = return)\n *   2. cwd-map → resolveByCwd(cwd)?.workspace → return binding.workspace\n *   3. KHÔNG có → throw NeedsInitError\n */\nexport async function resolveWorkspace(\n  explicit?: string,\n  ctx: ResolverCtx = { cwd: process.cwd() },\n): Promise<string> {\n  const credPath = ctx.credentialsPath ?? CREDENTIALS_PATH;\n  const configPath = ctx.configPath ?? CONFIG_PATH;\n\n  // 1. Explicit param\n  if (explicit !== undefined && explicit.length > 0) {\n    // Try exact id first\n    const byId = await getWorkspace(explicit, credPath);\n    if (byId !== undefined) {\n      return explicit;\n    }\n    // Try findByName (multi-result possible)\n    const matches = await findByName(explicit, credPath);\n    if (matches.length === 1) {\n      return matches[0].id;\n    }\n    if (matches.length > 1) {\n      throw new NeedsDisambiguationError(\n        matches.map((m) => ({ id: m.id, url: m.url, workspace: m.workspace })),\n      );\n    }\n    throw new NeedsInitError(\n      `Workspace \"${explicit}\" not found in credentials. Run /huly init to add it.`,\n    );\n  }\n\n  // 2. cwd-map\n  const binding = await resolveByCwd(ctx.cwd, configPath);\n  if (binding !== undefined) {\n    // NOTE: intentional — KHÔNG verify workspace còn tồn tại trong credentials\n    // ở đây. Credential staleness (binding tồn tại nhưng workspace bị remove)\n    // là trách nhiệm client/pool (T-05/T-06), không phải resolver.\n    return binding.workspace;\n  }\n\n  // 3. No resolution\n  throw new NeedsInitError();\n}\n\n/**\n * Resolve project id cho tool call.\n * Chain:\n *   1. explicit param → return as-is\n *   2. cwd-map → resolveByCwd(cwd)?.project → return binding.project\n *   3. KHÔNG có → return undefined (caller prompt list_projects)\n */\nexport async function resolveProject(\n  explicit?: string,\n  ctx: ResolverCtx = { cwd: process.cwd() },\n): Promise<string | undefined> {\n  // 1. Explicit param\n  if (explicit !== undefined && explicit.length > 0) {\n    return explicit;\n  }\n\n  // 2. cwd-map\n  const configPath = ctx.configPath ?? CONFIG_PATH;\n  const binding: ProjectBinding | undefined = await resolveByCwd(ctx.cwd, configPath);\n  if (binding !== undefined) {\n    return binding.project;\n  }\n\n  // 3. No resolution → undefined (caller prompt)\n  return undefined;\n}\n","// confirmGate — confirmDestructive cho destructive ops (FR-09 D9).\n// Design: 04-system.md §6 tools/confirm.ts, 01 §B.9 D9, 06-api.md §6 confirm flow.\n//\n// Behavior:\n//   ctx.hasUI === true (TUI/RPC) → ctx.ui.confirm prompt — user choose yes/no\n//   ctx.hasUI === false (print/json/CI) → auto-deny (KHÔNG bypass — 05 §4 safety)\n//\n// Confirm KHÔNG bypass: non-TUI mode deny mọi destructive op (NFR-10 safety).\n\nimport type { ExtensionContext } from \"@earendil-works/pi-coding-agent\";\n\n/** Detail object cho confirm prompt. */\nexport interface ConfirmContext {\n  /** Type entity bị xóa (vd \"issue\", \"document\", \"project\"). */\n  type: string;\n  /** Identifier (vd \"PD-123\", doc id). */\n  id: string;\n  /** Optional extra detail (vd cascade count \"Cascade: 5 items\"). */\n  detail?: string;\n}\n\n/**\n * Confirm destructive operation với user (FR-09 D9).\n *\n * @param ctx Pi extension context (cho hasUI check + ui.confirm)\n * @param c   Confirm context: type + id + optional detail\n * @returns true nếu user confirmed, false nếu denied HOẶC non-TUI auto-deny\n *\n * Non-TUI (print/json/CI, ctx.hasUI===false) → auto-deny KHÔNG bypass.\n */\nexport async function confirmDestructive(\n  ctx: ExtensionContext,\n  c: ConfirmContext,\n): Promise<boolean> {\n  // Non-TUI → auto-deny (KHÔNG bypass — NFR-10)\n  if (ctx.hasUI !== true) {\n    return false;\n  }\n\n  const title = `Delete ${c.type}`;\n  const message =\n    c.detail !== undefined && c.detail.length > 0\n      ? `Delete ${c.type} \"${c.id}\"? ${c.detail}`\n      : `Delete ${c.type} \"${c.id}\"?`;\n\n  try {\n    return await ctx.ui.confirm(title, message);\n  } catch {\n    // UI error (e.g. dialog dismissed) → treat as deny (safe default)\n    return false;\n  }\n}\n","// toolBuilder — single seam cho mọi Huly tool (defineHulyTool).\n// Design: 04-system.md §6 tools/builder.ts, 06-api.md §1 Tool Interface Pattern,\n// 01-vision §B.4 D4 (~102 tools), §B.5 D5 (huly_ prefix).\n//\n// defineHulyTool tự động:\n//   - prefix `huly_` (D5 FR-02)\n//   - resolve workspace + project từ params (FR-06 chain: explicit > cwd-map)\n//   - getClient từ pool (D14 shared)\n//   - error map → AgentToolResult isError (FR-14, 08 §A no-leak)\n//   - confirm gate nếu destructive (FR-09 D9)\n//   - assignee default cho tool khai báo needsAssignee (D15 FR-18)\n//\n// Domain module chỉ khai báo opts (schema + handler thuần), builder lo phần binding.\n\nimport type { ExtensionContext } from \"@earendil-works/pi-coding-agent\";\nimport type { Static, TObject } from \"typebox\";\nimport { getClient } from \"../client/pool.js\";\nimport { mapError, sanitize } from \"../client/errors.js\";\nimport type { HulyClient, CurrentUser } from \"../client/client.js\";\nimport {\n  resolveProject,\n  resolveWorkspace,\n  NeedsDisambiguationError,\n  NeedsInitError,\n  type ResolverCtx,\n} from \"../config/resolver.js\";\nimport { confirmDestructive, type ConfirmContext } from \"./confirm.js\";\n\n/** Tool parameter schema phải là TObject (Type.Object) cho LLM-callable. */\nexport type ToolParams = TObject;\n\n/** Error class identifier (re-export từ errors.ts — single source). */\nexport type { ErrorClass, HulyError } from \"../client/errors.js\";\n\n/**\n * Huly tool context — passed vào handler sau khi builder resolve binding.\n * Handler nhận client đã kết nối + resolved workspace/project, KHÔNG phải tự lookup.\n */\nexport interface HulyToolContext {\n  /** Pi extension context (ui, cwd, hasUI, ...). */\n  ctx: ExtensionContext;\n  /** Resolved workspace id-handle (đã qua FR-06 chain). */\n  workspace: string;\n  /** Resolved project identifier (FR-06 chain; undefined nếu tool không cần project). */\n  project: string | undefined;\n  /** Current user (cached sau getClient — D15 default assignee source). */\n  currentUser: CurrentUser;\n  /** HulyClient đã kết nối (cho handler gọi CRUD). */\n  client: HulyClient;\n}\n\n/**\n * Result trả về từ handler. Builder convert sang AgentToolResult.\n * - `content` text cho LLM (≤ 50KB / 2000 lines — pi truncate)\n * - `details` structured cho render + state (entity shapes từ 05-data-model.md)\n * - `isError?` true → LLM thấy error\n */\nexport interface HulyToolResult<TDetails = unknown> {\n  /** Human-readable text cho LLM. */\n  content: string;\n  /** Structured details cho render + downstream. */\n  details?: TDetails;\n  /** True nếu result là error (builder wrap message + isError=true). */\n  isError?: boolean;\n}\n\n/**\n * Handler signature cho Huly tool.\n * - `params`: validated theo schema (typebox Static<P>)\n * - `toolCtx`: resolved binding (client + workspace + project + user)\n * - Return HulyToolResult (builder convert sang AgentToolResult)\n *\n * TDetails default `unknown` — caller KHÔNG cần khai báo, return type flexible.\n */\nexport type HulyToolHandler<P extends ToolParams, TDetails = unknown> = (\n  params: Static<P>,\n  toolCtx: HulyToolContext,\n) => Promise<HulyToolResult<TDetails>>;\n\n/** Re-export HulyClient type cho domain consumer. */\nexport type { HulyClient, CurrentUser } from \"../client/client.js\";\n/** Re-export ResolverCtx cho consumer (test mock). */\nexport type { ResolverCtx, NeedsInitError, NeedsDisambiguationError } from \"../config/resolver.js\";\n\n/**\n * defineHulyTool options — domain module chỉ khai báo này.\n * Builder wrap thành ToolDefinition cho pi.registerTool.\n *\n * TDetails default `unknown` — domain KHÔNG cần khai báo. Handler return type flexible\n * (nhiều shape success/error/not-found → TDetails cố định gây union conflict).\n */\nexport interface DefineHulyToolOptions<P extends ToolParams = ToolParams, TDetails = unknown> {\n  /** Tool name KHÔNG có prefix `huly_` — builder tự thêm (D5). VD: \"create_issue\". */\n  name: string;\n  /** Human-readable label cho UI. */\n  label: string;\n  /** Description cho LLM (khi nào gọi, input shape mong đợi). */\n  description: string;\n  /** Optional 1 dòng snippet cho system prompt \"Available tools\" section. */\n  promptSnippet?: string;\n  /** Optional guideline bullets appended to system prompt. */\n  promptGuidelines?: string[];\n  /** Parameter schema (typebox Type.Object). */\n  parameters: P;\n  /** Handler thuần — nhận resolved binding, return HulyToolResult. */\n  handler: (params: Static<P>, toolCtx: HulyToolContext) => Promise<HulyToolResult<TDetails>>;\n  /** True → confirm gate (FR-09 D9). Builder call confirmDestructive trước handler. */\n  destructive?: boolean;\n  /**\n   * Detail object cho confirm prompt (khi destructive=true).\n   * Builder call confirmDestructive({ type, id, detail }).\n   */\n  destructiveContext?: (params: Static<P>) => ConfirmContext;\n  /**\n   * True → tool cần project resolved (issues/milestones/components/templates).\n   * False → tool global (workspaces, search, contacts, ...).\n   * Default: false (handler tự resolve nếu cần).\n   */\n  needsProject?: boolean;\n  /**\n   * True → tool có assignee?/owner? param cần auto-resolve currentUser khi absent (D15 FR-18).\n   * Builder resolve trước khi pass params vào handler (param `assignee` filled).\n   */\n  needsAssignee?: boolean;\n  /**\n   * Field name chứa assignee (default \"assignee\"). Builder fill params[fieldName] = email khi absent.\n   */\n  assigneeField?: string;\n}\n\n/**\n * Pi ToolDefinition-compatible shape (subset — builder output).\n * Domain modules return HulyToolDefinition[]; register.ts call pi.registerTool\n * (cast qua ToolDefinition full khi register — bổ sung execute signature chuẩn).\n */\nexport interface HulyToolDefinition<P extends ToolParams = ToolParams, TDetails = unknown> {\n  name: string;\n  label: string;\n  description: string;\n  promptSnippet?: string;\n  promptGuidelines?: string[];\n  parameters: P;\n  execute: (\n    toolCallId: string,\n    params: Static<P>,\n    signal: AbortSignal | undefined,\n    onUpdate:\n      | ((partialResult: {\n          content: Array<{ type: \"text\"; text: string }>;\n          details: TDetails;\n          isError?: true;\n        }) => void)\n      | undefined,\n    ctx: ExtensionContext,\n  ) => Promise<{\n    content: Array<{ type: \"text\"; text: string }>;\n    details: TDetails;\n    isError?: true;\n  }>;\n}\n\n/**\n * Build Huly tool từ declaration → pi ToolDefinition-compatible.\n *\n * Flow execute (chạy khi LLM gọi tool):\n *   1. Resolve workspace (params.workspace > cwd-map > NeedsInitError → error result)\n *   2. Resolve project nếu needsProject (params.project > cwd-map > undefined)\n *   3. getClient(workspace) từ pool\n *   4. Nếu needsAssignee + params[fieldName] absent → resolveAssignee (D15)\n *   5. Nếu destructive → confirmDestructive; deny → return \"cancelled\"\n *   6. Call handler(params, { ctx, client, workspace, project, currentUser })\n *   7. Handler throw → mapError → error result (FR-14, 08 §A no-leak)\n *   8. Handler return HulyToolResult → convert sang AgentToolResult shape\n */\nexport function defineHulyTool<P extends ToolParams>(\n  opts: DefineHulyToolOptions<P, unknown>,\n): HulyToolDefinition<P, unknown> {\n  const fullName = `huly_${opts.name}`;\n  const assigneeField = opts.assigneeField ?? \"assignee\";\n  const needsProject = opts.needsProject === true;\n  const needsAssignee = opts.needsAssignee === true;\n\n  return {\n    name: fullName,\n    label: opts.label,\n    description: opts.description,\n    promptSnippet: opts.promptSnippet,\n    promptGuidelines: opts.promptGuidelines,\n    parameters: opts.parameters,\n\n    async execute(_toolCallId, rawParams, _signal, _onUpdate, ctx) {\n      const params = { ...(rawParams as Static<P>) } as Record<string, unknown>;\n      const resolverCtx: ResolverCtx = { cwd: ctx.cwd };\n\n      // 1. Resolve workspace\n      let workspace: string;\n      try {\n        workspace = await resolveWorkspace(\n          typeof params.workspace === \"string\" ? params.workspace : undefined,\n          resolverCtx,\n        );\n      } catch (e) {\n        return toErrorResult(e);\n      }\n\n      // 2. Resolve project nếu cần\n      let project: string | undefined;\n      if (needsProject) {\n        try {\n          project = await resolveProject(\n            typeof params.project === \"string\" ? params.project : undefined,\n            resolverCtx,\n          );\n        } catch (e) {\n          return toErrorResult(e);\n        }\n      }\n\n      // 3. getClient từ pool\n      let client: HulyClient;\n      try {\n        client = await getClient(workspace);\n      } catch (e) {\n        return toErrorResult(e);\n      }\n\n      // 4. Current user (cached — D15)\n      let currentUser: CurrentUser;\n      try {\n        currentUser = await client.getCurrentUser();\n      } catch (e) {\n        return toErrorResult(e);\n      }\n\n      // 5. Auto-resolve assignee nếu cần + absent (D15 FR-18)\n      // Dùng currentUser đã fetch ở step 4 (cached — single source = Huly).\n      if (needsAssignee) {\n        const current = params[assigneeField];\n        if (current === undefined || current === null || current === \"\") {\n          params[assigneeField] = currentUser.email;\n        }\n      }\n\n      // 6. Confirm gate (FR-09 D9) — non-TUI auto-deny (KHÔNG bypass)\n      if (opts.destructive === true) {\n        let destructiveCtx: ConfirmContext;\n        if (opts.destructiveContext) {\n          try {\n            destructiveCtx = opts.destructiveContext(rawParams as Static<P>);\n          } catch {\n            // destructiveContext throw (domain bug) → fallback safe defaults\n            destructiveCtx = { type: opts.name, id: \"<unknown>\" };\n          }\n        } else {\n          destructiveCtx = { type: opts.name, id: \"<unknown>\" };\n        }\n        const confirmed = await confirmDestructive(ctx, destructiveCtx);\n        if (!confirmed) {\n          return {\n            content: [\n              {\n                type: \"text\",\n                text: `Cancelled: ${opts.name} requires confirmation.`,\n              },\n            ],\n            details: { cancelled: true, tool: fullName },\n            isError: true,\n          };\n        }\n      }\n\n      // 7. Call handler\n      try {\n        const result = await opts.handler(params as Static<P>, {\n          ctx,\n          workspace,\n          project,\n          currentUser,\n          client,\n        });\n        // 8. Convert HulyToolResult → AgentToolResult shape\n        // Sanitize content (08 §A no-leak) — handler có thể return entity có\n        // token user paste (vd issue description). Success path cũng strip.\n        const contentText = sanitize(result.content);\n        // T-92 (#138): LUÔN append details summary vào content cho LLM — KHÔNG\n        // gate theo hasUI. Trước đây gate `hasUI !== true` khiến TUI mode drop\n        // details cho ~99 tool (chỉ 3 tool có renderResult hook: get_issue /\n        // list_issues / get_document), model thấy count-only → không drive được\n        // tool follow-up (list_issues không trả identifier, list_tags không _id,\n        // fulltext_search không identifier, add_comment/create_todo không id, …).\n        // Render hook (3 tool) vẫn consume details cho UI user; content (model)\n        // giờ cũng thấy → khác audience, KHÔNG xung đột. Append bị cap\n        // LLM_ARRAY_CAP + sanitize mỗi field. Error path KHÔNG append (content\n        // error message đã đủ, tránh noise).\n        const finalContent =\n          result.isError !== true ? appendDetailsForLLM(contentText, result.details) : contentText;\n        return {\n          content: [{ type: \"text\", text: finalContent }],\n          details: result.details ?? {},\n          isError: result.isError === true ? true : undefined,\n        };\n      } catch (e) {\n        return toErrorResult(e);\n      }\n    },\n  };\n}\n\n/**\n * Số item tối đa khi serialize array details → content text (T-40).\n * Tránh bloat context khi list trả nhiều (list_issues limit 50, có thể lớn hơn).\n */\nconst LLM_ARRAY_CAP = 30;\n\n/**\n * Append summary của `details` vào content text cho non-TUI path (T-40 #22 #26).\n *\n * Heuristic shape-aware (KHÔNG schema per-tool — 1 seam generic):\n * - Detect MỌI array field (vd `issues`, `members`, `attachments`, `tags`, ...)\n *   KHÔNG whitelist — iterate toàn bộ keys, kiểm `Array.isArray`. Serialize\n *   cap top `LLM_ARRAY_CAP` + đuôi \"... và N khác\". Lưu ý: handler nào đặt\n *   array lớn binary/debug vào details (vd `chunks`) cũng sẽ serialize —\n *   domain tránh pattern đó.\n * - Detect field `id`/`_id`/`identifier` (entity vừa create) → append dạng\n *   `id: <val>`.\n * - Bỏ qua field meta trống/count trùng (count đã trong content gốc nhiều case).\n *\n * Return text đã append (content gốc + \"\\n\" + summary). Nếu details rỗng/không\n * có gì hữu ích → return content gốc y nguyên.\n */\nfunction appendDetailsForLLM(content: string, details: unknown): string {\n  if (details === null || details === undefined) return content;\n  if (typeof details !== \"object\") return content;\n  const d = details as Record<string, unknown>;\n  const keys = Object.keys(d);\n  if (keys.length === 0) return content;\n\n  const lines: string[] = [];\n\n  // 1. Array fields: serialize cap top items\n  const seenArrays = new Set<string>();\n  for (const k of keys) {\n    const v = d[k];\n    if (Array.isArray(v) && v.length > 0) {\n      seenArrays.add(k);\n      const items = v.slice(0, LLM_ARRAY_CAP);\n      const remaining = v.length - items.length;\n      const serialized = items\n        .map((item, idx) => {\n          if (item !== null && typeof item === \"object\") {\n            const obj = item as Record<string, unknown>;\n            // Pick most useful fields cho LLM (identifier/id + title/name + status)\n            const ident = (obj.identifier ?? obj._id ?? obj.id) as string | undefined;\n            const title = (obj.title ?? obj.name ?? obj.label) as string | undefined;\n            const status = (obj.status ?? obj.priority) as string | undefined;\n            const parts: string[] = [];\n            // Sanitize mỗi field (08 §A NFR-04) — details có thể chứa token\n            // user paste (vd issue title có secret). Tránh leak qua non-TUI path.\n            if (ident !== undefined) parts.push(sanitize(String(ident)));\n            if (title !== undefined) parts.push(sanitize(String(title)));\n            if (status !== undefined) parts.push(`[${sanitize(String(status))}]`);\n            return parts.length > 0 ? `  ${idx + 1}. ${parts.join(\" — \")}` : null;\n          }\n          return `  ${idx + 1}. ${sanitize(String(item))}`;\n        })\n        .filter((line): line is string => line !== null);\n      if (serialized.length > 0) {\n        lines.push(`${k} (${v.length}):`);\n        lines.push(...serialized);\n        if (remaining > 0) {\n          lines.push(`  ... và ${remaining} khác.`);\n        }\n      }\n    }\n  }\n\n  // 2. Scalar id-like fields (entity create): id/_id/identifier + title/name.\n  // CHỈ khi chưa có array nào chiếm chỗ (tránh lặp cho list). Hiển thị TẤT CẢ\n  // id-like field (LLM cần `_id` raw cho 1 số tool, `identifier` human-friendly cho\n  // tool khác — vd create_issue trả _id internal + identifier PD-42).\n  if (seenArrays.size === 0) {\n    const idCandidates: Array<[string, unknown]> = [\n      [\"identifier\", d.identifier],\n      [\"_id\", d._id],\n      [\"id\", d.id],\n    ];\n    const idFields = idCandidates.filter(\n      (pair): pair is [string, unknown] => pair[1] !== undefined && pair[1] !== null,\n    );\n    const parts: string[] = [];\n    for (const [k, v] of idFields) {\n      const sv = sanitize(String(v));\n      // Skip nếu id đã xuất hiện trong content (tránh duplicate)\n      if (!content.includes(sv)) {\n        parts.push(`${k}: ${sv}`);\n      }\n    }\n    const title = (d.title ?? d.name ?? d.label) as string | undefined;\n    if (title !== undefined) {\n      const st = sanitize(String(title));\n      if (!content.includes(st)) {\n        parts.push(`title: ${st}`);\n      }\n    }\n    if (parts.length > 0) {\n      lines.push(parts.join(\" · \"));\n    }\n  }\n\n  if (lines.length === 0) return content;\n  return `${content}\\n${lines.join(\"\\n\")}`;\n}\n\n/**\n * Convert error → AgentToolResult với isError=true (FR-14, 08 §A no-leak).\n * Resolver errors (NeedsInit/NeedsDisambiguation) → clear recovery hint.\n * HulyError khác → mapError classify + sanitize.\n */\nfunction toErrorResult<TDetails = unknown>(\n  e: unknown,\n): {\n  content: Array<{ type: \"text\"; text: string }>;\n  details: TDetails;\n  isError: true;\n} {\n  // Resolver errors — clear hint cho LLM\n  if (e instanceof NeedsInitError) {\n    return {\n      content: [{ type: \"text\", text: e.message }],\n      details: { errorClass: \"Auth\", kind: \"NeedsInit\" } as unknown as TDetails,\n      isError: true,\n    };\n  }\n  if (e instanceof NeedsDisambiguationError) {\n    return {\n      content: [\n        {\n          type: \"text\",\n          text: `Workspace ambiguous: ${e.matches\n            .map((m) => `${m.id} (${m.url})`)\n            .join(\", \")}. Specify workspace param.`,\n        },\n      ],\n      details: {\n        errorClass: \"Auth\",\n        kind: \"NeedsDisambiguation\",\n        matches: e.matches,\n      } as unknown as TDetails,\n      isError: true,\n    };\n  }\n\n  // HulyError + PlatformError + network → mapError classify + sanitize\n  const hulyErr = mapError(e);\n  // T-57 #61: UnavailableError (domain not found) → render honest message với\n  // class ref thật + recovery hint, distinct generic InternalError. Dùng duck-type\n  // `class === \"Unavailable\"` (taxonomy identity) thay `instanceof` — compatible\n  // với test mock (mock tạo object cùng shape, KHÔNG phải subclass thật).\n  if (hulyErr.class === \"Unavailable\") {\n    const cls = (hulyErr as { hulyClass?: string }).hulyClass ?? \"<unknown>\";\n    return {\n      content: [\n        {\n          type: \"text\",\n          text:\n            `[UnavailableError] ${sanitize(hulyErr.message)}\\n\\n` +\n            `Recovery: kiểm tra workspace đã enable package chứa class \"${cls}\". ` +\n            `Nếu workspace OK → report bug pi-huly (sai class ref) kèm Huly version.`,\n        },\n      ],\n      details: { errorClass: \"Unavailable\", hulyClass: cls } as unknown as TDetails,\n      isError: true,\n    };\n  }\n  return {\n    content: [{ type: \"text\", text: `[${hulyErr.class}Error] ${sanitize(hulyErr.message)}` }],\n    details: { errorClass: hulyErr.class } as unknown as TDetails,\n    isError: true,\n  };\n}\n\n// Re-export sub-modules cho domain single-import.\nexport { confirmDestructive } from \"./confirm.js\";\nexport type { ConfirmContext } from \"./confirm.js\";\n// Re-export sanitize + LEAK_PATTERNS centralized (cho domain tool muốn sanitize custom output).\nexport { sanitize, LEAK_PATTERNS } from \"../client/errors.js\";\n","// Huly _class refs — string literal cast `as never` (branded Ref<T> bypass).\n// Centralized ở đây để domain modules KHÔNG lặp pattern, dễ search/audit.\n// Runtime: Huly packages có đầy đủ tracker/contact/document/..., pi-huly chỉ\n// dùng string literal (packages KHÔNG trong bundle, only runtime).\n//\n// T-43 fix (2026-07-27): re-verified class refs từ @hcengineering/*@0.7.423\n// source map (npm tarball extraction). Source of truth:\n// docs/design/11-runtime-audit.md. 6+ class broken root cause từng loại riêng\n// (mixin vs class / cross-package import / rename / base abstract).\n//\n// T-58 fix (2026-07-28): DEEP-AUDIT 12 packages @0.7.423 — verify plugin()\n// class block registration (KHÔNG chỉ interface existence). Key findings:\n//   - Document interface exists trong tracker source NHƯNG KHÔNG register class\n//     → `tracker:class:Document` runtime fail (interface orphan). Document search\n//     marked honest-unavailable (T-60).\n//   - Label: 0 match toàn packages → deprecated (Huly dùng TagElement).\n//   - TsRelation: 0 match → Issue.relations inline RelatedDocument[] (T-59\n//     refactor $push/$pull inline, xóa TS_RELATION_CLASS dead code).\n//   - DocumentSnapshot: 0 match → deprecated (T-58 honest-unavailable).\n//   - Space base abstract → Teamspace = drive:class:Drive (T-54).\n\n/**\n * Cast plain string thành Huly _class Ref (branded type bypass).\n * Runtime: string. Compile-time: Ref<T> (KHÔNG break generic constraint).\n */\nexport function classRef(ref: string): never {\n  return ref as never;\n}\n\n/** Cast plain string thành Huly _id Ref (branded type bypass). */\nexport function idRef(id: string): never {\n  return id as never;\n}\n\n/** Cast plain string thành Huly space Ref. */\nexport function spaceRef(space: string): never {\n  return space as never;\n}\n\n// === Domain class refs (verified từ @hcengineering/*@0.7.423 source map, 2026-07-27) ===\n\n// contact (Persons + Employee mixin)\n// Person/Contact = class. Employee = mixin (KHÔNG phải class — runtime lookup\n// khác → \"domain not found\" nếu query như class).\nexport const PERSON_CLASS = classRef(\"contact:class:Person\");\nexport const EMPLOYEE_CLASS = classRef(\"contact:mixin:Employee\"); // T-43: class → mixin\nexport const CONTACT_CLASS = classRef(\"contact:class:Contact\");\n// T-82G #108: Channel = email/phone provider attachments on Person.\n// Email resolve: findOne(Channel, {value: email, provider: Email}).\nexport const CHANNEL_CLASS = classRef(\"contact:class:Channel\");\nexport const EMAIL_PROVIDER = \"contact:channelProvider:Email\";\n\n// tracker (Issues/Milestones/Components/Projects — extends Task)\n// Issue/Milestone/Component/Project/IssueStatus/IssueTemplate/TimeSpendReport\n// define trong tracker package source (extends Task từ task package).\nexport const ISSUE_CLASS = classRef(\"tracker:class:Issue\");\nexport const MILESTONE_CLASS = classRef(\"tracker:class:Milestone\");\nexport const COMPONENT_CLASS = classRef(\"tracker:class:Component\");\nexport const PROJECT_CLASS = classRef(\"tracker:class:Project\");\nexport const ISSUE_STATUS_CLASS = classRef(\"tracker:class:IssueStatus\");\nexport const ISSUE_TEMPLATE_CLASS = classRef(\"tracker:class:IssueTemplate\");\nexport const TIME_SPEND_REPORT_CLASS = classRef(\"tracker:class:TimeSpendReport\"); // T-43: activity → tracker (verify runtime)\n\n// task (Task/TaskType/ProjectType — generic task model, tracker extends)\n// TaskType/ProjectType defined trong @hcengineering/task, import vào tracker.\n// Pi-huly đoán tracker pkg → sai domain.\nexport const TASK_TYPE_CLASS = classRef(\"task:class:TaskType\"); // T-43: tracker → task\nexport const PROJECT_TYPE_CLASS = classRef(\"task:class:ProjectType\"); // T-43: tracker → task\n// T-86 #121: Mixin doc + task.mixin.TaskTypeClass — UNVERIFIED (task pkg not\n// installed locally, không runtime self-host). Refs theo Huly naming convention\n// `<plugin>:<kind>:<Name>` (same convention verified core:space:Model, core:class:Space).\nexport const MIXIN_CLASS = classRef(\"core:class:Mixin\");\nexport const TASK_TYPE_MIXIN = classRef(\"task:mixin:TaskTypeClass\");\nexport const CLASSIFIER_KIND_MIXIN = 2; // ClassifierKind.MIXIN (numeric enum)\nexport const MODEL_LABEL_PREFIX = \"embedded:embedded:\"; // getEmbeddedLabel() format\n\n// Document / Teamspace / DocumentSnapshot — T-65 (2026-07-28): SUPERSEDES\n// T-58 interface-orphan conclusion. Real class registered trong\n// `@hcengineering/document` plugin() (KHÔNG phải tracker). T-58 audited chỉ\n// tracker package + missed document package. Verified vs trusted huly-mcp v0.45\n// (`/tmp/huly-mcp-trusted/src/huly/huly-plugins.ts` loads\n// `@hcengineering/document` → `documentPlugin.class.{Document,Teamspace,\n// DocumentSnapshot}`). Server-side: standard Huly installation bundles document\n// plugin → string ref resolves. Pi-huly dùng string literal (giống tất cả class\n// khác) — KHÔNG cần load plugin client-side (server resolves class by string).\nexport const DOCUMENT_CLASS = classRef(\"document:class:Document\"); // T-65: tracker → document pkg\nexport const TEAMSPACE_CLASS = classRef(\"document:class:Teamspace\"); // T-65: expose (từ document pkg)\nexport const DOCUMENT_SNAPSHOT_CLASS = classRef(\"document:class:DocumentSnapshot\");\n\n// Teamspace create refs (T-78): verified runtime = plain string literals\n// (plugin() factory prefixes `<pluginId>:<category>:<name>`). KHÔNG cần bundle\n// document plugin — same string-literal pattern as class refs.\nexport const TEAMSPACE_ICON = \"document:icon:Teamspace\";\nexport const DEFAULT_TEAMSPACE_TYPE = \"document:spaceType:DefaultTeamspaceType\";\n// T-doc-parent: top-level Document parent marker. Web Documents tree query\n// top-level = { parent: \"document:ids:NoParent\" }. Doc KHÔNG set field này (absent)\n// hay set \"\" → bị loại khỏi sidebar tree (chỉ search thấy). = documentPlugin.ids.NoParent.\n// Verified vs doc thật (Home trong \"Mattermost Payment Design Docs\") + huly-mcp createDocument.\nexport const DOCUMENT_NO_PARENT = \"document:ids:NoParent\";\n// Top-level spaces (Teamspace/Drive/Project) dùng core.space.Space làm parent.\nexport const SPACE_PARENT = spaceRef(\"core:space:Space\");\n\n// Space — base abstract class trong @hcengineering/core.\n// READ-ONLY SAFE: findAll/findOne trên SPACE_CLASS trả subclasses qua inheritance\n// (list_teamspaces/get_teamspace OK cross all space types). T-66 sẽ switch\n// list_teamspaces sang TEAMSPACE_CLASS (chỉ trả Teamspace, không lẫn Project/\n// Drive/ChunterSpace).\nexport const SPACE_CLASS = classRef(\"core:class:Space\");\n// T-54: drive:class:Drive = Documents/Files Teamspace thật (extends TypedSpace,\n// có SpaceTypeDescriptor). Register trong drive plugin() class block line 31.\nexport const DRIVE_CLASS = classRef(\"drive:class:Drive\");\n\n// T-67 (2026-07-28): refs cho create_* AttachedDoc + Project Type.\n// Huly convention <plugin>:<category>:<key> (giống class refs).\n// NoParent = empty ref sentinel (trusted issues-parent.ts:21 tracker.ids.NoParent=\"\").\nexport const NO_PARENT_REF = idRef(\"\");\n// Issue.kind = tracker.taskTypes.Issue (trusted issues-write.ts:168).\nexport const ISSUE_KIND_REF = classRef(\"tracker:taskTypes:Issue\");\n// Project.type (TypedSpace) = tracker.ids.ClassingProjectType (trusted projects.ts:185).\nexport const CLASSIC_PROJECT_TYPE_REF = classRef(\"tracker:ids:ClassingProjectType\");\n\n// chunter (Comments = ChatMessage)\nexport const CHAT_MESSAGE_CLASS = classRef(\"chunter:class:ChatMessage\");\n\n// attachment (Attachments)\nexport const ATTACHMENT_CLASS = classRef(\"attachment:class:Attachment\");\n\n// tags (TagElement = entity thật, NOT \"Tag\")\n// Huly thiết kế: TagElement = tag entity, TagReference = ref trong doc, TagCategory = group.\nexport const TAG_CLASS = classRef(\"tags:class:TagElement\"); // T-43: Tag → TagElement\nexport const TAG_REFERENCE_CLASS = classRef(\"tags:class:TagReference\"); // T-69: AttachedDoc cho tag attachments\nexport const TAG_CATEGORY_CLASS = classRef(\"tags:class:TagCategory\");\n\n// T-73: core.space.Model = root model space (workflow docs IssueStatus/TaskType\n// live here, KHÔNG project space). Verified trusted task-management.ts.\nexport const MODEL_SPACE = spaceRef(\"core:space:Model\");\n\n// T-81 #104: Status base class (task.class.Status alias core.class.Status).\n// Trusted issues-shared.ts:281 resolve statuses qua core.class.Status + batch $in\n// (KHÔNG findOne IssueStatus per ref — \"can fail on some workspaces\").\nexport const STATUS_CLASS = classRef(\"core:class:Status\");\n\n// T-73: StatusCategory Ref<StatusCategory> map (5 values, format task:statusCategory:<Key>).\n// IssueStatus.category = Ref<StatusCategory> (KHÔNG enum string). Verified T-71 + trusted.\nexport const STATUS_CATEGORY_REFS: Record<string, string> = {\n  UnStarted: \"task:statusCategory:UnStarted\",\n  ToDo: \"task:statusCategory:ToDo\",\n  Active: \"task:statusCategory:Active\",\n  Won: \"task:statusCategory:Won\",\n  Lost: \"task:statusCategory:Lost\",\n};\n\n// T-73: IssueStatus.ofAttribute required field (Ref<Attribute<Status>>).\n// Trusted hardcodes tracker.attribute.IssueStatus cho issue statuses.\nexport const ISSUE_STATUS_ATTRIBUTE = \"tracker:attribute:IssueStatus\";\n\n// view — T-58 DEEP-AUDIT: Label KHÔNG tồn tại trong 12 packages (0 match).\n// Deprecated — Huly dùng TagElement (tags:class:TagElement) cho tag/label entity.\n// Labels tools refactor dùng TAG_CLASS (T-45 pattern đã verify).\nexport const LABEL_CLASS = classRef(\"view:class:Label\");\n\n// time (ToDo — chữ viết hoa D, NOT \"Todo\")\n// ToDo extends AttachedDoc, define trong @hcengineering/time (KHÔNG phải task).\nexport const TODO_CLASS = classRef(\"time:class:ToDo\"); // T-43: task:Todo → time:ToDo\n// T-79 #102: ProjectToDo = subclass cho issue-attached todo (KHÔNG base ToDo).\n// Verified trusted huly-mcp planner.ts: createIssueTodo dùng time.class.ProjectToDo.\nexport const PROJECT_TODO_CLASS = classRef(\"time:class:ProjectToDo\");\n// T-79 #102: shared space cho mọi todo (KHÔNG issue.space). Trusted planner.ts:141.\nexport const TODOS_SPACE = spaceRef(\"time:space:ToDos\");\n// T-93b #139: workspace ROOT space cho workspace-global docs (TagCategory).\n// Probe live: 25 tag-categories đều space=\"core:space:Workspace\". Trước đây\n// create_tag_category dùng spaceRef(tctx.workspace) (handle string) → orphan.\nexport const WORKSPACE_SPACE = spaceRef(\"core:space:Workspace\");\n\n// T-59 (2026-07-28): TS_RELATION_CLASS XÓA — Issue relations KHÔNG phải class\n// riêng. Issue.relations?: RelatedDocument[] + Issue.blockedBy?: RelatedDocument[]\n// inline (RelatedDocument = Pick<Doc, '_id' | '_class'>). add/remove/list dùng\n// $push/$pull trực tiếp trên Issue, KHÔNG addCollection.\n","// Common typebox schemas cho domain tools — tránh lặp.\n// 06-api.md §2 Common Parameters Convention.\n\nimport { Type, type TObject, type TOptional, type TString, type TInteger } from \"typebox\";\nimport type { Class, Doc, DocumentUpdate, Ref, Space, TxResult } from \"@hcengineering/api-client\";\nimport type { HulyClient } from \"../../client/client.js\";\nimport type { HulyToolResult } from \"../builder.js\";\nimport { PROJECT_CLASS, PROJECT_TYPE_CLASS, STATUS_CLASS } from \"./_class-refs.js\";\n\n/** Workspace override param (mọi tool). */\nexport const workspaceParam: TOptional<TString> = Type.Optional(\n  Type.String({\n    description: \"Workspace id-handle override (default: cwd-map).\",\n  }),\n);\n\n/** Project override param (project-scoped tools). */\nexport const projectParam: TOptional<TString> = Type.Optional(\n  Type.String({\n    description: \"Huly project identifier (vd PD). Default: cwd-map.\",\n  }),\n);\n\n/** Limit param (list tools). Default service-side, pi truncate 50KB/2000 lines. */\nexport const limitParam: TOptional<TInteger> = Type.Optional(\n  Type.Integer({ description: \"Max results (default: 50).\", minimum: 1 }),\n);\n\n/** Identifier param (issue). vd \"PD-123\" HOẶC raw num. */\nexport const identifierParam = Type.String({\n  description: 'Issue identifier (vd \"PD-123\") hoặc raw number.',\n});\n\n/** Priority enum (create/update issue). */\nexport const prioritySchema = Type.Optional(\n  Type.Union([\n    Type.Literal(\"urgent\"),\n    Type.Literal(\"high\"),\n    Type.Literal(\"medium\"),\n    Type.Literal(\"low\"),\n    Type.Literal(\"no-priority\"),\n  ]),\n);\n\n/** statusCategory enum (list/update issue, derived). */\nexport const statusCategorySchema = Type.Optional(\n  Type.Union([\n    Type.Literal(\"UnStarted\"),\n    Type.Literal(\"ToDo\"),\n    Type.Literal(\"Active\"),\n    Type.Literal(\"Won\"),\n    Type.Literal(\"Lost\"),\n  ]),\n);\n\n/** Base params mọi tool có: workspace?. */\nexport function baseParams(): TObject {\n  return Type.Object({ workspace: workspaceParam });\n}\n\n/**\n * Project base params: workspace? + project?.\n * Domain tool extend thêm field riêng.\n */\nexport function projectParams(): TObject {\n  return Type.Object({ workspace: workspaceParam, project: projectParam });\n}\n\n/**\n * Resolve issue identifier: \"<PROJ>-<num>\" → as-is; raw num → \"<project>-<num>\".\n * Huly identifier format. Vd \"PD-123\" hoặc \"123\" (project=PD).\n *\n * Cross-project guard: nếu input có prefix \"<X>-<num>\" mà X != project →\n * throw Error (KHÔNG silently query sai project). Caller catch → isError.\n */\n/**\n * T-71: Resolve project _id (= space cho AttachedDoc scoping) từ identifier.\n * Project._id === Project.space (self-ref — T-67 confirmed). Trả undefined nếu\n * project không tồn tại (caller → isError).\n */\nexport async function getProjectSpace(\n  client: HulyClient,\n  projectIdentifier: string,\n): Promise<string | undefined> {\n  const project = await client.findOne(PROJECT_CLASS, { identifier: projectIdentifier });\n  return project?._id;\n}\n\n/**\n * T-71: Resolve IssueStatus docs cho project qua ProjectType.statuses traversal.\n * Flow: Project → project.type (Ref<ProjectType>) → ProjectType.statuses\n * (Ref<IssueStatus>[]) → resolve docs. Trả {statuses, defaultStatusId}.\n *\n * category Ref<StatusCategory> → enum key (strip `*:statusCategory:` prefix).\n * isDefault = status._id === project.defaultIssueStatus.\n */\nexport async function getProjectStatuses(\n  client: HulyClient,\n  projectIdentifier: string,\n): Promise<\n  | { statuses: Array<{ _id: string; name: string; category: string; isDefault: boolean }> }\n  | undefined\n> {\n  const project = await client.findOne(PROJECT_CLASS, {\n    identifier: projectIdentifier,\n  } as never);\n  if (!project) return undefined;\n  const projectTypeRef = (project as { type?: string }).type;\n  if (!projectTypeRef) return { statuses: [] };\n  const projectType = await client.findOne(PROJECT_TYPE_CLASS, { _id: projectTypeRef } as never);\n  // ProjectType.statuses = ProjectStatus[] (objects {_id: Ref<Status>, taskType, ...}),\n  // KHÔNG Ref[] — extract ._id trước (trusted issues-shared.ts:157 .map(s => s._id)).\n  const rawStatuses =\n    (projectType as { statuses?: Array<{ _id?: string }> } | null)?.statuses ?? [];\n  const statusRefs = rawStatuses\n    .map((s) => s._id)\n    .filter((r): r is string => typeof r === \"string\");\n  const defaultStatusId = (project as { defaultIssueStatus?: string }).defaultIssueStatus ?? \"\";\n  // T-81 #104: resolve statuses qua core.class.Status + batch $in (KHÔNG\n  // findOne IssueStatus per ref N+1 — trusted né: \"can fail on some workspaces\").\n  let statuses: Array<{ _id: string; name: string; category: string; isDefault: boolean }> = [];\n  if (statusRefs.length > 0) {\n    const statusDocs = (await client.findAll(STATUS_CLASS, {\n      _id: { $in: statusRefs },\n    } as never)) as Array<{ _id?: string; name?: string; category?: string }>;\n    statuses = statusRefs\n      .map((ref) => {\n        const s = statusDocs.find((d) => d._id === ref);\n        if (!s) return null;\n        const rawCat = s.category ?? \"\";\n        return {\n          _id: ref,\n          name: s.name ?? \"\",\n          category: rawCat.split(\":\").pop() ?? rawCat,\n          isDefault: ref === defaultStatusId,\n        };\n      })\n      .filter(\n        (x): x is { _id: string; name: string; category: string; isDefault: boolean } => x !== null,\n      );\n  }\n  return { statuses };\n}\n\nexport function resolveIdentifier(project: string, identifier: string): string {\n  if (/^\\d+$/.test(identifier)) {\n    return `${project}-${identifier}`;\n  }\n  // Check cross-project: input \"FOO-5\" nhưng tool scoped ở \"PD\"\n  const m = /^([A-Za-z]+)-(\\d+)$/.exec(identifier);\n  if (m && m[1] !== project) {\n    throw new Error(\n      `Cross-project identifier not allowed: \"${identifier}\" (tool scoped to project \"${project}\")`,\n    );\n  }\n  return identifier;\n}\n\n/**\n * Escape SQL LIKE wildcards (% _ \\) trong search pattern — tránh injection.\n * Huly $like dùng PostgreSQL LIKE semantics.\n */\nexport function escapeLikePattern(s: string): string {\n  return s.replace(/[\\\\%_]/g, (c) => `\\\\${c}`);\n}\n\n/**\n * Parse Huly markup JSON safe — return null nếu content không phải JSON markup\n * (plain text cũ HOẶC rỗng). Caller fallback về raw content.\n *\n * Huly content field có thể là:\n *   - JSON markup string (mới): `'{\"type\":\"doc\",...}'`\n *   - Plain text (cũ): `\"hello\"`\n *   - Empty: `\"\"`\n */\nexport function parseMarkupSafe(content: unknown): unknown {\n  if (typeof content !== \"string\" || content.length === 0) return null;\n  if (!content.startsWith(\"{\")) return null;\n  try {\n    return JSON.parse(content);\n  } catch {\n    return null;\n  }\n}\n\n// === T-63 #68: safeUpdateDoc / safeRemoveDoc — schema drift guard ===\n//\n// Khi tool gọi `client.updateDoc(_class, space, objectId, ops)` / `removeDoc(...)`\n// với `space` HOẶC `objectId` là `undefined` (data corruption, partial import,\n// schema drift), Huly server KHÔNG throw mà **skip silently** transaction\n// (ModelDb tìm doc theo `_id + space` không match) → update KHÔNG persist\n// (silent data loss, giống bug #36/#40 đã fix T-47/T-50).\n//\n// Helper centralize pattern T-50 (workspace.ts:155-173 — schema drift guard):\n// nhận doc ĐÃ LOOKUP (KHÔNG nhận space/objectId riêng — ép caller lấy từ doc),\n// tự extract `.space` / `._id` + guard undefined → return isError rõ ràng\n// (KHÔNG gửi updateDoc). Migration 42 call site sang helper (audit hardening).\n//\n// Discriminated union return: caller pattern:\n//   const result = await safeUpdateDoc(client, CLASS, doc, ops);\n//   if (!result.ok) return result.error; // isError sẵn sàng return cho LLM\n//   // result.result = TxResult\n\n/** Result khi guard pass — gọi updateDoc/removeDoc thành công. */\ntype SafeWriteOk = { ok: true; result: TxResult };\n/** Result khi guard fail — schema drift, KHÔNG gửi write. */\ntype SafeWriteErr = { ok: false; error: HulyToolResult };\n\n/**\n * Build error result cho schema drift guard. Message include _class + docId\n * (nếu có) cho debug. Details structured cho render.\n */\nfunction schemaDriftError(\n  _class: string,\n  doc: unknown,\n  missingField: \"space\" | \"_id\",\n): HulyToolResult {\n  const docId =\n    typeof doc === \"object\" && doc !== null ? (doc as { _id?: unknown })._id : undefined;\n  return {\n    content:\n      `Cannot update ${_class}: doc record missing \"${missingField}\" field (schema drift). ` +\n      `Update skipped to prevent silent no-op.`,\n    isError: true,\n    details: {\n      _class,\n      docId,\n      missingField,\n      ...(typeof doc === \"object\" && doc !== null ? { docRecord: doc } : {}),\n    },\n  };\n}\n\n/**\n * Validate doc có `.space` + `._id` field (string/ref). Return extracted hoặc\n * undefined nếu schema drift.\n */\nfunction extractDocRefs(\n  doc: unknown,\n): { space: Ref<Space>; objectId: string } | { missing: \"space\" | \"_id\" } {\n  if (typeof doc !== \"object\" || doc === null || Array.isArray(doc)) {\n    return { missing: \"space\" }; // doc không hợp lệ → guard space first\n  }\n  const d = doc as { space?: unknown; _id?: unknown };\n  if (d.space === undefined || d.space === null) return { missing: \"space\" };\n  if (d._id === undefined || d._id === null) return { missing: \"_id\" };\n  return { space: d.space as Ref<Space>, objectId: d._id as string };\n}\n\n/**\n * safeUpdateDoc — updateDoc với schema drift guard.\n *\n * @param client HulyClient đã kết nối\n * @param _class Class ref (vd tracker:class:Issue)\n * @param doc Doc ĐÃ LOOKUP (caller findOne trước). Helper extract .space/._id.\n * @param operations DocumentUpdate ops\n * @returns Discriminated union: ok → TxResult | !ok → isError result (return thẳng)\n *\n * Pattern T-50 (workspace.ts:155-173) centralized.\n */\nexport async function safeUpdateDoc<T extends Doc>(\n  client: HulyClient,\n  _class: Ref<Class<T>>,\n  doc: unknown,\n  operations: DocumentUpdate<T>,\n): Promise<SafeWriteOk | SafeWriteErr> {\n  const refs = extractDocRefs(doc);\n  if (\"missing\" in refs) {\n    return { ok: false, error: schemaDriftError(_class as string, doc, refs.missing) };\n  }\n  const result = await client.updateDoc(\n    _class,\n    refs.space,\n    refs.objectId as Ref<T>,\n    operations as never,\n  );\n  return { ok: true, result };\n}\n\n/**\n * safeRemoveDoc — removeDoc với schema drift guard.\n *\n * @param client HulyClient đã kết nối\n * @param _class Class ref\n * @param doc Doc ĐÃ LOOKUP. Helper extract .space/._id.\n * @returns Discriminated union: ok → TxResult | !ok → isError result\n */\nexport async function safeRemoveDoc<T extends Doc>(\n  client: HulyClient,\n  _class: Ref<Class<T>>,\n  doc: unknown,\n): Promise<SafeWriteOk | SafeWriteErr> {\n  const refs = extractDocRefs(doc);\n  if (\"missing\" in refs) {\n    return { ok: false, error: schemaDriftError(_class as string, doc, refs.missing) };\n  }\n  const result = await client.removeDoc(_class, refs.space, refs.objectId as Ref<T>);\n  return { ok: true, result };\n}\n","// tools/domains/workspace.ts — workspace + profile domain (5 tools).\n// Design: 04-system.md §6 (19 domain modules), 06-api.md §4 (Workspace/profile).\n//\n// Tools (5):\n//   1. huly_get_workspace_info      — workspace name/url (current)\n//   2. huly_list_workspaces         — T-74 honest-unavailable (account-client)\n//   3. huly_list_workspace_members  — T-74 honest-unavailable (account-client)\n//   4. huly_get_user_profile        — current user (getCurrentUser passthrough)\n//   5. huly_update_user_profile     — update current user name\n//\n// _class refs: contact.class.Person + contact.mixin:Employee (string literal).\n\nimport { Type } from \"typebox\";\nimport { defineHulyTool, type HulyToolDefinition } from \"../builder.js\";\nimport { PERSON_CLASS } from \"./_class-refs.js\";\nimport { safeUpdateDoc } from \"./_common.js\";\n\nexport const tools: HulyToolDefinition[] = [\n  // 1. get_workspace_info — workspace binding hiện tại\n  defineHulyTool({\n    name: \"get_workspace_info\",\n    label: \"Get workspace info\",\n    description: \"Get current workspace info (id, resolved). Use để verify binding sau /huly init.\",\n    promptSnippet: \"Get current Huly workspace binding info.\",\n    parameters: Type.Object({\n      workspace: Type.Optional(\n        Type.String({\n          description: \"Workspace id-handle override (default: cwd-map).\",\n        }),\n      ),\n    }),\n    async handler(_params, tctx) {\n      return {\n        content: `Workspace: ${tctx.workspace}`,\n        details: { workspace: tctx.workspace },\n      };\n    },\n  }),\n\n  // 2. list_workspaces — T-74: honest-unavailable (needs account-client HTTP layer)\n  defineHulyTool({\n    name: \"list_workspaces\",\n    label: \"List workspaces\",\n    description:\n      \"UNAVAILABLE — needs AccountClient HTTP layer (pi-huly data-client only). \" +\n      \"Workspaces = account-level (WorkspaceInfoWithStatus), not workspace-model query. \" +\n      \"Deferred behind ADR (add @hcengineering/account-client dep).\",\n    promptSnippet: \"List Huly workspaces accessible by current user.\",\n    parameters: Type.Object({\n      workspace: Type.Optional(Type.String()),\n      limit: Type.Optional(Type.Integer({ minimum: 1 })),\n    }),\n    async handler(_params, _tctx) {\n      return {\n        content:\n          \"list_workspaces KHÔNG khả dụng: workspaces = account-level data requiring \" +\n          \"AccountClient HTTP layer (pi-huly currently bundles data-client ws only). \" +\n          \"Deferred behind ADR — add @hcengineering/account-client dep + WorkspaceClient \" +\n          \"wrapper (AccountClient.getUserWorkspaces).\",\n        isError: true,\n        details: { reason: \"account_client_layer_required\" },\n      };\n    },\n  }),\n\n  // 3. list_workspace_members — T-74: honest-unavailable (needs account-client for roles)\n  defineHulyTool({\n    name: \"list_workspace_members\",\n    label: \"List workspace members\",\n    description:\n      \"UNAVAILABLE — workspace members with roles = account-level data (AccountClient.getWorkspaceMembers). \" +\n      \"Use huly_list_employees for employee data (data-client). Deferred behind ADR.\",\n    promptSnippet: \"List Huly workspace members.\",\n    parameters: Type.Object({\n      workspace: Type.Optional(Type.String()),\n      limit: Type.Optional(Type.Integer({ minimum: 1 })),\n    }),\n    async handler(_params, _tctx) {\n      return {\n        content:\n          \"list_workspace_members KHÔNG khả dụng: workspace members with roles = \" +\n          \"account-level data (AccountClient.getWorkspaceMembers, HTTP). Use \" +\n          \"huly_list_employees for employee data via data-client ws. Deferred behind ADR.\",\n        isError: true,\n        details: { reason: \"account_client_layer_required\", alternative: \"huly_list_employees\" },\n      };\n    },\n  }),\n\n  // 4. get_user_profile — current user (passthrough getCurrentUser)\n  defineHulyTool({\n    name: \"get_user_profile\",\n    label: \"Get user profile\",\n    description: \"Get current user profile (id, name, email) — default assignee source.\",\n    promptSnippet: \"Get current Huly user profile.\",\n    parameters: Type.Object({\n      workspace: Type.Optional(Type.String()),\n    }),\n    async handler(_params, tctx) {\n      return {\n        content: `User: ${tctx.currentUser.name} <${tctx.currentUser.email}> (id: ${tctx.currentUser.id})`,\n        details: { user: tctx.currentUser },\n      };\n    },\n  }),\n\n  // 5. update_user_profile — update current user name (firstName/lastName)\n  defineHulyTool({\n    name: \"update_user_profile\",\n    label: \"Update user profile\",\n    description:\n      'Update current user name (firstName/lastName → Huly \"LastName,FirstName\" format). ' +\n      \"Bio/city/socialLinks honest-unavailable (account-client ADR pending).\",\n    promptSnippet: \"Update current Huly user profile.\",\n    parameters: Type.Object({\n      workspace: Type.Optional(Type.String()),\n      firstName: Type.Optional(Type.String({ description: \"First name.\" })),\n      lastName: Type.Optional(Type.String({ description: \"Last name.\" })),\n    }),\n    async handler(params, tctx) {\n      // T-82 #105: Huly Person.name = \"LastName,FirstName\" (trusted persons.ts:65).\n      // Trước đây ghi raw params.name → phá format. Nay tách firstName/lastName +\n      // formatName. Partial update: parse current name, giữ field không truyền.\n      if (params.firstName === undefined && params.lastName === undefined) {\n        return {\n          content: \"No fields to update.\",\n          details: { updated: false },\n        };\n      }\n      // T-103 #157: Person linked to account qua `personUuid` field (= account.uuid\n      // = currentUser.id). Lookup-by-_id fail (Person._id = generated id, KHÔNG\n      // uuid). Channel(email) cũng KHÔNG reliable (numeric socialId). personUuid\n      // là canonical account→Person link.\n      const person = await tctx.client.findOne(PERSON_CLASS, {\n        personUuid: tctx.currentUser.id,\n      } as never);\n      if (!person) {\n        return {\n          content: `Person for current user (uuid ${tctx.currentUser.id}) not found. Cannot update profile.`,\n          isError: true,\n          details: { userId: tctx.currentUser.id },\n        };\n      }\n      const current = parsePersonName((person as { name?: string }).name);\n      const newFirst = params.firstName ?? current.firstName;\n      const newLast = params.lastName ?? current.lastName;\n      const operations: Record<string, unknown> = {\n        name: `${newLast},${newFirst}`,\n      };\n      const result = await safeUpdateDoc(tctx.client, PERSON_CLASS, person, operations);\n      if (!result.ok) return result.error;\n      return {\n        content: `Updated profile name: ${newLast},${newFirst}`,\n        details: { updated: true, fields: [\"name\"], name: `${newLast},${newFirst}` },\n      };\n    },\n  }),\n];\n\n/**\n * T-82 #105: parse Huly Person.name \"LastName,FirstName\" → {firstName, lastName}.\n * Port trusted persons.ts:67 parseName.\n */\nfunction parsePersonName(name: string | undefined): { firstName: string; lastName: string } {\n  if (name === undefined) return { firstName: \"\", lastName: \"\" };\n  const comma = name.indexOf(\",\");\n  if (comma !== -1) {\n    return { firstName: name.slice(comma + 1), lastName: name.slice(0, comma) };\n  }\n  return { firstName: name, lastName: \"\" };\n}\n","// tools/domains/projects.ts — Projects domain (6 tools).\n// Design: 06-api.md §4 Projects. CRUD projects + list_statuses.\n//\n// Tools (6, FR-04 D4):\n//   1. huly_list_projects          — list trong workspace (project-scoped)\n//   2. huly_get_project            — get by identifier\n//   3. huly_create_project         — {name, identifier} → {identifier}\n//   4. huly_update_project         — update name/description\n//   5. huly_delete_project         — destructive, confirm gate\n//   6. huly_list_statuses          — workflow statuses cho project\n\nimport { Type } from \"typebox\";\nimport { defineHulyTool, type HulyToolDefinition } from \"../builder.js\";\nimport { PROJECT_CLASS, CLASSIC_PROJECT_TYPE_REF } from \"./_class-refs.js\";\nimport {\n  workspaceParam,\n  projectParam,\n  safeUpdateDoc,\n  safeRemoveDoc,\n  getProjectStatuses,\n} from \"./_common.js\";\n\nexport const tools: HulyToolDefinition[] = [\n  // 1. list_projects\n  defineHulyTool({\n    name: \"list_projects\",\n    label: \"List projects\",\n    description: \"List Huly projects trong workspace.\",\n    promptSnippet: \"List Huly projects.\",\n    parameters: Type.Object({\n      workspace: workspaceParam,\n      includeArchived: Type.Optional(\n        Type.Boolean({ description: \"Include archived projects (default false).\" }),\n      ),\n    }),\n    async handler(params, tctx) {\n      // T-81G #107: archived-filter default (exclude archived) + sort name asc.\n      const query: Record<string, unknown> =\n        params.includeArchived === true ? {} : { archived: { $ne: true } };\n      const projects = await tctx.client.findAll(PROJECT_CLASS, query as never, {\n        sort: { name: 1 },\n      });\n      const list = projects.map((p) => ({\n        identifier: (p as { identifier?: string }).identifier ?? \"\",\n        name: (p as { name?: string }).name ?? \"\",\n        description: (p as { description?: string }).description,\n        archived: (p as { archived?: boolean }).archived === true,\n        total: (p as { sequence?: number }).sequence ?? 0,\n      }));\n      return {\n        content: `Found ${list.length} project(s): ${list.map((p) => p.identifier).join(\", \")}`,\n        details: { count: list.length, projects: list },\n      };\n    },\n  }),\n\n  // 2. get_project\n  defineHulyTool({\n    name: \"get_project\",\n    label: \"Get project\",\n    description: \"Get Huly project by identifier.\",\n    promptSnippet: \"Get Huly project details.\",\n    needsProject: true,\n    parameters: Type.Object({ workspace: workspaceParam, project: projectParam }),\n    async handler(_params, tctx) {\n      const project = await tctx.client.findOne(PROJECT_CLASS, {\n        identifier: tctx.project,\n      });\n      if (!project) {\n        return {\n          content: `Project \"${tctx.project}\" not found.`,\n          isError: true,\n          details: { project: tctx.project, found: false },\n        };\n      }\n      const projFields = project as {\n        identifier?: string;\n        name?: string;\n        description?: string;\n        archived?: boolean;\n      };\n      // T-81G #107: inline defaultStatus + statuses[] (convenience — avoid extra\n      // list_statuses call). getProjectStatuses resolves qua core.class.Status.\n      const statusResult = await getProjectStatuses(tctx.client, tctx.project!);\n      const statuses = statusResult?.statuses ?? [];\n      const defaultStatus = statuses.find((s) => s.isDefault)?.name;\n      return {\n        content: `Project ${projFields.identifier}: ${projFields.name ?? \"\"}`,\n        details: {\n          identifier: projFields.identifier,\n          name: projFields.name,\n          description: projFields.description,\n          archived: projFields.archived ?? false,\n          defaultStatus,\n          statuses: statuses.map((s) => ({ name: s.name, category: s.category })),\n        },\n      };\n    },\n  }),\n\n  // 3. create_project\n  defineHulyTool({\n    name: \"create_project\",\n    label: \"Create project\",\n    description:\n      \"Create Huly project. Idempotent (findOne by identifier trước). Returns identifier.\",\n    promptSnippet: \"Create a new Huly project.\",\n    parameters: Type.Object({\n      workspace: workspaceParam,\n      name: Type.String({ description: \"Project name.\" }),\n      identifier: Type.String({\n        description: \"1-5 chars uppercase, start with letter.\",\n        minLength: 1,\n        maxLength: 5,\n      }),\n      description: Type.Optional(Type.String()),\n    }),\n    async handler(params, tctx) {\n      // T-67 #75: idempotent — findOne by identifier trước (spec §9).\n      const existing = await tctx.client.findOne(PROJECT_CLASS, {\n        identifier: params.identifier,\n      });\n      if (existing) {\n        return {\n          content: `Project ${params.identifier} (${(existing as { name?: string }).name ?? \"\"}) đã tồn tại.`,\n          details: { identifier: params.identifier, id: existing._id, idempotent: true },\n        };\n      }\n      // T-67 #75: Project = TypedSpace, self-ref space (project._id = own space).\n      // Required fields: type (SpaceType), members/owners, sequence:0,\n      // defaultIssueStatus:\"\" (placeholder), defaultTimeReportDay:\"CurrentWorkDay\".\n      const projectId = `tracker:project.${Math.random().toString(36).slice(2, 14)}`;\n      const id = await tctx.client.createDoc(\n        PROJECT_CLASS,\n        projectId as never, // self-ref space\n        {\n          name: params.name,\n          identifier: params.identifier,\n          description: params.description ?? \"\",\n          private: false,\n          archived: false,\n          members: [tctx.currentUser.id],\n          owners: [tctx.currentUser.id],\n          sequence: 0,\n          type: CLASSIC_PROJECT_TYPE_REF,\n          defaultIssueStatus: \"\", // placeholder — server resolve từ ProjectType statuses\n          defaultTimeReportDay: \"CurrentWorkDay\",\n        } as never,\n        projectId as never,\n      );\n      return {\n        content: `Created project ${params.identifier} (${params.name}).`,\n        details: { identifier: params.identifier, id },\n      };\n    },\n  }),\n\n  // 4. update_project\n  defineHulyTool({\n    name: \"update_project\",\n    label: \"Update project\",\n    description: \"Update Huly project (name, description).\",\n    needsProject: true,\n    parameters: Type.Object({\n      workspace: workspaceParam,\n      project: projectParam,\n      name: Type.Optional(Type.String()),\n      description: Type.Optional(Type.Union([Type.String(), Type.Null()])),\n    }),\n    async handler(params, tctx) {\n      const existing = await tctx.client.findOne(PROJECT_CLASS, {\n        identifier: tctx.project,\n      });\n      if (!existing) {\n        return {\n          content: `Project \"${tctx.project}\" not found.`,\n          isError: true,\n          details: { project: tctx.project },\n        };\n      }\n      const operations: Record<string, unknown> = {};\n      if (typeof params.name === \"string\") operations.name = params.name;\n      // T-81G #107: description=null → $unset clear.\n      if (params.description !== undefined) {\n        if (params.description === null) {\n          operations.$unset = { description: \"\" };\n        } else {\n          operations.description = params.description;\n        }\n      }\n      if (Object.keys(operations).length === 0) {\n        return { content: \"No fields to update.\", details: { updated: false } };\n      }\n      const updResult = await safeUpdateDoc(tctx.client, PROJECT_CLASS, existing, operations);\n      if (!updResult.ok) return updResult.error;\n      const fields = Object.keys(operations).filter((f) => f !== \"$unset\");\n      if (operations.$unset !== undefined) fields.push(\"description(clear)\");\n      return {\n        content: `Updated project ${tctx.project}: ${fields.join(\", \")}`,\n        details: { updated: true, fields },\n      };\n    },\n  }),\n\n  // 5. delete_project — destructive, confirm gate\n  defineHulyTool({\n    name: \"delete_project\",\n    label: \"Delete project\",\n    description: \"Delete Huly project (destructive — confirm gate).\",\n    promptSnippet: \"Delete a Huly project (asks confirmation).\",\n    destructive: true,\n    needsProject: true,\n    destructiveContext: (p) => ({\n      type: \"project\",\n      id: (p as { project?: string }).project ?? \"<unknown>\",\n    }),\n    parameters: Type.Object({ workspace: workspaceParam, project: projectParam }),\n    async handler(_params, tctx) {\n      const existing = await tctx.client.findOne(PROJECT_CLASS, {\n        identifier: tctx.project,\n      });\n      if (!existing) {\n        return {\n          content: `Project \"${tctx.project}\" not found.`,\n          isError: true,\n          details: { project: tctx.project },\n        };\n      }\n      const delResult = await safeRemoveDoc(tctx.client, PROJECT_CLASS, existing);\n      if (!delResult.ok) return delResult.error;\n      return {\n        content: `Deleted project ${tctx.project}.`,\n        details: { deleted: true, identifier: tctx.project },\n      };\n    },\n  }),\n\n  // 6. list_statuses\n  defineHulyTool({\n    name: \"list_statuses\",\n    label: \"List statuses\",\n    description: \"List workflow statuses cho project.\",\n    needsProject: true,\n    parameters: Type.Object({ workspace: workspaceParam, project: projectParam }),\n    async handler(_params, tctx) {\n      // T-71: ProjectType.statuses traversal (KHÔNG findAll global).\n      const result = await getProjectStatuses(tctx.client, tctx.project!);\n      if (!result) {\n        return {\n          content: `Project \"${tctx.project}\" not found.`,\n          isError: true,\n          details: { project: tctx.project },\n        };\n      }\n      const list = result.statuses.map((s) => ({\n        name: s.name,\n        category: s.category, // enum key (strip Ref prefix)\n        isDefault: s.isDefault,\n      }));\n      return {\n        content: `Found ${list.length} status(es).`,\n        details: { count: list.length, statuses: list },\n      };\n    },\n  }),\n];\n","// tools/domains/milestones.ts — Milestones domain (6 tools).\n// Design: 06-api.md §4 Milestones. CRUD + set_issue_milestone.\n//\n// Tools (6, FR-04 D4):\n//   1. huly_list_milestones        — list trong project\n//   2. huly_get_milestone          — get by id\n//   3. huly_create_milestone       — {project, label, description?, targetDate} → {id}\n//   4. huly_update_milestone       — update label/description/targetDate/status\n//   5. huly_set_issue_milestone    — gán issue → milestone\n//   6. huly_delete_milestone       — destructive\n\nimport { Type } from \"typebox\";\nimport { defineHulyTool, type HulyToolDefinition } from \"../builder.js\";\nimport { MILESTONE_CLASS, ISSUE_CLASS, PROJECT_CLASS } from \"./_class-refs.js\";\n\n/**\n * T-72 #80: MilestoneStatus enum (numeric) ↔ string map.\n * Verified T-67: Planned=0, InProgress=1, Completed=2, Canceled=3.\n */\nconst MILESTONE_STATUS_MAP: Record<string, number> = {\n  planned: 0,\n  \"in-progress\": 1,\n  completed: 2,\n  canceled: 3,\n};\nfunction stringToMilestoneStatus(s: string): number {\n  const v = MILESTONE_STATUS_MAP[s];\n  if (v === undefined) {\n    throw new Error(\n      `Invalid milestone status \"${s}\". Valid: ${Object.keys(MILESTONE_STATUS_MAP).join(\", \")}.`,\n    );\n  }\n  return v;\n}\n/** T-82 #105: reverse map number → string (READ path). T-72 chỉ fix write. */\nfunction milestoneStatusToString(n: unknown): string {\n  return Object.entries(MILESTONE_STATUS_MAP).find(([, v]) => v === n)?.[0] ?? \"planned\";\n}\nimport {\n  workspaceParam,\n  projectParam,\n  identifierParam,\n  resolveIdentifier,\n  safeUpdateDoc,\n  safeRemoveDoc,\n  getProjectSpace,\n} from \"./_common.js\";\n\nexport const tools: HulyToolDefinition[] = [\n  // 1. list_milestones\n  defineHulyTool({\n    name: \"list_milestones\",\n    label: \"List milestones\",\n    description: \"List milestones trong project.\",\n    needsProject: true,\n    parameters: Type.Object({ workspace: workspaceParam, project: projectParam }),\n    async handler(_params, tctx) {\n      // T-71: space scoping (KHÔNG findAll global cross-project).\n      const space = await getProjectSpace(tctx.client, tctx.project!);\n      if (!space) {\n        return {\n          content: `Project \"${tctx.project}\" not found.`,\n          isError: true,\n          details: { project: tctx.project },\n        };\n      }\n      const milestones = await tctx.client.findAll(\n        MILESTONE_CLASS,\n        { space } as never,\n        // T-82G #108: sort modifiedOn desc.\n        { sort: { modifiedOn: -1 } } as never,\n      );\n      const list = milestones.map((m) => ({\n        id: m._id,\n        label: (m as { label?: string }).label ?? \"\",\n        // T-82 #105: status READ trả string (KHÔNG raw number — dead `?? \"planned\"`\n        // before fix vì 0 không nullish).\n        status: milestoneStatusToString((m as { status?: number }).status),\n        targetDate: (m as { targetDate?: number }).targetDate,\n      }));\n      return {\n        content: `Found ${list.length} milestone(s).`,\n        details: { count: list.length, milestones: list },\n      };\n    },\n  }),\n\n  // 2. get_milestone\n  defineHulyTool({\n    name: \"get_milestone\",\n    label: \"Get milestone\",\n    description: \"Get milestone by id.\",\n    needsProject: true,\n    parameters: Type.Object({\n      workspace: workspaceParam,\n      project: projectParam,\n      milestone: Type.String({ description: \"Milestone id.\" }),\n    }),\n    async handler(params, tctx) {\n      // T-100 (#146): scope milestone lookup theo project space (mirror components.ts T-81).\n      const space = await getProjectSpace(tctx.client, tctx.project!);\n      if (!space) {\n        return {\n          content: `Project \"${tctx.project}\" not found.`,\n          isError: true,\n          details: { project: tctx.project },\n        };\n      }\n      const m = await tctx.client.findOne(MILESTONE_CLASS, {\n        _id: params.milestone,\n        space,\n      } as never);\n      if (!m) {\n        return {\n          content: `Milestone \"${params.milestone}\" not found.`,\n          isError: true,\n          details: { milestone: params.milestone },\n        };\n      }\n      const ms = m as {\n        label?: string;\n        status?: number;\n        targetDate?: number;\n        description?: string | null;\n        space?: string;\n        modifiedOn?: number;\n        createdOn?: number;\n      };\n      // T-82G #108: description → markdown (fetchMarkup).\n      let description: string | undefined;\n      if (ms.description) {\n        try {\n          const markup = await tctx.client.fetchMarkup(\n            MILESTONE_CLASS,\n            m._id,\n            \"description\",\n            ms.description,\n            \"markdown\",\n          );\n          description = typeof markup === \"string\" ? markup : undefined;\n        } catch {\n          description = undefined;\n        }\n      }\n      return {\n        content: `Milestone ${ms.label ?? \"\"}`,\n        details: {\n          id: m._id,\n          label: ms.label,\n          // T-82 #105: status READ trả string (KHÔNG raw number).\n          status: milestoneStatusToString(ms.status),\n          targetDate: ms.targetDate,\n          // T-82G #108: add description (markdown), project (=space), modifiedOn, createdOn.\n          description,\n          project: ms.space,\n          modifiedOn: ms.modifiedOn,\n          createdOn: ms.createdOn,\n        },\n      };\n    },\n  }),\n\n  // 3. create_milestone\n  defineHulyTool({\n    name: \"create_milestone\",\n    label: \"Create milestone\",\n    description: \"Create milestone. targetDate BẮT BUỘC (Unix ms).\",\n    needsProject: true,\n    parameters: Type.Object({\n      workspace: workspaceParam,\n      project: projectParam,\n      label: Type.String(),\n      description: Type.Optional(Type.String()),\n      targetDate: Type.Integer({\n        description: \"Unix ms timestamp (BẮT BUỘC).\",\n      }),\n    }),\n    async handler(params, tctx) {\n      // T-103 #160: guard label non-empty.\n      if (params.label.trim() === \"\") {\n        return {\n          content: `create_milestone label must be non-empty.`,\n          isError: true,\n          details: { label: params.label },\n        };\n      }\n      const project = await tctx.client.findOne(PROJECT_CLASS, {\n        identifier: tctx.project,\n      });\n      // T-51 #41: project null → isError rõ ràng, KHÔNG fallback workspace.\n      if (!project) {\n        return {\n          content: `Project \"${tctx.project}\" not found. Run /huly init or check binding.`,\n          isError: true,\n          details: { project: tctx.project },\n        };\n      }\n      // T-97 (#143): space = project._id (KHÔNG project.space — T-67 assumption sai).\n      // T-103 #162: description = MarkupBlobRef. Pre-gen id → uploadMarkup ref\n      // (mirror create_component/create_issue). Trước đây push raw string.\n      const msId = `${MILESTONE_CLASS as string}.${Math.random().toString(36).slice(2, 12)}`;\n      let descriptionRef: unknown = null;\n      if (params.description && params.description.trim() !== \"\") {\n        descriptionRef = await tctx.client.uploadMarkup(\n          MILESTONE_CLASS,\n          msId,\n          \"description\",\n          params.description,\n          \"markdown\",\n        );\n      }\n      const id = await tctx.client.createDoc(\n        MILESTONE_CLASS,\n        project._id as never,\n        {\n          label: params.label,\n          description: descriptionRef,\n          targetDate: params.targetDate,\n          // T-67 #75: MilestoneStatus.Planned = 0 (numeric enum, KHÔNG phải string).\n          status: 0,\n        },\n        msId as never,\n      );\n      return {\n        content: `Created milestone \"${params.label}\".`,\n        details: { id, label: params.label },\n      };\n    },\n  }),\n\n  // 4. update_milestone\n  defineHulyTool({\n    name: \"update_milestone\",\n    label: \"Update milestone\",\n    description: \"Update milestone (label, description, targetDate, status).\",\n    needsProject: true,\n    parameters: Type.Object({\n      workspace: workspaceParam,\n      project: projectParam,\n      milestone: Type.String(),\n      label: Type.Optional(Type.String()),\n      description: Type.Optional(Type.String()),\n      targetDate: Type.Optional(Type.Integer()),\n      status: Type.Optional(\n        Type.Union([\n          Type.Literal(\"planned\"),\n          Type.Literal(\"in-progress\"),\n          Type.Literal(\"completed\"),\n          Type.Literal(\"canceled\"),\n        ]),\n      ),\n    }),\n    async handler(params, tctx) {\n      // T-100 (#146): scope milestone lookup theo project space.\n      const space = await getProjectSpace(tctx.client, tctx.project!);\n      if (!space) {\n        return {\n          content: `Project \"${tctx.project}\" not found.`,\n          isError: true,\n          details: { project: tctx.project },\n        };\n      }\n      const m = await tctx.client.findOne(MILESTONE_CLASS, {\n        _id: params.milestone,\n        space,\n      } as never);\n      if (!m) {\n        return {\n          content: `Milestone \"${params.milestone}\" not found.`,\n          isError: true,\n          details: { milestone: params.milestone },\n        };\n      }\n      const ops: Record<string, unknown> = {};\n      if (params.label !== undefined) {\n        if (params.label.trim() === \"\")\n          return {\n            content: \"label must be non-empty.\",\n            isError: true,\n            details: { label: params.label },\n          };\n        ops.label = params.label;\n      }\n      // T-103 #162: description = MarkupBlobRef → uploadMarkup ref (mirror update_component).\n      if (params.description !== undefined) {\n        const ref = await tctx.client.uploadMarkup(\n          MILESTONE_CLASS,\n          m._id,\n          \"description\",\n          params.description,\n          \"markdown\",\n        );\n        ops.description = ref;\n      }\n      if (params.targetDate !== undefined) ops.targetDate = params.targetDate;\n      if (params.status !== undefined) {\n        try {\n          ops.status = stringToMilestoneStatus(params.status);\n        } catch (e) {\n          return {\n            content: (e as Error).message,\n            isError: true,\n            details: { milestone: params.milestone, invalidStatus: params.status },\n          };\n        }\n      }\n      if (Object.keys(ops).length === 0) {\n        return { content: \"No fields to update.\", details: { updated: false } };\n      }\n      const updResult = await safeUpdateDoc(tctx.client, MILESTONE_CLASS, m, ops);\n      if (!updResult.ok) return updResult.error;\n      return {\n        content: `Updated milestone ${params.milestone}: ${Object.keys(ops).join(\", \")}`,\n        details: { updated: true, fields: Object.keys(ops) },\n      };\n    },\n  }),\n\n  // 5. set_issue_milestone\n  defineHulyTool({\n    name: \"set_issue_milestone\",\n    label: \"Set issue milestone\",\n    description: \"Gán milestone cho issue. Qua identifier (PD-123 HOẶC raw num).\",\n    needsProject: true,\n    parameters: Type.Object({\n      workspace: workspaceParam,\n      project: projectParam,\n      identifier: identifierParam,\n      // T-82G #108: milestone=null → clear (unassign).\n      milestone: Type.Optional(Type.Union([Type.String(), Type.Null()])),\n    }),\n    async handler(params, tctx) {\n      const issue = await tctx.client.findOne(ISSUE_CLASS, {\n        identifier: resolveIdentifier(tctx.project!, params.identifier),\n      });\n      if (!issue) {\n        return {\n          content: `Issue \"${params.identifier}\" not found.`,\n          isError: true,\n          details: { identifier: params.identifier },\n        };\n      }\n      // T-82G #108: milestone=null → clear.\n      if (params.milestone === null) {\n        const clr = await safeUpdateDoc(tctx.client, ISSUE_CLASS, issue, { milestone: null });\n        if (!clr.ok) return clr.error;\n        return {\n          content: `Cleared milestone on ${params.identifier}.`,\n          details: { identifier: params.identifier, milestone: null },\n        };\n      }\n      // T-100 (#146): scope milestone lookup theo issue space (issue đã load,\n      // = project._id — giống set_issue_component, tránh getProjectSpace thừa).\n      const milestone = await tctx.client.findOne(MILESTONE_CLASS, {\n        _id: params.milestone,\n        space: issue.space,\n      } as never);\n      if (!milestone) {\n        return {\n          content: `Milestone \"${params.milestone}\" not found.`,\n          isError: true,\n          details: { identifier: params.identifier, milestone: params.milestone },\n        };\n      }\n      const updResult = await safeUpdateDoc(tctx.client, ISSUE_CLASS, issue, {\n        milestone: milestone._id as never,\n      });\n      if (!updResult.ok) return updResult.error;\n      return {\n        content: `Set ${params.identifier} → milestone ${params.milestone}.`,\n        details: { identifier: params.identifier, milestone: params.milestone },\n      };\n    },\n  }),\n\n  // 6. delete_milestone — destructive\n  defineHulyTool({\n    name: \"delete_milestone\",\n    label: \"Delete milestone\",\n    description: \"Delete milestone (destructive — confirm gate).\",\n    destructive: true,\n    needsProject: true,\n    destructiveContext: (p) => ({\n      type: \"milestone\",\n      id: (p as { milestone?: string }).milestone ?? \"<unknown>\",\n    }),\n    parameters: Type.Object({\n      workspace: workspaceParam,\n      project: projectParam,\n      milestone: Type.String(),\n    }),\n    async handler(params, tctx) {\n      // T-100 (#146): scope milestone lookup theo project space.\n      const space = await getProjectSpace(tctx.client, tctx.project!);\n      if (!space) {\n        return {\n          content: `Project \"${tctx.project}\" not found.`,\n          isError: true,\n          details: { project: tctx.project },\n        };\n      }\n      const m = await tctx.client.findOne(MILESTONE_CLASS, {\n        _id: params.milestone,\n        space,\n      } as never);\n      if (!m) {\n        return {\n          content: `Milestone \"${params.milestone}\" not found.`,\n          isError: true,\n          details: { milestone: params.milestone },\n        };\n      }\n      const delResult = await safeRemoveDoc(tctx.client, MILESTONE_CLASS, m);\n      if (!delResult.ok) return delResult.error;\n      return {\n        content: `Deleted milestone ${params.milestone}.`,\n        details: { deleted: true, milestone: params.milestone },\n      };\n    },\n  }),\n];\n\n// resolveIdentifier imported từ _common.ts\n","// tools/domains/task-management.ts — Task-management domain (5 tools).\n// Design: 06-api.md §4 Task-mgmt. Project types + task types + status registration.\n//\n// T-73 (2026-07-28): rewrite create_issue_status + create_task_type theo trusted\n// task-management.ts. Status/tasktype created + REGISTERED vào project workflow\n// (ProjectType.statuses ProjectStatus[] + TaskType.statuses Ref[]). Trước đây\n// createDoc orphan — status/tasktype KHÔNG bao giờ link workflow (silent fail).\n// space = core.space.Model (root model space, KHÔNG workspace root).\n// category = Ref<StatusCategory> (KHÔNG raw enum string).\n//\n// Bonus fixes: list_task_types field ofProjectType → parent; create_task_type\n// field ofProjectType → parent + register projectType.tasks.\n\nimport { Type } from \"typebox\";\nimport { defineHulyTool, type HulyToolDefinition } from \"../builder.js\";\nimport {\n  PROJECT_TYPE_CLASS,\n  TASK_TYPE_CLASS,\n  MODEL_SPACE,\n  STATUS_CATEGORY_REFS,\n  ISSUE_STATUS_ATTRIBUTE,\n  MIXIN_CLASS,\n  TASK_TYPE_MIXIN,\n  CLASSIFIER_KIND_MIXIN,\n  MODEL_LABEL_PREFIX,\n  idRef,\n} from \"./_class-refs.js\";\nimport type { ProjectTypeDoc, TaskTypeDoc, MixinDoc, StatusDoc } from \"./_entity-types.js\";\nimport { workspaceParam } from \"./_common.js\";\n\n/** Generate id helper (Huly convention <class-prefix>.<rand>). */\nfunction genId(prefix: string): string {\n  return `${prefix}.${Math.random().toString(36).slice(2, 12)}`;\n}\n\nexport const tools: HulyToolDefinition[] = [\n  // 1. list_project_types\n  defineHulyTool({\n    name: \"list_project_types\",\n    label: \"List project types\",\n    description: \"List project types (vd tracker, recruiting, inventory).\",\n    parameters: Type.Object({ workspace: workspaceParam }),\n    async handler(_params, tctx) {\n      const pts = await tctx.client.findAll(PROJECT_TYPE_CLASS, {}, {});\n      const list = pts.map((p) => ({\n        _id: p._id,\n        name: (p as { name?: string }).name ?? \"\",\n        targetClass: (p as { targetClass?: string }).targetClass,\n      }));\n      return {\n        content: `Found ${list.length} project type(s).`,\n        details: { count: list.length, projectTypes: list },\n      };\n    },\n  }),\n\n  // 2. get_project_type\n  defineHulyTool({\n    name: \"get_project_type\",\n    label: \"Get project type\",\n    description: \"Get project type by id.\",\n    parameters: Type.Object({\n      workspace: workspaceParam,\n      projectType: Type.String(),\n    }),\n    async handler(params, tctx) {\n      const pt = await tctx.client.findOne(PROJECT_TYPE_CLASS, {\n        _id: params.projectType,\n      });\n      if (!pt) {\n        return {\n          content: `Project type \"${params.projectType}\" not found.`,\n          isError: true,\n          details: { projectType: params.projectType },\n        };\n      }\n      return {\n        content: `Project type ${(pt as { name?: string }).name ?? \"\"}`,\n        details: {\n          _id: pt._id,\n          name: (pt as { name?: string }).name,\n          targetClass: (pt as { targetClass?: string }).targetClass,\n        },\n      };\n    },\n  }),\n\n  // 3. list_task_types — T-73: field ofProjectType → parent (trusted query field)\n  defineHulyTool({\n    name: \"list_task_types\",\n    label: \"List task types\",\n    description: \"List task types cho project type.\",\n    parameters: Type.Object({\n      workspace: workspaceParam,\n      projectType: Type.Optional(Type.String()),\n    }),\n    async handler(params, tctx) {\n      // T-73: query field `parent` (KHÔNG ofProjectType — trusted getTaskTypesByProjectType).\n      const query = params.projectType !== undefined ? { parent: params.projectType } : {};\n      const tts = await tctx.client.findAll(TASK_TYPE_CLASS, query as never, {});\n      const list = tts.map((t) => ({\n        _id: t._id,\n        name: (t as { name?: string }).name ?? \"\",\n      }));\n      return {\n        content: `Found ${list.length} task type(s).`,\n        details: { count: list.length, taskTypes: list },\n      };\n    },\n  }),\n\n  // 4. create_task_type — T-73: parent field + core.space.Model + register projectType.tasks\n  // T-73 review (M1): copy required fields (statusClass/ofClass/kind/targetClass/\n  // statusCategories/descriptor) từ sibling template TaskType trong cùng projectType.\n  // T-73 review (L1): idempotent check by name+projectType.\n  defineHulyTool({\n    name: \"create_task_type\",\n    label: \"Create task type\",\n    description:\n      \"Create task type trong project type + register vào projectType.tasks. Copies descriptor fields from a sibling template task type.\",\n    parameters: Type.Object({\n      workspace: workspaceParam,\n      name: Type.String(),\n      projectType: Type.String(),\n    }),\n    async handler(params, tctx) {\n      const projectType = await tctx.client.findOne<ProjectTypeDoc>(PROJECT_TYPE_CLASS, {\n        _id: params.projectType,\n      });\n      if (!projectType) {\n        return {\n          content: `Project type \"${params.projectType}\" not found.`,\n          isError: true,\n          details: { projectType: params.projectType },\n        };\n      }\n      // T-73 review L1: idempotent — findOne existing TaskType by name+parent.\n      const existing = await tctx.client.findOne<TaskTypeDoc>(TASK_TYPE_CLASS, {\n        name: params.name,\n        parent: params.projectType,\n      });\n      if (existing) {\n        return {\n          content: `Task type \"${params.name}\" already exists (idempotent — no-op).`,\n          details: { id: existing._id, name: params.name, idempotent: true },\n        };\n      }\n      // T-73 review M1: copy required fields từ sibling template TaskType.\n      // T-90: native TaskTypeDoc (no inline cast). TaskType schema requires\n      // descriptor/kind/ofClass/targetClass/statusClass/statusCategories.\n      const existingTaskIds = projectType.tasks ?? [];\n      let template: TaskTypeDoc | undefined;\n      if (existingTaskIds.length > 0) {\n        template = await tctx.client.findOne<TaskTypeDoc>(TASK_TYPE_CLASS, {\n          _id: existingTaskIds[0],\n        });\n      }\n      if (!template) {\n        return {\n          content:\n            `Cannot create task type \"${params.name}\": no sibling template TaskType ` +\n            `found trong projectType \"${params.projectType}\" to copy required fields ` +\n            `(descriptor/kind/ofClass/targetClass/statusClass/statusCategories). ` +\n            `Create the first task type via Huly UI, then use this tool for siblings.`,\n          isError: true,\n          details: {\n            projectType: params.projectType,\n            reason: \"no_sibling_template\",\n          },\n        };\n      }\n      const taskTypeId = genId(\"task:tasktype\");\n      // T-86 #121: derive targetClass mixin ref + create Mixin classifier doc +\n      // createMixin(TaskTypeClass) để Huly apply task-typing behavior. Trước đây\n      // skip cả 2 → task type tồn tại nhưng KHÔNG apply TaskTypeClass mixin.\n      // UNVERIFIED: core:class:Mixin + task:mixin:TaskTypeClass theo naming\n      // convention (task pkg not installed locally — flag như T-43).\n      // T-90: native types + satisfies (no inline cast / as never trên payload).\n      const targetClassId = `${taskTypeId}:type:mixin`;\n      const mixinData = {\n        extends: template.ofClass,\n        kind: CLASSIFIER_KIND_MIXIN,\n        label: MODEL_LABEL_PREFIX + params.name,\n        ...(template.icon !== undefined ? { icon: template.icon } : {}),\n      } satisfies Partial<MixinDoc>;\n      await tctx.client.createDoc(MIXIN_CLASS, MODEL_SPACE, mixinData, idRef(targetClassId));\n      await tctx.client.createMixin(\n        idRef(targetClassId),\n        MIXIN_CLASS,\n        MODEL_SPACE,\n        TASK_TYPE_MIXIN,\n        { taskType: taskTypeId, projectType: projectType._id },\n      );\n      // T-86 #121: statuses copy từ template (KHÔNG start []) + targetClass =\n      // new mixin ref (KHÔNG copy template.targetClass).\n      const templateStatusIds = template.statuses ?? [];\n      const taskData = {\n        name: params.name,\n        parent: projectType._id,\n        descriptor: template.descriptor,\n        kind: template.kind,\n        ofClass: template.ofClass,\n        targetClass: targetClassId, // T-86: new mixin ref\n        statusClass: template.statusClass,\n        statusCategories: template.statusCategories,\n        statuses: templateStatusIds, // T-86: copy template (KHÔNG [])\n        ...(template.icon !== undefined ? { icon: template.icon } : {}),\n        ...(template.color !== undefined ? { color: template.color } : {}),\n        ...(template.allowedAsChildOf !== undefined\n          ? { allowedAsChildOf: template.allowedAsChildOf }\n          : {}),\n      } satisfies Partial<TaskTypeDoc>;\n      const id = await tctx.client.createDoc(\n        TASK_TYPE_CLASS,\n        MODEL_SPACE,\n        taskData,\n        idRef(taskTypeId),\n      );\n      // T-86 #121: register projectType.tasks + statuses append {id,taskType}.\n      const ptStatuses = projectType.statuses ?? [];\n      const appendedStatuses = [\n        ...ptStatuses,\n        ...templateStatusIds\n          .filter((sid) => !ptStatuses.some((s) => s._id === sid))\n          .map((sid) => ({ _id: sid, taskType: taskTypeId })),\n      ];\n      await tctx.client.updateDoc(PROJECT_TYPE_CLASS, MODEL_SPACE, idRef(projectType._id), {\n        tasks: existingTaskIds.includes(taskTypeId)\n          ? existingTaskIds\n          : [...existingTaskIds, taskTypeId],\n        statuses: appendedStatuses,\n      });\n      return {\n        content: `Created task type \"${params.name}\" + Mixin classifier + registered to projectType workflow.`,\n        details: {\n          id,\n          name: params.name,\n          projectType: projectType._id,\n          targetClass: targetClassId,\n          mixinCreated: true,\n          registered: true,\n        },\n      };\n    },\n  }),\n\n  // 5. create_issue_status — T-73: full proper flow (register workflow)\n  //   - resolve taskType → statusClass dynamic (taskType.statusClass)\n  //   - core.space.Model space (KHÔNG workspace root)\n  //   - category = Ref<StatusCategory> via STATUS_CATEGORY_REFS (KHÔNG raw enum)\n  //   - register: TaskType.statuses + ProjectType.statuses (ProjectStatus object)\n  //   - idempotent: findOne exact name trên target taskType (KHÔNG global)\n  defineHulyTool({\n    name: \"create_issue_status\",\n    label: \"Create issue status\",\n    description:\n      \"Create issue status + register vào project workflow. Requires taskType param (resolve statusClass). Idempotent per taskType+name.\",\n    parameters: Type.Object({\n      workspace: workspaceParam,\n      taskType: Type.String({ description: \"TaskType _id (resolve statusClass + register).\" }),\n      name: Type.String(),\n      category: Type.Union([\n        Type.Literal(\"UnStarted\"),\n        Type.Literal(\"ToDo\"),\n        Type.Literal(\"Active\"),\n        Type.Literal(\"Won\"),\n        Type.Literal(\"Lost\"),\n      ]),\n    }),\n    async handler(params, tctx) {\n      // T-73: resolve taskType → statusClass + parent projectType. T-90: native TaskTypeDoc.\n      const taskType = await tctx.client.findOne<TaskTypeDoc>(TASK_TYPE_CLASS, {\n        _id: params.taskType,\n      });\n      if (!taskType) {\n        return {\n          content: `Task type \"${params.taskType}\" not found.`,\n          isError: true,\n          details: { taskType: params.taskType },\n        };\n      }\n      const statusClass = taskType.statusClass;\n      if (!statusClass) {\n        return {\n          content: `Task type \"${params.taskType}\" has no statusClass (cannot determine target class).`,\n          isError: true,\n          details: { taskType: params.taskType },\n        };\n      }\n      const projectTypeId = taskType.parent;\n      if (!projectTypeId) {\n        return {\n          content: `Task type \"${params.taskType}\" has no parent projectType.`,\n          isError: true,\n          details: { taskType: params.taskType },\n        };\n      }\n      // T-73: category = Ref<StatusCategory> (KHÔNG raw enum string). Resolve\n      // trước existing-check để validate category mismatch (T-87 #122).\n      const categoryRef = STATUS_CATEGORY_REFS[params.category];\n      if (!categoryRef) {\n        return {\n          content: `Invalid category \"${params.category}\". Valid: ${Object.keys(STATUS_CATEGORY_REFS).join(\", \")}.`,\n          isError: true,\n          details: { invalidCategory: params.category },\n        };\n      }\n      // T-73 review H2: idempotent findOne by {name} trên statusClass ONLY (KHÔNG\n      // ofTaskType — that field KHÔNG thuộc Status schema, server strip → query miss).\n      // T-90: native StatusDoc (statusClass dynamic → as never structural, 1 boundary).\n      const existing = await tctx.client.findOne<StatusDoc>(statusClass as never, {\n        name: params.name,\n      });\n      if (existing) {\n        // T-87 #122: validate category match (trusted requireStatusCategoryMatch).\n        // Same name different category = silent workflow corruption. Error rõ.\n        const existingCategory = existing.category;\n        if (existingCategory !== undefined && existingCategory !== categoryRef) {\n          return {\n            content:\n              `Status \"${params.name}\" already exists with category '${existingCategory}', ` +\n              `not requested category '${params.category}'. Use a different name or category.`,\n            isError: true,\n            details: {\n              name: params.name,\n              existingCategory,\n              requestedCategory: params.category,\n              taskType: params.taskType,\n            },\n          };\n        }\n        return {\n          content: `Status \"${params.name}\" already exists on taskType ${params.taskType} (idempotent — no-op).`,\n          details: {\n            id: existing._id,\n            name: params.name,\n            taskType: params.taskType,\n            idempotent: true,\n          },\n        };\n      }\n      // T-73 review H1: ofAttribute required (Status.ofAttribute: Ref<Attribute<Status>>).\n      // Trusted hardcodes tracker.attribute.IssueStatus cho issue statuses. T-90: satisfies.\n      const statusId = genId(\"tracker:status\");\n      await tctx.client.createDoc(\n        statusClass as never,\n        MODEL_SPACE,\n        {\n          name: params.name,\n          ofAttribute: ISSUE_STATUS_ATTRIBUTE,\n          category: categoryRef,\n        } satisfies Partial<StatusDoc>,\n        idRef(statusId),\n      );\n      // T-73: register vào TaskType.statuses (read-modify-write idempotent).\n      const ttStatuses = taskType.statuses ?? [];\n      if (!ttStatuses.includes(statusId)) {\n        await tctx.client.updateDoc(TASK_TYPE_CLASS, MODEL_SPACE, idRef(taskType._id), {\n          statuses: [...ttStatuses, statusId],\n        });\n      }\n      // T-73: register vào ProjectType.statuses (ProjectStatus[] objects {_id, taskType}).\n      const projectType = await tctx.client.findOne<ProjectTypeDoc>(PROJECT_TYPE_CLASS, {\n        _id: projectTypeId,\n      });\n      if (projectType) {\n        const ptStatuses = projectType.statuses ?? [];\n        if (!ptStatuses.some((s) => s._id === statusId)) {\n          await tctx.client.updateDoc(PROJECT_TYPE_CLASS, MODEL_SPACE, idRef(projectType._id), {\n            statuses: [...ptStatuses, { _id: statusId, taskType: params.taskType }],\n          });\n        }\n      }\n      return {\n        content: `Created status \"${params.name}\" (${params.category}) + registered to workflow.`,\n        details: {\n          id: statusId,\n          name: params.name,\n          category: params.category,\n          statusClass,\n          taskType: params.taskType,\n          projectType: projectTypeId,\n          registered: true,\n        },\n      };\n    },\n  }),\n];\n","// tools/domains/contacts.ts — Contacts domain (2 tools, read-only).\n// Design: 06-api.md §4 Contacts. List employees/persons cho assignee resolution.\n\nimport { Type } from \"typebox\";\nimport { defineHulyTool, type HulyToolDefinition } from \"../builder.js\";\nimport { PERSON_CLASS, EMPLOYEE_CLASS, CHANNEL_CLASS, EMAIL_PROVIDER } from \"./_class-refs.js\";\nimport { workspaceParam, limitParam } from \"./_common.js\";\nimport type { HulyClient, CurrentUser } from \"../../client/client.js\";\n\n/**\n * T-71: Resolve Person._id từ name (cho list_issues assignee filter).\n * Match: findOne Person {name} (Huly Person.name = \"LastName, FirstName\").\n *\n * NOTE: email resolve CẦN Channel(Email)/SocialIdentity lookup (Person.email\n * field KHÔNG tồn tại — email lives trong Channel attachedTo Person). Deferred\n * follow-up — hiện tại chỉ name match. Caller truyền email → undefined → isError.\n *\n * Port pattern (name path) trusted contacts-shared.ts:190.\n */\nexport async function findPersonByEmailOrName(\n  client: HulyClient,\n  input: string,\n  currentUser?: CurrentUser,\n): Promise<string | undefined> {\n  // T-82G #108: email resolve via Channel (provider email, value exact). Port\n  // trusted contacts-shared.ts findPersonByEmailOrName step 2 (Channel exact).\n  // SocialIdentity + $like fuzzy deferred (perf / workspace-members edge).\n  if (input.includes(\"@\")) {\n    const channel = await client.findOne(CHANNEL_CLASS, {\n      value: input,\n      provider: EMAIL_PROVIDER,\n    } as never);\n    if (channel) {\n      const person = await client.findOne(PERSON_CLASS, {\n        _id: (channel as { attachedTo?: string }).attachedTo,\n      } as never);\n      if (person) return person._id;\n    }\n    // Self-email fallback: self-host Huly thường KHÔNG tạo Channel email cho\n    // Person (verified: 0 email Channel trên workspace test). Link account→Person\n    // thật sự là Account.uuid === Person.personUuid. Account KHÔNG queryable qua\n    // findOne (\"domain not found\") + getAccount() KHÔNG expose email arbitrary,\n    // nên chỉ resolve được KHI input === currentUser.email (self-assign — case\n    // phổ biến nhất, vd update_issue assignee=<email get_user_profile trả>).\n    // Arbitrary teammate email vẫn cần Channel data (documented limitation).\n    if (currentUser && input.toLowerCase() === currentUser.email.toLowerCase()) {\n      const self = await client.findOne(PERSON_CLASS, {\n        personUuid: currentUser.id,\n      } as never);\n      if (self) return self._id;\n    }\n  }\n  // Name match (Huly Person.name = \"LastName, FirstName\").\n  const byName = await client.findOne(PERSON_CLASS, { name: input } as never);\n  return byName?._id;\n}\n\nexport const tools: HulyToolDefinition[] = [\n  // 1. list_employees\n  defineHulyTool({\n    name: \"list_employees\",\n    label: \"List employees\",\n    description: \"List employees trong workspace (cho assignee resolution).\",\n    parameters: Type.Object({ workspace: workspaceParam, limit: limitParam }),\n    async handler(params, tctx) {\n      const limit = typeof params.limit === \"number\" ? params.limit : 50;\n      const employees = await tctx.client.findAll(EMPLOYEE_CLASS, {}, { limit });\n      // T-74: email field KHÔNG tồn tại trên Employee/Person (lives trong Channel).\n      // T-82G #108: add position + active (Employee mixin fields).\n      const list = employees.map((e) => ({\n        id: e._id,\n        name: (e as { name?: string }).name ?? \"\",\n        position: (e as { role?: string }).role,\n        active: (e as { active?: boolean }).active !== false,\n      }));\n      return {\n        content: `Found ${list.length} employee(s).`,\n        details: { count: list.length, employees: list },\n      };\n    },\n  }),\n\n  // 2. list_persons\n  defineHulyTool({\n    name: \"list_persons\",\n    label: \"List persons\",\n    description: \"List persons (contacts) trong workspace.\",\n    parameters: Type.Object({ workspace: workspaceParam, limit: limitParam }),\n    async handler(params, tctx) {\n      const limit = typeof params.limit === \"number\" ? params.limit : 50;\n      const persons = await tctx.client.findAll(PERSON_CLASS, {}, { limit });\n      const list = persons.map((p) => ({\n        id: p._id,\n        name: (p as { name?: string }).name ?? \"\",\n        // T-82G #108: add city + modifiedOn. Drop dead email (T-82).\n        city: (p as { city?: string }).city,\n        modifiedOn: (p as { modifiedOn?: number }).modifiedOn,\n      }));\n      return {\n        content: `Found ${list.length} person(s).`,\n        details: { count: list.length, persons: list },\n      };\n    },\n  }),\n];\n","// tools/domains/components.ts — Components domain (6 tools).\n// Design: 06-api.md §4 Components. CRUD + set_issue_component.\n\nimport { Type } from \"typebox\";\nimport { defineHulyTool, type HulyToolDefinition } from \"../builder.js\";\nimport { COMPONENT_CLASS, ISSUE_CLASS, PROJECT_CLASS, PERSON_CLASS } from \"./_class-refs.js\";\nimport {\n  workspaceParam,\n  projectParam,\n  identifierParam,\n  resolveIdentifier,\n  safeUpdateDoc,\n  safeRemoveDoc,\n  getProjectSpace,\n} from \"./_common.js\";\nimport { findPersonByEmailOrName } from \"./contacts.js\";\n\nexport const tools: HulyToolDefinition[] = [\n  // 1. list_components\n  defineHulyTool({\n    name: \"list_components\",\n    label: \"List components\",\n    description: \"List components trong project.\",\n    needsProject: true,\n    parameters: Type.Object({ workspace: workspaceParam, project: projectParam }),\n    async handler(_params, tctx) {\n      // T-71: space scoping (KHÔNG findAll global cross-project).\n      const space = await getProjectSpace(tctx.client, tctx.project!);\n      if (!space) {\n        return {\n          content: `Project \"${tctx.project}\" not found.`,\n          isError: true,\n          details: { project: tctx.project },\n        };\n      }\n      const comps = await tctx.client.findAll(COMPONENT_CLASS, { space } as never, {});\n      const list = comps.map((c) => ({\n        id: c._id,\n        label: (c as { label?: string }).label ?? \"\",\n        lead: (c as { lead?: string }).lead,\n      }));\n      return {\n        content: `Found ${list.length} component(s).`,\n        details: { count: list.length, components: list },\n      };\n    },\n  }),\n\n  // 2. get_component\n  defineHulyTool({\n    name: \"get_component\",\n    label: \"Get component\",\n    description: \"Get component by id.\",\n    needsProject: true,\n    parameters: Type.Object({\n      workspace: workspaceParam,\n      project: projectParam,\n      component: Type.String(),\n    }),\n    async handler(params, tctx) {\n      // T-81 #104: scope component lookup theo project (space = project._id).\n      const space = await getProjectSpace(tctx.client, tctx.project!);\n      if (!space) {\n        return {\n          content: `Project \"${tctx.project}\" not found.`,\n          isError: true,\n          details: { project: tctx.project },\n        };\n      }\n      const c = await tctx.client.findOne(COMPONENT_CLASS, {\n        _id: params.component,\n        space,\n      } as never);\n      if (!c) {\n        return {\n          content: `Component \"${params.component}\" not found.`,\n          isError: true,\n          details: { component: params.component },\n        };\n      }\n      // T-81G #107: resolve lead raw Ref → Person name; description → markdown.\n      const comp = c as { label?: string; description?: string | null; lead?: string };\n      let leadName: string | undefined;\n      if (comp.lead) {\n        const person = await tctx.client.findOne(PERSON_CLASS, { _id: comp.lead } as never);\n        leadName = (person as { name?: string } | null)?.name;\n      }\n      let description: string | undefined;\n      if (comp.description) {\n        try {\n          const markup = await tctx.client.fetchMarkup(\n            COMPONENT_CLASS,\n            c._id,\n            \"description\",\n            comp.description,\n            \"markdown\",\n          );\n          description = typeof markup === \"string\" ? markup : undefined;\n        } catch {\n          description = undefined;\n        }\n      }\n      return {\n        content: `Component ${comp.label ?? \"\"}`,\n        details: {\n          id: c._id,\n          label: comp.label,\n          description,\n          lead: leadName,\n          leadRef: comp.lead,\n        },\n      };\n    },\n  }),\n\n  // 3. create_component\n  defineHulyTool({\n    name: \"create_component\",\n    label: \"Create component\",\n    description: \"Create component.\",\n    needsProject: true,\n    parameters: Type.Object({\n      workspace: workspaceParam,\n      project: projectParam,\n      label: Type.String(),\n      description: Type.Optional(Type.String()),\n      lead: Type.Optional(Type.String({ description: \"Lead email/name.\" })),\n    }),\n    async handler(params, tctx) {\n      // T-103 #160: guard label non-empty.\n      if (params.label.trim() === \"\") {\n        return {\n          content: `create_component label must be non-empty.`,\n          isError: true,\n          details: { label: params.label },\n        };\n      }\n      const project = await tctx.client.findOne(PROJECT_CLASS, {\n        identifier: tctx.project,\n      });\n      // T-51 #41: project null → isError rõ ràng, KHÔNG fallback workspace\n      // (trước đây fallback silent → document mồ côi không thuộc project).\n      if (!project) {\n        return {\n          content: `Project \"${tctx.project}\" not found. Run /huly init or check binding.`,\n          isError: true,\n          details: { project: tctx.project },\n        };\n      }\n      // T-81 #104: lead = Ref<Employee> (KHÔNG raw string). Resolve Person trước.\n      let leadRef: string | undefined;\n      if (params.lead !== undefined) {\n        leadRef = await findPersonByEmailOrName(tctx.client, params.lead, tctx.currentUser);\n        if (!leadRef) {\n          return {\n            content: `Lead \"${params.lead}\" not found (no Person matching email/name).`,\n            isError: true,\n            details: { lead: params.lead, project: tctx.project },\n          };\n        }\n      }\n      // T-81 #104: comments:0 default (pattern chung Component/Milestone/IssueTemplate).\n      // T-97 (#143): space = project._id (getProjectSpace canonical), KHÔNG\n      // project.space (T-67 assumption project._id===project.space SAI cho ws này\n      // → component orphan, set_issue_component scope issue.space=project._id\n      // không thấy). Đồng bộ list/get/update/set/delete (dùng getProjectSpace).\n      // T-103 #162: description = MarkupBlobRef. Pre-gen id → uploadMarkup ref\n      // (mirror create_issue/create_document). Trước đây push raw string →\n      // get_component fetchMarkup đọc garbage → description undefined.\n      const compId = `${COMPONENT_CLASS as string}.${Math.random().toString(36).slice(2, 12)}`;\n      let descriptionRef: unknown = null;\n      if (params.description && params.description.trim() !== \"\") {\n        descriptionRef = await tctx.client.uploadMarkup(\n          COMPONENT_CLASS,\n          compId,\n          \"description\",\n          params.description,\n          \"markdown\",\n        );\n      }\n      const id = await tctx.client.createDoc(\n        COMPONENT_CLASS,\n        project._id as never,\n        {\n          label: params.label,\n          description: descriptionRef,\n          lead: leadRef,\n          comments: 0,\n        },\n        compId as never,\n      );\n      return {\n        content: `Created component \"${params.label}\".`,\n        details: { id, label: params.label },\n      };\n    },\n  }),\n\n  // 4. update_component\n  defineHulyTool({\n    name: \"update_component\",\n    label: \"Update component\",\n    description: \"Update component (label, description, lead).\",\n    needsProject: true,\n    parameters: Type.Object({\n      workspace: workspaceParam,\n      project: projectParam,\n      component: Type.String(),\n      label: Type.Optional(Type.String()),\n      description: Type.Optional(Type.String()),\n      lead: Type.Optional(Type.String()),\n    }),\n    async handler(params, tctx) {\n      // T-81 #104: scope component lookup theo project.\n      const space = await getProjectSpace(tctx.client, tctx.project!);\n      if (!space) {\n        return {\n          content: `Project \"${tctx.project}\" not found.`,\n          isError: true,\n          details: { project: tctx.project },\n        };\n      }\n      const c = await tctx.client.findOne(COMPONENT_CLASS, {\n        _id: params.component,\n        space,\n      } as never);\n      if (!c) {\n        return {\n          content: `Component \"${params.component}\" not found.`,\n          isError: true,\n          details: { component: params.component },\n        };\n      }\n      const ops: Record<string, unknown> = {};\n      if (params.label !== undefined) {\n        if (params.label.trim() === \"\")\n          return {\n            content: \"label must be non-empty.\",\n            isError: true,\n            details: { label: params.label },\n          };\n        ops.label = params.label;\n      }\n      // T-103 #162: description = MarkupBlobRef → uploadMarkup ref (mirror update_issue).\n      if (params.description !== undefined) {\n        const ref = await tctx.client.uploadMarkup(\n          COMPONENT_CLASS,\n          c._id,\n          \"description\",\n          params.description,\n          \"markdown\",\n        );\n        ops.description = ref;\n      }\n      // T-81 #104: lead = Ref<Employee> (resolve Person, KHÔNG raw string).\n      if (params.lead !== undefined) {\n        const leadRef = await findPersonByEmailOrName(tctx.client, params.lead, tctx.currentUser);\n        if (!leadRef) {\n          return {\n            content: `Lead \"${params.lead}\" not found (no Person matching email/name).`,\n            isError: true,\n            details: { lead: params.lead, component: params.component },\n          };\n        }\n        ops.lead = leadRef;\n      }\n      if (Object.keys(ops).length === 0) {\n        return { content: \"No fields to update.\", details: { updated: false } };\n      }\n      const updResult = await safeUpdateDoc(tctx.client, COMPONENT_CLASS, c, ops);\n      if (!updResult.ok) return updResult.error;\n      return {\n        content: `Updated component ${params.component}.`,\n        details: { updated: true, fields: Object.keys(ops) },\n      };\n    },\n  }),\n\n  // 5. set_issue_component\n  defineHulyTool({\n    name: \"set_issue_component\",\n    label: \"Set issue component\",\n    description: \"Gán component cho issue.\",\n    needsProject: true,\n    parameters: Type.Object({\n      workspace: workspaceParam,\n      project: projectParam,\n      identifier: identifierParam,\n      // T-81G #107: component = label OR _id; null → clear (unassign).\n      component: Type.Optional(Type.Union([Type.String(), Type.Null()])),\n    }),\n    async handler(params, tctx) {\n      const issue = await tctx.client.findOne(ISSUE_CLASS, {\n        identifier: resolveIdentifier(tctx.project!, params.identifier),\n      });\n      if (!issue) {\n        return {\n          content: `Issue \"${params.identifier}\" not found.`,\n          isError: true,\n          details: { identifier: params.identifier },\n        };\n      }\n      // T-81G #107: component=null → clear (unassign).\n      if (params.component === null) {\n        const updResult = await safeUpdateDoc(tctx.client, ISSUE_CLASS, issue, {\n          component: null,\n        });\n        if (!updResult.ok) return updResult.error;\n        return {\n          content: `Cleared component on ${params.identifier}.`,\n          details: { identifier: params.identifier, component: null },\n        };\n      }\n      // T-52 #42 + T-81 #104 + T-81G #107: resolve component by _id OR label + scope.\n      const space = issue.space as string;\n      let component = await tctx.client.findOne(COMPONENT_CLASS, {\n        _id: params.component,\n        space,\n      } as never);\n      if (!component) {\n        // T-81G #107: label-fallback resolve.\n        component = await tctx.client.findOne(COMPONENT_CLASS, {\n          label: params.component,\n          space,\n        } as never);\n      }\n      if (!component) {\n        return {\n          content: `Component \"${params.component}\" not found (by _id or label).`,\n          isError: true,\n          details: { identifier: params.identifier, component: params.component },\n        };\n      }\n      const updResult = await safeUpdateDoc(tctx.client, ISSUE_CLASS, issue, {\n        component: component._id as never,\n      });\n      if (!updResult.ok) return updResult.error;\n      return {\n        content: `Set ${params.identifier} → component ${params.component}.`,\n        details: { identifier: params.identifier, component: params.component },\n      };\n    },\n  }),\n\n  // 6. delete_component — destructive\n  defineHulyTool({\n    name: \"delete_component\",\n    label: \"Delete component\",\n    description: \"Delete component (destructive).\",\n    destructive: true,\n    needsProject: true,\n    destructiveContext: (p) => ({\n      type: \"component\",\n      id: (p as { component?: string }).component ?? \"<unknown>\",\n    }),\n    parameters: Type.Object({\n      workspace: workspaceParam,\n      project: projectParam,\n      component: Type.String(),\n    }),\n    async handler(params, tctx) {\n      // T-81 #104: scope component lookup theo project.\n      const space = await getProjectSpace(tctx.client, tctx.project!);\n      if (!space) {\n        return {\n          content: `Project \"${tctx.project}\" not found.`,\n          isError: true,\n          details: { project: tctx.project },\n        };\n      }\n      const c = await tctx.client.findOne(COMPONENT_CLASS, {\n        _id: params.component,\n        space,\n      } as never);\n      if (!c) {\n        return {\n          content: `Component \"${params.component}\" not found.`,\n          isError: true,\n          details: { component: params.component },\n        };\n      }\n      const delResult = await safeRemoveDoc(tctx.client, COMPONENT_CLASS, c);\n      if (!delResult.ok) return delResult.error;\n      return {\n        content: `Deleted component ${params.component}.`,\n        details: { deleted: true, component: params.component },\n      };\n    },\n  }),\n];\n","// tools/domains/spaces.ts — Spaces domain (5 tools).\n// Design: 06-api.md §4 Spaces. Read-heavy + update.\n\nimport { Type } from \"typebox\";\nimport { defineHulyTool, type HulyToolDefinition } from \"../builder.js\";\nimport { SPACE_CLASS } from \"./_class-refs.js\";\nimport { workspaceParam, safeUpdateDoc } from \"./_common.js\";\n\nexport const tools: HulyToolDefinition[] = [\n  // 1. list_spaces\n  defineHulyTool({\n    name: \"list_spaces\",\n    label: \"List spaces\",\n    description: \"List Huly spaces (teamspaces + tracker spaces).\",\n    parameters: Type.Object({\n      workspace: workspaceParam,\n      includeArchived: Type.Optional(\n        Type.Boolean({ description: \"Include archived spaces (default false).\" }),\n      ),\n    }),\n    async handler(params, tctx) {\n      // T-81G #107: archived-filter default + widen output (class, privacy).\n      const query: Record<string, unknown> =\n        params.includeArchived === true ? {} : { archived: { $ne: true } };\n      const spaces = await tctx.client.findAll(SPACE_CLASS, query as never, {});\n      const list = spaces.map((s) => ({\n        _id: s._id,\n        name: (s as { name?: string }).name ?? \"\",\n        description: (s as { description?: string }).description,\n        class: (s as { _class?: string })._class,\n        private: (s as { private?: boolean }).private === true,\n        archived: (s as { archived?: boolean }).archived === true,\n      }));\n      return {\n        content: `Found ${list.length} space(s).`,\n        details: { count: list.length, spaces: list },\n      };\n    },\n  }),\n\n  // 2. get_space\n  defineHulyTool({\n    name: \"get_space\",\n    label: \"Get space\",\n    description: \"Get space by id.\",\n    parameters: Type.Object({\n      workspace: workspaceParam,\n      space: Type.String(),\n    }),\n    async handler(params, tctx) {\n      // T-81G #107: name-fallback — _id trước, exact name sau, ambiguous → isError.\n      let s = (await tctx.client.findOne(SPACE_CLASS, { _id: params.space })) as {\n        _id: string;\n        _class?: string;\n        name?: string;\n        description?: string;\n        private?: boolean;\n        archived?: boolean;\n      } | null;\n      if (!s) {\n        const byName = (await tctx.client.findAll(SPACE_CLASS, {\n          name: params.space,\n        } as never)) as Array<{\n          _id: string;\n          _class?: string;\n          name?: string;\n        }>;\n        if (byName.length === 0) {\n          return {\n            content: `Space \"${params.space}\" not found (by _id or name).`,\n            isError: true,\n            details: { space: params.space },\n          };\n        }\n        if (byName.length > 1) {\n          return {\n            content: `Space name \"${params.space}\" ambiguous (${byName.length} matches). Use _id.`,\n            isError: true,\n            details: {\n              space: params.space,\n              candidates: byName.map((x) => ({ _id: x._id, name: x.name })),\n            },\n          };\n        }\n        s = byName[0]!;\n      }\n      return {\n        content: `Space ${s.name ?? \"\"}`,\n        details: {\n          _id: s._id,\n          name: s.name,\n          description: s.description,\n          class: s._class,\n          private: s.private === true,\n          archived: s.archived === true,\n        },\n      };\n    },\n  }),\n\n  // 3. list_space_types — T-73: honest-unavailable (fabricated data removed).\n  // Space types = SpaceTypeDescriptor config (drive/class注册), KHÔNG query tự do.\n  // Pi-huly KHÔNG bundle drive plugin → KHÔNG access descriptors honestly.\n  defineHulyTool({\n    name: \"list_space_types\",\n    label: \"List space types\",\n    description:\n      \"UNAVAILABLE — space types = SpaceTypeDescriptor config (drive plugin not \" +\n      \"bundled). Create/browse spaces via Huly UI.\",\n    parameters: Type.Object({ workspace: workspaceParam }),\n    async handler(_params, _tctx) {\n      return {\n        content:\n          \"list_space_types KHÔNG khả dụng: space types = SpaceTypeDescriptor \" +\n          \"config registered qua drive plugin (pi-huly KHÔNG bundle drive). \" +\n          \"Browse/create spaces qua Huly UI trực tiếp.\",\n        isError: true,\n        details: { reason: \"spacetype_descriptor_inaccessible\" },\n      };\n    },\n  }),\n\n  // 4. get_space_type — T-73: honest-unavailable\n  defineHulyTool({\n    name: \"get_space_type\",\n    label: \"Get space type\",\n    description:\n      \"UNAVAILABLE — space type = SpaceTypeDescriptor config (drive plugin not \" +\n      \"bundled). Browse via Huly UI.\",\n    parameters: Type.Object({\n      workspace: workspaceParam,\n      spaceType: Type.String(),\n    }),\n    async handler(_params, _tctx) {\n      return {\n        content:\n          \"get_space_type KHÔNG khả dụng: space type = SpaceTypeDescriptor config \" +\n          \"(drive plugin not bundled). Browse via Huly UI.\",\n        isError: true,\n        details: { reason: \"spacetype_descriptor_inaccessible\" },\n      };\n    },\n  }),\n\n  // 5. update_space\n  defineHulyTool({\n    name: \"update_space\",\n    label: \"Update space\",\n    description: \"Update space (name, description, private, archived, autoJoin).\",\n    parameters: Type.Object({\n      workspace: workspaceParam,\n      space: Type.String(),\n      name: Type.Optional(Type.String()),\n      description: Type.Optional(Type.Union([Type.String(), Type.Null()])),\n      // T-81G #107: add private, archived, autoJoin (trusted có 5 fields).\n      private: Type.Optional(Type.Boolean()),\n      archived: Type.Optional(Type.Boolean()),\n      autoJoin: Type.Optional(Type.Boolean()),\n    }),\n    async handler(params, tctx) {\n      const s = await tctx.client.findOne(SPACE_CLASS, { _id: params.space });\n      if (!s) {\n        return {\n          content: `Space \"${params.space}\" not found.`,\n          isError: true,\n          details: { space: params.space },\n        };\n      }\n      const ops: Record<string, unknown> = {};\n      if (params.name !== undefined) ops.name = params.name;\n      if (params.description !== undefined) {\n        if (params.description === null) ops.$unset = { description: \"\" };\n        else ops.description = params.description;\n      }\n      if (params.private !== undefined) ops.private = params.private;\n      if (params.archived !== undefined) ops.archived = params.archived;\n      if (params.autoJoin !== undefined) ops.autoJoin = params.autoJoin;\n      if (Object.keys(ops).length === 0) {\n        return { content: \"No fields to update.\", details: { updated: false } };\n      }\n      const updResult = await safeUpdateDoc(tctx.client, SPACE_CLASS, s, ops);\n      if (!updResult.ok) return updResult.error;\n      const fields = Object.keys(ops).filter((f) => f !== \"$unset\");\n      if (ops.$unset !== undefined) fields.push(\"description(clear)\");\n      return {\n        content: `Updated space ${params.space}: ${fields.join(\", \")}`,\n        details: { updated: true, fields },\n      };\n    },\n  }),\n];\n","// tools/domains/document-snapshots.ts — Document snapshots domain (2 tools).\n// Design: 06-api.md §4 Snapshots. Read-only version history.\n//\n// T-66 (2026-07-28): RE-ENABLE từ honest-unavailable (T-58 conclusion sai).\n// Real class registered trong @hcengineering/document plugin() block —\n// `document:class:DocumentSnapshot`. Verified vs trusted huly-mcp v0.45\n// (document-snapshots.ts:74,80,95,121,139 dùng documentPlugin.class.DocumentSnapshot).\n// Snapshot content = MarkupBlobRef → fetchMarkup.\n\nimport { Type } from \"typebox\";\nimport { defineHulyTool, type HulyToolDefinition } from \"../builder.js\";\nimport { DOCUMENT_SNAPSHOT_CLASS } from \"./_class-refs.js\";\nimport { workspaceParam } from \"./_common.js\";\nimport type { DocumentSnapshotDoc } from \"./_entity-types.js\";\n\nexport const tools: HulyToolDefinition[] = [\n  // 1. list_document_snapshots — T-66: RE-ENABLED (DOCUMENT_SNAPSHOT_CLASS)\n  defineHulyTool({\n    name: \"list_document_snapshots\",\n    label: \"List document snapshots\",\n    description: \"List document snapshots (version history) for a document.\",\n    parameters: Type.Object({\n      workspace: workspaceParam,\n      document: Type.String({ description: \"Document id.\" }),\n      limit: Type.Optional(Type.Number({ description: \"Max snapshots to return.\" })),\n    }),\n    async handler(params, tctx) {\n      // T-85 #120: sort newest-first (trusted createdOn: Descending). T-90: native DocumentSnapshotDoc.\n      const snaps = await tctx.client.findAll<DocumentSnapshotDoc>(\n        DOCUMENT_SNAPSHOT_CLASS,\n        { attachedTo: params.document },\n        {\n          sort: { createdOn: -1 },\n          ...(params.limit !== undefined ? { limit: params.limit } : {}),\n        },\n      );\n      // T-99 (#145): field `_id` (KHÔNG `snapshotId`) — appendDetailsForLLM chỉ\n      // serialize identifier/_id/id → `snapshotId` bị drop → get_document_snapshot\n      // unreachable (dead-end).\n      const list = snaps.map((snap) => ({\n        _id: snap._id,\n        documentId: params.document,\n        title: snap.title,\n        parentDocumentId: snap.parent,\n        createdOn: snap.createdOn,\n        modifiedOn: snap.modifiedOn,\n      }));\n      return {\n        content: `Found ${list.length} snapshot(s) for document \"${params.document}\".`,\n        details: { count: list.length, snapshots: list },\n      };\n    },\n  }),\n\n  // 2. get_document_snapshot — T-66: RE-ENABLED + fetchMarkup content\n  defineHulyTool({\n    name: \"get_document_snapshot\",\n    label: \"Get document snapshot\",\n    description: \"Get a document snapshot content (markdown) by snapshot id.\",\n    parameters: Type.Object({\n      workspace: workspaceParam,\n      snapshot: Type.String({ description: \"Snapshot id.\" }),\n    }),\n    async handler(params, tctx) {\n      const s = await tctx.client.findOne<DocumentSnapshotDoc>(DOCUMENT_SNAPSHOT_CLASS, {\n        _id: params.snapshot,\n      });\n      if (!s) {\n        return {\n          content: `Snapshot \"${params.snapshot}\" not found.`,\n          isError: true,\n          details: { snapshot: params.snapshot },\n        };\n      }\n      // Snapshot content = MarkupBlobRef → fetchMarkup resolve to markdown.\n      const contentRef = s.content;\n      let content: string | undefined;\n      if (contentRef) {\n        try {\n          content = await tctx.client.fetchMarkup(\n            DOCUMENT_SNAPSHOT_CLASS,\n            s._id,\n            \"content\",\n            contentRef,\n            \"markdown\",\n          );\n        } catch {\n          // Markup fetch fail — return metadata without content.\n        }\n      }\n      // T-99 (#145): body vào content (clone get_document T-88 #123). Trước đây\n      // body chỉ trong details.content → appendDetailsForLLM skip → LLM mất body.\n      const header = `Snapshot ${s.title ?? s._id}${s.createdOn ? ` · ${new Date(s.createdOn).toISOString()}` : \"\"}`;\n      return {\n        content: content !== undefined ? `${header}\\n\\n---\\n${content}` : header,\n        details: {\n          _id: s._id,\n          documentId: s.attachedTo,\n          title: s.title,\n          parentDocumentId: s.parent,\n          createdOn: s.createdOn,\n          modifiedOn: s.modifiedOn,\n          content,\n        },\n      };\n    },\n  }),\n];\n","// tools/domains/labels.ts — Labels domain (4 tools, GLOBAL namespace).\n// Design: 06-api.md §4 Labels. CRUD GLOBAL (KHÔNG project-scoped).\n//\n// T-58 #43 fix (2026-07-28): DEEP-AUDIT 12 packages @0.7.423 — `view:class:Label`\n// KHÔNG tồn tại (0 match interface + class toàn packages). Deprecated — Huly\n// runtime dùng `tags:class:TagElement` cho tag/label entity (đã verify T-43,\n// dùng ở tags.ts). User yêu cầu \"KHÔNG defensive che lỗi\" → honest-unavailable\n// tất cả 4 label tools, hướng dẫn user dùng tag tools (huly_list_tags /\n// huly_create_tag / huly_attach_tag) thay thế.\n\nimport { Type } from \"typebox\";\nimport { defineHulyTool, type HulyToolDefinition } from \"../builder.js\";\nimport { workspaceParam } from \"./_common.js\";\n\n/** Honest-unavailable message cho label tools (deprecated — dùng tag tools). */\nfunction labelUnavailableMessage(operation: string): string {\n  return (\n    `huly_${operation} KHÔNG khả dụng: Huly runtime class \"view:class:Label\" ` +\n    `KHÔNG tồn tại (0 match trong 12 packages @0.7.423 — deprecated). Huly dùng ` +\n    `tags:class:TagElement cho tag/label entity. Dùng tag tools thay thế: ` +\n    `huly_list_tags, huly_create_tag, huly_update_tag, huly_attach_tag, ` +\n    `huly_detach_tag (xem tags domain).`\n  );\n}\n\nexport const tools: HulyToolDefinition[] = [\n  // 1. list_labels — honest-unavailable (deprecated)\n  defineHulyTool({\n    name: \"list_labels\",\n    label: \"List labels\",\n    description: \"UNAVAILABLE — Label deprecated in Huly runtime. Use huly_list_tags instead.\",\n    parameters: Type.Object({ workspace: workspaceParam }),\n    async handler(_params, _tctx) {\n      return {\n        content: labelUnavailableMessage(\"list_labels\"),\n        isError: true,\n        details: {\n          reason: \"deprecated\",\n          useClass: \"tags:class:TagElement\",\n          useTool: \"huly_list_tags\",\n        },\n      };\n    },\n  }),\n\n  // 2. create_label — honest-unavailable (deprecated)\n  defineHulyTool({\n    name: \"create_label\",\n    label: \"Create label\",\n    description: \"UNAVAILABLE — Label deprecated in Huly runtime. Use huly_create_tag instead.\",\n    parameters: Type.Object({\n      workspace: workspaceParam,\n      title: Type.String(),\n      color: Type.Optional(Type.String()),\n      description: Type.Optional(Type.String()),\n      category: Type.Optional(Type.String()),\n    }),\n    async handler(_params, _tctx) {\n      return {\n        content: labelUnavailableMessage(\"create_label\"),\n        isError: true,\n        details: {\n          reason: \"deprecated\",\n          useClass: \"tags:class:TagElement\",\n          useTool: \"huly_create_tag\",\n        },\n      };\n    },\n  }),\n\n  // 3. update_label — honest-unavailable (deprecated)\n  defineHulyTool({\n    name: \"update_label\",\n    label: \"Update label\",\n    description: \"UNAVAILABLE — Label deprecated in Huly runtime. Use huly_update_tag instead.\",\n    parameters: Type.Object({\n      workspace: workspaceParam,\n      label: Type.String(),\n      title: Type.Optional(Type.String()),\n      color: Type.Optional(Type.String()),\n      description: Type.Optional(Type.String()),\n      category: Type.Optional(Type.String()),\n    }),\n    async handler(_params, _tctx) {\n      return {\n        content: labelUnavailableMessage(\"update_label\"),\n        isError: true,\n        details: {\n          reason: \"deprecated\",\n          useClass: \"tags:class:TagElement\",\n          useTool: \"huly_update_tag\",\n        },\n      };\n    },\n  }),\n\n  // 4. delete_label — honest-unavailable (deprecated)\n  defineHulyTool({\n    name: \"delete_label\",\n    label: \"Delete label\",\n    description: \"UNAVAILABLE — Label deprecated in Huly runtime. Use huly_delete_tag instead.\",\n    parameters: Type.Object({\n      workspace: workspaceParam,\n      label: Type.String(),\n    }),\n    async handler(_params, _tctx) {\n      return {\n        content: labelUnavailableMessage(\"delete_label\"),\n        isError: true,\n        details: {\n          reason: \"deprecated\",\n          useClass: \"tags:class:TagElement\",\n          useTool: \"huly_delete_tag\",\n        },\n      };\n    },\n  }),\n];\n","// tools/domains/tags.ts — Tags domain (7 tools).\n// Design: 06-api.md §4 Tags. CRUD + attach/detach/list_attached.\n//\n// Tags khác labels: PROJECT-SCOPED (không global). (05-data-model §3)\n\nimport { Type } from \"typebox\";\nimport { defineHulyTool, type HulyToolDefinition } from \"../builder.js\";\nimport { TAG_CLASS, TAG_REFERENCE_CLASS, ISSUE_CLASS, idRef } from \"./_class-refs.js\";\nimport {\n  workspaceParam,\n  projectParam,\n  identifierParam,\n  resolveIdentifier,\n  safeUpdateDoc,\n  safeRemoveDoc,\n  getProjectSpace,\n} from \"./_common.js\";\n\nexport const tools: HulyToolDefinition[] = [\n  // 1. list_tags — T-73: optional targetClass filter (tags scoped theo class attach)\n  defineHulyTool({\n    name: \"list_tags\",\n    label: \"List tags\",\n    description: \"List tags trong project. Optional targetClass filter (vd tracker:class:Issue).\",\n    needsProject: true,\n    parameters: Type.Object({\n      workspace: workspaceParam,\n      project: projectParam,\n      targetClass: Type.Optional(\n        Type.String({ description: \"Filter tags theo target class (vd tracker:class:Issue).\" }),\n      ),\n    }),\n    async handler(params, tctx) {\n      // T-93 (#139): scope theo project space (tags là PROJECT-SCOPED). Trước đây\n      // findAll không filter → list không thấy tag vừa create (tag tạo sai space).\n      const space = await getProjectSpace(tctx.client, tctx.project!);\n      if (!space) {\n        return {\n          content: `Project \"${tctx.project}\" not found.`,\n          isError: true,\n          details: { project: tctx.project },\n        };\n      }\n      const query: Record<string, unknown> = { space };\n      if (params.targetClass !== undefined) query.targetClass = params.targetClass;\n      const tags = await tctx.client.findAll(TAG_CLASS, query as never, {});\n      const list = tags.map((t) => ({\n        _id: t._id,\n        title: (t as { title?: string }).title ?? \"\",\n        color: (t as { color?: string }).color,\n      }));\n      return {\n        content: `Found ${list.length} tag(s).`,\n        details: { count: list.length, tags: list },\n      };\n    },\n  }),\n\n  // 2. create_tag\n  defineHulyTool({\n    name: \"create_tag\",\n    label: \"Create tag\",\n    description: \"Create tag (project-scoped).\",\n    needsProject: true,\n    parameters: Type.Object({\n      workspace: workspaceParam,\n      project: projectParam,\n      title: Type.String(),\n      color: Type.Optional(Type.String()),\n    }),\n    async handler(params, tctx) {\n      // T-103 #160: guard title non-empty.\n      if (params.title.trim() === \"\") {\n        return {\n          content: `create_tag title must be non-empty.`,\n          isError: true,\n          details: { title: params.title },\n        };\n      }\n      // T-93 (#139): tạo trong PROJECT space (project._id self-ref qua\n      // getProjectSpace), KHÔNG spaceRef(tctx.workspace) (workspace-handle string\n      // → tag orphan, list/attach không thấy). File header: tags PROJECT-SCOPED.\n      const space = await getProjectSpace(tctx.client, tctx.project!);\n      if (!space) {\n        return {\n          content: `Project \"${tctx.project}\" not found.`,\n          isError: true,\n          details: { project: tctx.project },\n        };\n      }\n      const id = await tctx.client.createDoc(TAG_CLASS, space as never, {\n        title: params.title,\n        color: params.color,\n      });\n      return {\n        content: `Created tag \"${params.title}\".`,\n        details: { id, title: params.title },\n      };\n    },\n  }),\n\n  // 3. update_tag\n  defineHulyTool({\n    name: \"update_tag\",\n    label: \"Update tag\",\n    description: \"Update tag (title, color).\",\n    needsProject: true,\n    parameters: Type.Object({\n      workspace: workspaceParam,\n      project: projectParam,\n      tag: Type.String(),\n      title: Type.Optional(Type.String()),\n      color: Type.Optional(Type.String()),\n    }),\n    async handler(params, tctx) {\n      const t = await tctx.client.findOne(TAG_CLASS, { _id: params.tag });\n      if (!t) {\n        return {\n          content: `Tag \"${params.tag}\" not found.`,\n          isError: true,\n          details: { tag: params.tag },\n        };\n      }\n      const ops: Record<string, unknown> = {};\n      if (params.title !== undefined) {\n        if (params.title.trim() === \"\")\n          return {\n            content: \"title must be non-empty.\",\n            isError: true,\n            details: { title: params.title },\n          };\n        ops.title = params.title;\n      }\n      if (params.color !== undefined) ops.color = params.color;\n      if (Object.keys(ops).length === 0) {\n        return { content: \"No fields to update.\", details: { updated: false } };\n      }\n      const updResult = await safeUpdateDoc(tctx.client, TAG_CLASS, t, ops);\n      if (!updResult.ok) return updResult.error;\n      return {\n        content: `Updated tag ${params.tag}.`,\n        details: { updated: true, fields: Object.keys(ops) },\n      };\n    },\n  }),\n\n  // 4. delete_tag — destructive\n  defineHulyTool({\n    name: \"delete_tag\",\n    label: \"Delete tag\",\n    description: \"Delete tag (destructive).\",\n    destructive: true,\n    needsProject: true,\n    destructiveContext: (p) => ({\n      type: \"tag\",\n      id: (p as { tag?: string }).tag ?? \"<unknown>\",\n    }),\n    parameters: Type.Object({\n      workspace: workspaceParam,\n      project: projectParam,\n      tag: Type.String(),\n    }),\n    async handler(params, tctx) {\n      const t = await tctx.client.findOne(TAG_CLASS, { _id: params.tag });\n      if (!t) {\n        return {\n          content: `Tag \"${params.tag}\" not found.`,\n          isError: true,\n          details: { tag: params.tag },\n        };\n      }\n      const delResult = await safeRemoveDoc(tctx.client, TAG_CLASS, t);\n      if (!delResult.ok) return delResult.error;\n      return {\n        content: `Deleted tag ${params.tag}.`,\n        details: { deleted: true, tag: params.tag },\n      };\n    },\n  }),\n\n  // 5. list_attached_tags — T-69: findAll TagReference (KHÔNG issue.tags inline)\n  defineHulyTool({\n    name: \"list_attached_tags\",\n    label: \"List attached tags\",\n    description: \"List tags attached to issue.\",\n    needsProject: true,\n    parameters: Type.Object({\n      workspace: workspaceParam,\n      project: projectParam,\n      identifier: identifierParam,\n    }),\n    async handler(params, tctx) {\n      const issue = await tctx.client.findOne(ISSUE_CLASS, {\n        identifier: resolveIdentifier(tctx.project!, params.identifier),\n      });\n      if (!issue) {\n        return {\n          content: `Issue \"${params.identifier}\" not found.`,\n          isError: true,\n          details: { identifier: params.identifier },\n        };\n      }\n      // T-69: TagReference là AttachedDoc — findAll collection \"labels\".\n      const refs = await tctx.client.findAll(\n        TAG_REFERENCE_CLASS,\n        {\n          attachedTo: issue._id,\n          attachedToClass: ISSUE_CLASS,\n          collection: \"labels\",\n        } as never,\n        {},\n      );\n      const tags = refs.map((r) => {\n        const ref = r as { _id: string; tag?: string; title?: string; color?: number };\n        return { _id: ref._id, tag: ref.tag, title: ref.title, color: ref.color };\n      });\n      return {\n        content: `Found ${tags.length} tag(s) attached to ${params.identifier}.`,\n        details: { count: tags.length, tags },\n      };\n    },\n  }),\n\n  // 6. attach_tag — T-69: addCollection TagReference (collection \"labels\")\n  defineHulyTool({\n    name: \"attach_tag\",\n    label: \"Attach tag\",\n    description: \"Attach tag to issue. Accepts tag title or _id (resolved title-first).\",\n    needsProject: true,\n    parameters: Type.Object({\n      workspace: workspaceParam,\n      project: projectParam,\n      identifier: identifierParam,\n      tag: Type.String({ description: \"Tag title or _id.\" }),\n    }),\n    async handler(params, tctx) {\n      const issue = await tctx.client.findOne(ISSUE_CLASS, {\n        identifier: resolveIdentifier(tctx.project!, params.identifier),\n      });\n      if (!issue) {\n        return {\n          content: `Issue \"${params.identifier}\" not found.`,\n          isError: true,\n          details: { identifier: params.identifier },\n        };\n      }\n      // T-94 (#140): title-first, _id fallback (mirror add_issue_label). Trước đây\n      // _id-only → dead-end (create_tag/list_tags không surface _id cho LLM).\n      const tag =\n        (await tctx.client.findOne(TAG_CLASS, { title: params.tag })) ??\n        (await tctx.client.findOne(TAG_CLASS, { _id: idRef(params.tag) }));\n      if (!tag) {\n        return {\n          content: `Tag \"${params.tag}\" not found. Create via create_tag first.`,\n          isError: true,\n          details: { identifier: params.identifier, tag: params.tag },\n        };\n      }\n      const tagDoc = tag as { _id: string; title?: string; color?: number | string };\n      // Idempotent: findAll TagReference collection \"labels\" check exists.\n      const existing = await tctx.client.findAll(\n        TAG_REFERENCE_CLASS,\n        {\n          attachedTo: issue._id,\n          attachedToClass: ISSUE_CLASS,\n          collection: \"labels\",\n          tag: tagDoc._id,\n        } as never,\n        {},\n      );\n      if (existing.length > 0) {\n        return {\n          content: `Tag ${params.tag} already attached (no-op).`,\n          details: { attached: true, tag: params.tag, idempotent: true },\n        };\n      }\n      // addCollection TagReference AttachedDoc (collection \"labels\"). Attributes\n      // {tag, title, color:Number} — weight optional, omit khi undefined.\n      const attrs: Record<string, unknown> = {\n        tag: tagDoc._id,\n        title: tagDoc.title ?? params.tag,\n        color: Number(tagDoc.color ?? 0),\n      };\n      const id = await tctx.client.addCollection(\n        TAG_REFERENCE_CLASS,\n        issue.space as never,\n        issue._id as never,\n        ISSUE_CLASS,\n        \"labels\",\n        attrs as never,\n      );\n      return {\n        content: `Attached tag ${params.tag} to ${params.identifier}.`,\n        details: {\n          identifier: params.identifier,\n          tag: params.tag,\n          tagId: tagDoc._id,\n          tagRefId: id,\n        },\n      };\n    },\n  }),\n\n  // 7. detach_tag — T-69: findAll TagReference + removeDoc matching\n  defineHulyTool({\n    name: \"detach_tag\",\n    label: \"Detach tag\",\n    description: \"Detach tag from issue. Accepts tag title or _id (resolved title-first).\",\n    needsProject: true,\n    parameters: Type.Object({\n      workspace: workspaceParam,\n      project: projectParam,\n      identifier: identifierParam,\n      tag: Type.String({ description: \"Tag title or _id.\" }),\n    }),\n    async handler(params, tctx) {\n      const issue = await tctx.client.findOne(ISSUE_CLASS, {\n        identifier: resolveIdentifier(tctx.project!, params.identifier),\n      });\n      if (!issue) {\n        return {\n          content: `Issue \"${params.identifier}\" not found.`,\n          isError: true,\n          details: { identifier: params.identifier },\n        };\n      }\n      // T-94 (#140): title-first, _id fallback (đồng bộ attach_tag).\n      const tag =\n        (await tctx.client.findOne(TAG_CLASS, { title: params.tag })) ??\n        (await tctx.client.findOne(TAG_CLASS, { _id: idRef(params.tag) }));\n      if (!tag) {\n        return {\n          content: `Tag \"${params.tag}\" not found.`,\n          isError: true,\n          details: { identifier: params.identifier, tag: params.tag },\n        };\n      }\n      const tagDoc = tag as { _id: string };\n      // findAll TagReference matching tag trên issue.\n      const refs = await tctx.client.findAll(\n        TAG_REFERENCE_CLASS,\n        {\n          attachedTo: issue._id,\n          attachedToClass: ISSUE_CLASS,\n          collection: \"labels\",\n          tag: tagDoc._id,\n        } as never,\n        {},\n      );\n      if (refs.length === 0) {\n        return {\n          content: `Tag ${params.tag} not on ${params.identifier} (no-op).`,\n          details: { detached: false, idempotent: true, tag: params.tag },\n        };\n      }\n      // removeDoc each matching TagReference.\n      for (const r of refs) {\n        const ref = r as { _id: string; space?: string };\n        await tctx.client.removeDoc(\n          TAG_REFERENCE_CLASS,\n          (ref.space ?? issue.space) as never,\n          ref._id as never,\n        );\n      }\n      return {\n        content: `Detached tag ${params.tag} from ${params.identifier}.`,\n        details: {\n          identifier: params.identifier,\n          tag: params.tag,\n          tagId: tagDoc._id,\n          removed: refs.length,\n        },\n      };\n    },\n  }),\n];\n","// tools/domains/tag-categories.ts — Tag categories domain (4 tools).\n// Design: 06-api.md §4 Tag-categories. CRUD.\n//\n// T-77 (2026-07-28): field thật là `label` (KHÔNG `title` — TagCategory.label).\n// reality-checker CONFIRMED vs @hcengineering/tags types. TagElement dùng title,\n// TagCategory dùng label — KHÔNG nhầm.\n\nimport { Type } from \"typebox\";\nimport { defineHulyTool, type HulyToolDefinition } from \"../builder.js\";\nimport { TAG_CATEGORY_CLASS, WORKSPACE_SPACE } from \"./_class-refs.js\";\nimport { workspaceParam, safeUpdateDoc, safeRemoveDoc } from \"./_common.js\";\n\nexport const tools: HulyToolDefinition[] = [\n  // 1. list_tag_categories\n  defineHulyTool({\n    name: \"list_tag_categories\",\n    label: \"List tag categories\",\n    description: \"List tag categories.\",\n    parameters: Type.Object({ workspace: workspaceParam }),\n    async handler(_params, tctx) {\n      const cats = await tctx.client.findAll(TAG_CATEGORY_CLASS, {}, {});\n      const list = cats.map((c) => ({\n        _id: c._id,\n        label: (c as { label?: string }).label ?? \"\",\n        targetClass: (c as { targetClass?: string }).targetClass,\n      }));\n      return {\n        content: `Found ${list.length} tag category(ies).`,\n        details: { count: list.length, categories: list },\n      };\n    },\n  }),\n\n  // 2. create_tag_category\n  defineHulyTool({\n    name: \"create_tag_category\",\n    label: \"Create tag category\",\n    description: \"Create tag category.\",\n    parameters: Type.Object({\n      workspace: workspaceParam,\n      label: Type.String(),\n      targetClass: Type.Optional(Type.String()),\n    }),\n    async handler(params, tctx) {\n      const id = await tctx.client.createDoc(TAG_CATEGORY_CLASS, WORKSPACE_SPACE, {\n        label: params.label,\n        targetClass: params.targetClass,\n        // T-77: defaults (trusted createTagCategory).\n        icon: \"\",\n        tags: [],\n        default: false,\n      } as never);\n      return {\n        content: `Created tag category \"${params.label}\".`,\n        details: { id, label: params.label },\n      };\n    },\n  }),\n\n  // 3. update_tag_category\n  defineHulyTool({\n    name: \"update_tag_category\",\n    label: \"Update tag category\",\n    description: \"Update tag category (label, targetClass).\",\n    parameters: Type.Object({\n      workspace: workspaceParam,\n      category: Type.String(),\n      label: Type.Optional(Type.String()),\n      targetClass: Type.Optional(Type.String()),\n    }),\n    async handler(params, tctx) {\n      const c = await tctx.client.findOne(TAG_CATEGORY_CLASS, { _id: params.category });\n      if (!c) {\n        return {\n          content: `Tag category \"${params.category}\" not found.`,\n          isError: true,\n          details: { category: params.category },\n        };\n      }\n      const ops: Record<string, unknown> = {};\n      if (params.label !== undefined) ops.label = params.label;\n      if (params.targetClass !== undefined) ops.targetClass = params.targetClass;\n      if (Object.keys(ops).length === 0) {\n        return { content: \"No fields to update.\", details: { updated: false } };\n      }\n      const updResult = await safeUpdateDoc(tctx.client, TAG_CATEGORY_CLASS, c, ops);\n      if (!updResult.ok) return updResult.error;\n      return {\n        content: `Updated tag category ${params.category}.`,\n        details: { updated: true, fields: Object.keys(ops) },\n      };\n    },\n  }),\n\n  // 4. delete_tag_category — destructive\n  defineHulyTool({\n    name: \"delete_tag_category\",\n    label: \"Delete tag category\",\n    description: \"Delete tag category (destructive).\",\n    destructive: true,\n    destructiveContext: (p) => ({\n      type: \"tag category\",\n      id: (p as { category?: string }).category ?? \"<unknown>\",\n    }),\n    parameters: Type.Object({\n      workspace: workspaceParam,\n      category: Type.String(),\n    }),\n    async handler(params, tctx) {\n      const c = await tctx.client.findOne(TAG_CATEGORY_CLASS, { _id: params.category });\n      if (!c) {\n        return {\n          content: `Tag category \"${params.category}\" not found.`,\n          isError: true,\n          details: { category: params.category },\n        };\n      }\n      const delResult = await safeRemoveDoc(tctx.client, TAG_CATEGORY_CLASS, c);\n      if (!delResult.ok) return delResult.error;\n      return {\n        content: `Deleted tag category ${params.category}.`,\n        details: { deleted: true, category: params.category },\n      };\n    },\n  }),\n];\n","// MarkupConverter — markdown ↔ Huly markup wrapper.\n// Design: 04-system.md §6 markup.ts, 01 §B.10 D10 (parser dùng text-markdown).\n//\n// Parser = @hcengineering/text-markdown (markdownToMarkup/markupToMarkdown).\n// Native-ref transform (browse-URL) = reimplement ở T-08b (separate module).\n\n// CJS interop: @hcengineering/text-markdown ships CommonJS → named ESM imports\n// crash at runtime. Default import + destructure.\nimport textMarkdown from \"@hcengineering/text-markdown\";\nimport type { MarkdownOptions } from \"@hcengineering/text-markdown\";\nimport type { MarkupNode } from \"@hcengineering/text-core\";\nconst { markdownToMarkup, markupToMarkdown } = textMarkdown;\n\n/** Re-export MarkupNode type cho consumer. */\nexport type { MarkupNode, MarkdownOptions };\n\n/**\n * Convert markdown → Huly markup node tree.\n * Native-ref transform (md link → native ref) = T-08b (KHÔNG ở đây).\n */\nexport function mdToMarkup(md: string, options?: MarkdownOptions): MarkupNode {\n  return markdownToMarkup(md, options);\n}\n\n/**\n * Convert Huly markup node tree → markdown.\n * Native-ref transform (native ref → md link) = T-08b (KHÔNG ở đây).\n */\nexport function markupToMd(markup: MarkupNode, options?: MarkdownOptions): string {\n  return markupToMarkdown(markup, options);\n}\n\n/**\n * Round-trip: markdown → markup → markdown.\n * Useful cho test (lossless check).\n *\n * Note: KHÔNG guaranteed lossless do markdown dialects khác.\n * R8 native-ref round-trip fidelity = T-08b concern.\n */\nexport function roundTripMd(md: string, options?: MarkdownOptions): string {\n  return markupToMd(mdToMarkup(md, options), options);\n}\n","// tools/domains/comments.ts — Comments domain (4 tools).\n// Design: 06-api.md §4 Comments.\n//\n// T-70 (2026-07-28): field thật là `message` (KHÔNG `body` — gotcha cũ bị\n// ĐẢO ngược). reality-checker CONFIRMED vs trusted comments.ts:150\n// `message: markdownToMarkupString(params.body)`. ChatMessage.message = inline\n// Markup = JSON.stringify(mdToMarkup(md)). KHÔNG MarkupBlobRef (KHÔNG uploadMarkup).\n//\n// Comment = chunter:class:ChatMessage attached to issue (collection \"comments\").\n\nimport { Type } from \"typebox\";\nimport { defineHulyTool, type HulyToolDefinition } from \"../builder.js\";\nimport { CHAT_MESSAGE_CLASS, ISSUE_CLASS } from \"./_class-refs.js\";\nimport {\n  workspaceParam,\n  projectParam,\n  identifierParam,\n  resolveIdentifier,\n  safeUpdateDoc,\n  safeRemoveDoc,\n} from \"./_common.js\";\nimport { mdToMarkup, markupToMd } from \"../../markup/markup.js\";\n\n/** Markdown → inline Huly Markup string (JSON.stringify(markupNode)). */\nfunction markdownToMessage(md: string): string {\n  return JSON.stringify(mdToMarkup(md));\n}\n\n/** Inline Huly Markup string → markdown (round-trip for list read). */\nfunction messageToMarkdown(message: unknown): string | undefined {\n  if (typeof message !== \"string\" || message === \"\") return undefined;\n  try {\n    return markupToMd(JSON.parse(message) as never);\n  } catch {\n    // Non-JSON message (legacy/edge) — return raw.\n    return message;\n  }\n}\n\nexport const tools: HulyToolDefinition[] = [\n  // 1. list_comments — T-70: filter attachedToClass + read field `message`\n  defineHulyTool({\n    name: \"list_comments\",\n    label: \"List comments\",\n    description: \"List comments trên issue.\",\n    needsProject: true,\n    parameters: Type.Object({\n      workspace: workspaceParam,\n      project: projectParam,\n      identifier: identifierParam,\n    }),\n    async handler(params, tctx) {\n      const issue = await tctx.client.findOne(ISSUE_CLASS, {\n        identifier: resolveIdentifier(tctx.project!, params.identifier),\n      });\n      if (!issue) {\n        return {\n          content: `Issue \"${params.identifier}\" not found.`,\n          isError: true,\n          details: { identifier: params.identifier },\n        };\n      }\n      // T-70: query thêm attachedToClass: ISSUE_CLASS (trusted pattern — tránh\n      // trả comments từ attachment/activity khác attach cùng issue).\n      const comments = await tctx.client.findAll(\n        CHAT_MESSAGE_CLASS,\n        { attachedTo: issue._id, attachedToClass: ISSUE_CLASS } as never,\n        { sort: { createdOn: 1 } } as never,\n      );\n      const list = comments.map((c) => {\n        const raw = c as { message?: string; createdOn?: number; modifiedBy?: string };\n        return {\n          _id: c._id,\n          message: messageToMarkdown(raw.message),\n          createdOn: raw.createdOn,\n          modifiedBy: raw.modifiedBy,\n        };\n      });\n      return {\n        content: `Found ${list.length} comment(s) on ${params.identifier}.`,\n        details: { count: list.length, comments: list },\n      };\n    },\n  }),\n\n  // 2. add_comment — T-70: field `message` (inline Markup), KHÔNG `body`\n  defineHulyTool({\n    name: \"add_comment\",\n    label: \"Add comment\",\n    description: \"Add comment to issue. Body param → message field (Huly inline Markup).\",\n    needsProject: true,\n    needsAssignee: true,\n    assigneeField: \"author\",\n    parameters: Type.Object({\n      workspace: workspaceParam,\n      project: projectParam,\n      identifier: identifierParam,\n      body: Type.String({ description: \"Comment body (markdown).\" }),\n    }),\n    async handler(params, tctx) {\n      const issue = await tctx.client.findOne(ISSUE_CLASS, {\n        identifier: resolveIdentifier(tctx.project!, params.identifier),\n      });\n      if (!issue) {\n        return {\n          content: `Issue \"${params.identifier}\" not found.`,\n          isError: true,\n          details: { identifier: params.identifier },\n        };\n      }\n      const id = await tctx.client.addCollection(\n        CHAT_MESSAGE_CLASS,\n        issue.space as never,\n        issue._id as never,\n        ISSUE_CLASS,\n        \"comments\",\n        { message: markdownToMessage(params.body) } as never,\n      );\n      return {\n        content: `Comment added to ${params.identifier}.`,\n        details: { id, identifier: params.identifier },\n      };\n    },\n  }),\n\n  // 3. update_comment — T-70: field `message` + editedOn timestamp\n  defineHulyTool({\n    name: \"update_comment\",\n    label: \"Update comment\",\n    description: \"Update comment body (→ message field + editedOn).\",\n    parameters: Type.Object({\n      workspace: workspaceParam,\n      comment: Type.String(),\n      body: Type.String(),\n    }),\n    async handler(params, tctx) {\n      const c = await tctx.client.findOne(CHAT_MESSAGE_CLASS, { _id: params.comment });\n      if (!c) {\n        return {\n          content: `Comment \"${params.comment}\" not found.`,\n          isError: true,\n          details: { comment: params.comment },\n        };\n      }\n      const updResult = await safeUpdateDoc(tctx.client, CHAT_MESSAGE_CLASS, c, {\n        message: markdownToMessage(params.body),\n        editedOn: Date.now(),\n      } as never);\n      if (!updResult.ok) return updResult.error;\n      return {\n        content: `Updated comment ${params.comment}.`,\n        details: { updated: true, comment: params.comment },\n      };\n    },\n  }),\n\n  // 4. delete_comment — destructive (không affected by field name)\n  defineHulyTool({\n    name: \"delete_comment\",\n    label: \"Delete comment\",\n    description: \"Delete comment (destructive).\",\n    destructive: true,\n    destructiveContext: (p) => ({\n      type: \"comment\",\n      id: (p as { comment?: string }).comment ?? \"<unknown>\",\n    }),\n    parameters: Type.Object({\n      workspace: workspaceParam,\n      comment: Type.String(),\n    }),\n    async handler(params, tctx) {\n      const c = await tctx.client.findOne(CHAT_MESSAGE_CLASS, { _id: params.comment });\n      if (!c) {\n        return {\n          content: `Comment \"${params.comment}\" not found.`,\n          isError: true,\n          details: { comment: params.comment },\n        };\n      }\n      const delResult = await safeRemoveDoc(tctx.client, CHAT_MESSAGE_CLASS, c);\n      if (!delResult.ok) return delResult.error;\n      return {\n        content: `Deleted comment ${params.comment}.`,\n        details: { deleted: true, comment: params.comment },\n      };\n    },\n  }),\n];\n","// tools/domains/search.ts — Search domain (1 tool, global).\n// Design: 06-api.md §4 Search.\n//\n// T-42 fix (#24): expand query across 3 domains (Issue title, Document title,\n// ChatMessage content) thay vì chỉ Issue.title. $like là client-side regex\n// predicate (audit §3 — % → .*, case-insensitive, anchored). Server có thể\n// KHÔNG support $like → catch + honest error (KHÔNG fake \"Found 0\").\n//\n// T-60 #55 #64 fix (2026-07-28): REMOVE Document domain khỏi search —\n// `tracker:class:Document` interface tồn tại trong source NHƯNG KHÔNG register\n// trong plugin() class block (interface orphan) → runtime fail \"domain not\n// found\" (#55 report 2 lần, T-49 Promise.allSettled chỉ che warning, root cause\n// chưa fix). User yêu cầu \"KHÔNG defensive che lỗi\" → honest remove domain,\n// update tool description rõ Document search KHÔNG available (dùng\n// huly_list_documents trong teamspace cụ thể để browse document).\n\nimport { Type } from \"typebox\";\nimport { defineHulyTool, type HulyToolDefinition } from \"../builder.js\";\nimport { workspaceParam, limitParam, escapeLikePattern } from \"./_common.js\";\nimport { ISSUE_CLASS, CHAT_MESSAGE_CLASS } from \"./_class-refs.js\";\n\n/** Kết quả search từ 1 domain, tag type cho LLM phân biệt. */\ninterface SearchResult {\n  _id: string;\n  type: \"issue\" | \"message\";\n  identifier?: string;\n  title?: string;\n  preview?: string;\n}\n\n/**\n * Query 1 domain với $like substring, return tagged results.\n * Throw nếu server reject $like (caller catch → honest error).\n */\nasync function searchDomain(\n  client: Parameters<Parameters<typeof defineHulyTool>[0][\"handler\"]>[1][\"client\"],\n  _class: string,\n  field: string,\n  query: string,\n  limit: number,\n  type: SearchResult[\"type\"],\n): Promise<SearchResult[]> {\n  const docs = await client.findAll(\n    _class as never,\n    { [field]: { $like: `%${query}%` } } as never,\n    {\n      limit,\n    },\n  );\n  return (docs as unknown as Array<Record<string, unknown>>).map((d) => ({\n    _id: String(d._id ?? \"\"),\n    type,\n    identifier: d.identifier !== undefined ? String(d.identifier) : undefined,\n    title: d.title !== undefined ? String(d.title) : undefined,\n    preview:\n      d.content !== undefined\n        ? String(d.content).slice(0, 120)\n        : d.title !== undefined\n          ? String(d.title).slice(0, 120)\n          : undefined,\n  }));\n}\n\nexport const tools: HulyToolDefinition[] = [\n  // 1. fulltext_search — global (KHÔNG project-scoped)\n  defineHulyTool({\n    name: \"fulltext_search\",\n    label: \"Fulltext search\",\n    description:\n      \"Substring search across Huly workspace: issue titles + message content. \" +\n      \"Uses $like pattern (case-insensitive substring). NOT a fulltext index — \" +\n      \"complex queries may miss partial matches. Document search NOT available \" +\n      \"(Huly tracker:class:Document not registered runtime) — use huly_list_documents \" +\n      \"in a specific teamspace to browse documents. Global across workspace.\",\n    promptSnippet: \"Search Huly issues + messages by substring.\",\n    parameters: Type.Object({\n      workspace: workspaceParam,\n      query: Type.String({ description: \"Search query (substring, case-insensitive).\" }),\n      limit: limitParam,\n    }),\n    async handler(params, tctx) {\n      const limit = typeof params.limit === \"number\" ? params.limit : 50;\n      // Escape wildcards (% _ \\) tránh injection / unintended pattern.\n      const query = escapeLikePattern(params.query);\n\n      // T-77: prefer searchFulltext API (relevance-ranked fulltext index) khi\n      // available. Fallback $like substring nếu WS transport KHÔNG expose.\n      if (typeof tctx.client.searchFulltext === \"function\") {\n        try {\n          const raw = (await tctx.client.searchFulltext({ query: params.query }, { limit })) as {\n            docs?: Array<Record<string, unknown>>;\n            total?: number;\n          };\n          const docs = raw?.docs ?? [];\n          const results: SearchResult[] = docs.map((d) => {\n            const doc = (d.doc ?? d) as Record<string, unknown>;\n            return {\n              _id: String(doc._id ?? d.id ?? \"\"),\n              type: String(doc._class ?? \"\").includes(\"Issue\") ? \"issue\" : \"message\",\n              identifier: doc.identifier !== undefined ? String(doc.identifier) : undefined,\n              title:\n                d.title !== undefined\n                  ? String(d.title)\n                  : doc.title !== undefined\n                    ? String(doc.title)\n                    : undefined,\n              preview:\n                d.description !== undefined ? String(d.description).slice(0, 120) : undefined,\n            };\n          });\n          return {\n            content: `Found ${results.length} result(s) for \"${params.query}\" (searchFulltext).`,\n            details: {\n              count: results.length,\n              query: params.query,\n              engine: \"searchFulltext\",\n              results,\n            },\n          };\n        } catch {\n          // Fall through to $like fallback.\n        }\n      }\n\n      // T-60: chỉ 2 domain — Issue (title) + ChatMessage (content). Document\n      // domain REMOVE (class not registered runtime — #55 honest unavailable).\n      const domainConfigs: Array<{\n        name: string;\n        type: SearchResult[\"type\"];\n        _class: string;\n        field: string;\n      }> = [\n        { name: \"issues\", type: \"issue\", _class: ISSUE_CLASS, field: \"title\" },\n        { name: \"messages\", type: \"message\", _class: CHAT_MESSAGE_CLASS, field: \"content\" },\n      ];\n\n      try {\n        const settled = await Promise.allSettled(\n          domainConfigs.map((cfg) =>\n            searchDomain(tctx.client, cfg._class, cfg.field, query, limit, cfg.type),\n          ),\n        );\n\n        const results: SearchResult[] = [];\n        const counts: Record<string, number> = {};\n        const failedDomains: Array<{ name: string; reason: string }> = [];\n\n        settled.forEach((s, idx) => {\n          const cfg = domainConfigs[idx];\n          if (s.status === \"fulfilled\") {\n            results.push(...s.value);\n            counts[cfg.name] = s.value.length;\n          } else {\n            // Non-Error rejection (string/number/object) → String() fallback\n            const reason = s.reason instanceof Error ? s.reason.message : String(s.reason);\n            failedDomains.push({ name: cfg.name, reason });\n            counts[cfg.name] = 0;\n          }\n        });\n\n        // All domains failed → isError (KHÔNG fake \"Found 0 results\").\n        if (results.length === 0 && failedDomains.length === domainConfigs.length) {\n          const reasons = failedDomains.map((d) => `${d.name}: ${d.reason}`).join(\"; \");\n          return {\n            content: `All search domains failed: ${reasons}.`,\n            isError: true,\n            details: { query: params.query, failedDomains },\n          };\n        }\n\n        // Build content: partial result + warning nếu có domain fail.\n        const countSummary = domainConfigs\n          .map((cfg) => `${counts[cfg.name]} ${cfg.name}`)\n          .join(\", \");\n        let content = `Found ${results.length} result(s) for \"${params.query}\" (${countSummary}).`;\n        if (failedDomains.length > 0) {\n          const warnings = failedDomains\n            .map((d) => `${d.name} search failed: ${d.reason.slice(0, 100)}`)\n            .join(\" | \");\n          content += ` Warning: ${warnings}.`;\n        }\n\n        return {\n          content,\n          details: {\n            count: results.length,\n            query: params.query,\n            results,\n            failedDomains: failedDomains.length > 0 ? failedDomains : undefined,\n          },\n        };\n      } catch (e) {\n        // Safety net cho unexpected programming errors.\n        const msg = e instanceof Error ? e.message : String(e);\n        return {\n          content: `Search failed unexpectedly: ${msg}.`,\n          isError: true,\n          details: { query: params.query, error: msg },\n        };\n      }\n    },\n  }),\n];\n","// tools/domains/deletion.ts — Deletion preview domain (1 tool).\n// Design: 06-api.md §4 Deletion. Preview cascade trước khi delete.\n\nimport { Type } from \"typebox\";\nimport { defineHulyTool, type HulyToolDefinition } from \"../builder.js\";\nimport { workspaceParam, projectParam, identifierParam, resolveIdentifier } from \"./_common.js\";\nimport { ISSUE_CLASS } from \"./_class-refs.js\";\n\nexport const tools: HulyToolDefinition[] = [\n  // 1. preview_deletion — cascade preview\n  defineHulyTool({\n    name: \"preview_deletion\",\n    label: \"Preview deletion\",\n    description:\n      \"Preview cascade deletion của entity (issues, comments, attachments affected). KHÔNG xóa — preview only.\",\n    needsProject: true,\n    parameters: Type.Object({\n      workspace: workspaceParam,\n      project: projectParam,\n      identifier: identifierParam,\n      _class: Type.Optional(\n        Type.String({ description: \"Entity _class (default: tracker:class:Issue).\" }),\n      ),\n    }),\n    async handler(params, tctx) {\n      const cls = (params._class ?? ISSUE_CLASS) as never;\n      const entity = await tctx.client.findOne(cls, {\n        identifier: resolveIdentifier(tctx.project!, params.identifier),\n      });\n      if (!entity) {\n        return {\n          content: `Entity \"${params.identifier}\" not found.`,\n          isError: true,\n          details: { identifier: params.identifier },\n        };\n      }\n      // T-84 #119: read CollectionSize counters trực tiếp từ entity (subIssues/\n      // comments/attachments) + inline blockedBy/relations. KHÔNG N+1 findAll\n      // (Issue có sẵn counters) + KHÔNG reverseBlocks (dotted-path `blockedBy._id`\n      // broken query — T-80 confirmed trả 0 rows; trusted previewIssueDeletion\n      // không track direction này). total match trusted formula (no +1 entity).\n      const issueFields = entity as {\n        subIssues?: number;\n        comments?: number;\n        attachments?: number;\n        blockedBy?: Array<{ _id?: string }>;\n        relations?: Array<{ _id?: string }>;\n      };\n      const subIssues = issueFields.subIssues ?? 0;\n      const comments = issueFields.comments ?? 0;\n      const attachments = issueFields.attachments ?? 0;\n      const blockedByCount = issueFields.blockedBy?.length ?? 0;\n      const relationsCount = issueFields.relations?.length ?? 0;\n      const cascade = {\n        entity: entity._id,\n        comments,\n        attachments,\n        subIssues,\n        blockedBy: blockedByCount,\n        relations: relationsCount,\n        total: subIssues + comments + attachments + blockedByCount + relationsCount,\n      };\n      const warnings: string[] = [];\n      if (subIssues > 0) warnings.push(`${subIssues} sub-issue(s) orphaned`);\n      if (blockedByCount > 0) warnings.push(`${blockedByCount} blockedBy reference(s) dropped`);\n      if (relationsCount > 0) warnings.push(`${relationsCount} relation(s) dropped`);\n      const warnText = warnings.length > 0 ? ` Warnings: ${warnings.join(\"; \")}.` : \"\";\n      return {\n        content: `Deletion preview for ${params.identifier}: ${cascade.total} item(s) affected (${subIssues} sub-issues + ${comments} comments + ${attachments} attachments + ${blockedByCount} blockedBy + ${relationsCount} relations).${warnText}`,\n        details: { cascade, warnings: warnings.length > 0 ? warnings : undefined },\n      };\n    },\n  }),\n];\n","// tools/domains/time.ts — Time log domain (1 tool).\n// Design: 06-api.md §4 Time.\n//\n// T-74 (2026-07-28): collection \"reports\" (KHÔNG \"timetracking\"), value = hours\n// (Huly native unit, fractional OK — 0.25 = 15min), date + employee fields.\n// reality-checker CONFIRMED vs trusted time.ts + tracker-types.ts.\n\nimport { Type } from \"typebox\";\nimport { defineHulyTool, type HulyToolDefinition } from \"../builder.js\";\nimport { TIME_SPEND_REPORT_CLASS, ISSUE_CLASS, EMPLOYEE_CLASS } from \"./_class-refs.js\";\nimport { workspaceParam, projectParam, identifierParam, resolveIdentifier } from \"./_common.js\";\n\nexport const tools: HulyToolDefinition[] = [\n  // 1. log_time — T-74: value = hours (Huly native unit)\n  defineHulyTool({\n    name: \"log_time\",\n    label: \"Log time\",\n    description:\n      \"Log time on issue (value = HOURS, Huly native unit — 0.25 = 15min, 8 = 1 work day). \" +\n      \"Fractional allowed. Employee resolved từ current user.\",\n    promptSnippet: \"Log time spent on a Huly issue.\",\n    needsProject: true,\n    parameters: Type.Object({\n      workspace: workspaceParam,\n      project: projectParam,\n      identifier: identifierParam,\n      value: Type.Number({\n        description: \"Time in HOURS (0.25 = 15min, 8 = 1 day).\",\n        minimum: 0.01,\n      }),\n      description: Type.Optional(Type.String()),\n    }),\n    async handler(params, tctx) {\n      // T-103 #158: guard value > 0 (schema min 0.01 unenforced — negative =\n      // time corruption, 0 = noise). Reject loudly.\n      if (!(params.value > 0)) {\n        return {\n          content: `log_time value must be > 0 hours (got ${params.value}). Negative corrupts tracked time, 0 is noise.`,\n          isError: true,\n          details: { identifier: params.identifier, value: params.value },\n        };\n      }\n      const issue = await tctx.client.findOne(ISSUE_CLASS, {\n        identifier: resolveIdentifier(tctx.project!, params.identifier),\n      });\n      if (!issue) {\n        return {\n          content: `Issue \"${params.identifier}\" not found.`,\n          isError: true,\n          details: { identifier: params.identifier },\n        };\n      }\n      // T-74: resolve current user → Employee ref (best-effort).\n      let employeeRef: string | undefined;\n      try {\n        const user = await tctx.client.getCurrentUser();\n        const emp = await tctx.client.findOne(EMPLOYEE_CLASS, {\n          personUuid: user.id,\n        } as never);\n        employeeRef = emp?._id;\n      } catch {\n        // Resolution fail — omit employee, server may default to current.\n      }\n      const attrs: Record<string, unknown> = {\n        value: params.value,\n        date: Date.now(),\n      };\n      if (params.description !== undefined) attrs.description = params.description;\n      if (employeeRef !== undefined) attrs.employee = employeeRef;\n      // T-74: collection \"reports\" (KHÔNG \"timetracking\" — Issue.reports field).\n      await tctx.client.addCollection(\n        TIME_SPEND_REPORT_CLASS,\n        issue.space as never,\n        issue._id as never,\n        ISSUE_CLASS,\n        \"reports\",\n        attrs as never,\n      );\n      return {\n        content: `Logged ${params.value}h on ${params.identifier}.`,\n        details: {\n          identifier: params.identifier,\n          value: params.value,\n          unit: \"hours\",\n          employee: employeeRef,\n          date: attrs.date,\n        },\n      };\n    },\n  }),\n];\n","// tools/domains/documents.ts — Documents/Teamspaces domain (10 tools).\n// Design: 06-api.md §4 Documents/Teamspaces. Teamspace + Document CRUD.\n//\n// T-66 (2026-07-28): RE-ENABLE từ honest-unavailable (T-58/T-60 conclusion sai).\n// Real class registered trong @hcengineering/document plugin() block — verified\n// vs trusted huly-mcp v0.45. Class refs từ _class-refs.ts (T-65 fix):\n//   TEAMSPACE_CLASS = document:class:Teamspace\n//   DOCUMENT_CLASS  = document:class:Document\n//\n// Teamspace model (verified trusted documents.ts):\n//   - findAll/findOne TEAMSPACE_CLASS (KHÔNG SPACE_CLASS — trả cross all spaces)\n//   - CRUD space param = core.space.Space (root, top-level space parent)\n//   - fields: name, description, private, archived, members, owners\n//   - create needs icon (documentPlugin.icon.Teamspace) + spaceType\n//     (documentPlugin.spaceType.DefaultTeamspaceType) — Ref values từ document\n//     plugin, pi-huly KHÔNG bundle → create_teamspace stays honest-unavailable.\n//\n// Document model (verified trusted documents-edit.ts):\n//   - findAll/findOne DOCUMENT_CLASS + space=teamspace._id (scoping)\n//   - content = MarkupBlobRef → fetchMarkup (get) / uploadMarkup (create+edit).\n//     Library KHÔNG có updateMarkup — edit = uploadMarkup + updateDoc (new ref).\n//   - parent: Ref<Document> (document hierarchy), rank (lexorank)\n\nimport { Type } from \"typebox\";\nimport { defineHulyTool, type HulyToolDefinition } from \"../builder.js\";\nimport {\n  TEAMSPACE_CLASS,\n  TEAMSPACE_ICON,\n  DEFAULT_TEAMSPACE_TYPE,\n  SPACE_PARENT,\n  DOCUMENT_CLASS,\n  DOCUMENT_NO_PARENT,\n} from \"./_class-refs.js\";\nimport { workspaceParam, limitParam, safeRemoveDoc } from \"./_common.js\";\nimport type { TeamspaceDoc, DocumentDoc } from \"./_entity-types.js\";\n// generateId từ @hcengineering/core (CJS). Default/namespace import đều gãy\n// interop (giống makeCollabId T-103) → createRequire. Trả hex 24 ký tự, match\n// doc thật + huly-mcp (KHÔNG dùng `${DOCUMENT_CLASS}.<rand>` class-prefix — id\n// hex là convention Huly).\nimport { createRequire } from \"node:module\";\nconst generateId = (\n  createRequire(import.meta.url)(\"@hcengineering/core\") as {\n    generateId: () => string;\n  }\n).generateId;\n\n/** Teamspace CRUD space = core.space.Space (root, top-level space parent). */\nconst TEAMSPACE_PARENT_SPACE = SPACE_PARENT;\n\nexport const tools: HulyToolDefinition[] = [\n  // === Teamspaces (5) ===\n\n  // 1. list_teamspaces — T-66: TEAMSPACE_CLASS (chỉ trả Teamspace, không lẫn Project/Drive)\n  defineHulyTool({\n    name: \"list_teamspaces\",\n    label: \"List teamspaces\",\n    description: \"List teamspaces (document spaces).\",\n    parameters: Type.Object({ workspace: workspaceParam, limit: limitParam }),\n    async handler(params, tctx) {\n      const limit = typeof params.limit === \"number\" ? params.limit : 50;\n      // T-88 #123: sort name Ascending (trusted). T-90: native TeamspaceDoc.\n      const spaces = await tctx.client.findAll<TeamspaceDoc>(\n        TEAMSPACE_CLASS,\n        { archived: false },\n        {\n          limit,\n          sort: { name: 1 },\n        },\n      );\n      const list = spaces.map((s) => ({\n        id: s._id,\n        name: s.name ?? \"\",\n        description: s.description,\n        private: s.private ?? false,\n        archived: s.archived ?? false,\n      }));\n      // T-78: surface ids+names trong content (agent đọc content để resolve).\n      const lines = list.map((t) => `- ${t.name} (${t.id})`).join(\"\\n\");\n      return {\n        content:\n          list.length === 0\n            ? \"No teamspaces found.\"\n            : `Found ${list.length} teamspace(s):\\n${lines}`,\n        details: { count: list.length, teamspaces: list },\n      };\n    },\n  }),\n\n  // 2. get_teamspace — T-66: TEAMSPACE_CLASS\n  defineHulyTool({\n    name: \"get_teamspace\",\n    label: \"Get teamspace\",\n    description: \"Get teamspace by id.\",\n    parameters: Type.Object({\n      workspace: workspaceParam,\n      teamspace: Type.String(),\n    }),\n    async handler(params, tctx) {\n      const s = await tctx.client.findOne<TeamspaceDoc>(TEAMSPACE_CLASS, { _id: params.teamspace });\n      if (!s) {\n        return {\n          content: `Teamspace \"${params.teamspace}\" not found.`,\n          isError: true,\n          details: { teamspace: params.teamspace },\n        };\n      }\n      // T-88 #123: document count trong teamspace (capped 1000). T-90: native DocumentDoc.\n      const docs = await tctx.client.findAll<DocumentDoc>(\n        DOCUMENT_CLASS,\n        { space: s._id },\n        {\n          limit: 1000,\n        },\n      );\n      return {\n        content: `Teamspace ${s.name ?? \"\"}`,\n        details: {\n          id: s._id,\n          name: s.name,\n          description: s.description,\n          private: s.private,\n          archived: s.archived ?? false,\n          documentCount: docs.length,\n        },\n      };\n    },\n  }),\n\n  // 3. create_teamspace — T-78: implement (string-literal icon/spaceType refs).\n  // Idempotent: return existing nếu name đã tồn tại (archived:false).\n  defineHulyTool({\n    name: \"create_teamspace\",\n    label: \"Create teamspace\",\n    description:\n      \"Create teamspace. Idempotent (returns existing if name exists). \" +\n      \"Returns teamspace id for use in document tools.\",\n    parameters: Type.Object({\n      workspace: workspaceParam,\n      name: Type.String(),\n      description: Type.Optional(Type.String()),\n      private: Type.Optional(Type.Boolean()),\n    }),\n    async handler(params, tctx) {\n      // Idempotent: findOne by name (archived:false).\n      const existing = await tctx.client.findOne(TEAMSPACE_CLASS, {\n        name: params.name,\n        archived: false,\n      });\n      if (existing) {\n        return {\n          content: `Teamspace \"${params.name}\" already exists (id ${existing._id}).`,\n          details: { id: existing._id, name: params.name, created: false },\n        };\n      }\n      // Account UUID for members/owners.\n      const account = await tctx.client.getAccount();\n      const uuid = account.uuid as string;\n      const id = await tctx.client.createDoc(TEAMSPACE_CLASS, TEAMSPACE_PARENT_SPACE, {\n        name: params.name,\n        description: params.description ?? \"\",\n        private: params.private ?? false,\n        archived: false,\n        members: [uuid],\n        owners: [uuid],\n        icon: TEAMSPACE_ICON,\n        type: DEFAULT_TEAMSPACE_TYPE,\n      } as never);\n      return {\n        content: `Created teamspace \"${params.name}\" (id ${id}).`,\n        details: { id, name: params.name, created: true },\n      };\n    },\n  }),\n\n  // 4. update_teamspace — T-66: TEAMSPACE_CLASS + core.space.Space parent\n  defineHulyTool({\n    name: \"update_teamspace\",\n    label: \"Update teamspace\",\n    description: \"Update teamspace (name, description, private).\",\n    parameters: Type.Object({\n      workspace: workspaceParam,\n      teamspace: Type.String(),\n      name: Type.Optional(Type.String()),\n      description: Type.Optional(Type.String()),\n      private: Type.Optional(Type.Boolean()),\n    }),\n    async handler(params, tctx) {\n      const s = await tctx.client.findOne(TEAMSPACE_CLASS, { _id: params.teamspace });\n      if (!s) {\n        return {\n          content: `Teamspace \"${params.teamspace}\" not found.`,\n          isError: true,\n          details: { teamspace: params.teamspace },\n        };\n      }\n      const ops: Record<string, unknown> = {};\n      if (params.name !== undefined) ops.name = params.name;\n      if (params.description !== undefined) ops.description = params.description;\n      if (params.private !== undefined) ops.private = params.private;\n      if (Object.keys(ops).length === 0) {\n        return { content: \"No fields to update.\", details: { updated: false } };\n      }\n      // Teamspace = top-level space, parent space = core.space.Space (root).\n      await tctx.client.updateDoc(\n        TEAMSPACE_CLASS,\n        TEAMSPACE_PARENT_SPACE,\n        s._id as never,\n        ops as never,\n      );\n      return {\n        content: `Updated teamspace ${params.teamspace}.`,\n        details: { updated: true, fields: Object.keys(ops) },\n      };\n    },\n  }),\n\n  // 5. delete_teamspace — destructive. T-66: TEAMSPACE_CLASS + core.space.Space\n  defineHulyTool({\n    name: \"delete_teamspace\",\n    label: \"Delete teamspace\",\n    description: \"Delete teamspace (destructive). Cascade xóa tất cả documents.\",\n    destructive: true,\n    destructiveContext: (p) => ({\n      type: \"teamspace\",\n      id: (p as { teamspace?: string }).teamspace ?? \"<unknown>\",\n    }),\n    parameters: Type.Object({\n      workspace: workspaceParam,\n      teamspace: Type.String(),\n    }),\n    async handler(params, tctx) {\n      const s = await tctx.client.findOne(TEAMSPACE_CLASS, { _id: params.teamspace });\n      if (!s) {\n        return {\n          content: `Teamspace \"${params.teamspace}\" not found.`,\n          isError: true,\n          details: { teamspace: params.teamspace },\n        };\n      }\n      await tctx.client.removeDoc(TEAMSPACE_CLASS, TEAMSPACE_PARENT_SPACE, s._id as never);\n      return {\n        content: `Deleted teamspace ${params.teamspace}.`,\n        details: { deleted: true, teamspace: params.teamspace },\n      };\n    },\n  }),\n\n  // === Documents (5) — T-66: RE-ENABLED (DOCUMENT_CLASS + space scoping) ===\n\n  // 6. list_documents — T-66: DOCUMENT_CLASS + space=teamspace._id\n  defineHulyTool({\n    name: \"list_documents\",\n    label: \"List documents\",\n    description: \"List documents in a teamspace.\",\n    parameters: Type.Object({\n      workspace: workspaceParam,\n      teamspace: Type.String(),\n      limit: limitParam,\n      titleSearch: Type.Optional(Type.String()),\n    }),\n    async handler(params, tctx) {\n      const ts = await tctx.client.findOne<TeamspaceDoc>(TEAMSPACE_CLASS, {\n        _id: params.teamspace,\n      });\n      if (!ts) {\n        return {\n          content: `Teamspace \"${params.teamspace}\" not found.`,\n          isError: true,\n          details: { teamspace: params.teamspace },\n        };\n      }\n      const limit = typeof params.limit === \"number\" ? params.limit : 50;\n      const query: Record<string, unknown> = { space: ts._id };\n      if (params.titleSearch) {\n        query.title = { $like: `%${params.titleSearch}%` };\n      }\n      // T-88 #123: sort modifiedOn Descending + output teamspace/modifiedOn. T-90: native DocumentDoc.\n      const docs = await tctx.client.findAll<DocumentDoc>(DOCUMENT_CLASS, query, {\n        limit,\n        sort: { modifiedOn: -1 },\n      });\n      const tsName = ts.name ?? params.teamspace;\n      const list = docs.map((d) => ({\n        id: d._id,\n        title: d.title ?? \"\",\n        teamspace: tsName,\n        modifiedOn: d.modifiedOn,\n      }));\n      // T-88 #123 fix: surface titles+ids trong content (giống list_teamspaces).\n      // Trước đó chỉ count → LLM/consumer không thấy danh sách.\n      const lines = list.map((d) => `- ${d.title || \"(untitled)\"} (${d.id})`).join(\"\\n\");\n      return {\n        content:\n          list.length === 0\n            ? `No documents found in teamspace \"${tsName}\".`\n            : `Found ${list.length} document(s) in teamspace \"${tsName}\":\\n${lines}`,\n        details: { count: list.length, documents: list },\n      };\n    },\n  }),\n\n  // 7. get_document — T-66: DOCUMENT_CLASS + fetchMarkup content\n  defineHulyTool({\n    name: \"get_document\",\n    label: \"Get document\",\n    description: \"Get document by id with full content (markdown).\",\n    parameters: Type.Object({\n      workspace: workspaceParam,\n      document: Type.String(),\n    }),\n    async handler(params, tctx) {\n      const d = await tctx.client.findOne<DocumentDoc>(DOCUMENT_CLASS, { _id: params.document });\n      if (!d) {\n        return {\n          content: `Document \"${params.document}\" not found.`,\n          isError: true,\n          details: { document: params.document },\n        };\n      }\n      // Document.content = MarkupBlobRef → fetchMarkup resolve to markdown.\n      const contentRef = d.content;\n      let content: string | undefined;\n      if (contentRef) {\n        try {\n          content = await tctx.client.fetchMarkup(\n            DOCUMENT_CLASS,\n            d._id,\n            \"content\",\n            contentRef,\n            \"markdown\",\n          );\n        } catch {\n          // Markup fetch fail (blob missing/corrupted) — return metadata without content.\n        }\n      }\n      // T-88 #123: resolve teamspace name + createdOn. T-90: native TeamspaceDoc.\n      let teamspaceName: string | undefined;\n      if (d.space) {\n        const ts = await tctx.client.findOne<TeamspaceDoc>(TEAMSPACE_CLASS, { _id: d.space });\n        teamspaceName = ts?.name;\n      }\n      // T-88 #123 fix: body markdown phải đến content text (LLM đọc document).\n      // Trước đó content chỉ = \"Document <title>\" — body nằm trong details.content\n      // (string, KHÔNG array) → appendDetailsForLLM skip → LLM mất body hoàn toàn.\n      const titleDisplay = d.title?.trim() || \"(untitled)\";\n      const header = `Document \"${titleDisplay}\" (id ${d._id})`;\n      const body = content ?? \"(no content)\";\n      return {\n        content: `${header}\\n\\n---\\n${body}`,\n        details: {\n          id: d._id,\n          title: d.title,\n          teamspace: teamspaceName ?? d.space,\n          createdOn: d.createdOn,\n        },\n      };\n    },\n  }),\n\n  // 8. create_document — T-66: DOCUMENT_CLASS + uploadMarkup content\n  defineHulyTool({\n    name: \"create_document\",\n    label: \"Create document\",\n    description: \"Create document in a teamspace with optional markdown content.\",\n    parameters: Type.Object({\n      workspace: workspaceParam,\n      teamspace: Type.String(),\n      title: Type.String(),\n      content: Type.Optional(Type.String({ description: \"Markdown content.\" })),\n      parent: Type.Optional(\n        Type.String({\n          description:\n            \"Parent document title or _id trong cùng teamspace (tạo nested doc). Bỏ qua = top-level.\",\n        }),\n      ),\n    }),\n    async handler(params, tctx) {\n      const ts = await tctx.client.findOne(TEAMSPACE_CLASS, { _id: params.teamspace });\n      if (!ts) {\n        return {\n          content: `Teamspace \"${params.teamspace}\" not found.`,\n          isError: true,\n          details: { teamspace: params.teamspace },\n        };\n      }\n      // T-doc-parent: resolve parent doc (nếu có) — by _id trước, fallback title,\n      // scope trong teamspace. Match huly-mcp findByNameOrId pattern.\n      let parentRef: string = DOCUMENT_NO_PARENT;\n      if (params.parent !== undefined) {\n        const byId = await tctx.client.findOne<DocumentDoc>(DOCUMENT_CLASS, {\n          _id: params.parent as never,\n          space: ts._id as never,\n        } as never);\n        const parentDoc =\n          byId ??\n          (await tctx.client.findOne<DocumentDoc>(DOCUMENT_CLASS, {\n            title: params.parent,\n            space: ts._id as never,\n          } as never));\n        if (!parentDoc) {\n          return {\n            content: `Parent document \"${params.parent}\" not found in teamspace \"${\n              (ts as { name?: string }).name ?? params.teamspace\n            }\" (by _id or title).`,\n            isError: true,\n            details: { parent: params.parent, teamspace: ts._id },\n          };\n        }\n        parentRef = parentDoc._id;\n      }\n      // T-doc-parent: generateId() (hex 24, convention Huly) — KHÔNG `${DOCUMENT_CLASS}.<rand>`.\n      const docId = generateId();\n      let contentRef: unknown = null;\n      if (params.content && params.content.trim() !== \"\") {\n        contentRef = await tctx.client.uploadMarkup(\n          DOCUMENT_CLASS,\n          docId,\n          \"content\",\n          params.content,\n          \"markdown\",\n        );\n      }\n      const newId = await tctx.client.createDoc(\n        DOCUMENT_CLASS,\n        ts._id as never,\n        {\n          title: params.title,\n          content: contentRef,\n          // T-doc-parent: top-level marker hoặc parent doc._id (nested).\n          // Web Documents tree query top-level = { parent: \"document:ids:NoParent\" }.\n          parent: parentRef,\n        } as never,\n        docId as never,\n      );\n      return {\n        content: `Created document \"${params.title}\" in teamspace \"${\n          (ts as { name?: string }).name ?? params.teamspace\n        }\"${params.parent ? ` under \"${params.parent}\"` : \" (top-level)\"}.`,\n        details: { id: newId, title: params.title, teamspace: ts._id, parent: parentRef },\n      };\n    },\n  }),\n\n  // 9. edit_document — T-66: DOCUMENT_CLASS + uploadMarkup+updateDoc (no updateMarkup)\n  defineHulyTool({\n    name: \"edit_document\",\n    label: \"Edit document\",\n    description: \"Edit document. Either full content replace OR search-and-replace.\",\n    parameters: Type.Object({\n      workspace: workspaceParam,\n      document: Type.String(),\n      old_text: Type.Optional(Type.String()),\n      new_text: Type.Optional(Type.String()),\n      content: Type.Optional(Type.String({ description: \"Full new content (markdown).\" })),\n      replace_all: Type.Optional(\n        Type.Boolean({ description: \"true nếu old_text match nhiều (default false).\" }),\n      ),\n    }),\n    async handler(params, tctx) {\n      const d = await tctx.client.findOne(DOCUMENT_CLASS, { _id: params.document });\n      if (!d) {\n        return {\n          content: `Document \"${params.document}\" not found.`,\n          isError: true,\n          details: { document: params.document },\n        };\n      }\n      const existingContentRef = (d as { content?: unknown }).content;\n      // Markup blobs immutable — @hcengineering KHÔNG có updateMarkup method.\n      // Mỗi edit = uploadMarkup (tạo version mới) + updateDoc point content → ref mới.\n      const saveContent = async (text: string): Promise<void> => {\n        // T-103 #156: createMarkup (uploadMarkup/createContent rpc) KHÔNG update\n        // document đã tồn tại (content unchanged + 0 snapshot). Dùng updateMarkup\n        // (updateContent rpc) — edit operation đúng cho existing doc content.\n        await tctx.client.updateMarkup!(DOCUMENT_CLASS, d._id, \"content\", text, \"markdown\");\n      };\n\n      // Mode validation: content vs old_text/new_text mutually exclusive.\n      if (params.content !== undefined && (params.old_text || params.new_text)) {\n        return {\n          content: \"edit_document: content cannot combine with old_text/new_text.\",\n          isError: true,\n          details: { document: params.document },\n        };\n      }\n\n      // Mode 1: full content replace.\n      if (params.content !== undefined) {\n        const newContent = params.content.trim() === \"\" ? \"\" : params.content;\n        await saveContent(newContent);\n        return {\n          content: `Updated document ${params.document} content.`,\n          details: { updated: true, mode: \"content-replace\", document: d._id },\n        };\n      }\n\n      // Mode 2: search-and-replace.\n      if (params.old_text !== undefined && params.new_text !== undefined) {\n        if (!existingContentRef) {\n          return {\n            content: `Document \"${params.document}\" has no content to search.`,\n            isError: true,\n            details: { document: params.document },\n          };\n        }\n        const current = await tctx.client.fetchMarkup(\n          DOCUMENT_CLASS,\n          d._id,\n          \"content\",\n          existingContentRef,\n          \"markdown\",\n        );\n        const idx = current.indexOf(params.old_text);\n        if (idx === -1) {\n          return {\n            content: `Text not found in document \"${params.document}\".`,\n            isError: true,\n            details: { document: params.document, search: params.old_text },\n          };\n        }\n        const occurrences = current.split(params.old_text).length - 1;\n        if (occurrences > 1 && !params.replace_all) {\n          return {\n            content: `Text matches ${occurrences} times. Set replace_all=true to replace all.`,\n            isError: true,\n            details: { document: params.document, matches: occurrences },\n          };\n        }\n        const updated = params.replace_all\n          ? current.split(params.old_text).join(params.new_text)\n          : current.substring(0, idx) +\n            params.new_text +\n            current.substring(idx + params.old_text.length);\n        await saveContent(updated);\n        return {\n          content: `Updated document ${params.document} (search-replace).`,\n          details: {\n            updated: true,\n            mode: \"search-replace\",\n            replaced: params.replace_all ? occurrences : 1,\n            document: d._id,\n          },\n        };\n      }\n\n      return {\n        content: \"edit_document: provide content OR old_text+new_text.\",\n        isError: true,\n        details: { document: params.document },\n      };\n    },\n  }),\n\n  // 10. delete_document — destructive. T-66: DOCUMENT_CLASS + space from doc\n  defineHulyTool({\n    name: \"delete_document\",\n    label: \"Delete document\",\n    description: \"Delete document (destructive).\",\n    destructive: true,\n    destructiveContext: (p) => ({\n      type: \"document\",\n      id: (p as { document?: string }).document ?? \"<unknown>\",\n    }),\n    parameters: Type.Object({\n      workspace: workspaceParam,\n      document: Type.String(),\n    }),\n    async handler(params, tctx) {\n      const d = await tctx.client.findOne(DOCUMENT_CLASS, { _id: params.document });\n      if (!d) {\n        return {\n          content: `Document \"${params.document}\" not found.`,\n          isError: true,\n          details: { document: params.document },\n        };\n      }\n      const delResult = await safeRemoveDoc(tctx.client, DOCUMENT_CLASS, d);\n      if (!delResult.ok) return delResult.error;\n      return {\n        content: `Deleted document ${params.document}.`,\n        details: { deleted: true, document: params.document },\n      };\n    },\n  }),\n];\n","// tools/domains/issues-hierarchy.ts — Issue parent/child hierarchy helpers.\n//\n// T-68 (2026-07-28): Huly models issue hierarchy qua AttachedDoc fields:\n//   - attachedTo:      Ref<Issue> — parent issue _id (top-level = NoParent \"\")\n//   - attachedToClass: Ref<Class>  — tracker:class:Issue\n//   - collection:      \"subIssues\" — Huly collection name\n//   - parents:         IssueParentInfo[] — breadcrumb (grandparents → direct parent)\n//   - subIssues:       number — count of direct children\n//\n// Field `parentIssue` KHÔNG tồn tại runtime (T-68 root cause — trusted\n// issues-parent.ts dùng attachedTo/attachedToClass/collection/parents).\n//\n// Port từ trusted issues-parent.ts + issues-move.ts (adapted: string-literal\n// class refs, direct async/await thay Effect, HulyClient interface pi-huly).\n\nimport type { HulyClient } from \"../../client/client.js\";\nimport { ISSUE_CLASS, NO_PARENT_REF } from \"./_class-refs.js\";\n\n/** IssueParentInfo shape (Huly tracker): breadcrumb entry cho parent chain. */\nexport interface IssueParentInfo {\n  parentId: string;\n  identifier: string;\n  parentTitle: string;\n  space: string;\n}\n\n/** Minimal issue shape cho hierarchy ops (chỉ cần fields hierarchy). */\nexport interface IssueHierarchyFields {\n  _id: string;\n  identifier?: string;\n  title?: string;\n  attachedTo?: string;\n  attachedToClass?: string;\n  subIssues?: number;\n  parents?: IssueParentInfo[];\n  space?: string;\n}\n\n/** Parent data cần set khi attach issue làm child (hoặc top-level). */\nexport interface IssueParentData {\n  attachedTo: string; // Ref<Issue> or NoParent \"\"\n  attachedToClass: string; // ISSUE_CLASS\n  collection: \"subIssues\";\n  parents: IssueParentInfo[];\n}\n\n/** Build parent data cho top-level issue (NoParent sentinel). */\nexport function topLevelIssueParent(): IssueParentData {\n  return {\n    attachedTo: NO_PARENT_REF as string,\n    attachedToClass: ISSUE_CLASS as string,\n    collection: \"subIssues\",\n    parents: [],\n  };\n}\n\n/** Build parent data cho child issue (attached to parentIssue). */\nexport function childIssueParent(\n  parentIssue: Pick<IssueHierarchyFields, \"_id\" | \"identifier\" | \"parents\" | \"title\">,\n  projectSpace: string,\n): IssueParentData {\n  return {\n    attachedTo: parentIssue._id,\n    attachedToClass: ISSUE_CLASS as string,\n    collection: \"subIssues\",\n    parents: [\n      ...((parentIssue.parents as IssueParentInfo[] | undefined) ?? []),\n      {\n        parentId: parentIssue._id,\n        identifier: parentIssue.identifier ?? \"\",\n        parentTitle: parentIssue.title ?? \"\",\n        space: projectSpace,\n      },\n    ],\n  };\n}\n\n/** Check nếu issue có parent là issue (KHÔNG phải top-level NoParent). */\nexport function hasConcreteIssueParent(\n  issue: Pick<IssueHierarchyFields, \"attachedTo\" | \"attachedToClass\">,\n): boolean {\n  return (\n    issue.attachedToClass === (ISSUE_CLASS as string) &&\n    issue.attachedTo !== (NO_PARENT_REF as string) &&\n    issue.attachedTo !== undefined &&\n    issue.attachedTo !== \"\"\n  );\n}\n\n/**\n * Attach issue làm child của parentIssue:\n *   1. updateDoc issue: set attachedTo/attachedToClass/collection/parents + extra ops\n *   2. updateDoc parentIssue: $inc subIssues +1\n *\n * Non-atomic (2 thao tác riêng, khớp trusted attachIssueChild).\n */\nexport async function attachIssueChild(\n  client: HulyClient,\n  projectSpace: string,\n  childId: string,\n  parentIssue: Pick<IssueHierarchyFields, \"_id\" | \"identifier\" | \"parents\" | \"title\">,\n  additionalUpdate: Record<string, unknown>,\n): Promise<void> {\n  const parent = childIssueParent(parentIssue, projectSpace);\n  await client.updateDoc(\n    ISSUE_CLASS,\n    projectSpace as never,\n    childId as never,\n    {\n      ...additionalUpdate,\n      attachedTo: parent.attachedTo,\n      attachedToClass: parent.attachedToClass,\n      collection: parent.collection,\n      parents: parent.parents,\n    } as never,\n  );\n  await client.updateDoc(\n    ISSUE_CLASS,\n    projectSpace as never,\n    parentIssue._id as never,\n    { $inc: { subIssues: 1 } } as never,\n  );\n}\n\n/**\n * Recursively update parents[] breadcrumb trên tất cả descendants khi 1 issue\n * được move. Mỗi descendant giữ chain cũ NHƯNG prepend new ancestor chain.\n *\n * Port từ trusted updateDescendantParents (issues-move.ts:161-188).\n */\nexport async function updateDescendantParents(\n  client: HulyClient,\n  spaceId: string,\n  parentIssue: IssueHierarchyFields,\n  parentNewParents: IssueParentInfo[],\n): Promise<void> {\n  const thisParentInfo: IssueParentInfo = {\n    parentId: parentIssue._id,\n    identifier: parentIssue.identifier ?? \"\",\n    parentTitle: parentIssue.title ?? \"\",\n    space: spaceId,\n  };\n  const children = (await client.findAll(ISSUE_CLASS, {\n    attachedTo: parentIssue._id,\n    space: spaceId,\n  } as never)) as IssueHierarchyFields[];\n  for (const child of children) {\n    const childNewParents = [...parentNewParents, thisParentInfo];\n    await client.updateDoc(\n      ISSUE_CLASS,\n      spaceId as never,\n      child._id as never,\n      { parents: childNewParents } as never,\n    );\n    if ((child.subIssues ?? 0) > 0) {\n      await updateDescendantParents(client, spaceId, child, childNewParents);\n    }\n  }\n}\n","// tools/domains/issues-core.ts — Issues core domain (8 tools).\n// Design: 06-api.md §4 Issues (subset). List/get/create/update/delete/move + labels.\n//\n// Tools (8, FR-04 D4):\n//   1. list_issues      2. get_issue      3. create_issue\n//   4. update_issue     5. delete_issue   6. move_issue\n//   7. add_issue_label  8. remove_issue_label\n//\n// Assignee default: D15 FR-18 (currentUser email khi absent).\n\nimport { Type } from \"typebox\";\nimport { defineHulyTool, type HulyToolDefinition } from \"../builder.js\";\nimport {\n  ISSUE_CLASS,\n  PROJECT_CLASS,\n  PERSON_CLASS,\n  COMPONENT_CLASS,\n  TAG_REFERENCE_CLASS,\n  TAG_CLASS,\n  idRef,\n  NO_PARENT_REF,\n  ISSUE_KIND_REF,\n} from \"./_class-refs.js\";\nimport type { TagElementDoc, TagReferenceDoc } from \"./_entity-types.js\";\nimport {\n  topLevelIssueParent,\n  attachIssueChild,\n  hasConcreteIssueParent,\n  updateDescendantParents,\n  type IssueHierarchyFields,\n} from \"./issues-hierarchy.js\";\nimport {\n  workspaceParam,\n  projectParam,\n  identifierParam,\n  prioritySchema,\n  statusCategorySchema,\n  resolveIdentifier,\n  escapeLikePattern,\n  safeUpdateDoc,\n  safeRemoveDoc,\n  getProjectSpace,\n  getProjectStatuses,\n} from \"./_common.js\";\nimport { findPersonByEmailOrName } from \"./contacts.js\";\n\nexport const tools: HulyToolDefinition[] = [\n  // 1. list_issues\n  defineHulyTool({\n    name: \"list_issues\",\n    label: \"List issues\",\n    description:\n      \"List issues trong project. Filter by status, statusCategory, assignee, component, parentIssue, titleSearch.\",\n    promptSnippet: \"List Huly issues in a project.\",\n    needsProject: true,\n    parameters: Type.Object({\n      workspace: workspaceParam,\n      project: projectParam,\n      status: Type.Optional(\n        Type.String({\n          description: \"IssueStatus name or _id (resolved → Ref). See huly_list_statuses.\",\n        }),\n      ),\n      statusCategory: statusCategorySchema,\n      assignee: Type.Optional(Type.String()),\n      component: Type.Optional(\n        Type.String({ description: \"Component label or _id (resolved → Ref).\" }),\n      ),\n      parentIssue: Type.Optional(Type.String()),\n      titleSearch: Type.Optional(Type.String()),\n      limit: Type.Optional(Type.Integer({ minimum: 1 })),\n    }),\n    async handler(params, tctx) {\n      const limit = typeof params.limit === \"number\" ? params.limit : 50;\n      // T-71: space scoping — project._id = space (canonical, thay identifier $like).\n      const space = await getProjectSpace(tctx.client, tctx.project!);\n      if (!space) {\n        return {\n          content: `Project \"${tctx.project}\" not found.`,\n          isError: true,\n          details: { project: tctx.project },\n        };\n      }\n      const query: Record<string, unknown> = { space };\n      // T-102 #153: status resolve name → IssueStatus._id (mirror update_issue T-98).\n      // Issue.status = Ref<IssueStatus>, raw name → 0 match. Match _id exact trước,\n      // fallback name. Invalid → isError + list valid. Empty workflow → isError.\n      if (params.status !== undefined) {\n        const projectStatuses = await getProjectStatuses(tctx.client, tctx.project!);\n        if (!projectStatuses) {\n          return {\n            content: `Project \"${tctx.project}\" not found.`,\n            isError: true,\n            details: { project: tctx.project },\n          };\n        }\n        const statuses = projectStatuses.statuses;\n        if (statuses.length === 0) {\n          return {\n            content:\n              \"No workflow statuses configured for this project. \" +\n              \"Set up project workflow first (huly_create_issue_status).\",\n            isError: true,\n            details: { requestedStatus: params.status, noStatusesConfigured: true },\n          };\n        }\n        const requested = params.status.trim();\n        const byId = statuses.find((s) => s._id === requested);\n        const byName = statuses.find((s) => s.name === requested);\n        const match = byId ?? byName;\n        if (match === undefined) {\n          const valid = statuses\n            .map((s) => s.name)\n            .filter((n) => n.length > 0)\n            .join(\", \");\n          return {\n            content: `Invalid status \"${params.status}\". Valid statuses: ${valid}.`,\n            isError: true,\n            details: { invalidStatus: params.status, validStatuses: statuses.map((s) => s.name) },\n          };\n        }\n        query.status = match._id;\n      }\n      if (params.statusCategory !== undefined) query.statusCategory = params.statusCategory;\n      // T-71: assignee resolve email/name → Person._id (Issue.assignee = Ref<Person>).\n      if (params.assignee !== undefined) {\n        const personId = await findPersonByEmailOrName(tctx.client, params.assignee, tctx.currentUser);\n        if (!personId) {\n          return {\n            content: `Assignee \"${params.assignee}\" not found (no Person matching email/name).`,\n            isError: true,\n            details: { assignee: params.assignee },\n          };\n        }\n        query.assignee = personId;\n      }\n      // T-102 #153: component resolve label/_id → Component._id (mirror\n      // set_issue_component T-81G). Issue.component = Ref<Component>, raw label\n      // → 0 match. Try _id first, then label. Both miss → isError.\n      if (params.component !== undefined) {\n        let component = await tctx.client.findOne(COMPONENT_CLASS, {\n          _id: params.component,\n          space,\n        } as never);\n        if (!component) {\n          component = await tctx.client.findOne(COMPONENT_CLASS, {\n            label: params.component,\n            space,\n          } as never);\n        }\n        if (!component) {\n          return {\n            content: `Component \"${params.component}\" not found (by _id or label).`,\n            isError: true,\n            details: { component: params.component },\n          };\n        }\n        query.component = (component as { _id: string })._id;\n      }\n      // T-68: parentIssue filter → resolve identifier → _id, query.attachedTo.\n      if (params.parentIssue !== undefined) {\n        const parent = await tctx.client.findOne(ISSUE_CLASS, {\n          identifier: resolveIdentifier(tctx.project!, params.parentIssue),\n        });\n        if (!parent) {\n          return {\n            content: `Parent issue \"${params.parentIssue}\" not found.`,\n            isError: true,\n            details: { parentIssue: params.parentIssue },\n          };\n        }\n        query.attachedTo = parent._id;\n      }\n      // T-71: titleSearch ADD filter (KHÔNG xóa space — tránh leak cross-project).\n      if (params.titleSearch !== undefined) {\n        query.title = { $like: `%${escapeLikePattern(params.titleSearch)}%` };\n      }\n      const issues = await tctx.client.findAll(ISSUE_CLASS, query, { limit });\n      const list = issues.map((i) => ({\n        identifier: (i as { identifier?: string }).identifier ?? \"\",\n        title: (i as { title?: string }).title ?? \"\",\n        status: (i as { status?: string }).status,\n        priority: (i as { priority?: string }).priority,\n        assignee: (i as { assignee?: string }).assignee,\n      }));\n      return {\n        content: `Found ${list.length} issue(s).`,\n        details: { count: list.length, issues: list },\n      };\n    },\n  }),\n\n  // 2. get_issue\n  defineHulyTool({\n    name: \"get_issue\",\n    label: \"Get issue\",\n    description: \"Get issue detail by identifier.\",\n    needsProject: true,\n    parameters: Type.Object({\n      workspace: workspaceParam,\n      project: projectParam,\n      identifier: identifierParam,\n    }),\n    async handler(params, tctx) {\n      const issue = await tctx.client.findOne(ISSUE_CLASS, {\n        identifier: resolveIdentifier(tctx.project!, params.identifier),\n      });\n      if (!issue) {\n        return {\n          content: `Issue \"${params.identifier}\" not found.`,\n          isError: true,\n          details: { identifier: params.identifier },\n        };\n      }\n      const f = issue as {\n        _id?: string;\n        identifier?: string;\n        title?: string;\n        description?: string | null;\n        status?: string;\n        priority?: string;\n        assignee?: string;\n        milestone?: string;\n        component?: string;\n        dueDate?: number;\n        estimation?: number;\n        parents?: Array<{ _id?: string; identifier?: string }>;\n        subIssues?: number;\n        modifiedOn?: number;\n        createdOn?: number;\n      };\n      // T-41 #23: Issue.description là MarkupBlobRef (document ref), KHÔNG inline\n      // markup string. fetchMarkup resolve ref → markdown content qua collaborator.\n      // Null/undefined description → skip. fetchMarkup fail → fallback descriptionRef\n      // rõ ràng cho LLM (tránh trả ref string vô nghĩa).\n      let description: string | undefined;\n      let descriptionRef: string | undefined;\n      if (f.description !== null && f.description !== undefined && f._id !== undefined) {\n        try {\n          const markup = await tctx.client.fetchMarkup(\n            ISSUE_CLASS,\n            f._id,\n            \"description\",\n            f.description,\n            \"markdown\",\n          );\n          description = typeof markup === \"string\" ? markup : undefined;\n        } catch {\n          // fetchMarkup fail (ref stale / collaborator down / REST transport) →\n          // fallback descriptionRef rõ ràng, không trả ref vô nghĩa cho LLM.\n          descriptionRef = f.description;\n        }\n      }\n      // T-80 #103: resolve raw refs → human names. status _id → name (qua\n      // getProjectStatuses ProjectType traversal). assignee Person _id → name.\n      // labels = TagReference attachedTo issue. parentIssue = parents[last].\n      let statusName = f.status;\n      if (f.status !== undefined) {\n        const projectStatuses = await getProjectStatuses(tctx.client, tctx.project!);\n        const match = projectStatuses?.statuses.find((s) => s._id === f.status);\n        if (match) statusName = match.name;\n      }\n      let assigneeName: string | undefined;\n      if (f.assignee !== undefined && f.assignee !== null) {\n        const person = await tctx.client.findOne(PERSON_CLASS, { _id: f.assignee } as never);\n        assigneeName = (person as { name?: string } | null)?.name;\n      }\n      let labels: Array<{ title?: unknown; color?: unknown }> = [];\n      if (f._id !== undefined) {\n        const tagRefs = (await tctx.client.findAll(TAG_REFERENCE_CLASS, {\n          attachedTo: f._id,\n        } as never)) as Array<{ title?: unknown; color?: unknown }>;\n        labels = tagRefs;\n      }\n      const directParent =\n        f.parents !== undefined && f.parents.length > 0\n          ? f.parents[f.parents.length - 1]\n          : undefined;\n      return {\n        content:\n          `${f.identifier}: ${f.title ?? \"\"}\\n\\n` +\n          `Status: ${statusName ?? \"?\"} · Priority: ${f.priority ?? \"?\"} · Assignee: ${assigneeName ?? \"?\"}\\n\\n` +\n          `${description ?? \"\"}`,\n        details: {\n          identifier: f.identifier,\n          title: f.title,\n          description,\n          descriptionRef,\n          status: statusName,\n          statusRef: f.status,\n          priority: f.priority,\n          assignee: assigneeName,\n          assigneeRef: f.assignee,\n          milestone: f.milestone,\n          component: f.component,\n          dueDate: f.dueDate,\n          estimation: f.estimation,\n          parentIssue: directParent?.identifier,\n          subIssues: f.subIssues,\n          labels: labels.map((l) => ({ title: l.title, color: l.color })),\n          modifiedOn: f.modifiedOn,\n          createdOn: f.createdOn,\n        },\n      };\n    },\n  }),\n\n  // 3. create_issue\n  defineHulyTool({\n    name: \"create_issue\",\n    label: \"Create issue\",\n    description:\n      \"Create issue. Assignee absent → default currentUser email (D15). Description = markdown.\",\n    promptSnippet: \"Create a new Huly issue.\",\n    needsProject: true,\n    needsAssignee: true,\n    parameters: Type.Object({\n      workspace: workspaceParam,\n      project: projectParam,\n      title: Type.String(),\n      description: Type.Optional(Type.String()),\n      priority: prioritySchema,\n      assignee: Type.Optional(Type.String()),\n      status: Type.Optional(Type.String()),\n      taskType: Type.Optional(Type.String()),\n      parentIssue: Type.Optional(Type.String()),\n      dueDate: Type.Optional(Type.Integer()),\n      estimation: Type.Optional(Type.Integer()),\n    }),\n    async handler(params, tctx) {\n      // T-103 #159: guard title non-empty (trim). Empty/whitespace title = garbage\n      // issue (no subject). Schema lacks minLength; server accepts empty.\n      if (params.title.trim() === \"\") {\n        return {\n          content: `create_issue title must be non-empty (got \"${params.title}\"). An issue needs a subject.`,\n          isError: true,\n          details: { title: params.title },\n        };\n      }\n      const project = await tctx.client.findOne(PROJECT_CLASS, {\n        identifier: tctx.project,\n      });\n      if (!project) {\n        return {\n          content: `Project \"${tctx.project}\" not found. Run /huly init or check binding.`,\n          isError: true,\n          details: { project: tctx.project },\n        };\n      }\n      // T-67 #75: $inc sequence trên Project → lấy sequence number (atomic, tránh\n      // race duplicate identifier). trusted issues-write.ts:133.\n      const incResult = await tctx.client.updateDoc(\n        PROJECT_CLASS,\n        \"core:space:Space\" as never,\n        project._id as never,\n        { $inc: { sequence: 1 } } as never,\n        true,\n      );\n      // Extract sequence từ txResult (Huly trả { object: { sequence: N } }).\n      const seqRaw = (incResult as { object?: { sequence?: number } })?.object?.sequence;\n      const sequence =\n        typeof seqRaw === \"number\"\n          ? seqRaw\n          : ((project as { sequence?: number }).sequence ?? 0) + 1;\n      const identifier = `${(project as { identifier?: string }).identifier ?? tctx.project}-${sequence}`;\n\n      // T-72 #80: description = MarkupBlobRef (KHÔNG inline string). uploadMarkup\n      // trả ref → gán vào description. Format \"markdown\" — client parse md→markup.\n      const issueId = `tracker:issue.${Math.random().toString(36).slice(2, 14)}`;\n      let descriptionRef: unknown = null;\n      if (params.description !== undefined && params.description.trim() !== \"\") {\n        descriptionRef = await tctx.client.uploadMarkup(\n          ISSUE_CLASS,\n          issueId,\n          \"description\",\n          params.description,\n          \"markdown\",\n        );\n      }\n      // T-95 (#141): resolve assignee email/name → Person._id (mirror update_issue).\n      // Trước đây push raw email string vào Ref<Person> → garbage ref, get_issue\n      // render \"Assignee: ?\". Builder D15 fill params.assignee = currentUser.email\n      // khi absent → resolve ở đây.\n      // Resilient: default-assignee (== currentUser.email) KHÔNG resolve → fallback\n      // null (unassigned, KHÔNG garbage, KHÔNG fail create — tránh workspace user\n      // chưa có email Channel block toàn bộ create). Explicit assignee KHÔNG resolve\n      // → error rõ (user yêu cầu người cụ thể).\n      let assigneeRef: string | null = null;\n      if (params.assignee !== undefined && params.assignee !== null && params.assignee !== \"\") {\n        const personId = await findPersonByEmailOrName(tctx.client, params.assignee, tctx.currentUser);\n        const isDefault = params.assignee === tctx.currentUser.email;\n        if (!personId && !isDefault) {\n          return {\n            content: `Assignee \"${params.assignee}\" not found (no Person matching email/name). Issue not created.`,\n            isError: true,\n            details: { assignee: params.assignee },\n          };\n        }\n        assigneeRef = personId ?? null; // default không resolve → null (unassigned)\n      }\n      // T-98 (#144): resolve status name → IssueStatus._id (mirror update_issue).\n      // Trước đây push raw name string vào Ref<IssueStatus> → server silent-reject,\n      // status lost. Guard: chỉ resolve khi params.status provided; statuses rỗng\n      // (workspace chưa config workflow) → leave undefined (server default, KHÔNG\n      // fail create); provided + statuses exist + no match → error rõ.\n      let statusRef: string | undefined;\n      if (params.status !== undefined && params.status !== \"\") {\n        const projectStatuses = await getProjectStatuses(tctx.client, tctx.project!);\n        if (projectStatuses && projectStatuses.statuses.length > 0) {\n          const requested = params.status.trim();\n          const match =\n            projectStatuses.statuses.find((s) => s._id === requested) ??\n            projectStatuses.statuses.find((s) => s.name === requested);\n          if (!match) {\n            const valid = projectStatuses.statuses\n              .map((s) => s.name)\n              .filter(Boolean)\n              .join(\", \");\n            return {\n              content: `Invalid status \"${params.status}\". Valid statuses: ${valid}. Issue not created.`,\n              isError: true,\n              details: {\n                invalidStatus: params.status,\n                validStatuses: projectStatuses.statuses.map((s) => s.name),\n              },\n            };\n          }\n          statusRef = match._id;\n        }\n        // statuses empty → leave undefined (server default), don't block create.\n      }\n      const id = await tctx.client.addCollection(\n        ISSUE_CLASS,\n        project._id as never, // space = project (issues live trong project space)\n        NO_PARENT_REF, // attachedTo = NoParent sentinel (top-level)\n        ISSUE_CLASS, // attachedToClass\n        \"subIssues\", // collection\n        {\n          title: params.title,\n          description: descriptionRef,\n          priority: params.priority,\n          assignee: assigneeRef,\n          status: statusRef,\n          number: sequence,\n          kind: ISSUE_KIND_REF,\n          identifier,\n          component: null,\n          estimation: params.estimation ?? 0,\n          remainingTime: 0,\n          reportedTime: 0,\n          reports: 0,\n          subIssues: 0,\n          parents: [],\n          childInfo: [],\n          dueDate: params.dueDate ?? null,\n          rank: \"\", // lexorank empty — server gán nếu empty (pattern T-46)\n        } as never,\n        issueId as never,\n      );\n      // T-40 #26: identifier computed locally (T-67) — KHÔNG cần lookup server.\n      const contentMsg = `Created issue ${identifier}: \"${params.title}\".`;\n      return {\n        content: contentMsg,\n        details: { id, identifier, title: params.title, number: sequence },\n      };\n    },\n  }),\n\n  // 4. update_issue\n  // T-47 #36: KHÔNG dùng needsAssignee (D15 chỉ cho create). Update KHÔNG\n  // auto-fill assignee → caller muốn đổi assignee phải truyền rõ. Trước đây\n  // leak sang update → mọi update tự claim current user (silent overwrite).\n  // T-47 #36: status phải validate workflow enum — server reject raw short\n  // name (\"Done\") mà cần full ref (\"tracker:status:Done\"). Trước đây push raw\n  // → silent reject, status không persist. Giờ lookup IssueStatus → resolve.\n  defineHulyTool({\n    name: \"update_issue\",\n    label: \"Update issue\",\n    description:\n      \"Update issue fields. Status must match exact IssueStatus name (case-sensitive) or _id full ref.\",\n    needsProject: true,\n    parameters: Type.Object({\n      workspace: workspaceParam,\n      project: projectParam,\n      identifier: identifierParam,\n      title: Type.Optional(Type.String()),\n      description: Type.Optional(Type.String()),\n      priority: prioritySchema,\n      assignee: Type.Optional(Type.Union([Type.String(), Type.Null()])),\n      status: Type.Optional(\n        Type.String({\n          description:\n            \"Exact IssueStatus name (case-sensitive) or _id ref. Run huly_list_statuses for valid names.\",\n        }),\n      ),\n      dueDate: Type.Optional(Type.Integer()),\n      estimation: Type.Optional(Type.Integer()),\n    }),\n    async handler(params, tctx) {\n      const issue = await tctx.client.findOne(ISSUE_CLASS, {\n        identifier: resolveIdentifier(tctx.project!, params.identifier),\n      });\n      if (!issue) {\n        return {\n          content: `Issue \"${params.identifier}\" not found.`,\n          isError: true,\n          details: { identifier: params.identifier },\n        };\n      }\n      const ops: Record<string, unknown> = {};\n      if (params.title !== undefined) {\n        if (params.title.trim() === \"\")\n          return {\n            content: \"title must be non-empty.\",\n            isError: true,\n            details: { title: params.title },\n          };\n        ops.title = params.title;\n      }\n      // T-72 #80: description = MarkupBlobRef. Library KHÔNG có updateMarkup —\n      // luôn uploadMarkup (new version) + ops.description = ref.\n      if (params.description !== undefined) {\n        const ref = await tctx.client.uploadMarkup(\n          ISSUE_CLASS,\n          issue._id,\n          \"description\",\n          params.description,\n          \"markdown\",\n        );\n        ops.description = ref;\n      }\n      if (params.priority !== undefined) ops.priority = params.priority;\n      if (params.assignee !== undefined) {\n        // T-80 #103: resolve assignee email/name → Person._id (đồng bộ create_issue).\n        // Trước đây push raw string vào Ref<Person> → garbage. Hỗ trợ null (unassign).\n        if (params.assignee === null) {\n          ops.assignee = null;\n        } else {\n          const personId = await findPersonByEmailOrName(tctx.client, params.assignee, tctx.currentUser);\n          if (!personId) {\n            return {\n              content:\n                `Assignee \"${params.assignee}\" not found (no Person matching email/name). ` +\n                `Assignee unchanged.`,\n              isError: true,\n              details: { assignee: params.assignee, identifier: params.identifier },\n            };\n          }\n          ops.assignee = personId;\n        }\n      }\n      if (params.dueDate !== undefined) ops.dueDate = params.dueDate;\n      if (params.estimation !== undefined) ops.estimation = params.estimation;\n      // T-47 #36: resolve status short name (\"Done\") → full ref\n      // (\"tracker:status:Done\") trước khi push. Huly IssueStatus có _id = full\n      // ref, name = short human. Match _id exact trước (caller truyền full ref\n      // → match chắc), fallback name (caller truyền short → heuristic; có thể\n      // ambiguous nếu multi-project workspace có cùng status name — documented\n      // limitation, scope của fix này không filter theo taskType). Invalid →\n      // isError + list valid statuses cho LLM retry.\n      //\n      // T-47 review fix:\n      // - Empty statuses (fresh workspace chưa config workflow) → isError rõ\n      //   ràng KHÔNG \"Valid statuses: .\" (misleading). Hướng dẫn setup trước.\n      // - Match thành công nhưng _id undefined (schema drift) → isError KHÔNG\n      //   fallback raw params.status (reintroduce bug gốc — raw short name bị\n      //   server silent reject).\n      // - Input trim → match linh hoạt với \" Done \" / \"Done\" (caller LLM hay\n      //   thêm whitespace). Exact case vẫn giữ (Huly status name verbatim).\n      if (params.status !== undefined) {\n        // T-72 #80: scope status theo project (getProjectStatuses T-71 ProjectType\n        // traversal) — KHÔNG findAll global (cross-project ambiguous match).\n        const projectStatuses = await getProjectStatuses(tctx.client, tctx.project!);\n        if (!projectStatuses) {\n          return {\n            content: `Project \"${tctx.project}\" not found.`,\n            isError: true,\n            details: { identifier: params.identifier, project: tctx.project },\n          };\n        }\n        const statuses = projectStatuses.statuses;\n        if (statuses.length === 0) {\n          return {\n            content:\n              \"No workflow statuses configured for this project. \" +\n              \"Set up project workflow or create statuses first (huly_create_issue_status).\",\n            isError: true,\n            details: {\n              identifier: params.identifier,\n              requestedStatus: params.status,\n              noStatusesConfigured: true,\n            },\n          };\n        }\n        const requested = params.status.trim();\n        // Ưu tiên _id exact trước name short (giảm ambiguity multi-project).\n        const byId = statuses.find((s) => s._id === requested);\n        const byName = statuses.find((s) => s.name === requested);\n        const match = byId ?? byName;\n        if (match === undefined) {\n          const valid = statuses\n            .map((s) => s.name)\n            .filter((n) => n.length > 0)\n            .join(\", \");\n          return {\n            content: `Invalid status \"${params.status}\". Valid statuses: ${valid}.`,\n            isError: true,\n            details: {\n              identifier: params.identifier,\n              invalidStatus: params.status,\n              validStatuses: statuses.map((s) => s.name),\n            },\n          };\n        }\n        ops.status = match._id;\n      }\n      if (Object.keys(ops).length === 0) {\n        return { content: \"No fields to update.\", details: { updated: false } };\n      }\n      const updResult = await safeUpdateDoc(tctx.client, ISSUE_CLASS, issue, ops);\n      if (!updResult.ok) return updResult.error;\n      const fields = Object.keys(ops);\n      return {\n        content: `Updated issue ${params.identifier}: ${fields.join(\", \")}`,\n        details: { updated: true, identifier: params.identifier, fields },\n      };\n    },\n  }),\n\n  // 5. delete_issue — destructive\n  defineHulyTool({\n    name: \"delete_issue\",\n    label: \"Delete issue\",\n    description: \"Delete issue (destructive — confirm gate).\",\n    destructive: true,\n    needsProject: true,\n    destructiveContext: (p) => ({\n      type: \"issue\",\n      id: (p as { identifier?: string }).identifier ?? \"<unknown>\",\n    }),\n    parameters: Type.Object({\n      workspace: workspaceParam,\n      project: projectParam,\n      identifier: identifierParam,\n    }),\n    async handler(params, tctx) {\n      const issue = await tctx.client.findOne(ISSUE_CLASS, {\n        identifier: resolveIdentifier(tctx.project!, params.identifier),\n      });\n      if (!issue) {\n        return {\n          content: `Issue \"${params.identifier}\" not found.`,\n          isError: true,\n          details: { identifier: params.identifier },\n        };\n      }\n      const delResult = await safeRemoveDoc(tctx.client, ISSUE_CLASS, issue);\n      if (!delResult.ok) return delResult.error;\n      return {\n        content: `Deleted issue ${params.identifier}.`,\n        details: { deleted: true, identifier: params.identifier },\n      };\n    },\n  }),\n\n  // 6. move_issue — change parent (AttachedDoc hierarchy, T-68 fix).\n  // T-52 #42: KHÔNG truyền parentIssue = top-level promotion (Option A user chốt).\n  // T-68: dùng attachedTo/attachedToClass/collection/parents/subIssues thay vì\n  // field `parentIssue` (KHÔNG tồn tại runtime). Helper issues-hierarchy.ts.\n  defineHulyTool({\n    name: \"move_issue\",\n    label: \"Move issue\",\n    description: \"Move issue to new parent (epic). KHÔNG truyền parentIssue → promote top-level.\",\n    needsProject: true,\n    parameters: Type.Object({\n      workspace: workspaceParam,\n      project: projectParam,\n      identifier: identifierParam,\n      parentIssue: Type.Optional(\n        Type.String({\n          description: \"New parent issue identifier. KHÔNG truyền = top-level promotion.\",\n        }),\n      ),\n    }),\n    async handler(params, tctx) {\n      const issue = (await tctx.client.findOne(ISSUE_CLASS, {\n        identifier: resolveIdentifier(tctx.project!, params.identifier),\n      })) as IssueHierarchyFields & { space?: string };\n      if (!issue) {\n        return {\n          content: `Issue \"${params.identifier}\" not found.`,\n          isError: true,\n          details: { identifier: params.identifier },\n        };\n      }\n      const projectSpace = (issue.space ?? \"\") as never;\n      // Capture old parent state BEFORE mutate (attachIssueChild overwrites attachedTo).\n      const oldAttachedTo = issue.attachedTo;\n      const wasChild = hasConcreteIssueParent(issue);\n\n      // Case A: top-level promotion (no parentIssue param).\n      if (params.parentIssue === undefined) {\n        const topFields = topLevelIssueParent();\n        await tctx.client.updateDoc(\n          ISSUE_CLASS,\n          projectSpace,\n          issue._id as never,\n          {\n            attachedTo: topFields.attachedTo,\n            attachedToClass: topFields.attachedToClass,\n            collection: topFields.collection,\n            parents: topFields.parents,\n          } as never,\n        );\n        // Dec old parent subIssues if was child (trusted always decs when oldParentIsIssue).\n        if (wasChild && oldAttachedTo) {\n          await tctx.client.updateDoc(\n            ISSUE_CLASS,\n            projectSpace,\n            oldAttachedTo as never,\n            { $inc: { subIssues: -1 } } as never,\n          );\n        }\n        // Re-breadcrumb descendants (clear chain to []).\n        if ((issue.subIssues ?? 0) > 0) {\n          await updateDescendantParents(tctx.client, projectSpace as string, issue, []);\n        }\n        return {\n          content: `Moved ${params.identifier} → top-level.`,\n          details: { identifier: params.identifier, parentIssue: null },\n        };\n      }\n\n      // Case B: move to new parent.\n      const parent = (await tctx.client.findOne(ISSUE_CLASS, {\n        identifier: resolveIdentifier(tctx.project!, params.parentIssue),\n      })) as IssueHierarchyFields;\n      if (!parent) {\n        return {\n          content: `Parent issue \"${params.parentIssue}\" not found.`,\n          isError: true,\n          details: { identifier: params.identifier, parentIssue: params.parentIssue },\n        };\n      }\n      // attachIssueChild: set child fields + $inc new parent subIssues +1.\n      await attachIssueChild(tctx.client, projectSpace as string, issue._id, parent, {});\n      // Dec old parent subIssues if was child (always when wasChild — same-parent net 0).\n      if (wasChild && oldAttachedTo) {\n        await tctx.client.updateDoc(\n          ISSUE_CLASS,\n          projectSpace,\n          oldAttachedTo as never,\n          { $inc: { subIssues: -1 } } as never,\n        );\n      }\n      // Re-breadcrumb descendants với new ancestor chain.\n      if ((issue.subIssues ?? 0) > 0) {\n        const parentInfo = {\n          parentId: parent._id,\n          identifier: parent.identifier ?? \"\",\n          parentTitle: parent.title ?? \"\",\n          space: projectSpace as string,\n        };\n        await updateDescendantParents(tctx.client, projectSpace as string, issue, [\n          ...(parent.parents ?? []),\n          parentInfo,\n        ]);\n      }\n      return {\n        content: `Moved ${params.identifier} → parent ${params.parentIssue}.`,\n        details: { identifier: params.identifier, parentIssue: params.parentIssue },\n      };\n    },\n  }),\n\n  // 7. add_issue_label — GLOBAL labels (05-data-model §3)\n  // T-45 #27: validate label tồn tại + push TagReference object shape (audit §4).\n  // T-58 #43: dùng TAG_CLASS (TagElement) thay LABEL_CLASS (deprecated —\n  // view:class:Label 0 match runtime). Label workflow giờ dùng tag entity.\n  defineHulyTool({\n    name: \"add_issue_label\",\n    label: \"Add issue label\",\n    description:\n      \"Add label/tag to issue. Accepts tag title or _id (resolved via tags:class:TagElement). \" +\n      \"Validates tag exists before push. Use huly_create_tag to create new.\",\n    needsProject: true,\n    parameters: Type.Object({\n      workspace: workspaceParam,\n      project: projectParam,\n      identifier: identifierParam,\n      label: Type.String({ description: \"Label title or _id ref.\" }),\n    }),\n    async handler(params, tctx) {\n      const issue = await tctx.client.findOne(ISSUE_CLASS, {\n        identifier: resolveIdentifier(tctx.project!, params.identifier),\n      });\n      if (!issue) {\n        return {\n          content: `Issue \"${params.identifier}\" not found.`,\n          isError: true,\n          details: { identifier: params.identifier },\n        };\n      }\n      // T-45 + T-58: validate tag tồn tại — try by title first, fallback by _id.\n      // T-58: dùng TAG_CLASS (TagElement) thay LABEL_CLASS (deprecated — view:class:Label\n      // 0 match runtime). Label workflow giờ dùng tag entity. T-90: native TagElementDoc.\n      const label =\n        (await tctx.client.findOne<TagElementDoc>(TAG_CLASS, {\n          title: params.label,\n        })) ?? (await tctx.client.findOne<TagElementDoc>(TAG_CLASS, { _id: idRef(params.label) }));\n      if (!label) {\n        return {\n          content: `Label/tag \"${params.label}\" not found. Create via huly_create_tag first.`,\n          isError: true,\n          details: { label: params.label, identifier: params.identifier },\n        };\n      }\n      // T-83 #118: labels = TagReference AttachedDoc (collection \"labels\"), KHÔNG\n      // inline Issue.labels field. $push labels (T-45) = silent data loss (field\n      // không tồn tại runtime). Migrate sang addCollection matching attach_tag (T-69).\n      // T-90: native TagReferenceDoc. Idempotent: findAll check existing.\n      const existing = await tctx.client.findAll<TagReferenceDoc>(\n        TAG_REFERENCE_CLASS,\n        {\n          attachedTo: issue._id,\n          attachedToClass: ISSUE_CLASS,\n          collection: \"labels\",\n          tag: label._id,\n        },\n        {},\n      );\n      if (existing.length > 0) {\n        return {\n          content: `Label ${params.label} already on ${params.identifier} (no-op).`,\n          details: { added: false, idempotent: true, label: params.label },\n        };\n      }\n      // addCollection TagReference AttachedDoc (collection \"labels\"). T-90: satisfies.\n      const attrs = {\n        tag: label._id,\n        title: label.title ?? params.label,\n        color: Number(label.color ?? 0),\n      } satisfies Partial<TagReferenceDoc>;\n      const tagRefId = await tctx.client.addCollection(\n        TAG_REFERENCE_CLASS,\n        idRef(issue.space),\n        idRef(issue._id),\n        ISSUE_CLASS,\n        \"labels\",\n        attrs,\n      );\n      return {\n        content: `Added label ${params.label} to ${params.identifier}.`,\n        details: {\n          added: true,\n          identifier: params.identifier,\n          label: params.label,\n          labelId: label._id,\n          tagRefId,\n        },\n      };\n    },\n  }),\n\n  // 8. remove_issue_label — symmetric with add (T-45)\n  defineHulyTool({\n    name: \"remove_issue_label\",\n    label: \"Remove issue label\",\n    description:\n      \"Remove global label from issue. Accepts label title or _id. \" +\n      \"No-op if label not present on issue (idempotent).\",\n    needsProject: true,\n    parameters: Type.Object({\n      workspace: workspaceParam,\n      project: projectParam,\n      identifier: identifierParam,\n      label: Type.String({ description: \"Label title or _id ref.\" }),\n    }),\n    async handler(params, tctx) {\n      const issue = await tctx.client.findOne(ISSUE_CLASS, {\n        identifier: resolveIdentifier(tctx.project!, params.identifier),\n      });\n      if (!issue) {\n        return {\n          content: `Issue \"${params.identifier}\" not found.`,\n          isError: true,\n          details: { identifier: params.identifier },\n        };\n      }\n      // Validate tag exists (T-58: TAG_CLASS thay LABEL_CLASS deprecated). T-90: native TagElementDoc.\n      const label =\n        (await tctx.client.findOne<TagElementDoc>(TAG_CLASS, {\n          title: params.label,\n        })) ?? (await tctx.client.findOne<TagElementDoc>(TAG_CLASS, { _id: idRef(params.label) }));\n      if (!label) {\n        return {\n          content: `Label \"${params.label}\" not found. Cannot remove.`,\n          isError: true,\n          details: { label: params.label, identifier: params.identifier },\n        };\n      }\n      // T-83 #118: findAll TagReference matching tag trên issue (matching detach_tag).\n      // $pull labels (T-45) = silent no-op (field không tồn tại runtime). T-90: native TagReferenceDoc.\n      const refs = await tctx.client.findAll<TagReferenceDoc>(\n        TAG_REFERENCE_CLASS,\n        {\n          attachedTo: issue._id,\n          attachedToClass: ISSUE_CLASS,\n          collection: \"labels\",\n          tag: label._id,\n        },\n        {},\n      );\n      if (refs.length === 0) {\n        return {\n          content: `Label ${params.label} not on ${params.identifier} (no-op).`,\n          details: { removed: false, idempotent: true, label: params.label },\n        };\n      }\n      // removeDoc each matching TagReference.\n      for (const ref of refs) {\n        await tctx.client.removeDoc(\n          TAG_REFERENCE_CLASS,\n          idRef(ref.space ?? issue.space),\n          idRef(ref._id),\n        );\n      }\n      return {\n        content: `Removed label ${params.label} from ${params.identifier}.`,\n        details: {\n          removed: true,\n          identifier: params.identifier,\n          label: params.label,\n          labelId: label._id,\n          removedCount: refs.length,\n        },\n      };\n    },\n  }),\n];\n","// tools/domains/issues-relations.ts — Issue relations + doclink domain (5 tools).\n// Design: 06-api.md §4 Issue relations. DAG + doc↔issue links.\n//\n// T-61 fix (2026-07-28): storage pattern KHỚP 100% với Huly thật, verified từ:\n//   - plugins/tracker-resources/src/components/RelationsPopup.svelte:33-41\n//   - plugins/tracker-resources/src/issues.ts:111 updateIssueRelation\n//   - tests/sanity/tests/tracker/relations.spec.ts (\"Mark as blocked by\" / \"Mark as blocking\")\n//\n// Issue interface (Huly thật) CHỈ có 2 field relation:\n//   - Issue.blockedBy?: RelatedDocument[]    — issues đang BLOCK issue này\n//   - Issue.relations?: RelatedDocument[]    — related-to (bidirectional)\n// RelatedDocument = Pick<Doc, '_id' | '_class'> = { _id, _class } — KHÔNG có\n// relationType field. KHÔNG có field `blocks` — \"blocks\" được COMPUTE bằng\n// reverse query (tìm issues có blockedBy._id === currentIssue._id).\n//\n// Mapping relationType → storage (T-61, đúng Huly pattern):\n//   - \"blocks\"        → target.blockedBy[] push { _id: source, _class }\n//                       (A blocks B → B.blockedBy.push(A) — push lên ĐÍCH B)\n//   - \"is-blocked-by\" → source.blockedBy[] push { _id: target, _class }\n//                       (A blocked-by B → A.blockedBy.push(B) — push lên NGUỒN A)\n//   - \"relates-to\"    → BIDIRECTIONAL: A.relations.push(B) + B.relations.push(A)\n//                       (2 updateDoc call, khớp RelationsPopup dòng 34-39)\n//\n// Tools (5, FR-04 D4):\n//   1. add_issue_relation     2. remove_issue_relation  3. list_issue_relations\n//   4. link_document_to_issue 5. unlink_document_to_issue\n\nimport { Type } from \"typebox\";\nimport { defineHulyTool, type HulyToolDefinition } from \"../builder.js\";\nimport { ISSUE_CLASS } from \"./_class-refs.js\";\nimport {\n  workspaceParam,\n  projectParam,\n  identifierParam,\n  resolveIdentifier,\n  safeUpdateDoc,\n} from \"./_common.js\";\n\n/** RelatedDocument shape = { _id: Ref<Doc>, _class: Ref<Class<Doc>> }. */\nfunction makeRelatedDoc(targetId: string): { _id: string; _class: string } {\n  return { _id: targetId, _class: ISSUE_CLASS };\n}\n\n/** Check nếu relation đã tồn tại trong mảng (idempotent guard). */\nfunction hasRelation(arr: unknown[] | undefined, targetId: string): boolean {\n  if (!Array.isArray(arr)) return false;\n  return arr.some((r) => (r as { _id?: string })._id === targetId);\n}\n\nexport const tools: HulyToolDefinition[] = [\n  // 1. add_issue_relation — DAG dependency\n  defineHulyTool({\n    name: \"add_issue_relation\",\n    label: \"Add issue relation\",\n    description:\n      \"Add relation between issues. relationType: blocks | is-blocked-by | relates-to. \" +\n      \"Storage (T-61, khớp Huly UI): blocks→target.blockedBy, is-blocked-by→source.blockedBy, \" +\n      \"relates-to→bidirectional (cả 2 issue.relations).\",\n    needsProject: true,\n    parameters: Type.Object({\n      workspace: workspaceParam,\n      project: projectParam,\n      identifier: identifierParam,\n      targetIssue: Type.String({ description: \"Target issue identifier.\" }),\n      relationType: Type.Union([\n        Type.Literal(\"blocks\"),\n        Type.Literal(\"is-blocked-by\"),\n        Type.Literal(\"relates-to\"),\n      ]),\n    }),\n    async handler(params, tctx) {\n      const issue = await tctx.client.findOne(ISSUE_CLASS, {\n        identifier: resolveIdentifier(tctx.project!, params.identifier),\n      });\n      if (!issue) {\n        return {\n          content: `Issue \"${params.identifier}\" not found.`,\n          isError: true,\n          details: { identifier: params.identifier },\n        };\n      }\n      // T-52 #42: validate targetIssue tồn tại + resolve identifier → _id.\n      // targetIssue cho phép CROSS-PROJECT (raw identifier, KHÔNG resolveIdentifier)\n      // — khác source (identifier dòng 67 dùng resolveIdentifier throw nếu cross).\n      // Khớp Huly UI RelationsPopup: ObjectSearchPopup pick bất kỳ issue nào bất kể\n      // project. Đây là INTENT, không phải bug.\n      const target = await tctx.client.findOne(ISSUE_CLASS, {\n        identifier: params.targetIssue,\n      });\n      if (!target) {\n        return {\n          content: `Target issue \"${params.targetIssue}\" not found. Check identifier.`,\n          isError: true,\n          details: { targetIssue: params.targetIssue, identifier: params.identifier },\n        };\n      }\n\n      // T-61 fix: storage pattern KHỚP Huly thật (RelationsPopup.svelte +\n      // updateIssueRelation). 3 nhánh rõ ràng:\n      //   - blocks         → target.blockedBy push source (A blocks B → B.blockedBy.push(A))\n      //   - is-blocked-by  → source.blockedBy push target (A blocked-by B → A.blockedBy.push(B))\n      //   - relates-to     → BIDIRECTIONAL: A.relations.push(B) + B.relations.push(A)\n      if (params.relationType === \"blocks\") {\n        // A blocks B → B.blockedBy.push(A). Push lên ĐÍCH B.\n        const targetBlockedBy = (target as { blockedBy?: unknown[] }).blockedBy;\n        if (hasRelation(targetBlockedBy, issue._id as string)) {\n          return {\n            content: `Relation ${params.identifier} -[blocks]-> ${params.targetIssue} already exists (no-op).`,\n            details: { idempotent: true, relationType: params.relationType },\n          };\n        }\n        const updResult = await safeUpdateDoc(tctx.client, ISSUE_CLASS, target, {\n          $push: { blockedBy: makeRelatedDoc(issue._id as string) },\n        });\n        if (!updResult.ok) return updResult.error;\n      } else if (params.relationType === \"is-blocked-by\") {\n        // A is-blocked-by B → A.blockedBy.push(B). Push trên NGUỒN A.\n        const issueBlockedBy = (issue as { blockedBy?: unknown[] }).blockedBy;\n        if (hasRelation(issueBlockedBy, target._id as string)) {\n          return {\n            content: `Relation ${params.identifier} -[is-blocked-by]-> ${params.targetIssue} already exists (no-op).`,\n            details: { idempotent: true, relationType: params.relationType },\n          };\n        }\n        const updResult = await safeUpdateDoc(tctx.client, ISSUE_CLASS, issue, {\n          $push: { blockedBy: makeRelatedDoc(target._id as string) },\n        });\n        if (!updResult.ok) return updResult.error;\n      } else {\n        // relates-to → BIDIRECTIONAL: A.relations.push(B) + B.relations.push(A).\n        // Khớp RelationsPopup.svelte dòng 34-39 (updateRelation type='relations'\n        // gọi updateIssueRelation 2 lần: value→refDocument + refDocument→value).\n        //\n        // NON-ATOMIC (khớp hành vi Huly gốc — RelationsPopup cũng 2 thao tác riêng,\n        // không transaction): nếu forward commit xong nhưng reverse throw (vd network\n        // drop, quyền space khác khi cross-project), A.relations có B nhưng B.relations\n        // chưa có A → lệch 1 chiều. Idempotent guard (forwardExists/reverseExists)\n        // cho phép retry an toàn — lần sau chỉ push chiều còn thiếu, không duplicate.\n        const issueRelations = (issue as { relations?: unknown[] }).relations;\n        const targetRelations = (target as { relations?: unknown[] }).relations;\n        const forwardExists = hasRelation(issueRelations, target._id as string);\n        const reverseExists = hasRelation(targetRelations, issue._id as string);\n        if (forwardExists && reverseExists) {\n          return {\n            content: `Relation ${params.identifier} -[relates-to]-> ${params.targetIssue} already exists (no-op).`,\n            details: { idempotent: true, relationType: params.relationType },\n          };\n        }\n        // Forward: A.relations.push(B)\n        if (!forwardExists) {\n          const updResult = await safeUpdateDoc(tctx.client, ISSUE_CLASS, issue, {\n            $push: { relations: makeRelatedDoc(target._id as string) },\n          });\n          if (!updResult.ok) return updResult.error;\n        }\n        // Reverse: B.relations.push(A)\n        if (!reverseExists) {\n          const updResult = await safeUpdateDoc(tctx.client, ISSUE_CLASS, target, {\n            $push: { relations: makeRelatedDoc(issue._id as string) },\n          });\n          if (!updResult.ok) return updResult.error;\n        }\n      }\n      return {\n        content: `Added relation ${params.identifier} -[${params.relationType}]-> ${params.targetIssue}.`,\n        details: {\n          identifier: params.identifier,\n          targetIssue: params.targetIssue,\n          targetIssueId: target._id,\n          relationType: params.relationType,\n        },\n      };\n    },\n  }),\n\n  // 2. remove_issue_relation — T-59: $pull theo targetIssue + relationType\n  // (KHÔNG dùng relation _id nữa — relation là array element, KHÔNG phải doc riêng)\n  defineHulyTool({\n    name: \"remove_issue_relation\",\n    label: \"Remove issue relation\",\n    description:\n      \"Remove relation between issues. Pass targetIssue + relationType (KHÔNG dùng relation _id — \" +\n      \"Huly stores relations inline trong Issue.relations / blockedBy array). Storage (T-61, khớp \" +\n      \"Huly UI): blocks→target.blockedBy, is-blocked-by→source.blockedBy, relates-to→bidirectional.\",\n    destructive: true,\n    needsProject: true,\n    destructiveContext: (p) => ({\n      type: \"issue relation\",\n      id: (p as { identifier?: string }).identifier ?? \"<unknown>\",\n    }),\n    parameters: Type.Object({\n      workspace: workspaceParam,\n      project: projectParam,\n      identifier: identifierParam,\n      targetIssue: Type.String({ description: \"Target issue identifier to remove relation to.\" }),\n      relationType: Type.Union([\n        Type.Literal(\"blocks\"),\n        Type.Literal(\"is-blocked-by\"),\n        Type.Literal(\"relates-to\"),\n      ]),\n    }),\n    async handler(params, tctx) {\n      const issue = await tctx.client.findOne(ISSUE_CLASS, {\n        identifier: resolveIdentifier(tctx.project!, params.identifier),\n      });\n      if (!issue) {\n        return {\n          content: `Issue \"${params.identifier}\" not found.`,\n          isError: true,\n          details: { identifier: params.identifier },\n        };\n      }\n      const target = await tctx.client.findOne(ISSUE_CLASS, {\n        identifier: params.targetIssue,\n      });\n      if (!target) {\n        return {\n          content: `Target issue \"${params.targetIssue}\" not found.`,\n          isError: true,\n          details: { targetIssue: params.targetIssue },\n        };\n      }\n\n      // T-61 fix: $pull đối xứng add. 3 nhánh rõ ràng:\n      //   - blocks         → $pull target.blockedBy (xóa source khỏi blockedBy của đích)\n      //   - is-blocked-by  → $pull source.blockedBy (xóa target khỏi blockedBy của nguồn)\n      //   - relates-to     → BIDIRECTIONAL: $pull cả 2 chiều issue.relations + target.relations\n      const pullRef = makeRelatedDoc(target._id as string);\n      const pullSourceRef = makeRelatedDoc(issue._id as string);\n      if (params.relationType === \"blocks\") {\n        // A blocks B → xóa A khỏi B.blockedBy[]. Pull trên ĐÍCH B.\n        if (!hasRelation((target as { blockedBy?: unknown[] }).blockedBy, issue._id as string)) {\n          return {\n            content: `Relation ${params.identifier} -[blocks]-> ${params.targetIssue} did not exist (no-op, idempotent).`,\n            details: { idempotent: true, relationType: params.relationType },\n          };\n        }\n        const updResult = await safeUpdateDoc(tctx.client, ISSUE_CLASS, target, {\n          $pull: { blockedBy: pullSourceRef },\n        });\n        if (!updResult.ok) return updResult.error;\n      } else if (params.relationType === \"is-blocked-by\") {\n        // A is-blocked-by B → xóa B khỏi A.blockedBy[]. Pull trên NGUỒN A.\n        if (!hasRelation((issue as { blockedBy?: unknown[] }).blockedBy, target._id as string)) {\n          return {\n            content: `Relation ${params.identifier} -[is-blocked-by]-> ${params.targetIssue} did not exist (no-op, idempotent).`,\n            details: { idempotent: true, relationType: params.relationType },\n          };\n        }\n        const updResult = await safeUpdateDoc(tctx.client, ISSUE_CLASS, issue, {\n          $pull: { blockedBy: pullRef },\n        });\n        if (!updResult.ok) return updResult.error;\n      } else {\n        // relates-to → BIDIRECTIONAL: $pull cả 2 chiều.\n        const forwardExists = hasRelation(\n          (issue as { relations?: unknown[] }).relations,\n          target._id as string,\n        );\n        const reverseExists = hasRelation(\n          (target as { relations?: unknown[] }).relations,\n          issue._id as string,\n        );\n        if (!forwardExists && !reverseExists) {\n          return {\n            content: `Relation ${params.identifier} -[relates-to]-> ${params.targetIssue} did not exist (no-op, idempotent).`,\n            details: { idempotent: true, relationType: params.relationType },\n          };\n        }\n        if (forwardExists) {\n          const updResult = await safeUpdateDoc(tctx.client, ISSUE_CLASS, issue, {\n            $pull: { relations: pullRef },\n          });\n          if (!updResult.ok) return updResult.error;\n        }\n        if (reverseExists) {\n          const updResult = await safeUpdateDoc(tctx.client, ISSUE_CLASS, target, {\n            $pull: { relations: pullSourceRef },\n          });\n          if (!updResult.ok) return updResult.error;\n        }\n      }\n      return {\n        content: `Removed relation ${params.identifier} -[${params.relationType}]-> ${params.targetIssue}.`,\n        details: {\n          identifier: params.identifier,\n          targetIssue: params.targetIssue,\n          relationType: params.relationType,\n        },\n      };\n    },\n  }),\n\n  // 3. list_issue_relations — T-59: read Issue.relations + blockedBy trực tiếp\n  defineHulyTool({\n    name: \"list_issue_relations\",\n    label: \"List issue relations\",\n    description:\n      \"List relations (blocks/is-blocked-by/relates-to) của issue. \" +\n      \"blocks: reverse query findAll (issues có blockedBy._id === issue._id). \" +\n      \"is-blocked-by: đọc issue.blockedBy trực tiếp. \" +\n      \"relates-to: đọc issue.relations (bidirectional).\",\n    needsProject: true,\n    parameters: Type.Object({\n      workspace: workspaceParam,\n      project: projectParam,\n      identifier: identifierParam,\n    }),\n    async handler(params, tctx) {\n      const issue = await tctx.client.findOne(ISSUE_CLASS, {\n        identifier: resolveIdentifier(tctx.project!, params.identifier),\n      });\n      if (!issue) {\n        return {\n          content: `Issue \"${params.identifier}\" not found.`,\n          isError: true,\n          details: { identifier: params.identifier },\n        };\n      }\n      // T-61 fix: 3 hướng rõ ràng, khớp Huly UI RelationsPopup:\n      //   - is-blocked-by: đọc issue.blockedBy (issues blocking this)\n      //   - relates-to:    đọc issue.relations (bidirectional related)\n      //   - blocks:        REVERSE QUERY — findAll issues có blockedBy._id === issue._id\n      //                    (issues mà issue này blocks — KHÔNG có field riêng)\n      const blockedBy = ((issue as { blockedBy?: unknown[] }).blockedBy ?? []) as Array<{\n        _id?: string;\n        _class?: string;\n      }>;\n      const relations = ((issue as { relations?: unknown[] }).relations ?? []) as Array<{\n        _id?: string;\n        _class?: string;\n      }>;\n      // T-80 #103: blocks = REVERSE QUERY. Dotted-path `{ \"blockedBy._id\": x }`\n      // returns NO rows trong Huly query engine — phải object form\n      // `{ blockedBy: { _id, _class } }` (verified trusted PR #48 comment).\n      const blockedResults = (await tctx.client.findAll(ISSUE_CLASS, {\n        blockedBy: { _id: issue._id, _class: ISSUE_CLASS },\n      } as never)) as Array<{ _id?: string; identifier?: string; _class?: string }>;\n      // T-80 #103: resolve raw _id → identifier (batch findAll $in). Trước đây\n      // trả raw Ref → LLM không dùng được kết quả.\n      const allIds = [\n        ...blockedResults.map((r) => r._id),\n        ...blockedBy.map((r) => r._id),\n        ...relations.map((r) => r._id),\n      ].filter((id): id is string => typeof id === \"string\");\n      const idMap = new Map<string, string>();\n      if (allIds.length > 0) {\n        const resolved = (await tctx.client.findAll(ISSUE_CLASS, {\n          _id: { $in: allIds },\n        } as never)) as Array<{ _id?: string; identifier?: string }>;\n        for (const r of resolved) {\n          if (r._id !== undefined && r.identifier !== undefined) {\n            idMap.set(r._id, r.identifier);\n          }\n        }\n      }\n      const blocksList = blockedResults.map((r) => ({\n        identifier: r._id !== undefined ? idMap.get(r._id) : undefined,\n        targetIssueId: r._id,\n        direction: \"blocks\" as const,\n      }));\n      const blockedList = blockedBy.map((r) => ({\n        identifier: r._id !== undefined ? idMap.get(r._id) : undefined,\n        targetIssueId: r._id,\n        direction: \"is-blocked-by\" as const,\n      }));\n      const relList = relations.map((r) => ({\n        identifier: r._id !== undefined ? idMap.get(r._id) : undefined,\n        targetIssueId: r._id,\n        direction: \"relates-to\" as const,\n      }));\n      const all = [...blocksList, ...blockedList, ...relList];\n      return {\n        content:\n          `Found ${all.length} relation(s) on ${params.identifier} ` +\n          `(${blocksList.length} blocks, ${blockedList.length} is-blocked-by, ${relList.length} relates-to).`,\n        details: { count: all.length, relations: all },\n      };\n    },\n  }),\n\n  // 4. link_document_to_issue — T-60: honest-unavailable (DOCUMENT_CLASS orphan)\n  defineHulyTool({\n    name: \"link_document_to_issue\",\n    label: \"Link document to issue\",\n    description:\n      \"UNAVAILABLE — tracker:class:Document not registered runtime. Link doc↔issue via Huly UI.\",\n    needsProject: true,\n    parameters: Type.Object({\n      workspace: workspaceParam,\n      project: projectParam,\n      identifier: identifierParam,\n      document: Type.String(),\n    }),\n    async handler(_params, _tctx) {\n      return {\n        content:\n          `link_document_to_issue KHÔNG khả dụng: Huly runtime class ` +\n          `\"tracker:class:Document\" KHÔNG register trong plugin() class block ` +\n          `(interface orphan — T-58 audit). Link doc↔issue qua Huly UI Relations ` +\n          `panel trực tiếp.`,\n        isError: true,\n        details: { reason: \"interface_orphan\", useClass: \"tracker:class:Document\" },\n      };\n    },\n  }),\n\n  // 5. unlink_document_to_issue — T-60: honest-unavailable (DOCUMENT_CLASS orphan)\n  defineHulyTool({\n    name: \"unlink_document_to_issue\",\n    label: \"Unlink document from issue\",\n    description:\n      \"UNAVAILABLE — tracker:class:Document not registered runtime. Unlink doc↔issue via Huly UI.\",\n    needsProject: true,\n    parameters: Type.Object({\n      workspace: workspaceParam,\n      project: projectParam,\n      identifier: identifierParam,\n      document: Type.String(),\n    }),\n    async handler(_params, _tctx) {\n      return {\n        content:\n          `unlink_document_to_issue KHÔNG khả dụng: Huly runtime class ` +\n          `\"tracker:class:Document\" KHÔNG register trong plugin() class block ` +\n          `(interface orphan — T-58 audit). Unlink doc↔issue qua Huly UI ` +\n          `Relations panel trực tiếp.`,\n        isError: true,\n        details: { reason: \"interface_orphan\", useClass: \"tracker:class:Document\" },\n      };\n    },\n  }),\n];\n","// tools/domains/issues-templates.ts — Issue templates domain (8 tools).\n// Design: 06-api.md §4 Issue templates. CRUD + create_from + children.\n\nimport { Type } from \"typebox\";\nimport { defineHulyTool, type HulyToolDefinition } from \"../builder.js\";\nimport {\n  ISSUE_TEMPLATE_CLASS,\n  ISSUE_CLASS,\n  PROJECT_CLASS,\n  PERSON_CLASS,\n  COMPONENT_CLASS,\n  NO_PARENT_REF,\n  ISSUE_KIND_REF,\n} from \"./_class-refs.js\";\nimport type { IssueTemplateDoc, PersonDoc, ComponentDoc } from \"./_entity-types.js\";\nimport {\n  workspaceParam,\n  projectParam,\n  safeUpdateDoc,\n  safeRemoveDoc,\n  getProjectSpace,\n} from \"./_common.js\";\nimport { mdToMarkup } from \"../../markup/markup.js\";\nimport { findPersonByEmailOrName } from \"./contacts.js\";\n\n/** T-76: IssueTemplateChild object shape (replaces raw string in children array). */\ninterface TemplateChild {\n  id: string;\n  title: string;\n  description?: string;\n  priority?: string;\n  assignee?: string | null;\n  component?: string | null;\n  estimation?: number;\n}\n\n/** Generate Huly-style id for template child (Ref<Issue> placeholder). */\nfunction genChildId(): string {\n  return `tracker:issue.${Math.random().toString(36).slice(2, 12)}`;\n}\n\nexport const tools: HulyToolDefinition[] = [\n  // 1. list_templates\n  defineHulyTool({\n    name: \"list_templates\",\n    label: \"List issue templates\",\n    description: \"List issue templates trong project.\",\n    needsProject: true,\n    parameters: Type.Object({ workspace: workspaceParam, project: projectParam }),\n    async handler(_params, tctx) {\n      // T-71: space scoping (KHÔNG findAll global cross-project).\n      const space = await getProjectSpace(tctx.client, tctx.project!);\n      if (!space) {\n        return {\n          content: `Project \"${tctx.project}\" not found.`,\n          isError: true,\n          details: { project: tctx.project },\n        };\n      }\n      // T-89 #124: sort modifiedOn Descending + output priority/modifiedOn/childrenCount. T-90: native IssueTemplateDoc.\n      const tpls = await tctx.client.findAll<IssueTemplateDoc>(\n        ISSUE_TEMPLATE_CLASS,\n        { space },\n        {\n          sort: { modifiedOn: -1 },\n        },\n      );\n      const list = tpls.map((tpl) => ({\n        _id: tpl._id,\n        title: tpl.title ?? \"\",\n        priority: tpl.priority,\n        modifiedOn: tpl.modifiedOn,\n        childrenCount: tpl.children?.length ?? 0,\n      }));\n      return {\n        content: `Found ${list.length} template(s).`,\n        details: { count: list.length, templates: list },\n      };\n    },\n  }),\n\n  // 2. get_template\n  defineHulyTool({\n    name: \"get_template\",\n    label: \"Get issue template\",\n    description: \"Get issue template by id.\",\n    needsProject: true,\n    parameters: Type.Object({\n      workspace: workspaceParam,\n      project: projectParam,\n      template: Type.String(),\n    }),\n    async handler(params, tctx) {\n      // T-100 (#146): scope template lookup theo project space (mirror components.ts T-81).\n      const space = await getProjectSpace(tctx.client, tctx.project!);\n      if (!space) {\n        return {\n          content: `Project \"${tctx.project}\" not found.`,\n          isError: true,\n          details: { project: tctx.project },\n        };\n      }\n      const tpl = await tctx.client.findOne<IssueTemplateDoc>(ISSUE_TEMPLATE_CLASS, {\n        _id: params.template,\n        space,\n      } as never);\n      if (!tpl) {\n        return {\n          content: `Template \"${params.template}\" not found.`,\n          isError: true,\n          details: { template: params.template },\n        };\n      }\n      // T-89 #124: resolve description MarkupBlobRef → markdown.\n      let description: string | undefined;\n      if (tpl.description) {\n        try {\n          description = await tctx.client.fetchMarkup(\n            ISSUE_TEMPLATE_CLASS,\n            tpl._id,\n            \"description\",\n            tpl.description,\n            \"markdown\",\n          );\n        } catch {\n          // Markup fetch fail — omit description.\n        }\n      }\n      // T-89 #124: resolve assignee (Person name) + component (label). T-90: native PersonDoc/ComponentDoc.\n      let assigneeName: string | undefined;\n      if (tpl.assignee) {\n        const person = await tctx.client.findOne<PersonDoc>(PERSON_CLASS, { _id: tpl.assignee });\n        assigneeName = person?.name;\n      }\n      let componentLabel: string | undefined;\n      if (tpl.component) {\n        const comp = await tctx.client.findOne<ComponentDoc>(COMPONENT_CLASS, {\n          _id: tpl.component,\n        });\n        componentLabel = comp?.label;\n      }\n      return {\n        content: `Template ${tpl.title ?? \"\"}`,\n        details: {\n          _id: tpl._id,\n          title: tpl.title,\n          description,\n          priority: tpl.priority,\n          assignee: assigneeName ?? tpl.assignee,\n          component: componentLabel ?? tpl.component,\n          estimation: tpl.estimation,\n          modifiedOn: tpl.modifiedOn,\n          createdOn: tpl.createdOn,\n          children: tpl.children,\n        },\n      };\n    },\n  }),\n\n  // 3. create_template\n  defineHulyTool({\n    name: \"create_template\",\n    label: \"Create issue template\",\n    description: \"Create issue template.\",\n    needsProject: true,\n    parameters: Type.Object({\n      workspace: workspaceParam,\n      project: projectParam,\n      title: Type.String(),\n      description: Type.Optional(Type.String()),\n    }),\n    async handler(params, tctx) {\n      // T-103 #160: guard title non-empty.\n      if (params.title.trim() === \"\") {\n        return {\n          content: `create_template title must be non-empty.`,\n          isError: true,\n          details: { title: params.title },\n        };\n      }\n      const project = await tctx.client.findOne(PROJECT_CLASS, {\n        identifier: tctx.project,\n      });\n      // T-51 #41: project null → isError rõ ràng, KHÔNG fallback workspace.\n      if (!project) {\n        return {\n          content: `Project \"${tctx.project}\" not found. Run /huly init or check binding.`,\n          isError: true,\n          details: { project: tctx.project },\n        };\n      }\n      const descMarkup =\n        params.description !== undefined\n          ? JSON.stringify(mdToMarkup(params.description))\n          : undefined;\n      // T-97 (#143): space = project._id (KHÔNG project.space).\n      const id = await tctx.client.createDoc(\n        ISSUE_TEMPLATE_CLASS,\n        project._id as never,\n        {\n          title: params.title,\n          description: descMarkup,\n          // T-76: default fields (trusted createIssueTemplate).\n          priority: \"no-priority\",\n          assignee: null,\n          component: null,\n          estimation: 0,\n          children: [],\n          comments: 0,\n        } as never,\n      );\n      return {\n        content: `Created template \"${params.title}\".`,\n        details: { id, title: params.title },\n      };\n    },\n  }),\n\n  // 4. create_issue_from_template\n  defineHulyTool({\n    name: \"create_issue_from_template\",\n    label: \"Create issue from template\",\n    description: \"Create new issue from template.\",\n    needsProject: true,\n    parameters: Type.Object({\n      workspace: workspaceParam,\n      project: projectParam,\n      template: Type.String(),\n      title: Type.Optional(Type.String()),\n    }),\n    async handler(params, tctx) {\n      // T-100 (#146): project first — dùng project._id scope cho tpl lookup\n      // (tránh getProjectSpace thừa; handler tạo issue trong project._id space).\n      const project = await tctx.client.findOne(PROJECT_CLASS, {\n        identifier: tctx.project,\n      });\n      if (!project) {\n        return {\n          content: `Project \"${tctx.project}\" not found. Run /huly init or check binding.`,\n          isError: true,\n          details: { project: tctx.project },\n        };\n      }\n      const tpl = await tctx.client.findOne(ISSUE_TEMPLATE_CLASS, {\n        _id: params.template,\n        space: project._id,\n      } as never);\n      if (!tpl) {\n        return {\n          content: `Template \"${params.template}\" not found.`,\n          isError: true,\n          details: { template: params.template },\n        };\n      }\n      const title = params.title ?? (tpl as { title?: string }).title ?? \"Untitled\";\n      // T-76: copy priority/assignee/component từ template (trước chỉ copy title+desc).\n      const tplFields = tpl as {\n        priority?: string;\n        assignee?: string | null;\n        component?: string | null;\n        description?: string;\n      };\n      // T-103 #155: Issue = AttachedDoc → createDoc crash ('cannot be used for objects\n      // inherited from AttachedDoc'). Mirror create_issue: $inc sequence → identifier\n      // → addCollection (attached-to-project collection), KHÔNG createDoc.\n      const incResult = await tctx.client.updateDoc(\n        PROJECT_CLASS,\n        \"core:space:Space\" as never,\n        project._id as never,\n        { $inc: { sequence: 1 } } as never,\n        true,\n      );\n      const seqRaw = (incResult as { object?: { sequence?: number } })?.object?.sequence;\n      const sequence =\n        typeof seqRaw === \"number\"\n          ? seqRaw\n          : ((project as { sequence?: number }).sequence ?? 0) + 1;\n      const identifier = `${(project as { identifier?: string }).identifier ?? tctx.project}-${sequence}`;\n      // description: copy markup ref từ template (nếu có), KHÔNG re-upload.\n      const issueId = `tracker:issue.${Math.random().toString(36).slice(2, 14)}`;\n      const id = await tctx.client.addCollection(\n        ISSUE_CLASS,\n        project._id as never, // space = project (issues live trong project space)\n        NO_PARENT_REF, // attachedTo = NoParent sentinel (top-level)\n        ISSUE_CLASS, // attachedToClass\n        \"subIssues\", // collection\n        {\n          title,\n          description: tplFields.description ?? null,\n          priority: tplFields.priority ?? \"no-priority\",\n          assignee: tplFields.assignee ?? null,\n          component: tplFields.component ?? null,\n          status: undefined,\n          number: sequence,\n          kind: ISSUE_KIND_REF,\n          identifier,\n          estimation: 0,\n          remainingTime: 0,\n          reportedTime: 0,\n          reports: 0,\n          subIssues: 0,\n          parents: [],\n          childInfo: [],\n          dueDate: null,\n          rank: \"\",\n        } as never,\n        issueId as never,\n      );\n      return {\n        content: `Created issue ${identifier}: \"${title}\" from template.`,\n        details: { id, identifier, title, template: params.template },\n      };\n    },\n  }),\n\n  // 5. update_template\n  defineHulyTool({\n    name: \"update_template\",\n    label: \"Update issue template\",\n    description: \"Update template (title, description).\",\n    needsProject: true,\n    parameters: Type.Object({\n      workspace: workspaceParam,\n      project: projectParam,\n      template: Type.String(),\n      title: Type.Optional(Type.String()),\n      description: Type.Optional(Type.String()),\n    }),\n    async handler(params, tctx) {\n      // T-100 (#146): scope template lookup theo project space.\n      const space = await getProjectSpace(tctx.client, tctx.project!);\n      if (!space) {\n        return {\n          content: `Project \"${tctx.project}\" not found.`,\n          isError: true,\n          details: { project: tctx.project },\n        };\n      }\n      const t = await tctx.client.findOne(ISSUE_TEMPLATE_CLASS, {\n        _id: params.template,\n        space,\n      } as never);\n      if (!t) {\n        return {\n          content: `Template \"${params.template}\" not found.`,\n          isError: true,\n          details: { template: params.template },\n        };\n      }\n      const ops: Record<string, unknown> = {};\n      if (params.title !== undefined) {\n        if (params.title.trim() === \"\")\n          return {\n            content: \"title must be non-empty.\",\n            isError: true,\n            details: { title: params.title },\n          };\n        ops.title = params.title;\n      }\n      if (params.description !== undefined)\n        ops.description = JSON.stringify(mdToMarkup(params.description));\n      if (Object.keys(ops).length === 0) {\n        return { content: \"No fields to update.\", details: { updated: false } };\n      }\n      const updResult = await safeUpdateDoc(tctx.client, ISSUE_TEMPLATE_CLASS, t, ops);\n      if (!updResult.ok) return updResult.error;\n      return {\n        content: `Updated template ${params.template}.`,\n        details: { updated: true, fields: Object.keys(ops) },\n      };\n    },\n  }),\n\n  // 6. delete_template — destructive\n  defineHulyTool({\n    name: \"delete_template\",\n    label: \"Delete issue template\",\n    description: \"Delete template (destructive).\",\n    destructive: true,\n    needsProject: true,\n    destructiveContext: (p) => ({\n      type: \"template\",\n      id: (p as { template?: string }).template ?? \"<unknown>\",\n    }),\n    parameters: Type.Object({\n      workspace: workspaceParam,\n      project: projectParam,\n      template: Type.String(),\n    }),\n    async handler(params, tctx) {\n      // T-100 (#146): scope template lookup theo project space.\n      const space = await getProjectSpace(tctx.client, tctx.project!);\n      if (!space) {\n        return {\n          content: `Project \"${tctx.project}\" not found.`,\n          isError: true,\n          details: { project: tctx.project },\n        };\n      }\n      const t = await tctx.client.findOne(ISSUE_TEMPLATE_CLASS, {\n        _id: params.template,\n        space,\n      } as never);\n      if (!t) {\n        return {\n          content: `Template \"${params.template}\" not found.`,\n          isError: true,\n          details: { template: params.template },\n        };\n      }\n      const delResult = await safeRemoveDoc(tctx.client, ISSUE_TEMPLATE_CLASS, t);\n      if (!delResult.ok) return delResult.error;\n      return {\n        content: `Deleted template ${params.template}.`,\n        details: { deleted: true, template: params.template },\n      };\n    },\n  }),\n\n  // 7. add_template_child — T-76: build IssueTemplateChild object + replace array\n  defineHulyTool({\n    name: \"add_template_child\",\n    label: \"Add template child\",\n    description:\n      \"Add child template to parent. Builds IssueTemplateChild object {id,title,priority,...} + replaces full children array.\",\n    needsProject: true,\n    parameters: Type.Object({\n      workspace: workspaceParam,\n      project: projectParam,\n      template: Type.String(),\n      title: Type.String(),\n      description: Type.Optional(Type.String()),\n      priority: Type.Optional(Type.String()),\n      assignee: Type.Optional(Type.String()),\n      component: Type.Optional(Type.String()),\n      estimation: Type.Optional(Type.Integer()),\n    }),\n    async handler(params, tctx) {\n      // T-100 (#146): scope template lookup theo project space.\n      const space = await getProjectSpace(tctx.client, tctx.project!);\n      if (!space) {\n        return {\n          content: `Project \"${tctx.project}\" not found.`,\n          isError: true,\n          details: { project: tctx.project },\n        };\n      }\n      const t = await tctx.client.findOne(ISSUE_TEMPLATE_CLASS, {\n        _id: params.template,\n        space,\n      } as never);\n      if (!t) {\n        return {\n          content: `Template \"${params.template}\" not found.`,\n          isError: true,\n          details: { template: params.template },\n        };\n      }\n      // T-101 (#147): resolve assignee/component → Ref _id (KHÔNG raw string).\n      // Trước đây child.assignee/component = raw email/label → garbage Ref (cousin\n      // #141). Chỉ resolve khi provided (existing test không truyền → no shift).\n      let assigneeRef: string | undefined;\n      if (params.assignee !== undefined) {\n        assigneeRef = await findPersonByEmailOrName(tctx.client, params.assignee, tctx.currentUser);\n        if (!assigneeRef) {\n          return {\n            content: `Assignee \"${params.assignee}\" not found (no Person matching email/name).`,\n            isError: true,\n            details: { assignee: params.assignee, template: params.template },\n          };\n        }\n      }\n      let componentRef: string | undefined;\n      if (params.component !== undefined) {\n        const tplSpace = (t as { space?: string }).space;\n        const comp = await tctx.client.findOne(COMPONENT_CLASS, {\n          label: params.component,\n          space: tplSpace,\n        } as never);\n        if (!comp) {\n          return {\n            content: `Component \"${params.component}\" not found.`,\n            isError: true,\n            details: { component: params.component, template: params.template },\n          };\n        }\n        componentRef = (comp as { _id: string })._id;\n      }\n      // T-76: build IssueTemplateChild object (KHÔNG raw string).\n      const child: TemplateChild = {\n        id: genChildId(),\n        title: params.title,\n      };\n      if (params.description !== undefined) child.description = params.description;\n      if (params.priority !== undefined) child.priority = params.priority;\n      if (params.assignee !== undefined) child.assignee = assigneeRef;\n      if (params.component !== undefined) child.component = componentRef;\n      if (params.estimation !== undefined) child.estimation = params.estimation;\n      // T-76: replace full children array (KHÔNG $push).\n      const existingChildren = ((t as { children?: TemplateChild[] }).children ??\n        []) as TemplateChild[];\n      const updResult = await safeUpdateDoc(tctx.client, ISSUE_TEMPLATE_CLASS, t, {\n        children: [...existingChildren, child],\n      });\n      if (!updResult.ok) return updResult.error;\n      return {\n        content: `Added child \"${params.title}\" to template ${params.template}.`,\n        details: { template: params.template, childId: child.id, title: params.title },\n      };\n    },\n  }),\n\n  // 8. remove_template_child — T-76: find by id field + replace array\n  defineHulyTool({\n    name: \"remove_template_child\",\n    label: \"Remove template child\",\n    description: \"Remove child from parent template (by child id).\",\n    needsProject: true,\n    parameters: Type.Object({\n      workspace: workspaceParam,\n      project: projectParam,\n      template: Type.String(),\n      childId: Type.String({ description: \"IssueTemplateChild.id to remove.\" }),\n    }),\n    async handler(params, tctx) {\n      // T-100 (#146): scope template lookup theo project space.\n      const space = await getProjectSpace(tctx.client, tctx.project!);\n      if (!space) {\n        return {\n          content: `Project \"${tctx.project}\" not found.`,\n          isError: true,\n          details: { project: tctx.project },\n        };\n      }\n      const t = await tctx.client.findOne(ISSUE_TEMPLATE_CLASS, {\n        _id: params.template,\n        space,\n      } as never);\n      if (!t) {\n        return {\n          content: `Template \"${params.template}\" not found.`,\n          isError: true,\n          details: { template: params.template },\n        };\n      }\n      // T-76: find by id field trong children (KHÔNG $pull raw string).\n      const existingChildren = ((t as { children?: TemplateChild[] }).children ??\n        []) as TemplateChild[];\n      const idx = existingChildren.findIndex((c) => c.id === params.childId);\n      if (idx === -1) {\n        return {\n          content: `Child \"${params.childId}\" not found in template ${params.template}.`,\n          isError: true,\n          details: { template: params.template, childId: params.childId },\n        };\n      }\n      const newChildren = existingChildren.filter((_, i) => i !== idx);\n      const updResult = await safeUpdateDoc(tctx.client, ISSUE_TEMPLATE_CLASS, t, {\n        children: newChildren,\n      });\n      if (!updResult.ok) return updResult.error;\n      return {\n        content: `Removed child ${params.childId} from template ${params.template}.`,\n        details: { template: params.template, childId: params.childId },\n      };\n    },\n  }),\n];\n","// tools/domains/attachments.ts — Attachments domain (5 tools).\n// Design: 06-api.md §4 Attachments.\n\nimport { Type } from \"typebox\";\nimport { defineHulyTool, type HulyToolDefinition } from \"../builder.js\";\nimport { ATTACHMENT_CLASS, ISSUE_CLASS, spaceRef } from \"./_class-refs.js\";\nimport { workspaceParam, projectParam, identifierParam, resolveIdentifier } from \"./_common.js\";\n\nexport const tools: HulyToolDefinition[] = [\n  // 1. list_attachments\n  defineHulyTool({\n    name: \"list_attachments\",\n    label: \"List attachments\",\n    description: \"List attachments attached to entity.\",\n    needsProject: true,\n    parameters: Type.Object({\n      workspace: workspaceParam,\n      project: projectParam,\n      identifier: identifierParam,\n    }),\n    async handler(params, tctx) {\n      const issue = await tctx.client.findOne(ISSUE_CLASS, {\n        identifier: resolveIdentifier(tctx.project!, params.identifier),\n      });\n      if (!issue) {\n        return {\n          content: `Issue \"${params.identifier}\" not found.`,\n          isError: true,\n          details: { identifier: params.identifier },\n        };\n      }\n      const atts = await tctx.client.findAll(ATTACHMENT_CLASS, { attachedTo: issue._id }, {});\n      const list = atts.map((a) => ({\n        _id: a._id,\n        name: (a as { name?: string }).name ?? \"\",\n        type: (a as { type?: string }).type, // T-75: field `type` (KHÔNG contentType)\n        size: (a as { size?: number }).size,\n      }));\n      return {\n        content: `Found ${list.length} attachment(s).`,\n        details: { count: list.length, attachments: list },\n      };\n    },\n  }),\n\n  // 2. get_attachment\n  defineHulyTool({\n    name: \"get_attachment\",\n    label: \"Get attachment\",\n    description: \"Get attachment metadata by id.\",\n    parameters: Type.Object({\n      workspace: workspaceParam,\n      attachment: Type.String(),\n    }),\n    async handler(params, tctx) {\n      const a = await tctx.client.findOne(ATTACHMENT_CLASS, { _id: params.attachment });\n      if (!a) {\n        return {\n          content: `Attachment \"${params.attachment}\" not found.`,\n          isError: true,\n          details: { attachment: params.attachment },\n        };\n      }\n      return {\n        content: `Attachment ${(a as { name?: string }).name ?? \"\"}`,\n        details: {\n          _id: a._id,\n          name: (a as { name?: string }).name,\n          type: (a as { type?: string }).type, // T-75: field `type`\n          size: (a as { size?: number }).size,\n        },\n      };\n    },\n  }),\n\n  // 3. add_attachment (generic) — T-75: uploadFile → blobId → addCollection\n  defineHulyTool({\n    name: \"add_attachment\",\n    label: \"Add attachment\",\n    description:\n      \"Add attachment to entity. Uploads base64 data → blob, attaches via addCollection.\",\n    parameters: Type.Object({\n      workspace: workspaceParam,\n      attachedTo: Type.String(),\n      attachedToClass: Type.Optional(\n        Type.String({ description: \"Target class (default tracker:class:Issue).\" }),\n      ),\n      filename: Type.String(),\n      contentType: Type.String(),\n      data: Type.Optional(Type.String({ description: \"Base64 data (raw, no data: URL prefix).\" })),\n      description: Type.Optional(Type.String()),\n    }),\n    async handler(params, tctx) {\n      if (!params.data) {\n        return {\n          content: \"add_attachment requires `data` (base64).\",\n          isError: true,\n          details: { filename: params.filename },\n        };\n      }\n      if (typeof tctx.client.uploadBlob !== \"function\") {\n        return {\n          content: \"uploadBlob not available on this transport (use WS).\",\n          isError: true,\n          details: { reason: \"storage_not_wired\" },\n        };\n      }\n      // T-75: strip data: URL prefix nếu có.\n      const b64 = params.data.replace(/^data:[^;]+;base64,/, \"\");\n      const buffer = Buffer.from(b64, \"base64\");\n      const { blobId, size } = await tctx.client.uploadBlob(\n        params.filename,\n        buffer,\n        params.contentType,\n      );\n      // T-75: Attachment = AttachedDoc → addCollection (KHÔNG createDoc). Fields\n      // {name, file: Ref<Blob>, size, type, lastModified} (KHÔNG contentType/data).\n      const targetClass = params.attachedToClass ?? ISSUE_CLASS;\n      // T-93b TODO(#139): space nên là attachedTo entity's space (resolve entity →\n      // ._id → space). Hiện spaceRef(workspace) = handle string — có thể orphan.\n      // add_issue_attachment (project-scoped) đã đúng (issue.space). Generic path\n      // defer đến khi cần (ít dùng — đa số attach qua add_issue_attachment).\n      const id = await tctx.client.addCollection(\n        ATTACHMENT_CLASS,\n        spaceRef(tctx.workspace),\n        params.attachedTo as never,\n        targetClass as never,\n        \"attachments\",\n        {\n          name: params.filename,\n          file: blobId,\n          size,\n          type: params.contentType,\n          lastModified: Date.now(),\n          ...(params.description ? { description: params.description } : {}),\n        } as never,\n      );\n      return {\n        content: `Added attachment \"${params.filename}\".`,\n        details: { id, filename: params.filename, blobId, size },\n      };\n    },\n  }),\n\n  // 4. add_issue_attachment — issue-specific\n  defineHulyTool({\n    name: \"add_issue_attachment\",\n    label: \"Add issue attachment\",\n    description: \"Add attachment to issue.\",\n    needsProject: true,\n    parameters: Type.Object({\n      workspace: workspaceParam,\n      project: projectParam,\n      identifier: identifierParam,\n      filename: Type.String(),\n      contentType: Type.String(),\n      data: Type.Optional(Type.String()),\n      description: Type.Optional(Type.String()),\n    }),\n    async handler(params, tctx) {\n      if (!params.data) {\n        return {\n          content: \"add_issue_attachment requires `data` (base64).\",\n          isError: true,\n          details: { filename: params.filename },\n        };\n      }\n      if (typeof tctx.client.uploadBlob !== \"function\") {\n        return {\n          content: \"uploadBlob not available on this transport (use WS).\",\n          isError: true,\n          details: { reason: \"storage_not_wired\" },\n        };\n      }\n      const issue = await tctx.client.findOne(ISSUE_CLASS, {\n        identifier: resolveIdentifier(tctx.project!, params.identifier),\n      });\n      if (!issue) {\n        return {\n          content: `Issue \"${params.identifier}\" not found.`,\n          isError: true,\n          details: { identifier: params.identifier },\n        };\n      }\n      const b64 = params.data.replace(/^data:[^;]+;base64,/, \"\");\n      const buffer = Buffer.from(b64, \"base64\");\n      const { blobId, size } = await tctx.client.uploadBlob(\n        params.filename,\n        buffer,\n        params.contentType,\n      );\n      const id = await tctx.client.addCollection(\n        ATTACHMENT_CLASS,\n        issue.space as never,\n        issue._id as never,\n        ISSUE_CLASS,\n        \"attachments\",\n        {\n          name: params.filename,\n          file: blobId,\n          size,\n          type: params.contentType,\n          lastModified: Date.now(),\n          ...(params.description ? { description: params.description } : {}),\n        } as never,\n      );\n      return {\n        content: `Added attachment \"${params.filename}\" to ${params.identifier}.`,\n        details: { id, filename: params.filename, identifier: params.identifier, blobId, size },\n      };\n    },\n  }),\n\n  // 5. download_attachment — T-75: getBlob → base64 (KHÔNG đọc field `data`)\n  defineHulyTool({\n    name: \"download_attachment\",\n    label: \"Download attachment\",\n    description: \"Get attachment content (base64). Downloads blob via storageClient.\",\n    parameters: Type.Object({\n      workspace: workspaceParam,\n      attachment: Type.String(),\n    }),\n    async handler(params, tctx) {\n      const a = await tctx.client.findOne(ATTACHMENT_CLASS, { _id: params.attachment });\n      if (!a) {\n        return {\n          content: `Attachment \"${params.attachment}\" not found.`,\n          isError: true,\n          details: { attachment: params.attachment },\n        };\n      }\n      const fileId = (a as { file?: string }).file;\n      if (!fileId) {\n        return {\n          content: `Attachment \"${params.attachment}\" has no file blob ref.`,\n          isError: true,\n          details: { attachment: params.attachment },\n        };\n      }\n      if (typeof tctx.client.getBlob !== \"function\") {\n        return {\n          content: \"getBlob not available on this transport (use WS).\",\n          isError: true,\n          details: { reason: \"storage_not_wired\" },\n        };\n      }\n      const buffer = await tctx.client.getBlob(fileId);\n      return {\n        content: `Attachment ${(a as { name?: string }).name ?? \"\"} downloaded.`,\n        details: {\n          _id: a._id,\n          name: (a as { name?: string }).name,\n          type: (a as { type?: string }).type,\n          size: (a as { size?: number }).size,\n          data: buffer.toString(\"base64\"),\n        },\n      };\n    },\n  }),\n];\n","// tools/domains/todos.ts — Todos domain (7 tools).\n// Design: 06-api.md §4 Todos. attachedTo: {type:'issue', project, identifier}.\n\nimport { Type } from \"typebox\";\nimport { defineHulyTool, type HulyToolDefinition } from \"../builder.js\";\nimport { ISSUE_CLASS, TODO_CLASS, PROJECT_TODO_CLASS, TODOS_SPACE } from \"./_class-refs.js\";\nimport {\n  workspaceParam,\n  projectParam,\n  identifierParam,\n  resolveIdentifier,\n  safeUpdateDoc,\n  safeRemoveDoc,\n} from \"./_common.js\";\nimport { findPersonByEmailOrName } from \"./contacts.js\";\n\n/**\n * ToDoPriority enum (audit §5 — @hcengineering/time).\n * High=0, Medium=1, Low=2, NoPriority=3, Urgent=4.\n * Pi-huly API dùng string ('urgent', 'high', ...) → map sang number cho server.\n */\n// T-103 #164: Huly Priority enum (canonical, per @hcengineering):\n//   0=None, 1=Low, 2=Medium, 3=High, 4=Urgent (ASCENDING severity).\n// Trước đây map INVERTED (high:0, no-priority:3) → 'high' priority lưu 0=None,\n// 'no-priority' lưu 3=High (4/5 sai, chỉ urgent đúng). create/update todo\n// priority render sai semantic hoàn toàn.\nconst TODO_PRIORITY_MAP: Record<string, number> = {\n  \"no-priority\": 0,\n  low: 1,\n  medium: 2,\n  high: 3,\n  urgent: 4,\n};\n\n// Reverse: numeric Huly priority → human label (cho get_todo render readable).\nconst TODO_PRIORITY_LABELS: Record<number, string> = {\n  0: \"no-priority\",\n  1: \"low\",\n  2: \"medium\",\n  3: \"high\",\n  4: \"urgent\",\n};\n\n/** Priority param schema (string → number enum mapping). */\nconst todoPrioritySchema = Type.Optional(\n  Type.Union([\n    Type.Literal(\"urgent\"),\n    Type.Literal(\"high\"),\n    Type.Literal(\"medium\"),\n    Type.Literal(\"low\"),\n    Type.Literal(\"no-priority\"),\n  ]),\n);\n\nexport const tools: HulyToolDefinition[] = [\n  // 1. list_todos\n  defineHulyTool({\n    name: \"list_todos\",\n    label: \"List todos\",\n    description: \"List todos attached to issue.\",\n    needsProject: true,\n    parameters: Type.Object({\n      workspace: workspaceParam,\n      project: projectParam,\n      identifier: identifierParam,\n    }),\n    async handler(params, tctx) {\n      const issue = await tctx.client.findOne(ISSUE_CLASS, {\n        identifier: resolveIdentifier(tctx.project!, params.identifier),\n      });\n      if (!issue) {\n        return {\n          content: `Issue \"${params.identifier}\" not found.`,\n          isError: true,\n          details: { identifier: params.identifier },\n        };\n      }\n      // T-79 #102: issue.todos là CollectionSize counter (number), KHÔNG array.\n      // Query todos qua findAll theo attachedTo=issue._id (trusted planner.ts).\n      const todos = (await tctx.client.findAll(TODO_CLASS, {\n        attachedTo: issue._id,\n      } as never)) as Array<{ _id: string; title?: string; doneOn?: number | null }>;\n      const summary = todos.map((t) => ({\n        _id: t._id,\n        title: t.title ?? \"\",\n        done: t.doneOn != null,\n      }));\n      return {\n        content: `Found ${summary.length} todo(s) on ${params.identifier}.`,\n        details: { count: summary.length, todos: summary },\n      };\n    },\n  }),\n\n  // 2. get_todo\n  defineHulyTool({\n    name: \"get_todo\",\n    label: \"Get todo\",\n    description: \"Get todo by id.\",\n    parameters: Type.Object({\n      workspace: workspaceParam,\n      todo: Type.String(),\n    }),\n    async handler(params, tctx) {\n      const t = (await tctx.client.findOne(TODO_CLASS, { _id: params.todo })) as {\n        _id: string;\n        title?: string;\n        doneOn?: number | null;\n        user?: string;\n        dueDate?: number | null;\n        priority?: number;\n        description?: unknown;\n      } | null;\n      if (!t) {\n        return {\n          content: `Todo \"${params.todo}\" not found.`,\n          isError: true,\n          details: { todo: params.todo },\n        };\n      }\n      // T-103 #163: fetch description markup (MarkupBlobRef → markdown).\n      let description: string | undefined;\n      if (t.description) {\n        try {\n          const markup = await tctx.client.fetchMarkup(\n            TODO_CLASS,\n            t._id,\n            \"description\",\n            t.description,\n            \"markdown\",\n          );\n          description = typeof markup === \"string\" ? markup : undefined;\n        } catch {\n          description = undefined;\n        }\n      }\n      return {\n        content: `Todo: ${t.title ?? \"\"}`,\n        details: {\n          _id: t._id,\n          title: t.title,\n          description,\n          // T-79 #102: Huly ToDo dùng doneOn (timestamp|null), KHÔNG `done` bool.\n          doneOn: t.doneOn ?? null,\n          done: t.doneOn != null,\n          owner: t.user,\n          dueDate: t.dueDate ?? null,\n          priority: TODO_PRIORITY_LABELS[t.priority ?? -1] ?? t.priority,\n        },\n      };\n    },\n  }),\n\n  // 3. create_todo\n  defineHulyTool({\n    name: \"create_todo\",\n    label: \"Create todo\",\n    description: \"Create todo attached to issue.\",\n    needsProject: true,\n    needsAssignee: true,\n    assigneeField: \"owner\",\n    parameters: Type.Object({\n      workspace: workspaceParam,\n      project: projectParam,\n      identifier: identifierParam,\n      title: Type.String(),\n      description: Type.Optional(Type.String()),\n      dueDate: Type.Optional(Type.Integer()),\n      priority: todoPrioritySchema,\n    }),\n    async handler(params, tctx) {\n      // T-103 #160: guard title non-empty (empty = garbage todo).\n      if (params.title.trim() === \"\") {\n        return {\n          content: `create_todo title must be non-empty.`,\n          isError: true,\n          details: { title: params.title },\n        };\n      }\n      const issue = await tctx.client.findOne(ISSUE_CLASS, {\n        identifier: resolveIdentifier(tctx.project!, params.identifier),\n      });\n      if (!issue) {\n        return {\n          content: `Issue \"${params.identifier}\" not found.`,\n          isError: true,\n          details: { identifier: params.identifier },\n        };\n      }\n      // T-46 #28 + T-79 #102: ProjectToDo = subclass cho issue-attached todo.\n      // space = time.space.ToDos (KHÔNG issue.space). doneOn:null (KHÔNG `done`).\n      // attachedTo/attachedToClass = positional addCollection args (KHÔNG trong data).\n      // description = MarkupBlobRef qua uploadMarkup (KHÔNG JSON.stringify).\n      const priority = TODO_PRIORITY_MAP[params.priority ?? \"medium\"];\n      const todoId = `time:todo.${Math.random().toString(36).slice(2, 14)}` as never;\n      let descriptionRef: unknown = null;\n      if (params.description !== undefined && params.description.trim() !== \"\") {\n        descriptionRef = await tctx.client.uploadMarkup(\n          PROJECT_TODO_CLASS,\n          todoId,\n          \"description\",\n          params.description,\n          \"markdown\",\n        );\n      }\n      try {\n        const id = await tctx.client.addCollection(\n          PROJECT_TODO_CLASS,\n          TODOS_SPACE,\n          issue._id as never,\n          ISSUE_CLASS,\n          \"todos\",\n          {\n            title: params.title,\n            description: descriptionRef,\n            attachedSpace: issue.space,\n            user: tctx.currentUser.id, // Ref<Employee>\n            priority, // ToDoPriority number enum\n            visibility: \"Public\", // Visibility.Public default\n            rank: \"\", // lexorank empty — server gán nếu empty\n            workslots: 0,\n            doneOn: null, // T-79: open todo (KHÔNG `done:false`)\n            dueDate: params.dueDate,\n          },\n          todoId,\n        );\n        return {\n          content: `Created todo \"${params.title}\" on ${params.identifier}.`,\n          details: { id, title: params.title, identifier: params.identifier },\n        };\n      } catch (e) {\n        // Wrap lỗi generic của Huly server (platform:status:UnknownError) với\n        // context rõ ràng hơn — mention todo + issue + class để debug lần sau.\n        const msg = e instanceof Error ? e.message : String(e);\n        return {\n          content:\n            `Failed to create todo \"${params.title}\" on ${params.identifier} ` +\n            `(class ${PROJECT_TODO_CLASS}). Server error: ${msg}. ` +\n            `Verify issue exists and ProjectToDo required fields are valid.`,\n          isError: true,\n          details: {\n            identifier: params.identifier,\n            title: params.title,\n            error: msg,\n          },\n        };\n      }\n    },\n  }),\n\n  // 4. update_todo\n  defineHulyTool({\n    name: \"update_todo\",\n    label: \"Update todo\",\n    description:\n      \"Update todo (title, description, owner, priority, visibility, dueDate). \" +\n      \"dueDate=null clears ($unset).\",\n    parameters: Type.Object({\n      workspace: workspaceParam,\n      todo: Type.String(),\n      title: Type.Optional(Type.String()),\n      description: Type.Optional(Type.String()),\n      owner: Type.Optional(Type.String({ description: \"Owner email/name.\" })),\n      priority: todoPrioritySchema,\n      visibility: Type.Optional(\n        Type.Union([Type.Literal(\"public\"), Type.Literal(\"freeBusy\"), Type.Literal(\"private\")]),\n      ),\n      // T-79G #106: dueDate=null → \\$unset clear.\n      dueDate: Type.Optional(Type.Union([Type.Integer(), Type.Null()])),\n    }),\n    async handler(params, tctx) {\n      const t = await tctx.client.findOne(TODO_CLASS, { _id: params.todo });\n      if (!t) {\n        return {\n          content: `Todo \"${params.todo}\" not found.`,\n          isError: true,\n          details: { todo: params.todo },\n        };\n      }\n      const ops: Record<string, unknown> = {};\n      if (params.title !== undefined) {\n        if (params.title.trim() === \"\")\n          return {\n            content: \"title must be non-empty.\",\n            isError: true,\n            details: { title: params.title },\n          };\n        ops.title = params.title;\n      }\n      // T-103 #162: description = MarkupBlobRef → uploadMarkup ref + ops.description.\n      // Mirror update_issue (R11 proven persist). #106 trước dùng updateMarkup\n      // (updateContent) — chỉ EDIT blob existing, FAIL khi todo chưa có description\n      // (create without desc). uploadMarkup tạo blob mới + swap ref → works luôn.\n      if (params.description !== undefined) {\n        const ref = await tctx.client.uploadMarkup(\n          TODO_CLASS,\n          t._id,\n          \"description\",\n          params.description,\n          \"markdown\",\n        );\n        ops.description = ref;\n      }\n      // T-79G #106: owner → user: Ref<Employee> (resolve Person).\n      if (params.owner !== undefined) {\n        const ownerId = await findPersonByEmailOrName(tctx.client, params.owner, tctx.currentUser);\n        if (!ownerId) {\n          return {\n            content: `Owner \"${params.owner}\" not found (no Person matching email/name).`,\n            isError: true,\n            details: { owner: params.owner, todo: params.todo },\n          };\n        }\n        ops.user = ownerId;\n      }\n      if (params.priority !== undefined) ops.priority = TODO_PRIORITY_MAP[params.priority];\n      if (params.visibility !== undefined) {\n        // visibility string → Huly Visibility (public/freeBusy/private match 1:1).\n        ops.visibility = params.visibility.charAt(0).toUpperCase() + params.visibility.slice(1);\n      }\n      // T-79G #106: dueDate null → \\$unset (clear); number → set.\n      if (params.dueDate !== undefined) {\n        if (params.dueDate === null) {\n          ops.$unset = { dueDate: \"\" };\n        } else {\n          ops.dueDate = params.dueDate;\n        }\n      }\n      if (Object.keys(ops).length === 0) {\n        return { content: \"No fields to update.\", details: { updated: false } };\n      }\n      if (Object.keys(ops).length > 0) {\n        const updResult = await safeUpdateDoc(tctx.client, TODO_CLASS, t, ops);\n        if (!updResult.ok) return updResult.error;\n      }\n      const fields = Object.keys(ops).filter((f) => f !== \"$unset\");\n      if (ops.$unset !== undefined) fields.push(\"dueDate(clear)\");\n      return {\n        content: `Updated todo ${params.todo}: ${fields.join(\", \")}`,\n        details: { updated: true, fields },\n      };\n    },\n  }),\n\n  // 5. complete_todo\n  defineHulyTool({\n    name: \"complete_todo\",\n    label: \"Complete todo\",\n    description: \"Mark todo done.\",\n    parameters: Type.Object({\n      workspace: workspaceParam,\n      todo: Type.String(),\n    }),\n    async handler(params, tctx) {\n      const t = await tctx.client.findOne(TODO_CLASS, { _id: params.todo });\n      if (!t) {\n        return {\n          content: `Todo \"${params.todo}\" not found.`,\n          isError: true,\n          details: { todo: params.todo },\n        };\n      }\n      const updResult = await safeUpdateDoc(tctx.client, TODO_CLASS, t, {\n        doneOn: Date.now(), // T-79 #102: timestamp (KHÔNG `done:true` no-op)\n      });\n      if (!updResult.ok) return updResult.error;\n      return {\n        content: `Completed todo ${params.todo}.`,\n        details: { completed: true, todo: params.todo },\n      };\n    },\n  }),\n\n  // 6. reopen_todo\n  defineHulyTool({\n    name: \"reopen_todo\",\n    label: \"Reopen todo\",\n    description: \"Mark todo not done (reopen).\",\n    parameters: Type.Object({\n      workspace: workspaceParam,\n      todo: Type.String(),\n    }),\n    async handler(params, tctx) {\n      const t = await tctx.client.findOne(TODO_CLASS, { _id: params.todo });\n      if (!t) {\n        return {\n          content: `Todo \"${params.todo}\" not found.`,\n          isError: true,\n          details: { todo: params.todo },\n        };\n      }\n      const updResult = await safeUpdateDoc(tctx.client, TODO_CLASS, t, {\n        doneOn: null, // T-79 #102: clear completion (KHÔNG `done:false` no-op)\n      });\n      if (!updResult.ok) return updResult.error;\n      return {\n        content: `Reopened todo ${params.todo}.`,\n        details: { reopened: true, todo: params.todo },\n      };\n    },\n  }),\n\n  // 7. delete_todo — destructive\n  defineHulyTool({\n    name: \"delete_todo\",\n    label: \"Delete todo\",\n    description: \"Delete todo (destructive).\",\n    destructive: true,\n    destructiveContext: (p) => ({\n      type: \"todo\",\n      id: (p as { todo?: string }).todo ?? \"<unknown>\",\n    }),\n    parameters: Type.Object({\n      workspace: workspaceParam,\n      todo: Type.String(),\n    }),\n    async handler(params, tctx) {\n      const t = (await tctx.client.findOne(TODO_CLASS, { _id: params.todo })) as {\n        _id: string;\n        space: string;\n        attachedTo?: string;\n        attachedToClass?: string;\n        attachedSpace?: string;\n      } | null;\n      if (!t) {\n        return {\n          content: `Todo \"${params.todo}\" not found.`,\n          isError: true,\n          details: { todo: params.todo },\n        };\n      }\n      // T-79 #102: issue-attached todo = ProjectToDo subclass. removeDoc dùng\n      // PROJECT_TODO_CLASS (trusted planner.ts deleteTodo). Personal todo (base\n      // ToDo) dùng TODO_CLASS — distinguish qua attachedToClass + attachedTo.\n      const isIssueTodo =\n        t.attachedToClass === ISSUE_CLASS && t.attachedTo != null && t.attachedTo !== \"\";\n      const delResult = await safeRemoveDoc(\n        tctx.client,\n        isIssueTodo ? PROJECT_TODO_CLASS : TODO_CLASS,\n        t,\n      );\n      if (!delResult.ok) return delResult.error;\n      // Decrement parent Issue.todo counter (CollectionSize) — tránh drift.\n      if (isIssueTodo && t.attachedTo) {\n        const issueSpace = (t.attachedSpace ?? t.space) as never;\n        await tctx.client.updateDoc(\n          ISSUE_CLASS,\n          issueSpace,\n          t.attachedTo as never,\n          { $inc: { todos: -1 } } as never,\n        );\n      }\n      return {\n        content: `Deleted todo ${params.todo}.`,\n        details: { deleted: true, todo: params.todo },\n      };\n    },\n  }),\n];\n","// tools/register.ts — Register all domain modules với pi.\n// Design: 04-system.md §6 (register.ts), 06-api.md §4 (catalog).\n//\n// T-30: collect tools từ 21 domain files (19 domain theo spec FR-04, Issues\n// chia 3 files + Documents tách snapshots = 21 files) + registerTool each.\n// Total: 102 tools (FR-02).\n\nimport type { ExtensionAPI } from \"@earendil-works/pi-coding-agent\";\nimport type { HulyToolDefinition } from \"./builder.js\";\n\n// Import 19 domain modules\nimport { tools as workspaceTools } from \"./domains/workspace.js\";\nimport { tools as projectTools } from \"./domains/projects.js\";\nimport { tools as milestoneTools } from \"./domains/milestones.js\";\nimport { tools as taskMgmtTools } from \"./domains/task-management.js\";\nimport { tools as componentTools } from \"./domains/components.js\";\nimport { tools as spaceTools } from \"./domains/spaces.js\";\nimport { tools as snapshotTools } from \"./domains/document-snapshots.js\";\nimport { tools as labelTools } from \"./domains/labels.js\";\nimport { tools as tagTools } from \"./domains/tags.js\";\nimport { tools as tagCategoryTools } from \"./domains/tag-categories.js\";\nimport { tools as commentTools } from \"./domains/comments.js\";\nimport { tools as searchTools } from \"./domains/search.js\";\nimport { tools as deletionTools } from \"./domains/deletion.js\";\nimport { tools as timeTools } from \"./domains/time.js\";\nimport { tools as contactTools } from \"./domains/contacts.js\";\nimport { tools as documentTools } from \"./domains/documents.js\";\nimport { tools as issueCoreTools } from \"./domains/issues-core.js\";\nimport { tools as issueRelationTools } from \"./domains/issues-relations.js\";\nimport { tools as issueTemplateTools } from \"./domains/issues-templates.js\";\nimport { tools as attachmentTools } from \"./domains/attachments.js\";\nimport { tools as todoTools } from \"./domains/todos.js\";\n\n/**\n * All tools từ 19 domain modules. Collect 1 lần, register với pi.\n * Spec FR-02: ~102 tools prefix huly_.\n */\nexport const allTools: HulyToolDefinition[] = [\n  ...workspaceTools,\n  ...projectTools,\n  ...milestoneTools,\n  ...taskMgmtTools,\n  ...componentTools,\n  ...spaceTools,\n  ...snapshotTools,\n  ...labelTools,\n  ...tagTools,\n  ...tagCategoryTools,\n  ...commentTools,\n  ...searchTools,\n  ...deletionTools,\n  ...timeTools,\n  ...contactTools,\n  ...documentTools,\n  ...issueCoreTools,\n  ...issueRelationTools,\n  ...issueTemplateTools,\n  ...attachmentTools,\n  ...todoTools,\n];\n\n/**\n * Register all Huly tools với pi extension API.\n * Called từ index.ts factory (T-33).\n *\n * @param pi Pi ExtensionAPI\n * @param tools Override tool list (default: allTools). Cho phép factory attach\n *              render hooks qua shallow copy KHÔNG mutate module global.\n * @returns number of tools registered\n */\nexport function registerAllTools(pi: ExtensionAPI, tools: HulyToolDefinition[] = allTools): number {\n  let count = 0;\n  for (const tool of tools) {\n    // Cast HulyToolDefinition → pi ToolDefinition (compatible shape).\n    // pi.registerTool expects full ToolDefinition; HulyToolDefinition subset.\n    pi.registerTool(tool as never);\n    count++;\n  }\n  return count;\n}\n\n/** Count tools per domain (cho diagnostics). */\nexport function toolCountByDomain(): Record<string, number> {\n  return {\n    workspace: workspaceTools.length,\n    projects: projectTools.length,\n    milestones: milestoneTools.length,\n    \"task-management\": taskMgmtTools.length,\n    components: componentTools.length,\n    spaces: spaceTools.length,\n    snapshots: snapshotTools.length,\n    labels: labelTools.length,\n    tags: tagTools.length,\n    \"tag-categories\": tagCategoryTools.length,\n    comments: commentTools.length,\n    search: searchTools.length,\n    deletion: deletionTools.length,\n    time: timeTools.length,\n    contacts: contactTools.length,\n    documents: documentTools.length,\n    \"issues-core\": issueCoreTools.length,\n    \"issues-relations\": issueRelationTools.length,\n    \"issues-templates\": issueTemplateTools.length,\n    attachments: attachmentTools.length,\n    todos: todoTools.length,\n  };\n}\n","// commands/huly.ts — unified `/huly` command (git-like subcommands).\n// Design: 04-system.md §6 commands/huly.ts, 06-api.md §5 /huly command,\n// 01-vision §B.10 D10/D11, UC-01 (/huly init flow), UC-02 (link).\n//\n// Subcommands:\n//   /huly              smart: cwd bound → status; unbound → init flow\n//   /huly init         setup/bind cwd (UC-01): workspace → verify → project → bind\n//   /huly status       diagnostics: binding, pool.health, user, version\n//   /huly workspace list|add|remove   global workspace CRUD (credentials.ts)\n//   /huly link [ws] [project]         bind cwd manual\n//   /huly unlink                      remove cwd binding\n//\n// Architecture: tách pure logic (runHulyCommand) khỏi pi registration\n// (registerHulyCommand). runHulyCommand nhận CommandContext injectable →\n// testable KHÔNG cần mock toàn bộ ExtensionCommandContext. Output qua\n// ctx.ui.notify (TUI) + return string (non-TUI / log).\n\nimport type { ExtensionAPI, ExtensionCommandContext } from \"@earendil-works/pi-coding-agent\";\nimport {\n  addWorkspace,\n  findByName,\n  getWorkspace,\n  loadCredentials,\n  removeWorkspace,\n  type WorkspaceCreds,\n} from \"../config/credentials.js\";\nimport {\n  bindProject,\n  loadConfig,\n  resolveByCwd,\n  unbindProject,\n  type ProjectBinding,\n} from \"../config/config.js\";\nimport { getClient, health, closeAll } from \"../client/pool.js\";\nimport { createHulyClient } from \"../client/client.js\";\nimport { classRef, spaceRef } from \"../tools/domains/_class-refs.js\";\nimport { HULY_VERSION } from \"../version.js\";\n\n/**\n * UI surface mà command cần (subset của ExtensionUIContext — injectable test).\n * select/confirm/input return undefined khi user cancel hoặc non-TUI.\n */\nexport interface CommandUI {\n  /** Show selector → user choice (1 option). Undefined = cancel/non-TUI. */\n  select(title: string, options: string[]): Promise<string | undefined>;\n  /** Yes/no confirm. */\n  confirm(title: string, message: string): Promise<boolean>;\n  /** Free text input. Undefined = cancel/non-TUI. */\n  input(title: string, placeholder?: string): Promise<string | undefined>;\n  /** Show notification. */\n  notify(message: string, type?: \"info\" | \"warning\" | \"error\"): void;\n}\n\n/**\n * Context inject vào runHulyCommand (testability — thay vì ExtensionCommandContext\n * đầy đủ). Bao gồm UI + cwd + paths override (test inject temp).\n */\nexport interface CommandContext {\n  /** UI surface (TUI/RPC). */\n  ui: CommandUI;\n  /** Whether dialog-capable UI available. false → commands non-interactive. */\n  hasUI: boolean;\n  /** Current working directory. */\n  cwd: string;\n  /** Override credentials path (test). */\n  credentialsPath?: string;\n  /** Override config path (test). */\n  configPath?: string;\n}\n\n/** Parse subcommand + positional args từ raw command arg string. */\nexport interface ParsedArgs {\n  /** Subcommand keyword (init/status/workspace/link/unlink). Undefined = no-arg. */\n  subcommand: string | undefined;\n  /** Positional args sau subcommand. */\n  positional: string[];\n}\n\n/**\n * Parse raw arg string → subcommand + positional.\n *   \"\"              → { subcommand: undefined, positional: [] }\n *   \"init\"          → { subcommand: \"init\", positional: [] }\n *   \"workspace add\" → { subcommand: \"workspace\", positional: [\"add\"] }\n *   \"link ws-x PD\"  → { subcommand: \"link\", positional: [\"ws-x\", \"PD\"] }\n *   \"  status  \"    → { subcommand: \"status\", positional: [] } (trim)\n */\nexport function parseArgs(raw: string): ParsedArgs {\n  const tokens = raw\n    .trim()\n    .split(/\\s+/)\n    .filter((t) => t.length > 0);\n  if (tokens.length === 0) {\n    return { subcommand: undefined, positional: [] };\n  }\n  const [subcommand, ...positional] = tokens;\n  return { subcommand, positional };\n}\n\n/** Result trả về từ runHulyCommand (cho non-TUI log + test assert). */\nexport interface CommandResult {\n  /** Human-readable output line(s). */\n  message: string;\n  /** Notification type (info/warning/error). */\n  type: \"info\" | \"warning\" | \"error\";\n}\n\n/**\n * Run unified /huly command. Dispatch theo subcommand.\n *\n * Non-TUI (hasUI=false): commands không thể prompt → trả error message hướng\n * dẫn dùng subcommand explicit (vd `/huly link <ws> <project>` thay vì init\n * interactive). NFR-10 fail-safe — KHÔNG bypass confirmation.\n *\n * @returns CommandResult (message + type) cho caller notify/log\n */\nexport async function runHulyCommand(rawArgs: string, ctx: CommandContext): Promise<CommandResult> {\n  const { subcommand, positional } = parseArgs(rawArgs);\n\n  switch (subcommand) {\n    case undefined:\n      return runSmart(ctx);\n    case \"init\":\n      return runInit(ctx);\n    case \"status\":\n      return runStatus(ctx);\n    case \"workspace\":\n      return runWorkspace(positional, ctx);\n    case \"link\":\n      return runLink(positional, ctx);\n    case \"unlink\":\n      return runUnlink(ctx);\n    default:\n      return {\n        message: `Unknown subcommand \"${subcommand}\". Available: init, status, workspace, link, unlink.`,\n        type: \"error\",\n      };\n  }\n}\n\n// === Smart (no-arg) ===\n\n/** `/huly` no-arg: cwd bound → status; unbound → init flow (TUI only). */\nasync function runSmart(ctx: CommandContext): Promise<CommandResult> {\n  const binding = await safeResolveByCwd(ctx);\n  if (binding !== undefined) {\n    return runStatus(ctx);\n  }\n  // Unbound: init flow yêu cầu interactive UI. Non-TUI → hint link manual\n  // (tránh contradictory messages: notify \"starting init\" rồi init error \"requires UI\").\n  if (ctx.hasUI !== true) {\n    return {\n      message:\n        \"No Huly binding for this directory. Use `/huly link <workspace> <project>` to bind (non-interactive mode).\",\n      type: \"warning\",\n    };\n  }\n  ctx.ui.notify(\"No Huly binding for this directory. Starting /huly init…\", \"info\");\n  return runInit(ctx);\n}\n\n// === /huly init (UC-01) ===\n\n/**\n * `/huly init` — bind cwd → {workspace, project} (UC-01).\n * Flow:\n *   1. prompt workspace name\n *   2. findByName(name): 0 → add (prompt url + auth); 1 → reuse; N → disambiguate\n *   3. verify token (getClient → getCurrentUser)\n *   4. list_projects → pick HOẶC create new\n *   5. bindProject(cwd, {workspace, project})\n *\n * Non-TUI → KHÔNG interactive → error hướng dẫn `/huly link <ws> <project>`.\n * User cancel bất kỳ bước → abort (no bind).\n */\nasync function runInit(ctx: CommandContext): Promise<CommandResult> {\n  if (ctx.hasUI !== true) {\n    return {\n      message:\n        \"/huly init requires interactive UI. Use `/huly link <workspace> <project>` to bind non-interactively.\",\n      type: \"error\",\n    };\n  }\n\n  // 1. Prompt workspace name\n  const name = await ctx.ui.input(\"Huly workspace name:\");\n  if (name === undefined || name.length === 0) {\n    return { message: \"Init cancelled.\", type: \"info\" };\n  }\n\n  // 2. findByName → resolve workspace id-handle\n  let workspaceId: string;\n  try {\n    const matches = await findByName(name, ctx.credentialsPath);\n    if (matches.length === 0) {\n      // Add new workspace entry\n      const added = await promptAddWorkspace(name, ctx);\n      if (added === undefined) {\n        return { message: \"Init cancelled.\", type: \"info\" };\n      }\n      workspaceId = added;\n    } else if (matches.length === 1) {\n      workspaceId = matches[0].id;\n      ctx.ui.notify(`Reusing workspace \"${workspaceId}\".`, \"info\");\n    } else {\n      // Disambiguate (same-name diff-URL). Index lookup thay vì split string\n      // (tránh truncate sai nếu id/url chứa \" (\").\n      const opts = matches.map((m) => `${m.id} (${m.url})`);\n      const chosen = await ctx.ui.select(`Workspace \"${name}\" is ambiguous. Pick:`, opts);\n      if (chosen === undefined) {\n        return { message: \"Init cancelled.\", type: \"info\" };\n      }\n      const idx = opts.indexOf(chosen);\n      if (idx < 0 || matches[idx] === undefined) {\n        return { message: \"Init cancelled (invalid selection).\", type: \"info\" };\n      }\n      workspaceId = matches[idx]!.id;\n    }\n  } catch (e) {\n    return { message: `Init failed: ${errorMessage(e)}`, type: \"error\" };\n  }\n\n  // 3. Verify token (getClient → getCurrentUser). KHÔNG swallow — surface rõ.\n  let user: { name: string; email: string };\n  try {\n    const client = await getClient(workspaceId);\n    const u = await client.getCurrentUser();\n    user = { name: u.name, email: u.email };\n  } catch (e) {\n    return {\n      message: `Auth/connection failed for workspace \"${workspaceId}\": ${errorMessage(\n        e,\n      )}. Check URL/credentials (/huly workspace remove ${workspaceId} + add lại).`,\n      type: \"error\",\n    };\n  }\n\n  // 4. Project: list → pick HOẶC create\n  let project: string;\n  try {\n    project = await promptProject(workspaceId, ctx);\n    if (project.length === 0) {\n      return { message: \"Init cancelled (no project).\", type: \"info\" };\n    }\n  } catch (e) {\n    return { message: `Project setup failed: ${errorMessage(e)}`, type: \"error\" };\n  }\n\n  // 5. Bind cwd\n  try {\n    await bindProject(ctx.cwd, { workspace: workspaceId, project }, ctx.configPath);\n  } catch (e) {\n    return { message: `Bind failed: ${errorMessage(e)}`, type: \"error\" };\n  }\n\n  return {\n    message: `Bound ${ctx.cwd} → workspace \"${workspaceId}\", project \"${project}\" (user: ${user.name} <${user.email}>).`,\n    type: \"info\",\n  };\n}\n\n/**\n * Prompt url + auth method → addWorkspace. Trả id-handle HOẶC undefined (cancel).\n */\nasync function promptAddWorkspace(name: string, ctx: CommandContext): Promise<string | undefined> {\n  const url = await ctx.ui.input(\"Huly URL (vd https://huly.example.com):\");\n  if (url === undefined || url.length === 0) return undefined;\n\n  const method = await ctx.ui.select(\"Auth method:\", [\"Token\", \"Email + password\"]);\n  if (method === undefined) return undefined;\n\n  let entry: WorkspaceCreds;\n  if (method === \"Token\") {\n    const token = await ctx.ui.input(\"Token:\");\n    if (token === undefined || token.length === 0) return undefined;\n    entry = { url, workspace: name, token };\n  } else {\n    const email = await ctx.ui.input(\"Email:\");\n    if (email === undefined || email.length === 0) return undefined;\n    const password = await ctx.ui.input(\"Password:\");\n    if (password === undefined || password.length === 0) return undefined;\n    entry = { url, workspace: name, email, password };\n  }\n\n  // id-handle: dùng name (stable). Nếu trùng id → suffix -2, -3...\n  const baseId = await uniqueWorkspaceId(name, ctx);\n  await addWorkspace(baseId, entry, ctx.credentialsPath);\n  return baseId;\n}\n\n/** Tạo id-handle unik dựa trên name (suffix -2, -3 nếu trùng). */\nasync function uniqueWorkspaceId(name: string, ctx: CommandContext): Promise<string> {\n  const creds = await loadCredentials(ctx.credentialsPath);\n  if (!(name in creds.workspaces)) return name;\n  let i = 2;\n  while (`${name}-${i}` in creds.workspaces) i++;\n  return `${name}-${i}`;\n}\n\n/**\n * List projects → pick existing HOẶC create new.\n * Trả project identifier HOẶC \"\" (cancel).\n */\nasync function promptProject(workspaceId: string, ctx: CommandContext): Promise<string> {\n  const client = await getClient(workspaceId);\n  // Reuse PROJECT_CLASS via classRef (single source với domain modules).\n  // Pattern space=workspaceId-handle nhất quán với domains/projects.ts create_project.\n  const PROJECT_CLASS = classRef(\"tracker:class:Project\");\n  const projects = await client.findAll(PROJECT_CLASS, {}, {});\n  const items = projects.map((p) => ({\n    identifier: (p as { identifier?: string }).identifier ?? \"\",\n    name: (p as { name?: string }).name ?? \"\",\n  }));\n\n  const opts = [\"+ Create new project\", ...items.map((p) => `${p.identifier} — ${p.name}`)];\n  const chosen = await ctx.ui.select(\"Pick project:\", opts);\n  if (chosen === undefined) return \"\";\n\n  if (chosen === \"+ Create new project\") {\n    const name = await ctx.ui.input(\"Project name:\");\n    if (name === undefined || name.length === 0) return \"\";\n    // Validate identifier: 1-5 chars, uppercase letter start (Huly convention).\n    let identifier = await ctx.ui.input(\"Project identifier (1-5 uppercase):\");\n    if (identifier === undefined) return \"\";\n    identifier = identifier.trim().toUpperCase();\n    if (!/^[A-Z][A-Z0-9]{0,4}$/.test(identifier)) {\n      ctx.ui.notify(\n        `Invalid identifier \"${identifier}\": must be 1-5 chars, start with uppercase letter.`,\n        \"error\",\n      );\n      return \"\";\n    }\n    await client.createDoc(PROJECT_CLASS, spaceRef(workspaceId), { name, identifier });\n    return identifier;\n  }\n\n  // Pick existing: index lookup thay vì split string (tránh truncate nếu name chứa \" —\").\n  const idx = opts.indexOf(chosen) - 1; // -1 vì opts[0] = \"+ Create new\"\n  if (idx < 0 || items[idx] === undefined) return \"\";\n  return items[idx]!.identifier;\n}\n\n// === /huly status ===\n\n/**\n * `/huly status` — diagnostics.\n * Output: version, cwd binding (workspace+project), pool health, current user.\n * KHÔNG throw — catch hết, surface dạng warning/error.\n */\nasync function runStatus(ctx: CommandContext): Promise<CommandResult> {\n  const lines: string[] = [`pi-huly v${HULY_VERSION}`, `cwd: ${ctx.cwd}`];\n\n  // Binding\n  const binding = await safeResolveByCwd(ctx);\n  if (binding !== undefined) {\n    lines.push(`binding: workspace \"${binding.workspace}\" · project \"${binding.project}\"`);\n  } else {\n    lines.push(\"binding: (none — run /huly init)\");\n  }\n\n  // Config transport\n  try {\n    const config = await loadConfig(ctx.configPath);\n    lines.push(`transport: ${config.transport ?? \"ws\"}`);\n  } catch (e) {\n    lines.push(`transport: error reading config — ${errorMessage(e)}`);\n  }\n\n  // Credentials count\n  try {\n    const creds = await loadCredentials(ctx.credentialsPath);\n    lines.push(`workspaces: ${Object.keys(creds.workspaces).length} configured`);\n  } catch (e) {\n    lines.push(`workspaces: error reading credentials — ${errorMessage(e)}`);\n  }\n\n  // Pool health (only if binding exists → check specific workspace)\n  try {\n    const target = binding?.workspace;\n    const statuses = await health(target);\n    if (statuses.length === 0) {\n      lines.push(\"pool: (no active connections)\");\n    } else {\n      // T-62 #67: total noise cross entry (module-level counter) — show 1 lần.\n      let noiseTotal = 0;\n      let noiseByPattern: Record<string, number> = {};\n      for (const s of statuses) {\n        const userStr = s.user ? `${s.user.name} <${s.user.email}>` : \"(user unknown)\";\n        lines.push(\n          `pool[${s.workspace}]: ${s.connected ? \"connected\" : \"disconnected\"} (${s.transport}) · ${userStr}`,\n        );\n        if (s.upstreamNoiseFiltered !== undefined) {\n          noiseTotal = Math.max(noiseTotal, s.upstreamNoiseFiltered.total);\n          noiseByPattern = s.upstreamNoiseFiltered.byPattern;\n        }\n      }\n      if (noiseTotal > 0) {\n        // Per-pattern breakdown giúp user phân biệt nguồn noise (vd #67 model-tx\n        // vs T-64 WS error). Sort desc theo count, format \"key: N\" top 3.\n        const sorted = Object.entries(noiseByPattern)\n          .sort((a, b) => b[1] - a[1])\n          .slice(0, 3)\n          .map(([pattern, count]) => `${pattern}: ${count}`)\n          .join(\", \");\n        lines.push(\n          `pool noise: ${noiseTotal} upstream log filtered${sorted ? ` (${sorted})` : \"\"}`,\n        );\n      }\n    }\n  } catch (e) {\n    lines.push(`pool: health check failed — ${errorMessage(e)}`);\n  }\n\n  return { message: lines.join(\"\\n\"), type: \"info\" };\n}\n\n// === /huly workspace list|add|remove ===\n\nasync function runWorkspace(positional: string[], ctx: CommandContext): Promise<CommandResult> {\n  const action = positional[0];\n  switch (action) {\n    case \"list\":\n      return runWorkspaceList(ctx);\n    case \"add\":\n      return runWorkspaceAdd(ctx);\n    case \"remove\":\n      return runWorkspaceRemove(positional[1], ctx);\n    default:\n      return {\n        message: \"Usage: /huly workspace list|add|remove\",\n        type: \"error\",\n      };\n  }\n}\n\n/** `/huly workspace list` — list configured workspaces (id + url + workspace name). */\nasync function runWorkspaceList(ctx: CommandContext): Promise<CommandResult> {\n  try {\n    const creds = await loadCredentials(ctx.credentialsPath);\n    const ids = Object.keys(creds.workspaces);\n    if (ids.length === 0) {\n      return {\n        message: \"No workspaces configured. Run /huly init or /huly workspace add.\",\n        type: \"info\",\n      };\n    }\n    const lines = ids.map((id) => {\n      const w = creds.workspaces[id]!;\n      const auth = \"token\" in w ? \"token\" : \"email+pass\";\n      return `${id} → ${w.url} · workspace=\"${w.workspace}\" · auth=${auth}`;\n    });\n    return { message: `Workspaces (${ids.length}):\\n${lines.join(\"\\n\")}`, type: \"info\" };\n  } catch (e) {\n    return { message: `Failed to list workspaces: ${errorMessage(e)}`, type: \"error\" };\n  }\n}\n\n/** `/huly workspace add` — interactive add (TUI only). */\nasync function runWorkspaceAdd(ctx: CommandContext): Promise<CommandResult> {\n  if (ctx.hasUI !== true) {\n    return {\n      message: \"/huly workspace add requires interactive UI. Edit credentials.json manually.\",\n      type: \"error\",\n    };\n  }\n  const name = await ctx.ui.input(\"Workspace name (Huly workspace):\");\n  if (name === undefined || name.length === 0) return { message: \"Cancelled.\", type: \"info\" };\n  const id = await promptAddWorkspace(name, ctx);\n  if (id === undefined) return { message: \"Cancelled.\", type: \"info\" };\n  return { message: `Added workspace \"${id}\".`, type: \"info\" };\n}\n\n/** `/huly workspace remove <id>` — remove by id-handle. */\nasync function runWorkspaceRemove(\n  id: string | undefined,\n  ctx: CommandContext,\n): Promise<CommandResult> {\n  if (id === undefined || id.length === 0) {\n    return { message: \"Usage: /huly workspace remove <id>\", type: \"error\" };\n  }\n  try {\n    const existing = await getWorkspace(id, ctx.credentialsPath);\n    if (existing === undefined) {\n      return { message: `Workspace \"${id}\" not found.`, type: \"warning\" };\n    }\n    await removeWorkspace(id, ctx.credentialsPath);\n    return { message: `Removed workspace \"${id}\".`, type: \"info\" };\n  } catch (e) {\n    return { message: `Failed to remove workspace: ${errorMessage(e)}`, type: \"error\" };\n  }\n}\n\n// === /huly link [ws] [project] ===\n\n/**\n * `/huly link [workspace] [project]` — bind cwd manual (non-interactive OK).\n *   /huly link              → TUI: prompt ws + project\n *   /huly link ws PD        → bind trực tiếp (verify workspace tồn tại)\n * Validate workspace có trong credentials trước khi bind (fail-fast).\n */\nasync function runLink(positional: string[], ctx: CommandContext): Promise<CommandResult> {\n  let workspace: string | undefined = positional[0];\n  let project: string | undefined = positional[1];\n\n  // Interactive fill nếu thiếu (TUI only)\n  if ((workspace === undefined || project === undefined) && ctx.hasUI === true) {\n    if (workspace === undefined) {\n      workspace = (await ctx.ui.input(\"Workspace id:\")) ?? undefined;\n    }\n    if (project === undefined && workspace !== undefined && workspace.length > 0) {\n      project = (await ctx.ui.input(\"Project identifier:\")) ?? undefined;\n    }\n  }\n\n  if (workspace === undefined || workspace.length === 0) {\n    return { message: \"Usage: /huly link <workspace> <project>\", type: \"error\" };\n  }\n  if (project === undefined || project.length === 0) {\n    return { message: \"Usage: /huly link <workspace> <project>\", type: \"error\" };\n  }\n\n  // Validate workspace tồn tại trong credentials\n  try {\n    const existing = await getWorkspace(workspace, ctx.credentialsPath);\n    if (existing === undefined) {\n      return {\n        message: `Workspace \"${workspace}\" not found in credentials. Run /huly workspace add first.`,\n        type: \"error\",\n      };\n    }\n  } catch (e) {\n    return { message: `Failed to validate workspace: ${errorMessage(e)}`, type: \"error\" };\n  }\n\n  try {\n    await bindProject(ctx.cwd, { workspace, project }, ctx.configPath);\n  } catch (e) {\n    return { message: `Bind failed: ${errorMessage(e)}`, type: \"error\" };\n  }\n  return {\n    message: `Bound ${ctx.cwd} → workspace \"${workspace}\", project \"${project}\".`,\n    type: \"info\",\n  };\n}\n\n// === /huly unlink ===\n\n/** `/huly unlink` — remove cwd binding. No-op nếu chưa bound. */\nasync function runUnlink(ctx: CommandContext): Promise<CommandResult> {\n  try {\n    const binding = await safeResolveByCwd(ctx);\n    if (binding === undefined) {\n      return { message: `${ctx.cwd} has no Huly binding.`, type: \"info\" };\n    }\n    await unbindProject(ctx.cwd, ctx.configPath);\n    return { message: `Unbound ${ctx.cwd}.`, type: \"info\" };\n  } catch (e) {\n    return { message: `Unbind failed: ${errorMessage(e)}`, type: \"error\" };\n  }\n}\n\n// === Helpers ===\n\n/** resolveByCwd wrap — KHÔNG throw (tránh crash command khi config corrupt). */\nasync function safeResolveByCwd(ctx: CommandContext): Promise<ProjectBinding | undefined> {\n  try {\n    return await resolveByCwd(ctx.cwd, ctx.configPath);\n  } catch {\n    return undefined;\n  }\n}\n\n/** Extract message từ unknown error (KHÔNG leak stack). */\nfunction errorMessage(e: unknown): string {\n  if (e instanceof Error) return e.message;\n  return String(e);\n}\n\n// === Pi registration ===\n\n/**\n * Map CommandUI methods sang ExtensionCommandContext. select/confirm/input\n * trả undefined khi non-TUI (pi đã handle internally).\n */\nfunction adaptUI(ctx: ExtensionCommandContext): CommandUI {\n  return {\n    select: (title, options) => ctx.ui.select(title, options),\n    confirm: (title, message) => ctx.ui.confirm(title, message),\n    input: (title, placeholder) => ctx.ui.input(title, placeholder),\n    notify: (message, type) => ctx.ui.notify(message, type),\n  };\n}\n\n/**\n * Register unified `/huly` command với pi.\n * 1 registration, dispatch subcommand trong handler.\n *\n * @param pi Pi ExtensionAPI\n */\nexport function registerHulyCommand(pi: ExtensionAPI): void {\n  pi.registerCommand(\"huly\", {\n    description: \"Huly workspace/project management (init, status, workspace, link, unlink).\",\n    async handler(args, ctx) {\n      const cmdCtx: CommandContext = {\n        ui: adaptUI(ctx),\n        hasUI: ctx.hasUI,\n        cwd: ctx.cwd,\n      };\n      const result = await runHulyCommand(args, cmdCtx);\n      ctx.ui.notify(result.message, result.type);\n    },\n  });\n}\n\n// Re-export closeAll cho index.ts factory (session_shutdown cleanup).\nexport { closeAll };\n// Re-export createHulyClient cho potential direct use (test/verify).\nexport { createHulyClient };\n","// render/util.ts — shared helpers cho render/issue.ts + render/document.ts.\n// Tách ra để tránh duplicate fmtDate/getOrCreateText/joinLines/opt giữa 2 file\n// (code-review-mentor #3). Cũng chứa ANSI sanitize (#5 security).\n\nimport { Text } from \"@earendil-works/pi-tui\";\nimport type { Component } from \"@earendil-works/pi-tui\";\n\n/**\n * Minimal theme surface mà render dùng. Pi Theme runtime CHỈ có fg/bg/bold/...,\n * KHÔNG có method dim/muted — \"dim\"/\"muted\" là ThemeColor enum values, gọi qua\n * theme.fg(\"dim\", text) (code-review-mentor #1).\n */\nexport interface RenderTheme {\n  fg(color: string, text: string): string;\n  bg?(color: string, text: string): string;\n  bold(text: string): string;\n  italic?(text: string): string;\n}\n\n/**\n * Minimal render context (ToolRenderContext của pi KHÔNG re-export public).\n * Structurally compatible subset — chỉ cần lastComponent để reuse Text component.\n */\nexport interface RenderContext {\n  /** Previously returned component for this render slot, if any (reuse để avoid flicker). */\n  lastComponent?: Component;\n}\n\n/** Get-or-create Text component (reuse lastComponent nếu là Text, else create new). */\nexport function getOrCreateText(ctx: RenderContext): Text {\n  return ctx.lastComponent instanceof Text ? ctx.lastComponent : new Text(\"\", 0, 0);\n}\n\n/** Format timestamp (Unix ms) → YYYY-MM-DD; invalid/undefined → \"\". */\nexport function fmtDate(ms: number | undefined, theme: RenderTheme): string {\n  if (ms === undefined || ms === null) return \"\";\n  const d = new Date(ms);\n  if (Number.isNaN(d.getTime())) return \"\";\n  return theme.fg(\"warning\", d.toISOString().slice(0, 10));\n}\n\n/** Join non-empty lines (skip empty/undefined entries). */\nexport function joinLines(lines: string[]): string {\n  return lines.filter((l) => l.length > 0).join(\"\\n\");\n}\n\n/** Optional labeled row: skip nếu value undefined/empty; else \"Label: value\". */\nexport function opt(label: string, value: string | undefined, theme: RenderTheme): string {\n  if (value === undefined || value === null || value.length === 0) return \"\";\n  return `${theme.bold(label)}: ${value}`;\n}\n\n/**\n * Strip ANSI escape sequences từ string sourced từ Huly server (code-review-mentor #5).\n * Huly title/description/content/status/assignee có thể chứa escape sequences thật\n * (user input HOẶC markup legacy) → nếu render raw, terminal bị corrupt (hidden\n * cursor, changed title, cleared screen, màu sai).\n *\n * Strip CSI (Control Sequence Introducer) + OSC (Operating System Command) + ESC.\n * Whitelist-ish: giữ printable ASCII + tab + newline.\n */\nexport function sanitize(str: string): string {\n  if (typeof str !== \"string\") return \"\";\n  // Strip ANSI escape sequences từ server-sourced strings (terminal injection防御).\n  // Mọi regex match control chars (U+001B/U+0007/...) — intentional, KHÔNG bug.\n  // eslint-disable-next-line no-control-regex -- CSI escape sequence (intentional strip)\n  const noCsi = str.replace(/\\u001b\\[[0-9;?]*[A-Za-z]/g, \"\");\n  // eslint-disable-next-line no-control-regex -- OSC escape sequence (intentional strip)\n  const noOsc = noCsi.replace(/\\u001b\\][^\\u0007\\u001b]*(?:\\u0007|\\u001b\\\\)/g, \"\");\n  // eslint-disable-next-line no-control-regex -- keypad mode escape (intentional strip)\n  const noKeypad = noOsc.replace(/\\u001b[=>]/g, \"\");\n  // eslint-disable-next-line no-control-regex -- control chars except \\t \\n \\r (intentional strip)\n  return noKeypad.replace(/[\\u0000-\\u0008\\u000b\\u000c\\u000e-\\u001f\\u007f]/g, \"\");\n}\n","// render/issue.ts — TUI render cho huly_get_issue (card) + huly_list_issues (table).\n// Design: 04-system.md §6 render/issue.ts, 06-api.md §3 render hooks (D12).\n//\n// Render functions theo pi signature: (result, options, theme, context) => Component.\n// Strategy: pure format function (formatIssueCard/formatIssueList) dùng theme.fg()\n// colorize → wrap vào Text component (reuse context.lastComponent khi có).\n//\n// Pure function testable KHÔNG cần pi types (chỉ cần theme stub có fg/bg/bold).\n// Shared helpers + RenderTheme/RenderContext ở render/util.ts.\n\nimport type { Component } from \"@earendil-works/pi-tui\";\nimport type { AgentToolResult, ToolRenderResultOptions } from \"@earendil-works/pi-coding-agent\";\nimport {\n  fmtDate,\n  getOrCreateText,\n  joinLines,\n  opt,\n  sanitize,\n  type RenderContext,\n  type RenderTheme,\n} from \"./util.js\";\n\n/** Issue shape từ huly_get_issue details (xem domains/issues-core.ts get_issue). */\nexport interface IssueDetails {\n  identifier?: string;\n  title?: string;\n  description?: string;\n  status?: string;\n  priority?: string;\n  assignee?: string;\n  milestone?: string;\n  component?: string;\n  dueDate?: number;\n  estimation?: number;\n}\n\n/** IssueListItem shape từ huly_list_issues details. */\nexport interface IssueListItem {\n  identifier?: string;\n  title?: string;\n  status?: string;\n  priority?: string;\n  assignee?: string;\n}\n\n/** List details shape. */\nexport interface IssueListDetails {\n  count?: number;\n  issues?: IssueListItem[];\n}\n\n// Re-export shared types cho consumer single-import.\nexport type { RenderTheme, RenderContext } from \"./util.js\";\n\n/** Due line: skip nếu dueDate undefined HOẶC invalid (fmtDate trả \"\"). */\nfunction dueLine(ms: number | undefined, t: RenderTheme): string {\n  if (ms === undefined || ms === null) return \"\";\n  const d = fmtDate(ms, t);\n  return d.length > 0 ? `Due: ${d}` : \"\";\n}\n\n/**\n * Format issue card (single issue). Pure function — testable.\n * Layout:\n *   PD-123: Title (bold)\n *   Status: X · Priority: Y · Assignee: Z\n *   Milestone: M · Component: C · Due: 2026-01-01\n *   ─── Description ─── (dim)\n *   <description preview>\n *\n * Mọi string từ server qua sanitize() (code-review-mentor #5 ANSI injection).\n */\nexport function formatIssueCard(details: IssueDetails, theme: RenderTheme): string {\n  const id = sanitize(details.identifier ?? \"?\");\n  const title = sanitize(details.title ?? \"(no title)\");\n  const header = `${theme.fg(\"accent\", id)}: ${theme.bold(title)}`;\n\n  const meta1 = joinLines([\n    opt(\n      \"Status\",\n      details.status ? theme.fg(\"success\", sanitize(details.status)) : undefined,\n      theme,\n    ),\n    opt(\"Priority\", details.priority !== undefined ? sanitize(details.priority) : undefined, theme),\n    opt(\"Assignee\", details.assignee !== undefined ? sanitize(details.assignee) : undefined, theme),\n  ]).replace(/\\n/g, \" · \");\n\n  const meta2 = joinLines([\n    opt(\n      \"Milestone\",\n      details.milestone !== undefined ? sanitize(details.milestone) : undefined,\n      theme,\n    ),\n    opt(\n      \"Component\",\n      details.component !== undefined ? sanitize(details.component) : undefined,\n      theme,\n    ),\n    dueLine(details.dueDate, theme),\n    details.estimation !== undefined ? `Estimation: ${details.estimation}m` : \"\",\n  ]).replace(/\\n/g, \" · \");\n\n  const lines = [header];\n  if (meta1.length > 0) lines.push(meta1);\n  if (meta2.length > 0) lines.push(meta2);\n\n  // Description preview (KHÔNG full — pi truncate tự). Giới hạn 8 dòng đầu.\n  if (details.description !== undefined && details.description.length > 0) {\n    const descLines = sanitize(details.description).split(\"\\n\").slice(0, 8);\n    lines.push(theme.fg(\"dim\", \"─── Description ───\"));\n    lines.push(...descLines);\n  }\n\n  return lines.join(\"\\n\");\n}\n\n/**\n * Format issue list (compact table). Pure function — testable.\n * Layout:\n *   N issue(s)\n *   PD-123  [Status]  Title                          @assignee\n *   PD-124  [Status]  Another title\n *\n * Empty list: theme.fg(\"muted\", \"No issues found (N total).\") — luôn include count\n * (code-review-mentor #2: trước đây dùng theme.muted method KHÔNG tồn tại runtime).\n */\nexport function formatIssueList(details: IssueListDetails, theme: RenderTheme): string {\n  const count = details.count ?? details.issues?.length ?? 0;\n  const issues = details.issues ?? [];\n  if (issues.length === 0) {\n    return theme.fg(\"muted\", `No issues found (${count} total).`);\n  }\n  const header = `${count} issue(s)`;\n  // Column widths: identifier (max 10), status (max 12), title (flex), assignee (suffix)\n  const idWidth = Math.max(8, ...issues.map((i) => sanitize(i.identifier ?? \"\").length));\n  const rows = issues.map((i) => {\n    const id = theme.fg(\"accent\", sanitize(i.identifier ?? \"?\").padEnd(idWidth));\n    const status = theme.fg(\"success\", `[${sanitize(i.status ?? \"?\")}]`.padEnd(12));\n    const title = sanitize(i.title ?? \"(no title)\");\n    const assignee = sanitize(i.assignee ?? \"\");\n    const assigneeSuffix = assignee.length > 0 ? ` ${theme.fg(\"dim\", `@${assignee}`)}` : \"\";\n    return `${id}  ${status}  ${title}${assigneeSuffix}`;\n  });\n  return [header, ...rows].join(\"\\n\");\n}\n\n/**\n * Render cho huly_get_issue (card layout).\n * Pi ToolDefinition.renderResult signature.\n */\nexport function renderIssueResult(\n  result: AgentToolResult<IssueDetails>,\n  _options: ToolRenderResultOptions,\n  theme: RenderTheme,\n  context: RenderContext,\n): Component {\n  const text = getOrCreateText(context);\n  text.setText(formatIssueCard(result.details, theme));\n  return text;\n}\n\n/**\n * Render cho huly_list_issues (compact table).\n * Pi ToolDefinition.renderResult signature.\n */\nexport function renderIssueListResult(\n  result: AgentToolResult<IssueListDetails>,\n  _options: ToolRenderResultOptions,\n  theme: RenderTheme,\n  context: RenderContext,\n): Component {\n  const text = getOrCreateText(context);\n  text.setText(formatIssueList(result.details, theme));\n  return text;\n}\n","// render/document.ts — TUI render cho huly_get_document (title + content preview).\n// Design: 04-system.md §6 render/document.ts, 06-api.md §3 render hooks (D12).\n//\n// renderDocumentResult theo pi signature: (result, options, theme, context) => Component.\n// Pure format function (formatDocumentPreview) dùng theme.fg() colorize.\n// Shared helpers + RenderTheme/RenderContext ở render/util.ts.\n//\n// Layout:\n//   Title (bold, mdHeading color)\n//   ─── Content (preview) ─── (dim)\n//   <content preview, 12 dòng đầu>\n//   modified: 2026-01-01 (dim)\n\nimport type { Component } from \"@earendil-works/pi-tui\";\nimport type { AgentToolResult, ToolRenderResultOptions } from \"@earendil-works/pi-coding-agent\";\nimport {\n  fmtDate,\n  getOrCreateText,\n  sanitize,\n  type RenderContext,\n  type RenderTheme,\n} from \"./util.js\";\n\n/** Document details shape từ huly_get_document (xem domains/documents.ts). */\nexport interface DocumentDetails {\n  id?: string;\n  title?: string;\n  content?: string;\n  modifiedOn?: number;\n}\n\n// Re-export cho consumer single-import.\nexport type { RenderTheme, RenderContext } from \"./util.js\";\n\n/**\n * Format document preview. Pure function — testable.\n * Layout:\n *   Title (mdHeading, bold)\n *   ─── Content (preview) ─── (dim)\n *   <content preview — 12 dòng đầu>\n *   modified: 2026-01-01 (dim, optional)\n *\n * Content preview giới hạn 12 dòng (pi tự truncate byte/line). Tránh dump full\n * document dài vào render (LLM đã nhận content đầy đủ qua tool result text).\n * Mọi string từ server qua sanitize() (code-review-mentor #5 ANSI injection).\n */\nexport function formatDocumentPreview(details: DocumentDetails, theme: RenderTheme): string {\n  const title = sanitize(details.title ?? \"(untitled document)\");\n  const lines: string[] = [`${theme.bold(theme.fg(\"mdHeading\", title))}`];\n\n  if (details.content !== undefined && details.content.length > 0) {\n    const contentLines = sanitize(details.content).split(\"\\n\").slice(0, 12);\n    lines.push(theme.fg(\"dim\", \"─── Content (preview) ───\"));\n    lines.push(...contentLines);\n  }\n\n  const modified = fmtDate(details.modifiedOn, theme);\n  if (modified.length > 0) {\n    lines.push(theme.fg(\"dim\", `modified: ${modified}`));\n  }\n\n  return lines.join(\"\\n\");\n}\n\n/**\n * Render cho huly_get_document (title + content preview).\n * Pi ToolDefinition.renderResult signature.\n */\nexport function renderDocumentResult(\n  result: AgentToolResult<DocumentDetails>,\n  _options: ToolRenderResultOptions,\n  theme: RenderTheme,\n  context: RenderContext,\n): Component {\n  const text = getOrCreateText(context);\n  text.setText(formatDocumentPreview(result.details, theme));\n  return text;\n}\n","// pi-huly extension entry — factory register tools + commands + lifecycle.\n// Design: 04-system.md §6 index.ts, 07-uc-04 (subagent shared pool), FR-12 (session_shutdown).\n//\n// Factory (T-33):\n//   1. registerAllTools(pi) — 102 tools từ 21 domain modules (register.ts)\n//   2. wire render hooks vào 3 high-value tools (huly_get_issue/list_issues/get_document)\n//   3. registerHulyCommand(pi) — unified /huly command (commands/huly.ts)\n//   4. pi.on(\"session_shutdown\") → pool.closeAll() — cleanup WS connections (FR-12)\n//   5. T-55: pi.on(\"session_start\") → warm pool (fire-and-forget) — fix first-call failure\n//   6. T-56: pi.on(\"tool_execution_start\") → log tool name + args (debug, stderr)\n//   7. Skills qua package manifest `pi.skills` (declarative, KHÔNG runtime register)\n//\n// R6 verification: type-only import force load pi types → typecheck catch TS 7\n// incompatibility với pi types sớm (design 03 §8 R6).\n\nimport type {\n  AgentToolResult,\n  ExtensionAPI,\n  ToolRenderResultOptions,\n} from \"@earendil-works/pi-coding-agent\";\nimport type { Component } from \"@earendil-works/pi-tui\";\n\nimport { HULY_VERSION } from \"./version.js\";\n// Re-export giữ backward-compat cho consumer import từ index.\nexport { HULY_VERSION };\n\nimport { allTools, registerAllTools } from \"./tools/register.js\";\nimport { registerHulyCommand } from \"./commands/huly.js\";\nimport { closeAll, getClient } from \"./client/pool.js\";\nimport { loadCredentials, type Credentials } from \"./config/credentials.js\";\nimport { sanitize } from \"./client/errors.js\";\nimport { renderIssueListResult, renderIssueResult } from \"./render/issue.js\";\nimport { renderDocumentResult } from \"./render/document.js\";\nimport {\n  DEFAULT_UPSTREAM_NOISE_PATTERNS,\n  installGlobalConsoleFilter,\n} from \"./client/console-filter.js\";\nimport { loadConfig, type Config } from \"./config/config.js\";\n\n/**\n * Render hook signature (pi ToolDefinition.renderResult subset).\n * ToolRenderContext KHÔNG re-export public từ pi → dùng context minimal.\n * Dùng AgentToolResult + ToolRenderResultOptions thật từ pi (type-safe hơn cast toàn bộ).\n */\ntype RenderHook = (\n  result: AgentToolResult<unknown>,\n  options: ToolRenderResultOptions,\n  theme: unknown,\n  context: { lastComponent?: Component },\n) => Component;\n\n/** Map tool name → render hook (3 high-value per design 04 §6 D12). */\nconst RENDER_HOOKS: Record<string, RenderHook> = {\n  huly_get_issue: renderIssueResult as unknown as RenderHook,\n  huly_list_issues: renderIssueListResult as unknown as RenderHook,\n  huly_get_document: renderDocumentResult as unknown as RenderHook,\n};\n\n/**\n * Build tool list với render hooks attached (shallow copy — KHÔNG mutate allTools\n * module-level global, tránh leak state giữa các consumer import allTools).\n * Tools KHÔNG trong RENDER_HOOKS → pi fallback default text render (~99 tool).\n */\nfunction buildToolsWithRender(): typeof allTools {\n  return allTools.map((tool) => {\n    const hook = RENDER_HOOKS[tool.name];\n    return hook !== undefined ? { ...tool, renderResult: hook } : tool;\n  });\n}\n\n/** Module-level guard: setup() chỉ chạy 1 lần (tránh dev-reload leak handler/command). */\nlet setupCalled = false;\n\n/** Test-only: reset setup guard (vitest isolation — tránh leak state giữa tests). */\nexport function __resetSetupGuardForTests(): void {\n  setupCalled = false;\n}\n\n/**\n * T-55 #59: Warm pool cho workspace đầu tiên trong credentials (fire-and-forget).\n * Fix first-call failure — WS chỉ kết nối khi tool đầu tiên gọi getClient (lazy),\n * gây delay/fail nếu credentials init chậm. Warm at session_start → connection\n * sẵn sàng trước khi LLM gọi tool đầu tiên.\n *\n * Bounds:\n * - KHÔNG block startup (fire-and-forget — không await trong caller).\n * - Skip khi credentials rỗng / NeedsInitError (no-op, không log lỗi).\n * - KHÔNG crash nếu warm fail (swallow — lazy retry ở lần gọi tool đầu tiên).\n * - Qua getClient(workspace) (KHÔNG bypass pool — D14 shared state nhất quán).\n */\nasync function warmPool(): Promise<void> {\n  try {\n    const creds: Credentials = await loadCredentials();\n    const ids = Object.keys(creds.workspaces);\n    if (ids.length === 0) return; // chưa init → no-op im lặng\n    // Warm workspace đầu tiên (default). Multi-workspace warm là overkill — lazy\n    // connect còn lại khi tool resolve workspace khác.\n    await getClient(ids[0]!);\n  } catch {\n    // Swallow — warm là best-effort. Lần gọi tool đầu tiên sẽ retry lazy connect\n    // như cũ (getClient throw → builder return error result rõ ràng cho LLM).\n  }\n}\n\n/**\n * T-55 #59: Reason hợp lệ để warm pool. Chỉ warm khi \"startup\" (session mới hoàn\n * toàn) hoặc \"resume\" (tiếp tục session trước — pool module-level đã clear khi\n * process exit). Skip \"reload\" (dev-reload pool vẫn còn) + \"new\"/\"fork\" (user\n * chủ động tạo session mới, có thể KHÔNG muốn connect ngay).\n */\nconst WARM_REASONS = new Set([\"startup\", \"resume\"]);\n\n/** Bound JSON length cho log tool args (T-56 #60) — tránh bloat stderr. */\nconst LOG_ARGS_CAP = 500;\n\n/**\n * T-64 #69: Resolve console filter pattern từ config cho global install.\n * - `quietUpstreamNoise === false` → null (escape hatch, KHÔNG filter)\n * - `upstreamNoisePatterns` override → compile user pattern (case-insensitive)\n * - Default → DEFAULT_UPSTREAM_NOISE_PATTERNS\n *\n * KHÔNG throw nếu pattern invalid (skip + fallback default).\n */\nfunction resolvePatternsFromConfig(config: Config): RegExp[] | null {\n  if (config.quietUpstreamNoise === false) return null;\n  if (config.upstreamNoisePatterns !== undefined && config.upstreamNoisePatterns.length > 0) {\n    const compiled: RegExp[] = [];\n    for (const src of config.upstreamNoisePatterns) {\n      try {\n        compiled.push(new RegExp(src, \"i\"));\n      } catch {\n        // Skip invalid — validateConfig đã catch khi load, runtime skip cho safety.\n      }\n    }\n    return compiled.length > 0 ? compiled : DEFAULT_UPSTREAM_NOISE_PATTERNS;\n  }\n  return DEFAULT_UPSTREAM_NOISE_PATTERNS;\n}\n\n/**\n * T-56 #60: Log tool call khi LLM gọi Huly tool (debug observability).\n * Subscribe tool_execution_start → log `[huly_<tool>] args: <json>` ra stderr.\n *\n * Bounds:\n * - Filter `toolName.startsWith(\"huly_\")` — skip built-in tool (bash, read, ...).\n * - Sanitize args qua `sanitize()` (strip LEAK_PATTERNS — token/secret) trước log.\n * - Truncate JSON > LOG_ARGS_CAP chars (500) + đuôi `... (truncated, N chars total)`.\n * - console.error (stderr) — pi TUI hiển thị nhưng JSON/print mode KHÔNG parse\n *   thành output → an toàn cho programmatic consumer.\n */\nfunction logToolCall(event: { toolName: string; args: unknown }): void {\n  if (!event.toolName.startsWith(\"huly_\")) return;\n  let json: string;\n  try {\n    json = JSON.stringify(event.args ?? {});\n  } catch {\n    json = \"<unserializable>\";\n  }\n  // Truncate TRƯỚC sanitize (code-review MINOR #1) — đảm bảo sanitize luôn chạy\n  // sau cùng, không có secret nào lọt qua vì slice cắt giữa (vd token có ký tự\n  // lạ KHÔNG match LEAK_PATTERNS → nếu sanitize trước truncate, phần raw token\n  // có thể nằm trong phần bị truncate khỏi log).\n  const capped =\n    json.length > LOG_ARGS_CAP\n      ? `${json.slice(0, LOG_ARGS_CAP)}... (truncated, ${json.length} chars total)`\n      : json;\n  console.error(`[${event.toolName}] args: ${sanitize(capped)}`);\n}\n\n/**\n * pi-huly extension factory — pi gọi default export khi load extension.\n *\n * Idempotent: lần 2+ là no-op (return 0) — tránh dev-reload leak\n * (đăng ký trùng session_shutdown handler + /huly command).\n *\n * @param pi Pi ExtensionAPI\n * @returns number of tools registered (0 nếu đã setup, debug aid)\n */\nexport default function setup(pi: ExtensionAPI): number {\n  // Guard: pi thực guard load 1 lần production, nhưng dev-reload có thể gọi lại.\n  // Tránh leak: 2x session_shutdown handler → closeAll() gọi 2 lần song song.\n  if (setupCalled) return 0;\n  setupCalled = true;\n\n  // 1. Build tools với render hooks (shallow copy, KHÔNG mutate module global)\n  const tools = buildToolsWithRender();\n\n  // 2. Register 102 tools (21 domain modules)\n  const toolCount = registerAllTools(pi, tools);\n\n  // 3. Register unified /huly command (init/status/workspace/link/unlink)\n  registerHulyCommand(pi);\n\n  // 3.5. T-64 #69: install global console filter ASAP (active toàn session).\n  // Cần thiết vì WS error (wsocket.onerror async callback) fires post-connect —\n  // runWithConsoleFilter trong createHulyClient chỉ cover connect-time, restore\n  // console.error trước khi WS error thật fire → token leak nếu KHÔNG global filter.\n  // Async vì resolveFilterPatterns đọc config ( KHÔNG block setup — fire-and-forget).\n  void (async () => {\n    try {\n      const config = await loadConfig();\n      if (config.quietUpstreamNoise === false) return; // escape hatch\n      const patterns = resolvePatternsFromConfig(config);\n      if (patterns !== null) installGlobalConsoleFilter(patterns);\n    } catch {\n      // Config error → install default patterns (best-effort, KHÔNG block setup).\n      installGlobalConsoleFilter(DEFAULT_UPSTREAM_NOISE_PATTERNS);\n    }\n  })();\n\n  // 4. session_shutdown hook → close all WS connections (FR-12, D14 pool cleanup).\n  // Pi AWAIT handler xong trước khi exit (contract ExtensionHandler async support).\n  // closeAll nên ngắn (WS close nhanh) — nếu block lâu, pi shutdown bị chậm.\n  pi.on(\"session_shutdown\", async () => {\n    try {\n      await closeAll();\n    } catch {\n      // Shutdown cleanup KHÔNG block exit — swallow để pi exit sạch\n      // (dù closeAll throw, handler resolve → pi tiếp tục shutdown).\n    }\n  });\n\n  // 5. T-55 #59: session_start → warm pool fire-and-forget (fix first-call failure).\n  // Chỉ warm khi reason ∈ {startup, resume} — skip reload/new/fork. Handler\n  // fire-and-forget (KHÔNG await trong subscribe — pi có thể xử lý sync, warm\n  // chạy nền). warmPool swallow mọi error (best-effort).\n  pi.on(\"session_start\", (event) => {\n    if (!WARM_REASONS.has(event.reason)) return;\n    void warmPool(); // fire-and-forget — KHÔNG await, KHÔNG crash setup\n  });\n\n  // 6. T-56 #60: tool_execution_start → log tool name + args (debug observability).\n  // Filter huly_ prefix, sanitize args (strip secret), truncate JSON > 500 chars.\n  // Log ra stderr (pi TUI hiển thị, JSON/print mode không parse → safe).\n  pi.on(\"tool_execution_start\", (event) => {\n    try {\n      logToolCall(event);\n    } catch {\n      // Logging KHÔNG block tool execution — swallow mọi error (vd args circular).\n    }\n  });\n\n  // 7. Skills qua package manifest `pi.skills` (declarative — pi auto-load, KHÔNG runtime)\n\n  return toolCount;\n}\n"],"mappings":"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"}