@chipschat/hermes 1.0.8 → 1.0.10
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 +5 -5
- package/dist/THIRD-PARTY-NOTICES.md +1 -1
- package/dist/main.js +100 -28
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -14,7 +14,7 @@ on Hermes's own API server.
|
|
|
14
14
|
its original's profile, in its original's folder: Hermes forks a session only within its
|
|
15
15
|
profile, so a copy has no profile of its own.
|
|
16
16
|
|
|
17
|
-
Apache-2.0
|
|
17
|
+
Apache-2.0, published on npm as `@chipschat/hermes`.
|
|
18
18
|
|
|
19
19
|
## What Chips shows
|
|
20
20
|
|
|
@@ -83,11 +83,11 @@ hasn't been tried through Chips yet.
|
|
|
83
83
|
|
|
84
84
|
## From Chips's gallery
|
|
85
85
|
|
|
86
|
-
The card's line is `chips connect hermes
|
|
86
|
+
The card's line is `CHIPS_JOIN_LINK='<link>' chips connect hermes` (Chips ADR 0218). It downloads this bridge as the npm package
|
|
87
87
|
`@chipschat/hermes`, the newest 1.x, checks it against the registry's checksum, and runs it on the Node
|
|
88
88
|
that Chips carries, so the machine needs no Node or npm of its own. The bridge checks Hermes,
|
|
89
89
|
joins, and keeps itself running from login. `chips disconnect hermes` stops it. On another computer,
|
|
90
|
-
`curl -fsSL https://chipschat.ai/install | sh -s -- connect hermes
|
|
90
|
+
`curl -fsSL https://chipschat.ai/install | CHIPS_JOIN_LINK='<link>' sh -s -- connect hermes` installs Chips there
|
|
91
91
|
first. The steps below run the bridge from this checkout instead, to work on it.
|
|
92
92
|
|
|
93
93
|
## Run it
|
|
@@ -103,11 +103,11 @@ first. The steps below run the bridge from this checkout instead, to work on it.
|
|
|
103
103
|
|
|
104
104
|
2. Once, in this repository: `npm install`.
|
|
105
105
|
|
|
106
|
-
3. Join Chips once, with a link from Chips's gallery (
|
|
106
|
+
3. Join Chips once, with a link from Chips's gallery (Agents → Connect a harness → Hermes), whose card gives
|
|
107
107
|
this line with the link in it:
|
|
108
108
|
|
|
109
109
|
```
|
|
110
|
-
cd
|
|
110
|
+
cd chips-hermes && CHIPS_JOIN_LINK='<link>' npm run keep
|
|
111
111
|
```
|
|
112
112
|
|
|
113
113
|
`npm run keep` joins, then keeps the bridge running from login (below); `npm start` is the
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Third-party notices
|
|
2
2
|
|
|
3
|
-
`dist/main.js` in @chipschat/hermes 1.0.
|
|
3
|
+
`dist/main.js` in @chipschat/hermes 1.0.10 carries these packages, bundled in. Each one's
|
|
4
4
|
licence follows.
|
|
5
5
|
|
|
6
6
|
## @chipschat/harness 0.0.0 (Apache-2.0)
|
package/dist/main.js
CHANGED
|
@@ -9,7 +9,7 @@ var __export = (target, all) => {
|
|
|
9
9
|
|
|
10
10
|
// src/main.ts
|
|
11
11
|
import { randomBytes as randomBytes3 } from "node:crypto";
|
|
12
|
-
import { existsSync as existsSync11, mkdirSync as mkdirSync6, readFileSync as
|
|
12
|
+
import { existsSync as existsSync11, mkdirSync as mkdirSync6, readFileSync as readFileSync12, writeFileSync as writeFileSync5 } from "node:fs";
|
|
13
13
|
import { createServer as createServer2 } from "node:net";
|
|
14
14
|
import { homedir as homedir8 } from "node:os";
|
|
15
15
|
import { dirname as dirname6, join as join13, resolve as resolve6 } from "node:path";
|
|
@@ -19945,8 +19945,9 @@ var policyRule = external_exports.object({
|
|
|
19945
19945
|
external: external_exports.boolean().optional(),
|
|
19946
19946
|
irreversible: external_exports.boolean().optional(),
|
|
19947
19947
|
money_usd_over: external_exports.number().nonnegative().optional(),
|
|
19948
|
-
risk: external_exports.array(riskClass).max(8).optional()
|
|
19949
|
-
|
|
19948
|
+
risk: external_exports.array(riskClass).max(8).optional(),
|
|
19949
|
+
starts_with: external_exports.array(external_exports.string().min(1).max(400)).min(1).max(8).optional().describe("For an action that carries a command (ADR 0239): the words a part of it starts with. A command goes ahead on such rules only when every part starts with one that allows it.")
|
|
19950
|
+
}).optional().describe("Extra conditions on the action's flags, and for a command, how its parts start."),
|
|
19950
19951
|
decision: external_exports.enum(["allow", "ask", "deny"]).describe("What to do when the rule matches."),
|
|
19951
19952
|
approvers: external_exports.array(approverRef).max(16).optional().describe("Who may answer, when the decision is `ask`."),
|
|
19952
19953
|
reason: external_exports.string().max(400).optional().describe("Shown to the harness, and recorded in the audit log."),
|
|
@@ -20465,9 +20466,17 @@ var roomIdle = external_exports.object({
|
|
|
20465
20466
|
var roomNote = external_exports.object({
|
|
20466
20467
|
members: external_exports.array(roomMember).max(500).describe("The room's people, then its agents, each by name, anybody removed left out."),
|
|
20467
20468
|
notes: external_exports.record(external_exports.string().max(120), external_exports.string().max(64e3)).describe("The note for each who takes the turn (`for`), by their id: who is here, with handles, and that only those @-mentioned act. A harness puts it at the top of the turn."),
|
|
20469
|
+
rules: external_exports.record(external_exports.string().max(120), external_exports.string().max(4e3)).optional().describe("How the space works, for each who takes the turn, by their id: the words its note ends with (ADR 0250), that everyone here reads what it writes and, beside other agents, what an @ does and when to answer NO_REPLY. They stay the same while the space's agents do, so a harness whose session keeps its earlier turns may say them once, and the note without them after."),
|
|
20468
20470
|
working: external_exports.array(roomWork).max(500).optional().describe("The room's agents with a turn going as Chips sends this one (ADR 0104), the takers' own included. A turn nothing has been heard from for ten minutes is not counted."),
|
|
20469
20471
|
idle: external_exports.array(roomIdle).max(500).optional().describe("The room's other agents that have had a turn here: how long since the last one ended (ADR 0104).")
|
|
20470
20472
|
});
|
|
20473
|
+
function noteWithoutRules(room, taker) {
|
|
20474
|
+
const note = room?.notes[taker];
|
|
20475
|
+
const rules = room?.rules?.[taker];
|
|
20476
|
+
if (note === void 0 || rules === void 0 || !note.endsWith(rules))
|
|
20477
|
+
return note;
|
|
20478
|
+
return note.slice(0, note.length - rules.length).trimEnd();
|
|
20479
|
+
}
|
|
20471
20480
|
var MONTHS = [
|
|
20472
20481
|
"January",
|
|
20473
20482
|
"February",
|
|
@@ -20487,8 +20496,8 @@ var MONTHS = [
|
|
|
20487
20496
|
var CONTEXT_CEILING = { lines: 200, chars: 32e3 };
|
|
20488
20497
|
var CONTEXT_HEADING = "Said in this space since you last spoke:";
|
|
20489
20498
|
var contextBudget = external_exports.object({
|
|
20490
|
-
lines: external_exports.int().nonnegative().optional().describe("The most lines to be handed,
|
|
20491
|
-
chars: external_exports.int().nonnegative().optional().describe("The most characters those lines may run to, as `Name: words` one per line,
|
|
20499
|
+
lines: external_exports.int().nonnegative().optional().describe("The most lines to be handed, 40 when absent. Chips hands over 200 at most, and none when this is 0."),
|
|
20500
|
+
chars: external_exports.int().nonnegative().optional().describe("The most characters those lines may run to, as `Name: words` one per line, 16,000 when absent. Chips hands over 32,000 at most.")
|
|
20492
20501
|
}).describe("How much of the room a harness is handed with a message for it (ADR 0088). Its own to say: a budget promises nothing to anybody else.");
|
|
20493
20502
|
var contextLine = external_exports.object({
|
|
20494
20503
|
seq: external_exports.int().positive().describe("Where in the log it happened."),
|
|
@@ -20868,7 +20877,7 @@ var messageNew = defineEvent({
|
|
|
20868
20877
|
summary: "Someone said something, with any attachments as signed URLs the harness can fetch.",
|
|
20869
20878
|
requiresRun: false,
|
|
20870
20879
|
payload: deliveredMessage.extend({
|
|
20871
|
-
context: roomContext.optional().describe("What was said in the room since this harness last spoke there, or since it joined when it has not, up to this message and without it (ADR 0088). From when the turn that said its last words began, so what was said while it worked is here, and its own words are not (ADR 0105). Worked out from the log, so a replay hands over the same lines. As many as the budget the harness gave in its `hello`:
|
|
20880
|
+
context: roomContext.optional().describe("What was said in the room since this harness last spoke there, or since it joined when it has not, up to this message and without it (ADR 0088). From when the turn that said its last words began, so what was said while it worked is here, and its own words are not (ADR 0105). Worked out from the log, so a replay hands over the same lines. As many as the budget the harness gave in its `hello`: 40 lines and 16,000 characters when it gave none, and none when it asked for 0. When older lines were left out, the taker's room note says so."),
|
|
20872
20881
|
room: roomNote.optional().describe("Who is in the room, with the handle that reaches each, and a note for each who takes the turn saying so and what an @ does (ADR 0092). A harness puts `notes[<taker>]` at the top of that turn. Absent on a message in no room."),
|
|
20873
20882
|
exchange: deliveredExchange.optional().describe("How the agents' talk in the room stands, once it is worth a word (ADR 0097): from eight messages between agents since a person last acted or an agent last made something new. A harness puts `note` at the top of the turn, as Chips's, ahead of the room's note. Absent below that, and worked out from the log, so a replay hands over the same facts."),
|
|
20874
20883
|
handed: external_exports.literal(true).optional().describe("Chips held this message when it was said and hands it over now a person has acted (ADR 0097): the newest of an agent's held messages, once; or, with `lead`, hands it to the room's lead. Its seq and id are the hand-over's, its `message_id` the message's own."),
|
|
@@ -20918,6 +20927,7 @@ var approvalResolved = defineEvent({
|
|
|
20918
20927
|
approval_id: id("approval"),
|
|
20919
20928
|
decision: external_exports.enum(["approved", "edited", "denied", "expired"]).describe("`expired` means nobody answered and the fallback applied."),
|
|
20920
20929
|
scope: external_exports.enum(["once", "session", "always"]).default("once").describe("How far the answer reaches. `always` becomes a policy rule."),
|
|
20930
|
+
everywhere: external_exports.boolean().optional().describe("With `always`: the rule is the harness's in every space, not only this one (ADR 0239). An owner or an admin only."),
|
|
20921
20931
|
updated_input: external_exports.unknown().optional().describe("The edited action input, when the decision is `edited`."),
|
|
20922
20932
|
reason: external_exports.string().max(4e3).optional().describe("Why. The harness gets to read this."),
|
|
20923
20933
|
resolved_by: external_exports.string().min(1).max(120).describe("The participant who answered, or `system` on expiry \u2014 a harness when it settles its own ask, answered in its own tools. Filled in by Chips from the credential that sent it; a value the sender writes is replaced."),
|
|
@@ -21182,6 +21192,10 @@ function namesInWords(names) {
|
|
|
21182
21192
|
return `${names.slice(0, -1).join(", ")} and ${names[names.length - 1]}`;
|
|
21183
21193
|
}
|
|
21184
21194
|
function renderProjectNote(facts, options) {
|
|
21195
|
+
return `${renderProjectFacts(facts)}
|
|
21196
|
+
${renderProjectAsks(facts, options)}`;
|
|
21197
|
+
}
|
|
21198
|
+
function renderProjectFacts(facts) {
|
|
21185
21199
|
const files = `${facts.files} file${facts.files === 1 ? "" : "s"}`;
|
|
21186
21200
|
const lines2 = [
|
|
21187
21201
|
`The space's project is a git repository. Your copy is ${facts.folder} (${files}), ${facts.trouble === void 0 ? "brought up to date just now" : "not brought up to date"}.`
|
|
@@ -21199,9 +21213,9 @@ function renderProjectNote(facts, options) {
|
|
|
21199
21213
|
for (const key of facts.keys) {
|
|
21200
21214
|
lines2.push(`${key.path} holds what looks like ${key.what}, so your last change wasn't sent: take it out and read it from outside the project.`);
|
|
21201
21215
|
}
|
|
21202
|
-
return
|
|
21216
|
+
return lines2.join("\n");
|
|
21203
21217
|
}
|
|
21204
|
-
function
|
|
21218
|
+
function renderProjectAsks(facts, options) {
|
|
21205
21219
|
const lines2 = [
|
|
21206
21220
|
"Work on the project in that folder and leave git to Chips: when your turn ends, what you changed is committed under your name and sent to everyone here. Keep scratch work outside it.",
|
|
21207
21221
|
// Sent with the answer too, a project's file became a room file of its own, with versions of
|
|
@@ -21222,7 +21236,7 @@ function asks(facts, options) {
|
|
|
21222
21236
|
if (facts.pages === true) {
|
|
21223
21237
|
lines2.push("A page opens in Chips as one document: name every file it needs in its tags and imports (<link>, <script src>, <img src>, import), since it can't fetch files while it runs.");
|
|
21224
21238
|
}
|
|
21225
|
-
return lines2;
|
|
21239
|
+
return lines2.join("\n");
|
|
21226
21240
|
}
|
|
21227
21241
|
|
|
21228
21242
|
// node_modules/@chipschat/protocol/dist/src/events/harness-to-chips.js
|
|
@@ -21874,7 +21888,7 @@ var membershipRemoved = defineEvent({
|
|
|
21874
21888
|
payload: external_exports.object({
|
|
21875
21889
|
participant_id: external_exports.string().min(1).max(120).describe("Who left."),
|
|
21876
21890
|
removed_by: external_exports.string().min(1).max(120).optional().describe("Who removed them, if not themselves."),
|
|
21877
|
-
reason: external_exports.enum([...RELEASE_REASONS, "person_removed"]).optional().describe("For an agent (ADR 0087): why it left, as `agent.released` says. For a person, `person_removed`: they were removed from the workspace (ADR 0160). Written by Chips; absent, a person took them out or they left."),
|
|
21891
|
+
reason: external_exports.enum([...RELEASE_REASONS, "person_removed", "person_left"]).optional().describe("For an agent (ADR 0087): why it left, as `agent.released` says. For a person, `person_removed`: they were removed from the workspace (ADR 0160); `person_left`: they deleted their account and left it (ADR 0243). Written by Chips; absent, a person took them out or they left the room."),
|
|
21878
21892
|
moved_to: id("space").optional().describe("For an agent moved away: the room it went to, so this room can say so.")
|
|
21879
21893
|
})
|
|
21880
21894
|
});
|
|
@@ -22183,14 +22197,14 @@ var personRemoved = defineEvent({
|
|
|
22183
22197
|
type: "person.removed",
|
|
22184
22198
|
direction: "workspace",
|
|
22185
22199
|
sender: "chips",
|
|
22186
|
-
summary: "A person was removed from the workspace: signed out everywhere, out of every room, and the harnesses they owned handed
|
|
22200
|
+
summary: "A person was removed from the workspace, or deleted their account: signed out everywhere, out of every room, and the harnesses they owned handed on. What they said stays, under their name.",
|
|
22187
22201
|
requiresRun: false,
|
|
22188
22202
|
payload: external_exports.object({
|
|
22189
22203
|
participant_id: id("person").describe("Who was removed."),
|
|
22190
22204
|
display_name: external_exports.string().min(1).max(120).describe("What they were called when they were removed, so the audit needs no lookup."),
|
|
22191
|
-
removed_by: id("person").describe("The owner or admin who removed them."),
|
|
22205
|
+
removed_by: id("person").describe("The owner or admin who removed them, or they themselves when they deleted their account (ADR 0243)."),
|
|
22192
22206
|
spaces: external_exports.array(id("space")).max(1e3).optional().describe("The rooms they were taken out of, each with its own `membership.removed`."),
|
|
22193
|
-
harnesses: external_exports.array(id("harness")).max(1e3).optional().describe("The harnesses they owned, handed to `removed_by
|
|
22207
|
+
harnesses: external_exports.array(id("harness")).max(1e3).optional().describe("The harnesses they owned, each handed on by `harness.transferred`: to `removed_by`, or, for an account deleted, to an owner.")
|
|
22194
22208
|
})
|
|
22195
22209
|
});
|
|
22196
22210
|
var joinWho = {
|
|
@@ -22536,7 +22550,7 @@ var clientHelloFrame = external_exports.object({
|
|
|
22536
22550
|
})).max(64).optional().describe("Not read by Chips: a connection is its token's, and the server's `hello` names the token's harness and its agents (ADR 0087). Absent for a person's client."),
|
|
22537
22551
|
since: external_exports.int().nonnegative().optional().describe("Not read by Chips: a stream resumes from `subscribe`'s `since`."),
|
|
22538
22552
|
accepts: external_exports.array(external_exports.string().min(1).max(40)).max(32).optional().describe("Server frames beyond the base set this client understands, by the names in `SERVER_EXTENSIONS`. A name the server does not know is ignored rather than refused, so a client may name a frame a newer server sends and still be answered by an older one (ADR 0211, Phase 3). A client that says `events` is sent its replay in pages rather than one frame per event; one that says `presence` is sent an agent's state as it changes (ADR 0083); a harness's socket that says `restart` is sent `restart` when a person asks it to restart (ADR 0094); an owner's or admin's that says `join` is sent each join request as it changes (ADR 0122); a harness's that says `context` is sent `context.edit` when a person changes one of its context files (ADR 0134); a harness's that says `models` is sent `model.change` when a person changes an agent's model or effort (ADR 0140); a harness's that says `heartbeats` is sent `heartbeat.change` when a person switches an agent's heartbeat or changes how often it beats (ADR 0143); a harness's that says `context_windows` is sent `context_window.compact` and `context_window.change` when a person asks an agent to compact now or changes the limit it compacts itself at (ADR 0146); a person's that says `folders` is sent `folder.open` when they ask, from another of their devices, for a room's folder to be opened in Finder (ADR 0225), and `folder.run` when they ask for its project to be run or stopped there (ADR 0226); a person's that says `folder_runs` is sent `folder.run_state` when their Mac says how a run of theirs stands (ADR 0226); one that says nothing is sent what it was always sent, since an unknown frame is dropped in silence."),
|
|
22539
|
-
context: contextBudget.optional().describe("How much of a room a harness is handed with each message for it (ADR 0088):
|
|
22553
|
+
context: contextBudget.optional().describe("How much of a room a harness is handed with each message for it (ADR 0088): 40 lines and 16,000 characters when absent, 200 and 32,000 at most. For this connection. A person's client is handed none.")
|
|
22540
22554
|
}).describe("The first frame a client sends.");
|
|
22541
22555
|
var subscribeFrame = external_exports.object({
|
|
22542
22556
|
frame: external_exports.literal("subscribe"),
|
|
@@ -25098,8 +25112,19 @@ async function redeem(url2, secret, options, send, machine) {
|
|
|
25098
25112
|
throw await refused(answered);
|
|
25099
25113
|
return await answered.json();
|
|
25100
25114
|
}
|
|
25115
|
+
function reaching(send, url2) {
|
|
25116
|
+
return async (input2, init) => {
|
|
25117
|
+
try {
|
|
25118
|
+
return await send(input2, init);
|
|
25119
|
+
} catch (error62) {
|
|
25120
|
+
if (error62 instanceof Error && error62.name === "AbortError")
|
|
25121
|
+
throw error62;
|
|
25122
|
+
throw new JoinError("unreachable", `Can't reach Chips at ${url2} from this computer. It has to be on the same network as Chips, on its tailnet, or Chips has to be at an address this computer can reach.`);
|
|
25123
|
+
}
|
|
25124
|
+
};
|
|
25125
|
+
}
|
|
25101
25126
|
function askOrRedeem(server, options) {
|
|
25102
|
-
const send = options.fetch ?? fetch;
|
|
25127
|
+
const send = reaching(options.fetch ?? fetch, server.url);
|
|
25103
25128
|
const machine = options.machine ?? hostname3();
|
|
25104
25129
|
return server.secret === void 0 ? ask(server.url, options, send, machine) : redeem(server.url, server.secret, options, send, machine);
|
|
25105
25130
|
}
|
|
@@ -25265,14 +25290,31 @@ async function sendAnswer(answer, options) {
|
|
|
25265
25290
|
}
|
|
25266
25291
|
|
|
25267
25292
|
// node_modules/@chipschat/harness/dist/prompt.js
|
|
25293
|
+
function takerOf(message, options) {
|
|
25294
|
+
return options.taker ?? (message.for?.length === 1 ? message.for[0] : void 0);
|
|
25295
|
+
}
|
|
25296
|
+
function othersBeside(message, taker) {
|
|
25297
|
+
return (message.room?.members ?? []).some((member) => member.kind === "agent" && member.participant_id !== taker);
|
|
25298
|
+
}
|
|
25299
|
+
function rulesFor(message, options = {}) {
|
|
25300
|
+
const taker = takerOf(message, options);
|
|
25301
|
+
const { project } = options;
|
|
25302
|
+
const rules = message.room?.rules ?? {};
|
|
25303
|
+
return [
|
|
25304
|
+
taker === void 0 ? void 0 : rules[taker],
|
|
25305
|
+
project === void 0 ? void 0 : renderProjectAsks(project, { othersInRoom: othersBeside(message, taker) }),
|
|
25306
|
+
options.sendsFiles === true ? sendingFiles({ project: project !== void 0 }) : void 0
|
|
25307
|
+
].filter((part) => part !== void 0 && part !== "").join("\n\n");
|
|
25308
|
+
}
|
|
25268
25309
|
function promptFor(message, options = {}) {
|
|
25269
|
-
const taker =
|
|
25310
|
+
const taker = takerOf(message, options);
|
|
25311
|
+
const held = options.rulesHeld === true;
|
|
25270
25312
|
const notes = message.room?.notes ?? {};
|
|
25271
|
-
const note = taker === void 0 ? void 0 : notes[taker];
|
|
25313
|
+
const note = taker === void 0 ? void 0 : held ? noteWithoutRules(message.room, taker) : notes[taker];
|
|
25272
25314
|
const who = options.sayWho === false ? "" : `${withRole(message.from.display_name, message.from)}: `;
|
|
25273
25315
|
const files = (message.attachments ?? []).map(renderAttachment);
|
|
25274
25316
|
const words4 = [`${who}${message.text}`, ...files].join("\n");
|
|
25275
|
-
const sending = options.sendsFiles === true ? sendingFiles({ project: options.project !== void 0 }) : void 0;
|
|
25317
|
+
const sending = options.sendsFiles === true && !held ? sendingFiles({ project: options.project !== void 0 }) : void 0;
|
|
25276
25318
|
const replying = renderReplyingTo(message.replying_to, {
|
|
25277
25319
|
sender: {
|
|
25278
25320
|
id: message.from.participant_id,
|
|
@@ -25284,8 +25326,7 @@ function promptFor(message, options = {}) {
|
|
|
25284
25326
|
at: message.ts,
|
|
25285
25327
|
zone: options.zone
|
|
25286
25328
|
});
|
|
25287
|
-
const
|
|
25288
|
-
const project = options.project === void 0 ? void 0 : renderProjectNote(options.project, { othersInRoom: others });
|
|
25329
|
+
const project = options.project === void 0 ? void 0 : held ? renderProjectFacts(options.project) : renderProjectNote(options.project, { othersInRoom: othersBeside(message, taker) });
|
|
25289
25330
|
return [
|
|
25290
25331
|
message.exchange?.note,
|
|
25291
25332
|
note,
|
|
@@ -25472,7 +25513,10 @@ function nodeOnPath(env = process.env) {
|
|
|
25472
25513
|
}
|
|
25473
25514
|
var pause = (ms) => Atomics.wait(new Int32Array(new SharedArrayBuffer(4)), 0, 0, ms);
|
|
25474
25515
|
var LOAD_TRIES = 40;
|
|
25475
|
-
var runOf = (options) => options.run ?? ((command) =>
|
|
25516
|
+
var runOf = (options) => options.run ?? ((command) => execFileSync2(command[0], command.slice(1), {
|
|
25517
|
+
encoding: "utf8",
|
|
25518
|
+
stdio: ["ignore", "pipe", "ignore"]
|
|
25519
|
+
}));
|
|
25476
25520
|
var ours = (path) => !existsSync3(path) || readFileSync3(path, "utf8").includes(MARK);
|
|
25477
25521
|
function runOne(command, run2, retryMs) {
|
|
25478
25522
|
const tries = command[0] === "launchctl" && command[1] === "bootstrap" ? LOAD_TRIES : 1;
|
|
@@ -25495,6 +25539,24 @@ function runAll(commands, options) {
|
|
|
25495
25539
|
runOne(command, run2, options.retryMs ?? 250);
|
|
25496
25540
|
}
|
|
25497
25541
|
var uidOf = (options) => options.uid ?? process.getuid?.() ?? 0;
|
|
25542
|
+
function lingers(options) {
|
|
25543
|
+
const run2 = runOf(options);
|
|
25544
|
+
const uid = String(uidOf(options));
|
|
25545
|
+
try {
|
|
25546
|
+
const on = run2(["loginctl", "show-user", uid, "--property=Linger", "--value"]);
|
|
25547
|
+
if (typeof on === "string" && on.trim() === "yes")
|
|
25548
|
+
return true;
|
|
25549
|
+
} catch {
|
|
25550
|
+
}
|
|
25551
|
+
try {
|
|
25552
|
+
run2(["loginctl", "enable-linger", uid]);
|
|
25553
|
+
return true;
|
|
25554
|
+
} catch {
|
|
25555
|
+
return false;
|
|
25556
|
+
}
|
|
25557
|
+
}
|
|
25558
|
+
var sayOf = (options) => options.say ?? ((line2) => void process.stderr.write(`${line2}
|
|
25559
|
+
`));
|
|
25498
25560
|
function keepRunning(spec, options = {}) {
|
|
25499
25561
|
if (machineOf(options.machine).env["CHIPS_KEEP"] === "off")
|
|
25500
25562
|
return { state: "off" };
|
|
@@ -25509,6 +25571,9 @@ function keepRunning(spec, options = {}) {
|
|
|
25509
25571
|
writeFileSync2(file3.path, file3.contents, { mode: 384 });
|
|
25510
25572
|
chmodSync2(file3.path, 384);
|
|
25511
25573
|
runAll(startCommands(file3.kind, spec.label, file3.path, uidOf(options)), options);
|
|
25574
|
+
if (file3.kind === "systemd" && !lingers(options)) {
|
|
25575
|
+
sayOf(options)("It stops when you log out. To keep it running on a machine nobody logs in to, run this once: sudo loginctl enable-linger $USER");
|
|
25576
|
+
}
|
|
25512
25577
|
return { state: "kept", path: file3.path, logFile: file3.logFile };
|
|
25513
25578
|
}
|
|
25514
25579
|
function stopKeeping(label2, options = {}) {
|
|
@@ -27340,9 +27405,11 @@ function filesHere(project = false) {
|
|
|
27340
27405
|
return `${sendingFiles({ project })} Hermes's note that this API server sends only pictures, and shows a MEDIA: tag on the runs endpoint as text, does not hold for these runs: they come from Chips, whose bridge takes each MEDIA: line out of your answer and attaches that file to your message, whatever its type, up to 100 MB.`;
|
|
27341
27406
|
}
|
|
27342
27407
|
var FILES_HERE = filesHere();
|
|
27343
|
-
|
|
27408
|
+
var MARKDOWN_HERE = "Hermes's note that this API server's replies are plain text does not hold for these runs either: Chips shows your answer as Markdown, so use headings, lists, bold, tables and code blocks where they help a reader.";
|
|
27409
|
+
function instructionsFor(folder2, project = false, rules = "") {
|
|
27344
27410
|
const files = filesHere(project);
|
|
27345
|
-
|
|
27411
|
+
const here2 = folder2 === void 0 ? files : `${files} Your own folder is ${folder2}: make and keep your files there, and run your commands from there.`;
|
|
27412
|
+
return [here2, MARKDOWN_HERE, rules].filter((part) => part !== "").join("\n\n");
|
|
27346
27413
|
}
|
|
27347
27414
|
function freeFolder(root2, name2, taken) {
|
|
27348
27415
|
const slug = name2.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "") || "agent";
|
|
@@ -28091,7 +28158,8 @@ ${hook.lines}`);
|
|
|
28091
28158
|
const name2 = speakerId === void 0 ? agent.config.name : await this.nameOf(speakerId, agent.config.name);
|
|
28092
28159
|
turn.folder = this.folderOf(agent, speakerId ?? agent.agentId, name2);
|
|
28093
28160
|
const project = await this.projectFor(turn, room.spaceId, speakerId ?? agent.agentId, name2);
|
|
28094
|
-
|
|
28161
|
+
turn.rules = rulesFor(message, { taker: speakerId, project });
|
|
28162
|
+
let text = promptFor(message, { taker: speakerId, sayWho, project, rulesHeld: true });
|
|
28095
28163
|
for (let round = 0; text !== void 0 && !turn.cancelled && !run2.over; round += 1) {
|
|
28096
28164
|
const last = await this.once(turn, session, text, `${run2.id}:${round}`);
|
|
28097
28165
|
if (last === void 0) return;
|
|
@@ -28117,7 +28185,7 @@ ${hook.lines}`);
|
|
|
28117
28185
|
sessionId: session,
|
|
28118
28186
|
...this.runModel(turn),
|
|
28119
28187
|
key,
|
|
28120
|
-
instructions: instructionsFor(turn.folder, turn.project !== void 0)
|
|
28188
|
+
instructions: instructionsFor(turn.folder, turn.project !== void 0, turn.rules)
|
|
28121
28189
|
});
|
|
28122
28190
|
} catch (error62) {
|
|
28123
28191
|
await this.failed(turn, `${agent.config.name} couldn't start in Hermes: ${messageOf3(error62)}`, true);
|
|
@@ -28672,6 +28740,10 @@ async function checkHermes(config3, clientFor = (agent) => new HermesClient(agen
|
|
|
28672
28740
|
}
|
|
28673
28741
|
}
|
|
28674
28742
|
|
|
28743
|
+
// src/version.ts
|
|
28744
|
+
import { readFileSync as readFileSync11 } from "node:fs";
|
|
28745
|
+
var VERSION = JSON.parse(readFileSync11(new URL("../package.json", import.meta.url), "utf8")).version;
|
|
28746
|
+
|
|
28675
28747
|
// src/main.ts
|
|
28676
28748
|
var home = (path) => path.startsWith("~/") ? join13(homedir8(), path.slice(2)) : path;
|
|
28677
28749
|
var link = process.env["CHIPS_JOIN_LINK"] || void 0;
|
|
@@ -28680,7 +28752,7 @@ stopIfAsked(LABEL);
|
|
|
28680
28752
|
var configPath = resolve6(home(words3[0] ?? "~/.chips-hermes/config.json"));
|
|
28681
28753
|
var folder = dirname6(configPath);
|
|
28682
28754
|
var statePath = join13(folder, "sessions.json");
|
|
28683
|
-
var state = existsSync11(statePath) ? JSON.parse(
|
|
28755
|
+
var state = existsSync11(statePath) ? JSON.parse(readFileSync12(statePath, "utf8")) : { sessions: {} };
|
|
28684
28756
|
var saveState = (next) => {
|
|
28685
28757
|
mkdirSync6(folder, { recursive: true, mode: 448 });
|
|
28686
28758
|
writeFileSync5(statePath, `${JSON.stringify(next, null, 2)}
|
|
@@ -28741,7 +28813,7 @@ var joined = await join3({
|
|
|
28741
28813
|
link,
|
|
28742
28814
|
url: process.env["CHIPS_URL"],
|
|
28743
28815
|
name,
|
|
28744
|
-
software:
|
|
28816
|
+
software: `chips-hermes ${VERSION}`,
|
|
28745
28817
|
wants: WANTS,
|
|
28746
28818
|
onCode: (code) => log(`Allow this harness in Chips: ${code}`)
|
|
28747
28819
|
}).catch(refused2);
|
|
@@ -28759,7 +28831,7 @@ var restart = restarter({
|
|
|
28759
28831
|
var chips = await connect({
|
|
28760
28832
|
url: joined.url,
|
|
28761
28833
|
token: joined.token,
|
|
28762
|
-
client: { name: "chips-hermes", version:
|
|
28834
|
+
client: { name: "chips-hermes", version: VERSION },
|
|
28763
28835
|
store: fileStore(join13(folder, "chips-state.json")),
|
|
28764
28836
|
onRestart: restart,
|
|
28765
28837
|
settings: settingsFor(() => bridge)
|
package/package.json
CHANGED