@hcmai/sdk 0.1.0 → 0.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.ts CHANGED
@@ -310,10 +310,20 @@ interface AttachmentMeta {
310
310
  }
311
311
  declare function guessMimeType(filePath: string): string;
312
312
  /**
313
- * 上传本地文件到 HCM 文档存储(web ChatInput 同端点同 storageCategory),
314
- * 返回 message.create 可直接携带的附件元数据。类型限制跟随服务端校验。
313
+ * 上传本地文件到 HCM 文档存储,返回可直接携带的附件元数据。
314
+ * 类型限制跟随服务端校验。
315
+ *
316
+ * @param storageCategory 存储分类。**必须是目标环境里真实存在的分类**——
317
+ * 它是服务端数据而非枚举,不同环境的分类表可以不同。
318
+ * 聊天附件传 {@link CHAT_ATTACHMENT_CATEGORY};报表模板一类传 `flex-report`。
319
+ *
320
+ * <p>🔴 此前这里硬编码 `'ai-conversation'`,于是 `hcm upload <任意文件>` 在
321
+ * 没有该分类的环境上**一律失败**,而错误被包成
322
+ * `BUSINESS_RULE_VIOLATION: Request failed with status code 404`——看不出真因是
323
+ * 「分类不存在」。2026-08-26 按交付技能跑弹性报表端到端时,Step 4「上传模板」
324
+ * 卡在这里;模板是报表的必需件,这条不通整条链就断了。
315
325
  */
316
- declare function uploadDocument(http: AxiosInstance, filePath: string): Promise<AttachmentMeta>;
326
+ declare function uploadDocument(http: AxiosInstance, filePath: string, storageCategory?: string): Promise<AttachmentMeta>;
317
327
  /** 默认产物落盘目录(对标 Claude Code 工具产物本地直接访问)。 */
318
328
  declare function defaultDownloadDir(): string;
319
329
  /**
@@ -1685,8 +1695,13 @@ declare function createHttpClient(opts: HttpClientOptions): AxiosInstance;
1685
1695
  * 必须先装技能才能建租户。所以本模块只需要 endpoint,不碰 identity/token。
1686
1696
  *
1687
1697
  * 后端契约(ChironController):
1688
- * - `GET /skills.json` 目录 manifest
1689
- * - `GET /skills/{id}.md` 技能原文
1698
+ * - `GET {base}/skills.json` 目录 manifest
1699
+ * - `GET {base}/skills/{id}.md` 技能原文
1700
+ * - `GET {base}/skills/{id}/references/{path}` 技能自带的参考文件
1701
+ *
1702
+ * 🔴 `{base}` 是 `'/api'` 或 `''`,由 {@link resolveChironBase} 探出来。真实部署只把
1703
+ * `/api/**` 路由给后端,根路径归前端 SPA——`GET /skills.json` 在客户环境上拿回来的是
1704
+ * 一段 HTML。而老版本后端只有根路径。两种都要能连上,所以先探再用,不写死。
1690
1705
  */
