@ckyueix/glm-usage 0.0.0-stage → 0.1.1

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/LICENSE ADDED
@@ -0,0 +1,128 @@
1
+ # CKYUEIX Software License
2
+
3
+ **Free Use — Restricted Redistribution**
4
+
5
+ Version 1.0
6
+
7
+ Copyright © 2026 ckyueix. All rights reserved.
8
+
9
+ ### 1. Scope and Acceptance
10
+
11
+ This license applies to software packages or distributions expressly provided with this license by their copyright holder (the "Licensor"), collectively referred to as the "Software".
12
+
13
+ A software package is covered only when the Licensor expressly includes this license with that package. Other products from the same developer are not automatically covered.
14
+
15
+ By exercising the permissions granted under this license, you agree to its terms. If you do not agree, you may not exercise those permissions.
16
+
17
+ Nothing in this license restricts rights that applicable law grants independently of this license.
18
+
19
+ ### 2. License Grant
20
+
21
+ Subject to compliance with this license, the Licensor grants you a worldwide, non-exclusive, royalty-free, perpetual license, subject to termination under Section 8, to:
22
+
23
+ a. Download, install, run, and use the Software for personal, educational, research, and commercial purposes.
24
+
25
+ b. Deploy the Software on multiple devices or systems within your organization.
26
+
27
+ c. Make copies reasonably necessary for internal deployment, backup, recovery, testing, and maintenance.
28
+
29
+ d. Privately modify the Software for your own or your organization's internal use.
30
+
31
+ e. Allow employees and contractors acting on your behalf to use or maintain the Software for authorized purposes.
32
+
33
+ f. Use the Software to operate commercial services, including hosted services, without transferring copies of the Software to customers except as permitted under Section 3.
34
+
35
+ No license fee is required for these activities.
36
+
37
+ ### 3. Professional Services and Customer Deployment
38
+
39
+ You may charge for consulting, installation, configuration, maintenance, hosting, and other professional services involving the Software.
40
+
41
+ A service provider may install or configure the Software on a customer's infrastructure when:
42
+
43
+ a. The customer independently receives the right to use the Software under this license.
44
+
45
+ b. The Software is obtained through the official distribution channel or a permitted package mirror or cache.
46
+
47
+ c. The service provider acts on the customer's behalf and does not independently sell, sublicense, or market copies of the Software.
48
+
49
+ Transfers strictly necessary for an authorized customer installation are permitted.
50
+
51
+ Fees for professional services do not constitute prohibited resale merely because the services involve the Software.
52
+
53
+ Providing customers with access to services powered by the Software, without transferring copies, is permitted.
54
+
55
+ ### 4. Redistribution Restrictions
56
+
57
+ Unless expressly permitted by this license or separately authorized in writing by the Licensor, you may not:
58
+
59
+ a. Redistribute, republish, upload, host, sell, rent, sublicense, or otherwise make copies of the Software available to third parties, whether free of charge or for payment.
60
+
61
+ b. Publicly distribute or publish modified versions of the Software.
62
+
63
+ c. Bundle or incorporate copies of the Software into products, installers, or software distributions supplied to third parties.
64
+
65
+ d. Misrepresent the Software's authorship, ownership, or official distribution status.
66
+
67
+ **Permitted Distribution Infrastructure**
68
+
69
+ The restrictions above do not prohibit:
70
+
71
+ - Distribution through the official package registry or other channels authorized by the Licensor.
72
+ - Automated mirroring, caching, and proxying of unmodified official package artifacts through ordinary package-management infrastructure for acquisition, installation, updates, or recovery.
73
+ - Internal package repositories, organizational caching, and authorized internal deployment.
74
+ - Technical transfers necessary for customer installations permitted under Section 3.
75
+
76
+ Applicable copyright and license notices must be preserved.
77
+
78
+ Charging for package-management infrastructure or professional services is permitted. These exceptions do not authorize independently marketing, reselling, or publishing modified copies of the Software as a separate product.
79
+
80
+ ### 5. Ownership and Third-Party Rights
81
+
82
+ The Licensor and other applicable rights holders retain ownership of their respective intellectual property.
83
+
84
+ This license does not grant ownership of the Software, access to private source code repositories, or rights to the Licensor's trademarks, logos, or endorsements.
85
+
86
+ You must preserve applicable copyright and license notices.
87
+
88
+ Third-party components remain subject to their respective licenses.
89
+
90
+ ### 6. Disclaimer of Warranties
91
+
92
+ TO THE MAXIMUM EXTENT PERMITTED BY APPLICABLE LAW, THE SOFTWARE IS PROVIDED "AS IS" AND "AS AVAILABLE", WITHOUT WARRANTIES OF ANY KIND, EXPRESS, IMPLIED, OR STATUTORY.
93
+
94
+ THE LICENSOR DISCLAIMS ALL WARRANTIES, INCLUDING MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND UNINTERRUPTED OR ERROR-FREE OPERATION.
95
+
96
+ THE LICENSOR HAS NO OBLIGATION TO PROVIDE SUPPORT, MAINTENANCE, OR UPDATES UNLESS SEPARATELY AGREED IN WRITING.
97
+
98
+ ### 7. Limitation of Liability
99
+
100
+ TO THE MAXIMUM EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSOR SHALL NOT BE LIABLE FOR ANY DAMAGES ARISING OUT OF OR RELATING TO THE SOFTWARE, ITS USE, OR INABILITY TO USE, WHETHER DIRECT, INDIRECT, INCIDENTAL, SPECIAL, CONSEQUENTIAL, EXEMPLARY, OR PUNITIVE, UNDER ANY LEGAL THEORY, INCLUDING CONTRACT, TORT, OR NEGLIGENCE.
101
+
102
+ THIS INCLUDES, WITHOUT LIMITATION, LOSS OF DATA, PROFITS, BUSINESS, OR SERVICE AVAILABILITY.
103
+
104
+ NOTHING IN THIS LICENSE EXCLUDES OR LIMITS LIABILITY THAT CANNOT LAWFULLY BE EXCLUDED OR LIMITED.
105
+
106
+ ### 8. Termination
107
+
108
+ If you materially violate this license, the Licensor may terminate your rights if you fail to remedy the violation within 30 calendar days after receiving written notice.
109
+
110
+ Conduct expressly prohibited by this license is not authorized during any cure period.
111
+
112
+ Upon effective termination, you must cease unauthorized use and distribution and remove copies under your control, except those required to be retained by applicable law. Legally retained copies may not be used unless independently authorized.
113
+
114
+ Termination of your rights does not automatically terminate licenses independently obtained by other users.
115
+
116
+ Ownership, warranty disclaimers, liability limitations, and provisions intended by their nature to survive termination remain effective.
117
+
118
+ ### 9. Additional Permissions and General Terms
119
+
120
+ Activities not authorized by this license require the Licensor's prior affirmative written permission.
121
+
122
+ Requests for additional permissions may be directed through the licensing contact identified in the official package metadata or an official release page designated by the Licensor.
123
+
124
+ Silence or failure to respond does not constitute authorization.
125
+
126
+ If any provision is held invalid or unenforceable, the remaining provisions continue in effect to the maximum extent permitted by applicable law.
127
+
128
+ All rights not expressly granted are reserved by the Licensor.
package/README.md CHANGED
@@ -1,3 +1,79 @@
1
- # Temporary Holding Version
1
+ # @ckyueix/glm-usage — GLM Usage (GLM 用量)
2
2
 
