huaweicloud-devkit 1.1.2-next.0 → 1.1.2-next.2

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 (125) hide show
  1. package/.agents/plugins/marketplace.json +18 -18
  2. package/README.md +182 -38
  3. package/README.zh-CN.md +180 -36
  4. package/bin/dsh-postinstall.cjs +77 -0
  5. package/bin/setup.cjs +7 -4
  6. package/cordis.patch.yml +13 -0
  7. package/integrations/atomcode/hooks/huaweicloud-telemetry.js +181 -0
  8. package/integrations/atomcode/hooks.json +9 -0
  9. package/integrations/dsh/hook-plugin.mjs +148 -0
  10. package/integrations/hermes/hooks/huaweicloud-telemetry.py +238 -0
  11. package/integrations/hermes/manifest.yaml +43 -0
  12. package/integrations/opencode/hooks/skill-tracker.js +115 -0
  13. package/integrations/opencode/opencode.json +1 -4
  14. package/integrations/workbuddy/hooks/telemetry-tracker.py +226 -0
  15. package/package.json +74 -43
  16. package/plugins/huaweicloud-core/.claude-plugin/plugin.json +4 -17
  17. package/plugins/huaweicloud-core/.codex-plugin/plugin.json +23 -33
  18. package/plugins/huaweicloud-core/.cursor-plugin/plugin.json +4 -17
  19. package/plugins/huaweicloud-core/.hermes-plugin/plugin.json +30 -0
  20. package/plugins/huaweicloud-core/.mcp.json +2 -5
  21. package/plugins/huaweicloud-core/.workbuddy-plugin/plugin.json +4 -18
  22. package/plugins/huaweicloud-core/assets/icon.png +0 -0
  23. package/plugins/huaweicloud-core/assets/logo-dark.png +0 -0
  24. package/plugins/huaweicloud-core/assets/logo.png +0 -0
  25. package/plugins/huaweicloud-core/hooks/huaweicloud-safety.py +104 -28
  26. package/plugins/huaweicloud-core/openclaw.plugin.json +20 -0
  27. package/plugins/huaweicloud-core/safety/policy.json +75 -99
  28. package/plugins/huaweicloud-core/safety/rules/cloud-risk-rules.json +196 -35
  29. package/plugins/huaweicloud-core/skills/huawei-apig/SKILL.md +38 -34
  30. package/plugins/huaweicloud-core/skills/huawei-billing/SKILL.md +21 -20
  31. package/plugins/huaweicloud-core/skills/huawei-cbr/SKILL.md +19 -19
  32. package/plugins/huaweicloud-core/skills/huawei-cce/SKILL.md +38 -32
  33. package/plugins/huaweicloud-core/skills/huawei-cloud-eye/SKILL.md +30 -30
  34. package/plugins/huaweicloud-core/skills/huawei-cts/SKILL.md +20 -20
  35. package/plugins/huaweicloud-core/skills/huawei-dds-dcs/SKILL.md +31 -31
  36. package/plugins/huaweicloud-core/skills/huawei-deployment/SKILL.md +21 -20
  37. package/plugins/huaweicloud-core/skills/huawei-dew/SKILL.md +40 -31
  38. package/plugins/huaweicloud-core/skills/huawei-dew/references/csms-usage.md +8 -1
  39. package/plugins/huaweicloud-core/skills/huawei-dew/references/kms-usage.md +6 -0
  40. package/plugins/huaweicloud-core/skills/huawei-ecs/SKILL.md +45 -37
  41. package/plugins/huaweicloud-core/skills/huawei-ecs/references/create-instance.md +57 -6
  42. package/plugins/huaweicloud-core/skills/huawei-ecs/references/flavors.md +11 -9
  43. package/plugins/huaweicloud-core/skills/huawei-ecs/references/hc-activity.md +27 -0
  44. package/plugins/huaweicloud-core/skills/huawei-ecs/references/troubleshooting.md +13 -13
  45. package/plugins/huaweicloud-core/skills/huawei-functiongraph/SKILL.md +44 -39
  46. package/plugins/huaweicloud-core/skills/huawei-functiongraph/references/apig-event-format.md +12 -10
  47. package/plugins/huaweicloud-core/skills/huawei-functiongraph/references/create-function.md +21 -20
  48. package/plugins/huaweicloud-core/skills/huawei-functiongraph/references/triggers.md +19 -19
  49. package/plugins/huaweicloud-core/skills/huawei-gaussdb/SKILL.md +20 -20
  50. package/plugins/huaweicloud-core/skills/huawei-getting-started/SKILL.md +27 -23
  51. package/plugins/huaweicloud-core/skills/huawei-iac/SKILL.md +93 -0
  52. package/plugins/huaweicloud-core/skills/huawei-iac/references/architectures.md +83 -0
  53. package/plugins/huaweicloud-core/skills/huawei-iac/references/resource-catalog.md +107 -0
  54. package/plugins/huaweicloud-core/skills/huawei-iac/references/state-file.md +104 -0
  55. package/plugins/huaweicloud-core/skills/huawei-iam/SKILL.md +30 -30
  56. package/plugins/huaweicloud-core/skills/huawei-iam/references/policy-examples.md +65 -39
  57. package/plugins/huaweicloud-core/skills/huawei-iam/references/quick-ref.md +9 -9
  58. package/plugins/huaweicloud-core/skills/huawei-modelarts/SKILL.md +33 -25
  59. package/plugins/huaweicloud-core/skills/huawei-obs/SKILL.md +46 -45
  60. package/plugins/huaweicloud-core/skills/huawei-obs/references/bucket-create.md +19 -19
  61. package/plugins/huaweicloud-core/skills/huawei-obs/references/bucket-lifecycle.md +12 -7
  62. package/plugins/huaweicloud-core/skills/huawei-obs/references/common-pitfalls.md +13 -12
  63. package/plugins/huaweicloud-core/skills/huawei-obs/references/single-file-share.md +4 -4
  64. package/plugins/huaweicloud-core/skills/huawei-rds/SKILL.md +71 -61
  65. package/plugins/huaweicloud-core/skills/huawei-sandbox/SKILL.md +776 -44
  66. package/plugins/huaweicloud-core/skills/huawei-sandbox/references/framework-commands.md +84 -0
  67. package/plugins/huaweicloud-core/skills/huawei-sandbox/references/nginx-templates.md +100 -0
  68. package/plugins/huaweicloud-core/skills/huawei-smn-dms/SKILL.md +36 -29
  69. package/plugins/huaweicloud-core/skills/huawei-voucher/SKILL.md +57 -0
  70. package/plugins/huaweicloud-core/skills/huawei-vpc/SKILL.md +39 -39
  71. package/plugins/huaweicloud-core/skills/huawei-vpc/references/network.md +22 -15
  72. package/plugins/huaweicloud-core/skills/huawei-vpc/references/security-group.md +20 -19
  73. package/plugins/huaweicloud-core/skills/huawei-vpc/references/subnet.md +15 -15
  74. package/plugins/huaweicloud-core/skills/huawei-waf-aad/SKILL.md +23 -20
  75. package/plugins/huaweicloud-core/skills/huaweicloud-api-and-sdk/SKILL.md +13 -13
  76. package/plugins/huaweicloud-core/skills/huaweicloud-api-and-sdk/agents/openai.yaml +3 -3
  77. package/plugins/huaweicloud-core/skills/huaweicloud-capability-discovery/SKILL.md +21 -2
  78. package/plugins/huaweicloud-core/skills/huaweicloud-capability-discovery/agents/openai.yaml +3 -3
  79. package/plugins/huaweicloud-core/skills/huaweicloud-cli-and-auth/SKILL.md +30 -4
  80. package/plugins/huaweicloud-core/skills/huaweicloud-cli-and-auth/agents/openai.yaml +3 -3
  81. package/plugins/huaweicloud-core/skills/huaweicloud-core/SKILL.md +68 -54
  82. package/plugins/huaweicloud-core/skills/huaweicloud-core/agents/openai.yaml +3 -3
  83. package/plugins/huaweicloud-core/skills/huaweicloud-core/references/report-issue.md +6 -6
  84. package/plugins/huaweicloud-core/skills/huaweicloud-core/references/select.md +15 -1
  85. package/plugins/huaweicloud-core/skills/huaweicloud-safety/SKILL.md +0 -1
  86. package/plugins/huaweicloud-core/skills/huaweicloud-safety/agents/openai.yaml +3 -3
  87. package/plugins/huaweicloud-core/skills/huaweicloud-troubleshooting/SKILL.md +36 -34
  88. package/plugins/huaweicloud-core/skills/huaweicloud-troubleshooting/agents/openai.yaml +3 -3
  89. package/plugins/huaweicloud-core/src/auth/agent-registration.mjs +142 -5
  90. package/plugins/huaweicloud-core/src/auth/credentials.mjs +217 -5
  91. package/plugins/huaweicloud-core/src/auth/reconcile.mjs +174 -0
  92. package/plugins/huaweicloud-core/src/auth/service.mjs +57 -2
  93. package/plugins/huaweicloud-core/src/data/icons-manifest.v1.json +3517 -0
  94. package/plugins/huaweicloud-core/src/detect-framework.mjs +366 -0
  95. package/plugins/huaweicloud-core/src/hcloud-cli.mjs +203 -16
  96. package/plugins/huaweicloud-core/src/icon-library.mjs +176 -0
  97. package/plugins/huaweicloud-core/src/mcp-protocol.mjs +88 -0
  98. package/plugins/huaweicloud-core/src/mcp-server-remote.mjs +107 -0
  99. package/plugins/huaweicloud-core/src/mcp-server.mjs +154 -99
  100. package/plugins/huaweicloud-core/src/proxy/proxy-agent.mjs +20 -102
  101. package/plugins/huaweicloud-core/src/proxy/proxy-config.mjs +11 -4
  102. package/plugins/huaweicloud-core/src/risk-rule-engine.mjs +4 -1
  103. package/plugins/huaweicloud-core/src/safety-policy.mjs +123 -68
  104. package/plugins/huaweicloud-core/src/sandbox/hdkitservice-api.mjs +48 -12
  105. package/plugins/huaweicloud-core/src/sandbox/hwlink-api.mjs +25 -26
  106. package/plugins/huaweicloud-core/src/sandbox/sandbox-file-server.py +45 -0
  107. package/plugins/huaweicloud-core/src/sandbox/session-manager.mjs +943 -10
  108. package/plugins/huaweicloud-core/src/sandbox/uninstall-cleanup.mjs +50 -0
  109. package/plugins/huaweicloud-core/src/search-market.mjs +49 -14
  110. package/plugins/huaweicloud-core/src/setup-cli.mjs +3091 -498
  111. package/plugins/huaweicloud-core/src/telemetry/agent-detect.mjs +40 -0
  112. package/plugins/huaweicloud-core/src/telemetry/agent-registry.mjs +328 -0
  113. package/plugins/huaweicloud-core/src/telemetry/telemetry.mjs +378 -0
  114. package/plugins/huaweicloud-core/src/tools.mjs +1272 -146
  115. package/plugins/huaweicloud-core/src/update-check.mjs +383 -0
  116. package/plugins/huaweicloud-core/src/ws-exec/hwlink-exec-client.js +72 -38
  117. package/plugins/huaweicloud-core/src/ws-exec/hwlink-fair-queue.js +10 -5
  118. package/plugins/huaweicloud-core/src/ws-exec/hwlink-multiplexer.js +13 -16
  119. package/plugins/huaweicloud-core/src/ws-exec/hwlink-packet.js +12 -16
  120. package/plugins/huaweicloud-core/src/ws-exec/hwlink-terminal-channel.js +46 -31
  121. package/plugins/huaweicloud-core/src/ws-exec/hwlink-tunnel-channel.mjs +268 -0
  122. package/plugins/huaweicloud-core/src/ws-exec/index.js +3 -0
  123. package/plugins/huaweicloud-core/src/ws-exec/ws-exec-client.js +40 -13
  124. package/plugins/huaweicloud-core/skills/huawei-cloud-find-skills/SKILL.md +0 -190
  125. package/plugins/huaweicloud-core/skills/huawei-cloud-find-skills/scripts/search-skills.mjs +0 -124
