@cjhyy/code-shell-link 0.9.40 → 0.9.42
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 +4 -0
- package/dist/catalog.js +9 -2
- package/dist/file-selection.d.ts +21 -0
- package/dist/file-selection.js +75 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +1 -0
- package/dist/types.d.ts +7 -0
- package/package.json +1 -1
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("
|
|
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
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
|
}
|