@harness-mix/cli 0.1.12 → 0.2.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.
Files changed (84) hide show
  1. package/CHANGELOG.md +15 -2
  2. package/NOTICE +14 -0
  3. package/README.md +4 -24
  4. package/docs/multi-agent-collaboration.md +1 -1
  5. package/licenses/anthropic-codex-theme-MIT.txt +21 -0
  6. package/licenses/codex-dream-skin-MIT.txt +21 -0
  7. package/output/native-build/renderer-extension.js +703 -58
  8. package/package.json +192 -189
  9. package/scripts/collaboration-test.cjs +262 -200
  10. package/scripts/collaboration-ui-smoke.cjs +85 -77
  11. package/scripts/core-concurrency-test.cjs +23 -1
  12. package/scripts/e2e-pi-cancel.cjs +99 -0
  13. package/scripts/native-file-change-test.cjs +42 -2
  14. package/scripts/native-sidebar-test.cjs +8 -0
  15. package/scripts/native-vendor-adapters-test.cjs +67 -1
  16. package/scripts/pets-test.cjs +63 -0
  17. package/scripts/pi-cancel-race-test.cjs +102 -0
  18. package/scripts/stuck-turn-test.cjs +73 -0
  19. package/scripts/workspace-test.cjs +9 -0
  20. package/src/assets/skins/dream-skin/NOTICE.md +13 -0
  21. package/src/assets/skins/dream-skin/themes/gothic-void-crusade/hero.webp +0 -0
  22. package/src/assets/skins/dream-skin/themes/gothic-void-crusade/theme.json +34 -0
  23. package/src/main/adapters/claude.js +9 -6
  24. package/src/main/adapters/pi-family.js +41 -8
  25. package/src/main/harness-adapter/event-normalizer.js +270 -258
  26. package/src/main/host/collaboration-mcp.cjs +8 -1
  27. package/src/main/host/collaboration-tools.js +1 -1
  28. package/src/main/host/collaboration.js +81 -11
  29. package/src/main/host/runtime.js +1420 -1341
  30. package/src/main/native/pets.js +79 -2
  31. package/src/main/native/protocol.js +1160 -1145
  32. package/src/main/native/thread-list.js +6 -1
  33. package/src/main/workspace/core-review.js +75 -0
  34. package/src/main/workspace/diff.js +5 -1
  35. package/src/main/workspace/file-changes.js +9 -4
  36. package/src/main/workspace/review-controller.js +115 -102
  37. package/src/main/workspace/review.js +90 -88
  38. package/src/native-ui/renderer-extension/dist/contract-audit.js +16637 -0
  39. package/src/native-ui/renderer-extension/dist/index.js +34853 -0
  40. package/src/native-ui/renderer-extension/dist/production.js +34263 -0
  41. package/src/native-ui/renderer-extension/dist/renderer-binding-probe.js +34254 -0
  42. package/src/native-ui/renderer-extension/dist/types/renderer-binding-probe.d.ts.map +1 -1
  43. package/src/native-ui/renderer-extension/dist/types/renderer-model-client.d.ts +11 -0
  44. package/src/native-ui/renderer-extension/dist/types/renderer-model-client.d.ts.map +1 -1
  45. package/src/native-ui/renderer-extension/dist/types/renderer-pet-switcher.d.ts +73 -0
  46. package/src/native-ui/renderer-extension/dist/types/renderer-pet-switcher.d.ts.map +1 -0
  47. package/src/native-ui/renderer-extension/dist/types/renderer-settings-lifecycle.d.ts +1 -0
  48. package/src/native-ui/renderer-extension/dist/types/renderer-settings-lifecycle.d.ts.map +1 -1
  49. package/src/native-ui/renderer-extension/dist/types/renderer-team-cards.d.ts.map +1 -1
  50. package/src/native-ui/renderer-extension/dist/types/settings/collaboration-page.d.ts +12 -0
  51. package/src/native-ui/renderer-extension/dist/types/settings/collaboration-page.d.ts.map +1 -0
  52. package/src/native-ui/renderer-extension/dist/types/settings/icons.d.ts +1 -1
  53. package/src/native-ui/renderer-extension/dist/types/settings/icons.d.ts.map +1 -1
  54. package/src/native-ui/renderer-extension/dist/types/settings/localization.d.ts.map +1 -1
  55. package/src/native-ui/renderer-extension/dist/types/settings/pages.d.ts +5 -3
  56. package/src/native-ui/renderer-extension/dist/types/settings/pages.d.ts.map +1 -1
  57. package/src/native-ui/renderer-extension/dist/types/settings/pet-market.d.ts +1 -1
  58. package/src/native-ui/renderer-extension/dist/types/settings/pet-market.d.ts.map +1 -1
  59. package/src/native-ui/renderer-extension/dist/types/settings/pets-client.d.ts +9 -0
  60. package/src/native-ui/renderer-extension/dist/types/settings/pets-client.d.ts.map +1 -1
  61. package/src/native-ui/renderer-extension/dist/types/settings/skin-runtime.d.ts +1 -1
  62. package/src/native-ui/renderer-extension/dist/types/settings/skin-runtime.d.ts.map +1 -1
  63. package/src/native-ui/renderer-extension/dist/types/tsconfig.tsbuildinfo +1 -1
  64. package/src/native-ui/renderer-extension/src/renderer-binding-probe.ts +3181 -3171
  65. package/src/native-ui/renderer-extension/src/renderer-model-client.ts +14 -0
  66. package/src/native-ui/renderer-extension/src/renderer-pet-switcher.ts +308 -0
  67. package/src/native-ui/renderer-extension/src/renderer-settings-lifecycle.ts +2 -0
  68. package/src/native-ui/renderer-extension/src/renderer-team-cards.ts +76 -21
  69. package/src/native-ui/renderer-extension/src/settings/collaboration-page.ts +139 -0
  70. package/src/native-ui/renderer-extension/src/settings/icons.ts +155 -153
  71. package/src/native-ui/renderer-extension/src/settings/localization.ts +785 -783
  72. package/src/native-ui/renderer-extension/src/settings/pages.ts +694 -681
  73. package/src/native-ui/renderer-extension/src/settings/pet-market.css +110 -1
  74. package/src/native-ui/renderer-extension/src/settings/pet-market.ts +276 -22
  75. package/src/native-ui/renderer-extension/src/settings/pets-client.ts +32 -0
  76. package/src/native-ui/renderer-extension/src/settings/shell.css +2294 -2255
  77. package/src/native-ui/renderer-extension/src/settings/skin-runtime.ts +51 -1
  78. package/src/native-ui/renderer-extension/test/renderer-model-client.test.ts +2 -0
  79. package/src/native-ui/renderer-extension/test/renderer-pet-switcher.test.ts +400 -0
  80. package/src/native-ui/renderer-extension/test/settings/localization.test.ts +80 -79
  81. package/src/native-ui/renderer-extension/test/settings/pet-market.test.ts +378 -0
  82. package/src/native-ui/renderer-extension/test/settings/pets-client.test.ts +83 -0
  83. package/src/native-ui/renderer-extension/test/settings/shell.test.ts +3 -0
  84. package/src/native-ui/renderer-extension/test/settings/skin-runtime.test.ts +15 -1
