kira-glasses-bridge 2.20.0 → 2.21.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.
- package/package.json +1 -1
- package/src/agents/claude-local.mjs +29 -0
- package/src/agents/complete.mjs +59 -0
- package/src/index.mjs +2 -16
package/package.json
CHANGED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
// Claude Code on this Mac, as the person signed in to it: which account it uses, and one piece
|
|
2
|
+
// of text written with that sign-in (complete.mjs). The bridge's calls for both.
|
|
3
|
+
import { execFile } from 'node:child_process'
|
|
4
|
+
import { completeText } from './complete.mjs'
|
|
5
|
+
|
|
6
|
+
/** Which Claude account Claude Code on this Mac is signed in to (`claude auth status --json`). */
|
|
7
|
+
async function claudeAccount() {
|
|
8
|
+
const bin = process.env.KIRA_CLAUDE_BIN || 'claude'
|
|
9
|
+
return new Promise(resolve =>
|
|
10
|
+
execFile(bin, ['auth', 'status', '--json'], { timeout: 10_000 }, (err, stdout) => {
|
|
11
|
+
try {
|
|
12
|
+
const s = JSON.parse(stdout)
|
|
13
|
+
resolve({
|
|
14
|
+
loggedIn: !!s.loggedIn,
|
|
15
|
+
email: s.email ?? null,
|
|
16
|
+
plan: s.subscriptionType ?? null,
|
|
17
|
+
org: s.orgName ?? null,
|
|
18
|
+
method: s.authMethod ?? null,
|
|
19
|
+
})
|
|
20
|
+
} catch {
|
|
21
|
+
const missing = err?.code === 'ENOENT'
|
|
22
|
+
const why = missing ? 'Claude Code is not installed on this Mac' : 'Claude Code did not say which account'
|
|
23
|
+
resolve({ error: why })
|
|
24
|
+
}
|
|
25
|
+
}),
|
|
26
|
+
)
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export const claudeTools = { claude_account: claudeAccount, complete_text: completeText }
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
// One piece of text from the person's own Claude Code, with their own sign-in (no API key): a task
|
|
2
|
+
// brief, a recording's notes, an automation's thinking step. One turn, no tools, nothing written:
|
|
3
|
+
// the API asks this when their Mac is online, and uses an API key only when it isn't.
|
|
4
|
+
import { query } from '@anthropic-ai/claude-agent-sdk'
|
|
5
|
+
import { mkdirSync } from 'node:fs'
|
|
6
|
+
import { homedir } from 'node:os'
|
|
7
|
+
import { join } from 'node:path'
|
|
8
|
+
|
|
9
|
+
/** Everything Claude Code could reach for: text only here. */
|
|
10
|
+
const NO_TOOLS = [
|
|
11
|
+
'Read', 'Write', 'Edit', 'MultiEdit', 'NotebookEdit', 'Bash', 'Glob', 'Grep', 'LS', 'WebFetch', 'WebSearch',
|
|
12
|
+
'Task', 'Agent', 'TodoWrite', 'ToolSearch', 'Skill', 'ExitPlanMode', 'ListMcpResourcesTool', 'ReadMcpResourceTool',
|
|
13
|
+
]
|
|
14
|
+
const MAX_MS = 170_000
|
|
15
|
+
|
|
16
|
+
/** Its own folder, so these one-off turns don't land among the person's sessions for real work. */
|
|
17
|
+
function folder() {
|
|
18
|
+
const dir = join(homedir(), '.kira', 'text')
|
|
19
|
+
mkdirSync(dir, { recursive: true })
|
|
20
|
+
return dir
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export async function completeText(args) {
|
|
24
|
+
const system = String(args?.system ?? '').trim()
|
|
25
|
+
const user = String(args?.user ?? '').trim()
|
|
26
|
+
if (!user) return { error: 'user is required' }
|
|
27
|
+
const abort = new AbortController()
|
|
28
|
+
const timer = setTimeout(() => abort.abort(), Math.min(Number(args?.timeout_ms) || 60_000, MAX_MS))
|
|
29
|
+
try {
|
|
30
|
+
const q = query({
|
|
31
|
+
prompt: user,
|
|
32
|
+
options: {
|
|
33
|
+
cwd: folder(),
|
|
34
|
+
env: { ...process.env, ENABLE_CLAUDEAI_MCP_SERVERS: 'false' },
|
|
35
|
+
...(system ? { systemPrompt: system } : {}),
|
|
36
|
+
disallowedTools: NO_TOOLS,
|
|
37
|
+
canUseTool: async () => ({ behavior: 'deny', message: 'Write the answer as text; no tools here.' }),
|
|
38
|
+
// Claude's best for writing that people read; the API can ask for another ("sonnet", "haiku").
|
|
39
|
+
model: String(args?.model ?? 'opus'),
|
|
40
|
+
maxTurns: 1,
|
|
41
|
+
settingSources: [],
|
|
42
|
+
abortController: abort,
|
|
43
|
+
...(process.env.KIRA_CLAUDE_BIN ? { pathToClaudeCodeExecutable: process.env.KIRA_CLAUDE_BIN } : {}),
|
|
44
|
+
},
|
|
45
|
+
})
|
|
46
|
+
let model = null
|
|
47
|
+
for await (const m of q) {
|
|
48
|
+
if (m.type === 'system' && m.subtype === 'init') model = m.model ?? null
|
|
49
|
+
if (m.type !== 'result') continue
|
|
50
|
+
if (m.subtype !== 'success') return { error: `Claude stopped: ${m.subtype}` }
|
|
51
|
+
return { text: String(m.result ?? '').trim(), model }
|
|
52
|
+
}
|
|
53
|
+
return { error: 'Claude ended without an answer' }
|
|
54
|
+
} catch (err) {
|
|
55
|
+
return { error: abort.signal.aborted ? 'Claude took too long' : `could not run Claude: ${err.message}` }
|
|
56
|
+
} finally {
|
|
57
|
+
clearTimeout(timer)
|
|
58
|
+
}
|
|
59
|
+
}
|
package/src/index.mjs
CHANGED
|
@@ -13,6 +13,7 @@ import { openApp, installedApps } from './apps.mjs'
|
|
|
13
13
|
import { listFiles, readUserFile, createFolder, writeUserFile, trashPath, resolveUserPath } from './files.mjs'
|
|
14
14
|
import { initTerminals, terminalCall, terminalMessage, terminalsOffline } from './terminals.mjs'
|
|
15
15
|
import { gitTools } from './git-tools.mjs'
|
|
16
|
+
import { claudeTools } from './agents/claude-local.mjs'
|
|
16
17
|
|
|
17
18
|
import { createRequire } from 'node:module'
|
|
18
19
|
const { version: BRIDGE_VERSION } = createRequire(import.meta.url)('../package.json')
|
|
@@ -212,22 +213,7 @@ end tell`
|
|
|
212
213
|
},
|
|
213
214
|
|
|
214
215
|
...gitTools,
|
|
215
|
-
|
|
216
|
-
/** Which Claude account Claude Code on this Mac is signed in to (`claude auth status --json`). */
|
|
217
|
-
async claude_account() {
|
|
218
|
-
const { execFile } = await import('node:child_process')
|
|
219
|
-
const bin = process.env.KIRA_CLAUDE_BIN || 'claude'
|
|
220
|
-
return new Promise(resolve =>
|
|
221
|
-
execFile(bin, ['auth', 'status', '--json'], { timeout: 10_000 }, (err, stdout) => {
|
|
222
|
-
try {
|
|
223
|
-
const s = JSON.parse(stdout)
|
|
224
|
-
resolve({ loggedIn: !!s.loggedIn, email: s.email ?? null, plan: s.subscriptionType ?? null, org: s.orgName ?? null, method: s.authMethod ?? null })
|
|
225
|
-
} catch {
|
|
226
|
-
resolve({ error: err?.code === 'ENOENT' ? 'Claude Code is not installed on this Mac' : 'Claude Code did not say which account it uses' })
|
|
227
|
-
}
|
|
228
|
-
}),
|
|
229
|
-
)
|
|
230
|
-
},
|
|
216
|
+
...claudeTools,
|
|
231
217
|
|
|
232
218
|
|
|
233
219
|
}
|