dsh-workbuddy-connect 0.5.3 → 0.5.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/bin.js CHANGED
@@ -1,5 +1,5 @@
1
1
  #!/usr/bin/env node
2
- import { E as WorkBuddyUpstreamClient, J as resolveAppVersion, b as WorkBuddyCredentialStore, f as WORKBUDDY_CONNECT_VERSION, g as FALLBACK_WORKBUDDY_MODELS, h as FALLBACK_WORKBUDDY_AI_MODELS, i as variantFor, l as readHostHeartbeat, n as CN_VARIANT, r as WORKBUDDY_VARIANTS, s as isHeartbeatProcessAlive, u as workbuddyHostHeartbeatPath } from "./variants-CdmzOPIT.js";
2
+ import { E as WorkBuddyUpstreamClient, J as resolveAppVersion, b as WorkBuddyCredentialStore, f as WORKBUDDY_CONNECT_VERSION, g as FALLBACK_WORKBUDDY_MODELS, h as FALLBACK_WORKBUDDY_AI_MODELS, i as variantFor, l as readHostHeartbeat, n as CN_VARIANT, r as WORKBUDDY_VARIANTS, s as isHeartbeatProcessAlive, u as workbuddyHostHeartbeatPath } from "./variants-XUStsapF.js";
3
3
  import { realpathSync } from "node:fs";
4
4
  import { fileURLToPath } from "node:url";
5
5
  //#region src/bin.ts
package/lib/index.d.ts CHANGED
@@ -801,12 +801,12 @@ interface WorkBuddyProbeRecord {
801
801
  *
802
802
  * An effort set is a fact about one account's entitlement as much as about
803
803
  * the model: the same model id can accept different levels under a different
804
- * subscription. Without this a record outlived the account that produced it,
805
- * so signing out and in as someone else inherited the previous account's
806
- * detected levels. Records written before this field existed carry no
807
- * identity and are therefore never reused.
804
+ * subscription. Records are stored under this identity and only ever served
805
+ * back to it, so one account never inherits another's detected levels — and
806
+ * because the store nests by this identity, switching back finds this
807
+ * account's own records intact rather than re-probing from scratch.
808
808
  */
809
- account?: string;
809
+ account: string;
810
810
  }
811
811
  /**
812
812
  * Plugin-owned probe record path inside the Harness home.
@@ -839,8 +839,9 @@ interface WorkBuddyProbeStoreOptions {
839
839
  now?: () => number;
840
840
  }
841
841
  /**
842
- * The plugin's probe records: read once, written atomically, never trusted
843
- * across a fingerprint change or past the TTL.
842
+ * The plugin's probe records: read once, written atomically, keyed by the
843
+ * account that produced each observation, and never trusted across a
844
+ * fingerprint change or past the TTL.
844
845
  */
