@cjhyy/code-shell-server 0.9.30 → 0.9.31

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.
@@ -113,6 +113,7 @@ export function createLinkHttp(options) {
113
113
  "connectionId",
114
114
  "expectedRevision",
115
115
  "authModeId",
116
+ "resourceUrl",
116
117
  ]);
117
118
  result = await service.startAuthorization(owner, input, input.authModeId);
118
119
  }
@@ -170,6 +171,7 @@ export function createLinkHttp(options) {
170
171
  "connectionId",
171
172
  "expectedRevision",
172
173
  ...(token ? ["token"] : []),
174
+ ...(url.pathname.endsWith("/remote") ? ["resourceUrl"] : []),
173
175
  ]);
174
176
  result = token
175
177
  ? await service.connectToken(owner, input)
@@ -186,6 +186,14 @@ export function createLinkService(options = {}) {
186
186
  id: meta.linkAccountId,
187
187
  label: meta.linkAccountLabel,
188
188
  resources: meta.linkResourceLabels?.slice(0, 100) ?? [],
189
+ ...(remote && meta.linkResourceGroups
190
+ ? {
191
+ resourceGroups: meta.linkResourceGroups.map((group) => ({
192
+ id: group.id,
193
+ items: group.items.map((item) => ({ id: item.id, label: item.label })),
194
+ })),
195
+ }
196
+ : {}),
189
197
  },
190
198
  capabilityIds: meta.linkCapabilityIds ?? [],
191
199
  verifiedAt: meta.linkLastVerifiedAt,
