@jxgame2020/dsh-token-quota 0.1.17 → 0.1.18

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/client.js CHANGED
@@ -79,7 +79,7 @@ window.__ModuleLoader__.load({
79
79
  d.dimWhenIdle = dimWhenIdle;
80
80
  },
81
81
  setUpgrade: (d, upgrade) => {
82
- const normalized = upgrade !== null && upgrade.latestVersion !== "" && upgrade.latestVersion !== "0.1.17" ? upgrade : null;
82
+ const normalized = upgrade !== null && upgrade.latestVersion !== "" && upgrade.latestVersion !== "0.1.18" ? upgrade : null;
83
83
  if (d.upgrade === null || d.upgrade.latestVersion !== normalized?.latestVersion) d.upgradeDismissed = false;
84
84
  d.upgrade = normalized;
85
85
  },
@@ -185,91 +185,91 @@ window.__ModuleLoader__.load({
185
185
  document.head.appendChild(tag);
186
186
  }
187
187
  var TokenQuotaPanel_module_css_default = {
188
- "logPager": "NPLLIq_logPager",
189
- "logToolbar": "NPLLIq_logToolbar",
190
- "radioRow": "NPLLIq_radioRow",
191
- "dialogClose": "NPLLIq_dialogClose",
192
- "gearBtn": "NPLLIq_gearBtn",
188
+ "tabIcon": "NPLLIq_tabIcon",
189
+ "upgradeCommands": "NPLLIq_upgradeCommands",
190
+ "versionNew": "NPLLIq_versionNew",
191
+ "checkErrorHint": "NPLLIq_checkErrorHint",
192
+ "collapse": "NPLLIq_collapse",
193
+ "rowName": "NPLLIq_rowName",
194
+ "upgradeBannerFlash": "NPLLIq_upgradeBannerFlash",
195
+ "dialogHint": "NPLLIq_dialogHint",
193
196
  "panelDim": "NPLLIq_panelDim",
194
- "fillIdle": "NPLLIq_fillIdle",
195
- "monitorHint": "NPLLIq_monitorHint",
196
- "logPagerControls": "NPLLIq_logPagerControls",
197
- "currentBadge": "NPLLIq_currentBadge",
198
- "tabLabel": "NPLLIq_tabLabel",
199
- "dialogTitle": "NPLLIq_dialogTitle",
197
+ "upgradeHint": "NPLLIq_upgradeHint",
198
+ "logPagerInfo": "NPLLIq_logPagerInfo",
199
+ "resetSelect": "NPLLIq_resetSelect",
200
200
  "logClearDialog": "NPLLIq_logClearDialog",
201
- "checkUpdatesLabel": "NPLLIq_checkUpdatesLabel",
202
- "settingsBtn": "NPLLIq_settingsBtn",
203
- "dialogActions": "NPLLIq_dialogActions",
204
- "logPageSizeSelect": "NPLLIq_logPageSizeSelect",
205
- "rowName": "NPLLIq_rowName",
206
- "logHeader": "NPLLIq_logHeader",
207
- "row": "NPLLIq_row",
208
- "checkUpdatesRow": "NPLLIq_checkUpdatesRow",
209
- "panel": "NPLLIq_panel",
210
- "copyBtn": "NPLLIq_copyBtn",
211
- "dialogLabel": "NPLLIq_dialogLabel",
212
- "upgradeCommand": "NPLLIq_upgradeCommand",
213
- "logSearch": "NPLLIq_logSearch",
214
- "version": "NPLLIq_version",
215
- "logDialog": "NPLLIq_logDialog",
216
- "rowMeta": "NPLLIq_rowMeta",
201
+ "dialogClose": "NPLLIq_dialogClose",
217
202
  "selectBtn": "NPLLIq_selectBtn",
218
- "dialogOverlay": "NPLLIq_dialogOverlay",
219
- "controls": "NPLLIq_controls",
220
- "fullNotice": "NPLLIq_fullNotice",
221
- "upgradeBannerFlash": "NPLLIq_upgradeBannerFlash",
222
- "dialog": "NPLLIq_dialog",
223
- "upgradeCommands": "NPLLIq_upgradeCommands",
224
- "copyBtnDone": "NPLLIq_copyBtnDone",
225
- "input": "NPLLIq_input",
203
+ "logClearDate": "NPLLIq_logClearDate",
204
+ "rowMeta": "NPLLIq_rowMeta",
205
+ "tabLabel": "NPLLIq_tabLabel",
206
+ "dialogSection": "NPLLIq_dialogSection",
207
+ "copyBtn": "NPLLIq_copyBtn",
208
+ "resetRow": "NPLLIq_resetRow",
209
+ "dialogActions": "NPLLIq_dialogActions",
210
+ "fillOver": "NPLLIq_fillOver",
211
+ "save": "NPLLIq_save",
212
+ "logModelCol": "NPLLIq_logModelCol",
213
+ "fillIdle": "NPLLIq_fillIdle",
226
214
  "header": "NPLLIq_header",
227
- "tabIcon": "NPLLIq_tabIcon",
215
+ "logUsedCol": "NPLLIq_logUsedCol",
216
+ "radioRow": "NPLLIq_radioRow",
217
+ "dialogBtn": "NPLLIq_dialogBtn",
218
+ "body": "NPLLIq_body",
228
219
  "monitorName": "NPLLIq_monitorName",
229
- "checkBtn": "NPLLIq_checkBtn",
230
- "rowHeader": "NPLLIq_rowHeader",
231
- "panelDimStrong": "NPLLIq_panelDimStrong",
232
- "bar": "NPLLIq_bar",
233
- "save": "NPLLIq_save",
234
- "upgradeClose": "NPLLIq_upgradeClose",
235
- "dialogHeader": "NPLLIq_dialogHeader",
236
- "upgradeBanner": "NPLLIq_upgradeBanner",
237
- "resetRow": "NPLLIq_resetRow",
238
- "notice": "NPLLIq_notice",
239
- "logClearDate": "NPLLIq_logClearDate",
220
+ "dialog": "NPLLIq_dialog",
240
221
  "switch": "NPLLIq_switch",
241
- "headerActions": "NPLLIq_headerActions",
242
- "logModelCol": "NPLLIq_logModelCol",
243
- "dialogBtnPrimary": "NPLLIq_dialogBtnPrimary",
244
- "checkErrorHint": "NPLLIq_checkErrorHint",
245
- "logPagerPages": "NPLLIq_logPagerPages",
246
- "dialogSection": "NPLLIq_dialogSection",
247
- "monitorRow": "NPLLIq_monitorRow",
222
+ "currentBadge": "NPLLIq_currentBadge",
223
+ "subtitle": "NPLLIq_subtitle",
224
+ "upgradeBanner": "NPLLIq_upgradeBanner",
225
+ "copyBtnDone": "NPLLIq_copyBtnDone",
226
+ "checkUpdatesRow": "NPLLIq_checkUpdatesRow",
248
227
  "logScroll": "NPLLIq_logScroll",
249
- "logTable": "NPLLIq_logTable",
250
- "logClearBtn": "NPLLIq_logClearBtn",
251
- "headerText": "NPLLIq_headerText",
252
- "fillWarn": "NPLLIq_fillWarn",
228
+ "logToolbar": "NPLLIq_logToolbar",
229
+ "logPagerControls": "NPLLIq_logPagerControls",
230
+ "logPageSizeSelect": "NPLLIq_logPageSizeSelect",
231
+ "logDialog": "NPLLIq_logDialog",
253
232
  "logDayCol": "NPLLIq_logDayCol",
254
- "logPagerBtn": "NPLLIq_logPagerBtn",
255
- "collapse": "NPLLIq_collapse",
256
- "dialogHint": "NPLLIq_dialogHint",
257
233
  "monitorList": "NPLLIq_monitorList",
258
- "logPagerInfo": "NPLLIq_logPagerInfo",
259
- "title": "NPLLIq_title",
260
- "subtitle": "NPLLIq_subtitle",
261
- "logUsedCol": "NPLLIq_logUsedCol",
234
+ "panelDimStrong": "NPLLIq_panelDimStrong",
235
+ "monitorHint": "NPLLIq_monitorHint",
236
+ "logTable": "NPLLIq_logTable",
237
+ "logPager": "NPLLIq_logPager",
238
+ "dialogOverlay": "NPLLIq_dialogOverlay",
262
239
  "noticeError": "NPLLIq_noticeError",
263
- "dialogBody": "NPLLIq_dialogBody",
264
- "body": "NPLLIq_body",
265
- "dialogBtn": "NPLLIq_dialogBtn",
266
- "fillOver": "NPLLIq_fillOver",
267
- "upgradeCommandRow": "NPLLIq_upgradeCommandRow",
268
- "upgradeHint": "NPLLIq_upgradeHint",
269
240
  "tab": "NPLLIq_tab",
270
241
  "upgradeBannerText": "NPLLIq_upgradeBannerText",
271
- "resetSelect": "NPLLIq_resetSelect",
272
- "versionNew": "NPLLIq_versionNew"
242
+ "logClearBtn": "NPLLIq_logClearBtn",
243
+ "notice": "NPLLIq_notice",
244
+ "fillWarn": "NPLLIq_fillWarn",
245
+ "upgradeCommand": "NPLLIq_upgradeCommand",
246
+ "dialogHeader": "NPLLIq_dialogHeader",
247
+ "title": "NPLLIq_title",
248
+ "logSearch": "NPLLIq_logSearch",
249
+ "controls": "NPLLIq_controls",
250
+ "input": "NPLLIq_input",
251
+ "logHeader": "NPLLIq_logHeader",
252
+ "settingsBtn": "NPLLIq_settingsBtn",
253
+ "upgradeCommandRow": "NPLLIq_upgradeCommandRow",
254
+ "dialogBtnPrimary": "NPLLIq_dialogBtnPrimary",
255
+ "logPagerBtn": "NPLLIq_logPagerBtn",
256
+ "panel": "NPLLIq_panel",
257
+ "version": "NPLLIq_version",
258
+ "upgradeClose": "NPLLIq_upgradeClose",
259
+ "headerText": "NPLLIq_headerText",
260
+ "fullNotice": "NPLLIq_fullNotice",
261
+ "logPagerPages": "NPLLIq_logPagerPages",
262
+ "headerActions": "NPLLIq_headerActions",
263
+ "rowHeader": "NPLLIq_rowHeader",
264
+ "bar": "NPLLIq_bar",
265
+ "dialogTitle": "NPLLIq_dialogTitle",
266
+ "checkUpdatesLabel": "NPLLIq_checkUpdatesLabel",
267
+ "gearBtn": "NPLLIq_gearBtn",
268
+ "monitorRow": "NPLLIq_monitorRow",
269
+ "checkBtn": "NPLLIq_checkBtn",
270
+ "dialogLabel": "NPLLIq_dialogLabel",
271
+ "dialogBody": "NPLLIq_dialogBody",
272
+ "row": "NPLLIq_row"
273
273
  };
274
274
  //#endregion
275
275
  //#region lib/types/client/TokenQuotaPanel.js
@@ -572,13 +572,13 @@ window.__ModuleLoader__.load({
572
572
  title: t("upgradeAvailableHint"),
573
573
  children: [
574
574
  "v",
575
- "0.1.17",
575
+ "0.1.18",
576
576
  " → v",
577
577
  upgrade.latestVersion
578
578
  ]
579
579
  }) : (0, react_jsx_runtime.jsxs)("span", {
580
580
  className: TokenQuotaPanel_module_css_default.version,
581
- children: ["v", "0.1.17"]
581
+ children: ["v", "0.1.18"]
582
582
  })]
583
583
  }), (0, react_jsx_runtime.jsx)("div", {
584
584
  className: TokenQuotaPanel_module_css_default.subtitle,
package/lib/index.js CHANGED
@@ -1,5 +1,5 @@
1
1
  import { assertTokenQuotaLimit, splitTokenQuotaKey } from "./invariant.js";
2
- import { existsSync, mkdirSync, readFileSync, readdirSync, writeFileSync } from "node:fs";
2
+ import { mkdirSync, readFileSync, readdirSync, statSync, writeFileSync } from "node:fs";
3
3
  import { homedir } from "node:os";
4
4
  import { dirname, join } from "node:path";
5
5
  import { Service } from "@deepseek-ai/cordis";
@@ -91,13 +91,54 @@ function registryUpgradeCommands(profileDir, manager) {
91
91
  function linkUpgradeCommands(linkPath) {
92
92
  return [`git -C "${linkPath}" pull`];
93
93
  }
94
- /** Detect the profile's package manager from its lockfiles; defaults to npm. */
94
+ /**
95
+ * Detect the profile's package manager; defaults to npm.
96
+ *
97
+ * Lockfiles alone are unreliable: a profile can accumulate several of them over
98
+ * time (e.g. a leftover `pnpm-lock.yaml` next to a fresh `package-lock.json`
99
+ * after switching from pnpm to npm), and a bare existence check then reports
100
+ * the WRONG manager. Instead, look at the installer fingerprints inside
101
+ * `node_modules` — each manager leaves a marker when it actually installs —
102
+ * and pick the most recently touched one. Only if no marker exists fall back
103
+ * to comparing lockfile mtimes.
104
+ */
95
105
  function detectManager(dir) {
96
- if (existsSync(join(dir, "pnpm-lock.yaml"))) return "pnpm";
97
- if (existsSync(join(dir, "yarn.lock"))) return "yarn";
98
- if (existsSync(join(dir, "package-lock.json"))) return "npm";
99
- if (existsSync(join(dir, "bun.lockb")) || existsSync(join(dir, "bun.lock"))) return "bun";
100
- return "npm";
106
+ const stat = (path) => {
107
+ try {
108
+ return statSync(path).mtimeMs;
109
+ } catch {
110
+ return;
111
+ }
112
+ };
113
+ const fingerprints = [
114
+ ["node_modules/.pnpm", "pnpm"],
115
+ ["node_modules/.bun", "bun"],
116
+ ["node_modules/.package-lock.json", "npm"],
117
+ ["node_modules/.yarn-integrity", "yarn"]
118
+ ];
119
+ let best;
120
+ for (const [rel, manager] of fingerprints) {
121
+ const mtime = stat(join(dir, rel));
122
+ if (mtime !== void 0 && (best === void 0 || mtime > best.mtime)) best = {
123
+ manager,
124
+ mtime
125
+ };
126
+ }
127
+ if (best !== void 0) return best.manager;
128
+ for (const [rel, manager] of [
129
+ ["pnpm-lock.yaml", "pnpm"],
130
+ ["yarn.lock", "yarn"],
131
+ ["package-lock.json", "npm"],
132
+ ["bun.lockb", "bun"],
133
+ ["bun.lock", "bun"]
134
+ ]) {
135
+ const mtime = stat(join(dir, rel));
136
+ if (mtime !== void 0 && (best === void 0 || mtime > best.mtime)) best = {
137
+ manager,
138
+ mtime
139
+ };
140
+ }
141
+ return best?.manager ?? "npm";
101
142
  }
102
143
  /**
103
144
  * Locate the profile directory that declares this plugin as a dependency, along
@@ -116,7 +157,11 @@ function findProfile() {
116
157
  for (const name of names) {
117
158
  const dir = join(profilesDir, name);
118
159
  const manifestPath = join(dir, "package.json");
119
- if (!existsSync(manifestPath)) continue;
160
+ try {
161
+ if (!statSync(manifestPath).isFile()) continue;
162
+ } catch {
163
+ continue;
164
+ }
120
165
  let manifest;
121
166
  try {
122
167
  manifest = JSON.parse(readFileSync(manifestPath, "utf8"));
@@ -409,7 +454,7 @@ var TokenQuotaService = class TokenQuotaService extends Service {
409
454
  return this.upgradeCheck;
410
455
  }
411
456
  async doRefreshUpgrade() {
412
- const current = "0.1.17";
457
+ const current = "0.1.18";
413
458
  let latest;
414
459
  try {
415
460
  const response = await fetch(REGISTRY_LATEST_URL, {
@@ -29,7 +29,7 @@
29
29
  *
30
30
  * @module @jxgame2020/dsh-token-quota
31
31
  */
32
- import { existsSync, mkdirSync, readdirSync, readFileSync, writeFileSync } from 'node:fs';
32
+ import { mkdirSync, readdirSync, readFileSync, statSync, writeFileSync } from 'node:fs';
33
33
  import { homedir } from 'node:os';
34
34
  import { dirname, join } from 'node:path';
35
35
  import { Service } from '@deepseek-ai/cordis';
@@ -76,17 +76,57 @@ function registryUpgradeCommands(profileDir, manager) {
76
76
  function linkUpgradeCommands(linkPath) {
77
77
  return [`git -C "${linkPath}" pull`];
78
78
  }
79
- /** Detect the profile's package manager from its lockfiles; defaults to npm. */
79
+ /**
80
+ * Detect the profile's package manager; defaults to npm.
81
+ *
82
+ * Lockfiles alone are unreliable: a profile can accumulate several of them over
83
+ * time (e.g. a leftover `pnpm-lock.yaml` next to a fresh `package-lock.json`
84
+ * after switching from pnpm to npm), and a bare existence check then reports
85
+ * the WRONG manager. Instead, look at the installer fingerprints inside
86
+ * `node_modules` — each manager leaves a marker when it actually installs —
87
+ * and pick the most recently touched one. Only if no marker exists fall back
88
+ * to comparing lockfile mtimes.
89
+ */
80
90
  function detectManager(dir) {
81
- if (existsSync(join(dir, 'pnpm-lock.yaml')))
82
- return 'pnpm';
83
- if (existsSync(join(dir, 'yarn.lock')))
84
- return 'yarn';
85
- if (existsSync(join(dir, 'package-lock.json')))
86
- return 'npm';
87
- if (existsSync(join(dir, 'bun.lockb')) || existsSync(join(dir, 'bun.lock')))
88
- return 'bun';
89
- return 'npm';
91
+ const stat = (path) => {
92
+ try {
93
+ return statSync(path).mtimeMs;
94
+ }
95
+ catch {
96
+ return undefined;
97
+ }
98
+ };
99
+ // Installer fingerprints inside node_modules, by manager.
100
+ const fingerprints = [
101
+ ['node_modules/.pnpm', 'pnpm'],
102
+ ['node_modules/.bun', 'bun'],
103
+ ['node_modules/.package-lock.json', 'npm'],
104
+ ['node_modules/.yarn-integrity', 'yarn'],
105
+ ];
106
+ let best;
107
+ for (const [rel, manager] of fingerprints) {
108
+ const mtime = stat(join(dir, rel));
109
+ if (mtime !== undefined && (best === undefined || mtime > best.mtime)) {
110
+ best = { manager, mtime };
111
+ }
112
+ }
113
+ if (best !== undefined)
114
+ return best.manager;
115
+ // Fallback: the most recently modified lockfile.
116
+ const lockfiles = [
117
+ ['pnpm-lock.yaml', 'pnpm'],
118
+ ['yarn.lock', 'yarn'],
119
+ ['package-lock.json', 'npm'],
120
+ ['bun.lockb', 'bun'],
121
+ ['bun.lock', 'bun'],
122
+ ];
123
+ for (const [rel, manager] of lockfiles) {
124
+ const mtime = stat(join(dir, rel));
125
+ if (mtime !== undefined && (best === undefined || mtime > best.mtime)) {
126
+ best = { manager, mtime };
127
+ }
128
+ }
129
+ return best?.manager ?? 'npm';
90
130
  }
91
131
  /**
92
132
  * Locate the profile directory that declares this plugin as a dependency, along
@@ -108,8 +148,13 @@ function findProfile() {
108
148
  for (const name of names) {
109
149
  const dir = join(profilesDir, name);
110
150
  const manifestPath = join(dir, 'package.json');
111
- if (!existsSync(manifestPath))
151
+ try {
152
+ if (!statSync(manifestPath).isFile())
153
+ continue;
154
+ }
155
+ catch {
112
156
  continue;
157
+ }
113
158
  let manifest;
114
159
  try {
115
160
  manifest = JSON.parse(readFileSync(manifestPath, 'utf8'));
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@jxgame2020/dsh-token-quota",
3
3
  "description": "Daily per-model token quota accounting, enforcement, and a floating quota panel for the DeepSeek Harness — a fully self-contained plugin (no core-Harness wiring, no generated RPC contract)",
4
- "version": "0.1.17",
4
+ "version": "0.1.18",
5
5
  "publishConfig": {
6
6
  "access": "public"
7
7
  },