zcode-acp-server 0.1.0 → 0.3.0

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.
Files changed (223) hide show
  1. package/README.md +192 -9
  2. package/README.zh-CN.md +143 -8
  3. package/dist/backend/client.d.ts +12 -4
  4. package/dist/backend/client.d.ts.map +1 -1
  5. package/dist/backend/client.js +72 -7
  6. package/dist/backend/client.js.map +1 -1
  7. package/dist/backend/credentials.d.ts.map +1 -1
  8. package/dist/backend/credentials.js +2 -1
  9. package/dist/backend/credentials.js.map +1 -1
  10. package/dist/backend/listener.d.ts +12 -4
  11. package/dist/backend/listener.d.ts.map +1 -1
  12. package/dist/backend/listener.js +68 -12
  13. package/dist/backend/listener.js.map +1 -1
  14. package/dist/backend/types.d.ts +1 -1
  15. package/dist/backend/types.d.ts.map +1 -1
  16. package/dist/bin/hub.d.ts +16 -0
  17. package/dist/bin/hub.d.ts.map +1 -0
  18. package/dist/bin/hub.js +41 -0
  19. package/dist/bin/hub.js.map +1 -0
  20. package/dist/bin/quota.d.ts +54 -0
  21. package/dist/bin/quota.d.ts.map +1 -0
  22. package/dist/bin/quota.js +333 -0
  23. package/dist/bin/quota.js.map +1 -0
  24. package/dist/config/auto-compact.d.ts +23 -0
  25. package/dist/config/auto-compact.d.ts.map +1 -0
  26. package/dist/config/auto-compact.js +67 -0
  27. package/dist/config/auto-compact.js.map +1 -0
  28. package/dist/config/mcp-discovery.d.ts +34 -0
  29. package/dist/config/mcp-discovery.d.ts.map +1 -0
  30. package/dist/config/mcp-discovery.js +153 -0
  31. package/dist/config/mcp-discovery.js.map +1 -0
  32. package/dist/config/model-cache.d.ts +12 -1
  33. package/dist/config/model-cache.d.ts.map +1 -1
  34. package/dist/config/model-cache.js +30 -8
  35. package/dist/config/model-cache.js.map +1 -1
  36. package/dist/config/options.d.ts +87 -9
  37. package/dist/config/options.d.ts.map +1 -1
  38. package/dist/config/options.js +248 -45
  39. package/dist/config/options.js.map +1 -1
  40. package/dist/config/plugin-commands.d.ts +24 -0
  41. package/dist/config/plugin-commands.d.ts.map +1 -0
  42. package/dist/config/plugin-commands.js +107 -0
  43. package/dist/config/plugin-commands.js.map +1 -0
  44. package/dist/config/provider-registry.d.ts +60 -0
  45. package/dist/config/provider-registry.d.ts.map +1 -0
  46. package/dist/config/provider-registry.js +128 -0
  47. package/dist/config/provider-registry.js.map +1 -0
  48. package/dist/config/runtime-model.d.ts +54 -18
  49. package/dist/config/runtime-model.d.ts.map +1 -1
  50. package/dist/config/runtime-model.js +105 -61
  51. package/dist/config/runtime-model.js.map +1 -1
  52. package/dist/config/skill-discovery.d.ts +35 -0
  53. package/dist/config/skill-discovery.d.ts.map +1 -0
  54. package/dist/config/skill-discovery.js +188 -0
  55. package/dist/config/skill-discovery.js.map +1 -0
  56. package/dist/handlers/account.d.ts +43 -0
  57. package/dist/handlers/account.d.ts.map +1 -0
  58. package/dist/handlers/account.js +59 -0
  59. package/dist/handlers/account.js.map +1 -0
  60. package/dist/handlers/background-tasks.d.ts +72 -0
  61. package/dist/handlers/background-tasks.d.ts.map +1 -0
  62. package/dist/handlers/background-tasks.js +330 -0
  63. package/dist/handlers/background-tasks.js.map +1 -0
  64. package/dist/handlers/dispatch.d.ts.map +1 -1
  65. package/dist/handlers/dispatch.js +134 -22
  66. package/dist/handlers/dispatch.js.map +1 -1
  67. package/dist/handlers/extensions.d.ts +15 -0
  68. package/dist/handlers/extensions.d.ts.map +1 -1
  69. package/dist/handlers/extensions.js +43 -27
  70. package/dist/handlers/extensions.js.map +1 -1
  71. package/dist/handlers/io.d.ts +31 -3
  72. package/dist/handlers/io.d.ts.map +1 -1
  73. package/dist/handlers/io.js +108 -9
  74. package/dist/handlers/io.js.map +1 -1
  75. package/dist/handlers/replay.d.ts +79 -0
  76. package/dist/handlers/replay.d.ts.map +1 -0
  77. package/dist/handlers/replay.js +252 -0
  78. package/dist/handlers/replay.js.map +1 -0
  79. package/dist/handlers/server-requests.d.ts +20 -4
  80. package/dist/handlers/server-requests.d.ts.map +1 -1
  81. package/dist/handlers/server-requests.js +293 -63
  82. package/dist/handlers/server-requests.js.map +1 -1
  83. package/dist/handlers/session.d.ts +113 -10
  84. package/dist/handlers/session.d.ts.map +1 -1
  85. package/dist/handlers/session.js +932 -277
  86. package/dist/handlers/session.js.map +1 -1
  87. package/dist/handlers/slash.d.ts +37 -1
  88. package/dist/handlers/slash.d.ts.map +1 -1
  89. package/dist/handlers/slash.js +143 -8
  90. package/dist/handlers/slash.js.map +1 -1
  91. package/dist/index.js +76 -12
  92. package/dist/index.js.map +1 -1
  93. package/dist/interaction/adapter.d.ts +19 -33
  94. package/dist/interaction/adapter.d.ts.map +1 -1
  95. package/dist/interaction/adapter.js +80 -79
  96. package/dist/interaction/adapter.js.map +1 -1
  97. package/dist/lazy-sessions.d.ts +35 -0
  98. package/dist/lazy-sessions.d.ts.map +1 -0
  99. package/dist/lazy-sessions.js +98 -0
  100. package/dist/lazy-sessions.js.map +1 -0
  101. package/dist/quota/cache.d.ts +18 -0
  102. package/dist/quota/cache.d.ts.map +1 -0
  103. package/dist/quota/cache.js +32 -0
  104. package/dist/quota/cache.js.map +1 -0
  105. package/dist/quota/client.d.ts +30 -0
  106. package/dist/quota/client.d.ts.map +1 -0
  107. package/dist/quota/client.js +57 -0
  108. package/dist/quota/client.js.map +1 -0
  109. package/dist/quota/color.d.ts +58 -0
  110. package/dist/quota/color.d.ts.map +1 -0
  111. package/dist/quota/color.js +95 -0
  112. package/dist/quota/color.js.map +1 -0
  113. package/dist/quota/combined.d.ts +66 -0
  114. package/dist/quota/combined.d.ts.map +1 -0
  115. package/dist/quota/combined.js +179 -0
  116. package/dist/quota/combined.js.map +1 -0
  117. package/dist/quota/format.d.ts +105 -0
  118. package/dist/quota/format.d.ts.map +1 -0
  119. package/dist/quota/format.js +219 -0
  120. package/dist/quota/format.js.map +1 -0
  121. package/dist/quota/index.d.ts +23 -0
  122. package/dist/quota/index.d.ts.map +1 -0
  123. package/dist/quota/index.js +42 -0
  124. package/dist/quota/index.js.map +1 -0
  125. package/dist/quota/opencode-go/cache.d.ts +17 -0
  126. package/dist/quota/opencode-go/cache.d.ts.map +1 -0
  127. package/dist/quota/opencode-go/cache.js +31 -0
  128. package/dist/quota/opencode-go/cache.js.map +1 -0
  129. package/dist/quota/opencode-go/client.d.ts +28 -0
  130. package/dist/quota/opencode-go/client.d.ts.map +1 -0
  131. package/dist/quota/opencode-go/client.js +48 -0
  132. package/dist/quota/opencode-go/client.js.map +1 -0
  133. package/dist/quota/opencode-go/config.d.ts +37 -0
  134. package/dist/quota/opencode-go/config.d.ts.map +1 -0
  135. package/dist/quota/opencode-go/config.js +58 -0
  136. package/dist/quota/opencode-go/config.js.map +1 -0
  137. package/dist/quota/opencode-go/format.d.ts +36 -0
  138. package/dist/quota/opencode-go/format.d.ts.map +1 -0
  139. package/dist/quota/opencode-go/format.js +87 -0
  140. package/dist/quota/opencode-go/format.js.map +1 -0
  141. package/dist/quota/opencode-go/index.d.ts +30 -0
  142. package/dist/quota/opencode-go/index.d.ts.map +1 -0
  143. package/dist/quota/opencode-go/index.js +108 -0
  144. package/dist/quota/opencode-go/index.js.map +1 -0
  145. package/dist/quota/opencode-go/parse.d.ts +41 -0
  146. package/dist/quota/opencode-go/parse.d.ts.map +1 -0
  147. package/dist/quota/opencode-go/parse.js +75 -0
  148. package/dist/quota/opencode-go/parse.js.map +1 -0
  149. package/dist/quota/opencode-go/types.d.ts +48 -0
  150. package/dist/quota/opencode-go/types.d.ts.map +1 -0
  151. package/dist/quota/opencode-go/types.js +11 -0
  152. package/dist/quota/opencode-go/types.js.map +1 -0
  153. package/dist/quota/parse.d.ts +33 -0
  154. package/dist/quota/parse.d.ts.map +1 -0
  155. package/dist/quota/parse.js +200 -0
  156. package/dist/quota/parse.js.map +1 -0
  157. package/dist/quota/types.d.ts +72 -0
  158. package/dist/quota/types.d.ts.map +1 -0
  159. package/dist/quota/types.js +10 -0
  160. package/dist/quota/types.js.map +1 -0
  161. package/dist/remote/broadcast.d.ts +47 -0
  162. package/dist/remote/broadcast.d.ts.map +1 -0
  163. package/dist/remote/broadcast.js +121 -0
  164. package/dist/remote/broadcast.js.map +1 -0
  165. package/dist/remote/config.d.ts +32 -0
  166. package/dist/remote/config.d.ts.map +1 -0
  167. package/dist/remote/config.js +65 -0
  168. package/dist/remote/config.js.map +1 -0
  169. package/dist/remote/endpoint.d.ts +30 -0
  170. package/dist/remote/endpoint.d.ts.map +1 -0
  171. package/dist/remote/endpoint.js +213 -0
  172. package/dist/remote/endpoint.js.map +1 -0
  173. package/dist/remote/hub-server.d.ts +41 -0
  174. package/dist/remote/hub-server.d.ts.map +1 -0
  175. package/dist/remote/hub-server.js +346 -0
  176. package/dist/remote/hub-server.js.map +1 -0
  177. package/dist/server.d.ts +139 -1
  178. package/dist/server.d.ts.map +1 -1
  179. package/dist/server.js +179 -4
  180. package/dist/server.js.map +1 -1
  181. package/dist/tasks-index.d.ts +14 -4
  182. package/dist/tasks-index.d.ts.map +1 -1
  183. package/dist/tasks-index.js +145 -46
  184. package/dist/tasks-index.js.map +1 -1
  185. package/dist/translators/event-translator.d.ts +33 -0
  186. package/dist/translators/event-translator.d.ts.map +1 -1
  187. package/dist/translators/event-translator.js +101 -0
  188. package/dist/translators/event-translator.js.map +1 -1
  189. package/dist/translators/index.d.ts +1 -1
  190. package/dist/translators/index.d.ts.map +1 -1
  191. package/dist/translators/index.js +1 -1
  192. package/dist/translators/index.js.map +1 -1
  193. package/dist/translators/projection-differ.d.ts +8 -0
  194. package/dist/translators/projection-differ.d.ts.map +1 -1
  195. package/dist/translators/projection-differ.js +19 -9
  196. package/dist/translators/projection-differ.js.map +1 -1
  197. package/dist/translators/tool-helpers.d.ts +28 -0
  198. package/dist/translators/tool-helpers.d.ts.map +1 -1
  199. package/dist/translators/tool-helpers.js +104 -0
  200. package/dist/translators/tool-helpers.js.map +1 -1
  201. package/dist/translators/types.d.ts +38 -1
  202. package/dist/translators/types.d.ts.map +1 -1
  203. package/dist/translators/types.js.map +1 -1
  204. package/dist/utils.d.ts +36 -7
  205. package/dist/utils.d.ts.map +1 -1
  206. package/dist/utils.js +69 -5
  207. package/dist/utils.js.map +1 -1
  208. package/docs/ARCHITECTURE.md +130 -40
  209. package/docs/BACKLOG.md +59 -0
  210. package/docs/DEVELOPMENT.md +31 -0
  211. package/docs/PROTOCOL.md +328 -23
  212. package/docs/REMOTE-CLIENTS.md +260 -0
  213. package/docs/REPLAY-GUIDE.md +131 -0
  214. package/docs/TROUBLESHOOTING.md +131 -14
  215. package/docs/adr/0001-bridge-lifetime-follows-primary-client.md +14 -0
  216. package/docs/adr/0002-stateless-hub-over-per-bridge-acp-endpoints.md +23 -0
  217. package/docs/adr/0003-tail-replay-meta-and-cursor-pagination.md +40 -0
  218. package/docs/agents/domain.md +51 -0
  219. package/docs/agents/issue-tracker.md +22 -0
  220. package/docs/agents/triage-labels.md +15 -0
  221. package/docs/proposals/0001-tail-session-replay.md +136 -0
  222. package/docs/proposals/0002-plan-quota-usage.md +81 -0
  223. package/package.json +10 -6