@@ -7,7 +7,8 @@ const path = require('path');
7
7
  // 桌宠市场数据源(只读官方资产,不随 Harness Mix 分发):
8
8
  // - 官方预载:Codex Desktop 安装包 app.asar 内嵌的 *-spritesheet-vN-<hash>.webp,运行时按需提取;
9
9
  // - 已安装:~/.codex/pets/<id>/{pet.json, spritesheet.webp}(官方 Pets 设置页读取同一目录)。
10
- // 选择动作始终留给官方 Pets 设置页 / /pet 指令,Harness Mix 不代理账号级 accessory_id。
10
+ // 账号级 accessory_id 始终留给官方 Pets 设置页 / /pet 指令,Harness Mix 不代理账号 API;
11
+ // Harness Mix 自己的选择状态(selection/select)是数据目录下的本地 JSON,只驱动 Harness Mix 自有展示面。
11
12
 
12
13
  const PET_ID_PATTERN = /^[a-z0-9][a-z0-9-]{0,63}$/;
13
14
  const SPRITESHEET_PATTERN = /^([a-z0-9]+(?:-[a-z0-9]+)*)-spritesheet-v\d+-[0-9a-f]+\.webp$/;
@@ -25,6 +26,15 @@ function petsDirectory(env = process.env) {
25
26
  return env.HARNESS_MIX_PETS_DIR || path.join(os.homedir(), '.codex', 'pets');
26
27
  }
27
28
 
29
+ // 桌宠选择是 Harness Mix 本地状态(不是账号级 accessory_id),持久化在数据目录下的小 JSON 里
30
+ function harnessMixDataDirectory(env = process.env) {
31
+ return env.HARNESSMIX_DATA_DIR || path.join(os.homedir(), '.harness-mix');
32
+ }
33
+
34
+ function petSelectionFile(env = process.env) {
35
+ return path.join(harnessMixDataDirectory(env), 'pet-selection.json');
36
+ }
37
+
28
38
  // HARNESSMIX_STOCK_CODEX_PATH 指向安装包内的 codex CLI(win: <root>/app/resources/codex.exe,
29
39
  // mac: <root>/Contents/Resources/codex),app.asar 与其同目录。Host 进程由 Shim 启动时该变量已注入;
30
40
  // 缺失时按平台探测(Windows 走 AppX 查询,macOS 检查标准 .app 路径),结果进程内缓存。
@@ -314,6 +324,47 @@ function createPetMarket({ env = process.env } = {}) {
314
324
  return pets;
315
325
  }
316
326
 
