@agentshouse/kit 0.1.0-alpha.16 → 0.1.0-alpha.18
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 +69 -17
- package/bin/connect-linux.sh +14 -4
- package/bootstrap.json +3 -3
- package/package.json +2 -1
- package/src/adapter-mcp.js +0 -13
- package/src/bridge.js +1 -1
- package/src/contract.js +10 -2
- package/src/house-main.js +65 -8
- package/src/house.js +98 -86
- package/src/inbound.js +2 -18
- package/src/launcher.js +2 -3
- package/src/local-files.js +3 -11
- package/src/mcp.js +13 -0
- package/src/sync-library.js +7 -11
- package/src/sync.js +1 -1
- package/src/worker.js +81 -15
- package/src/working-copy.js +516 -47
package/README.md
CHANGED
|
@@ -10,7 +10,7 @@ On Linux `amd64` or `arm64` with a working Docker Engine, run the published,
|
|
|
10
10
|
versioned bootstrap once:
|
|
11
11
|
|
|
12
12
|
```sh
|
|
13
|
-
bash <(curl -fsSL https://github.com/agentshouse/kit/releases/download/v0.1.0-alpha.
|
|
13
|
+
bash <(curl -fsSL https://github.com/agentshouse/kit/releases/download/v0.1.0-alpha.18/connect-linux.sh)
|
|
14
14
|
```
|
|
15
15
|
|
|
16
16
|
The release asset pins one immutable multi-architecture image digest. It creates
|
|
@@ -105,6 +105,14 @@ Forwarding installs no host-native Kit and gives the container no Docker socket
|
|
|
105
105
|
or further mount; it refuses when no Kit is installed or the installed one
|
|
106
106
|
differs from this bootstrap's.
|
|
107
107
|
|
|
108
|
+
The owner's working copy push is forwarded the same way: run
|
|
109
|
+
`bash <(curl -fsSL …/connect-linux.sh) house git push [commit] --owner` from a
|
|
110
|
+
directory beneath the workspace root, such as a Room copy under
|
|
111
|
+
`working-copies/rooms/`. The bootstrap runs the container's `house` in the
|
|
112
|
+
matching directory beneath `/agents/house`, through the resident's lease when
|
|
113
|
+
the container runs, and refuses a directory outside the workspace before
|
|
114
|
+
anything reaches House.
|
|
115
|
+
|
|
108
116
|
## Building the package
|
|
109
117
|
|
|
110
118
|
The repository checkout is the development source. Build the package
|
|
@@ -760,11 +768,13 @@ prompt's stop reason through the contract's own table to one of four turn
|
|
|
760
768
|
outcomes: completed, interrupted, refused by the provider, or exhausted. A stop
|
|
761
769
|
reason the contract does not name, including a vendor-specific one a different
|
|
762
770
|
contract names, fails the turn as `kit_adapter_contract_mismatch` rather than
|
|
763
|
-
being guessed.
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
771
|
+
being guessed. After committing the Run, and again on every resumption, the
|
|
772
|
+
Kit reads what the Session was started for from House's
|
|
773
|
+
`/kit/runs/<run>/request` with the Session credential: the Routine Request with
|
|
774
|
+
its input, references, requester and the pinned revision's instruction, or the
|
|
775
|
+
sealed conversation turn. It sends that as the first prompt block, followed by
|
|
776
|
+
current House guidance fetched through the Run connection, so the Agent calls
|
|
777
|
+
nothing to learn it. An unreadable request or guidance refuses the turn. It forwards only adapter-classified User-visible assistant
|
|
768
778
|
text back over the local channel, and leaves reasoning, tool traces, and
|
|
769
779
|
terminal output where they are. The supervised process's own House calls travel
|
|
770
780
|
that same channel through the `house` CLI. The Kit holds the WorkerRunToken, replaces it in place when
|
|
@@ -827,7 +837,9 @@ nonzero exit status. The CLI holds
|
|
|
827
837
|
no credential: it calls over its Session's bridge, which attaches the Session
|
|
828
838
|
credential and refuses a caller without that Session's nonce as
|
|
829
839
|
`kit_bridge_unauthorized`. House network calls use only the selected
|
|
830
|
-
`2026-07-28` profile.
|
|
840
|
+
`2026-07-28` profile. `house git push` is the one local verb House does not list;
|
|
841
|
+
[working copies](#working-copies) describe it, and `house --help` and
|
|
842
|
+
`house git push --help` explain it.
|
|
831
843
|
|
|
832
844
|
Two verbs name files on the Session's own computer: `upload_attachment` takes
|
|
833
845
|
one `path`, and `append_record` takes `attachments` as local paths. The CLI
|
|
@@ -910,8 +922,8 @@ receiving a complete byte stream, validating any reported size, and writing the
|
|
|
910
922
|
file. A lost acknowledgement preserves the completed local file for House's
|
|
911
923
|
idempotent admission and later cleanup. Failed files remain pending; House's
|
|
912
924
|
all-files-ready gate keeps their turn unprocessed.
|
|
913
|
-
The provider receives absolute local paths beside the owning messages
|
|
914
|
-
|
|
925
|
+
The provider receives absolute local paths beside the owning messages in its
|
|
926
|
+
first prompt. The cache persists across
|
|
915
927
|
turns; only House-authorized terminal Run cleanup removes its Run directory.
|
|
916
928
|
|
|
917
929
|
The accepted attachment's retained original is separate from that cache. The Kit
|
|
@@ -936,8 +948,8 @@ outcome it handled, and exits non-zero while any of them is unsaved.
|
|
|
936
948
|
One `kit worker run` then takes one House-authorized resumption, or otherwise
|
|
937
949
|
acquires one waiting Run, and supervises exactly that WorkerSession. A resumed
|
|
938
950
|
conversation loads its retained native provider session through ACP
|
|
939
|
-
`session/load`, receives the current input
|
|
940
|
-
|
|
951
|
+
`session/load`, receives the current input House answers for the Run in its
|
|
952
|
+
first prompt, and executes one turn. Historical output replayed during
|
|
941
953
|
loading is not emitted as new assistant output. Missing or rejected provider
|
|
942
954
|
continuation never starts a replacement provider conversation in the same Run.
|
|
943
955
|
|
|
@@ -1246,14 +1258,54 @@ current grant. Every other file is read-only House content: the generated
|
|
|
1246
1258
|
grants anything, and House refuses a change to a read-only path however it is
|
|
1247
1259
|
committed.
|
|
1248
1260
|
|
|
1249
|
-
Local edits, staging and commits change nothing in House
|
|
1250
|
-
records the House content last received
|
|
1251
|
-
|
|
1252
|
-
|
|
1253
|
-
|
|
1261
|
+
Local edits, staging and commits change nothing in House until a commit is
|
|
1262
|
+
pushed. `refs/house/received` records the House content last received; each
|
|
1263
|
+
commit Kit wrote there, and each commit it acknowledged for a push, is a House
|
|
1264
|
+
state. The House revision of every file content Kit received, keyed by path and
|
|
1265
|
+
Git blob, stays in Kit home under `state/working-copies/`, outside the
|
|
1266
|
+
repository. A local commit is a local tree, never a House revision.
|
|
1267
|
+
|
|
1268
|
+
`house git push [commit]`, run anywhere inside a copy or one of its linked
|
|
1269
|
+
worktrees, submits one commit, `HEAD` by default, resolved once. Kit compares
|
|
1270
|
+
that commit's tree with the newest House state in its history, so every linked
|
|
1271
|
+
worktree keeps its own base, and sends the difference as one ordinary House edit:
|
|
1272
|
+
a changed field, section or preamble against its own prior value, any other
|
|
1273
|
+
change as the whole file against its exact revision, a new file as a create and
|
|
1274
|
+
a committed deletion as a removal. Staged and unstaged work, and files absent
|
|
1275
|
+
only from the working tree, are never sent. Native `git push` reaches no House
|
|
1276
|
+
remote. Inside an Agent Session the push goes through that Session's bridge,
|
|
1277
|
+
under its own authority and provenance; outside one it needs
|
|
1278
|
+
`house git push [commit] --owner`, which the resident Kit carries out under its
|
|
1279
|
+
control lease when a resident runs, and which otherwise acquires and releases
|
|
1280
|
+
its own. A Session refuses `--owner`, and a missing bridge is never replaced by
|
|
1281
|
+
owner authority.
|
|
1282
|
+
|
|
1283
|
+
House decides before any local Git step. A refusal changes nothing in House;
|
|
1284
|
+
after `edit_conflict` Kit records the current content House names for the
|
|
1285
|
+
refused paths in `refs/house/received`, reading by revision any content the
|
|
1286
|
+
refusal does not carry, so the agent merges or rebases onto it with native Git,
|
|
1287
|
+
commits, and pushes again. After acceptance Kit records House's result for the
|
|
1288
|
+
pushed paths, the contents an owner push receives or each accepted revision
|
|
1289
|
+
read by name, in a commit that covers the pushed one and in
|
|
1290
|
+
`refs/house/received`; a read-only path House regenerates, such as the Wiki
|
|
1291
|
+
index, stays out of Git. Kit then
|
|
1292
|
+
fast-forwards a clean branch still at the pushed commit, or rebases only its
|
|
1293
|
+
later commits. A result not yet readable, uncommitted tracked changes,
|
|
1294
|
+
a moved branch or a rebase conflict leave the branch as it was, with no stash or
|
|
1295
|
+
reset, and the push answers that House accepted it while local integration is
|
|
1296
|
+
pending; the next `house git push` finishes that integration without another
|
|
1297
|
+
House edit. A push whose answer was lost is recorded in Kit home before it is
|
|
1298
|
+
sent, and the next push by the same Session, or by the owner for an owner push,
|
|
1299
|
+
resends it under its original operation. Another caller cannot
|
|
1300
|
+
recover it: while the pushing Session lives it is refused as
|
|
1301
|
+
`kit_working_copy_push_pending`, and once that Session has ended Kit reads House
|
|
1302
|
+
again and drops it. When a retained push's operation has expired, Kit reads the
|
|
1303
|
+
Room again: if House holds the pushed content the push finishes as accepted,
|
|
1304
|
+
otherwise it is dropped and the next push submits it as a new operation.
|
|
1254
1305
|
|
|
1255
1306
|
Deselecting a Room, or losing read access to it, marks its copy inactive:
|
|
1256
|
-
launches omit it
|
|
1307
|
+
launches omit it, a new push is refused as `kit_working_copy_inactive`, and
|
|
1308
|
+
nothing local is deleted; a push already sent still settles and integrates. Selecting it again reads the Room
|
|
1257
1309
|
again, advances `refs/house/received`, and replaces only the read-only content
|
|
1258
1310
|
Kit wrote, never the branch, the index or a tracked file. A Room the owner may
|
|
1259
1311
|
read without sync is refused as `operation_denied` and stays uncopied, while its
|
package/bin/connect-linux.sh
CHANGED
|
@@ -9,6 +9,7 @@ MANUAL=0
|
|
|
9
9
|
WORKSPACE_SELECTED=0
|
|
10
10
|
HOUSE_SELECTED=0
|
|
11
11
|
FORWARDING=0
|
|
12
|
+
FORWARDED=kit
|
|
12
13
|
FORWARD=()
|
|
13
14
|
|
|
14
15
|
refuse() {
|
|
@@ -41,8 +42,9 @@ start_resident() {
|
|
|
41
42
|
docker run -d --name "$NAME" --restart unless-stopped --user "$(id -u):$(id -g)" --mount "$KIT_HOME_MOUNT" --mount "$WORKSPACE_MOUNT" --label "agentshouse.house=$HOUSE" --env HOME=/kit-home --env HOUSE_KIT_HOME=/kit-home --env HOUSE_KIT_CONTAINER=1 "$IMAGE" resident --house "$HOUSE" >/dev/null
|
|
42
43
|
}
|
|
43
44
|
|
|
44
|
-
if [[ "${1:-}" == kit ]]; then
|
|
45
|
+
if [[ "${1:-}" == kit || "${1:-}" == house ]]; then
|
|
45
46
|
FORWARDING=1
|
|
47
|
+
FORWARDED="$1"
|
|
46
48
|
FORWARD=("${@:2}")
|
|
47
49
|
set --
|
|
48
50
|
fi
|
|
@@ -129,10 +131,18 @@ if docker container inspect "$NAME" >/dev/null 2>&1; then
|
|
|
129
131
|
[[ "$(docker inspect --format '{{index .Config.Labels "agentshouse.house"}}' "$NAME")" == "$HOUSE" ]] || refuse 'the installed Kit uses another House origin'
|
|
130
132
|
[[ -f "$KIT_HOME/credential" && -f "$KIT_HOME/environment" && -f "$KIT_HOME/house" ]] || refuse 'the installed Kit has no enrolled authority'
|
|
131
133
|
if ((FORWARDING)); then
|
|
132
|
-
if [[ "${FORWARD[0]:-}" == login ]]; then
|
|
134
|
+
if [[ "$FORWARDED" == kit && "${FORWARD[0]:-}" == login ]]; then
|
|
133
135
|
login_kit "${FORWARD[@]:1}"
|
|
134
136
|
exit 0
|
|
135
137
|
fi
|
|
138
|
+
PLACED=()
|
|
139
|
+
ENTRY=()
|
|
140
|
+
if [[ "$FORWARDED" == house ]]; then
|
|
141
|
+
HERE=$(pwd -P)
|
|
142
|
+
[[ "$HERE" == "$WORKSPACE" || "$HERE" == "$WORKSPACE"/* ]] || refuse "the current directory is outside the workspace $WORKSPACE"
|
|
143
|
+
PLACED=(--workdir "/agents/house${HERE#"$WORKSPACE"}")
|
|
144
|
+
ENTRY=(--entrypoint house)
|
|
145
|
+
fi
|
|
136
146
|
TERMINAL=()
|
|
137
147
|
if [[ -t 0 && -t 1 ]]; then TERMINAL=(-t); fi
|
|
138
148
|
if [[ -t 0 && ! -t 1 ]]; then
|
|
@@ -141,9 +151,9 @@ if docker container inspect "$NAME" >/dev/null 2>&1; then
|
|
|
141
151
|
stty -echo
|
|
142
152
|
fi
|
|
143
153
|
if [[ "$(docker inspect --format '{{.State.Running}}' "$NAME")" == true ]]; then
|
|
144
|
-
docker exec -i "${TERMINAL[@]}" "$NAME"
|
|
154
|
+
docker exec -i "${TERMINAL[@]}" "${PLACED[@]}" "$NAME" "$FORWARDED" "${FORWARD[@]}"
|
|
145
155
|
else
|
|
146
|
-
"${DOCKER_RUN[@]:0:2}" -i "${TERMINAL[@]}" "${DOCKER_RUN[@]:2}" "${FORWARD[@]}"
|
|
156
|
+
"${DOCKER_RUN[@]:0:2}" -i "${TERMINAL[@]}" "${PLACED[@]}" "${ENTRY[@]}" "${DOCKER_RUN[@]:2}" "${FORWARD[@]}"
|
|
147
157
|
fi
|
|
148
158
|
exit
|
|
149
159
|
fi
|
package/bootstrap.json
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"schemaVersion": 1,
|
|
3
|
-
"version": "0.1.0-alpha.
|
|
3
|
+
"version": "0.1.0-alpha.18",
|
|
4
4
|
"hosts": {
|
|
5
5
|
"linux": {
|
|
6
|
-
"command": "bash <(curl -fsSL https://github.com/agentshouse/kit/releases/download/v0.1.0-alpha.
|
|
6
|
+
"command": "bash <(curl -fsSL https://github.com/agentshouse/kit/releases/download/v0.1.0-alpha.18/connect-linux.sh)",
|
|
7
7
|
"asset": {
|
|
8
8
|
"name": "connect-linux.sh",
|
|
9
|
-
"url": "https://github.com/agentshouse/kit/releases/download/v0.1.0-alpha.
|
|
9
|
+
"url": "https://github.com/agentshouse/kit/releases/download/v0.1.0-alpha.18/connect-linux.sh"
|
|
10
10
|
},
|
|
11
11
|
"workspace": {
|
|
12
12
|
"argument": "--workspace",
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@agentshouse/kit",
|
|
3
|
-
"version": "0.1.0-alpha.
|
|
3
|
+
"version": "0.1.0-alpha.18",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -9,6 +9,7 @@
|
|
|
9
9
|
"private": false,
|
|
10
10
|
"type": "module",
|
|
11
11
|
"bin": {
|
|
12
|
+
"house": "src/session-bin/house",
|
|
12
13
|
"kit": "bin/kit.js"
|
|
13
14
|
},
|
|
14
15
|
"exports": {
|
package/src/adapter-mcp.js
CHANGED
|
@@ -29,16 +29,3 @@ export async function commandHouseInstructions(bridge) {
|
|
|
29
29
|
}
|
|
30
30
|
return frame.result.instructions;
|
|
31
31
|
}
|
|
32
|
-
|
|
33
|
-
export async function commandHouseRequest(bridge) {
|
|
34
|
-
const frame = await commandHouseReply(bridge, { method: "tools/call", params: { name: "session_get_request", arguments: {} } });
|
|
35
|
-
if (frame.error !== undefined || frame.result?.isError === true) throw new KitRefusal("kit_run_input_unreadable");
|
|
36
|
-
try {
|
|
37
|
-
const content = frame.result.content;
|
|
38
|
-
const input = JSON.parse(content.find((item) => item.type === "text").text);
|
|
39
|
-
if (typeof input !== "object" || input === null || Array.isArray(input)) throw new Error();
|
|
40
|
-
return input;
|
|
41
|
-
} catch {
|
|
42
|
-
throw new KitRefusal("kit_run_input_unreadable");
|
|
43
|
-
}
|
|
44
|
-
}
|
package/src/bridge.js
CHANGED
|
@@ -18,7 +18,7 @@ import {
|
|
|
18
18
|
import { operationId } from "./operation.js";
|
|
19
19
|
import { houseFailed } from "./refusal.js";
|
|
20
20
|
|
|
21
|
-
function bridgedFrame(request, operation) {
|
|
21
|
+
export function bridgedFrame(request, operation) {
|
|
22
22
|
if (typeof request.method !== "string") return request;
|
|
23
23
|
const params = typeof request.params === "object" && request.params !== null ? request.params : {};
|
|
24
24
|
const declared = typeof params._meta === "object" && params._meta !== null ? params._meta : {};
|
package/src/contract.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { CLAUDE_PASTED_CODE, CODEX_DEVICE_CODE, GROK_DEVICE_CODE } from "./agent-logins.js";
|
|
2
2
|
|
|
3
|
-
export const KIT_CONTRACT_VERSION = "2026-09-28-
|
|
3
|
+
export const KIT_CONTRACT_VERSION = "2026-09-28-first-prompt";
|
|
4
4
|
export const KIT_CAPTURE_BATCH_MAX = 100;
|
|
5
5
|
export const COMMAND_INPUT_MAX_BYTES = 4 * 1024;
|
|
6
6
|
export const AUTHORIZATION_OUTPUT_MAX_BYTES = 4 * 1024;
|
|
@@ -40,6 +40,10 @@ export function runOutcomePath(run) {
|
|
|
40
40
|
return `/kit/runs/${encodeURIComponent(run)}/outcome`;
|
|
41
41
|
}
|
|
42
42
|
|
|
43
|
+
export function runRequestPath(run) {
|
|
44
|
+
return `/kit/runs/${encodeURIComponent(run)}/request`;
|
|
45
|
+
}
|
|
46
|
+
|
|
43
47
|
export const KIT_SESSIONS_REPORT_PATH = "/kit/sessions/report";
|
|
44
48
|
export const KIT_SESSIONS_REPORT_MAX = 256;
|
|
45
49
|
|
|
@@ -288,17 +292,21 @@ export const KIT_DOOR_DISCOVER_PATH = "/kit/door/discover";
|
|
|
288
292
|
export const KIT_DOOR_BOOTSTRAP_PATH = "/kit/door/bootstrap";
|
|
289
293
|
export const KIT_DOOR_ENUMERATE_PATH = "/kit/door/enumerate";
|
|
290
294
|
export const KIT_DOOR_BATCH_PATH = "/kit/door/batch";
|
|
295
|
+
export const KIT_DOOR_REVISIONS_PATH = "/kit/door/revisions";
|
|
291
296
|
export const EXPLICIT_SYNC_VERSION = "explicit-sync/2";
|
|
292
297
|
export const KIT_DOOR_UNMOUNT_PATH = "/kit/door/unmount";
|
|
293
298
|
|
|
294
299
|
export const KIT_WORKING_COPY_SELECTION_PATH = "/kit/working-copy/selection";
|
|
295
|
-
export const WORKING_COPY_VERSION = "working-copy-state/
|
|
300
|
+
export const WORKING_COPY_VERSION = "working-copy-state/2";
|
|
296
301
|
export const WORKING_COPIES_HOME = "working-copies";
|
|
297
302
|
export const WORKING_COPY_ROOM_HOMES = ["capture", "library", "collaboration"];
|
|
298
303
|
export const WORKING_COPY_PRIVATE_HOMES = ["library", "collaboration", "rooms", "agents", "house"];
|
|
299
304
|
export const WORKING_COPY_RECEIVED_REF = "refs/house/received";
|
|
300
305
|
export const WORKING_COPY_BRANCH = "main";
|
|
301
306
|
export const ROOM_REFERENCE = /^r_[0-9a-z]+\.[0-9a-z]$/;
|
|
307
|
+
export const WORKING_COPY_PUSH_METHOD = "house/git/push";
|
|
308
|
+
export const WORKING_COPY_PUSH_HELP =
|
|
309
|
+
"Submit a Room commit to House; default HEAD. Use --owner only outside an Agent Session. Native git push is not a House remote.";
|
|
302
310
|
|
|
303
311
|
export const MIGRATOR_CONTRACT = "kit-migrator/1";
|
|
304
312
|
export const MIGRATOR_CATEGORY = "migrator";
|
package/src/house-main.js
CHANGED
|
@@ -1,9 +1,19 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
|
|
1
|
+
import { homedir } from "node:os";
|
|
2
|
+
import { join, resolve } from "node:path";
|
|
3
|
+
import {
|
|
4
|
+
BRIDGE_NONCE_ENVIRONMENT,
|
|
5
|
+
BRIDGE_SOCKET_ENVIRONMENT,
|
|
6
|
+
WORKING_COPY_PUSH_HELP,
|
|
7
|
+
WORKING_COPY_PUSH_METHOD,
|
|
8
|
+
} from "./contract.js";
|
|
9
|
+
import { storedHouse } from "./login.js";
|
|
10
|
+
import { answerText, bridgeCall } from "./mcp.js";
|
|
11
|
+
import { formatCommandError, KitRefusal } from "./refusal.js";
|
|
12
|
+
import { ownerPush } from "./working-copy.js";
|
|
5
13
|
|
|
6
14
|
const HELP = ["--help", "-h"];
|
|
15
|
+
const OWNER = "--owner";
|
|
16
|
+
const GIT_PUSH_USAGE = `usage: house git push [commit] [${OWNER}]`;
|
|
7
17
|
const usage = (verb) => `usage: house ${verb} ['<arguments as one JSON object>' | - for standard input]`;
|
|
8
18
|
|
|
9
19
|
async function answered(method, params) {
|
|
@@ -49,10 +59,59 @@ function located(verb, args) {
|
|
|
49
59
|
return args;
|
|
50
60
|
}
|
|
51
61
|
|
|
62
|
+
function printed(result) {
|
|
63
|
+
const text = answerText(result);
|
|
64
|
+
return result?.isError === true ? { err: text, status: 1 } : { out: text };
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
async function ownerPushed(request) {
|
|
68
|
+
const directory = process.env.HOUSE_KIT_HOME ?? join(homedir(), ".house-kit");
|
|
69
|
+
const cancellation = new AbortController();
|
|
70
|
+
const cancel = () => cancellation.abort();
|
|
71
|
+
process.once("SIGINT", cancel);
|
|
72
|
+
process.once("SIGTERM", cancel);
|
|
73
|
+
try {
|
|
74
|
+
const pushed = await ownerPush(
|
|
75
|
+
{ house: await storedHouse(directory), directory, signal: cancellation.signal },
|
|
76
|
+
request,
|
|
77
|
+
);
|
|
78
|
+
return pushed.refused ? { err: pushed.text, status: 1 } : { out: pushed.text };
|
|
79
|
+
} catch (refusal) {
|
|
80
|
+
return { err: formatCommandError(refusal), status: 1 };
|
|
81
|
+
} finally {
|
|
82
|
+
process.removeListener("SIGINT", cancel);
|
|
83
|
+
process.removeListener("SIGTERM", cancel);
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
async function gitPush([action, ...rest]) {
|
|
88
|
+
if (action !== "push") throw new KitRefusal("kit_house_arguments_invalid", GIT_PUSH_USAGE);
|
|
89
|
+
if (rest.some((argument) => HELP.includes(argument))) return { out: `${GIT_PUSH_USAGE}\n\n${WORKING_COPY_PUSH_HELP}` };
|
|
90
|
+
const owner = rest.includes(OWNER);
|
|
91
|
+
const named = rest.filter((argument) => argument !== OWNER);
|
|
92
|
+
if (named.length > 1 || named.some((argument) => argument.startsWith("-"))) {
|
|
93
|
+
throw new KitRefusal("kit_house_arguments_invalid", GIT_PUSH_USAGE);
|
|
94
|
+
}
|
|
95
|
+
const request = { cwd: process.cwd(), commit: named[0] ?? "HEAD" };
|
|
96
|
+
if (process.env[BRIDGE_SOCKET_ENVIRONMENT] === undefined) {
|
|
97
|
+
if (!owner) throw new KitRefusal("kit_bridge_unavailable");
|
|
98
|
+
return ownerPushed(request);
|
|
99
|
+
}
|
|
100
|
+
if (owner) throw new KitRefusal("kit_house_arguments_invalid", `${OWNER} is only for use outside an Agent Session`);
|
|
101
|
+
return printed(await answered(WORKING_COPY_PUSH_METHOD, request));
|
|
102
|
+
}
|
|
103
|
+
|
|
52
104
|
async function house([verb, argument, ...rest]) {
|
|
105
|
+
if (verb === "git") return gitPush([argument, ...rest].filter((part) => part !== undefined));
|
|
53
106
|
if (verb === undefined || HELP.includes(verb)) {
|
|
54
107
|
const tools = await listed();
|
|
55
|
-
return {
|
|
108
|
+
return {
|
|
109
|
+
out: [
|
|
110
|
+
usage("<verb>"),
|
|
111
|
+
...tools.map((tool) => `${tool.name}\n${tool.description}`),
|
|
112
|
+
`git push [commit]\n${WORKING_COPY_PUSH_HELP}`,
|
|
113
|
+
].join("\n\n"),
|
|
114
|
+
};
|
|
56
115
|
}
|
|
57
116
|
if (HELP.includes(argument)) {
|
|
58
117
|
const tool = (await listed()).find((one) => one.name === verb);
|
|
@@ -61,9 +120,7 @@ async function house([verb, argument, ...rest]) {
|
|
|
61
120
|
}
|
|
62
121
|
if (rest.length > 0) throw new KitRefusal("kit_house_arguments_invalid", usage(verb));
|
|
63
122
|
const args = located(verb, await argumentsOf(verb, argument));
|
|
64
|
-
|
|
65
|
-
const text = (result?.content ?? []).filter((item) => item.type === "text").map((item) => item.text).join("\n");
|
|
66
|
-
return result?.isError === true ? { err: text, status: 1 } : { out: text };
|
|
123
|
+
return printed(await answered("tools/call", { name: verb, arguments: args }));
|
|
67
124
|
}
|
|
68
125
|
|
|
69
126
|
house(process.argv.slice(2)).then(
|