@cjhyy/code-shell-link 0.9.39 → 0.9.41

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/README.md CHANGED
@@ -36,3 +36,7 @@ Core 也不反向依赖这个包。Desktop / Link Server 作为宿主,在加
36
36
  新增 Provider 时,先在 `src/catalog.ts` 增加 manifest,再在可信执行宿主实现相同的 `actionIds`。
37
37
  `bun run test` 会校验每个 Provider 都有可用本地方法、独立服务端方法、完整授权引导,并锁定支持
38
38
  零复制会话的官方 CLI 清单。
39
+
40
+ Slack 精确消息/线程与 GitHub PR 文件、提交和 exact commit 的只读契约,见
41
+ [Link source reads](../../docs/link-source-reads.md)。本地、CLI 与远程执行宿主必须显式支持
42
+ 相同的 Action;已部署远程服务不会因客户端清单更新而自动新增能力。
package/dist/catalog.js CHANGED
@@ -76,6 +76,7 @@ export const LINK_PROVIDER_MANIFESTS = [
76
76
  },
77
77
  { ...managedOAuth("GitHub App"), id: "github-app" },
78
78
  ],
79
+ fileSelection: { kind: "github-file", action: "get_file", resourceGroup: "repositories" },
79
80
  actionIds: [
80
81
  "list_repositories",
81
82
  "get_repository",
@@ -87,6 +88,9 @@ export const LINK_PROVIDER_MANIFESTS = [
87
88
  "get_issue",
88
89
  "list_pull_requests",
89
90
  "get_pull_request",
91
+ "list_pull_request_files",
92
+ "list_pull_request_commits",
93
+ "get_commit",
90
94
  "create_issue",
91
95
  "update_issue",
92
96
  ],
@@ -204,7 +208,7 @@ export const LINK_PROVIDER_MANIFESTS = [
204
208
  id: "slack",
205
209
  displayName: "Slack",
206
210
  category: "communication",
207
- description: text("列出频道并读取最近消息。", "List channels and read recent messages."),
211
+ description: text("列出频道、读取精确消息及分页线程。", "List channels, read exact messages and paged threads."),
208
212
  brandText: "S",
209
213
  icon: "conversation",
210
214
  accent: "fuchsia",
@@ -234,15 +238,17 @@ export const LINK_PROVIDER_MANIFESTS = [
234
238
  text("在 Slack API 创建 App,并选择目标工作区。", "Create an app in Slack API and choose the target workspace."),
235
239
  text("在 OAuth & Permissions 添加 Bot Token Scopes。", "Add the bot token scopes under OAuth & Permissions."),
236
240
  text("安装 App 到工作区;需要读消息的频道还要邀请该 App。", "Install the app, then invite it to channels whose history it should read."),
241
+ text("公开或私有频道的完整线程读取可能需要 User OAuth Token(xoxp-)与相应 history 权限;Bot Token 不一定能读取频道线程。", "Public/private channel threads may require a User OAuth Token (xoxp-) with the corresponding history scope; bot tokens may not read those threads."),
237
242
  text("复制 Bot User OAuth Token(xoxb-)并回到这里验证。", "Copy the Bot User OAuth Token (xoxb-) and verify it here."),
238
243
  ],
239
244
  }),
240
245
  managedOAuth("Slack"),
241
246
  ],
242
- actionIds: ["list_channels", "get_channel_history"],
247
+ actionIds: ["list_channels", "get_channel_history", "get_message", "get_thread"],
243
248
  },
244
249
  {
245
250
  id: "notion",
251
+ fileSelectionLimitation: "document-content-unavailable",
246
252
  displayName: "Notion",
247
253
  category: "work",
248
254
  description: text("搜索并读取已共享的页面和数据库。", "Search and read shared pages and databases."),
@@ -395,6 +401,7 @@ export const LINK_PROVIDER_MANIFESTS = [
395
401
  }),
396
402
  { ...managedOAuth("Figma"), id: "figma-oauth" },
397
403
  ],
404
+ fileSelection: { kind: "figma-file", action: "get_file", resourceGroup: "files" },
398
405
  actionIds: ["get_file", "get_comments"],
399
406
  },
400
407
  ];
