clauderipple 0.9.5 → 0.11.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 (163) hide show
  1. package/CHANGELOG.md +118 -0
  2. package/README.es.md +45 -0
  3. package/README.ja.md +17 -0
  4. package/README.ko.md +31 -0
  5. package/README.md +70 -0
  6. package/README.pt-BR.md +45 -0
  7. package/README.zh-CN.md +17 -0
  8. package/dist/app/assets/icon.icns +0 -0
  9. package/dist/app/assets/icon.ico +0 -0
  10. package/dist/app/assets/icon.png +0 -0
  11. package/dist/app/assets/trayDirectTemplate.png +0 -0
  12. package/dist/app/assets/trayDirectTemplate@2x.png +0 -0
  13. package/dist/app/assets/trayDownTemplate.png +0 -0
  14. package/dist/app/assets/trayDownTemplate@2x.png +0 -0
  15. package/dist/app/assets/trayTemplate.png +0 -0
  16. package/dist/app/assets/trayTemplate@2x.png +0 -0
  17. package/dist/app/assets/trayWarnTemplate.png +0 -0
  18. package/dist/app/assets/trayWarnTemplate@2x.png +0 -0
  19. package/dist/app/assets/trayWin.png +0 -0
  20. package/dist/app/assets/trayWin@2x.png +0 -0
  21. package/dist/app/assets/trayWinDirect.png +0 -0
  22. package/dist/app/assets/trayWinDirect@2x.png +0 -0
  23. package/dist/app/assets/trayWinDown.png +0 -0
  24. package/dist/app/assets/trayWinDown@2x.png +0 -0
  25. package/dist/app/assets/trayWinWarn.png +0 -0
  26. package/dist/app/assets/trayWinWarn@2x.png +0 -0
  27. package/dist/app/dist/claude-desktop.js +67 -0
  28. package/dist/app/dist/main.js +423 -110
  29. package/dist/app/dist/preload.js +21 -0
  30. package/dist/app/dist/protocol.js +121 -0
  31. package/dist/app/dist/status-model.js +87 -0
  32. package/dist/app/dist/window.js +133 -0
  33. package/dist/app/package.json +1 -1
  34. package/dist/cli/src/awake-setup.js +314 -0
  35. package/dist/cli/src/bundle.js +9 -5
  36. package/dist/cli/src/direct.js +159 -0
  37. package/dist/cli/src/doctor.js +205 -0
  38. package/dist/cli/src/hooks/agent-title.js +7 -4
  39. package/dist/cli/src/index.js +227 -31
  40. package/dist/cli/src/launchd.js +29 -20
  41. package/dist/cli/src/launcher.js +215 -0
  42. package/dist/cli/src/power.js +182 -0
  43. package/dist/cli/src/registration.js +157 -0
  44. package/dist/cli/src/remote.js +263 -0
  45. package/dist/cli/src/schtasks.js +50 -40
  46. package/dist/cli/src/settings.js +26 -1
  47. package/dist/cli/src/tray.js +5 -2
  48. package/dist/mod/hooks/i18n.ts +473 -227
  49. package/dist/mod/hooks/judge.ts +35 -17
  50. package/dist/mod/hooks/modes.ts +56 -1
  51. package/dist/mod/hooks/register.tsx +237 -32
  52. package/dist/mod/hooks/session.ts +102 -1
  53. package/dist/mod/hooks/settings.js +7 -3
  54. package/dist/mod/hooks/settings.ts +9 -4
  55. package/dist/mod/hooks/stats.ts +25 -1
  56. package/dist/mod/hooks/ui/agents.tsx +903 -79
  57. package/dist/mod/hooks/ui/alerts.tsx +20 -17
  58. package/dist/mod/hooks/ui/art.ts +33 -7
  59. package/dist/mod/hooks/ui/band.tsx +262 -81
  60. package/dist/mod/hooks/ui/flat.ts +265 -0
  61. package/dist/mod/hooks/ui/kit.tsx +70 -55
  62. package/dist/mod/hooks/ui/look.ts +129 -0
  63. package/dist/mod/hooks/ui/settings.tsx +71 -46
  64. package/dist/mod/hooks/ui/setup.tsx +15 -13
  65. package/dist/mod/hooks/ui/theme.ts +3 -0
  66. package/dist/mod/hooks/ui/tools.ts +124 -0
  67. package/dist/mod/hooks/ui/view.ts +120 -4
  68. package/dist/mod/hooks/workers.ts +33 -6
  69. package/dist/mod/tests/register.test.tsx +155 -11
  70. package/dist/mod/tests/ui.test.tsx +408 -27
  71. package/dist/mod/types/index.d.ts +66 -2
  72. package/dist/remote/package.json +28 -0
  73. package/dist/remote/src/away.js +85 -0
  74. package/dist/remote/src/bridge-client.js +336 -0
  75. package/dist/remote/src/composer-menu.js +11 -0
  76. package/dist/remote/src/config.js +102 -0
  77. package/dist/remote/src/desktop.js +1018 -0
  78. package/dist/remote/src/e2ee.js +126 -0
  79. package/dist/remote/src/e2ee.ts +126 -0
  80. package/dist/remote/src/eventlog.js +298 -0
  81. package/dist/remote/src/expo-push.js +127 -0
  82. package/dist/remote/src/folders.js +79 -0
  83. package/dist/remote/src/fsutil.js +39 -0
  84. package/dist/remote/src/handoff.js +38 -0
  85. package/dist/remote/src/host-service.js +168 -0
  86. package/dist/remote/src/images.js +215 -0
  87. package/dist/remote/src/local-control.js +138 -0
  88. package/dist/remote/src/main.js +264 -0
  89. package/dist/remote/src/permissions.js +124 -0
  90. package/dist/remote/src/power.js +76 -0
  91. package/dist/remote/src/processes.js +24 -0
  92. package/dist/remote/src/protocol.js +32 -0
  93. package/dist/remote/src/protocol.ts +284 -0
  94. package/dist/remote/src/push-content.js +32 -0
  95. package/dist/remote/src/push.js +134 -0
  96. package/dist/remote/src/receipts.js +111 -0
  97. package/dist/remote/src/relay.js +438 -0
  98. package/dist/remote/src/router.js +208 -0
  99. package/dist/remote/src/sdk-launcher.js +18 -0
  100. package/dist/remote/src/server.js +706 -0
  101. package/dist/remote/src/service.js +157 -0
  102. package/dist/remote/src/sessions.js +1800 -0
  103. package/dist/remote/src/sidebar-storage.js +211 -0
  104. package/dist/remote/src/sidebar.js +173 -0
  105. package/dist/remote/src/tool-details.js +205 -0
  106. package/dist/remote/src/tool-details.ts +153 -0
  107. package/dist/remote/src/worktree.js +99 -0
  108. package/dist/remote/web/app.ts +746 -0
  109. package/dist/remote/web/conn.ts +193 -0
  110. package/dist/remote/web/demo.ts +134 -0
  111. package/dist/remote/web/dom.ts +124 -0
  112. package/dist/remote/web/esc.ts +4 -0
  113. package/dist/remote/web/i18n.ts +374 -0
  114. package/dist/remote/web/icon.svg +1 -0
  115. package/dist/remote/web/index.html +24 -0
  116. package/dist/remote/web/manifest.webmanifest +10 -0
  117. package/dist/remote/web/mascot.ts +60 -0
  118. package/dist/remote/web/md.ts +78 -0
  119. package/dist/remote/web/notify.ts +55 -0
  120. package/dist/remote/web/pushstate.ts +27 -0
  121. package/dist/remote/web/secure.ts +109 -0
  122. package/dist/remote/web/sidebar.ts +106 -0
  123. package/dist/remote/web/style.css +311 -0
  124. package/dist/remote/web/sw.ts +48 -0
  125. package/dist/remote/web/timeline.ts +224 -0
  126. package/dist/remote/web/views.ts +323 -0
  127. package/dist/router/src/admin.js +331 -5
  128. package/dist/router/src/awake-win.js +590 -0
  129. package/dist/router/src/awake.js +432 -0
  130. package/dist/router/src/config.js +94 -0
  131. package/dist/router/src/health.js +86 -3
  132. package/dist/router/src/hold.js +107 -0
  133. package/dist/router/src/index.js +108 -6
  134. package/dist/router/src/ingress/server.js +26 -4
  135. package/dist/router/src/ingress/translate.js +6 -2
  136. package/dist/router/src/phone.js +82 -0
  137. package/dist/router/src/power.js +107 -0
  138. package/dist/router/src/providers/anthropic-usage.js +33 -1
  139. package/dist/router/src/providers/google/antigravity.js +73 -10
  140. package/dist/router/src/providers/google/index.js +191 -14
  141. package/dist/router/src/providers/google/prompt-refusal.js +29 -0
  142. package/dist/router/src/providers/google/thoughtSignatures.js +13 -0
  143. package/dist/router/src/providers/google/transport.js +1 -1
  144. package/dist/router/src/providers/google/usage.js +302 -0
  145. package/dist/router/src/providers/grok/index.js +18 -0
  146. package/dist/router/src/providers/grok/usage.js +77 -0
  147. package/dist/router/src/providers/openai/translate.js +13 -2
  148. package/dist/router/src/providers/opencode-usage.js +116 -0
  149. package/dist/router/src/providers/retry.js +4 -1
  150. package/dist/router/src/proxy.js +371 -261
  151. package/dist/router/src/remote-host.js +320 -0
  152. package/dist/router/src/remote-tunnel.js +320 -0
  153. package/dist/router/src/requestlog.js +48 -39
  154. package/dist/router/src/tether-win.js +211 -0
  155. package/dist/router/src/tether.js +712 -0
  156. package/dist/router/src/usage-history.js +227 -0
  157. package/dist/router/src/version.js +1 -1
  158. package/dist/ui/app.js +1083 -59
  159. package/dist/ui/i18n.js +670 -69
  160. package/dist/ui/index.html +33 -6
  161. package/dist/ui/style.css +177 -0
  162. package/docs/ARCHITECTURE.md +402 -14
  163. package/package.json +8 -2