@@ -664,6 +672,8 @@ export function createLinkService(options = {}) {
664
672
  async function startAuthorization(context, input, rawAuthModeId) {
665
673
  await authorize(context);
666
674
  const authModeId = string(rawAuthModeId, 80);
675
+ if (input?.resourceUrl !== undefined && authModeId !== "remote-link")
676
+ throw new LinkServiceError(400, "invalid_request");
667
677
  if (authModeId === "remote-link")
668
678
  await refreshRemoteCatalog(context);
669
679
  const provider = snapshot().providers.find((candidate) => candidate.id === input?.providerId);
@@ -1029,7 +1039,12 @@ export function createLinkService(options = {}) {
1029
1039
  checkCapacity();
1030
1040
  if (!input ||
1031
1041
  input.methodId !== "remote-link" ||
1032
- !REMOTE_LINK_ADAPTERS.some((adapter) => adapter.id === input.providerId))
1042
+ !REMOTE_LINK_ADAPTERS.some((adapter) => adapter.id === input.providerId) ||
1043
+ (input.resourceUrl !== undefined &&
1044
+ (input.providerId !== "figma" ||
1045
+ !input.connectionId ||
1046
+ typeof input.resourceUrl !== "string" ||
1047
+ !input.resourceUrl)))
1033
1048
  throw new LinkServiceError(400, "invalid_request");
1034
1049
  const config = options.remoteLink?.();
1035
1050
  if (!config)
@@ -1055,11 +1070,24 @@ export function createLinkService(options = {}) {
1055
1070
  throw new LinkServiceError(409, "conflict");
1056
1071
  }
1057
1072
  const prepared = { id, expected, input: { ...input, label: string(input.label) } };
1073
+ if (input.resourceUrl !== undefined && !expected)
1074
+ throw new LinkServiceError(400, "invalid_request");
1058
1075
  let attempt;
1059
1076
  try {
1077
+ let resourceFiles;
1078
+ if (input.providerId === "figma") {
1079
+ // Recover the old whitelist from Host custody. Browser input can only suggest one new file.
1080
+ const groups = expected?.meta?.linkResourceGroups;
1081
+ if (expected && (!groups || groups.length !== 1 || groups[0]?.id !== "files"))
1082
+ throw new Error("Invalid saved Figma resources");
1083
+ resourceFiles = groups?.[0]?.items.map((item) => item.id) ?? [];
1084
+ if (input.resourceUrl !== undefined)
1085
+ resourceFiles.push(input.resourceUrl);
1086
+ }
1060
1087
  attempt = beginRemoteLinkAuthorization(config, now(), {
1061
1088
  providerId: input.providerId,
1062
1089
  actions: capabilities.actions,
1090
+ ...(resourceFiles !== undefined ? { resourceFiles } : {}),
1063
1091
  });
1064
1092
  }
1065
1093
  catch {
@@ -1123,6 +1151,10 @@ export function createLinkService(options = {}) {
1123
1151
  },
1124
1152
  });
1125
1153
  await check();
1154
+ if (job.attempt.providerId === "figma" &&
1155
+ job.prepared.expected &&
1156
+ credential.meta?.linkAccountId !== job.prepared.expected.meta?.linkAccountId)
1157
+ throw new LinkServiceError(409, "conflict");
1126
1158
  const guarded = {
1127
1159
  ownerId: context.ownerId,
1128
1160
  authorize: async () => {
@@ -1,5 +1,4 @@
1
1
  import { type PanelAppPreview, type PanelAppSourceInput } from "@cjhyy/code-shell-core";
2
- import { getRefCommit } from "@cjhyy/code-shell-core/internal/skills";
3
2
  import type { PanelCompatibility, PanelDiscovery, PanelOperationContext, PanelReview, PanelProjectReview, PanelSnapshot, PanelPackageHistory, PanelPackageRestoreReview } from "./types.js";
4
3
  export declare class PanelManagementError extends Error {
5
4
  readonly status: number;
@@ -23,7 +22,10 @@ export interface PanelManagementOptions {
23
22
  compatibility?: (app: Pick<PanelAppPreview, "permissions" | "agent">) => PanelCompatibility;
24
23
  now?: () => number;
25
24
  /** Network seam only; production still uses the reviewed Core installer. */
26
- resolveCommit?: typeof getRefCommit;
25
+ resolveCommit?: (info: {
26
+ owner: string;
27
+ repo: string;
28
+ }, ref: string) => Promise<string>;
27
29
  }
28
30
  export declare function createPanelManagement(options: PanelManagementOptions): {
29
31
  snapshot: (appId?: string) => Promise<PanelSnapshot>;
@@ -3,9 +3,9 @@ import { panelPackageMutationMatches } from "./package-mutation.js";
3
3
  import { createHash, randomBytes } from "node:crypto";
4
4
  import { lstatSync, mkdirSync, statSync } from "node:fs";
5
5
  import { basename, extname, isAbsolute, join, resolve } from "node:path";
6
- import { SettingsManager, PanelAppAlreadyInstalledError, PanelAppInstallError, PanelAppReviewChangedError, assertSafePanelAppId, discoverGitPanelApps, installReviewedLocalPanelApp, invalidateSkillCache, listInstalledPanelApps, inspectProjectPanelApps, listRetainedPanelAppPackages, resolvePanelAppPackage, parsePanelAppPackagePins, retainInstalledPanelApp, userHome, panelAppsRoot, previewLocalPanelApp, resolvePanelAppBindingPolicy, uninstallPanelApp, } from "@cjhyy/code-shell-core";
6
+ import { SettingsManager, PanelAppAlreadyInstalledError, PanelAppInstallError, PanelAppReviewChangedError, assertSafePanelAppId, discoverGitPanelApps, installReviewedLocalPanelApp, invalidateSkillCache, listInstalledPanelApps, inspectProjectPanelApps, listRetainedPanelAppPackages, resolvePanelAppPackage, parsePanelAppPackagePins, retainInstalledPanelApp, userHome, panelAppsRoot, previewLocalPanelApp, resolveGitHubPanelAppCommit, resolvePanelAppBindingPolicy, uninstallPanelApp, } from "@cjhyy/code-shell-core";
7
7
  import { mutateJsonFile } from "@cjhyy/code-shell-core/internal";
8
- import { getRefCommit, parseGithubUrl } from "@cjhyy/code-shell-core/internal/skills";
8
+ import { parseGithubUrl } from "@cjhyy/code-shell-core/internal/skills";
9
9
  const REVIEW_TTL = 8 * 60_000;
10
10
  const MAX_REVIEWS = 8;
11
11
  const MAX_NETWORK = 2;
@@ -47,7 +47,7 @@ export function publicPanelError(error) {
47
47
  return new PanelManagementError(503, "github_unavailable", "GitHub 暂时不可用,请稍后重试。");
48
48
  if (/(?:ENOTFOUND|EAI_AGAIN|ECONNRESET|ECONNREFUSED|UND_ERR_SOCKET)/.test(code) ||
49
49
  /^(?:fetch failed|Failed to fetch)$/i.test(message) ||
50
- /GitHub source download failed/i.test(message))
50
+ /GitHub source (?:download|ref lookup) failed/i.test(message))
51
51
  return new PanelManagementError(502, "github_network", "服务端无法连接 GitHub,请检查网络、DNS 或代理设置后重试。");
52
52
  if (error instanceof PanelAppInstallError)
53
53
  return new PanelManagementError(400, "invalid_source", error.message);
@@ -352,7 +352,9 @@ export function createPanelManagement(options) {
352
352
  const ref = parsed.source.ref ?? "HEAD";
353
353
  const commit = SHA.test(ref)
354
354
  ? ref.toLowerCase()
355
- : await (options.resolveCommit ?? getRefCommit)({ owner: parsed.owner, repo: parsed.repo }, ref);
355
+ : options.resolveCommit
356
+ ? await options.resolveCommit({ owner: parsed.owner, repo: parsed.repo }, ref)
357
+ : await resolveGitHubPanelAppCommit(parsed.source);
356
358
  await guard();
357
359
  if (!SHA.test(commit))
358
360
  throw new PanelManagementError(502, "invalid_source", "GitHub 没有返回有效的提交版本。");
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cjhyy/code-shell-server",
3
- "version": "0.9.30",
3
+ "version": "0.9.31",
4
4
  "description": "CodeShell server transport layer — mobile remote HTTP/WS host, pairing, passcode gate, tunnel, rooms, uploads, and session/attachment services. Electron-free; precursor of the auth gateway.",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -60,13 +60,13 @@
60
60
  "clean": "node -e \"require('node:fs').rmSync('dist',{recursive:true,force:true})\""
61
61
  },
62
62
  "dependencies": {
63
- "@cjhyy/code-shell-capability-coding": "0.9.30",
64
- "@cjhyy/code-shell-core": "0.9.30",
65
- "@cjhyy/code-shell-web": "0.9.30",
63
+ "@cjhyy/code-shell-capability-coding": "0.9.31",
64
+ "@cjhyy/code-shell-core": "0.9.31",
65
+ "@cjhyy/code-shell-web": "0.9.31",
66
66
  "@modelcontextprotocol/sdk": "^1.31.0",
67
67
  "@types/ws": "^8.18.1",
68
68
  "ws": "^8.21.0",
69
- "@cjhyy/code-shell-link": "0.9.30"
69
+ "@cjhyy/code-shell-link": "0.9.31"
70
70
  },
71
71
  "engines": {
72
72
  "node": ">=20.10"