@@ -0,0 +1,21 @@
1
+ export type LinkFileSelectionInput = {
2
+ kind: "github-file";
3
+ owner: string;
4
+ repo: string;
5
+ path: string;
6
+ ref?: string;
7
+ label?: string;
8
+ } | {
9
+ kind: "figma-file";
10
+ fileUrlOrKey: string;
11
+ label?: string;
12
+ };
13
+ /** Provider-owned normalization, shared by Hosts without accepting arbitrary action JSON. */
14
+ export declare function resolveLinkFileSelection(providerId: string, input: unknown): {
15
+ providerId: string;
16
+ action: "get_file";
17
+ scopeId: string;
18
+ params: Record<string, string>;
19
+ resourceId: string;
20
+ label: string;
21
+ };
@@ -0,0 +1,75 @@
1
+ import { getLinkProviderManifest } from "./catalog.js";
2
+ function text(value, field, max) {
3
+ if (typeof value !== "string" ||
4
+ !value.trim() ||
5
+ value.length > max ||
6
+ /[\x00-\x1f\x7f]/.test(value))
7
+ throw new Error(`Invalid linked file ${field}`);
8
+ return value.trim();
9
+ }
10
+ /** Provider-owned normalization, shared by Hosts without accepting arbitrary action JSON. */
11
+ export function resolveLinkFileSelection(providerId, input) {
12
+ const capability = getLinkProviderManifest(providerId)?.fileSelection;
13
+ if (!capability || !input || typeof input !== "object" || Array.isArray(input))
14
+ throw new Error("This connection does not support document file selection");
15
+ const file = input;
16
+ if (file.kind !== capability.kind)
17
+ throw new Error("Linked file belongs to another provider");
18
+ const allowed = capability.kind === "github-file"
19
+ ? ["kind", "owner", "repo", "path", "ref", "label"]
20
+ : ["kind", "fileUrlOrKey", "label"];
21
+ if (Object.keys(file).some((key) => !allowed.includes(key)))
22
+ throw new Error("Unknown linked file field");
23
+ const label = file.label === undefined ? undefined : text(file.label, "label", 512);
24
+ let params, resourceId, defaultLabel;
25
+ if (capability.kind === "github-file") {
26
+ const owner = text(file.owner, "owner", 100).toLowerCase();
27
+ const repo = text(file.repo, "repository", 100).toLowerCase();
28
+ if (!/^[a-z0-9][a-z0-9-]{0,38}$/.test(owner) ||
29
+ !/^[a-z0-9_.-]+$/.test(repo) ||
30
+ [".", ".."].includes(repo))
31
+ throw new Error("Invalid GitHub repository");
32
+ const path = text(file.path, "path", 2_000);
33
+ for (const segment of path.split("/")) {
34
+ let decoded = segment;
35
+ try {
36
+ decoded = decodeURIComponent(segment);
37
+ }
38
+ catch {
39
+ /* Literal percent signs are allowed. */
40
+ }
41
+ if ([segment, decoded].some((part) => !part || part === "." || part === ".." || /[/\\]/.test(part)))
42
+ throw new Error("Invalid GitHub file path");
43
+ }
44
+ const ref = file.ref === undefined || file.ref === "" ? undefined : text(file.ref, "ref", 300);
45
+ params = { owner, repo, path, ...(ref ? { ref } : {}) };
46
+ resourceId = `${owner}/${repo}`;
47
+ defaultLabel = `${resourceId}/${path}`;
48
+ }
49
+ else {
50
+ let key = text(file.fileUrlOrKey, "Figma file", 1_000);
51
+ if (key.startsWith("https://")) {
52
+ const url = new URL(key);
53
+ if (!["figma.com", "www.figma.com"].includes(url.hostname) ||
54
+ url.username ||
55
+ url.password ||
56
+ url.port)
57
+ throw new Error("Invalid Figma file URL");
58
+ key =
59
+ /^\/(?:file|design|board)\/([A-Za-z0-9_-]{1,200})(?:\/|$)/.exec(url.pathname)?.[1] ?? "";
60
+ }
61
+ if (!/^[A-Za-z0-9_-]{1,200}$/.test(key))
62
+ throw new Error("Invalid Figma file key");
63
+ params = { file_url_or_key: key };
64
+ resourceId = key;
65
+ defaultLabel = `Figma · ${key}`;
66
+ }
67
+ return {
68
+ providerId,
69
+ action: capability.action,
70
+ scopeId: `${providerId}:${capability.action}`,
71
+ params,
72
+ resourceId,
73
+ label: label ?? defaultLabel.slice(-512),
74
+ };
75
+ }
package/dist/index.d.ts CHANGED
@@ -1,3 +1,5 @@
1
1
  export { LINK_PROVIDER_MANIFESTS, getLinkProviderManifest, localizeLinkText } from "./catalog.js";
2
+ export { resolveLinkFileSelection } from "./file-selection.js";
3
+ export type { LinkFileSelectionInput } from "./file-selection.js";
2
4
  export type { LinkAuthGuide, LinkAuthKind, LinkConnectionMethodManifest, LinkCliSessionAuth, LinkExecutionRuntime, LinkLocalizedText, LinkMethodAvailability, LinkPermissionGuide, LinkPermissionLevel, LinkProviderAccent, LinkProviderCategory, LinkProviderIcon, LinkProviderManifest, LinkSecretLocation, } from "./types.js";
3
5
  export type { LinkProviderView, LinkAuthMode, LinkAuthorization, LinkAuthorizationInput, LinkAuthorizationResponse, LinkAuthorizationStep, LinkCredentialFieldView, LinkResourceGroupView, LinkConnectionInput, LinkErrorCode, LinkSnapshot, MaskedLinkConnection, TokenConnectionInput, } from "./management-types.js";
package/dist/index.js CHANGED
@@ -1 +1,2 @@
1
1
  export { LINK_PROVIDER_MANIFESTS, getLinkProviderManifest, localizeLinkText } from "./catalog.js";
2
+ export { resolveLinkFileSelection } from "./file-selection.js";
package/dist/types.d.ts CHANGED
@@ -82,4 +82,11 @@ export interface LinkProviderManifest {
82
82
  featured?: boolean;
83
83
  connectionMethods: LinkConnectionMethodManifest[];
84
84
  actionIds: string[];
85
+ /** Reviewed exact-file reads; absence means this provider cannot supply file content. */
86
+ fileSelection?: {
87
+ kind: "github-file" | "figma-file";
88
+ action: "get_file";
89
+ resourceGroup: "repositories" | "files";
90
+ };
91
+ fileSelectionLimitation?: "document-content-unavailable";
85
92
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cjhyy/code-shell-link",
3
- "version": "0.9.39",
3
+ "version": "0.9.41",
4
4
  "description": "Framework-independent provider manifests and authorization guides for CodeShell Link.",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",