@yolo-labs/yolobridge 0.1.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/dist/api-client.js +136 -0
- package/dist/attach-cmd.js +299 -0
- package/dist/browser-open.js +46 -0
- package/dist/cli.js +353 -0
- package/dist/config-store.js +99 -0
- package/dist/detach-cmd.js +37 -0
- package/dist/device-auth.js +149 -0
- package/dist/frame-actions.js +34 -0
- package/dist/heartbeat.js +31 -0
- package/dist/local-agent.js +437 -0
- package/dist/login-cmd.js +50 -0
- package/dist/reconnect.js +41 -0
- package/dist/sse-frame-parser.js +66 -0
- package/dist/status-cmd.js +52 -0
- package/dist/workspaces-cmd.js +37 -0
- package/package.json +34 -0
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `yolo-bridge status` — prints current login/attach state.
|
|
3
|
+
*
|
|
4
|
+
* This reads persisted local state only (config-store.ts), not a live
|
|
5
|
+
* process: `attach` runs its daemon loop in the foreground of whatever
|
|
6
|
+
* process invoked it, and `status` is typically run from a different
|
|
7
|
+
* terminal. So this reports "what does this machine believe" (logged in
|
|
8
|
+
* as of token expiry X, last attached to workspace Y at time Z) — it
|
|
9
|
+
* cannot see whether that attach process is still alive right now
|
|
10
|
+
* (connected vs. mid-backoff vs. crashed). A future iteration could add
|
|
11
|
+
* a pidfile / lockfile next to attachment.json to close that gap; not
|
|
12
|
+
* implemented here — flagged as a known limitation, not silently glossed
|
|
13
|
+
* over.
|
|
14
|
+
*/
|
|
15
|
+
import { loadAuth, loadAttachment } from './config-store.js';
|
|
16
|
+
export function getStatus(deps = {}) {
|
|
17
|
+
const now = deps.now ?? Date.now;
|
|
18
|
+
const auth = loadAuth(deps.env, deps.io);
|
|
19
|
+
const attachment = loadAttachment(deps.env, deps.io);
|
|
20
|
+
const report = {
|
|
21
|
+
loggedIn: Boolean(auth),
|
|
22
|
+
attached: Boolean(attachment),
|
|
23
|
+
};
|
|
24
|
+
if (auth) {
|
|
25
|
+
report.tokenExpiresAtMs = auth.expiresAtMs;
|
|
26
|
+
report.tokenExpired = auth.expiresAtMs <= now();
|
|
27
|
+
}
|
|
28
|
+
if (attachment) {
|
|
29
|
+
report.workspaceId = attachment.workspaceId;
|
|
30
|
+
report.tileId = attachment.tileId;
|
|
31
|
+
report.attachmentId = attachment.attachmentId;
|
|
32
|
+
report.attachedAt = attachment.attachedAt;
|
|
33
|
+
}
|
|
34
|
+
return report;
|
|
35
|
+
}
|
|
36
|
+
export function formatStatus(report) {
|
|
37
|
+
const lines = [];
|
|
38
|
+
if (!report.loggedIn) {
|
|
39
|
+
lines.push('Logged in: no (run `yolo-bridge login`)');
|
|
40
|
+
}
|
|
41
|
+
else {
|
|
42
|
+
lines.push(`Logged in: yes${report.tokenExpired ? ' (access token expired — log in again)' : ` (token expires ${new Date(report.tokenExpiresAtMs).toISOString()})`}`);
|
|
43
|
+
}
|
|
44
|
+
if (!report.attached) {
|
|
45
|
+
lines.push('Attached: no');
|
|
46
|
+
}
|
|
47
|
+
else {
|
|
48
|
+
lines.push(`Attached: yes — workspace=${report.workspaceId} tile=${report.tileId} attachmentId=${report.attachmentId} since=${report.attachedAt}`);
|
|
49
|
+
lines.push('(local file only — does not confirm the attach daemon process is still running/connected)');
|
|
50
|
+
}
|
|
51
|
+
return lines.join('\n');
|
|
52
|
+
}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `yolo-bridge workspaces` — lists the caller's own selectable workspaces
|
|
3
|
+
* (`GET /v1/workspaces/selectable` via api-client.ts's
|
|
4
|
+
* `listSelectableWorkspaces`), so a user running `yolo-bridge attach` for
|
|
5
|
+
* the first time has somewhere to find a workspaceId without already
|
|
6
|
+
* knowing a raw MongoDB ObjectId. Non-interactive/scriptable: plain text
|
|
7
|
+
* to stdout, no prompting, safe to pipe.
|
|
8
|
+
*/
|
|
9
|
+
import { listSelectableWorkspaces } from './api-client.js';
|
|
10
|
+
import { loadAuth } from './config-store.js';
|
|
11
|
+
export async function runListWorkspaces(deps) {
|
|
12
|
+
const auth = loadAuth(deps.env, deps.io);
|
|
13
|
+
if (!auth)
|
|
14
|
+
return { ok: false, reason: 'not-logged-in', message: 'Not logged in — run `yolo-bridge login` first.' };
|
|
15
|
+
try {
|
|
16
|
+
const workspaces = await listSelectableWorkspaces({
|
|
17
|
+
commonApiBaseUrl: deps.commonApiBaseUrl,
|
|
18
|
+
accessToken: auth.accessToken,
|
|
19
|
+
fetchImpl: deps.fetchImpl,
|
|
20
|
+
});
|
|
21
|
+
return { ok: true, workspaces };
|
|
22
|
+
}
|
|
23
|
+
catch (err) {
|
|
24
|
+
return { ok: false, reason: 'error', message: err instanceof Error ? err.message : String(err) };
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
/** Renders a simple aligned-columns table: id, name, status per row. */
|
|
28
|
+
export function formatWorkspacesTable(workspaces) {
|
|
29
|
+
if (workspaces.length === 0) {
|
|
30
|
+
return 'No workspaces found.';
|
|
31
|
+
}
|
|
32
|
+
const idWidth = Math.max('ID'.length, ...workspaces.map((w) => w.id.length));
|
|
33
|
+
const nameWidth = Math.max('NAME'.length, ...workspaces.map((w) => (w.name || '(unnamed)').length));
|
|
34
|
+
const header = `${'ID'.padEnd(idWidth)} ${'NAME'.padEnd(nameWidth)} STATUS`;
|
|
35
|
+
const rows = workspaces.map((w) => `${w.id.padEnd(idWidth)} ${(w.name || '(unnamed)').padEnd(nameWidth)} ${w.status}`);
|
|
36
|
+
return [header, ...rows].join('\n');
|
|
37
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@yolo-labs/yolobridge",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "YoloBridge — local coding-agent daemon that attaches a user's own Claude Code/Codex session to a YOLO Studio workspace as a first-class tile (docs/YOLOBRIDGE_PLAN.md, build-order Phase 5).",
|
|
5
|
+
"license": "MIT",
|
|
6
|
+
"type": "module",
|
|
7
|
+
"bin": {
|
|
8
|
+
"yolo-bridge": "dist/cli.js"
|
|
9
|
+
},
|
|
10
|
+
"publishConfig": {
|
|
11
|
+
"access": "public"
|
|
12
|
+
},
|
|
13
|
+
"files": [
|
|
14
|
+
"dist/**/*.js",
|
|
15
|
+
"!dist/**/*.test.js",
|
|
16
|
+
"README.md"
|
|
17
|
+
],
|
|
18
|
+
"scripts": {
|
|
19
|
+
"build": "tsc -p tsconfig.json",
|
|
20
|
+
"test": "npm run build && node --test --test-reporter=spec dist/*.test.js",
|
|
21
|
+
"clean": "rm -rf dist"
|
|
22
|
+
},
|
|
23
|
+
"engines": {
|
|
24
|
+
"node": ">=20"
|
|
25
|
+
},
|
|
26
|
+
"devDependencies": {
|
|
27
|
+
"@types/node": "^20.0.0",
|
|
28
|
+
"typescript": "^5.4.0"
|
|
29
|
+
},
|
|
30
|
+
"dependencies": {
|
|
31
|
+
"@xterm/headless": "^6.0.0",
|
|
32
|
+
"node-pty": "^1.1.0"
|
|
33
|
+
}
|
|
34
|
+
}
|