1691
1706
  interface ChironSkill {
1692
1707
  id: string;
@@ -1697,8 +1712,15 @@ interface ChironSkill {
1697
1712
  description: string;
1698
1713
  /** 交付生命周期阶段(多值)——一个技能天然跨阶段 */
1699
1714
  stages: string[];
1715
+ /** 安装本技能前必须同时安装的其他 Chiron 技能 id;旧服务端缺省时视为空。 */
1716
+ requires?: string[];
1700
1717
  bytes: number;
1701
1718
  markdownUrl: string;
1719
+ /**
1720
+ * 技能自带的参考文件相对路径(相对 `<skill>/references/`)。SKILL.md 正文用
1721
+ * `[x](references/x.md)` 引它们——不跟着装下来就是一堆死链。旧服务端缺省时视为空。
1722
+ */
1723
+ references?: string[];
1702
1724
  }
1703
1725
  interface ChironStage {
1704
1726
  key: string;
@@ -1721,9 +1743,51 @@ interface ChironManifest {
1721
1743
  stages: ChironStage[];
1722
1744
  categories: ChironCategory[];
1723
1745
  }
1724
- declare function fetchSkillCatalog(http: AxiosInstance): Promise<ChironManifest>;
1725
- declare function fetchSkillMarkdown(http: AxiosInstance, id: string): Promise<string>;
1746
+ /**
1747
+ * 探出本环境技能库的前缀。
1748
+ *
1749
+ * 为什么不能写死任何一个:
1750
+ * - 真实部署(反代把 `/api/**` 给后端、其余给前端)下根路径返回的是前端 SPA 的 HTML,
1751
+ * HTTP 200 但根本不是 manifest —— 所以判据必须看**内容**,不能看状态码;
1752
+ * - 还没升级到带 `/api` 别名那一版的后端,只有根路径可用。
1753
+ *
1754
+ * 两条都探不到时抛出可执行的错误,而不是把一段 HTML 当目录解析出满屏乱码。
1755
+ */
1756
+ declare function resolveChironBase(http: AxiosInstance): Promise<string>;
1757
+ declare function fetchSkillCatalog(http: AxiosInstance, base: string): Promise<ChironManifest>;
1758
+ declare function fetchSkillMarkdown(http: AxiosInstance, id: string, base: string): Promise<string>;
1759
+ /** 取技能自带的参考文件原文。`relativePath` 相对 `<skill>/references/`。 */
1760
+ declare function fetchSkillReference(http: AxiosInstance, id: string, relativePath: string, base: string): Promise<string>;
1761
+ /**
1762
+ * 参考文件相对路径约束——与后端 `ChironCatalogService.SAFE_REFERENCE_PATH` 同形。
1763
+ *
1764
+ * 🔴 服务端返回什么,本地就按什么建目录,所以这里是**写文件前**的闸:`..` 段会让
1765
+ * 安装写出技能目录之外。不要因为「服务端已经校验过」就省掉——CLI 可以指向任何 endpoint。
1766
+ */
1767
+ declare function assertSafeReferencePath(relativePath: string): void;
1768
+ /** 归一 references 字段:旧服务端缺省时视为空,逐条过白名单。 */
1769
+ declare function normalizeReferences(raw: unknown, skillId: string): string[];
1726
1770
  declare function flattenSkills(manifest: ChironManifest): ChironSkill[];
1771
+ /**
1772
+ * 计算技能安装闭包,返回稳定的「依赖在前、目标在后」顺序。
1773
+ *
1774
+ * 这是纯函数:远程安装与测试共用,不在这里发请求或写文件。旧目录没有 requires 时
1775
+ * 自然退化为只安装目标技能。
1776
+ */
1777
+ declare function resolveSkillInstallOrder(manifest: ChironManifest, targetId: string): ChironSkill[];
1778
+ /**
1779
+ * 全目录的安装顺序:逐个技能求依赖闭包后合并去重,依赖仍排在被依赖者之前。
1780
+ *
1781
+ * `install --all` 用它。顾问不必知道谁依赖谁,也不该为了装全而写 shell 循环——
1782
+ * 那个循环在 zsh 下 `for id in $(...)` 不分词,会一个都不装却退出码 0。
1783
+ */
1784
+ declare function resolveAllSkillsInstallOrder(manifest: ChironManifest): ChironSkill[];
1785
+ /** 读 SKILL.md 的 frontmatter;没有 frontmatter 返回空对象,YAML 非法则报错。 */
1786
+ declare function parseSkillFrontmatter(markdown: string, skillId: string): Record<string, unknown>;
1787
+ /** 从一份 SKILL.md 读取本地安装所需的 requires,不接受正文中的近似语法。 */
1788
+ declare function parseSkillRequirements(markdown: string, skillId: string): string[];
1789
+ /** Chiron 与公开端点共用的小写安全 id 约束。 */
1790
+ declare function assertSafeSkillId(id: string): void;
1727
1791
  /** 按交付生命周期阶段筛选。 */
1728
1792
  declare function filterByStage(skills: ChironSkill[], stage?: string): ChironSkill[];
1729
1793
  /** 关键词匹配 id / 标题 / 描述 / 分类,全部小写包含。 */
@@ -1772,4 +1836,4 @@ declare function resetSettingItem(http: AxiosInstance, domain: string, namespace
1772
1836
  */
1773
1837
  declare function parseSettingAssignment(raw: string): SettingWrite;
1774
1838
 
1775
- export { type ActionHttpMethod, type ActionInput, type ActionMeta, type ActionResult, type ActionScope, type AnyStreamEvent, type ApprovalConfirmPayload, type ApprovalRejectPayload, type AttachmentMeta, type AuthScheme, type BootstrapReconcileResult, type BootstrapTenantRequest, type BootstrapTenantResult, type CacheClearResult, type CacheStats, type ChangePasswordInput, type ChironCategory, type ChironManifest, type ChironSkill, type ChironStage, type ClearMetaCacheOpts, CliError, CliErrorCode, type CliErrorInit, type ClientAuthContext, type ClientCredentialsInput, type ConnectionMessage, type ControlChannelEnvelope, type ConversationListItem, type ConversationListResult, type ConversationState, type CreateResult, type CreatedConversation, DEFAULT_AGENT_ID, DEFAULT_SESSION_TTL_SECONDS, type DescribeOpts, type EnvConfig, ExitCode, type FieldMeta, type Fixture, type FormatOptions, type GlobalConfig, HcmClient, type HcmClientOpts, type HttpClientOptions, type IdentityMeta, type ImportClient, type ImportOptions, type ImportResult, type InteractionAnswerPayload, type InteractionRequest, type InteractionResolved, type ListTenantMetaOpts, type LoginOutcome, MINI_CONTEXT_FILE, MINI_CONTEXT_KIND, MINI_CONTEXT_VERSION, MINI_PULL_MANIFEST_FILE, MINI_REMOTE_ROOT, MINI_STATE_DIR, type MessageClass, type MessageCreatePayload, type MessageStreamHandle, type MigrationSummary, type MiniFileSnapshot, type MiniInitArgs, type MiniLocalFile, type MiniLocalStatus, type MiniPreviewTarget, type MiniProjectContext, type MiniPullArgs, type MiniPullManifest, type MiniPullResult, type MiniPushArgs, type MiniPushConflict, type MiniPushOperation, type MiniPushPlanItem, type MiniPushResult, type MiniSmokeCheckArgs, type MiniSmokeFetch, type MiniSmokeFetchResponse, type MiniSmokeResult, type MiniSmokeTargetKind, type MiniSmokeTargetResult, type MiniStatusEntry, type MiniSurface, type MiniTemplateArgs, type MiniTemplateKind, type MiniValidationResult, type MiniVerifyAgentReport, type MiniVerifyBrowserAcceptance, type MiniVerifyChangedFile, type MiniVerifyNextAction, type MiniVerifyPlan, type MiniVerifyPreviewUrl, type MiniVerifyReport, type MiniVerifySummary, type MiniWritableTemplateConfig, type ModelDescription, type ModelQueryDsl, type OneShotOpts, type OneShotResult, type OneShotToolCall, type OutputFormat, PASSWORD_CHANGE_REQUIRED, PROACTIVE_REFRESH_MARGIN_SECONDS, type PairingLoginInput, type ParsedPlaceholder, type PasswordChangeChallenge, type PasswordLoginInput, type PatLoginInput, type Principal, type ProfileConfig, type QueryResult, RefStore, type RefreshInput, type RelationMeta, type RemoveResult, type ResponseCompletedPayload, type ResponseFailedPayload, type ResponsePartDeltaPayload, type ResponseStartedPayload, type ResumeSummary, type ResumeTurn, type RowResult, type RowStatus, SDK_VERSION, type SaveMetaResult, type SendMessageOpts, type SettingItem, type SettingWrite, type StreamCancelPayload, type StreamCommand, type StreamCommandEnvelope, type StreamCommandType, type StreamEventEnvelope, type StreamEventType, type TaskProgressPayload, type TenantMetaEntry, type TimelineItemLite, type TokenRecord, TokenStore, type ToolCallFailedPayload, type ToolCallResultPayload, type ToolCallStartedPayload, type V4RenderSink, type V4StreamEventType, type WorkspaceFileContent, type WorkspaceFileItem, type WorkspaceFileListResult, WsClient, type WsClientOpts, absoluteDownloadUrl, archiveDir, bootstrapTenant, buildAnswer, buildConfirm, buildInterrupt, buildMiniAppTemplateFiles, buildMiniPreviewTargets, buildMiniVerifyAgentReport, buildReject, buildResumeSummary, buildSteer, camelizeKeys, changePassword, classifyMessage, clearMetaCache, clearModelCache, conversationStateFile, create, createConversation, createHttpClient, createV4Reducer, createWorkspaceFile, credentialsFile, defaultDownloadDir, defaultMiniRequiredScopes, deleteEnv, deleteIdentity, deleteTenantMeta, deleteWorkspaceFile, deriveNamelessToolLabel, describePrincipal, detectDelegationPause, detectDirectInteractionPending, detectPasswordChangeChallenge, displayWidth, downloadDocument, ensureSessionFresh, envDir, envFile, envsDir, exitCodeFor, extractNextSteps, fetchConversationTimeline, fetchConversationTimelineStrict, fetchRecentConversations, fetchSkillCatalog, fetchSkillMarkdown, filterByStage, findLastAssistantSeq, flattenSkills, formatMiniVerifyReport, formatObject, formatRows, fromAxiosError, getCacheStats, getMiniStatus, getSettingDomain, getTenantMeta, globalConfigFile, guessMimeType, hcmConfigDir, identitiesDir, identityDir, identityMetaFile, inferEnvName, inferMiniWritableTemplateOptionsFromModel, initMiniAppProject, isDelegationToolName, isServerSlidingSession, listEnvs, listIdentities, listProfiles, listTenantMeta, listWorkspaceFiles, loadConversationState, loadEnv, loadGlobalConfig, loadIdentity, loadProfile, loadWorkspaceFileContent, loginClientCredentials, loginPairing, loginPassword, loginPat, matchSkills, migrateLegacyProfiles, needsRefresh, oneShot, parseConfirmToolName, parseFixture, parseInteractionRequest, parseInteractionResolved, parsePlaceholder, parseSettingAssignment, patchSettingDomain, profileDir, profileFile, pullMiniAppProject, pushMiniAppProject, readMiniContext, readPullManifest, refreshToken, remove, replHistoryFile, resetSettingItem, resolveActiveEnv, resolveActiveIdentity, resolveActiveProfile, resolveRefs, runImport, runMiniSmokeChecks, saveConversationState, saveEnv, saveGlobalConfig, saveIdentity, saveProfile, saveTenantMeta, saveWorkspaceFileContent, sendMessageAndStream, snakeToCamel, toJson, toOrigin, toPrincipal, toTable, toYaml, truncateDisplay, update, uploadDocument, validateMiniProject };
1839
+ export { type ActionHttpMethod, type ActionInput, type ActionMeta, type ActionResult, type ActionScope, type AnyStreamEvent, type ApprovalConfirmPayload, type ApprovalRejectPayload, type AttachmentMeta, type AuthScheme, type BootstrapReconcileResult, type BootstrapTenantRequest, type BootstrapTenantResult, type CacheClearResult, type CacheStats, type ChangePasswordInput, type ChironCategory, type ChironManifest, type ChironSkill, type ChironStage, type ClearMetaCacheOpts, CliError, CliErrorCode, type CliErrorInit, type ClientAuthContext, type ClientCredentialsInput, type ConnectionMessage, type ControlChannelEnvelope, type ConversationListItem, type ConversationListResult, type ConversationState, type CreateResult, type CreatedConversation, DEFAULT_AGENT_ID, DEFAULT_SESSION_TTL_SECONDS, type DescribeOpts, type EnvConfig, ExitCode, type FieldMeta, type Fixture, type FormatOptions, type GlobalConfig, HcmClient, type HcmClientOpts, type HttpClientOptions, type IdentityMeta, type ImportClient, type ImportOptions, type ImportResult, type InteractionAnswerPayload, type InteractionRequest, type InteractionResolved, type ListTenantMetaOpts, type LoginOutcome, MINI_CONTEXT_FILE, MINI_CONTEXT_KIND, MINI_CONTEXT_VERSION, MINI_PULL_MANIFEST_FILE, MINI_REMOTE_ROOT, MINI_STATE_DIR, type MessageClass, type MessageCreatePayload, type MessageStreamHandle, type MigrationSummary, type MiniFileSnapshot, type MiniInitArgs, type MiniLocalFile, type MiniLocalStatus, type MiniPreviewTarget, type MiniProjectContext, type MiniPullArgs, type MiniPullManifest, type MiniPullResult, type MiniPushArgs, type MiniPushConflict, type MiniPushOperation, type MiniPushPlanItem, type MiniPushResult, type MiniSmokeCheckArgs, type MiniSmokeFetch, type MiniSmokeFetchResponse, type MiniSmokeResult, type MiniSmokeTargetKind, type MiniSmokeTargetResult, type MiniStatusEntry, type MiniSurface, type MiniTemplateArgs, type MiniTemplateKind, type MiniValidationResult, type MiniVerifyAgentReport, type MiniVerifyBrowserAcceptance, type MiniVerifyChangedFile, type MiniVerifyNextAction, type MiniVerifyPlan, type MiniVerifyPreviewUrl, type MiniVerifyReport, type MiniVerifySummary, type MiniWritableTemplateConfig, type ModelDescription, type ModelQueryDsl, type OneShotOpts, type OneShotResult, type OneShotToolCall, type OutputFormat, PASSWORD_CHANGE_REQUIRED, PROACTIVE_REFRESH_MARGIN_SECONDS, type PairingLoginInput, type ParsedPlaceholder, type PasswordChangeChallenge, type PasswordLoginInput, type PatLoginInput, type Principal, type ProfileConfig, type QueryResult, RefStore, type RefreshInput, type RelationMeta, type RemoveResult, type ResponseCompletedPayload, type ResponseFailedPayload, type ResponsePartDeltaPayload, type ResponseStartedPayload, type ResumeSummary, type ResumeTurn, type RowResult, type RowStatus, SDK_VERSION, type SaveMetaResult, type SendMessageOpts, type SettingItem, type SettingWrite, type StreamCancelPayload, type StreamCommand, type StreamCommandEnvelope, type StreamCommandType, type StreamEventEnvelope, type StreamEventType, type TaskProgressPayload, type TenantMetaEntry, type TimelineItemLite, type TokenRecord, TokenStore, type ToolCallFailedPayload, type ToolCallResultPayload, type ToolCallStartedPayload, type V4RenderSink, type V4StreamEventType, type WorkspaceFileContent, type WorkspaceFileItem, type WorkspaceFileListResult, WsClient, type WsClientOpts, absoluteDownloadUrl, archiveDir, assertSafeReferencePath, assertSafeSkillId, bootstrapTenant, buildAnswer, buildConfirm, buildInterrupt, buildMiniAppTemplateFiles, buildMiniPreviewTargets, buildMiniVerifyAgentReport, buildReject, buildResumeSummary, buildSteer, camelizeKeys, changePassword, classifyMessage, clearMetaCache, clearModelCache, conversationStateFile, create, createConversation, createHttpClient, createV4Reducer, createWorkspaceFile, credentialsFile, defaultDownloadDir, defaultMiniRequiredScopes, deleteEnv, deleteIdentity, deleteTenantMeta, deleteWorkspaceFile, deriveNamelessToolLabel, describePrincipal, detectDelegationPause, detectDirectInteractionPending, detectPasswordChangeChallenge, displayWidth, downloadDocument, ensureSessionFresh, envDir, envFile, envsDir, exitCodeFor, extractNextSteps, fetchConversationTimeline, fetchConversationTimelineStrict, fetchRecentConversations, fetchSkillCatalog, fetchSkillMarkdown, fetchSkillReference, filterByStage, findLastAssistantSeq, flattenSkills, formatMiniVerifyReport, formatObject, formatRows, fromAxiosError, getCacheStats, getMiniStatus, getSettingDomain, getTenantMeta, globalConfigFile, guessMimeType, hcmConfigDir, identitiesDir, identityDir, identityMetaFile, inferEnvName, inferMiniWritableTemplateOptionsFromModel, initMiniAppProject, isDelegationToolName, isServerSlidingSession, listEnvs, listIdentities, listProfiles, listTenantMeta, listWorkspaceFiles, loadConversationState, loadEnv, loadGlobalConfig, loadIdentity, loadProfile, loadWorkspaceFileContent, loginClientCredentials, loginPairing, loginPassword, loginPat, matchSkills, migrateLegacyProfiles, needsRefresh, normalizeReferences, oneShot, parseConfirmToolName, parseFixture, parseInteractionRequest, parseInteractionResolved, parsePlaceholder, parseSettingAssignment, parseSkillFrontmatter, parseSkillRequirements, patchSettingDomain, profileDir, profileFile, pullMiniAppProject, pushMiniAppProject, readMiniContext, readPullManifest, refreshToken, remove, replHistoryFile, resetSettingItem, resolveActiveEnv, resolveActiveIdentity, resolveActiveProfile, resolveAllSkillsInstallOrder, resolveChironBase, resolveRefs, resolveSkillInstallOrder, runImport, runMiniSmokeChecks, saveConversationState, saveEnv, saveGlobalConfig, saveIdentity, saveProfile, saveTenantMeta, saveWorkspaceFileContent, sendMessageAndStream, snakeToCamel, toJson, toOrigin, toPrincipal, toTable, toYaml, truncateDisplay, update, uploadDocument, validateMiniProject };
package/dist/index.js CHANGED
@@ -1403,13 +1403,14 @@ var MIME_BY_EXT = {
1403
1403
  function guessMimeType(filePath) {
1404
1404
  return MIME_BY_EXT[path4.extname(filePath).toLowerCase()] ?? "application/octet-stream";
1405
1405
  }
1406
- async function uploadDocument(http, filePath) {
1406
+ var CHAT_ATTACHMENT_CATEGORY = "ai-conversation";
1407
+ async function uploadDocument(http, filePath, storageCategory = CHAT_ATTACHMENT_CATEGORY) {
1407
1408
  const abs = expandHome(filePath);
1408
1409
  const buf = await fsp.readFile(abs);
1409
1410
  const fileName = path4.basename(abs);
1410
1411
  const form = new FormData();
1411
1412
  form.append("file", new Blob([buf], { type: guessMimeType(abs) }), fileName);
1412
- form.append("storageCategory", "ai-conversation");
1413
+ form.append("storageCategory", storageCategory);
1413
1414
  form.append("allowEmptyFormId", "true");
1414
1415
  const resp = await http.post("/api/documents/upload", form);
1415
1416
  const meta = resp.data?.data ?? resp.data;
@@ -5002,20 +5003,163 @@ async function deleteTenantMeta(http, path6) {
5002
5003
  }
5003
5004
 
5004
5005
  // src/skills.ts
5005
- async function fetchSkillCatalog(http) {
5006
- const resp = await http.get("/skills.json");
5006
+ import yaml7, { JSON_SCHEMA as JSON_SCHEMA2 } from "js-yaml";
5007
+ var CHIRON_BASE_CANDIDATES = ["/api", ""];
5008
+ function looksLikeManifest(data) {
5009
+ if (!data || typeof data !== "object") return false;
5010
+ const m = data;
5011
+ return m.name === "chiron" && Array.isArray(m.categories);
5012
+ }
5013
+ async function resolveChironBase(http) {
5014
+ const tried = [];
5015
+ for (const base of CHIRON_BASE_CANDIDATES) {
5016
+ const url = `${base}/skills.json`;
5017
+ tried.push(url);
5018
+ try {
5019
+ const resp = await http.get(url);
5020
+ const data = resp.data?.data ?? resp.data;
5021
+ if (looksLikeManifest(data)) return base;
5022
+ } catch {
5023
+ }
5024
+ }
5025
+ throw new CliError({
5026
+ code: "INVALID_ARGUMENT" /* INVALID_ARGUMENT */,
5027
+ message: `\u8FD9\u4E2A\u73AF\u5883\u4E0A\u627E\u4E0D\u5230\u777F\u620E\u6280\u80FD\u5E93\uFF08\u8BD5\u8FC7 ${tried.join(" \u548C ")}\uFF09\u3002\u5E38\u89C1\u539F\u56E0\uFF1A\u2460 \u540E\u7AEF\u7248\u672C\u8FD8\u6CA1\u6709 /api/skills \u7AEF\u70B9\uFF0C\u5347\u7EA7\u540E\u7AEF\u5373\u53EF\uFF1B\u2461 endpoint \u586B\u7684\u662F\u524D\u7AEF\u5730\u5740\u4E14\u672A\u53CD\u4EE3\u5230\u540E\u7AEF\uFF1B\u2462 \u5730\u5740\u6216\u7F51\u7EDC\u4E0D\u901A\u3002`
5028
+ });
5029
+ }
5030
+ async function fetchSkillCatalog(http, base) {
5031
+ const resp = await http.get(`${base}/skills.json`);
5007
5032
  return resp.data?.data ?? resp.data;
5008
5033
  }
5009
- async function fetchSkillMarkdown(http, id) {
5010
- const resp = await http.get(`/skills/${encodeURIComponent(id)}.md`, {
5034
+ async function fetchSkillMarkdown(http, id, base) {
5035
+ const resp = await http.get(`${base}/skills/${encodeURIComponent(id)}.md`, {
5036
+ responseType: "text",
5037
+ transformResponse: [(d) => d]
5038
+ });
5039
+ return String(resp.data ?? "");
5040
+ }
5041
+ async function fetchSkillReference(http, id, relativePath, base) {
5042
+ assertSafeReferencePath(relativePath);
5043
+ const encoded = relativePath.split("/").map(encodeURIComponent).join("/");
5044
+ const resp = await http.get(`${base}/skills/${encodeURIComponent(id)}/references/${encoded}`, {
5011
5045
  responseType: "text",
5012
5046
  transformResponse: [(d) => d]
5013
5047
  });
5014
5048
  return String(resp.data ?? "");
5015
5049
  }
5050
+ function assertSafeReferencePath(relativePath) {
5051
+ const ok = /^[A-Za-z0-9_][A-Za-z0-9._-]{0,63}(\/[A-Za-z0-9_][A-Za-z0-9._-]{0,63}){0,2}$/.test(relativePath);
5052
+ if (!ok) {
5053
+ throw invalid(`\u53C2\u8003\u6587\u4EF6\u8DEF\u5F84\u4E0D\u5408\u6CD5\uFF1A${JSON.stringify(relativePath)}`);
5054
+ }
5055
+ }
5056
+ function normalizeReferences(raw, skillId) {
5057
+ if (raw === void 0 || raw === null) return [];
5058
+ if (!Array.isArray(raw)) throw invalid(`\u6280\u80FD ${skillId} \u7684 references \u53EA\u80FD\u662F\u5B57\u7B26\u4E32\u6570\u7EC4`);
5059
+ const out = [];
5060
+ for (const value of raw) {
5061
+ if (typeof value !== "string" || !value.trim()) {
5062
+ throw invalid(`\u6280\u80FD ${skillId} \u7684 references \u53EA\u80FD\u662F\u975E\u7A7A\u5B57\u7B26\u4E32\u6570\u7EC4`);
5063
+ }
5064
+ const rel = value.trim();
5065
+ assertSafeReferencePath(rel);
5066
+ if (!out.includes(rel)) out.push(rel);
5067
+ }
5068
+ return out;
5069
+ }
5016
5070
  function flattenSkills(manifest2) {
5017
5071
  return (manifest2.categories ?? []).flatMap((c) => c.skills ?? []);
5018
5072
  }
5073
+ function resolveSkillInstallOrder(manifest2, targetId) {
5074
+ const byId = /* @__PURE__ */ new Map();
5075
+ for (const skill of flattenSkills(manifest2)) {
5076
+ if (byId.has(skill.id)) {
5077
+ throw invalid(`\u6280\u80FD\u76EE\u5F55\u5B58\u5728\u91CD\u590D id: ${skill.id}`);
5078
+ }
5079
+ byId.set(skill.id, skill);
5080
+ }
5081
+ if (!byId.has(targetId)) {
5082
+ throw invalid(`\u6280\u80FD\u76EE\u5F55\u4E2D\u4E0D\u5B58\u5728 ${targetId}`);
5083
+ }
5084
+ const state = /* @__PURE__ */ new Map();
5085
+ const path6 = [];
5086
+ const order = [];
5087
+ const visit = (id, requiredBy) => {
5088
+ const current = state.get(id);
5089
+ if (current === "done") return;
5090
+ if (current === "visiting") {
5091
+ const cycleStart = path6.indexOf(id);
5092
+ const cycle = [...path6.slice(Math.max(0, cycleStart)), id];
5093
+ throw invalid(`\u6280\u80FD\u4F9D\u8D56\u5B58\u5728\u73AF: ${cycle.join(" -> ")}`);
5094
+ }
5095
+ const skill = byId.get(id);
5096
+ if (!skill) {
5097
+ throw invalid(`\u6280\u80FD ${requiredBy ?? targetId} \u4F9D\u8D56\u4E0D\u5B58\u5728: ${id}`);
5098
+ }
5099
+ assertSafeSkillId(skill.id);
5100
+ state.set(id, "visiting");
5101
+ path6.push(id);
5102
+ for (const required of normalizeRequirements(skill.requires, skill.id)) {
5103
+ visit(required, skill.id);
5104
+ }
5105
+ path6.pop();
5106
+ state.set(id, "done");
5107
+ order.push(skill);
5108
+ };
5109
+ visit(targetId);
5110
+ return order;
5111
+ }
5112
+ function resolveAllSkillsInstallOrder(manifest2) {
5113
+ const order = /* @__PURE__ */ new Map();
5114
+ const all = flattenSkills(manifest2).map((skill) => skill.id).sort();
5115
+ for (const id of all) {
5116
+ for (const skill of resolveSkillInstallOrder(manifest2, id)) {
5117
+ if (!order.has(skill.id)) order.set(skill.id, skill);
5118
+ }
5119
+ }
5120
+ return [...order.values()];
5121
+ }
5122
+ function parseSkillFrontmatter(markdown, skillId) {
5123
+ const match = /^---\r?\n([\s\S]*?)\r?\n---(?:\r?\n|$)/.exec(markdown);
5124
+ if (!match) return {};
5125
+ let frontmatter;
5126
+ try {
5127
+ frontmatter = yaml7.load(match[1] ?? "", { schema: JSON_SCHEMA2 });
5128
+ } catch (cause) {
5129
+ throw new CliError({
5130
+ code: "INVALID_ARGUMENT" /* INVALID_ARGUMENT */,
5131
+ message: `\u6280\u80FD ${skillId} \u7684 frontmatter \u4E0D\u662F\u5408\u6CD5 YAML`,
5132
+ cause
5133
+ });
5134
+ }
5135
+ if (!frontmatter || typeof frontmatter !== "object" || Array.isArray(frontmatter)) return {};
5136
+ return frontmatter;
5137
+ }
5138
+ function parseSkillRequirements(markdown, skillId) {
5139
+ return normalizeRequirements(parseSkillFrontmatter(markdown, skillId).requires, skillId);
5140
+ }
5141
+ function assertSafeSkillId(id) {
5142
+ if (!/^[a-z0-9][a-z0-9-]{0,63}$/.test(id)) {
5143
+ throw invalid(`\u6280\u80FD id \u53EA\u80FD\u662F\u5C0F\u5199\u5B57\u6BCD/\u6570\u5B57/\u8FDE\u5B57\u7B26\uFF0C\u6536\u5230 "${id}"`);
5144
+ }
5145
+ }
5146
+ function normalizeRequirements(raw, skillId) {
5147
+ if (raw === void 0 || raw === null) return [];
5148
+ const values = Array.isArray(raw) ? raw : [raw];
5149
+ const normalized = [];
5150
+ for (const value of values) {
5151
+ if (typeof value !== "string" || !value.trim()) {
5152
+ throw invalid(`\u6280\u80FD ${skillId} \u7684 requires \u53EA\u80FD\u662F\u975E\u7A7A\u6280\u80FD id \u6570\u7EC4`);
5153
+ }
5154
+ const id = value.trim();
5155
+ assertSafeSkillId(id);
5156
+ if (!normalized.includes(id)) normalized.push(id);
5157
+ }
5158
+ return normalized;
5159
+ }
5160
+ function invalid(message) {
5161
+ return new CliError({ code: "INVALID_ARGUMENT" /* INVALID_ARGUMENT */, message });
5162
+ }
5019
5163
  function filterByStage(skills, stage) {
5020
5164
  if (!stage) return skills;
5021
5165
  return skills.filter((s) => (s.stages ?? []).includes(stage));
@@ -5076,6 +5220,8 @@ export {
5076
5220
  WsClient,
5077
5221
  absoluteDownloadUrl,
5078
5222
  archiveDir,
5223
+ assertSafeReferencePath,
5224
+ assertSafeSkillId,
5079
5225
  bootstrapTenant,
5080
5226
  buildAnswer,
5081
5227
  buildConfirm,
@@ -5122,6 +5268,7 @@ export {
5122
5268
  fetchRecentConversations,
5123
5269
  fetchSkillCatalog,
5124
5270
  fetchSkillMarkdown,
5271
+ fetchSkillReference,
5125
5272
  filterByStage,
5126
5273
  findLastAssistantSeq,
5127
5274
  flattenSkills,
@@ -5162,6 +5309,7 @@ export {
5162
5309
  matchSkills,
5163
5310
  migrateLegacyProfiles,
5164
5311
  needsRefresh,
5312
+ normalizeReferences,
5165
5313
  oneShot,
5166
5314
  parseConfirmToolName,
5167
5315
  parseFixture,
@@ -5169,6 +5317,8 @@ export {
5169
5317
  parseInteractionResolved,
5170
5318
  parsePlaceholder,
5171
5319
  parseSettingAssignment,
5320
+ parseSkillFrontmatter,
5321
+ parseSkillRequirements,
5172
5322
  patchSettingDomain,
5173
5323
  profileDir,
5174
5324
  profileFile,
@@ -5183,7 +5333,10 @@ export {
5183
5333
  resolveActiveEnv,
5184
5334
  resolveActiveIdentity,
5185
5335
  resolveActiveProfile,
5336
+ resolveAllSkillsInstallOrder,
5337
+ resolveChironBase,
5186
5338
  resolveRefs,
5339
+ resolveSkillInstallOrder,
5187
5340
  runImport,
5188
5341
  runMiniSmokeChecks,
5189
5342
  saveConversationState,