@cortexkit/opencode-anthropic-auth 1.23.0 → 2.0.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 (82) hide show
  1. package/README.md +239 -195
  2. package/dist/cli-failure.d.ts +69 -0
  3. package/dist/cli.d.ts +14 -9
  4. package/dist/cli.js +98 -76
  5. package/dist/custody-dimensions.d.ts +7 -24
  6. package/dist/custody-mode.d.ts +29 -169
  7. package/dist/effort-history.d.ts +6 -1
  8. package/dist/index-1jkyhgyr.js +2 -0
  9. package/dist/{index-8y2t4mwz.js → index-2arfb1y3.js} +1 -1
  10. package/dist/{index-0jfsxyn9.js → index-4ya27n12.js} +1 -1
  11. package/dist/index-aaajxwzd.js +2 -0
  12. package/dist/index-ae3fq4n6.js +42 -0
  13. package/dist/{index-xzbhzz0a.js → index-fds0s2j4.js} +2 -2
  14. package/dist/index-nngmvczq.js +450 -0
  15. package/dist/index-pn597b6f.js +2 -0
  16. package/dist/{index-1gr8v4fn.js → index-rqync0pc.js} +1 -1
  17. package/dist/index.js +1 -38
  18. package/dist/native-command.d.ts +19 -0
  19. package/dist/rpc/notifications.d.ts +2 -1
  20. package/dist/rpc/port-file.js +1 -1
  21. package/dist/rpc/protocol.d.ts +8 -4
  22. package/dist/rpc/protocol.js +1 -1
  23. package/dist/rpc/rpc-client.d.ts +2 -0
  24. package/dist/rpc/rpc-client.js +1 -1
  25. package/dist/rpc/rpc-dir.js +1 -1
  26. package/dist/rpc/rpc-server.d.ts +5 -1
  27. package/dist/setup/command.d.ts +12 -0
  28. package/dist/setup/command.test.d.ts +1 -0
  29. package/dist/setup/native-activation.d.ts +29 -0
  30. package/dist/setup/native-enrollment.d.ts +26 -0
  31. package/dist/setup/native-enrollment.test.d.ts +1 -0
  32. package/dist/setup/native-local.d.ts +20 -0
  33. package/dist/setup/native-login.d.ts +3 -0
  34. package/dist/setup/native-paths.d.ts +15 -0
  35. package/dist/setup/native-paths.test.d.ts +1 -0
  36. package/dist/setup/pi.d.ts +13 -3
  37. package/dist/setup/process-fence.d.ts +7 -1
  38. package/dist/setup/process-fence.test.d.ts +1 -0
  39. package/dist/sidebar-state.js +1 -1
  40. package/dist/tui/command-dialogs.d.ts +5 -0
  41. package/dist/tui-preferences.js +2 -2
  42. package/dist/v2/activation.d.ts +7 -0
  43. package/dist/v2/adapter.d.ts +276 -0
  44. package/dist/v2/install.d.ts +13 -0
  45. package/dist/v2/lifecycle.d.ts +8 -0
  46. package/dist/v2/menu-contract.d.ts +8 -0
  47. package/dist/v2/menu.d.ts +10 -0
  48. package/dist/v2/models.d.ts +6 -0
  49. package/dist/v2/ownership.d.ts +11 -0
  50. package/dist/v2/prime.d.ts +12 -0
  51. package/dist/v2/rpc.d.ts +50 -0
  52. package/dist/v2/server.d.ts +8 -0
  53. package/dist/v2/server.js +4 -0
  54. package/dist/v2/setup.d.ts +58 -0
  55. package/dist/v2/source.d.ts +41 -0
  56. package/dist/v2/tui.d.ts +13 -0
  57. package/dist/v2/tui.js +2 -0
  58. package/dist/v2/wire.d.ts +36 -0
  59. package/package.json +20 -5
  60. package/src/rpc/notifications.ts +9 -2
  61. package/src/rpc/protocol.ts +8 -7
  62. package/src/rpc/rpc-client.ts +17 -0
  63. package/src/rpc/rpc-server.ts +20 -3
  64. package/src/tui/command-dialogs.tsx +264 -0
  65. package/src/tui/entry.mjs +44 -18
  66. package/src/tui-compiled/rpc/protocol.ts +8 -7
  67. package/src/tui-compiled/rpc/rpc-client.ts +17 -0
  68. package/src/tui-compiled/tui/command-dialogs.tsx +315 -76
  69. package/src/tui-compiled/tui.tsx +24 -7
  70. package/src/tui.tsx +37 -9
  71. package/dist/claustrum-enrollment-registry.d.ts +0 -4
  72. package/dist/custody-enrollment.d.ts +0 -14
  73. package/dist/custody-live.d.ts +0 -111
  74. package/dist/custody-manifest-watcher.d.ts +0 -16
  75. package/dist/index-1fq7h6yd.js +0 -430
  76. package/dist/index-797pmamn.js +0 -2
  77. package/dist/index-a5d6v3ba.js +0 -5
  78. package/dist/index-n96q8pks.js +0 -2
  79. package/dist/index-xxhyhp98.js +0 -2
  80. package/dist/index-z7gfdyv3.js +0 -1
  81. package/dist/local-login.d.ts +0 -64
  82. package/dist/logger-kk9vyem9.js +0 -1