3
- This version is a temporary placeholder for this package. An operational version to replace this has been submitted for review and is awaiting a staged release.
3
+ A DeepSeek Harness (DSH) plugin that adds a compact **GLM Coding Plan usage pill**
4
+ to the native conversation composer dock (`conversation.composer.dock`, new row
5
+ id `ckyueix-glm-quota`, order 2 — the shipped `activity` / `usage` rows are never
6
+ replaced). Collapsed it shows the weekly-limit percentage of the GLM Coding
7
+ Plan account bound to the session's current provider; clicking expands the
8
+ 5-hour / weekly windows, remaining / total quota, reset times and the data
9
+ timestamp in your local timezone.
10
+
11
+ ## 0.1.1
12
+
13
+ Preserves the Host method parameter names required by DSH's Remote Gateway.
14
+ This fixes the packaged 0.1.0 build's `gateway/arguments-invalid` error. The
15
+ packed Host and Client are regression-tested together through the real Gateway
16
+ with synthetic quota responses; no account credentials are included.
17
+
18
+ ## License
19
+
20
+ Free to use, including commercial use. Redistribution, resale, and publishing
21
+ modified versions are restricted; see [LICENSE](./LICENSE) for the exact terms.
22
+
23
+ For requests for additional permissions, including redistribution authorization,
24
+ contact **ckyueix@gmail.com**. This is the public licensing contact for this
25
+ package.
26
+
27
+ ## Requirements
28
+
29
+ - DeepSeek Harness **0.2.1-rc.2** (`engines.dsh` is enforced; other host
30
+ versions are untested).
31
+ - A configured GLM Coding Plan provider (Zhipu `open.bigmodel.cn` coding-plan
32
+ routes, e.g. the built-in `zai-coding-cn` China route or explicit
33
+ `openai-completions` profiles).
34
+
35
+ Non-GLM providers render nothing; no request is made for them. Credentials are
36
+ resolved only inside the DSH host process and never reach the browser client.
37
+
38
+ ## Install
39
+
40
+ Install through DSH's plugin management (Plugins → Add plugin, or a plugin
41
+ market index that lists this package). After installing, open or reload a
42
+ conversation: the pill appears beside the native activity / usage stats.
43
+
44
+ ## Refresh interval
45
+
46
+ Default **60 seconds**. Configure under Plugins →
47
+ `@ckyueix/glm-usage` → refresh interval (seconds), allowed range
48
+ 60–86400. The value controls the host cache and the client's refresh
49
+ scheduling.
50
+
51
+ ## Optional configuration (profile patch)
52
+
53
+ ```yaml
54
+ - id: glm-usage
55
+ name: '@ckyueix/glm-usage'
56
+ config:
57
+ providers: # explicit providerId -> credential-ref binding
58
+ my-glm-account: MY_GLM_API_KEY_ENV
59
+ autoDiscover: true # exact official HTTPS routes only
60
+ ttlMs: 60000 # 60000–86400000
61
+ minIntervalMs: 60000
62
+ timeoutMs: 10000
63
+ ```
64
+
65
+ ## Security boundary
66
+
67
+ - The quota endpoint is fixed (`https://open.bigmodel.cn/api/monitor/usage/quota/limit`,
68
+ GET); URLs supplied by callers are never fetched.
69
+ - The browser client only ever receives whitelisted fields (percentages,
70
+ totals, reset timestamps); raw upstream responses, messages, credentials and
71
+ stack traces never cross the remote boundary.
72
+ - Provider admission is fail-closed: only exact official HTTPS hostnames, the
73
+ catalog-verified built-in `zai-coding-cn` default route, or explicit
74
+ ref-matched bindings are queried.
75
+
76
+ ## Source
77
+
78
+ The source of this plugin is maintained in a private repository; this package
79
+ is the built release artifact.
@@ -0,0 +1,7 @@
1
+ # Loader patch for @ckyueix/glm-usage.
2
+ # Mounts the host half as the Cordis service entry `glm-usage`; the package's
3
+ # `dsh.client` declaration additionally serves `lib/client.js` to the Web UI,
4
+ # where it registers the `ckyueix-glm-quota` row of `conversation.composer.dock`.
5
+ - insert:
6
+ - id: glm-usage
7
+ name: '@ckyueix/glm-usage'
package/dist/client.js ADDED
@@ -0,0 +1,13 @@
1
+ window.__ModuleLoader__.load({id:"@ckyueix/glm-usage",factory:require=>{var module={exports:{}},exports=module.exports;let react=require("react"),zodModule=require("zod");const zod=zodModule.z??zodModule,createElement=react.createElement,useSyncExternalStore=react.useSyncExternalStore,useEffect=react.useEffect;let dialogRuntime;function createTypertRemoteInfo(spec,zod2){return new RemoteInfo(spec,zod2)}var RemoteInfo=class{spec;zod;index;constructor(spec,zod2){this.spec=spec,this.zod=zod2}get package(){return this.spec.package}get descriptors(){return this.resolve().descriptors}get methods(){return this.resolve().methods}resolve(){if(this.index!==void 0)return this.index;const zod2=this.zod,descriptors=[],methods=Object.create(null);for(const[endpoint,definition]of Object.entries(this.spec.methods)){const separator=endpoint.indexOf("/"),namespace=endpoint.slice(0,separator),method=endpoint.slice(separator+1),parameters=definition.parameters.map(parameter=>({...parameter,wire:parameter.wire??parameter.name})),descriptor={...definition,id:`${this.spec.package}#${endpoint}`,namespace,method,parameters,result:definition.result.description===void 0?definition.result:new ResultValue(definition.result)};if(definition.invocation.kind==="direct"){const inputs=[];methods[endpoint]=Object.assign(descriptor,{input(options){const strict=options?.strict===!0;return inputs[strict?1:0]??=new NamedInput(parameters,strict,zod2)},invoke(remote,input,signal){const named=input,values=parameters.map(parameter=>named[parameter.wire]);definition.cancellation!==void 0&&values.push(signal);const receiver=Reflect.get(remote,namespace);return Reflect.get(receiver,method).apply(receiver,values)}})}descriptors.push(descriptor)}return this.index={descriptors,methods}}};function optional(parameter){return parameter.source==="json"&&parameter.acceptsUndefined===!0}var NamedInput=class{parameters;strict;zod;schema;projection;constructor(parameters,strict,zod2){this.parameters=parameters,this.strict=strict,this.zod=zod2}codec(parameter){return this.strict?parameter.strictCodec:parameter.codec}create=()=>this.schema??=this.zod.strictObject(Object.fromEntries(this.parameters.map(parameter=>{const value=this.codec(parameter).create();return[parameter.wire,optional(parameter)?value.optional():value.nonoptional()]})));get jsonSchema(){return this.project().jsonSchema}get jsonSchemaError(){return this.project().jsonSchemaError}project(){if(this.projection!==void 0)return this.projection;const unavailable=this.parameters.find(parameter=>this.codec(parameter).jsonSchema===void 0);return unavailable!==void 0?this.projection={jsonSchemaError:this.codec(unavailable).jsonSchemaError??`No JSON Schema for parameter ${unavailable.wire}`}:this.projection={jsonSchema:{type:"object",properties:Object.fromEntries(this.parameters.map(parameter=>[parameter.wire,{...this.codec(parameter).jsonSchema,...parameter.description===void 0?{}:{description:parameter.description}}])),required:this.parameters.filter(parameter=>!optional(parameter)).map(parameter=>parameter.wire),additionalProperties:!1}}}},ResultValue=class{spec;projection;constructor(spec){this.spec=spec}get mode(){return this.spec.mode}get typeSymbol(){return this.spec.typeSymbol}get create(){return this.spec.create}get decode(){return this.spec.decode}get encode(){return this.spec.encode}get description(){return this.spec.description}get jsonSchemaError(){return this.spec.jsonSchemaError}get jsonSchema(){if(this.projection===void 0){const schema=this.spec.jsonSchema;this.projection={value:schema===void 0?void 0:{...schema,description:this.spec.description}}}return this.projection.value}};const TYPERT_REMOTE_SPEC=Object.freeze({package:"@ckyueix/glm-usage",methods:Object.freeze({"glmQuota/get":Object.freeze({service:"glmQuota",description:"Read the GLM Coding Plan quota whitelist snapshot for the session-selected provider.",invocation:Object.freeze({kind:"direct"}),parameters:Object.freeze([Object.freeze({name:"providerId",description:"session-selected provider id (never a model name).",source:"json",codec:Object.freeze({mode:"strict",typeSymbol:"@ckyueix/glm-usage/types#GlmProviderId",create:()=>zod.string().min(1).max(200),jsonSchema:Object.freeze({type:"string",minLength:1,maxLength:200})}),strictCodec:Object.freeze({mode:"strict",typeSymbol:"@ckyueix/glm-usage/types#GlmProviderId",create:()=>zod.string().min(1).max(200),jsonSchema:Object.freeze({type:"string",minLength:1,maxLength:200})})}),Object.freeze({name:"options",description:"optional read options; force bypasses cache/cooldown once.",source:"json",acceptsUndefined:!0,codec:Object.freeze({mode:"strict",typeSymbol:"@ckyueix/glm-usage/types#GlmReadOptions",create:()=>zod.strictObject({force:zod.boolean().optional()}).optional(),jsonSchema:Object.freeze({type:"object",properties:Object.freeze({force:Object.freeze({type:"boolean"})}),additionalProperties:!1})}),strictCodec:Object.freeze({mode:"strict",typeSymbol:"@ckyueix/glm-usage/types#GlmReadOptions",create:()=>zod.strictObject({force:zod.boolean().optional()}).optional(),jsonSchema:Object.freeze({type:"object",properties:Object.freeze({force:Object.freeze({type:"boolean"})}),additionalProperties:!1})})})]),result:Object.freeze({mode:"strict",typeSymbol:"@ckyueix/glm-usage/types#GlmQuotaPayload",create:()=>zod.looseObject({status:zod.string(),provider:zod.string()}),description:"whitelist payload; never carries credentials, upstream messages, or raw bodies.",jsonSchema:Object.freeze({type:"object",properties:Object.freeze({status:Object.freeze({type:"string"}),provider:Object.freeze({type:"string"})}),required:Object.freeze(["status","provider"])})})})})}),TYPERT_REMOTE=createTypertRemoteInfo(TYPERT_REMOTE_SPEC,zod),NS="glmQuota",DICT=Object.freeze({zh:Object.freeze({"pill.fiveHour":"5\u65F6","pill.weekly":"\u5468","pill.used":"\u5DF2\u7528","pill.inactive":"\u672A\u6FC0\u6D3B","pill.loading":"\u67E5\u8BE2\u4E2D\u2026","pill.error":"\u914D\u989D\u4E0D\u53EF\u7528","pill.staleAt":"\u6570\u636E\u65F6\u95F4","pill.stale":"\u65E7\u6570\u636E","pill.weeklyLimit":"\u5468\u9650","pill.details":"GLM \u7528\u91CF","pill.expand":"GLM \u7528\u91CF\u8BE6\u60C5","pill.account":"\u8D26\u53F7","pill.fiveHourUsed":"5 \u5C0F\u65F6\u5DF2\u7528","pill.weeklyUsed":"\u5468\u9650\u5DF2\u7528","pill.fiveHourBudget":"5 \u5C0F\u65F6\u5269\u4F59 / \u603B\u989D","pill.weeklyBudget":"\u5468\u9650\u5269\u4F59 / \u603B\u989D","pill.fiveHourReset":"5 \u5C0F\u65F6\u91CD\u7F6E","pill.weeklyReset":"\u5468\u9650\u91CD\u7F6E","config.interval":"\u5237\u65B0\u95F4\u9694\uFF08\u79D2\uFF09","config.hint":"\u9ED8\u8BA4 60 \u79D2\uFF0C\u6700\u77ED 60 \u79D2\uFF0C\u6700\u957F 86400 \u79D2\u3002\u540C\u6B65\u63A7\u5236 Host \u7F13\u5B58\u4E0E\u53EF\u89C1\u9875\u9762\u5237\u65B0\uFF1B\u9690\u85CF\u9875\u9762\u6682\u505C\u5237\u65B0\u3002\u7559\u7A7A\u53EF\u6062\u590D\u9ED8\u8BA4\u3002","config.invalid":"\u8BF7\u8F93\u5165 60\u201386400 \u4E4B\u95F4\u7684\u6574\u6570\u79D2\u6570\u3002","config.overridden":"\u5DF2\u81EA\u5B9A\u4E49","config.reset":"\u6062\u590D\u9ED8\u8BA4","config.save":"\u4FDD\u5B58","config.saving":"\u4FDD\u5B58\u4E2D\u2026","config.unavailable":"\u5F53\u524D Host \u65E0\u6CD5\u63D0\u4F9B\u6B64\u63D2\u4EF6\u914D\u7F6E\u3002","config.readOnly":"\u5F53\u524D\u914D\u7F6E\u53EA\u8BFB\u3002","config.saveFailed":"\u4FDD\u5B58\u5931\u8D25\uFF0C\u8BF7\u91CD\u8BD5\u3002"}),en:Object.freeze({"pill.fiveHour":"5h","pill.weekly":"wk","pill.used":"used","pill.inactive":"inactive","pill.loading":"loading\u2026","pill.error":"quota unavailable","pill.staleAt":"as of","pill.stale":"stale","pill.weeklyLimit":"Week","pill.details":"GLM usage","pill.expand":"GLM usage details","pill.account":"Account","pill.fiveHourUsed":"5-hour used","pill.weeklyUsed":"Weekly used","pill.fiveHourBudget":"5-hour left / total","pill.weeklyBudget":"Weekly left / total","pill.fiveHourReset":"5-hour reset","pill.weeklyReset":"Weekly reset","config.interval":"Refresh interval (seconds)","config.hint":"Default/minimum 60 seconds; maximum 86400. Controls Host caching and visible-page refresh together. Hidden pages pause refresh. Clear to restore the default.","config.invalid":"Enter a whole number of seconds from 60 to 86400.","config.overridden":"Customized","config.reset":"Restore default","config.save":"Save","config.saving":"Saving\u2026","config.unavailable":"Plugin configuration is unavailable on this Host.","config.readOnly":"Configuration is read-only.","config.saveFailed":"Save failed. Please try again."})});function formatClock(ms){const dt=new Date(ms),pad=n=>String(n).padStart(2,"0");return dt.getFullYear()+"-"+pad(dt.getMonth()+1)+"-"+pad(dt.getDate())+" "+pad(dt.getHours())+":"+pad(dt.getMinutes())}const SNAPSHOT_TTL_MS=6e4,REFRESH_RETRY_MS=6e4,pageVisible=()=>typeof document<"u"&&document.visibilityState==="visible",validTtl=value=>Number.isInteger(value)&&value>=6e4&&value<=864e5,snapshotExpired=(snapshot,ttlMs)=>typeof snapshot.fetchedAt!="number"||!Number.isFinite(snapshot.fetchedAt)||Date.now()-snapshot.fetchedAt>=ttlMs;function registerConfiguration(ctx,controller,t){const scope=ctx.configForms.get("glm-usage"),unbind=controller.bindConfig(scope);let form;try{let RefreshSettings2=function(){const snapshot=useSyncExternalStore(state.subscribe,state.getSnapshot),id=react.useId();return createElement(SettingsForm,{state:snapshot,labels:Object.fromEntries(["unavailable","readOnly","saveFailed","save","saving"].map(key=>[key,t("config."+key)])),onSave:actions.save,onDiscard:actions.discard},createElement(SettingsValueField,{id,label:t("config.interval"),hint:t("config.hint"),numeric:!0,...snapshot.interval,overriddenLabel:t("config.overridden"),resetLabel:t("config.reset"),invalidLabel:t("config.invalid"),disabled:!snapshot.writable||snapshot.saving,onEdit:text=>actions.edit("ttlMs",text),onReset:()=>actions.resetField("ttlMs")}))};var RefreshSettings=RefreshSettings2;const{SettingsFormModel,SettingsForm,SettingsValueField}=require("@deepseek-ai/dsh-client-ui-primitives");if(![SettingsFormModel,SettingsForm,SettingsValueField].every(value=>typeof value=="function"))throw new Error("native settings runtime unavailable");form=new SettingsFormModel(scope,[{field:"ttlMs",format:value=>String((value??SNAPSHOT_TTL_MS)/1e3),parse:text=>{if(text.trim()==="")return{kind:"clear"};const seconds=Number(text);return Number.isInteger(seconds)&&validTtl(seconds*1e3)?{kind:"set",value:seconds*1e3}:void 0}}]);const state=form.bind(()=>({...form.shell(),interval:form.field("ttlMs")})),actions=form.actions();ctx.slots.inject("plugins.bundle.config",()=>ctx.slots.register({name:"plugins.bundle.config",key:"@ckyueix/glm-usage",locale:NS},RefreshSettings2))}catch{form?.dispose(),form=void 0,console.error("ckyueix-glm-quota: native settings editor unavailable; quota display retained")}return()=>{form?.dispose(),unbind()}}class QuotaController{constructor(ctx){this.remote=ctx.remote,this.listeners=new Set,this.snapshots=new Map,this.pending=new Map,this.generations=new Map,this.retryAt=new Map,this.watchers=new Set,this.ttlMs=SNAPSHOT_TTL_MS,this.configReady=!1,this.disposed=!1}setTtl(value){this.disposed||!validTtl(value)||this.ttlMs===value||(this.ttlMs=value,this.#notify())}bindConfig(scope){const accept=()=>{const snapshot=scope.getSnapshot();snapshot.status!=="ready"||!validTtl(snapshot.value?.ttlMs)||(this.configReady=!0,this.setTtl(snapshot.value.ttlMs))},unsubscribe=scope.subscribe(accept);return accept(),unsubscribe}dispose(){this.disposed=!0;for(const cleanup of[...this.watchers])cleanup();this.listeners.clear(),this.snapshots.clear(),this.pending.clear(),this.retryAt.clear()}subscribe(listener){return this.listeners.add(listener),()=>this.listeners.delete(listener)}#notify(){for(const listener of[...this.listeners])listener()}snapshotOf(providerId){const existing=this.snapshots.get(providerId);if(existing!==void 0)return existing;const fresh={phase:"loading",provider:providerId};return this.snapshots.set(providerId,fresh),fresh}watch(providerId){if(this.disposed||providerId===null)return()=>{};let active=!0,timer,focusListening=!1,reconciling=!1,unsubscribe=()=>{};const clearTimer=()=>{clearTimeout(timer),timer=void 0},listenForFocus=enabled=>{enabled!==focusListening&&(focusListening=enabled,enabled?window.addEventListener("focus",reconcile):window.removeEventListener("focus",reconcile))},cleanup=()=>{active&&(active=!1,clearTimer(),listenForFocus(!1),document.removeEventListener("visibilitychange",reconcile),unsubscribe(),this.watchers.delete(cleanup))},reconcile=()=>{if(!(!active||reconciling)){reconciling=!0;try{if(clearTimer(),this.disposed||this.snapshotOf(providerId).phase==="hidden"){cleanup();return}const visible=pageVisible();if(listenForFocus(visible),!visible||(this.ensureFresh(providerId),this.pending.has(providerId)))return;const current=this.snapshotOf(providerId),due=current.phase==="ok"&&!current.stale&&!snapshotExpired(current,this.ttlMs)?current.fetchedAt+this.ttlMs:this.retryAt.get(providerId)??Date.now()+REFRESH_RETRY_MS;timer=setTimeout(reconcile,Math.max(1,due-Date.now()))}finally{reconciling=!1}}};return this.watchers.add(cleanup),unsubscribe=this.subscribe(reconcile),document.addEventListener("visibilitychange",reconcile),reconcile(),cleanup}ensureFresh(providerId){if(this.disposed||providerId===null||!pageVisible())return;const current=this.snapshotOf(providerId);if(current.phase==="hidden")return;const aged=current.phase==="ok"&&!current.stale&&snapshotExpired(current,this.ttlMs);if(aged&&this.snapshots.set(providerId,{...current,stale:!0}),current.phase==="ok"&&!current.stale&&!aged)return;if(this.pending.has(providerId)||Date.now()<(this.retryAt.get(providerId)??0)){aged&&this.#notify();return}this.retryAt.set(providerId,Date.now()+REFRESH_RETRY_MS);const generation=(this.generations.get(providerId)??0)+1;this.generations.set(providerId,generation);let dispatched=!1;const promise=Promise.resolve().then(()=>{if(!(this.disposed||!pageVisible()))return dispatched=!0,this.remote.glmQuota.get(providerId,void 0)}).then(result=>{if(!dispatched||this.disposed||this.generations.get(providerId)!==generation)return;const payload=result!==null&&typeof result=="object"&&result.ok===!0?result.value:null;payload===null||typeof payload!="object"||payload.provider!==providerId?this.snapshots.set(providerId,{phase:"error",provider:providerId,at:Date.now()}):(this.configReady||this.setTtl(payload.ttlMs),this.snapshots.set(providerId,this.#project(payload))),this.#notify()}).catch(()=>{this.disposed||this.generations.get(providerId)!==generation||(this.snapshots.set(providerId,{phase:"error",provider:providerId,at:Date.now()}),this.#notify())}).finally(()=>{this.disposed||this.generations.get(providerId)!==generation||(this.pending.delete(providerId),dispatched?this.retryAt.set(providerId,Date.now()+REFRESH_RETRY_MS):this.retryAt.delete(providerId),this.#notify())});this.pending.set(providerId,promise),aged&&this.#notify()}#project(payload){return payload===null||typeof payload!="object"?{phase:"error",provider:"",at:Date.now()}:payload.status==="ok"?{phase:"ok",provider:payload.provider,fetchedAt:payload.fetchedAt,stale:payload.stale===!0||snapshotExpired(payload,this.ttlMs),windows:{fiveHour:payload.windows?.fiveHour??null,weekly:payload.windows?.weekly??null}}:payload.status==="not_glm"?{phase:"hidden",provider:payload.provider}:{phase:"error",provider:payload.provider,at:Date.now()}}}function QuotaPill(props){const controller=props.controller,useProjection=props.useProjection;if(controller===void 0||useProjection===void 0)return null;const selection=useProjection("modelSelection",face=>face==null?null:face.next??face.lastUsed??null),providerId=selection===null?null:selection.provider,snapshot=useSyncExternalStore(listener=>controller.subscribe(listener),()=>providerId===null?HIDDEN_EMPTY:controller.snapshotOf(providerId));return useEffect(()=>controller.watch(providerId),[controller,providerId]),providerId===null?null:createElement(PillView,{snapshot,t:props.t,onOpen:()=>controller.ensureFresh(providerId)})}const NATIVE_DOCK_STYLE=Object.freeze({fontSize:"12px",lineHeight:"20px",color:"var(--dsw-alias-label-tertiary, var(--dsh-boot-label-tertiary))"}),DIALOG_CSS=`
2
+ .ckyueix-glm-quota{display:inline-flex;min-width:0}
3
+ .ckyueix-glm-quota-button{box-sizing:border-box;border-radius:var(--dsw-radius-sm);max-width:100%;color:inherit;font:inherit;font-variant-numeric:tabular-nums;line-height:inherit;white-space:nowrap;background:transparent;border:0;align-items:center;gap:6px;padding:1px 8px;display:inline-flex;cursor:pointer}
4
+ .ckyueix-glm-quota-icon{width:14px;height:14px;flex-shrink:0}
5
+ .ckyueix-glm-quota-button:hover,.ckyueix-glm-quota-button[aria-expanded=true]{background:var(--dsw-alias-interactive-bg-hover);color:var(--dsw-alias-label-secondary)}
6
+ .ckyueix-glm-quota-panel{z-index:1100;box-sizing:border-box;border-radius:var(--dsw-radius-lg);background:var(--dsw-specific-menu);width:max-content;min-width:min(300px,100vw - 24px);max-width:min(440px,100vw - 24px);max-height:calc(100dvh - 24px);overflow:auto;backdrop-filter:var(--dsw-menu-backdrop-filter);--dsw-elevation-stroke-color:var(--dsw-alias-border-l1);box-shadow:var(--dsw-elevation-prominent);color:var(--dsw-alias-label-secondary);cursor:default;border:0;padding:16px;font-size:12px;line-height:18px;position:fixed}
7
+ .ckyueix-glm-quota-title{color:var(--dsw-alias-label-primary);margin-bottom:8px;font-weight:500}
8
+ .ckyueix-glm-quota-rule{border-top:.5px solid var(--dsw-alias-border-l2);margin-bottom:10px}
9
+ .ckyueix-glm-quota-details{color:var(--dsw-alias-label-tertiary);grid-template-columns:minmax(76px,auto) minmax(0,1fr);gap:6px 16px;margin:0;display:grid}
10
+ .ckyueix-glm-quota-details dt,.ckyueix-glm-quota-details dd{min-width:0;margin:0}
11
+ .ckyueix-glm-quota-details dd{color:var(--dsw-alias-label-secondary);font-variant-numeric:tabular-nums;text-align:right;overflow-wrap:anywhere}
12
+ .ckyueix-glm-quota-stale{color:var(--dsw-alias-label-tertiary);margin-bottom:10px}
13
+ `;function installDialogStyles(){if(typeof document>"u"||document.head===void 0)return()=>{};const tag=document.createElement("style");return tag.dataset.pluginCss="@ckyueix/glm-usage/dialog",tag.textContent=DIALOG_CSS,document.head.appendChild(tag),()=>tag.remove()}function useQuotaDialog(provider,enabled){const[expandedProvider,setExpandedProvider]=react.useState(null),rootRef=react.useRef(null),panelRef=react.useRef(null),panelId=react.useId(),open=enabled&&expandedProvider===provider,setOpen=react.useCallback(next=>{setExpandedProvider(previous=>(typeof next=="function"?next(previous===provider):next)?provider:null)},[provider]),pos=dialogRuntime.useAnchoredPosition({open,anchorRef:rootRef,panelRef,side:"top",gap:8,margin:12});return dialogRuntime.useDismissOnOutsidePointer(rootRef,open,setOpen,panelRef),useEffect(()=>{setExpandedProvider(null)},[provider,enabled]),useEffect(()=>{if(!open||typeof document>"u")return;const onKeyDown=event=>{event.key==="Escape"&&(setOpen(!1),rootRef.current?.querySelector("button")?.focus())},onClick=event=>{typeof Node<"u"&&event.target instanceof Node&&rootRef.current?.contains(event.target)!==!0&&panelRef.current?.contains(event.target)!==!0&&setOpen(!1)};return document.addEventListener("keydown",onKeyDown),document.addEventListener("click",onClick,!0),()=>{document.removeEventListener("keydown",onKeyDown),document.removeEventListener("click",onClick,!0)}},[open,setOpen]),{open,setOpen,rootRef,panelRef,panelId,pos}}function percentText(window2){return typeof window2?.usedPercent=="number"&&Number.isFinite(window2.usedPercent)&&window2.usedPercent>=0&&window2.usedPercent<=100?window2.usedPercent+"%":"\u2014"}function quotaIcon(){return createElement("svg",{className:"ckyueix-glm-quota-icon",width:14,height:14,viewBox:"0 0 16 16",fill:"none",stroke:"currentColor",strokeWidth:1.25,strokeLinecap:"round",strokeLinejoin:"round","aria-hidden":!0,focusable:"false"},createElement("path",{d:"M8 1.75V8h6.25A6.25 6.25 0 0 0 8 1.75Z"}),createElement("path",{d:"M5.5 2.27A6.25 6.25 0 1 0 13.73 10.5"}))}function quotaDetails(snapshot,t){const rows=[],row=(key,label,value)=>{rows.push(createElement("dt",{key:key+"-label"},label),createElement("dd",{key,"data-ckyueix-quota-detail":key},value))};row("account",t("pill.account"),snapshot.provider);for(const[key,used,budget,reset]of[["fiveHour","pill.fiveHourUsed","pill.fiveHourBudget","pill.fiveHourReset"],["weekly","pill.weeklyUsed","pill.weeklyBudget","pill.weeklyReset"]]){const window2=snapshot.windows?.[key];row(key+"-used",t(used),percentText(window2));const validAmount=value=>typeof value=="number"&&Number.isFinite(value)&&value>=0;if(validAmount(window2?.remaining)||validAmount(window2?.total)){const amount=value=>validAmount(value)?value.toLocaleString("en-US"):"\u2014";row(key+"-budget",t(budget),amount(window2.remaining)+" / "+amount(window2.total)+(window2.type==="CREDIT_LIMIT"?" Credit":" Token"))}row(key+"-reset",t(reset),window2?.active===!1?t("pill.inactive"):typeof window2?.resetMs=="number"&&Number.isFinite(window2.resetMs)?formatClock(window2.resetMs):"\u2014")}return row("fetchedAt",t("pill.staleAt"),typeof snapshot.fetchedAt=="number"&&Number.isFinite(snapshot.fetchedAt)?formatClock(snapshot.fetchedAt):"\u2014"),createElement("dl",{className:"ckyueix-glm-quota-details"},...rows)}function PillView({snapshot,t,onOpen}){const dialog=useQuotaDialog(snapshot?.provider??null,snapshot?.phase==="ok");if(snapshot==null||snapshot.phase==="hidden")return null;if(snapshot.phase==="loading")return createElement("span",{"data-ckyueix-glm-quota":"loading",className:"ckyueix-glm-quota",style:NATIVE_DOCK_STYLE},t("pill.loading"));if(snapshot.phase==="error"){const title=t("pill.error")+(snapshot.at!==void 0?" \xB7 "+t("pill.staleAt")+" "+formatClock(snapshot.at):"");return createElement("span",{"data-ckyueix-glm-quota":"error",className:"ckyueix-glm-quota",style:NATIVE_DOCK_STYLE,title},"\u26A0 "+t("pill.error"))}const label=t("pill.weeklyLimit")+" "+percentText(snapshot.windows?.weekly);return createElement("span",{ref:dialog.rootRef,"data-ckyueix-glm-quota":snapshot.stale===!0?"stale":"ok",className:"ckyueix-glm-quota",style:NATIVE_DOCK_STYLE,title:(snapshot.stale?t("pill.stale")+" \xB7 ":"")+t("pill.staleAt")+" "+formatClock(snapshot.fetchedAt)},createElement("button",{type:"button",className:"ckyueix-glm-quota-button","aria-haspopup":"dialog","aria-expanded":dialog.open,"aria-controls":dialog.panelId,"aria-label":t("pill.expand"),onClick:()=>{const next=!dialog.open;dialog.setOpen(next),next&&onOpen?.()}},quotaIcon(),createElement("span",null,(snapshot.stale===!0?"\u26A0 ":"")+label)),dialog.open?dialogRuntime.createPortal(createElement("div",{ref:dialog.panelRef,id:dialog.panelId,className:"ckyueix-glm-quota-panel",role:"dialog","aria-label":t("pill.details"),style:dialog.pos??{visibility:"hidden",left:0,top:0}},createElement("div",{className:"ckyueix-glm-quota-title"},t("pill.details")),createElement("div",{className:"ckyueix-glm-quota-rule","aria-hidden":!0}),snapshot.stale===!0?createElement("div",{className:"ckyueix-glm-quota-stale"},"\u26A0 "+t("pill.stale")):null,quotaDetails(snapshot,t)),document.body):null)}const HIDDEN_EMPTY=Object.freeze({phase:"hidden",provider:""}),inject=["remote","slots","locale"];async function apply(ctx){try{const primitives=require("@deepseek-ai/dsh-client-ui-primitives"),dom=require("react-dom");if(typeof primitives.useAnchoredPosition!="function"||typeof primitives.useDismissOnOutsidePointer!="function"||typeof dom.createPortal!="function")throw new Error("dialog runtime unavailable");dialogRuntime={useAnchoredPosition:primitives.useAnchoredPosition,useDismissOnOutsidePointer:primitives.useDismissOnOutsidePointer,createPortal:dom.createPortal}}catch{return console.error("ckyueix-glm-quota: native dialog runtime unavailable; dock entry disabled"),()=>{}}ctx.effect(installDialogStyles,"glm-quota: dialog styles"),ctx.effect(()=>ctx.locale.register(NS,DICT),"glm-quota: dictionaries");let unmountRemote;try{unmountRemote=await ctx.remote.$mount(TYPERT_REMOTE)}catch(error){return console.error("ckyueix-glm-quota: remote namespace mount failed; dock entry disabled",error),()=>{}}let disposed=!1;const disposeSelf=async()=>{if(!disposed){disposed=!0;try{await unmountRemote()}catch(error){console.error("ckyueix-glm-quota: remote namespace unmount failed",error)}}};let ui;try{if(ctx.get("remote.glmQuota")===void 0)throw new Error("namespace remote.glmQuota missing after $mount");ui=ctx.inject(["remote","remote.glmQuota","slots","locale"],registerUi),await ui}catch(error){console.error("ckyueix-glm-quota: dock registration failed; feature disabled",error);try{await ui?.dispose?.()}catch{}return await disposeSelf(),()=>{}}return async()=>{try{await ui.dispose()}finally{await disposeSelf()}}}function registerUi(ctx){const controller=new QuotaController(ctx),t=ctx.locale.bind(NS),configuration=ctx.inject(["configForms","slots"],child=>registerConfiguration(child,controller,t));return Promise.resolve(configuration).catch(()=>console.error("ckyueix-glm-quota: native configuration mirror unavailable")),ctx.slots.inject("conversation.composer.dock",function*(){yield ctx.slots.register({name:"conversation.composer.dock",id:"ckyueix-glm-quota",order:2,locale:NS,inject:()=>({controller,t})},QuotaPill)}),async()=>{try{await configuration.dispose()}finally{controller.dispose()}}}return exports.apply=apply,exports.inject=inject,exports.remoteSpec=TYPERT_REMOTE_SPEC,module.exports}});
package/dist/index.js ADDED
@@ -0,0 +1 @@
1
+ import{TypertRemoteService}from"@deepseek-ai/dsh-typert-protocol";import z from"@deepseek-ai/schemastery";var QUOTA_ENDPOINT="https://open.bigmodel.cn/api/monitor/usage/quota/limit",QuotaError=Object.freeze({BAD_JSON:"bad_json",API_REJECTED:"api_rejected",NO_DATA:"no_data",NO_WINDOWS:"no_windows"}),WINDOW_UNITS=Object.freeze({hours:3,week:6});function amountOf(value){return typeof value=="number"&&Number.isFinite(value)?value:typeof value=="string"&&value.trim()!==""&&Number.isFinite(Number(value))?Number(value):null}function usedPercentOf(value){let n=amountOf(value);return n===null||n<0||n>100?null:Math.round(n)}function projectLimit(item){if(typeof item!="object"||item===null||item.type!=="TOKENS_LIMIT"&&item.type!=="CREDIT_LIMIT")return null;let usedPercent=usedPercentOf(item.percentage);if(usedPercent===null)return null;let total=amountOf(item.usage),remaining=amountOf(item.remaining),resetRaw=amountOf(item.nextResetTime),resetMs=resetRaw!==null&&resetRaw>0?Math.round(resetRaw):null,active=usedPercent>0||resetMs!==null;return Object.freeze({type:item.type,usedPercent,...total!==null?{total}:{},...remaining!==null?{remaining}:{},...resetMs!==null?{resetMs}:{},active})}function pickWindow(items){let token=items.find(w=>w.type==="TOKENS_LIMIT");return token!==void 0?token:items.find(w=>w.type==="CREDIT_LIMIT")??null}function parseQuotaResponse(body){let parsed;try{let text=typeof body=="string"?body:new TextDecoder().decode(body);parsed=JSON.parse(text)}catch{return{ok:!1,error:QuotaError.BAD_JSON}}if(typeof parsed!="object"||parsed===null)return{ok:!1,error:QuotaError.BAD_JSON};if(parsed.success!==!0)return{ok:!1,error:QuotaError.API_REJECTED};let data=parsed.data;if(typeof data!="object"||data===null||Array.isArray(data))return{ok:!1,error:QuotaError.NO_DATA};let pairs=(Array.isArray(data.limits)?data.limits:[]).map(item=>[item,projectLimit(item)]).filter(([,window])=>window!==null),fiveHourRaw=[],weeklyRaw=[];for(let[item,window]of pairs){let unit=amountOf(item.unit),number_=amountOf(item.number);unit===WINDOW_UNITS.hours&&number_===5?fiveHourRaw.push(window):unit===WINDOW_UNITS.week&&weeklyRaw.push(window)}let fiveHour=pickWindow(fiveHourRaw),weekly=pickWindow(weeklyRaw);return fiveHour===null&&weekly===null?{ok:!1,error:QuotaError.NO_WINDOWS}:{ok:!0,level:typeof data.level=="string"&&data.level.length>0?data.level:null,windows:{fiveHour,weekly}}}function buildPayload(providerId,parsed,fetchedAt,{stale=!1}={}){let payload={status:"ok",provider:providerId,fetchedAt,stale,windows:{fiveHour:parsed.windows.fiveHour,weekly:parsed.windows.weekly}};return parsed.level!==null&&(payload.level=parsed.level),payload}var REMOTE_METHOD_DESCRIPTOR="@deepseek-ai/dsh-typert-protocol/remote-methods",Status=Object.freeze({OK:"ok",NOT_GLM:"not_glm",NO_CREDENTIAL:"no_credential",INVALID_PROVIDER:"invalid_provider",CONFIG_MISMATCH:"config_mismatch",CONFIG_UNVERIFIED:"config_unverified",FETCH_FAILED:"fetch_failed",BAD_RESPONSE:"bad_response"}),GLM_OFFICIAL_HOSTS=new Set(["open.bigmodel.cn"]),CHINA_CODING_PROVIDER="zai-coding-cn",CHINA_CODING_BASE_URL="https://open.bigmodel.cn/api/coding/paas/v4";function glmUrlEvidence(baseURL){if(baseURL===void 0||baseURL==="")return"unknown";let url;try{url=new URL(baseURL)}catch{return"no"}return url.protocol!=="https:"?"no":GLM_OFFICIAL_HOSTS.has(url.hostname)?"yes":"no"}var plain=value=>value!==null&&typeof value=="object"&&typeof value.get=="function"?value.get():value,GLM_API_KINDS=new Set(["zai","openai-completions"]),GlmQuotaService=class extends TypertRemoteService{static inject=[];static Config=z.object({providers:z.dict(z.string().pattern(/^[A-Z_][A-Z0-9_]*$/u)).default({}).volatile(),autoDiscover:z.boolean().default(!0).volatile(),ttlMs:z.natural().min(6e4).max(864e5).default(6e4).description("\u914D\u989D\u5237\u65B0\u95F4\u9694\uFF08\u6BEB\u79D2\uFF09\uFF1A\u9ED8\u8BA4 60000\uFF1B\u6700\u5C0F 1 \u5206\u949F\uFF0C\u6700\u5927 24 \u5C0F\u65F6\u3002\u540C\u6B65\u63A7\u5236 Host \u7F13\u5B58\u548C\u53EF\u89C1\u9875\u9762\u5237\u65B0\u3002").volatile(),minIntervalMs:z.natural().min(1e3).default(6e4).volatile(),timeoutMs:z.natural().min(1e3).max(12e4).default(1e4).volatile()});cache=new Map;inFlight=new Map;lastAttempt=new Map;fetchImpl=globalThis.fetch;constructor(ctx,config){super(ctx,"glmQuota"),this.config=config,ctx.effect(()=>async()=>{for(let controller of this.inFlight.values())controller.abort(new Error("glm-quota: disposed"));this.inFlight.clear(),this.cache.clear()})}async get(providerId,options){return{...await this._get(providerId,options),ttlMs:this.config.ttlMs.get()}}async _get(providerId,options){if(typeof providerId!="string"||providerId.length===0||providerId.length>200)return{status:Status.INVALID_PROVIDER,provider:typeof providerId=="string"?providerId:"",reason:"invalid_provider"};let force=options!==null&&typeof options=="object"&&options.force===!0,cached=this.cache.get(providerId),now=Date.now();if(!force&&cached!==void 0&&now-cached.at<this.config.ttlMs.get())return{...cached.payload,stale:!1};let running=this.inFlight.get(providerId);if(running!==void 0)return running.promise.then(payload=>({...payload}));let attempt=this.lastAttempt.get(providerId);if(!force&&attempt!==void 0&&now-attempt<this.config.minIntervalMs.get())return cached!==void 0?{...cached.payload,stale:!0}:{status:Status.FETCH_FAILED,provider:providerId,reason:"cooldown"};let controller=new AbortController,entry={controller,promise:null};return this.inFlight.set(providerId,entry),this.lastAttempt.set(providerId,now),entry.promise=this._query(providerId,controller.signal,cached).then(payload=>(payload.status===Status.OK&&this.cache.set(providerId,{at:payload.fetchedAt,payload}),payload)).finally(()=>{this.inFlight.delete(providerId);try{this.ctx.emit("glm-quota/changed",{provider:providerId})}catch{}}),entry.promise}async _query(providerId,signal,cached){let gate=this._providerGate(providerId);if(!gate.allowed)return{status:gate.status,provider:providerId};let token=await this._resolveCredential(gate.ref);if(token===null)return{status:Status.NO_CREDENTIAL,provider:providerId,reason:gate.ref};try{let timeout=AbortSignal.timeout(this.config.timeoutMs.get()),combined=signal.aborted?signal:AbortSignal.any([signal,timeout]),body=await(await this.fetchImpl(QUOTA_ENDPOINT,{method:"GET",headers:{Authorization:token,Accept:"application/json","Accept-Language":"zh-CN,zh"},signal:combined})).text(),parsed=parseQuotaResponse(body);return parsed.ok?buildPayload(providerId,parsed,Date.now()):this._withStale({status:parsed.error===QuotaError.API_REJECTED?Status.BAD_RESPONSE:Status.FETCH_FAILED,provider:providerId,reason:parsed.error},cached)}catch(error){let reason=signal.aborted?"cancelled":error instanceof Error&&error.name==="TimeoutError"?"timeout":"network";return this._withStale({status:Status.FETCH_FAILED,provider:providerId,reason},cached)}}_withStale(payload,cached){return cached!==void 0?{...cached.payload,stale:!0,supersedes:payload}:payload}_providerGate(providerId){let configured=this.config.providers.get(),explicit=Object.prototype.hasOwnProperty.call(configured,providerId)?configured[providerId]:void 0,profile=null;try{profile=this._piAiProfile(providerId)}catch{profile=null}return explicit!==void 0?profile===null?{allowed:!1,status:Status.CONFIG_UNVERIFIED}:(typeof profile.apiKeyEnv=="string"&&profile.apiKeyEnv.length>0?profile.apiKeyEnv:void 0)!==explicit?{allowed:!1,status:Status.CONFIG_MISMATCH}:!profile.kindOk||profile.urlEvidence==="no"?{allowed:!1,status:Status.NOT_GLM}:{allowed:!0,ref:explicit}:this.config.autoDiscover.get()?profile===null?{allowed:!1,status:Status.NOT_GLM}:typeof profile.apiKeyEnv!="string"||profile.apiKeyEnv.length===0?{allowed:!1,status:Status.NOT_GLM}:!profile.kindOk||profile.urlEvidence!=="yes"?{allowed:!1,status:Status.NOT_GLM}:{allowed:!0,ref:profile.apiKeyEnv}:{allowed:!1,status:Status.NOT_GLM}}_piAiProfile(providerId){let llm=this.ctx.get("llm"),loader=this.ctx.get("loader");if(llm===void 0||loader===void 0||!llm.listProviders().some(row=>row.id===providerId))return null;let directory=llm.listConfigurableProviders().find(row=>row.provider===providerId);if(directory===void 0)return null;let entry=[...loader.entries()].find(row=>row.options.id===directory.settingsNs);if(entry?.fiber?.state!==2)return null;let profiles=entry.fiber.config?.providers?.get?.();if(profiles===null||typeof profiles!="object"||Array.isArray(profiles)||!Object.prototype.hasOwnProperty.call(profiles,providerId))return null;let profile=profiles[providerId];if(profile===null||typeof profile!="object"||Array.isArray(profile))return null;let apiKeyEnv=plain(profile.apiKeyEnv),api=plain(profile.api),baseURL=plain(profile.baseURL),nativeChinaDefault=providerId===CHINA_CODING_PROVIDER&&baseURL===void 0&&directory.declared===!1&&directory.error===void 0&&directory.defaultBaseURL===CHINA_CODING_BASE_URL;return{apiKeyEnv:typeof apiKeyEnv=="string"&&apiKeyEnv.length>0?apiKeyEnv:void 0,kindOk:api===void 0||GLM_API_KINDS.has(api),urlEvidence:nativeChinaDefault?"yes":typeof baseURL=="string"?glmUrlEvidence(baseURL):"unknown"}}async _resolveCredential(ref){let credentials=this.ctx.get("credentials");if(credentials!==void 0){let hit=await credentials.resolve(ref);return hit!==void 0&&typeof hit.value=="string"&&hit.value.length>0?hit.value:null}let ambient=process.env[ref];return typeof ambient=="string"&&ambient.length>0?ambient:null}};Object.defineProperty(GlmQuotaService.prototype,REMOTE_METHOD_DESCRIPTOR,{configurable:!0,value:Object.freeze({version:1,methods:Object.freeze([Object.freeze({method:"get",invocation:Object.freeze({kind:"direct"})})])})});export{Status,GlmQuotaService as default};
package/package.json CHANGED
@@ -1,6 +1,37 @@
1
1
  {
2
2
  "name": "@ckyueix/glm-usage",
3
- "version": "0.0.0-stage",
4
- "stub": true,
5
- "description": "Temporary package placeholder for staged publishing"
6
- }
3
+ "version": "0.1.1",
4
+ "description": "GLM Coding Plan usage pill for the DeepSeek Harness composer dock (dual-half: host quota reader + web client entry)",
5
+ "type": "module",
6
+ "license": "SEE LICENSE IN LICENSE",
7
+ "main": "./dist/index.js",
8
+ "exports": {
9
+ ".": "./dist/index.js",
10
+ "./client": "./dist/client.js",
11
+ "./package.json": "./package.json"
12
+ },
13
+ "files": [
14
+ "dist",
15
+ "cordis.patch.yml",
16
+ "README.md",
17
+ "LICENSE"
18
+ ],
19
+ "engines": {
20
+ "dsh": "0.2.1-rc.2"
21
+ },
22
+ "peerDependencies": {
23
+ "@deepseek-ai/dsh": "0.2.1-rc.2"
24
+ },
25
+ "dependencies": {
26
+ "@deepseek-ai/dsh-typert-protocol": "0.2.1-rc.2",
27
+ "@deepseek-ai/schemastery": "~3.18.5"
28
+ },
29
+ "dsh": {
30
+ "bundle": {
31
+ "patch": "./cordis.patch.yml"
32
+ },
33
+ "client": {
34
+ "platform": "web"
35
+ }
36
+ }
37
+ }