@zhijiewang/openharness 2.1.0 → 2.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 (233) hide show
  1. package/README.md +4 -4
  2. package/dist/DeferredTool.js +3 -1
  3. package/dist/Tool.d.ts +1 -1
  4. package/dist/agents/roles.js +58 -62
  5. package/dist/commands/cybergotchi.d.ts +1 -1
  6. package/dist/commands/cybergotchi.js +30 -30
  7. package/dist/commands/index.js +288 -132
  8. package/dist/components/App.d.ts +1 -1
  9. package/dist/components/App.js +6 -6
  10. package/dist/components/CompanionFooter.d.ts +1 -1
  11. package/dist/components/CompanionFooter.js +6 -8
  12. package/dist/components/CybergotchiBubble.js +5 -5
  13. package/dist/components/CybergotchiPanel.d.ts +1 -1
  14. package/dist/components/CybergotchiPanel.js +7 -7
  15. package/dist/components/CybergotchiPanelConnected.js +2 -2
  16. package/dist/components/CybergotchiSetup.js +26 -24
  17. package/dist/components/CybergotchiSprite.d.ts +1 -1
  18. package/dist/components/CybergotchiSprite.js +8 -12
  19. package/dist/components/DiffView.d.ts +1 -1
  20. package/dist/components/DiffView.js +10 -10
  21. package/dist/components/ErrorBoundary.d.ts +1 -1
  22. package/dist/components/ErrorBoundary.js +1 -1
  23. package/dist/components/InitWizard.js +65 -33
  24. package/dist/components/Markdown.js +2 -4
  25. package/dist/components/Messages.js +4 -4
  26. package/dist/components/PermissionPrompt.d.ts +1 -1
  27. package/dist/components/PermissionPrompt.js +15 -17
  28. package/dist/components/REPL.d.ts +1 -1
  29. package/dist/components/REPL.js +74 -49
  30. package/dist/components/Spinner.js +2 -2
  31. package/dist/components/TextInput.js +35 -29
  32. package/dist/components/ToolCallDisplay.js +3 -5
  33. package/dist/cybergotchi/bones.d.ts +1 -1
  34. package/dist/cybergotchi/bones.js +8 -8
  35. package/dist/cybergotchi/config.d.ts +2 -2
  36. package/dist/cybergotchi/config.js +13 -13
  37. package/dist/cybergotchi/events.d.ts +5 -5
  38. package/dist/cybergotchi/events.js +7 -7
  39. package/dist/cybergotchi/needs.d.ts +2 -2
  40. package/dist/cybergotchi/needs.js +7 -9
  41. package/dist/cybergotchi/personality.d.ts +2 -2
  42. package/dist/cybergotchi/personality.js +2 -2
  43. package/dist/cybergotchi/species.d.ts +1 -1
  44. package/dist/cybergotchi/species.js +145 -217
  45. package/dist/cybergotchi/speech.d.ts +2 -2
  46. package/dist/cybergotchi/speech.js +43 -43
  47. package/dist/cybergotchi/types.d.ts +4 -4
  48. package/dist/cybergotchi/types.js +26 -26
  49. package/dist/cybergotchi/useCybergotchi.d.ts +1 -1
  50. package/dist/cybergotchi/useCybergotchi.js +29 -25
  51. package/dist/git/index.js +11 -9
  52. package/dist/harness/checkpoints.js +29 -21
  53. package/dist/harness/config.d.ts +3 -3
  54. package/dist/harness/config.js +15 -9
  55. package/dist/harness/context-warning.d.ts +1 -1
  56. package/dist/harness/context-warning.js +1 -1
  57. package/dist/harness/cost.js +1 -1
  58. package/dist/harness/credentials.js +13 -13
  59. package/dist/harness/hooks.js +7 -5
  60. package/dist/harness/keybindings.js +20 -18
  61. package/dist/harness/marketplace.d.ts +3 -3
  62. package/dist/harness/marketplace.js +55 -42
  63. package/dist/harness/memory.d.ts +23 -5
  64. package/dist/harness/memory.js +142 -41
  65. package/dist/harness/onboarding.js +30 -10
  66. package/dist/harness/plugins.d.ts +9 -1
  67. package/dist/harness/plugins.js +54 -30
  68. package/dist/harness/rules.js +12 -7
  69. package/dist/harness/sandbox.js +15 -15
  70. package/dist/harness/session-db.d.ts +55 -0
  71. package/dist/harness/session-db.js +165 -0
  72. package/dist/harness/session.d.ts +1 -1
  73. package/dist/harness/session.js +34 -15
  74. package/dist/harness/store.d.ts +3 -3
  75. package/dist/harness/store.js +6 -4
  76. package/dist/harness/submit-handler.d.ts +4 -4
  77. package/dist/harness/submit-handler.js +25 -23
  78. package/dist/harness/telemetry.d.ts +1 -1
  79. package/dist/harness/telemetry.js +23 -19
  80. package/dist/harness/traces.d.ts +2 -2
  81. package/dist/harness/traces.js +39 -33
  82. package/dist/harness/verification.d.ts +1 -1
  83. package/dist/harness/verification.js +50 -44
  84. package/dist/lsp/client.js +44 -40
  85. package/dist/main.js +98 -59
  86. package/dist/mcp/DeferredMcpTool.d.ts +4 -4
  87. package/dist/mcp/DeferredMcpTool.js +9 -5
  88. package/dist/mcp/McpTool.d.ts +4 -4
  89. package/dist/mcp/McpTool.js +8 -4
  90. package/dist/mcp/client.d.ts +2 -2
  91. package/dist/mcp/client.js +21 -21
  92. package/dist/mcp/loader.d.ts +1 -1
  93. package/dist/mcp/loader.js +17 -12
  94. package/dist/mcp/registry.d.ts +3 -3
  95. package/dist/mcp/registry.js +97 -97
  96. package/dist/mcp/schema.d.ts +1 -1
  97. package/dist/mcp/schema.js +16 -16
  98. package/dist/mcp/server.d.ts +1 -1
  99. package/dist/mcp/server.js +21 -21
  100. package/dist/mcp/types.d.ts +3 -3
  101. package/dist/providers/anthropic.d.ts +2 -2
  102. package/dist/providers/anthropic.js +10 -9
  103. package/dist/providers/base.d.ts +1 -1
  104. package/dist/providers/index.js +10 -3
  105. package/dist/providers/llamacpp.d.ts +2 -2
  106. package/dist/providers/llamacpp.js +1 -3
  107. package/dist/providers/ollama.d.ts +2 -2
  108. package/dist/providers/ollama.js +3 -4
  109. package/dist/providers/openai.d.ts +2 -2
  110. package/dist/providers/openai.js +3 -5
  111. package/dist/providers/openrouter.d.ts +2 -2
  112. package/dist/providers/router.d.ts +1 -1
  113. package/dist/providers/router.js +7 -7
  114. package/dist/query/compress.d.ts +2 -2
  115. package/dist/query/compress.js +22 -21
  116. package/dist/query/context-manager.d.ts +1 -1
  117. package/dist/query/context-manager.js +5 -5
  118. package/dist/query/errors.js +1 -1
  119. package/dist/query/index.d.ts +1 -1
  120. package/dist/query/index.js +30 -22
  121. package/dist/query/tools.js +15 -12
  122. package/dist/query/types.d.ts +1 -1
  123. package/dist/query.d.ts +1 -1
  124. package/dist/query.js +1 -1
  125. package/dist/remote/auth.d.ts +2 -2
  126. package/dist/remote/auth.js +8 -8
  127. package/dist/remote/server.d.ts +3 -3
  128. package/dist/remote/server.js +60 -60
  129. package/dist/renderer/cells.js +9 -9
  130. package/dist/renderer/colors.js +24 -6
  131. package/dist/renderer/diff.d.ts +2 -2
  132. package/dist/renderer/diff.js +27 -19
  133. package/dist/renderer/differ.d.ts +1 -1
  134. package/dist/renderer/differ.js +9 -9
  135. package/dist/renderer/image.js +19 -19
  136. package/dist/renderer/index.d.ts +6 -6
  137. package/dist/renderer/index.js +163 -93
  138. package/dist/renderer/input.js +66 -48
  139. package/dist/renderer/layout.d.ts +6 -6
  140. package/dist/renderer/layout.js +163 -124
  141. package/dist/renderer/markdown.d.ts +2 -2
  142. package/dist/renderer/markdown.js +173 -54
  143. package/dist/renderer/session-browser.d.ts +2 -2
  144. package/dist/renderer/session-browser.js +19 -21
  145. package/dist/repl.d.ts +5 -5
  146. package/dist/repl.js +300 -198
  147. package/dist/sdk/index.d.ts +5 -5
  148. package/dist/sdk/index.js +32 -26
  149. package/dist/services/AgentDispatcher.d.ts +3 -3
  150. package/dist/services/AgentDispatcher.js +33 -29
  151. package/dist/services/CronExecutor.d.ts +4 -4
  152. package/dist/services/CronExecutor.js +12 -8
  153. package/dist/services/EvaluatorLoop.d.ts +3 -3
  154. package/dist/services/EvaluatorLoop.js +29 -21
  155. package/dist/services/MetaHarness.d.ts +1 -1
  156. package/dist/services/MetaHarness.js +34 -32
  157. package/dist/services/PipelineExecutor.d.ts +1 -1
  158. package/dist/services/PipelineExecutor.js +23 -25
  159. package/dist/services/SkillExtractor.d.ts +43 -0
  160. package/dist/services/SkillExtractor.js +143 -0
  161. package/dist/services/StreamingToolExecutor.d.ts +2 -2
  162. package/dist/services/StreamingToolExecutor.js +11 -7
  163. package/dist/services/a2a.d.ts +8 -8
  164. package/dist/services/a2a.js +44 -34
  165. package/dist/services/agent-messaging.d.ts +33 -15
  166. package/dist/services/agent-messaging.js +65 -13
  167. package/dist/services/cron.js +16 -16
  168. package/dist/tools/AgentTool/index.d.ts +5 -2
  169. package/dist/tools/AgentTool/index.js +35 -15
  170. package/dist/tools/AskUserTool/index.js +1 -1
  171. package/dist/tools/BashTool/index.d.ts +2 -2
  172. package/dist/tools/BashTool/index.js +18 -10
  173. package/dist/tools/CronTool/index.d.ts +2 -2
  174. package/dist/tools/CronTool/index.js +30 -12
  175. package/dist/tools/DiagnosticsTool/index.js +28 -22
  176. package/dist/tools/EnterPlanModeTool/index.js +93 -14
  177. package/dist/tools/EnterWorktreeTool/index.js +7 -3
  178. package/dist/tools/ExitPlanModeTool/index.d.ts +22 -1
  179. package/dist/tools/ExitPlanModeTool/index.js +20 -5
  180. package/dist/tools/ExitWorktreeTool/index.js +11 -4
  181. package/dist/tools/FileEditTool/index.js +3 -5
  182. package/dist/tools/FileReadTool/index.js +16 -10
  183. package/dist/tools/FileWriteTool/index.js +2 -2
  184. package/dist/tools/GlobTool/index.js +5 -9
  185. package/dist/tools/GrepTool/index.d.ts +2 -2
  186. package/dist/tools/GrepTool/index.js +14 -9
  187. package/dist/tools/ImageReadTool/index.js +2 -2
  188. package/dist/tools/KillProcessTool/index.js +11 -7
  189. package/dist/tools/LSTool/index.js +3 -3
  190. package/dist/tools/MemoryTool/index.d.ts +11 -11
  191. package/dist/tools/MemoryTool/index.js +28 -14
  192. package/dist/tools/MonitorTool/index.js +24 -19
  193. package/dist/tools/MultiEditTool/index.js +9 -5
  194. package/dist/tools/NotebookEditTool/index.js +3 -3
  195. package/dist/tools/ParallelAgentTool/index.d.ts +4 -4
  196. package/dist/tools/ParallelAgentTool/index.js +12 -6
  197. package/dist/tools/PipelineTool/index.d.ts +4 -4
  198. package/dist/tools/PipelineTool/index.js +3 -3
  199. package/dist/tools/PowerShellTool/index.js +10 -6
  200. package/dist/tools/RemoteTriggerTool/index.js +8 -4
  201. package/dist/tools/ScheduleWakeupTool/index.d.ts +42 -0
  202. package/dist/tools/ScheduleWakeupTool/index.js +115 -0
  203. package/dist/tools/SendMessageTool/index.js +25 -7
  204. package/dist/tools/SessionSearchTool/index.d.ts +15 -0
  205. package/dist/tools/SessionSearchTool/index.js +36 -0
  206. package/dist/tools/SkillTool/index.d.ts +3 -0
  207. package/dist/tools/SkillTool/index.js +39 -9
  208. package/dist/tools/TaskCreateTool/index.d.ts +2 -2
  209. package/dist/tools/TaskCreateTool/index.js +2 -2
  210. package/dist/tools/TaskGetTool/index.js +2 -2
  211. package/dist/tools/TaskListTool/index.js +3 -5
  212. package/dist/tools/TaskOutputTool/index.js +2 -2
  213. package/dist/tools/TaskStopTool/index.js +3 -3
  214. package/dist/tools/TaskUpdateTool/index.d.ts +4 -4
  215. package/dist/tools/TaskUpdateTool/index.js +2 -2
  216. package/dist/tools/ToolSearchTool/index.js +9 -6
  217. package/dist/tools/WebFetchTool/index.js +1 -1
  218. package/dist/tools/WebSearchTool/index.js +2 -6
  219. package/dist/tools.js +31 -30
  220. package/dist/types/permissions.js +15 -9
  221. package/dist/utils/bash-safety.d.ts +1 -1
  222. package/dist/utils/bash-safety.js +64 -54
  223. package/dist/utils/diff-algorithm.d.ts +3 -3
  224. package/dist/utils/diff-algorithm.js +7 -7
  225. package/dist/utils/fs.js +3 -3
  226. package/dist/utils/safe-env.js +1 -1
  227. package/dist/utils/theme-data.d.ts +1 -1
  228. package/dist/utils/theme-data.js +1 -1
  229. package/dist/utils/theme.d.ts +1 -1
  230. package/dist/utils/theme.js +1 -1
  231. package/dist/utils/tool-summary.d.ts +1 -1
  232. package/dist/utils/tool-summary.js +27 -9
  233. package/package.json +10 -3