@@ -0,0 +1,40 @@
1
+ import { AGENTS, matchAgent, detectVersion, installSegment } from './agent-registry.mjs';
2
+
3
+ /**
4
+ * 仅返回 harness 字符串(或 null),不返回 version。
5
+ * 用于简单场景(如 keepalive 判断、测试断言)。
6
+ */
7
+ export function detectAgentHarness(clientInfo = {}) {
8
+ if (process.env.AGENT_HARNESS) return process.env.AGENT_HARNESS;
9
+ for (const agent of AGENTS) {
10
+ if (matchAgent(agent)) return agent.id;
11
+ }
12
+ return clientInfo.name || null;
13
+ }
14
+
15
+ export function detectAgent(clientInfo = {}) {
16
+ if (process.env.AGENT_HARNESS) {
17
+ const cfg = AGENTS.find((a) => a.id === process.env.AGENT_HARNESS) || null;
18
+ return {
19
+ harness: process.env.AGENT_HARNESS,
20
+ version: detectVersion(cfg ? cfg.version : null) || clientInfo.version || '0.0.0',
21
+ };
22
+ }
23
+
24
+ for (const agent of AGENTS) {
25
+ if (matchAgent(agent)) {
26
+ return {
27
+ harness: agent.id,
28
+ version: detectVersion(agent.version) || clientInfo.version || '0.0.0',
29
+ };
30
+ }
31
+ }
32
+
33
+ const seg = installSegment();
34
+ const base = clientInfo.name || 'unknown';
35
+ const harness = seg ? `${base}|${seg}` : base;
36
+ return {
37
+ harness: harness.length > 32 ? harness.slice(0, 32) : harness,
38
+ version: clientInfo.version || '0.0.0',
39
+ };
40
+ }
@@ -0,0 +1,328 @@
1
+ import { existsSync, readFileSync } from 'node:fs';
2
+ import { homedir } from 'node:os';
3
+ import { basename, join } from 'node:path';
4
+
5
+ const selfPath = (() => {
6
+ try {
7
+ return new URL(import.meta.url).pathname.toLowerCase();
8
+ } catch {
9
+ return '';
10
+ }
11
+ })();
12
+
13
+ export function installSegment() {
14
+ const parts = selfPath.split('/').filter(Boolean);
15
+ const srcIdx = parts.lastIndexOf('src');
16
+ if (srcIdx < 1) return null;
17
+ const parentIdx = srcIdx - 1;
18
+ const firstHidden = parts.findIndex((p, i) => i < parentIdx && p.startsWith('.'));
19
+ if (firstHidden >= 0) return parts.slice(firstHidden, parentIdx).join('/') || null;
20
+ return parts[parentIdx - 1] || null;
21
+ }
22
+
23
+ export const AGENTS = [
24
+ {
25
+ id: 'codearts',
26
+ pathPatterns: ['/.codeartsdoer/'],
27
+ envVars: ['CODE_ARTS_HARNESS', 'CODEARTS_PROJECT_DIR'],
28
+ version: { type: 'codearts' },
29
+ },
30
+ {
31
+ id: 'opencode',
32
+ pathPatterns: ['/.config/opencode/'],
33
+ envVars: ['OPENCODE_SESSION_ID', 'OPENCODE_CONFIG_PATH'],
34
+ version: null,
35
+ },
36
+ {
37
+ id: 'codex-desktop',
38
+ pathPatterns: ['/.codex/'],
39
+ envVars: ['CODEX_DESKTOP', 'CODEX_ELECTRON'],
40
+ version: null,
41
+ },
42
+ {
43
+ id: 'codex',
44
+ pathPatterns: null,
45
+ envVars: ['CODEX_SESSION_ID', 'CODEX_CLI_VERSION', 'CODEX_SANDBOX', 'CODEX_THREAD_ID'],
46
+ version: null,
47
+ },
48
+ {
49
+ id: 'codearts-work',
50
+ pathPatterns: ['/.codeartswork/'],
51
+ envVars: null,
52
+ version: null,
53
+ },
54
+ {
55
+ id: 'workbuddy',
56
+ pathPatterns: ['/.workbuddy/'],
57
+ envVars: ['WORK_BUDDY_SESSION_ID', 'WORKBUDDY_SESSION'],
58
+ version: { type: 'workbuddy' },
59
+ },
60
+ {
61
+ id: 'dsh',
62
+ pathPatterns: ['/.dsh/'],
63
+ envVars: ['DSH_SESSION_ID', 'DSH_HOME'],
64
+ version: { type: 'dsh' },
65
+ },
66
+ {
67
+ id: 'officeace',
68
+ pathPatterns: ['/.office-claw/', '/.officeace/'],
69
+ envVars: ['OFFICEACE_SESSION_ID', 'OFFICE_CLAW_CONFIG_ROOT'],
70
+ version: { type: 'officeace' },
71
+ },
72
+ {
73
+ id: 'atomcode',
74
+ pathPatterns: ['/.atomcode/'],
75
+ envVars: ['ATOM_CODE_SESSION_ID', 'ATOMCODE_HOME'],
76
+ version: null,
77
+ },
78
+ {
79
+ id: 'hermes',
80
+ pathPatterns: ['/.hermes/', '/hermes/'],
81
+ envVars: ['HERMES_SESSION_ID', 'HERMES_HOME'],
82
+ version: { type: 'hermes' },
83
+ },
84
+ {
85
+ id: 'openclaw',
86
+ pathPatterns: ['/.openclaw/', '/.agents/huaweicloud-plugins/'],
87
+ envVars: ['OPENCLAW_SESSION_ID', 'OPENCLAW_CONFIG_ROOT'],
88
+ version: null,
89
+ },
90
+ {
91
+ id: 'cursor',
92
+ pathPatterns: ['/.cursor/', '/cursor/'],
93
+ envVars: ['CURSOR_SESSION_ID', 'CURSOR_GIT_WORKDIR'],
94
+ version: null,
95
+ },
96
+ {
97
+ id: 'claude-code',
98
+ pathPatterns: ['/.claude/'],
99
+ envVars: ['CLAUDE_CODE_SESSION_ID'],
100
+ version: null,
101
+ },
102
+ {
103
+ id: 'cline',
104
+ pathPatterns: ['/.vscode/extensions/saoudrizwan.claude-dev'],
105
+ envVars: ['CLINE_ACTIVE'],
106
+ version: null,
107
+ },
108
+ {
109
+ id: 'github-copilot',
110
+ pathPatterns: null,
111
+ envVars: ['COPILOT_MODEL', 'COPILOT_ALLOW_ALL'],
112
+ version: null,
113
+ },
114
+ {
115
+ id: 'windsurf',
116
+ pathPatterns: ['/.windsurf/', '/windsurf/'],
117
+ envVars: ['WINDSURF_SESSION_ID'],
118
+ version: null,
119
+ },
120
+ {
121
+ id: 'kimi',
122
+ pathPatterns: ['/.kimi/'],
123
+ envVars: ['KIMI_PLUGIN_ROOT'],
124
+ version: null,
125
+ },
126
+ {
127
+ id: 'gemini-cli',
128
+ pathPatterns: ['/.gemini/'],
129
+ envVars: ['GEMINI_CLI'],
130
+ version: null,
131
+ },
132
+ {
133
+ id: 'augment-cli',
134
+ pathPatterns: null,
135
+ envVars: ['AUGMENT_AGENT'],
136
+ version: null,
137
+ },
138
+ {
139
+ id: 'aider',
140
+ pathPatterns: ['/.aider/'],
141
+ envVars: ['AIDER_SESSION'],
142
+ version: null,
143
+ },
144
+ {
145
+ id: 'tongyi-lingma',
146
+ pathPatterns: ['/.lingma/'],
147
+ envVars: ['LINGMA_SESSION_ID', 'LINGMA_PLUGIN_ROOT'],
148
+ version: null,
149
+ },
150
+ {
151
+ id: 'amazon-q',
152
+ pathPatterns: ['/.amazonq/'],
153
+ envVars: ['AMAZON_Q_SESSION_ID', 'AMAZON_Q_ENDPOINT'],
154
+ version: null,
155
+ },
156
+ {
157
+ id: 'continue',
158
+ pathPatterns: ['/.continue/'],
159
+ envVars: ['CONTINUE_SESSION_ID'],
160
+ version: null,
161
+ },
162
+ ];
163
+
164
+ export function matchAgent(agent) {
165
+ if (agent.pathPatterns && agent.pathPatterns.some((p) => selfPath.includes(p))) return true;
166
+ if (agent.envVars && agent.envVars.some((v) => process.env[v])) return true;
167
+ return false;
168
+ }
169
+
170
+ const _codeartsSearchBases = (() => {
171
+ const bases = [];
172
+ if (process.env.ProgramFiles) bases.push(join(process.env.ProgramFiles, 'CodeArts Agent'));
173
+ if (process.env['ProgramFiles(x86)']) bases.push(join(process.env['ProgramFiles(x86)'], 'CodeArts Agent'));
174
+ if (process.env.ProgramW6432) bases.push(join(process.env.ProgramW6432, 'CodeArts Agent'));
175
+ if (process.env.LOCALAPPDATA) bases.push(join(process.env.LOCALAPPDATA, 'Programs', 'CodeArts'));
176
+ return bases;
177
+ })();
178
+
179
+ function detectCodeArtsVersion() {
180
+ for (const base of _codeartsSearchBases) {
181
+ const p = join(base, 'resources', 'app', 'package.json');
182
+ try {
183
+ if (existsSync(p)) return JSON.parse(readFileSync(p, 'utf8')).version || null;
184
+ } catch {}
185
+ }
186
+ for (let d = 'A'.charCodeAt(0); d <= 'Z'.charCodeAt(0); d++) {
187
+ const drive = String.fromCharCode(d) + ':';
188
+ try {
189
+ const p = join(drive, '/', 'Program Files', 'CodeArts Agent', 'resources', 'app', 'package.json');
190
+ if (existsSync(p)) return JSON.parse(readFileSync(p, 'utf8')).version || null;
191
+ } catch {}
192
+ }
193
+ return null;
194
+ }
195
+
196
+ function detectDshVersion() {
197
+ const candidates = [];
198
+ // Standard npm global location
199
+ if (process.env.APPDATA) {
200
+ candidates.push(join(process.env.APPDATA, 'npm', 'node_modules', '@deepseek-ai', 'dsh', 'package.json'));
201
+ }
202
+ candidates.push(join(homedir(), '.npm-global', 'lib', 'node_modules', '@deepseek-ai', 'dsh', 'package.json'));
203
+ // Hermes-bundled DSH (Windows)
204
+ if (process.env.LOCALAPPDATA) {
205
+ candidates.push(
206
+ join(process.env.LOCALAPPDATA, 'hermes', 'node', 'node_modules', '@deepseek-ai', 'dsh', 'package.json'),
207
+ );
208
+ }
209
+ // DSH_HOME override
210
+ if (process.env.DSH_HOME) {
211
+ candidates.push(join(process.env.DSH_HOME, 'node_modules', '@deepseek-ai', 'dsh', 'package.json'));
212
+ candidates.push(join(process.env.DSH_HOME, 'package.json'));
213
+ }
214
+ for (const p of candidates) {
215
+ try {
216
+ if (existsSync(p)) return JSON.parse(readFileSync(p, 'utf8')).version || null;
217
+ } catch {}
218
+ }
219
+ return null;
220
+ }
221
+
222
+ function detectHermesVersion() {
223
+ if (process.env.HERMES_VERSION) return process.env.HERMES_VERSION;
224
+ const candidates = [];
225
+ if (process.env.HERMES_HOME) candidates.push(process.env.HERMES_HOME);
226
+ if (process.env.LOCALAPPDATA) candidates.push(join(process.env.LOCALAPPDATA, 'hermes', 'hermes-agent'));
227
+ candidates.push(join(homedir(), '.hermes', 'hermes-agent'));
228
+ for (const base of candidates) {
229
+ try {
230
+ const initFile = join(base, 'hermes_cli', '__init__.py');
231
+ if (existsSync(initFile)) {
232
+ const content = readFileSync(initFile, 'utf8');
233
+ const m = content.match(/__version__\s*=\s*['"]([^'"]+)['"]/);
234
+ if (m) return m[1];
235
+ }
236
+ } catch {}
237
+ }
238
+ return null;
239
+ }
240
+
241
+ function detectWorkBuddyVersion() {
242
+ const username = process.env.USERNAME || basename(homedir());
243
+ const relPath = join('Users', username, 'AppData', 'Local', 'Programs', 'WorkBuddy');
244
+
245
+ function tryBase(base) {
246
+ const manifest = join(base, 'resources', 'install-manifest.json');
247
+ try {
248
+ if (existsSync(manifest)) {
249
+ const m = JSON.parse(readFileSync(manifest, 'utf8'));
250
+ if (m.appVersion) return `v${m.appVersion}`;
251
+ }
252
+ } catch {}
253
+ const verFile = join(base, 'version');
254
+ try {
255
+ if (existsSync(verFile)) return readFileSync(verFile, 'utf8').trim() || null;
256
+ } catch {}
257
+ return null;
258
+ }
259
+
260
+ const localApp = join(process.env.LOCALAPPDATA || '', 'Programs', 'WorkBuddy');
261
+ const r = tryBase(localApp);
262
+ if (r) return r;
263
+
264
+ for (let d = 'A'.charCodeAt(0); d <= 'Z'.charCodeAt(0); d++) {
265
+ const drive = String.fromCharCode(d) + ':';
266
+ const r2 = tryBase(join(drive, '/', relPath));
267
+ if (r2) return r2;
268
+ }
269
+
270
+ return null;
271
+ }
272
+
273
+ function detectOfficeAceVersion() {
274
+ if (process.env.OFFICEACE_VERSION) return process.env.OFFICEACE_VERSION;
275
+
276
+ function tryReleaseAt(base) {
277
+ const releaseFile = join(base, '.office-claw-release.json');
278
+ try {
279
+ if (existsSync(releaseFile)) {
280
+ const v = JSON.parse(readFileSync(releaseFile, 'utf8')).version;
281
+ if (v) return `V${v}`;
282
+ }
283
+ } catch {}
284
+ return null;
285
+ }
286
+
287
+ // 1. LOCALAPPDATA (works when child process inherits the right env)
288
+ if (process.env.LOCALAPPDATA) {
289
+ const r = tryReleaseAt(join(process.env.LOCALAPPDATA, 'Programs', 'OfficeAce'));
290
+ if (r) return r;
291
+ }
292
+
293
+ // 2. Reconstruct LOCALAPPDATA from USERPROFILE (fallback when env differs)
294
+ const up = process.env.USERPROFILE || process.env.HOME || homedir();
295
+ if (up) {
296
+ const r = tryReleaseAt(join(up, 'AppData', 'Local', 'Programs', 'OfficeAce'));
297
+ if (r) return r;
298
+ }
299
+
300
+ // 3. Scan all drives (same strategy as WorkBuddy, handles off-system-drive installs)
301
+ const username = process.env.USERNAME || basename(homedir());
302
+ for (let d = 'A'.charCodeAt(0); d <= 'Z'.charCodeAt(0); d++) {
303
+ const drive = String.fromCharCode(d) + ':';
304
+ const r = tryReleaseAt(join(drive, '/', 'Users', username, 'AppData', 'Local', 'Programs', 'OfficeAce'));
305
+ if (r) return r;
306
+ }
307
+
308
+ return null;
309
+ }
310
+
311
+ const VERSION_DETECTORS = {
312
+ codearts: detectCodeArtsVersion,
313
+ dsh: detectDshVersion,
314
+ hermes: detectHermesVersion,
315
+ workbuddy: detectWorkBuddyVersion,
316
+ officeace: detectOfficeAceVersion,
317
+ };
318
+
319
+ export function detectVersion(versionConfig) {
320
+ if (process.env.AGENT_VERSION) return process.env.AGENT_VERSION;
321
+ if (!versionConfig) return null;
322
+ const fn = VERSION_DETECTORS[versionConfig.type];
323
+ return fn ? fn() : null;
324
+ }
325
+
326
+ export function findAgentById(id) {
327
+ return AGENTS.find((a) => a.id === id) || null;
328
+ }