kira-glasses-bridge 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.
- package/package.json +1 -1
- package/src/git.mjs +28 -0
- package/src/index.mjs +20 -1
package/package.json
CHANGED
package/src/git.mjs
CHANGED
|
@@ -153,3 +153,31 @@ async function summary(before, root, files, diff, truncated, commits, treeAfter)
|
|
|
153
153
|
truncated,
|
|
154
154
|
}
|
|
155
155
|
}
|
|
156
|
+
|
|
157
|
+
/**
|
|
158
|
+
* Make a project folder ready: create it, then either clone the repo into it
|
|
159
|
+
* (SSH first, HTTPS as fallback) or start a fresh git repo with a README.
|
|
160
|
+
*/
|
|
161
|
+
export async function setupProjectFolder({ dir, name, description, sshUrl, httpsUrl }) {
|
|
162
|
+
const { mkdir, readdir, writeFile, stat } = await import('node:fs/promises')
|
|
163
|
+
const { execFile } = await import('node:child_process')
|
|
164
|
+
const run = (args, cwd) =>
|
|
165
|
+
new Promise(resolve => execFile('git', args, { cwd, maxBuffer: 8 * 1024 * 1024, timeout: 120_000 }, (err, stdout, stderr) => resolve({ ok: !err, out: String(stdout ?? ''), err: String(stderr ?? err?.message ?? '') })))
|
|
166
|
+
await mkdir(dir, { recursive: true })
|
|
167
|
+
const entries = (await readdir(dir)).filter(e => e !== '.DS_Store')
|
|
168
|
+
const already = await stat(`${dir}/.git`).then(s => s.isDirectory()).catch(() => false)
|
|
169
|
+
if (already) return { path: display(dir), existing: true, note: 'already a git repository' }
|
|
170
|
+
if (sshUrl || httpsUrl) {
|
|
171
|
+
if (entries.length) return { error: `${display(dir)} is not empty; choose an empty folder to clone into` }
|
|
172
|
+
let r = sshUrl ? await run(['clone', sshUrl, dir], dir) : { ok: false, err: 'no ssh url' }
|
|
173
|
+
if (!r.ok && httpsUrl) r = await run(['clone', httpsUrl, dir], dir)
|
|
174
|
+
if (!r.ok) return { error: `could not clone: ${r.err.trim().split('\n').pop()}` }
|
|
175
|
+
return { path: display(dir), cloned: true }
|
|
176
|
+
}
|
|
177
|
+
const r = await run(['init', '-q'], dir)
|
|
178
|
+
if (!r.ok) return { error: `git init failed: ${r.err.trim()}` }
|
|
179
|
+
if (!entries.includes('README.md')) await writeFile(`${dir}/README.md`, `# ${name ?? display(dir).split('/').pop()}\n${description ? `\n${description}\n` : ''}`)
|
|
180
|
+
await run(['add', '-A'], dir)
|
|
181
|
+
const c = await run(['commit', '-q', '-m', 'Initial commit'], dir)
|
|
182
|
+
return { path: display(dir), initialized: true, committed: c.ok, ...(c.ok ? {} : { note: 'git init done; the first commit needs git user.name and user.email configured' }) }
|
|
183
|
+
}
|
package/src/index.mjs
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
// machine on the user's behalf. Env: KIRA_BRIDGE_URL, KIRA_BRIDGE_TOKEN.
|
|
4
4
|
import WebSocket from 'ws'
|
|
5
5
|
import { listProjects, listSessions, readSession } from './claude-sessions.mjs'
|
|
6
|
-
import { snapshot, changesSince, display } from './git.mjs'
|
|
6
|
+
import { snapshot, changesSince, display, setupProjectFolder } from './git.mjs'
|
|
7
7
|
import { resolveCwd } from './claude-run.mjs'
|
|
8
8
|
import { agentById, AGENTS } from './agents/index.mjs'
|
|
9
9
|
import { normalizeAnswer } from './agents/protocol.mjs'
|
|
@@ -118,6 +118,25 @@ const tools = {
|
|
|
118
118
|
return tools.run_agent({ ...args, agent: 'claude' }, ws)
|
|
119
119
|
},
|
|
120
120
|
|
|
121
|
+
/** A new project's folder on this Mac: created, cloned from its repo or started fresh. */
|
|
122
|
+
async setup_project_folder(args) {
|
|
123
|
+
const dir = resolveUserPath(String(args.path ?? ''))
|
|
124
|
+
return setupProjectFolder({ dir, name: args.name, description: args.description, sshUrl: args.ssh_url, httpsUrl: args.https_url })
|
|
125
|
+
},
|
|
126
|
+
|
|
127
|
+
/** Open Terminal on this Mac in a folder and run a command there (used to hand a Claude session to the person). */
|
|
128
|
+
async open_terminal(args) {
|
|
129
|
+
const dir = resolveUserPath(String(args.cwd ?? ''))
|
|
130
|
+
const command = String(args.command ?? '').replace(/[^\w\s./:@=-]/g, '')
|
|
131
|
+
if (process.platform !== 'darwin') return { error: 'opening a terminal is only supported on macOS' }
|
|
132
|
+
const { execFile } = await import('node:child_process')
|
|
133
|
+
const script = `tell application "Terminal"
|
|
134
|
+
activate
|
|
135
|
+
do script "cd ${JSON.stringify(dir)} && ${command}"
|
|
136
|
+
end tell`
|
|
137
|
+
return new Promise(resolve => execFile('osascript', ['-e', script], err => resolve(err ? { error: err.message } : { opened: true, cwd: display(dir), command })))
|
|
138
|
+
},
|
|
139
|
+
|
|
121
140
|
/** Read-only git facts for a folder: repo, branch, head, dirty files. */
|
|
122
141
|
async git_status(args) {
|
|
123
142
|
const s = await snapshot(resolveCwd(args.path ?? args.cwd))
|