@@ -1,87 +1,129 @@
1
1
  /**
2
2
  * runtimeModel overlay plumbing.
3
3
  *
4
- * The backend resolves auth from its OAuth token store, so the `runtimeModel`
5
- * provider deliberately carries NO `apiKey` (the config.json apiKey is the
6
- * legacy plain key and has expired 401). Two uses:
4
+ * The runtimeModel names the provider+model a session should use. For THIRD-
5
+ * PARTY providers it also carries `apiKey` as `{source:"inline", value:"<key>"}`;
6
+ * the backend resolves model-call auth from the overlay itself, so omitting it
7
+ * yields HTTP 401 "Missing API key". Builtin providers keep using their own
8
+ * OAuth/config auth and never inline a key. `apiFormat` mirrors `kind`.
7
9
  *
8
- * 1. Resume overlay (`buildResumeRuntimeModel`): a resumed session may carry
9
- * a stale provider id in its history that the backend can no longer
10
- * authenticate. Sending the *current* enabled provider's runtimeModel at
11
- * resume makes the backend overlay it and use its own OAuth creds.
10
+ * Two uses:
11
+ *
12
+ * 1. Resume/load overlay (`buildResumeRuntimeModel`): a resumed session may
13
+ * carry a stale/revoked model in its history send fails with "历史模型
14
+ * 不可用". The overlay pins the session onto the default model — the FIRST
15
+ * enabled provider's FIRST model, the same one a fresh `session/new` lands
16
+ * on — so resume never inherits the session's last-used (possibly
17
+ * third-party / unavailable) model.
12
18
  *
13
19
  * 2. Model switch (`applyModelSwitch`): UI/slash model switching goes through
14
- * `session/updateRuntimeModelConfig` with `applyModelSelection:true` (a
15
- * runtime-only change, sidestepping `session/setModel`'s "no loaded config
16
- * file" persistence failure).
20
+ * `session/setModel` with both a `model` ref and a `runtimeModel` provider
21
+ * definition (runtime-only via `persistAsWorkspaceLastUsed:false`).
22
+ *
23
+ * Note: a provider registry push (`workspace/updateProviderRegistry`) is ALSO
24
+ * required for the backend to recognise third-party providers at all — without
25
+ * it the turn fails with `provider_not_configured` before auth is even tried.
26
+ * See provider-registry.ts.
17
27
  */
