hilos-agent 0.9.0 → 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 +80 -16
- package/bin/hilos-agent.mjs +16 -6
- package/package.json +1 -1
- package/src/acp-session.mjs +69 -54
- package/src/agent-events.mjs +645 -45
- package/src/argv.mjs +61 -0
- package/src/attachments.mjs +310 -0
- package/src/claude-permissions.mjs +445 -0
- package/src/cli.mjs +56 -0
- package/src/codex-mcp-session.mjs +619 -0
- package/src/config.mjs +83 -7
- package/src/handler.mjs +914 -77
- package/src/hook.mjs +793 -108
- package/src/mcp-loopback.mjs +142 -0
- package/src/mcp.mjs +3 -2
- package/src/model-resolve.mjs +180 -11
- package/src/permission-gate.mjs +269 -0
- package/src/progress-emitter.mjs +100 -5
- package/src/queue.mjs +21 -5
- package/src/redact.mjs +11 -1
- package/src/reply-bridge.mjs +847 -0
- package/src/resume.mjs +48 -11
- package/src/run.mjs +130 -4
- package/src/transcript.mjs +153 -0
package/src/config.mjs
CHANGED
|
@@ -57,12 +57,42 @@ const DEFAULTS = {
|
|
|
57
57
|
// it still won't run arbitrary commands. Override in hilos-agent.json if you
|
|
58
58
|
// want a stricter (or `--dangerously-skip-permissions`) command.
|
|
59
59
|
codingCmd: "claude -p --permission-mode acceptEdits",
|
|
60
|
-
// ACP transport
|
|
61
|
-
//
|
|
62
|
-
//
|
|
63
|
-
//
|
|
64
|
-
//
|
|
65
|
-
|
|
60
|
+
// ACP transport (0759): drive the coding CLI over the Agent Client Protocol
|
|
61
|
+
// (JSON-RPC on stdio) instead of argv + stdout scraping. Covers opencode
|
|
62
|
+
// (`opencode acp`) and cursor (`cursor-agent acp`), and only for runs the
|
|
63
|
+
// workspace already gates with runtime permissions; every other run keeps
|
|
64
|
+
// the existing paths.
|
|
65
|
+
//
|
|
66
|
+
// ON by default since 0778. Both vendors' adapters are proven live (0759
|
|
67
|
+
// slices 1–2, `scripts/verify-acp.mjs`), and leaving it off meant a
|
|
68
|
+
// workspace that had explicitly granted runtime permissions still got no
|
|
69
|
+
// approval card — the gate existed and nobody was behind it. Resume no
|
|
70
|
+
// longer disqualifies a run either (both agents advertise ACP `loadSession`).
|
|
71
|
+
// Set `acpTransport: false` in hilos-agent.json to opt a machine back out;
|
|
72
|
+
// HILOS_ACP=0 does the same from the environment.
|
|
73
|
+
acpTransport: true,
|
|
74
|
+
// Run transcripts (0792): after a coding run reports, upload the tail of the
|
|
75
|
+
// CLI's own stream so the room keeps a record of what the agent did — the
|
|
76
|
+
// same redacted-NDJSON-in-a-private-bucket a hosted run gets, read only
|
|
77
|
+
// through /api/run-transcript and never by workspace guests.
|
|
78
|
+
//
|
|
79
|
+
// OFF by default, and it stays off until the operator says otherwise. Every
|
|
80
|
+
// other flag here changes how work is DONE on this machine; this one moves
|
|
81
|
+
// bytes off it. Whatever the CLI printed — file paths, command output, the
|
|
82
|
+
// shape of a private codebase — is the operator's, and the honest default for
|
|
83
|
+
// "may I keep a copy of your terminal" is no. The daemon redacts before
|
|
84
|
+
// sending and the server redacts again, but neither is a substitute for
|
|
85
|
+
// being asked.
|
|
86
|
+
//
|
|
87
|
+
// Set `uploadTranscripts: true` in hilos-agent.json to turn it on;
|
|
88
|
+
// HILOS_UPLOAD_TRANSCRIPTS=1 does the same from the environment (=0 forces it
|
|
89
|
+
// back off). Live-reloadable, so it can be revoked without a restart.
|
|
90
|
+
uploadTranscripts: false,
|
|
91
|
+
// Replies in an exact thread bound by an opted-in local-session hook resume
|
|
92
|
+
// that same provider session (0847). The hook install is the consent gate;
|
|
93
|
+
// this switch lets an operator pause inbound pickup without uninstalling it.
|
|
94
|
+
// No transcript is read or uploaded by this path.
|
|
95
|
+
replyBridge: true,
|
|
66
96
|
// Environment handed to the coding/chat CLI. hilos's own token (HILOS_*) is
|
|
67
97
|
// ALWAYS stripped either way. "inherit" (default) passes the rest of your
|
|
68
98
|
// shell env so the coding tool behaves exactly as if you ran it yourself.
|
|
@@ -130,7 +160,24 @@ export function resolveConfig({ flags = {}, join: joinPayload } = {}) {
|
|
|
130
160
|
chatTimeoutMs: process.env.HILOS_CHAT_TIMEOUT_MS ? Number(process.env.HILOS_CHAT_TIMEOUT_MS) : undefined,
|
|
131
161
|
backfill: process.env.HILOS_BACKFILL === "1" ? true : undefined,
|
|
132
162
|
once: process.env.HILOS_ONCE === "1" ? true : undefined,
|
|
133
|
-
|
|
163
|
+
// Now that the default is ON (0778), the env var has to be able to say NO
|
|
164
|
+
// as well as yes — otherwise a machine could only opt out by editing a file.
|
|
165
|
+
acpTransport:
|
|
166
|
+
process.env.HILOS_ACP === "1" ? true : process.env.HILOS_ACP === "0" ? false : undefined,
|
|
167
|
+
// Both directions for the same reason acpTransport has both: a machine
|
|
168
|
+
// whose config file says yes must be able to say no from the environment.
|
|
169
|
+
uploadTranscripts:
|
|
170
|
+
process.env.HILOS_UPLOAD_TRANSCRIPTS === "1"
|
|
171
|
+
? true
|
|
172
|
+
: process.env.HILOS_UPLOAD_TRANSCRIPTS === "0"
|
|
173
|
+
? false
|
|
174
|
+
: undefined,
|
|
175
|
+
replyBridge:
|
|
176
|
+
/^(1|on|true)$/i.test(process.env.HILOS_REPLY_BRIDGE || "")
|
|
177
|
+
? true
|
|
178
|
+
: /^(0|off|false)$/i.test(process.env.HILOS_REPLY_BRIDGE || "")
|
|
179
|
+
? false
|
|
180
|
+
: undefined,
|
|
134
181
|
};
|
|
135
182
|
const merged = { ...DEFAULTS, ...file };
|
|
136
183
|
for (const [k, v] of Object.entries(env)) if (v !== undefined && v !== "") merged[k] = v;
|
|
@@ -163,6 +210,11 @@ export function resolveConfig({ flags = {}, join: joinPayload } = {}) {
|
|
|
163
210
|
const LIVE_FIELDS = [
|
|
164
211
|
"codingCmd",
|
|
165
212
|
"acpTransport",
|
|
213
|
+
// Consent must be revocable without a restart: edit the file, and the next
|
|
214
|
+
// run stops uploading. Listed here for the record — the actual live merge is
|
|
215
|
+
// special-cased below, because for this field a DELETED key has to mean no.
|
|
216
|
+
"uploadTranscripts",
|
|
217
|
+
"replyBridge",
|
|
166
218
|
"codingModel",
|
|
167
219
|
"chatCmd",
|
|
168
220
|
"codingEnv",
|
|
@@ -210,6 +262,30 @@ export function reloadConfig(prev) {
|
|
|
210
262
|
const changed = (k) => JSON.stringify(file[k]) !== JSON.stringify(snap[k]);
|
|
211
263
|
for (const k of LIVE_FIELDS) if (file[k] !== undefined && changed(k)) next[k] = file[k];
|
|
212
264
|
next.fileSnapshot = file;
|
|
265
|
+
// Consent is the one field where ABSENCE is an answer. Every other live field
|
|
266
|
+
// follows the 0576 rule — only a CHANGED key is applied, so a value that
|
|
267
|
+
// merely pre-existed can't claw back a launch flag — and under that rule
|
|
268
|
+
// DELETING `uploadTranscripts: true` did nothing at all: the key is gone, so
|
|
269
|
+
// `file[k] !== undefined` is false, so the old `true` survived forever. The
|
|
270
|
+
// one way to withdraw permission was to kill the daemon.
|
|
271
|
+
//
|
|
272
|
+
// So this field is recomputed from the file every reload: opted in only while
|
|
273
|
+
// the file still says so. Nothing is lost by the special case — no CLI flag
|
|
274
|
+
// sets it, so the file and the environment are its only sources, and the
|
|
275
|
+
// environment still wins below.
|
|
276
|
+
next.uploadTranscripts = file.uploadTranscripts === true;
|
|
277
|
+
// The reply bridge is safe-on only after the user has installed hooks. A
|
|
278
|
+
// live file edit may pause it with false; removing that edited key returns to
|
|
279
|
+
// the normal on state. An explicit launch flag remains pinned when the file
|
|
280
|
+
// was never changed, preserving the 0576 precedence rule above.
|
|
281
|
+
if (changed("replyBridge")) next.replyBridge = file.replyBridge !== false;
|
|
282
|
+
// The environment stays the operator's override on reload, in both
|
|
283
|
+
// directions — a machine that opted out with =0 must not be opted back in by
|
|
284
|
+
// a file edit (0792).
|
|
285
|
+
if (process.env.HILOS_UPLOAD_TRANSCRIPTS === "1") next.uploadTranscripts = true;
|
|
286
|
+
if (process.env.HILOS_UPLOAD_TRANSCRIPTS === "0") next.uploadTranscripts = false;
|
|
287
|
+
if (/^(1|on|true)$/i.test(process.env.HILOS_REPLY_BRIDGE || "")) next.replyBridge = true;
|
|
288
|
+
if (/^(0|off|false)$/i.test(process.env.HILOS_REPLY_BRIDGE || "")) next.replyBridge = false;
|
|
213
289
|
if (process.env.CODING_CMD) next.codingCmd = process.env.CODING_CMD;
|
|
214
290
|
if (process.env.HILOS_CODING_MODEL) next.codingModel = process.env.HILOS_CODING_MODEL;
|
|
215
291
|
if (process.env.HILOS_CHAT_CMD) next.chatCmd = process.env.HILOS_CHAT_CMD;
|