dsh-seework 0.1.2 → 0.1.4

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/lib/index.js CHANGED
@@ -1,6 +1,6 @@
1
1
  import { SettingsConflictError } from "@deepseek-ai/dsh-settings";
2
2
  import { defineTool } from "@deepseek-ai/dsh-tools";
3
- import { readFile } from "node:fs/promises";
3
+ import { readFile, writeFile } from "node:fs/promises";
4
4
  import { fileURLToPath } from "node:url";
5
5
  import { randomUUID } from "node:crypto";
6
6
  import { promises, readFileSync } from "node:fs";
@@ -3017,6 +3017,8 @@ function isNewer(candidate, current) {
3017
3017
  //#region src/update.ts
3018
3018
  /** The package name this plugin is published under. */
3019
3019
  const PACKAGE_NAME = "dsh-seework";
3020
+ /** Where to ask when the host names no registry. */
3021
+ const DEFAULT_REGISTRY = "https://registry.npmjs.org";
3020
3022
  /** The spec an update installs. */
3021
3023
  const UPDATE_SPEC = `${PACKAGE_NAME}@latest`;
3022
3024
  /**
@@ -3068,13 +3070,80 @@ function readInstallKind(profileDir, packageName = PACKAGE_NAME) {
3068
3070
  }
3069
3071
  }
3070
3072
  /**
3073
+ * The registry to ask, out of the host's configuration.
3074
+ *
3075
+ * `resolved` is what pnpm itself reads now; `registry` is the configured one,
3076
+ * and `null` there means "pnpm's own configuration decides" — in which case the
3077
+ * public registry is the honest guess rather than an error.
3078
+ *
3079
+ * @param registries - the host's answer.
3080
+ * @returns a registry base URL.
3081
+ */
3082
+ function registryOf(registries) {
3083
+ return registries.resolved ?? registries.registry ?? DEFAULT_REGISTRY;
3084
+ }
3085
+ /**
3086
+ * Add one exact version to the profile's release-age exemptions.
3087
+ *
3088
+ * pnpm 11 refuses to install a version published less than `minimumReleaseAge`
3089
+ * ago — 1440 minutes by default — and records the versions it *has* accepted in
3090
+ * `minimumReleaseAgeExclude`. That is why an installed version can be
3091
+ * reinstalled while the next one cannot be installed at all.
3092
+ *
3093
+ * Writing the version the user just asked for into that same list is the
3094
+ * narrowest exemption available: one package, one version, chosen by the person
3095
+ * who pressed the button. Nothing else in the profile is relaxed, and the next
3096
+ * release has to earn its own exemption.
3097
+ *
3098
+ * @param profileDir - the profile directory holding `pnpm-workspace.yaml`.
3099
+ * @param packageName - the package to exempt.
3100
+ * @param version - the exact version to exempt.
3101
+ * @returns whether the file was changed.
3102
+ */
3103
+ async function exemptVersion(profileDir, packageName, version) {
3104
+ const file = `${profileDir}/pnpm-workspace.yaml`;
3105
+ let text;
3106
+ try {
3107
+ text = await readFile(file, "utf8");
3108
+ } catch {
3109
+ return false;
3110
+ }
3111
+ const bullet = ` - ${`${packageName}@${version}`}`;
3112
+ if (text.split("\n").some((line) => line.trimEnd() === bullet)) return false;
3113
+ const header = "minimumReleaseAgeExclude:";
3114
+ await writeFile(file, text.includes(header) ? text.replace(header, `${header}\n${bullet}`) : `${text.replace(/\s*$/, "")}\n\n${header}\n${bullet}\n`, "utf8");
3115
+ return true;
3116
+ }
3117
+ /**
3118
+ * Read the newest published version out of a registry's `latest` document.
3119
+ *
3120
+ * `/<name>/latest` is the one endpoint that answers "what is the newest
3121
+ * release" without pulling the whole packument, and it is what `npm view
3122
+ * <name> version` reads.
3123
+ *
3124
+ * @param query - the registry, the package, and an optional fetch stub.
3125
+ * @returns the version string.
3126
+ * @throws when the registry refuses, answers with a non-JSON body, or carries no
3127
+ * version — each of which must surface as an error rather than as "up to date".
3128
+ */
3129
+ async function latestVersionFrom(query) {
3130
+ const base = query.registry.replace(/\/+$/, "");
3131
+ const path$1 = query.packageName.replace("/", "%2F");
3132
+ const response = await (query.fetchFn ?? fetch)(`${base}/${path$1}/latest`, { headers: { accept: "application/json" } });
3133
+ if (!response.ok) throw new Error(`注册表返回 HTTP ${response.status}`);
3134
+ const version = (await response.json()).version;
3135
+ if (typeof version !== "string" || version === "") throw new Error("注册表返回的文档里没有版本号");
3136
+ return version;
3137
+ }
3138
+ /**
3071
3139
  * Ask the registry what the newest version is, and compare it with ours.
3072
3140
  *
3073
3141
  * Never throws: the settings card has to keep rendering when the registry is
3074
3142
  * unreachable, when the host has no plugin manager, and when this is a local
3075
3143
  * install that has no update to offer.
3076
3144
  *
3077
- * @param deps - the host seam, the running version, and how it was installed.
3145
+ * @param deps - the host seam, the running version, how it was installed, and an
3146
+ * optional fetch stub.
3078
3147
  * @returns the status the card renders.
3079
3148
  */
3080
3149
  async function checkForUpdate(deps) {
@@ -3089,15 +3158,15 @@ async function checkForUpdate(deps) {
3089
3158
  error: "宿主没有提供插件管理服务。"
3090
3159
  };
3091
3160
  try {
3092
- const inspection = await deps.host.inspect(PACKAGE_NAME);
3093
- if (inspection.status !== "accepted" || inspection.version === void 0) return {
3094
- ...base,
3095
- error: inspection.reason ?? "注册表上没有这个包。"
3096
- };
3161
+ const latest = await latestVersionFrom({
3162
+ registry: registryOf(await deps.host.registries()),
3163
+ packageName: PACKAGE_NAME,
3164
+ ...deps.fetchFn === void 0 ? {} : { fetchFn: deps.fetchFn }
3165
+ });
3097
3166
  return {
3098
3167
  ...base,
3099
- latest: inspection.version,
3100
- updateAvailable: isNewer(inspection.version, deps.current)
3168
+ latest,
3169
+ updateAvailable: isNewer(latest, deps.current)
3101
3170
  };
3102
3171
  } catch (error) {
3103
3172
  return {
@@ -3465,9 +3534,22 @@ function makeRoutes(deps) {
3465
3534
  const host = deps.updateHost?.();
3466
3535
  if (host === void 0) return fail(res, 503, "unavailable", "宿主没有提供插件管理服务。");
3467
3536
  if (readInstallKind(profileDirectory()) === "local") return fail(res, 409, "local_install", "这是本地目录安装,更新请用 pnpm build && pnpm sync。");
3468
- ok(res, { started: true });
3537
+ let target;
3538
+ try {
3539
+ target = await latestVersionFrom({
3540
+ registry: registryOf(await host.registries()),
3541
+ packageName: PACKAGE_NAME
3542
+ });
3543
+ await exemptVersion(profileDirectory(), PACKAGE_NAME, target);
3544
+ } catch (error) {
3545
+ console.warn("[dsh-seework] could not resolve or exempt the target version:", error);
3546
+ }
3547
+ ok(res, {
3548
+ started: true,
3549
+ ...target === void 0 ? {} : { to: target }
3550
+ });
3469
3551
  setTimeout(() => {
3470
- host.installBundle(UPDATE_SPEC).catch((error) => {
3552
+ host.installBundle(target === void 0 ? UPDATE_SPEC : `${PACKAGE_NAME}@${target}`).catch((error) => {
3471
3553
  console.warn("[dsh-seework] self-update failed:", error);
3472
3554
  });
3473
3555
  }, 0);
@@ -3894,7 +3976,7 @@ function probeUpdateHost(ctx) {
3894
3976
  const service = ctx.get("pluginManager");
3895
3977
  if (service === null || service === void 0) return void 0;
3896
3978
  const candidate = service;
3897
- if (typeof candidate.inspect !== "function" || typeof candidate.installBundle !== "function") return void 0;
3979
+ if (typeof candidate.registries !== "function" || typeof candidate.installBundle !== "function") return void 0;
3898
3980
  return candidate;
3899
3981
  }
3900
3982
  /**
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "dsh-seework",
3
3
  "description": "SeeWork — DeepSeek Harness plugin for SeeAI Hub: generate images inside the agent conversation with your own SeeAI Hub API key (OpenAI-compatible /v1/images/generations), browse everything you generated in the sidebar material library, and arrange it on a canvas.",
4
- "version": "0.1.2",
4
+ "version": "0.1.4",
5
5
  "license": "MIT",
6
6
  "repository": {
7
7
  "type": "git",