@@ -1,4 +1,15 @@
1
1
  /** @jsxImportSource @opentui/solid */
2
+
3
+ import type {
4
+ CommandApplyRequest,
5
+ CommandApplyResult,
6
+ CommandDialogPayload,
7
+ CommandMenuModel,
8
+ KnobValue,
9
+ MenuAction,
10
+ MenuItem,
11
+ MenuSection,
12
+ } from '@cortexkit/anthropic-auth-core'
2
13
  import {
3
14
  custodyStatusLabel,
4
15
  type PrimeAccountStatus,
@@ -8,6 +19,259 @@ import type { AccountDialogAccount } from '../rpc/protocol'
8
19
  import type { OpenDialogPayload } from '../rpc/protocol.js'
9
20
  import { formatPrimeCost, formatPrimeTime } from '../sidebar-state.js'
10
21
 
22
+ /** Render menu sections, accounts and action inputs; send changes to the host instead of writing credentials here. */
23
+ export function openNativeMenuDialog(
24
+ api: {
25
+ readonly ui: Pick<
26
+ TuiPluginApi['ui'],
27
+ 'dialog' | 'DialogSelect' | 'DialogPrompt' | 'DialogConfirm' | 'toast'
28
+ >
29
+ },
30
+ payload: CommandDialogPayload,
31
+ apply: (request: CommandApplyRequest) => Promise<CommandApplyResult>,
32
+ isCurrentSession: () => boolean,
33
+ ): void {
34
+ let menu: CommandMenuModel = payload.menu
35
+ let inFlight = false
36
+ const DialogSelect = api.ui.DialogSelect<string>
37
+ const DialogPrompt = api.ui.DialogPrompt
38
+ const DialogConfirm = api.ui.DialogConfirm
39
+ const active = () => isCurrentSession() && !inFlight
40
+
41
+ const root = () => {
42
+ if (!active()) return
43
+ api.ui.dialog.setSize('xlarge')
44
+ api.ui.dialog.replace(() => (
45
+ <DialogSelect
46
+ title={menu.title}
47
+ options={[
48
+ ...menu.sections.map((section) => ({
49
+ title: section.title,
50
+ value: section.id,
51
+ })),
52
+ { title: 'Close', value: '__close' },
53
+ ]}
54
+ onSelect={(option) => {
55
+ if (!active()) return
56
+ const section = menu.sections.find(
57
+ (entry) => entry.id === option.value,
58
+ )
59
+ if (section) showSection(section)
60
+ else if (option.value === '__close') api.ui.dialog.clear()
61
+ }}
62
+ />
63
+ ))
64
+ }
65
+
66
+ const showSection = (section: MenuSection) => {
67
+ if (!active()) return
68
+ api.ui.dialog.replace(() => (
69
+ <box flexDirection='column' padding={1}>
70
+ <text>{section.lines.join('\n')}</text>
71
+ <DialogSelect
72
+ title={section.title}
73
+ options={[
74
+ ...section.items.map((item) => ({
75
+ title: item.label,
76
+ value: `item:${item.id}`,
77
+ description: item.detail,
78
+ })),
79
+ ...section.actions.map((action) => ({
80
+ title: action.label,
81
+ value: `action:${action.id}`,
82
+ description: action.description,
83
+ })),
84
+ { title: 'Back', value: '__back' },
85
+ ]}
86
+ onSelect={(option) => {
87
+ if (!active()) return
88
+ if (option.value === '__back') return root()
89
+ const action = section.actions.find(
90
+ (entry) => `action:${entry.id}` === option.value,
91
+ )
92
+ if (action) return collect(section, action)
93
+ const item = section.items.find(
94
+ (entry) => `item:${entry.id}` === option.value,
95
+ )
96
+ if (item) showItem(section, item)
97
+ }}
98
+ />
99
+ </box>
100
+ ))
101
+ }
102
+
103
+ const showItem = (section: MenuSection, item: MenuItem) => {
104
+ if (!active()) return
105
+ api.ui.dialog.replace(() => (
106
+ <box flexDirection='column' padding={1}>
107
+ <text>{item.detail ?? ''}</text>
108
+ <DialogSelect
109
+ title={item.label}
110
+ options={[
111
+ ...item.actions.map((action) => ({
112
+ title: action.label,
113
+ value: action.id,
114
+ description: action.description,
115
+ })),
116
+ { title: 'Back', value: '__back' },
117
+ ]}
118
+ onSelect={(option) => {
119
+ if (!active()) return
120
+ const action = item.actions.find(
121
+ (entry) => entry.id === option.value,
122
+ )
123
+ if (action) collect(section, action, item)
124
+ else if (option.value === '__back') showSection(section)
125
+ }}
126
+ />
127
+ </box>
128
+ ))
129
+ }
130
+
131
+ const collect = (
132
+ section: MenuSection,
133
+ action: MenuAction,
134
+ item?: MenuItem,
135
+ ) => {
136
+ const values: Record<string, KnobValue> = {}
137
+ const back = () => {
138
+ for (const key of Object.keys(values)) delete values[key]
139
+ if (item) showItem(section, item)
140
+ else showSection(section)
141
+ }
142
+ const submit = async () => {
143
+ if (!active()) return
144
+ inFlight = true
145
+ try {
146
+ const result = await apply({
147
+ command: menu.command,
148
+ sectionId: section.id,
149
+ actionId: action.id,
150
+ ...(item ? { itemId: item.id } : {}),
151
+ values: { ...values },
152
+ ...(action.confirm ? { confirmed: true } : {}),
153
+ })
154
+ if (!isCurrentSession()) return
155
+ menu = result.menu
156
+ api.ui.toast({ message: result.text })
157
+ } catch {
158
+ if (isCurrentSession())
159
+ api.ui.toast({ message: 'Menu apply unavailable; outcome unknown.' })
160
+ } finally {
161
+ for (const key of Object.keys(values)) delete values[key]
162
+ inFlight = false
163
+ if (isCurrentSession()) {
164
+ const refreshed = menu.sections.find(
165
+ (entry) => entry.id === section.id,
166
+ )
167
+ if (refreshed) showSection(refreshed)
168
+ else root()
169
+ }
170
+ }
171
+ }
172
+ const next = (index: number) => {
173
+ if (!active()) return
174
+ const knob = action.knobs[index]
175
+ if (!knob) {
176
+ if (!action.confirm) return void submit()
177
+ api.ui.dialog.replace(() => (
178
+ <DialogConfirm
179
+ title={action.label}
180
+ message={action.confirm?.message ?? ''}
181
+ onConfirm={() => void submit()}
182
+ onCancel={back}
183
+ />
184
+ ))
185
+ return
186
+ }
187
+ if (knob.kind === 'choice' || knob.kind === 'toggle') {
188
+ const choices =
189
+ knob.kind === 'choice'
190
+ ? knob.choices
191
+ : [
192
+ { value: 'on', label: 'On' },
193
+ { value: 'off', label: 'Off' },
194
+ ]
195
+ api.ui.dialog.replace(() => (
196
+ <DialogSelect
197
+ title={knob.label}
198
+ options={[
199
+ ...choices.map((choice) => ({
200
+ title: choice.label,
201
+ value: choice.value,
202
+ })),
203
+ { title: 'Cancel', value: '__cancel' },
204
+ ]}
205
+ onSelect={(option) => {
206
+ if (!active()) return
207
+ if (option.value === '__cancel') return back()
208
+ values[knob.id] =
209
+ knob.kind === 'toggle' ? option.value === 'on' : option.value
210
+ next(index + 1)
211
+ }}
212
+ />
213
+ ))
214
+ return
215
+ }
216
+ // DialogPrompt has no masking capability in the host API. Never seed a
217
+ // protected input or claim it is hidden; warn before collecting it.
218
+ api.ui.dialog.replace(() => (
219
+ <DialogPrompt
220
+ title={knob.label}
221
+ description={() => (
222
+ <text>
223
+ {knob.kind === 'text' && knob.masked
224
+ ? 'This host prompt displays input. Avoid screen sharing; the value is not echoed in menu results.'
225
+ : knob.required
226
+ ? 'Required input'
227
+ : 'Optional; leave empty for the default'}
228
+ </text>
229
+ )}
230
+ value={
231
+ knob.kind === 'text' && knob.masked
232
+ ? ''
233
+ : knob.value === undefined
234
+ ? ''
235
+ : String(knob.value)
236
+ }
237
+ placeholder={
238
+ knob.kind === 'text'
239
+ ? knob.placeholder
240
+ : `${knob.min ?? ''}-${knob.max ?? ''}`
241
+ }
242
+ onCancel={back}
243
+ onConfirm={(typed) => {
244
+ if (!active()) return
245
+ const text = typed.trim()
246
+ if (!text && knob.required) {
247
+ api.ui.toast({ message: `${knob.label} is required.` })
248
+ return
249
+ }
250
+ const value =
251
+ text === '' ? null : knob.kind === 'number' ? Number(text) : text
252
+ if (
253
+ knob.kind === 'number' &&
254
+ typeof value === 'number' &&
255
+ (!Number.isFinite(value) ||
256
+ (knob.min !== undefined && value < knob.min) ||
257
+ (knob.max !== undefined && value > knob.max))
258
+ ) {
259
+ api.ui.toast({
260
+ message: `${knob.label} needs a number in range.`,
261
+ })
262
+ return
263
+ }
264
+ values[knob.id] = value
265
+ next(index + 1)
266
+ }}
267
+ />
268
+ ))
269
+ }
270
+ next(0)
271
+ }
272
+ root()
273
+ }
274
+
11
275
  type ApplyFn = (
12
276
  command: OpenDialogPayload['command'],
13
277
  args: string,
package/src/tui/entry.mjs CHANGED
@@ -12,26 +12,52 @@ function isMissingRuntimeRegistry(error) {
12
12
  )
13
13
  }
14
14
 
15
- let mod
16
- try {
17
- await import(runtimeProbe)
18
- } catch (error) {
19
- if (!isMissingRuntimeRegistry(error)) {
20
- console.error('Anthropic Auth TUI runtime registry probe failed', error)
21
- throw error
22
- }
23
- // Older hosts and bare Bun do not provide the virtual registry. Their source
24
- // loader still applies the Solid transform, so retain the raw TSX fallback.
25
- mod = await import('../tui.tsx')
26
- }
27
-
28
- if (!mod) {
15
+ async function loadLegacyTui() {
16
+ let mod
29
17
  try {
30
- mod = await import('../tui-compiled/tui.tsx')
18
+ await import(runtimeProbe)
31
19
  } catch (error) {
32
- console.error('Anthropic Auth compiled TUI failed to load', error)
33
- throw error
20
+ if (!isMissingRuntimeRegistry(error)) {
21
+ console.error('Anthropic Auth TUI runtime registry probe failed', error)
22
+ throw error
23
+ }
24
+ // Older hosts and bare Bun do not provide the virtual registry. Their source
25
+ // loader still applies the Solid transform, so retain the raw TSX fallback.
26
+ mod = await import('../tui.tsx')
34
27
  }
28
+
29
+ if (!mod) {
30
+ try {
31
+ mod = await import('../tui-compiled/tui.tsx')
32
+ } catch (error) {
33
+ console.error('Anthropic Auth compiled TUI failed to load', error)
34
+ throw error
35
+ }
36
+ }
37
+ return mod.default
38
+ }
39
+
40
+ let legacyModule
41
+
42
+ // OpenCode 1 reads id and tui from the default definition; OpenCode 2 reads
43
+ // its setup method. Both use this package subpath, so these methods must be
44
+ // on the default export, not only exported as separate named bindings.
45
+ export const id = 'cortexkit.anthropic-auth'
46
+
47
+ /** @type {import('@opencode-ai/plugin/tui').TuiPlugin} */
48
+ export const tui = async (...args) => {
49
+ legacyModule ??= loadLegacyTui()
50
+ const plugin = await legacyModule
51
+ return plugin.tui(...args)
52
+ }
53
+
54
+ /** @type {import('@opencode/plugin/tui').Plugin.Definition['setup']} */
55
+ export const setup = async (context) => {
56
+ // OpenCode 2 already routes RPC through the active project. Importing its
57
+ // TUI must not load the OpenCode 1 renderer or start that renderer's separate
58
+ // loopback notification poller.
59
+ const { setupAnthropicTui } = await import('../../dist/v2/tui.js')
60
+ return setupAnthropicTui(context)
35
61
  }
36
62
 
37
- export default mod.default
63
+ export default { id, tui, setup }
@@ -1,4 +1,7 @@
1
- import type { ClaustrumEnrollmentStatus } from '@cortexkit/anthropic-auth-core'
1
+ import type {
2
+ ClaustrumEnrollmentStatus,
3
+ CommandDialogPayload,
4
+ } from '@cortexkit/anthropic-auth-core'
2
5
 
3
6
  export const COMMAND_MODAL_NAMES = [
4
7
  'claude-account',
@@ -53,12 +56,10 @@ export interface OpenDialogPayload {
53
56
  knobs: Record<string, unknown>
54
57
  }
55
58
 
56
- export interface RpcNotification {
57
- id: number
58
- type: 'open-dialog'
59
- payload: OpenDialogPayload
60
- sessionId: string
61
- }
59
+ export type RpcNotification = { id: number; sessionId: string } & (
60
+ | { type: 'open-dialog'; payload: OpenDialogPayload }
61
+ | { type: 'open-menu'; payload: CommandDialogPayload }
62
+ )
62
63
 
63
64
  export interface ApplyRequest {
64
65
  command: CommandModalName
@@ -1,3 +1,7 @@
1
+ import type {
2
+ CommandApplyRequest,
3
+ CommandApplyResult,
4
+ } from '@cortexkit/anthropic-auth-core'
1
5
  import { discoverPortFile } from './port-file'
2
6
  import type { ApplyRequest, ApplyResult, RpcNotification } from './protocol'
3
7
 
@@ -7,6 +11,7 @@ export interface RpcClient {
7
11
  sessionId: string,
8
12
  ) => Promise<RpcNotification[]>
9
13
  apply: (request: ApplyRequest) => Promise<ApplyResult>
14
+ applyMenu: (request: CommandApplyRequest) => Promise<CommandApplyResult>
10
15
  }
11
16
 
12
17
  async function call<T>(
@@ -58,5 +63,17 @@ export function createRpcClient(dir: string, expectedPid?: number): RpcClient {
58
63
  )
59
64
  return out ?? { text: 'apply failed', knobs: {} }
60
65
  },
66
+ async applyMenu(request) {
67
+ if (request.command !== 'claude' || !request.sessionId?.trim())
68
+ throw new TypeError('A claude menu sessionId is required')
69
+ const out = await call<CommandApplyResult>(
70
+ dir,
71
+ 'apply-menu',
72
+ { ...request },
73
+ expectedPid,
74
+ )
75
+ if (!out) throw new Error('Menu apply unavailable; outcome unknown')
76
+ return out
77
+ },
61
78
  }
62
79
  }