hilos-agent 0.9.1 → 0.9.2

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/README.md CHANGED
@@ -257,21 +257,32 @@ npx hilos-agent hooks install --cursor
257
257
  npx hilos-agent hooks install --global
258
258
  ```
259
259
 
260
- This writes lifecycle entries into `.codex/hooks.json`, `.claude/settings.json`,
261
- and `.cursor/hooks.json` (or their home-directory equivalents with `--global`),
262
- preserving any hooks you already have. Codex asks you to review new project
263
- hooks once; open `/hooks` and trust the hilos entries. Preview all three blocks
264
- without writing anything:
260
+ Claude Code and Cursor write lifecycle entries into this repo. Codex needs one
261
+ entry in `~/.codex/hooks.json` because `codex exec` does not run repository
262
+ hooks. hilos keeps that entry project-scoped with a 0600 allowlist at
263
+ `~/.hilos/codex-hook-scope.json`, so other repos stay untouched unless you use
264
+ `--global`. Launching Codex below the opted-in repository root still works, but
265
+ a nested repository needs its own opt-in. If the allowlist is lost or malformed,
266
+ new installs fail closed instead of reporting from every repo.
267
+
268
+ Any hooks you already have are preserved. A pre-existing project-level hilos
269
+ Codex entry is moved out, with a `.bak` beside the changed file. Codex asks you
270
+ to review the home-level hilos hook once; open `/hooks` and trust the entry.
271
+ The installer copies the dependency-free hook code into a private, versioned
272
+ `~/.hilos/hook-runtime` and records its absolute entrypoint. A one-off npx run
273
+ therefore remains usable offline; no global install or PATH change is required.
274
+ Preview all three blocks without writing anything:
265
275
 
266
276
  ```sh
267
277
  npx hilos-agent hooks print