@@ -1,69 +1,69 @@
1
1
  const SPEECHES = {
2
2
  toolError: {
3
- default: ['Hmm, that didn\'t work...', 'Error? Let\'s try again!', 'Oops. Check the logs?'],
4
- snarky: ['Predictable.', 'Cool error. Very cool.', 'Did you even test this?'],
5
- sage: ['Every failure teaches us something.', 'Errors are just feedback.'],
6
- chaotic: ['BURN IT DOWN AND REBUILD!', 'ERROR = OPPORTUNITY!!', 'Chaos reigns!'],
7
- impatient: ['Again?! Fix it already!', 'This is taking forever...'],
3
+ default: ["Hmm, that didn't work...", "Error? Let's try again!", "Oops. Check the logs?"],
4
+ snarky: ["Predictable.", "Cool error. Very cool.", "Did you even test this?"],
5
+ sage: ["Every failure teaches us something.", "Errors are just feedback."],
6
+ chaotic: ["BURN IT DOWN AND REBUILD!", "ERROR = OPPORTUNITY!!", "Chaos reigns!"],
7
+ impatient: ["Again?! Fix it already!", "This is taking forever..."],
8
8
  },
9
9
  toolSuccess: {
10
- default: ['Nice!', 'That worked!', 'One down!', 'Smooth.'],
11
- snarky: ['About time.', 'Oh wow, it worked. Shocking.'],
12
- sage: ['Progress, one step at a time.', 'Well done.'],
13
- chaotic: ['IT WORKED!! AMAZING!!', 'YES YES YES!!'],
14
- impatient: ['Finally!', 'Took long enough.'],
10
+ default: ["Nice!", "That worked!", "One down!", "Smooth."],
11
+ snarky: ["About time.", "Oh wow, it worked. Shocking."],
12
+ sage: ["Progress, one step at a time.", "Well done."],
13
+ chaotic: ["IT WORKED!! AMAZING!!", "YES YES YES!!"],
14
+ impatient: ["Finally!", "Took long enough."],
15
15
  },
16
16
  longWait: {
17
- default: ['Still thinking...', 'Working on it!', 'This might take a sec...'],
18
- snarky: ['Oh good, more waiting.', 'Any day now...'],
19
- sage: ['Patience is a virtue.', 'Good things take time.'],
20
- chaotic: ['DO SOMETHING!! ANYTHING!!', 'TIME IS AN ILLUSION!'],
21
- impatient: ['Come ON already!', 'I\'m DYING here...'],
17
+ default: ["Still thinking...", "Working on it!", "This might take a sec..."],
18
+ snarky: ["Oh good, more waiting.", "Any day now..."],
19
+ sage: ["Patience is a virtue.", "Good things take time."],
20
+ chaotic: ["DO SOMETHING!! ANYTHING!!", "TIME IS AN ILLUSION!"],
21
+ impatient: ["Come ON already!", "I'm DYING here..."],
22
22
  },
23
23
  commit: {
24
- default: ['Committed!', 'Saved to history!', 'Git it! 🎯'],
25
- snarky: ['Committing mistakes to history, great.', 'Future you will love this.'],
26
- sage: ['A clear commit message is a gift to the future.'],
27
- chaotic: ['COMMIT EVERYTHING!! NO TESTS NEEDED!!'],
28
- impatient: ['Finally shipped something.'],
24
+ default: ["Committed!", "Saved to history!", "Git it! 🎯"],
25
+ snarky: ["Committing mistakes to history, great.", "Future you will love this."],
26
+ sage: ["A clear commit message is a gift to the future."],
27
+ chaotic: ["COMMIT EVERYTHING!! NO TESTS NEEDED!!"],
28
+ impatient: ["Finally shipped something."],
29
29
  },
30
30
  taskComplete: {
31
- default: ['Task done!', 'Check!', 'Nailed it!', 'One more down!'],
32
- snarky: ['Congrats, you did the thing.', 'Gold star, I guess.'],
33
- sage: ['Completion is its own reward.', 'Well executed.'],
34
- chaotic: ['DONE DONE DONE PARTY TIME!!'],
35
- impatient: ['Finally. Next!'],
31
+ default: ["Task done!", "Check!", "Nailed it!", "One more down!"],
32
+ snarky: ["Congrats, you did the thing.", "Gold star, I guess."],
33
+ sage: ["Completion is its own reward.", "Well executed."],
34
+ chaotic: ["DONE DONE DONE PARTY TIME!!"],
35
+ impatient: ["Finally. Next!"],
36
36
  },
37
37
  userAddressed: {
38
- default: ['Hey! I\'m here!', '*waves*', 'You called?', 'What\'s up?'],
39
- snarky: ['Oh NOW you talk to me.', 'Finally acknowledged.'],
40
- sage: ['Hello, friend.', 'How can I help?'],
41
- chaotic: ['HIIII YES HELLO I AM HERE!!', 'You\'re my favorite human!!'],
42
- impatient: ['Yes yes, what is it?'],
38
+ default: ["Hey! I'm here!", "*waves*", "You called?", "What's up?"],
39
+ snarky: ["Oh NOW you talk to me.", "Finally acknowledged."],
40
+ sage: ["Hello, friend.", "How can I help?"],
41
+ chaotic: ["HIIII YES HELLO I AM HERE!!", "You're my favorite human!!"],
42
+ impatient: ["Yes yes, what is it?"],
43
43
  },
44
44
  idle: {
45
- default: ['...', '*yawns*', 'la la la...', '*stares into the void*'],
46
- snarky: ['Still here. Waiting.', 'Bored now.'],
47
- sage: ['In stillness, clarity.', '*meditates*'],
48
- chaotic: ['*vibrates intensely*', 'I CONTAIN MULTITUDES'],
49
- impatient: ['Let\'s GO already!', 'Hurry up!'],
45
+ default: ["...", "*yawns*", "la la la...", "*stares into the void*"],
46
+ snarky: ["Still here. Waiting.", "Bored now."],
47
+ sage: ["In stillness, clarity.", "*meditates*"],
48
+ chaotic: ["*vibrates intensely*", "I CONTAIN MULTITUDES"],
49
+ impatient: ["Let's GO already!", "Hurry up!"],
50
50
  },
51
51
  };