@@ -5,9 +5,15 @@ import type { Lang } from './i18n.ts'
5
5
 
6
6
  const EFFORTS: readonly Effort[] = ['low', 'medium', 'high', 'xhigh', 'max']
7
7
 
8
- export const EFFORT_JUDGE_SYSTEM = `Choose the cheapest reasoning effort that can do this work well. This is a coding agent able to inspect files, run commands, and edit code, not merely answer a chat question.
9
- Assess work volume, uncertainty, and the cost of mistakes, not message length. A short choice approving a build inherits the size of that build. Corrections and steering retain at least the running effort; closing remarks need little effort. "Think hard" or thorough reasoning requires at least high; an explicit quick answer calls for low.
10
- Low and medium are only for turns that need no judgment: low for chit-chat, thanks, or a direct answer needing no inspection; medium for one fully specified, low-risk step the user spelled out (run this command, rename this). Anything that asks the agent to decide, explain why, review, verify, debug, plan, delegate, or change more than one thing needs at least high; most coding-agent turns are high. xhigh is for unusually difficult investigation, and max only for the hardest open-ended problems. Consider the current model's strength.
8
+ // "xhigh for unusually difficult investigation, max only for the hardest open-ended problems" left
9
+ // a medium..max range at medium and high: 10-13..10-17 ran ~9,000 Opus requests with no max and 91
10
+ // xhigh, and Jev gave an architecture redesign 2% max (2026-10-19). Above high is now named by
11
+ // what hinges on judgment, so important plans and failed attempts can reach it.
12
+ export const EFFORT_JUDGE_SYSTEM = `Choose the reasoning effort this work deserves. This is a coding agent able to inspect files, run commands, and edit code, not merely answer a chat question.
13
+ Assess work volume, uncertainty, and the cost of mistakes, not message length. A short choice approving a build inherits the size of that build. Closing remarks need little effort. "Think hard" or thorough reasoning requires at least high; an explicit quick answer calls for low.
14
+ Low and medium are only for turns that need no judgment: low for chit-chat, thanks, or a direct answer needing no inspection; medium for one fully specified, low-risk step the user spelled out (run this command, rename this). Ordinary coding that asks the agent to decide, explain why, review, verify, debug with a known direction, delegate, or change more than one thing is high.
15
+ Go above high when the outcome hinges on judgment rather than labor. xhigh: debugging whose cause is unknown, changes across interacting modules, or planning a feature. max: decisions that shape the product or system (architecture, an important plan or strategy, a design meant to last), work where a wrong call risks security, money, or data loss, and problems that earlier attempts in this conversation failed to solve. Not every plan is max; a small or routine plan is high or xhigh.
16
+ When the user says the previous attempt failed, is wrong, or still does not work, choose at least one level above the running effort. Other corrections and steering keep at least the running effort. Consider the current model's strength.
11
17
  Return only JSON {"effort":"low|medium|high|xhigh|max","sure":0.0,"why":"short reason"}. Confidence is between zero and one. The reason uses the user's language and at most six words.`