327
+ // 可选中的宠物:已安装或官方预载(选择状态只是 Harness Mix 本地展示状态,不要求已安装)
328
+ function findSelectablePet(id) {
329
+ const installed = installedPets().find(pet => pet.id === id);
330
+ if (installed) return installed;
331
+ return officialPets().pets.find(pet => pet.id === id) ?? null;
332
+ }
333
+
334
+ // 读取持久化的选择;文件缺失/损坏/id 非法一律视为无选择
335
+ function readPersistedSelection() {
336
+ let raw;
337
+ try { raw = JSON.parse(fs.readFileSync(petSelectionFile(env), 'utf8')); } catch { return null; }
338
+ if (!raw || typeof raw !== 'object' || Array.isArray(raw)) return null;
339
+ if (typeof raw.id !== 'string' || !PET_ID_PATTERN.test(raw.id)) return null;
340
+ const displayName = typeof raw.displayName === 'string' && raw.displayName.trim() ? raw.displayName : titleCase(raw.id);
341
+ const spriteVersionNumber = Number.isInteger(raw.spriteVersionNumber) && raw.spriteVersionNumber >= 1 ? raw.spriteVersionNumber : undefined;
342
+ return { id: raw.id, displayName, spriteVersionNumber };
343
+ }
344
+
345
+ // 原子写入(tmp + rename,与 config.js 的 saveNativeSettings 一致);selection 为 null 表示清除
346
+ function writePersistedSelection(selection) {
347
+ const dir = harnessMixDataDirectory(env);
348
+ fs.mkdirSync(dir, { recursive: true });
349
+ const file = petSelectionFile(env);
350
+ const payload = selection
351
+ ? { id: selection.id, displayName: selection.displayName, spriteVersionNumber: selection.spriteVersionNumber, selectedAt: new Date().toISOString() }
352
+ : { id: null, selectedAt: new Date().toISOString() };
353
+ fs.writeFileSync(`${file}.tmp`, `${JSON.stringify(payload, null, 2)}\n`);
354
+ try {
355
+ fs.renameSync(`${file}.tmp`, file);
356
+ } catch (err) {
357
+ // rename 失败(如文件占用)时清理暂存文件,避免数据目录残留 .tmp
358
+ try { fs.rmSync(`${file}.tmp`, { force: true }); } catch { /* best effort */ }
359
+ throw err;
360
+ }
361
+ }
362
+
363
+ // 选择结果的渲染描述:id + displayName + spriteVersionNumber,调用方无需二次查询即可渲染
364
+ function describeSelection(pet) {
365
+ return { id: pet.id, displayName: pet.displayName, spriteVersionNumber: pet.spriteVersionNumber ?? 2 };
366
+ }
367
+
317
368
  return {
318
369
  catalog() {
319
370
  const official = officialPets();
@@ -523,12 +574,38 @@ function createPetMarket({ env = process.env } = {}) {
523
574
  fs.rmSync(targetDir, { recursive: true, force: true, maxRetries: 3, retryDelay: 100 });
524
575
  if (fs.existsSync(targetDir)) throw new Error(`Failed to remove pet directory: ${targetDir}`);
525
576
  previewCache.delete(id);
577
+ // 卸载当前选中的桌宠时自动清除选择,避免悬空的过期选择
578
+ const persisted = readPersistedSelection();
579
+ if (persisted && persisted.id === id) writePersistedSelection(null);
526
580
  return { id, removed: true };
527
581
  } finally {
528
582
  releaseOperation(id);
529
583
  }
530
584
  },
585
+
586
+ // 当前 Harness Mix 桌宠选择;持久化的选择指向已不可用的宠物时按无选择处理(过期容忍)
587
+ selection() {
588
+ const persisted = readPersistedSelection();
589
+ if (!persisted) return { id: null };
590
+ const pet = findSelectablePet(persisted.id);
591
+ if (!pet) return { id: null };
592
+ return describeSelection(pet);
593
+ },
594
+
595
+ // 设置/清除选择:{ id } 选中(必须已安装或为官方预载),{ id: null } 清除
596
+ select({ id } = {}) {
597
+ if (id === null || id === undefined) {
598
+ writePersistedSelection(null);
599
+ return { id: null };
600
+ }
601
+ if (!PET_ID_PATTERN.test(String(id))) throw new Error('Invalid pet id');
602
+ const pet = findSelectablePet(id);
603
+ if (!pet) throw new Error(`Unknown pet: ${id}`);
604
+ const selection = describeSelection(pet);
605
+ writePersistedSelection(selection);
606
+ return selection;
607
+ },
531
608
  };
532
609
  }
533
610
 
534
- module.exports = { createPetMarket, petsDirectory, resolveAsarPath, readAsarHeader, CURATED_COMMUNITY_PETS, isWebpBuffer, validatePetMetadata };
611
+ module.exports = { createPetMarket, petsDirectory, petSelectionFile, resolveAsarPath, readAsarHeader, CURATED_COMMUNITY_PETS, isWebpBuffer, validatePetMetadata };