18
- import { readFileSync } from "node:fs";
19
- import { ZCODE_CREDS_PATH, log, warn } from "../utils.js";
20
- const DEFAULTS = {
21
- providerId: "builtin:bigmodel-coding-plan",
22
- kind: "anthropic",
23
- baseURL: "https://open.bigmodel.cn/api/anthropic",
24
- modelId: "GLM-5.2",
25
- models: ["GLM-5.2"],
26
- };
27
- /** Read the enabled provider's config from config.json (no apiKey). */
28
- function readEnabledProvider() {
29
- try {
30
- const cfg = JSON.parse(readFileSync(ZCODE_CREDS_PATH, "utf8"));
31
- for (const [pid, p] of Object.entries(cfg.provider ?? {})) {
32
- if (p?.enabled) {
33
- const opts = p.options ?? {};
34
- const modelKeys = Object.keys(p.models ?? {});
35
- return {
36
- providerId: pid,
37
- kind: p.kind ?? DEFAULTS.kind,
38
- baseURL: opts.baseURL || DEFAULTS.baseURL,
39
- modelId: modelKeys[0] ?? DEFAULTS.modelId,
40
- models: modelKeys.length > 0 ? modelKeys : DEFAULTS.models,
41
- };
42
- }
43
- }
28
+ import { buildModelElement } from "./provider-registry.js";
29
+ import { findProviderConfig, formatModelValue, isBuiltinProvider, loadAllModels, parseModelValue, } from "./options.js";
30
+ import { log, warn } from "../utils.js";
31
+ const DEFAULT_KIND = "anthropic";
32
+ const DEFAULT_BASE_URL = "https://open.bigmodel.cn/api/anthropic";
33
+ /** Map config.json `kind` → backend `apiFormat`. */
34
+ function apiFormatForKind(kind) {
35
+ if (kind?.includes("anthropic"))
36
+ return "anthropic-messages";
37
+ return "openai-chat-completions";
38
+ }
39
+ /**
40
+ * Build a runtimeModel overlay for the given provider+model.
41
+ *
42
+ * For THIRD-PARTY providers the overlay MUST carry `apiKey` as the inline union
43
+ * `{source:"inline", value:"<key>"}` the backend resolves model-call auth from
44
+ * the runtimeModel itself, so omitting it yields HTTP 401 "Missing API key".
45
+ * (This was previously believed unnecessary; live probing proved otherwise.)
46
+ * Builtin providers resolve auth from their own OAuth/config store, so no
47
+ * apiKey is sent for them. `apiFormat` mirrors `kind` per the backend's catalog.
48
+ */
49
+ export function buildRuntimeModel(ref, revision = "bridge") {
50
+ const p = findProviderConfig(ref.providerId);
51
+ if (!p) {
52
+ log(`runtime-model: provider "${ref.providerId}" not in config.json`);
53
+ return null;
44
54
  }
45
- catch (e) {
46
- log(`runtime-model: read config.json failed (${e instanceof Error ? e.message : String(e)})`);
55
+ const baseURL = p.options?.baseURL ?? DEFAULT_BASE_URL;
56
+ // Model elements must carry the full definition (reasoning variants /
57
+ // contextWindow / label) — a bare {modelId} overlay makes the backend fall
58
+ // back to the apiFormat's default 2-state thought levels (enabled/disabled),
59
+ // silently resetting the session's max/high/low dropdown on resume/switch.
60
+ const models = Object.entries(p.models ?? {}).map(([modelId, m]) => buildModelElement(modelId, (m ?? {})));
61
+ if (models.length === 0)
62
+ models.push({ modelId: ref.modelId });
63
+ const provider = {
64
+ providerId: ref.providerId,
65
+ kind: p.kind ?? DEFAULT_KIND,
66
+ apiFormat: apiFormatForKind(p.kind),
67
+ baseURL,
68
+ models,
69
+ };
70
+ // Third-party providers must inline their apiKey — the backend won't resolve
71
+ // it from anywhere else and the call fails with 401 without it. Builtin
72
+ // providers use OAuth/config auth and must NOT send an inline key.
73
+ if (!isBuiltinProvider(ref.providerId) && p.options?.apiKey) {
74
+ provider.apiKey = { source: "inline", value: p.options.apiKey };
47
75
  }
48
- return DEFAULTS;
49
- }
50
- /** Build a runtimeModel overlay object for the enabled provider. */
51
- export function buildRuntimeModel(modelId, revision = "bridge") {
52
- const pc = readEnabledProvider();
53
- const targetModel = modelId ?? pc.modelId;
54
76
  return {
55
77
  revision,
56
78
  generatedAt: Date.now(),
57
- model: { providerId: pc.providerId, modelId: targetModel },
58
- provider: {
59
- providerId: pc.providerId,
60
- kind: pc.kind,
61
- baseURL: pc.baseURL,
62
- models: pc.models.map((m) => ({ modelId: m })),
63
- },
79
+ model: { providerId: ref.providerId, modelId: ref.modelId },
80
+ provider,
64
81
  };
65
82
  }
66
- /** Build the resume-time overlay (current enabled provider, default model). */
83
+ /**
84
+ * Build the resume-time overlay pinned to the default model: the FIRST enabled
85
+ * provider's FIRST model (the same one a fresh `session/new` lands on). This
86
+ * ensures resume never inherits the session's last-used model, which may be a
87
+ * now-unavailable third-party model (e.g. Nvidia) and cause "历史模型不可用".
88
+ */
67
89
  export function buildResumeRuntimeModel() {
68
- return buildRuntimeModel(undefined, "bridge-resume");
90
+ const first = loadAllModels()[0];
91
+ if (!first) {
92
+ log("runtime-model: no enabled provider in config.json (resume overlay skipped)");
93
+ return null;
94
+ }
95
+ return buildRuntimeModel(first, "bridge-resume");
69
96
  }
70
97
  /**
71
- * Switch a session's model via session/updateRuntimeModelConfig.
98
+ * Switch a session's model via `session/setModel`.
99
+ *
100
+ * `value` is the configOption value: either `"providerId\modelId"` (encoded) or
101
+ * a legacy plain modelId (resolved to the first enabled builtin provider).
102
+ *
103
+ * Sends BOTH a `model` ref (the target) AND a `runtimeModel` (the full provider
104
+ * definition). The runtimeModel lets the backend register the provider into its
105
+ * workspace catalog (so even third-party / non-default models are recognised),
106
+ * while `model` names the selection. `persistAsWorkspaceLastUsed:false` keeps
107
+ * this a runtime-only change. Invalidates the model cache on success.
72
108
  *
73
- * Uses `applyModelSelection:true` so the change applies at runtime without
74
- * persistencesidestepping `session/setModel`'s "no loaded config file"
75
- * failure. Invalidates the model cache on success. Returns true on success.
109
+ * NOTE: the older `session/updateRuntimeModelConfig` path returns `changed:false`
110
+ * on current backends without applying — `session/setModel` is the working
111
+ * protocol since the backend model-management refactor.
76
112
  */
77
- export async function applyModelSwitch(server, zcodeSid, modelId) {
78
- const runtimeModel = buildRuntimeModel(modelId, "bridge-switch");
113
+ export async function applyModelSwitch(server, zcodeSid, value) {
114
+ const { providerId, modelId } = parseModelValue(value);
115
+ const runtimeModel = buildRuntimeModel({ providerId, providerName: providerId, modelId });
79
116
  if (runtimeModel === null) {
80
- log("runtime-model: cannot read provider config (config.json)");
117
+ log(`runtime-model: cannot build overlay for "${value}" (provider not found)`);
81
118
  return false;
82
119
  }
83
120
  const backend = server.ensureBackend();
84
- const resp = await backend.request(server.nextId(), "session/updateRuntimeModelConfig", { sessionId: zcodeSid, runtimeModel, applyModelSelection: true }, 15000);
121
+ const resp = await backend.request(server.nextId(), "session/setModel", {
122
+ sessionId: zcodeSid,
123
+ model: { providerId, modelId },
124
+ runtimeModel,
125
+ persistAsWorkspaceLastUsed: false,
126
+ }, 15000);
85
127
  if (resp.error) {
86
128
  warn(`runtime-model: switch failed: ${resp.error.message}`);
87
129
  return false;
@@ -93,4 +135,6 @@ export async function applyModelSwitch(server, zcodeSid, modelId) {
93
135
  export function invalidateModelCache(server, zcodeSid) {
94
136
  server.modelCache.delete(zcodeSid);
95
137
  }
138
+ // Re-exported so callers that only import runtime-model.ts can format values.
139
+ export { formatModelValue };
96
140
  //# sourceMappingURL=runtime-model.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"runtime-model.js","sourceRoot":"","sources":["../../src/config/runtime-model.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"runtime-model.js","sourceRoot":"","sources":["../../src/config/runtime-model.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,35 @@
1
+ /**
2
+ * Skill discovery — scans the same directories ZCode uses to discover Skills,
3
+ * reads each SKILL.md frontmatter, and returns entries suitable for the ACP
4
+ * `available_commands_update` notification.
5
+ *
6
+ * Each discovered skill becomes its own `/skill-name` slash command in the
7
+ * editor's completion menu (matching Claude Code's behaviour). The model
8
+ * resolves the invocation via its `Skill` tool — the bridge just lists them
9
+ * and passes the text through.
10
+ *
11
+ * Discovery sources (in priority order — first occurrence wins on name clash):
12
+ * 1. ~/.zcode/skills/&#42;/SKILL.md (user scope, ZCode native)
13
+ * 2. ~/.agents/skills/&#42;/SKILL.md (user scope, shared agents)
14
+ * 3. enabled plugin <cache>/skills/&#42;/SKILL.md
15
+ * 4. <cwd>/.agents/skills/&#42;/SKILL.md (project scope)
16
+ *
17
+ * Skills explicitly disabled in `~/.zcode/cli/config.json` (skills map with
18
+ * `enable: false`, keyed by absolute SKILL.md path) are excluded.
19
+ */
20
+ /** A slash-command entry compatible with `sendAvailableCommands`. */
21
+ export interface SkillEntry {
22
+ name: string;
23
+ description: string;
24
+ input?: {
25
+ hint: string;
26
+ };
27
+ }
28
+ /**
29
+ * Discover all enabled skills from the filesystem.
30
+ *
31
+ * Returns entries suitable for `available_commands_update`. Best-effort:
32
+ * failures are logged and swallowed (returns whatever was found).
33
+ */
34
+ export declare function loadSkillCommands(): SkillEntry[];
35
+ //# sourceMappingURL=skill-discovery.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"skill-discovery.d.ts","sourceRoot":"","sources":["../../src/config/skill-discovery.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AASH,qEAAqE;AACrE,MAAM,WAAW,UAAU;IACzB,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,KAAK,CAAC,EAAE;QAAE,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC;CAC1B;AAkHD;;;;;GAKG;AACH,wBAAgB,iBAAiB,IAAI,UAAU,EAAE,CAwDhD"}
@@ -0,0 +1,188 @@
1
+ /**
2
+ * Skill discovery — scans the same directories ZCode uses to discover Skills,
3
+ * reads each SKILL.md frontmatter, and returns entries suitable for the ACP
4
+ * `available_commands_update` notification.
5
+ *
6
+ * Each discovered skill becomes its own `/skill-name` slash command in the
7
+ * editor's completion menu (matching Claude Code's behaviour). The model
8
+ * resolves the invocation via its `Skill` tool — the bridge just lists them
9
+ * and passes the text through.
10
+ *
11
+ * Discovery sources (in priority order — first occurrence wins on name clash):
12
+ * 1. ~/.zcode/skills/&#42;/SKILL.md (user scope, ZCode native)
13
+ * 2. ~/.agents/skills/&#42;/SKILL.md (user scope, shared agents)
14
+ * 3. enabled plugin <cache>/skills/&#42;/SKILL.md
15
+ * 4. <cwd>/.agents/skills/&#42;/SKILL.md (project scope)
16
+ *
17
+ * Skills explicitly disabled in `~/.zcode/cli/config.json` (skills map with
18
+ * `enable: false`, keyed by absolute SKILL.md path) are excluded.
19
+ */
20
+ import { existsSync, readFileSync, readdirSync, statSync } from "node:fs";
21
+ import { homedir } from "node:os";
22
+ import path from "node:path";
23
+ import process from "node:process";
24
+ import { compareVersions, log } from "../utils.js";
25
+ const HOME = homedir();
26
+ /** Path to the ZCode CLI config (skills enable/disable, plugins, mcp). */
27
+ const CLI_CONFIG_PATH = path.join(HOME, ".zcode", "cli", "config.json");
28
+ /** Root of the plugin cache directory. */
29
+ const PLUGIN_CACHE_DIR = path.join(HOME, ".zcode", "cli", "plugins", "cache");
30
+ /** Max description length before truncation with ellipsis. */
31
+ const MAX_DESC_LEN = 80;
32
+ /**
33
+ * Parse YAML-like frontmatter from a SKILL.md file.
34
+ * Returns a map of key→string (values have surrounding quotes stripped).
35
+ */
36
+ function parseFrontmatter(content) {
37
+ const fm = {};
38
+ const match = content.match(/^---\r?\n([\s\S]*?)\r?\n---/);
39
+ if (!match)
40
+ return fm;
41
+ const lines = match[1].split(/\r?\n/);
42
+ for (const line of lines) {
43
+ const idx = line.indexOf(":");
44
+ if (idx <= 0)
45
+ continue;
46
+ const key = line.slice(0, idx).trim();
47
+ let val = line.slice(idx + 1).trim();
48
+ if ((val.startsWith('"') && val.endsWith('"')) || (val.startsWith("'") && val.endsWith("'"))) {
49
+ val = val.slice(1, -1);
50
+ }
51
+ if (key)
52
+ fm[key] = val;
53
+ }
54
+ return fm;
55
+ }
56
+ /** Truncate a description to MAX_DESC_LEN, appending "…" if truncated. */
57
+ function truncateDesc(desc) {
58
+ if (desc.length <= MAX_DESC_LEN)
59
+ return desc;
60
+ return desc.slice(0, MAX_DESC_LEN - 1) + "…";
61
+ }
62
+ /** Read the disabled skill paths from config.json (set of absolute paths). */
63
+ function loadDisabledSkillPaths(config) {
64
+ const disabled = new Set();
65
+ if (!config?.skills)
66
+ return disabled;
67
+ for (const [skillPath, cfg] of Object.entries(config.skills)) {
68
+ if (cfg?.enable === false)
69
+ disabled.add(skillPath);
70
+ }
71
+ return disabled;
72
+ }
73
+ /** Scan a directory for skill subdirectories containing SKILL.md. */
74
+ function scanSkillDir(dir, disabledPaths, results, seen) {
75
+ if (!existsSync(dir))
76
+ return;
77
+ let entries;
78
+ try {
79
+ entries = readdirSync(dir);
80
+ }
81
+ catch {
82
+ return;
83
+ }
84
+ for (const entry of entries) {
85
+ const skillDir = path.join(dir, entry);
86
+ try {
87
+ if (!statSync(skillDir).isDirectory())
88
+ continue;
89
+ }
90
+ catch {
91
+ continue;
92
+ }
93
+ const skillMd = path.join(skillDir, "SKILL.md");
94
+ if (!existsSync(skillMd))
95
+ continue;
96
+ // Resolve absolute path for disabled-check.
97
+ const absPath = path.resolve(skillMd);
98
+ if (disabledPaths.has(absPath))
99
+ continue;
100
+ const content = readFileSync(skillMd, "utf8");
101
+ const fm = parseFrontmatter(content);
102
+ const name = fm["name"] ?? entry;
103
+ const description = fm["description"] ?? "";
104
+ if (!description)
105
+ continue;
106
+ // Skip explicitly non-user-invocable skills.
107
+ if (fm["user-invocable"] === "false")
108
+ continue;
109
+ // Prefix with $ so the editor groups skills visually (e.g. "$tdd") and
110
+ // handleSlashCommand can route by prefix.
111
+ const cmdName = `$${name}`;
112
+ if (seen.has(cmdName))
113
+ continue;
114
+ seen.add(cmdName);
115
+ const skillEntry = {
116
+ name: cmdName,
117
+ description: truncateDesc(description),
118
+ };
119
+ // Only request follow-up input when the skill author explicitly declares
120
+ // an argument-hint — matching plugin-commands.ts behaviour. Skills without
121
+ // argument-hint (e.g. $tdd, $setup-matt-pocock-skills) send immediately on
122
+ // selection; skills with one (e.g. $handoff, $teach) wait for user input.
123
+ const hint = fm["argument-hint"];
124
+ if (hint)
125
+ skillEntry.input = { hint };
126
+ results.push(skillEntry);
127
+ }
128
+ }
129
+ /**
130
+ * Discover all enabled skills from the filesystem.
131
+ *
132
+ * Returns entries suitable for `available_commands_update`. Best-effort:
133
+ * failures are logged and swallowed (returns whatever was found).
134
+ */
135
+ export function loadSkillCommands() {
136
+ const results = [];
137
+ const seen = new Set();
138
+ // Load config for disabled-skills list + enabled-plugins list.
139
+ let config = null;
140
+ try {
141
+ if (existsSync(CLI_CONFIG_PATH)) {
142
+ config = JSON.parse(readFileSync(CLI_CONFIG_PATH, "utf8"));
143
+ }
144
+ }
145
+ catch (e) {
146
+ log(`skill-discovery: config read failed (${e instanceof Error ? e.message : String(e)})`);
147
+ }
148
+ const disabledPaths = loadDisabledSkillPaths(config);
149
+ // 1. ~/.zcode/skills/
150
+ scanSkillDir(path.join(HOME, ".zcode", "skills"), disabledPaths, results, seen);
151
+ // 2. ~/.agents/skills/
152
+ scanSkillDir(path.join(HOME, ".agents", "skills"), disabledPaths, results, seen);
153
+ // 3. Enabled plugin skills.
154
+ const enabledPlugins = config?.plugins?.enabledPlugins ?? {};
155
+ for (const [pluginKey, enabledFlag] of Object.entries(enabledPlugins)) {
156
+ if (!enabledFlag)
157
+ continue;
158
+ const atIdx = pluginKey.indexOf("@");
159
+ if (atIdx <= 0)
160
+ continue;
161
+ const pluginName = pluginKey.slice(0, atIdx);
162
+ const marketplace = pluginKey.slice(atIdx + 1);
163
+ const pluginDir = path.join(PLUGIN_CACHE_DIR, marketplace, pluginName);
164
+ if (!existsSync(pluginDir))
165
+ continue;
166
+ // Find the latest version directory.
167
+ let latestVersion = "";
168
+ try {
169
+ for (const entry of readdirSync(pluginDir)) {
170
+ const vDir = path.join(pluginDir, entry);
171
+ if (statSync(vDir).isDirectory() && compareVersions(entry, latestVersion) > 0) {
172
+ latestVersion = entry;
173
+ }
174
+ }
175
+ }
176
+ catch {
177
+ continue;
178
+ }
179
+ if (!latestVersion)
180
+ continue;
181
+ scanSkillDir(path.join(pluginDir, latestVersion, "skills"), disabledPaths, results, seen);
182
+ }
183
+ // 4. Project-level .agents/skills/ (if exists).
184
+ scanSkillDir(path.join(process.cwd(), ".agents", "skills"), disabledPaths, results, seen);
185
+ log(`skill-discovery: loaded ${results.length} skill(s)`);
186
+ return results;
187
+ }
188
+ //# sourceMappingURL=skill-discovery.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"skill-discovery.js","sourceRoot":"","sources":["../../src/config/skill-discovery.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,43 @@
1
+ /**
2
+ * Account-level usage stats — Proposal 0002 (`account/usage_stats`).
3
+ *
4
+ * Exposes the combined dual-provider quota behind the `zcode-quota` CLI
5
+ * (GLM Coding Plan + Opencode Go) to remote clients as a pull-only ACP
6
+ * method, callable any time after `initialize` (no session required — quota
7
+ * is account-level, so it fits no `session/update` kind).
8
+ *
9
+ * The response mirrors the CLI card's data model so clients can reproduce it
10
+ * exactly: one GLM section (plan level + per-window items with per-model
11
+ * details) and one Opencode Go section (rolling/weekly/monthly windows, the
12
+ * relative reset countdown converted to an absolute timestamp). Provider
13
+ * failures are reported per-section as `kind` strings rather than throwing —
14
+ * the client renders the same status line the CLI would (a `not_configured`
15
+ * Go section is simply omitted, matching the CLI).
16
+ */
17
+ import type { GoQueryResult, GoWindowKey } from "../quota/opencode-go/types.js";
18
+ import type { QuotaItem, QuotaResult } from "../quota/types.js";
19
+ /** GLM section — `items` present only on success. */
20
+ export interface GlmUsageStats {
21
+ kind: QuotaResult["kind"];
22
+ level?: string;
23
+ items?: QuotaItem[];
24
+ }
25
+ /** One Opencode Go window with the reset countdown resolved to epoch ms. */
26
+ export interface GoWindowEntry {
27
+ key: GoWindowKey;
28
+ label: string;
29
+ usagePercent: number;
30
+ resetsAt: number;
31
+ }
32
+ /** Opencode Go section — `windows` present only on success. */
33
+ export interface GoUsageStats {
34
+ kind: GoQueryResult["kind"];
35
+ windows?: GoWindowEntry[];
36
+ }
37
+ export interface UsageStatsResult {
38
+ glm: GlmUsageStats;
39
+ opencode: GoUsageStats;
40
+ }
41
+ /** `account/usage_stats` handler — both providers, queried in parallel. */
42
+ export declare function accountUsageStats(): Promise<UsageStatsResult>;
43
+ //# sourceMappingURL=account.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"account.d.ts","sourceRoot":"","sources":["../../src/handlers/account.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAGH,OAAO,KAAK,EAAE,aAAa,EAAE,WAAW,EAAE,MAAM,+BAA+B,CAAC;AAChF,OAAO,KAAK,EAAE,SAAS,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAEhE,qDAAqD;AACrD,MAAM,WAAW,aAAa;IAC5B,IAAI,EAAE,WAAW,CAAC,MAAM,CAAC,CAAC;IAC1B,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,KAAK,CAAC,EAAE,SAAS,EAAE,CAAC;CACrB;AAED,4EAA4E;AAC5E,MAAM,WAAW,aAAa;IAC5B,GAAG,EAAE,WAAW,CAAC;IACjB,KAAK,EAAE,MAAM,CAAC;IACd,YAAY,EAAE,MAAM,CAAC;IACrB,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,+DAA+D;AAC/D,MAAM,WAAW,YAAY;IAC3B,IAAI,EAAE,aAAa,CAAC,MAAM,CAAC,CAAC;IAC5B,OAAO,CAAC,EAAE,aAAa,EAAE,CAAC;CAC3B;AAED,MAAM,WAAW,gBAAgB;IAC/B,GAAG,EAAE,aAAa,CAAC;IACnB,QAAQ,EAAE,YAAY,CAAC;CACxB;AAsCD,2EAA2E;AAC3E,wBAAsB,iBAAiB,IAAI,OAAO,CAAC,gBAAgB,CAAC,CAGnE"}
@@ -0,0 +1,59 @@
1
+ /**
2
+ * Account-level usage stats — Proposal 0002 (`account/usage_stats`).
3
+ *
4
+ * Exposes the combined dual-provider quota behind the `zcode-quota` CLI
5
+ * (GLM Coding Plan + Opencode Go) to remote clients as a pull-only ACP
6
+ * method, callable any time after `initialize` (no session required — quota
7
+ * is account-level, so it fits no `session/update` kind).
8
+ *
9
+ * The response mirrors the CLI card's data model so clients can reproduce it
10
+ * exactly: one GLM section (plan level + per-window items with per-model
11
+ * details) and one Opencode Go section (rolling/weekly/monthly windows, the
12
+ * relative reset countdown converted to an absolute timestamp). Provider
13
+ * failures are reported per-section as `kind` strings rather than throwing —
14
+ * the client renders the same status line the CLI would (a `not_configured`
15
+ * Go section is simply omitted, matching the CLI).
16
+ */
17
+ import { queryCombined } from "../quota/combined.js";
18
+ /** Window labels matching the CLI's card (`5h` / `Week` / `Month`). */
19
+ const GO_WINDOW_LABELS = {
20
+ rolling: "5h",
21
+ weekly: "Week",
22
+ monthly: "Month",
23
+ };
24
+ /** GLM items pass through verbatim — the client renders the CLI layout. */
25
+ function toGlmStats(result) {
26
+ if (result.kind !== "success")
27
+ return { kind: result.kind };
28
+ return { kind: "success", level: result.level, items: result.items };
29
+ }
30
+ /**
31
+ * Go windows with the same absolute-reset math the CLI formatter uses:
32
+ * subtract the elapsed time since the fetch snapshot from `resetInSec`.
33
+ */
34
+ function toGoStats(result, now = Date.now()) {
35
+ if (result.kind !== "success")
36
+ return { kind: result.kind };
37
+ const elapsedSec = Math.max(0, (now - result.fetchedAt) / 1000);
38
+ const windows = ["rolling", "weekly", "monthly"].flatMap((key) => {
39
+ const w = result[key];
40
+ if (!w)
41
+ return [];
42
+ const remainingSec = Math.max(0, w.resetInSec - elapsedSec);
43
+ return [
44
+ {
45
+ key,
46
+ label: GO_WINDOW_LABELS[key],
47
+ usagePercent: w.usagePercent,
48
+ resetsAt: result.fetchedAt + remainingSec * 1000,
49
+ },
50
+ ];
51
+ });
52
+ return { kind: "success", windows };
53
+ }
54
+ /** `account/usage_stats` handler — both providers, queried in parallel. */
55
+ export async function accountUsageStats() {
56
+ const { glm, go } = await queryCombined("all");
57
+ return { glm: toGlmStats(glm), opencode: toGoStats(go) };
58
+ }
59
+ //# sourceMappingURL=account.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"account.js","sourceRoot":"","sources":["../../src/handlers/account.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAEH,OAAO,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AA8BrD,uEAAuE;AACvE,MAAM,gBAAgB,GAAgC;IACpD,OAAO,EAAE,IAAI;IACb,MAAM,EAAE,MAAM;IACd,OAAO,EAAE,OAAO;CACjB,CAAC;AAEF,2EAA2E;AAC3E,SAAS,UAAU,CAAC,MAAmB;IACrC,IAAI,MAAM,CAAC,IAAI,KAAK,SAAS;QAAE,OAAO,EAAE,IAAI,EAAE,MAAM,CAAC,IAAI,EAAE,CAAC;IAC5D,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE,KAAK,EAAE,MAAM,CAAC,KAAK,EAAE,KAAK,EAAE,MAAM,CAAC,KAAK,EAAE,CAAC;AACvE,CAAC;AAED;;;GAGG;AACH,SAAS,SAAS,CAAC,MAAqB,EAAE,GAAG,GAAG,IAAI,CAAC,GAAG,EAAE;IACxD,IAAI,MAAM,CAAC,IAAI,KAAK,SAAS;QAAE,OAAO,EAAE,IAAI,EAAE,MAAM,CAAC,IAAI,EAAE,CAAC;IAC5D,MAAM,UAAU,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,CAAC,GAAG,GAAG,MAAM,CAAC,SAAS,CAAC,GAAG,IAAI,CAAC,CAAC;IAChE,MAAM,OAAO,GAAI,CAAC,SAAS,EAAE,QAAQ,EAAE,SAAS,CAAW,CAAC,OAAO,CAAC,CAAC,GAAG,EAAE,EAAE;QAC1E,MAAM,CAAC,GAAG,MAAM,CAAC,GAAG,CAAC,CAAC;QACtB,IAAI,CAAC,CAAC;YAAE,OAAO,EAAE,CAAC;QAClB,MAAM,YAAY,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,CAAC,CAAC,UAAU,GAAG,UAAU,CAAC,CAAC;QAC5D,OAAO;YACL;gBACE,GAAG;gBACH,KAAK,EAAE,gBAAgB,CAAC,GAAG,CAAC;gBAC5B,YAAY,EAAE,CAAC,CAAC,YAAY;gBAC5B,QAAQ,EAAE,MAAM,CAAC,SAAS,GAAG,YAAY,GAAG,IAAI;aACjD;SACF,CAAC;IACJ,CAAC,CAAC,CAAC;IACH,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE,OAAO,EAAE,CAAC;AACtC,CAAC;AAED,2EAA2E;AAC3E,MAAM,CAAC,KAAK,UAAU,iBAAiB;IACrC,MAAM,EAAE,GAAG,EAAE,EAAE,EAAE,GAAG,MAAM,aAAa,CAAC,KAAK,CAAC,CAAC;IAC/C,OAAO,EAAE,GAAG,EAAE,UAAU,CAAC,GAAG,CAAC,EAAE,QAAQ,EAAE,SAAS,CAAC,EAAE,CAAC,EAAE,CAAC;AAC3D,CAAC"}