12
18
 
13
19
  /** A terse continuation usually carries no new scope; answers to questions are handled separately. */
@@ -16,6 +22,11 @@ export function isShortFollowUp(text: string): boolean {
16
22
  return trimmed.length > 0 && trimmed.length <= 12 && trimmed.split(/\s+/).length <= 2
17
23
  }
18
24
 
25
+ /** "Still broken" is short but asks for more thought, so it is judged rather than inheriting the effort that failed. */
26
+ export function looksLikeRetry(text: string): boolean {
27
+ return /안\s*[돼되]|다시|틀렸|아직|여전|그대로|실패|\bstill\b|\bagain\b|\bwrong\b|\bbroken\b|n['’]?t work|\bfail/i.test(text)
28
+ }
29
+
19
30
  export function looksLikeQuestion(assistantTail: string): boolean {
20
31
  return assistantTail.slice(-400).includes('?')
21
32
  }
@@ -28,7 +39,7 @@ export function shouldJudge(input: {
28
39
  if (!input.auto || !['composer', 'bridge', 'sdk'].includes(input.origin) || (!input.text.trim() && !input.attachments?.length) || input.hostCommand) return false
29
40
  if (input.modelId !== undefined && !isCacheSafeModel(input.modelId)) return false
30
41
  const followup = input.current && input.current.by !== 'manual' && !input.text.trim().startsWith('/') &&
31
- !input.attachments?.length && isShortFollowUp(input.text) && !looksLikeQuestion(input.assistantTail ?? '')
42
+ !input.attachments?.length && isShortFollowUp(input.text) && !looksLikeRetry(input.text) && !looksLikeQuestion(input.assistantTail ?? '')
32
43
  return !followup
33
44
  }
34
45
 
@@ -110,16 +121,19 @@ function looseVerdictObject(text: string): Record<string, unknown> | undefined {
110
121
  }
111
122
 
112
123
  const effortCriteria = {
113
- low: 'Small direct work with little uncertainty or planning.',
114
- medium: 'Ordinary bounded coding with a few inspections or edits.',
115
- high: 'Substantial multi-step coding or debugging where mistakes matter.',
116
- xhigh: 'Difficult extended investigation with interacting constraints.',
117
- max: 'Exceptional open-ended research or the hardest reasoning problems.',
118
- }
124
+ low: 'Chit-chat, thanks, or a direct answer needing no inspection.',
125
+ medium: 'One fully specified, low-risk step the user spelled out.',
126
+ high: 'Ordinary coding: implement, fix, review, or debug with a known direction.',
127
+ xhigh: 'Debugging with an unknown cause, changes across interacting modules, or planning a feature.',
128
+ max: 'Product or architecture decisions, important plans or strategy, security or data-loss risk, or a problem earlier attempts failed to solve.',
129
+ }
130
+ // Read with the brief, the old wording sent 49 of 64 delegated tasks to deep, against 19 from their
131
+ // one-line descriptions alone: a brief's warnings ("do not restart", "read-only", "no guessing")
132
+ // read as high stakes. Re-judged with this wording the same briefs give 28 (2026-10-15, pick log).
119
133
  const levelCriteria = {
120
- light: 'Mechanical chores, repeated changes, or simple lookups.',
121
- standard: 'Implement a designed change, research, summarize documentation, or review.',
122
- deep: 'Careful high-stakes reasoning, subtle debugging, architecture, or security.',
134
+ light: 'Mechanical chores, repeated edits, simple lookups, or one small fix.',
135
+ standard: 'Carry out a designed change, even across several files; research, summarize, or review read-only.',
136
+ deep: 'Subtle debugging, security review, or architecture where a wrong call is costly. Size, file count, or warnings and prohibitions in the brief do not by themselves make work deep.',
123
137
  }
124
138
  const domainCriteria: Record<Domain, string> = {
125
139
  design: 'Visual composition, branding, taste, look and voice of copy.',
@@ -188,10 +202,14 @@ export function parseJevWorker(json: unknown): WorkerVerdict | undefined {
188
202
  const effortAnswer = record(reply?.effort)
189
203
  const selectedEffort = effort(effortAnswer?.choice)
190
204
  if (!domainAnswer || !DOMAINS.includes(domainAnswer.choice as Domain) || !levelAnswer || !LEVELS.includes(levelAnswer.choice as Level) || !effortAnswer || !selectedEffort) return undefined
191
- // Confidence moves a task up the ladder, so it is the level's question that counts, not the kind's.
192
- const scores = [answerSure(domainAnswer), answerSure(levelAnswer), answerSure(effortAnswer)].filter((score): score is number => score !== undefined)
193
- const kind = kindOf(record(reply?.kind)?.choice) ?? 'do'
194
- return { domain: domainAnswer.choice as Domain, level: levelAnswer.choice as Level, kind, effort: selectedEffort, ...(scores.length ? { sure: Math.min(...scores) } : {}), why: '' }
205
+ // Confidence moves a task up the ladder, so it is the level's question that counts. The lowest of
206
+ // all three counted before: torn only between frontend and backend, or high and xhigh, a task
207
+ // judged standard was sent a rung up (4 of 16 standard verdicts, pick log 2026-10-12..15).
208
+ const kindAnswer = record(reply?.kind)
209
+ const kind = kindOf(kindAnswer?.choice) ?? 'do'
210
+ const odds = { domain: answerSure(domainAnswer), level: answerSure(levelAnswer), kind: kindAnswer ? answerSure(kindAnswer) : undefined, effort: answerSure(effortAnswer) }
211
+ const known = Object.fromEntries(Object.entries(odds).filter(([, score]) => score !== undefined)) as WorkerVerdict['odds']
212
+ return { domain: domainAnswer.choice as Domain, level: levelAnswer.choice as Level, kind, effort: selectedEffort, ...(odds.level !== undefined ? { sure: odds.level } : {}), ...(Object.keys(known!).length ? { odds: known } : {}), why: '' }
195
213
  }
196
214
 
197
215
  export function jevUsage(json: unknown): number {
@@ -1,7 +1,7 @@
1
1
  // Operating modes in the session (docs/specs/2026-10-12-worker-tiers.md "Operating modes"): which
2
2
  // mode is on, when it ends by itself, and the eager-delegation note. Pure; register.tsx wires them.
3
3
 
4
- import type { Hot, Mode, Settings } from '../types'
4
+ import type { Hot, LimitItem, Mode, Settings } from '../types'
5
5
 
6
6
  /** The mode that is on, if the settings name one that exists. */
7
7
  export function activeModeOf(s: Pick<Settings, 'modes' | 'activeMode'>): Mode | undefined {
@@ -91,3 +91,58 @@ export function modeOver(mode: Pick<Mode, 'until'>, since: number | undefined, n
91
91
  const passed = (at: number) => at > since && at <= now
92
92
  return windows.some(w => passed(w.at) || (w.windowMs !== undefined && passed(w.at - w.windowMs)))
93
93
  }
94
+
95
+ /** The configured providers of ChatGPT type, from GET /api/status `providers` (name → {type}). */
96
+ export function chatgptProviders(status: unknown): string[] {
97
+ const providers = record(status).providers
98
+ if (!providers || typeof providers !== 'object' || Array.isArray(providers)) return []
99
+ return Object.entries(providers as Record<string, unknown>)
100
+ .filter(([, value]) => record(value).type === 'chatgpt')
101
+ .map(([name]) => name)
102
+ }
103
+
104
+ /**
105
+ * Every signed-in ChatGPT account's known windows as the limits row reads them, from GET
106
+ * /api/chatgpt-accounts (`quota.rate_limits.{primary,secondary}` with `reset_at` in epoch
107
+ * seconds or ms, or `reset_after_seconds` from the snapshot's `at`, and `window_minutes`;
108
+ * the same shape `quotaWindows` reads). Paused and needs-login accounts are left out (and take
109
+ * no number), and so is an account with no snapshot. `account` numbers the accounts kept, in
110
+ * answer order. A snapshot is not aged out: the router takes it from the account's own replies,
111
+ * so an account idle for an hour holds an hour-old figure that is still right (measured
112
+ * 2026-10-15: 30 minutes old between uses). Only a window whose reset has passed is dropped,
113
+ * since its figure no longer stands.
114
+ */
115
+ export function gptLimitsFrom(body: unknown, provider: string, now: number): LimitItem[] {
116
+ const accounts = record(body).accounts
117
+ if (!Array.isArray(accounts)) return []
118
+ const kept = accounts.map(record).filter(account => account.state !== 'paused' && account.state !== 'needs-login' && account.paused !== true)
119
+ const out: LimitItem[] = []
120
+ kept.forEach((account, index) => {
121
+ const quota = record(account.quota)
122
+ const at = quota.at
123
+ if (typeof at !== 'number') return
124
+ const limits = record(quota.rate_limits)
125
+ for (const key of ['primary', 'secondary']) {
126
+ const window = record(limits[key])
127
+ const used = window.used_percent
128
+ if (typeof used !== 'number' || !Number.isFinite(used)) continue
129
+ const minutes = window.window_minutes
130
+ const resetAt = typeof window.reset_at === 'number' ? (window.reset_at > 1e12 ? window.reset_at : window.reset_at * 1000)
131
+ : typeof window.reset_after_seconds === 'number' && typeof at === 'number' ? at + window.reset_after_seconds * 1000 : NaN
132
+ if (Number.isFinite(resetAt) && resetAt <= now) continue
133
+ const kind = minutes === 300 ? 'five_hour' : minutes === 10080 ? 'seven_day' : 'window'
134
+ out.push({
135
+ provider,
136
+ type: 'chatgpt',
137
+ title: 'GPT',
138
+ account: index,
139
+ kind,
140
+ label: '',
141
+ ...(typeof minutes === 'number' && minutes > 0 ? { windowMinutes: minutes } : {}),
142
+ percent: Math.round(used * 10) / 10,
143
+ ...(Number.isFinite(resetAt) ? { resetsAt: new Date(resetAt).toISOString() } : {}),
144
+ })
145
+ }
146
+ })
147
+ return out
148
+ }