845
846
  declare class WorkBuddyProbeStore {
846
847
  private readonly path;
@@ -853,24 +854,25 @@ declare class WorkBuddyProbeStore {
853
854
  filePath(): string;
854
855
  private load;
855
856
  /**
856
- * The usable record for a model, or `undefined` when there is none, it is
857
- * expired, it was taken against a different catalog row, or it belongs to a
858
- * different account.
857
+ * The usable record for one account and model, or `undefined` when there is
858
+ * none, it is expired, it was taken against a different catalog row, or it
859
+ * belongs to a different account.
859
860
  *
860
861
  * @param account - the account in effect, as `uid:enterpriseId`. Records are
861
862
  * only returned for the account that produced them.
862
863
  */
863
864
  get(modelId: string, fingerprint: string, account: string): WorkBuddyProbeRecord | undefined;
864
865
  /**
865
- * Store one observation. Only a decisive answer (`validating` /
866
- * `non-validating`) replaces an existing decisive record: a transient
867
- * `unknown` must not erase knowledge the user already paid for.
866
+ * Store one observation under the account stamped on it. Only a decisive
867
+ * answer (`validating` / `non-validating`) replaces an existing decisive
868
+ * record *of the same account*: a transient `unknown` must not erase
869
+ * knowledge the user already paid for.
868
870
  */
869
871
  set(modelId: string, record: WorkBuddyProbeRecord): void;
870
- /** Drop every record; used by the card's explicit "clear" action. */
872
+ /** Drop every record of every account; used by the card's explicit "clear" action. */
871
873
  clear(): void;
872
- /** Every record currently held, for status display. */
873
- all(): Readonly<Record<string, WorkBuddyProbeRecord>>;
874
+ /** Every record currently held, grouped by account, for status display. */
875
+ all(): Readonly<Record<string, Readonly<Record<string, WorkBuddyProbeRecord>>>>;
874
876
  /** Build a record stamped with this store's clock, version, and account. */
875
877
  record(fingerprint: string, validation: WorkBuddyProbeValidation, efforts: readonly WorkBuddyEffort[], account: string): WorkBuddyProbeRecord;
876
878
  /**
@@ -1032,8 +1034,8 @@ interface WorkBuddyProbeServiceOptions {
1032
1034
  * Records are read and written against this identity, and it is re-checked
1033
1035
  * after the sweep finishes: an observation produced under account A must not
1034
1036
  * be stored once account B is in effect, however long the probe took. The
1035
- * caller's `clear()` on an account switch is not sufficient on its own,
1036
- * because an in-flight probe completes *after* that clear.
1037
+ * store's per-account keying alone cannot catch that, because an in-flight
1038
+ * probe completes *after* the switch has already happened.
1037
1039
  */
1038
1040
  account: () => string | undefined;
1039
1041
  sentinel?: SentinelFactory;
package/lib/index.js CHANGED
@@ -1,4 +1,4 @@
1
- import { A as parseModelCatalog, B as fallbackChatIdentity, C as desktopAuthCandidatesFor, D as classifyUpstreamError, E as WorkBuddyUpstreamClient, F as probeModel, G as appUserAgent, H as resolveChatIdentity, I as randomSentinel, J as resolveAppVersion, K as installedAppVersion, L as CN_APP_VERSION_FILENAME, M as prepareInternationalChatBody, N as regionOf, O as modelWithCurrentPromotion, P as PROBE_EFFORT_CANDIDATES, R as FALLBACK_CN_APP_VERSION, S as defaultDesktopAuthPath, T as workbuddyOwnAuthPath, U as validCliVersion, V as readCliVersion, W as WORKBUDDY_APP_VERSION_FILENAME, Y as validAppVersion, _ as WorkBuddyCatalog, a as WORKBUDDY_HOST_HEARTBEAT_FILENAME, b as WorkBuddyCredentialStore, c as processStartTimeMs, d as writeHostHeartbeat, f as WORKBUDDY_CONNECT_VERSION, g as FALLBACK_WORKBUDDY_MODELS, h as FALLBACK_WORKBUDDY_AI_MODELS, i as variantFor, j as prepareChatBody, k as normalizeCredits, l as readHostHeartbeat, n as CN_VARIANT, o as clearHostHeartbeat, q as readBundleVersion, r as WORKBUDDY_VARIANTS, s as isHeartbeatProcessAlive, t as AI_VARIANT, u as workbuddyHostHeartbeatPath, v as WORKBUDDY_AUTH_FILENAME, w as parseWorkBuddyAuth, x as defaultDesktopAuthCandidates, y as WORKBUDDY_AUTH_FILE_ENV, z as chatUserAgent } from "./variants-CdmzOPIT.js";
1
+ import { A as parseModelCatalog, B as fallbackChatIdentity, C as desktopAuthCandidatesFor, D as classifyUpstreamError, E as WorkBuddyUpstreamClient, F as probeModel, G as appUserAgent, H as resolveChatIdentity, I as randomSentinel, J as resolveAppVersion, K as installedAppVersion, L as CN_APP_VERSION_FILENAME, M as prepareInternationalChatBody, N as regionOf, O as modelWithCurrentPromotion, P as PROBE_EFFORT_CANDIDATES, R as FALLBACK_CN_APP_VERSION, S as defaultDesktopAuthPath, T as workbuddyOwnAuthPath, U as validCliVersion, V as readCliVersion, W as WORKBUDDY_APP_VERSION_FILENAME, Y as validAppVersion, _ as WorkBuddyCatalog, a as WORKBUDDY_HOST_HEARTBEAT_FILENAME, b as WorkBuddyCredentialStore, c as processStartTimeMs, d as writeHostHeartbeat, f as WORKBUDDY_CONNECT_VERSION, g as FALLBACK_WORKBUDDY_MODELS, h as FALLBACK_WORKBUDDY_AI_MODELS, i as variantFor, j as prepareChatBody, k as normalizeCredits, l as readHostHeartbeat, n as CN_VARIANT, o as clearHostHeartbeat, q as readBundleVersion, r as WORKBUDDY_VARIANTS, s as isHeartbeatProcessAlive, t as AI_VARIANT, u as workbuddyHostHeartbeatPath, v as WORKBUDDY_AUTH_FILENAME, w as parseWorkBuddyAuth, x as defaultDesktopAuthCandidates, y as WORKBUDDY_AUTH_FILE_ENV, z as chatUserAgent } from "./variants-XUStsapF.js";
2
2
  import z from "@deepseek-ai/schemastery";
3
3
  import { dirname, join, resolve } from "node:path";
4
4
  import { resolveDshHome } from "@deepseek-ai/dsh-home-paths";
@@ -656,8 +656,17 @@ function createWorkBuddyShim(options) {
656
656
  */
657
657
  /** Basename of the probe record inside the Harness home. */
658
658
  const WORKBUDDY_PROBE_FILENAME = ".workbuddy-probe.json";
659
- /** On-disk format this reader accepts; other versions are discarded. */
660
- const PROBE_FORMAT_VERSION = 1;
659
+ /**
660
+ * On-disk format this reader accepts; other versions are discarded.
661
+ *
662
+ * Version 2 nested the records under the account that produced them
663
+ * (`records[account][modelId]`), so two accounts no longer overwrite each
664
+ * other's observations for the same model. Version 1 files (flat, one record
665
+ * per model) are deliberately not migrated: they read as empty and the
666
+ * affected models are re-probed on demand, which keeps the reader free of
667
+ * half-understood compatibility paths.
668
+ */
669
+ const PROBE_FORMAT_VERSION = 2;
661
670
  /**
662
671
  * How long an observation stays usable. Conservative on purpose: the plan's
663
672
  * whole argument is that upstream metadata moves fast, so a result that has
@@ -718,13 +727,15 @@ function isRecord(value) {
718
727
  if (typeof wrapped["fingerprint"] !== "string") return false;
719
728
  if (typeof wrapped["probedAtMs"] !== "number" || !Number.isFinite(wrapped["probedAtMs"])) return false;
720
729
  if (typeof wrapped["pluginVersion"] !== "string") return false;
730
+ if (typeof wrapped["account"] !== "string" || wrapped["account"] === "") return false;
721
731
  const efforts = wrapped["efforts"];
722
732
  if (!Array.isArray(efforts) || efforts.some((effort) => typeof effort !== "string")) return false;
723
733
  return true;
724
734
  }
725
735
  /**
726
- * The plugin's probe records: read once, written atomically, never trusted
727
- * across a fingerprint change or past the TTL.
736
+ * The plugin's probe records: read once, written atomically, keyed by the
737
+ * account that produced each observation, and never trusted across a
738
+ * fingerprint change or past the TTL.
728
739
  */
729
740
  var WorkBuddyProbeStore = class {
730
741
  path;
@@ -750,21 +761,26 @@ var WorkBuddyProbeStore = class {
750
761
  if (this.records === void 0) {
751
762
  const document = readDocument(this.path);
752
763
  const records = {};
753
- for (const [id, record] of Object.entries(document?.records ?? {})) if (isRecord(record)) records[id] = record;
764
+ for (const [account, bucket] of Object.entries(document?.records ?? {})) {
765
+ if (typeof bucket !== "object" || bucket === null || Array.isArray(bucket)) continue;
766
+ const parsed = {};
767
+ for (const [modelId, record] of Object.entries(bucket)) if (isRecord(record)) parsed[modelId] = record;
768
+ records[account] = parsed;
769
+ }
754
770
  this.records = records;
755
771
  }
756
772
  return this.records;
757
773
  }
758
774
  /**
759
- * The usable record for a model, or `undefined` when there is none, it is
760
- * expired, it was taken against a different catalog row, or it belongs to a
761
- * different account.
775
+ * The usable record for one account and model, or `undefined` when there is
776
+ * none, it is expired, it was taken against a different catalog row, or it
777
+ * belongs to a different account.
762
778
  *
763
779
  * @param account - the account in effect, as `uid:enterpriseId`. Records are
764
780
  * only returned for the account that produced them.
765
781
  */
766
782
  get(modelId, fingerprint, account) {
767
- const record = this.load()[modelId];
783
+ const record = this.load()[account]?.[modelId];
768
784
  if (record === void 0) return void 0;
769
785
  if (record.fingerprint !== fingerprint) return void 0;
770
786
  if (record.account !== account) return void 0;
@@ -772,25 +788,28 @@ var WorkBuddyProbeStore = class {
772
788
  return record;
773
789
  }
774
790
  /**
775
- * Store one observation. Only a decisive answer (`validating` /
776
- * `non-validating`) replaces an existing decisive record: a transient
777
- * `unknown` must not erase knowledge the user already paid for.
791
+ * Store one observation under the account stamped on it. Only a decisive
792
+ * answer (`validating` / `non-validating`) replaces an existing decisive
793
+ * record *of the same account*: a transient `unknown` must not erase
794
+ * knowledge the user already paid for.
778
795
  */
779
796
  set(modelId, record) {
780
797
  const records = this.load();
781
- const existing = records[modelId];
798
+ const bucket = records[record.account] ?? (records[record.account] = {});
799
+ const existing = bucket[modelId];
782
800
  if (record.validation === "unknown" && existing !== void 0 && existing.fingerprint === record.fingerprint && existing.validation !== "unknown") return;
783
- records[modelId] = record;
801
+ bucket[modelId] = record;
784
802
  this.persist();
785
803
  }
786
- /** Drop every record; used by the card's explicit "clear" action. */
804
+ /** Drop every record of every account; used by the card's explicit "clear" action. */
787
805
  clear() {
788
806
  this.records = {};
789
807
  this.persist();
790
808
  }
791
- /** Every record currently held, for status display. */
809
+ /** Every record currently held, grouped by account, for status display. */
792
810
  all() {
793
- return { ...this.load() };
811
+ const records = this.load();
812
+ return Object.fromEntries(Object.entries(records).map(([account, bucket]) => [account, { ...bucket }]));
794
813
  }
795
814
  /** Build a record stamped with this store's clock, version, and account. */
796
815
  record(fingerprint, validation, efforts, account) {
@@ -1552,13 +1571,12 @@ function apply(ctx, config) {
1552
1571
  * transition bumps {@link VariantRuntime.catalogGeneration}, which is what
1553
1572
  * makes an in-flight request from before the change refuse to write back.
1554
1573
  *
1555
- * Probe observations are dropped whenever the account actually changes —
1556
- * including sign-out, and including the "signed out, then in as someone else"
1557
- * sequence that used to look like a first sighting and let the new account
1558
- * inherit the old one's detected levels. They are deliberately NOT cleared on
1559
- * a first sign-in: no previous account's data could leak there, and clearing
1560
- * would delete records this very account owns (written before a restart, or
1561
- * seeded while all of this is running).
1574
+ * Probe observations are kept across an account change: the store nests them
1575
+ * per account, so the departing account's records simply stop being served
1576
+ * (every read is account-scoped) and are found intact if that account
1577
+ * returns. The "signed out, then in as someone else" sequence that used to
1578
+ * look like a first sighting is still safe — a record only ever answers for
1579
+ * the account stamped on it, so the new account inherits nothing.
1562
1580
  *
1563
1581
  * @param identity - the account now in effect, or `undefined` when signed out.
1564
1582
  */
@@ -1572,10 +1590,7 @@ function apply(ctx, config) {
1572
1590
  runtime.catalogGeneration += 1;
1573
1591
  runtime.inflightFetch?.controller.abort();
1574
1592
  runtime.inflightFetch = void 0;
1575
- if (hadCredential && known !== identity) {
1576
- runtime.probeStore.clear();
1577
- runtime.invalidate();
1578
- }
1593
+ if (hadCredential && known !== identity) runtime.invalidate();
1579
1594
  if (identity === void 0) {
1580
1595
  if (known !== void 0) runtime.savedCatalogs.delete(known);
1581
1596
  runtime.catalog.set(runtime.fallback);
@@ -2479,7 +2479,7 @@ const WORKBUDDY_AI_STATUS_PATH = "/plugins/dsh-workbuddy-connect/ai/status";
2479
2479
  const WORKBUDDY_AI_PROBE_PATH = "/plugins/dsh-workbuddy-connect/ai/probe";
2480
2480
  //#endregion
2481
2481
  //#region src/version.ts
2482
- const WORKBUDDY_CONNECT_VERSION = "0.5.3";
2482
+ const WORKBUDDY_CONNECT_VERSION = "0.5.4";
2483
2483
  //#endregion
2484
2484
  //#region src/host-heartbeat.ts
2485
2485
  /**
package/package.json CHANGED
@@ -2,7 +2,7 @@
2
2
  "name": "dsh-workbuddy-connect",
3
3
  "displayName": "DSH WorkBuddy Connect",
4
4
  "description": "将 WorkBuddy 桌面 App 包含的模型自动接入 DeepSeek Harness — bring WorkBuddy desktop app models into DeepSeek Harness with zero configuration.",
5
- "version": "0.5.3",
5
+ "version": "0.5.4",
6
6
  "author": "corrinehu",
7
7
  "keywords": [
8
8
  "dsh-plugin",