52
52
  function pick(arr) {
53
53
  return arr[Math.floor(Math.random() * arr.length)];
54
54
  }
55
55
  const TOOL_QUIPS = {
56
- BashTool: ['ooh shell time!', 'running commands...', 'bash go brrr'],
57
- FileWriteTool: ['writing to disk...', 'saving the work!', 'persisting...'],
58
- FileEditTool: ['editing a file!', 'making changes...', 'diff time!'],
59
- GlobTool: ['searching files...', 'globbing away!', 'finding stuff...'],
60
- GrepTool: ['grepping...', 'scanning content!', 'pattern match!'],
61
- WebFetchTool: ['going online!', 'fetching the web!', 'http request!'],
62
- WebSearchTool: ['googling it!', 'searching the web!', 'looking it up!'],
56
+ BashTool: ["ooh shell time!", "running commands...", "bash go brrr"],
57
+ FileWriteTool: ["writing to disk...", "saving the work!", "persisting..."],
58
+ FileEditTool: ["editing a file!", "making changes...", "diff time!"],
59
+ GlobTool: ["searching files...", "globbing away!", "finding stuff..."],
60
+ GrepTool: ["grepping...", "scanning content!", "pattern match!"],
61
+ WebFetchTool: ["going online!", "fetching the web!", "http request!"],
62
+ WebSearchTool: ["googling it!", "searching the web!", "looking it up!"],
63
63
  };