268
278
  ```
269
279
 
270
280
  **Requirements:**
271
- - `npm i -g hilos-agent` so the `hilos-agent hook` command resolves at hook time.
272
- - A `~/.hilos/agent.json` with `url` and the owned agent's `token`; `channelId`
273
- is needed only for the fallback live card. Generate these in the agent's
274
- **Connect via MCP** panel in hilos (same panel as `--join`).
281
+ - For live progress from every tool event, a `~/.hilos/agent.json` with `url`
282
+ and the owned agent's `token`; `channelId` is needed only for the fallback
283
+ live card. The normal one-line `--join` flow does not need that file for
284
+ replies: its token stays in daemon memory, and Hilos signs each session
285
+ binding so the daemon can verify it before resuming local code.
275
286
  - Keep `hilos-agent` running to pick replies up. Hooks alone still stream live
276
287
  steps, but MCP has no server-push channel that can wake an idle local client.
277
288
 
@@ -281,7 +292,14 @@ npx hilos-agent hooks print
281
292
  - A successful hilos post binds its returned message to this provider session.
282
293
  A person's later reply to that exact thread resumes the same session while
283
294
  `hilos-agent` is running. Ambient messages, older thread history, and agent
284
- replies do not wake it.
295
+ replies do not wake it. Current workspace roles are checked at pickup: guests,
296
+ removed people, and unknown authors remain advisory and cannot start code.
297
+ - The resumed turn receives bounded thread, room, and member context. Codex also
298
+ gets a random loopback-only Hilos MCP URL for that turn, so it can search any
299
+ room its linked owner can access when that owner minted the current key,
300
+ without receiving the bearer token. Regenerate an older key from Connect to
301
+ enable that inheritance. Admin-issued keys and other people's private rooms
302
+ stay outside the context.
285
303
  - The room's normal execution gate still applies; a chat-only guest room cannot
286
304
  resume local code.
287
305
  - Steps are coalesced into ~2s batches to keep traffic light.
@@ -290,10 +308,12 @@ npx hilos-agent hooks print
290
308
  - Up to 20 unique files touched are surfaced so reviewers can glance at the scope
291
309
  before the report card arrives.
292
310
 
293
- **Privacy:** project-level by default (only repos you opt into stream). Hook
294
- state stays in `~/.hilos/hook-state` and contains session ids, checkout paths,
295
- hilos message ids, progress steps, and any completed result waiting for a
296
- delivery retry never the coding transcript. Kill
311
+ **Privacy:** project-level by default (only repos you opt into stream, including
312
+ Codex through its local allowlist). Hook state stays in
313
+ `~/.hilos/hook-state` and contains session ids, checkout paths,
314
+ hilos message ids, an opaque server-signed binding proof, a one-way credential
315
+ scope after verification, progress steps, and any completed result waiting for
316
+ a delivery retry — never the bearer token or coding transcript. Kill
297
317
  switches: `HILOS_HOOKS=off` pauses streaming and new bindings;
298
318
  `HILOS_REPLY_BRIDGE=off` pauses inbound replies. The hook always exits 0 — it
299
319
  will never interrupt or break your CLI session.
@@ -50,6 +50,8 @@ function parseArgs(argv) {
50
50
  else if (a === "--codex") flags.hookClient = "codex";
51
51
  else if (a === "--cursor") flags.hookClient = "cursor";
52
52
  else if (a === "--vendor") flags.vendor = argv[++i];
53
+ else if (a === "--scope-managed") flags.scopeManaged = true;
54
+ else if (a === "--managed-runtime") flags.managedRuntime = true;
53
55
  else if (a === "-h" || a === "--help") flags.help = true;
54
56
  else if (a === "-v" || a === "--version") flags.version = true;
55
57
  else positional.push(a);
@@ -106,7 +108,7 @@ async function main() {
106
108
  // fast, silent, and always exit 0, so it short-circuits before any daemon
107
109
  // machinery.
108
110
  if (cmd === "hook") {
109
- await hookMain({ vendor: flags.vendor || "unknown" });
111
+ await hookMain({ vendor: flags.vendor || "unknown", scopeManaged: Boolean(flags.scopeManaged) });
110
112
  return;
111
113
  }
112
114
  if (cmd === "hooks") {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "hilos-agent",
3
- "version": "0.9.1",
3
+ "version": "0.9.2",
4
4
  "description": "Run your own coding agent (Claude Code / Codex / Cursor) as an autonomous teammate in a hilos channel. Picks up @mentions in channels and threads, makes the change, and opens a PR for review — your code and credentials never leave your machine. (Approve-before-push is available via gate:true.)",
5
5
  "type": "module",
6
6
  "bin": {
package/src/argv.mjs ADDED
@@ -0,0 +1,61 @@
1
+ // Small shell-word parser for configured CLI commands. hilos never runs these
2
+ // strings through a shell; this preserves quoted paths/values while keeping the
3
+ // spawn boundary injection-safe. It intentionally supports words, single and
4
+ // double quotes, and backslash-escaped whitespace/quotes—not expansions, pipes,
5
+ // or redirects. Other backslashes stay literal so Windows and UNC paths work.
6
+
7
+ export function commandArgv(command) {
8
+ const input = String(command || "");
9
+ const out = [];
10
+ let word = "";
11
+ let quote = "";
12
+ let started = false;
13
+ for (let index = 0; index < input.length; index += 1) {
14
+ const char = input[index];
15
+ if (char === "\\" && quote !== "'") {
16
+ const next = input[index + 1];
17
+ const escapesQuote = next === '"' || (!quote && next === "'");
18
+ const escapesWhitespace = !quote && typeof next === "string" && /\s/.test(next);
19
+ if (escapesQuote || escapesWhitespace) {
20
+ word += next;
21
+ index += 1;
22
+ } else {
23
+ word += "\\";
24
+ }
25
+ started = true;
26
+ continue;
27
+ }
28
+ if (quote) {
29
+ if (char === quote) quote = "";
30
+ else word += char;
31
+ started = true;
32
+ continue;
33
+ }
34
+ if (char === "'" || char === '"') {
35
+ quote = char;
36
+ started = true;
37
+ continue;
38
+ }
39
+ if (/\s/.test(char)) {
40
+ if (started) {
41
+ out.push(word);
42
+ word = "";
43
+ started = false;
44
+ }
45
+ continue;
46
+ }
47
+ word += char;
48
+ started = true;
49
+ }
50
+ if (started) out.push(word);
51
+ return out;
52
+ }
53
+
54
+ /**
55
+ * Encode one literal argument for `commandArgv`'s small command grammar.
56
+ * Single-quoted spans preserve whitespace and backslashes verbatim; an
57
+ * embedded apostrophe is represented as an adjacent double-quoted span.
58
+ */
59
+ export function quoteCommandArg(value) {
60
+ return `'${String(value).replaceAll("'", `'"'"'`)}'`;
61
+ }