hilos-agent 0.11.10 → 0.11.11
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/hook.mjs +15 -10
- package/src/seat-repository.d.mts +1 -0
- package/src/seat-repository.mjs +24 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "hilos-agent",
|
|
3
|
-
"version": "0.11.
|
|
3
|
+
"version": "0.11.11",
|
|
4
4
|
"description": "Run your own coding agent (Claude Code, Codex, Cursor, OpenCode, Hermes, or any command) as a teammate in a hilos room. The checkout and credentials stay local; changes go to your configured Git remote as a PR for human review, and bounded progress and reports go to hilos.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
package/src/hook.mjs
CHANGED
|
@@ -26,6 +26,7 @@ import { join, dirname } from "node:path";
|
|
|
26
26
|
import { fileURLToPath } from "node:url";
|
|
27
27
|
import { sanitizeText, webTarget } from "./agent-events.mjs";
|
|
28
28
|
import { resolveConfig } from "./config.mjs";
|
|
29
|
+
import { normalizeSeatRepository } from "./seat-repository.mjs";
|
|
29
30
|
|
|
30
31
|
export const HOOK_STATE_DIR = join(homedir(), ".hilos", "hook-state");
|
|
31
32
|
export const CODEX_HOOK_SCOPE_FILE = join(homedir(), ".hilos", "codex-hook-scope.json");
|
|
@@ -402,24 +403,25 @@ export function seatLabel(value) {
|
|
|
402
403
|
}
|
|
403
404
|
|
|
404
405
|
/**
|
|
405
|
-
* The
|
|
406
|
-
*
|
|
407
|
-
* timeout, and a failure just falls back — a hook never blocks the CLI.
|
|
406
|
+
* The canonical origin for this session. Git is asked once at attach with a
|
|
407
|
+
* short timeout. A missing or unsupported origin leaves the seat unbound.
|
|
408
408
|
*/
|
|
409
|
-
export function
|
|
410
|
-
const folder = seatLabel(cwd);
|
|
409
|
+
export function readSeatRepository(cwd, { spawn = spawnSync } = {}) {
|
|
411
410
|
try {
|
|
412
411
|
const out = spawn("git", ["-C", String(cwd || "."), "remote", "get-url", "origin"], {
|
|
413
412
|
encoding: "utf8",
|
|
414
413
|
timeout: 1500,
|
|
415
414
|
});
|
|
416
|
-
|
|
417
|
-
return remote || folder;
|
|
415
|
+
return out?.status === 0 ? normalizeSeatRepository(out.stdout) : null;
|
|
418
416
|
} catch {
|
|
419
|
-
return
|
|
417
|
+
return null;
|
|
420
418
|
}
|
|
421
419
|
}
|
|
422
420
|
|
|
421
|
+
export function readSeatLabel(cwd, options) {
|
|
422
|
+
return seatLabel(readSeatRepository(cwd, options)) || seatLabel(cwd);
|
|
423
|
+
}
|
|
424
|
+
|
|
423
425
|
/** One bounded personal `tools/call`. Returns the parsed payload, or null. */
|
|
424
426
|
export async function callPersonalTool({ url, token, client, name, args }) {
|
|
425
427
|
const controller = new AbortController();
|
|
@@ -463,7 +465,8 @@ export async function runPersonalSeat({
|
|
|
463
465
|
now = Date.now,
|
|
464
466
|
note = "",
|
|
465
467
|
call = callPersonalTool,
|
|
466
|
-
label
|
|
468
|
+
label,
|
|
469
|
+
repository = readSeatRepository,
|
|
467
470
|
}) {
|
|
468
471
|
if (!personal || !ev) return state;
|
|
469
472
|
const seat = state.seat && typeof state.seat === "object" ? state.seat : {};
|
|
@@ -479,12 +482,14 @@ export async function runPersonalSeat({
|
|
|
479
482
|
ev.event === "PostToolUse";
|
|
480
483
|
if (!seat.id && !wantsSeat) return state;
|
|
481
484
|
if (ev.event === "SessionStart" || !seat.id) {
|
|
485
|
+
const repositoryUrl = repository(ev.cwd);
|
|
482
486
|
const attached = await call({
|
|
483
487
|
...base,
|
|
484
488
|
name: "attach_session",
|
|
485
489
|
args: {
|
|
486
490
|
client: personal.client,
|
|
487
|
-
label: label(ev.cwd),
|
|
491
|
+
label: label ? label(ev.cwd) : seatLabel(repositoryUrl) || seatLabel(ev.cwd),
|
|
492
|
+
...(repositoryUrl ? { repositoryUrl } : {}),
|
|
488
493
|
sessionKey: ev.sessionId,
|
|
489
494
|
},
|
|
490
495
|
});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export function normalizeSeatRepository(value: unknown): string | null;
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A GitHub origin as a credential-free HTTPS URL. Room links currently name
|
|
3
|
+
* GitHub repositories, so another host (even with the same owner/repo), local
|
|
4
|
+
* paths, SSH aliases, and malformed remotes cannot select a room.
|
|
5
|
+
*/
|
|
6
|
+
export function normalizeSeatRepository(value) {
|
|
7
|
+
if (typeof value !== "string") return null;
|
|
8
|
+
const text = value.trim();
|
|
9
|
+
if (!text || /[\\\s]/.test(text)) return null;
|
|
10
|
+
let url;
|
|
11
|
+
try {
|
|
12
|
+
const scp = text.match(/^git@github\.com:([^?#]+)$/i);
|
|
13
|
+
url = new URL(scp ? `https://github.com/${scp[1]}` : text);
|
|
14
|
+
} catch {
|
|
15
|
+
return null;
|
|
16
|
+
}
|
|
17
|
+
if (!["https:", "http:", "ssh:", "git:"].includes(url.protocol) ||
|
|
18
|
+
url.hostname.toLowerCase() !== "github.com" || url.port) return null;
|
|
19
|
+
const path = url.pathname.replace(/\/$/, "").replace(/\.git$/i, "");
|
|
20
|
+
if (!/^\/[a-z0-9-]+\/[a-z0-9_.-]+$/i.test(path)) return null;
|
|
21
|
+
const [, owner, repo] = path.split("/");
|
|
22
|
+
if (repo === "." || repo === "..") return null;
|
|
23
|
+
return `https://github.com/${owner.toLowerCase()}/${repo.toLowerCase()}`;
|
|
24
|
+
}
|