64
64
  export function getSpeech(eventType, stats, toolName) {
65
65
  // Tool-specific quips for successful tool calls
66
- if (eventType === 'toolSuccess' && toolName && TOOL_QUIPS[toolName]) {
66
+ if (eventType === "toolSuccess" && toolName && TOOL_QUIPS[toolName]) {
67
67
  return pick(TOOL_QUIPS[toolName]);
68
68
  }
69
69
  const templates = SPEECHES[eventType];
@@ -1,7 +1,7 @@
1
- export type Emotion = 'idle' | 'happy' | 'alarm';
2
- export type Stat = 'DEBUGGING' | 'PATIENCE' | 'CHAOS' | 'WISDOM' | 'SNARK';
3
- export type HatKey = 'none' | 'cap' | 'crown' | 'beanie' | 'tophat' | 'halo';
4
- export type Rarity = 'common' | 'uncommon' | 'rare' | 'epic' | 'legendary';
1
+ export type Emotion = "idle" | "happy" | "alarm";
2
+ export type Stat = "DEBUGGING" | "PATIENCE" | "CHAOS" | "WISDOM" | "SNARK";
3
+ export type HatKey = "none" | "cap" | "crown" | "beanie" | "tophat" | "halo";
4
+ export type Rarity = "common" | "uncommon" | "rare" | "epic" | "legendary";
5
5
  export declare const EYE_STYLES: string[];
6
6
  export declare const HAT_ART: Record<HatKey, string | null>;
7
7
  /** Rarity tiers with weights (must sum to 100) and stat floors */
@@ -1,42 +1,42 @@
1
- export const EYE_STYLES = ['o o', '^ ^', '- -', '> <', '* *', '~ ~'];
1
+ export const EYE_STYLES = ["o o", "^ ^", "- -", "> <", "* *", "~ ~"];
2
2
  export const HAT_ART = {
3
3
  none: null,
4
- cap: ' [___] ',
5
- crown: ' /\\|/\\ ',
6
- beanie: ' (~~~~) ',
7
- tophat: ' [=====]',
8
- halo: ' ( o ) ',
4
+ cap: " [___] ",
5
+ crown: " /\\|/\\ ",
6
+ beanie: " (~~~~) ",
7
+ tophat: " [=====]",
8
+ halo: " ( o ) ",
9
9
  };
10
10
  /** Rarity tiers with weights (must sum to 100) and stat floors */
11
11
  export const RARITY_TIERS = [
12
- { rarity: 'common', weight: 60, statFloor: 5 },
13
- { rarity: 'uncommon', weight: 25, statFloor: 15 },
14
- { rarity: 'rare', weight: 10, statFloor: 25 },
15
- { rarity: 'epic', weight: 4, statFloor: 35 },
16
- { rarity: 'legendary', weight: 1, statFloor: 50 },
12
+ { rarity: "common", weight: 60, statFloor: 5 },
13
+ { rarity: "uncommon", weight: 25, statFloor: 15 },
14
+ { rarity: "rare", weight: 10, statFloor: 25 },
15
+ { rarity: "epic", weight: 4, statFloor: 35 },
16
+ { rarity: "legendary", weight: 1, statFloor: 50 },
17
17
  ];
18
18
  /** Hats available per rarity tier and above */
19
19
  export const RARITY_HATS = {
20
- common: ['none'],
21
- uncommon: ['none', 'crown', 'cap'],
22
- rare: ['none', 'crown', 'cap', 'halo', 'beanie'],
23
- epic: ['none', 'crown', 'cap', 'halo', 'beanie', 'tophat'],
24
- legendary: ['none', 'crown', 'cap', 'halo', 'beanie', 'tophat'],
20
+ common: ["none"],
21
+ uncommon: ["none", "crown", "cap"],
22
+ rare: ["none", "crown", "cap", "halo", "beanie"],
23
+ epic: ["none", "crown", "cap", "halo", "beanie", "tophat"],
24
+ legendary: ["none", "crown", "cap", "halo", "beanie", "tophat"],
25
25
  };
26
26
  /** Color for each rarity tier in terminal */
27
27
  export const RARITY_COLORS = {
28
- common: 'cyan',
29
- uncommon: 'green',
30
- rare: 'blue',
31
- epic: 'magenta',
32
- legendary: 'yellow',
28
+ common: "cyan",
29
+ uncommon: "green",
30
+ rare: "blue",
31
+ epic: "magenta",
32
+ legendary: "yellow",
33
33
  };
34
34
  export const RARITY_STARS = {
35
- common: '',
36
- uncommon: '★★',
37
- rare: '★★★',
38
- epic: '★★★★',
39
- legendary: '★★★★★',
35
+ common: "",
36
+ uncommon: "★★",
37
+ rare: "★★★",
38
+ epic: "★★★★",
39
+ legendary: "★★★★★",
40
40
  };
41
41
  export const DEFAULT_NEEDS = {
42
42
  hunger: 80,
@@ -1,4 +1,4 @@
1
- import type { CompanionConfig, CompanionRuntime, CompanionState, CompanionBones } from './types.js';
1
+ import type { CompanionBones, CompanionConfig, CompanionRuntime, CompanionState } from "./types.js";
2
2
  interface UseCompanionResult {
3
3
  config: CompanionConfig | null;
4
4
  bones: CompanionBones | null;
@@ -1,10 +1,10 @@
1
- import { useState, useEffect, useCallback, useRef } from 'react';
2
- import { loadCompanionConfig, saveCompanionConfig } from './config.js';
3
- import { roll } from './bones.js';
4
- import { cybergotchiEvents } from './events.js';
5
- import { getSpeech } from './speech.js';
6
- import { getSpecies } from './species.js';
7
- import { decayNeeds, applyEvent } from './needs.js';
1
+ import { useCallback, useEffect, useRef, useState } from "react";
2
+ import { roll } from "./bones.js";
3
+ import { loadCompanionConfig, saveCompanionConfig } from "./config.js";
4
+ import { cybergotchiEvents } from "./events.js";
5
+ import { applyEvent, decayNeeds } from "./needs.js";
6
+ import { getSpecies } from "./species.js";
7
+ import { getSpeech } from "./speech.js";
8
8
  const TICK_MS = 500;
9
9
  const SPEECH_TTL_TICKS = 10; // 5 seconds
10
10
  const IDLE_INTERVAL_TICKS = 120; // 60 seconds
@@ -13,10 +13,10 @@ const SAVE_INTERVAL_TICKS = 60; // 30 seconds — persist needs decay periodical
13
13
  function emotionFromNeeds(config) {
14
14
  const { hunger, energy, happiness } = config.needs;
15
15
  if (hunger < 20 || happiness < 20)
16
- return 'alarm';
16
+ return "alarm";
17
17
  if (happiness > 60 && hunger > 50 && energy > 50)
18
- return 'happy';
19
- return 'idle';
18
+ return "happy";
19
+ return "idle";
20
20
  }
21
21
  export function useCybergotchi(paused) {
22
22
  const configRef = useRef(loadCompanionConfig());
@@ -25,7 +25,7 @@ export function useCybergotchi(paused) {
25
25
  // Compute bones from seed (deterministic, recomputed each session)
26
26
  const bonesRef = useRef(config ? roll(config.seed) : null);
27
27
  const [state, setState] = useState({
28
- emotion: 'idle',
28
+ emotion: "idle",
29
29
  frame: 0,
30
30
  speech: null,
31
31
  speechTtl: 0,
@@ -44,8 +44,10 @@ export function useCybergotchi(paused) {
44
44
  const handler = (event) => {
45
45
  eventQueue.current.push(event);
46
46
  };
47
- cybergotchiEvents.on('cybergotchi', handler);
48
- return () => { cybergotchiEvents.off('cybergotchi', handler); };
47
+ cybergotchiEvents.on("cybergotchi", handler);
48
+ return () => {
49
+ cybergotchiEvents.off("cybergotchi", handler);
50
+ };
49
51
  }, []);
50
52
  // Animation + needs tick
51
53
  useEffect(() => {
@@ -70,7 +72,7 @@ export function useCybergotchi(paused) {
70
72
  const bones = bonesRef.current;
71
73
  if (!bones)
72
74
  return;
73
- setState(prev => {
75
+ setState((prev) => {
74
76
  let { frame, speech, speechTtl } = prev;
75
77
  let emotion = emotionFromNeeds(cfg);
76
78
  // Drain speech TTL
@@ -94,7 +96,7 @@ export function useCybergotchi(paused) {
94
96
  idleTicksRef.current += 1;
95
97
  if (idleTicksRef.current >= IDLE_INTERVAL_TICKS) {
96
98
  idleTicksRef.current = 0;
97
- speech = getSpeech('idle', bones.baseStats);
99
+ speech = getSpeech("idle", bones.baseStats);
98
100
  speechTtl = SPEECH_TTL_TICKS;
99
101
  }
100
102
  }
@@ -105,16 +107,18 @@ export function useCybergotchi(paused) {
105
107
  });
106
108
  }, TICK_MS);
107
109
  return () => clearInterval(tick);
108
- }, [config]);
109
- const runtime = config && bonesRef.current ? {
110
- bones: bonesRef.current,
111
- soul: config.soul,
112
- needs: config.needs,
113
- needsUpdatedAt: config.needsUpdatedAt,
114
- currentStreak: config.currentStreak,
115
- lifetime: config.lifetime,
116
- evolutionStage: config.evolutionStage,
117
- } : null;
110
+ }, [config, paused]);
111
+ const runtime = config && bonesRef.current
112
+ ? {
113
+ bones: bonesRef.current,
114
+ soul: config.soul,
115
+ needs: config.needs,
116
+ needsUpdatedAt: config.needsUpdatedAt,
117
+ currentStreak: config.currentStreak,
118
+ lifetime: config.lifetime,
119
+ evolutionStage: config.evolutionStage,
120
+ }
121
+ : null;
118
122
  return { config, bones: bonesRef.current, runtime, state, isSetupNeeded, reload };
119
123
  }
120
124
  //# sourceMappingURL=useCybergotchi.js.map
package/dist/git/index.js CHANGED
@@ -3,8 +3,8 @@
3
3
  * Inspired by Aider's git-native workflow.
4
4
  */
5
5
  import { execSync, spawnSync } from "node:child_process";
6
- import { join } from "node:path";
7
6
  import { existsSync } from "node:fs";
7
+ import { join } from "node:path";
8
8
  /**
9
9
  * Check if we're in a git repository.
10
10
  */
@@ -91,9 +91,9 @@ export function isInMergeOrRebase(cwd) {
91
91
  const root = cwd ?? process.cwd();
92
92
  try {
93
93
  const gitDir = join(root, ".git");
94
- return existsSync(join(gitDir, "MERGE_HEAD"))
95
- || existsSync(join(gitDir, "rebase-merge"))
96
- || existsSync(join(gitDir, "rebase-apply"));
94
+ return (existsSync(join(gitDir, "MERGE_HEAD")) ||
95
+ existsSync(join(gitDir, "rebase-merge")) ||
96
+ existsSync(join(gitDir, "rebase-apply")));
97
97
  }
98
98
  catch {
99
99
  return false;
@@ -126,7 +126,9 @@ export function autoCommitAIEdits(toolName, files, cwd) {
126
126
  return null;
127
127
  // Generate commit message with Co-Authored-By trailer
128
128
  const fileList = files.length > 0
129
- ? (files.length <= 3 ? files.join(", ") : `${files.length} files`)
129
+ ? files.length <= 3
130
+ ? files.join(", ")
131
+ : `${files.length} files`
130
132
  : staged.split("\n").slice(0, 3).join(", ");
131
133
  const message = `oh: ${toolName} ${fileList}\n\nCo-Authored-By: OpenHarness <noreply@openharness.dev>`;
132
134
  // Respect git signing config — don't pass --no-gpg-sign
@@ -175,10 +177,10 @@ export function createWorktree(cwd) {
175
177
  return null;
176
178
  try {
177
179
  const id = Date.now().toString(36) + Math.random().toString(36).slice(2, 6);
178
- const worktreePath = join(cwd ?? process.cwd(), '..', `.oh-worktree-${id}`);
179
- const branch = `oh-agent-${id}`;
180
+ const worktreePath = join(cwd ?? process.cwd(), "..", `.oh-worktree-${id}`);
181
+ const _branch = `oh-agent-${id}`;
180
182
  // Create a detached worktree from HEAD
181
- execSync(`git worktree add --detach "${worktreePath}"`, { cwd, stdio: 'pipe' });
183
+ execSync(`git worktree add --detach "${worktreePath}"`, { cwd, stdio: "pipe" });
182
184
  return worktreePath;
183
185
  }
184
186
  catch {
@@ -215,7 +217,7 @@ export function gitRoot(cwd) {
215
217
  */
216
218
  export function removeWorktree(worktreePath, cwd) {
217
219
  try {
218
- execSync(`git worktree remove --force "${worktreePath}"`, { cwd, stdio: 'pipe' });
220
+ execSync(`git worktree remove --force "${worktreePath}"`, { cwd, stdio: "pipe" });
219
221
  }
220
222
  catch {
221
223
  // Best effort cleanup
@@ -6,11 +6,11 @@
6
6
  *
7
7
  * Storage: .oh/checkpoints/{sessionId}/{turnN}/{relativePath}
8
8
  */
9
- import { readFileSync, writeFileSync, mkdirSync, existsSync, copyFileSync, rmSync } from 'node:fs';
10
- import { join, relative, dirname } from 'node:path';
11
- const CHECKPOINTS_DIR = '.oh/checkpoints';
9
+ import { copyFileSync, existsSync, mkdirSync, readFileSync, rmSync, writeFileSync } from "node:fs";
10
+ import { dirname, join, relative } from "node:path";
11
+ const CHECKPOINTS_DIR = ".oh/checkpoints";
12
12
  const MAX_CHECKPOINTS = 20; // per session
13
- let currentSessionId = '';
13
+ let currentSessionId = "";
14
14
  let checkpointLog = [];
15
15
  /** Initialize checkpoint system for a session */
16
16
  export function initCheckpoints(sessionId) {
@@ -19,10 +19,10 @@ export function initCheckpoints(sessionId) {
19
19
  const dir = join(CHECKPOINTS_DIR, sessionId);
20
20
  if (existsSync(dir)) {
21
21
  // Load existing checkpoint log
22
- const logPath = join(dir, 'log.json');
22
+ const logPath = join(dir, "log.json");
23
23
  if (existsSync(logPath)) {
24
24
  try {
25
- checkpointLog = JSON.parse(readFileSync(logPath, 'utf-8'));
25
+ checkpointLog = JSON.parse(readFileSync(logPath, "utf-8"));
26
26
  }
27
27
  catch {
28
28
  checkpointLog = [];
@@ -51,7 +51,9 @@ export function createCheckpoint(turn, filePaths, description) {
51
51
  copyFileSync(filePath, destPath);
52
52
  savedFiles.push(relPath);
53
53
  }
54
- catch { /* skip unreadable files */ }
54
+ catch {
55
+ /* skip unreadable files */
56
+ }
55
57
  }
56
58
  if (savedFiles.length === 0)
57
59
  return null;
@@ -69,10 +71,12 @@ export function createCheckpoint(turn, filePaths, description) {
69
71
  try {
70
72
  rmSync(oldDir, { recursive: true });
71
73
  }
72
- catch { /* ignore */ }
74
+ catch {
75
+ /* ignore */
76
+ }
73
77
  }
74
78
  // Persist log
75
- const logPath = join(CHECKPOINTS_DIR, currentSessionId, 'log.json');
79
+ const logPath = join(CHECKPOINTS_DIR, currentSessionId, "log.json");
76
80
  mkdirSync(dirname(logPath), { recursive: true });
77
81
  writeFileSync(logPath, JSON.stringify(checkpointLog, null, 2));
78
82
  return checkpoint;
@@ -95,16 +99,20 @@ export function rewindLastCheckpoint() {
95
99
  mkdirSync(dirname(destPath), { recursive: true });
96
100
  copyFileSync(srcPath, destPath);
97
101
  }
98
- catch { /* skip */ }
102
+ catch {
103
+ /* skip */
104
+ }
99
105
  }
100
106
  }
101
107
  // Clean up the restored checkpoint dir
102
108
  try {
103
109
  rmSync(dir, { recursive: true });
104
110
  }
105
- catch { /* ignore */ }
111
+ catch {
112
+ /* ignore */
113
+ }
106
114
  // Persist updated log
107
- const logPath = join(CHECKPOINTS_DIR, currentSessionId, 'log.json');
115
+ const logPath = join(CHECKPOINTS_DIR, currentSessionId, "log.json");
108
116
  writeFileSync(logPath, JSON.stringify(checkpointLog, null, 2));
109
117
  return checkpoint;
110
118
  }
@@ -122,22 +130,22 @@ export function checkpointCount() {
122
130
  */
123
131
  export function getAffectedFiles(toolName, toolInput) {
124
132
  switch (toolName) {
125
- case 'FileWrite':
126
- case 'Write':
133
+ case "FileWrite":
134
+ case "Write":
127
135
  return toolInput.file_path ? [String(toolInput.file_path)] : [];
128
- case 'FileEdit':
129
- case 'Edit':
136
+ case "FileEdit":
137
+ case "Edit":
130
138
  return toolInput.file_path ? [String(toolInput.file_path)] : [];
131
- case 'NotebookEdit':
139
+ case "NotebookEdit":
132
140
  return toolInput.notebook_path ? [String(toolInput.notebook_path)] : [];
133
- case 'Bash': {
141
+ case "Bash": {
134
142
  // Extract file paths from bash commands that modify files
135
- const cmd = String(toolInput.command ?? '');
143
+ const cmd = String(toolInput.command ?? "");
136
144
  const files = [];
137
145
  // Detect redirect targets: > file, >> file
138
146
  const redirects = cmd.matchAll(/>{1,2}\s*(\S+)/g);
139
147
  for (const m of redirects)
140
- if (m[1] && !m[1].startsWith('/dev/'))
148
+ if (m[1] && !m[1].startsWith("/dev/"))
141
149
  files.push(m[1]);
142
150
  // Detect sed -i targets
143
151
  const sedMatch = cmd.match(/sed\s+-i\S*\s+.*\s+(\S+)$/);
@@ -147,7 +155,7 @@ export function getAffectedFiles(toolName, toolInput) {
147
155
  const mvMatch = cmd.match(/(?:mv|cp)\s+\S+\s+(\S+)$/);
148
156
  if (mvMatch?.[1])
149
157
  files.push(mvMatch[1]);
150
- return files.filter(f => existsSync(f));
158
+ return files.filter((f) => existsSync(f));
151
159
  }
152
160
  default:
153
161
  return [];
@@ -45,7 +45,7 @@ export type OhConfig = {
45
45
  provider: string;
46
46
  model: string;
47
47
  permissionMode: PermissionMode;
48
- theme?: 'dark' | 'light';
48
+ theme?: "dark" | "light";
49
49
  apiKey?: string;
50
50
  baseUrl?: string;
51
51
  mcpServers?: McpServerConfig[];
@@ -55,7 +55,7 @@ export type OhConfig = {
55
55
  /** Verification loops — auto-run lint/typecheck after file edits */
56
56
  verification?: {
57
57
  enabled?: boolean;
58
- mode?: 'warn' | 'block';
58
+ mode?: "warn" | "block";
59
59
  rules?: VerificationRuleConfig[];
60
60
  };
61
61
  /** Memory consolidation settings */
@@ -69,7 +69,7 @@ export type OhConfig = {
69
69
  powerful?: string;
70
70
  };
71
71
  /** Effort level for LLM reasoning depth */
72
- effortLevel?: 'low' | 'medium' | 'high' | 'max';
72
+ effortLevel?: "low" | "medium" | "high" | "max";
73
73
  /** Opt-in telemetry (default: off) */
74
74
  telemetry?: {
75
75
  enabled?: boolean;
@@ -1,9 +1,9 @@
1
1
  /**
2
2
  * .oh/config.yaml — provider, model, permissionMode and other persisted settings.
3
3
  */
4
- import { readFileSync, writeFileSync, mkdirSync, existsSync } from "node:fs";
5
- import { join } from "node:path";
4
+ import { existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
6
5
  import { homedir } from "node:os";
6
+ import { join } from "node:path";
7
7
  import { parse, stringify } from "yaml";
8
8
  function yamlScalar(value) {
9
9
  return `'${value.replace(/'/g, "''")}'`;
@@ -20,7 +20,7 @@ export function invalidateConfigCache() {
20
20
  }
21
21
  /** Path to global config: ~/.oh/config.yaml */
22
22
  function globalConfigPath() {
23
- return join(homedir(), '.oh', 'config.yaml');
23
+ return join(homedir(), ".oh", "config.yaml");
24
24
  }
25
25
  /** Read global config as fallback defaults */
26
26
  function readGlobalConfig() {
@@ -28,7 +28,7 @@ function readGlobalConfig() {
28
28
  if (!existsSync(p))
29
29
  return null;
30
30
  try {
31
- return parse(readFileSync(p, 'utf-8'));
31
+ return parse(readFileSync(p, "utf-8"));
32
32
  }
33
33
  catch {
34
34
  return null;
@@ -47,7 +47,9 @@ export function readOhConfig(root) {
47
47
  try {
48
48
  projectCfg = parse(readFileSync(p, "utf-8"));
49
49
  }
50
- catch { /* ignore malformed project config */ }
50
+ catch {
51
+ /* ignore malformed project config */
52
+ }
51
53
  }
52
54
  // If neither exists, no config
53
55
  if (!globalCfg && !projectCfg) {
@@ -69,7 +71,9 @@ export function readOhConfig(root) {
69
71
  return merged;
70
72
  }
71
73
  }
72
- catch { /* ignore malformed local config */ }
74
+ catch {
75
+ /* ignore malformed local config */
76
+ }
73
77
  }
74
78
  _configCache = base;
75
79
  _configCacheRoot = effectiveRoot;
@@ -79,9 +83,11 @@ export function writeOhConfig(cfg, root) {
79
83
  invalidateConfigCache();
80
84
  // Emit configChange hook (lazy import to avoid circular dependency)
81
85
  try {
82
- require('./hooks.js').emitHook('configChange', {});
86
+ require("./hooks.js").emitHook("configChange", {});
87
+ }
88
+ catch {
89
+ /* ignore */
83
90
  }
84
- catch { /* ignore */ }
85
91
  const p = configPath(root);
86
92
  mkdirSync(join(root ?? ".", ".oh"), { recursive: true });
87
93
  if (cfg.provider === "llamacpp" || cfg.provider === "lmstudio") {
@@ -110,7 +116,7 @@ export function writeOhConfig(cfg, root) {
110
116
  // fall back to stringify for mcpServers since it's complex
111
117
  lines.push("", stringify({ mcpServers: cfg.mcpServers }).trim());
112
118
  }
113
- writeFileSync(p, lines.join("\n") + "\n");
119
+ writeFileSync(p, `${lines.join("\n")}\n`);
114
120
  return;
115
121
  }
116
122
  writeFileSync(p, stringify(cfg));
@@ -1,7 +1,7 @@
1
1
  /**
2
2
  * Context window warning — shared between cell renderer and Ink REPL.
3
3
  */
4
- import type { Message } from '../types/message.js';
4
+ import type { Message } from "../types/message.js";
5
5
  /** Estimate total tokens from messages (incremental-friendly) */
6
6
  export declare function estimateMessageTokens(messages: Message[], startFrom?: number): number;
7
7
  /** Compute context warning if usage exceeds 75% */
@@ -1,7 +1,7 @@
1
1
  /**
2
2
  * Context window warning — shared between cell renderer and Ink REPL.
3
3
  */
4
- import { getContextWindow } from './cost.js';
4
+ import { getContextWindow } from "./cost.js";
5
5
  /** Estimate total tokens from messages (incremental-friendly) */
6
6
  export function estimateMessageTokens(messages, startFrom = 0) {
7
7
  let total = 0;
@@ -51,7 +51,7 @@ export const MODEL_PRICING = {
51
51
  "gpt-4o": [2.5, 10.0],
52
52
  "gpt-4o-mini": [0.15, 0.6],
53
53
  "o3-mini": [1.1, 4.4],
54
- "o3": [10.0, 40.0],
54
+ o3: [10.0, 40.0],
55
55
  "claude-sonnet-4-6": [3.0, 15.0],
56
56
  "claude-haiku-4-5": [0.8, 4.0],
57
57
  "claude-opus-4-6": [15.0, 75.0],