@agentshouse/kit 0.2.1-c3e4a20bb3183 → 0.2.1-cb6679d048e60

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
@@ -6,17 +6,17 @@ through the agent CLIs you chose and gives each Agent the `house` command.
6
6
 
7
7
  ## Install
8
8
 
9
- Connect a computer from agents.house. It gives you the one command that
10
- installs House Kit on that computer and updates it when you run it again. On
11
- macOS and Linux it installs House Kit natively under your own account, without
12
- an admin password, as a service that runs while you are logged in. `kit` and
13
- `house` are then on your login shell's `PATH`, and your workspace is
14
- `~/AgentsHouse` unless you pass `--workspace <path>`.
9
+ Run `curl -fsSL agents.house/kit | sh`, or `irm agents.house/kit.ps1 | iex` on
10
+ Windows, and again to update; options follow `sh -s --`. On macOS and Linux it
11
+ installs House Kit natively under your own account, without an admin password,
12
+ as a service that runs while you are logged in. `kit` and `house` are then on
13
+ your login shell's `PATH`, and your workspace is `~/AgentsHouse` unless you
14
+ pass `--workspace <path>`.
15
15
 
16
16
  Add `--container` to run House Kit in one Docker container instead, with your
17
17
  workspace mounted at `/agents/house`; your Agents then reach only that
18
18
  workspace. On Windows 11 the container is the one choice. Append a `kit` or
19
- `house` command to the container's command to run it in that container.
19
+ `house` command to the container's options to run it in that container.
20
20
  Running the command for the other choice on a connected computer asks you to
21
21
  confirm, then replaces its Environment, whose Agents end, with a new one.
22
22
 
@@ -24,14 +24,12 @@ On your own Ubuntu 26.04 server, run the Linux command with `--linux` to
24
24
  install House Kit natively, with its workspace at `/agents/house`; `kit` and
25
25
  `house` are then on the server's `PATH`.
26
26
 
27
- House Kit runs the agent CLIs your login shell finds and installs a missing
28
- one through that CLI's own installer. Running the command again offers to
29
- update each CLI older than House Kit needs; add `--update-clis` to update every
30
- one to its latest release without asking.
31
-
32
- House Kit also gives every Agent on the Environment a set of agent skills. Add
33
- `--no-skills` to the command to leave them out; running it again without the
34
- flag brings them back.
27
+ House Kit runs the agent CLIs your login shell finds and installs a missing one
28
+ through that CLI's own installer. Running the command again offers to update
29
+ each CLI older than House Kit needs; add `--update-clis` to update every one to
30
+ its latest release without asking. House Kit also gives every Agent on the
31
+ Environment a set of agent skills. Add `--no-skills` to the command to leave
32
+ them out; running it again without the flag brings them back.
35
33
 
36
34
  ## Commands
37
35
 
@@ -40,13 +38,15 @@ Environment's credential in `~/.house-kit`, or in `$HOUSE_KIT_HOME` when it is
40
38
  set. Pass `--manual` to paste the code by hand on a machine without a browser,
41
39
  and `--environment <id>` to reconnect an Environment you already have. It also
42
40
  connects your own agent: `house <tool>` run outside an Agent conversation calls
43
- House as you, until you revoke that connection on Connections.
41
+ House as you, until you revoke that connection on Connections. `house help`
42
+ lists the Tools. `kit logout` disconnects this computer and stops House Kit; a
43
+ later `kit login` reconnects the same Environment.
44
44
 
45
45
  `kit resident` keeps the Environment connected, and keeps the Rooms you chose
46
46
  for this Environment as Git repositories under `local-copies` in the
47
- workspace. Commit in one and run `house git push --owner` there to send the
47
+ workspace. Commit in one and run `house push --owner` there to send the
48
48
  commit to House; in the container, run it through the install command from the
49
- copy's directory. Inside an Agent conversation the Agent runs `house git push`.
49
+ copy's directory. Inside an Agent conversation the Agent runs `house push`.
50
50
 
51
51
  House Kit turns each audio file of your message to an Agent into text on this
52
52
  computer before the Agent reads the message. The first audio file downloads the
@@ -1,30 +1,23 @@
1
1
  {
2
- "schemaVersion": 1,
3
- "version": "0.2.1-c3e4a20bb3183",
2
+ "schemaVersion": 2,
3
+ "version": "0.2.1-cb6679d048e60",
4
4
  "hosts": {
5
+ "macos": {
6
+ "asset": {
7
+ "name": "connect-linux.sh",
8
+ "url": "https://github.com/agentshouse/kit/releases/download/v0.2.1-cb6679d048e60/connect-linux.sh"
9
+ }
10
+ },
5
11
  "linux": {
6
- "command": "bash <(curl -fsSL https://github.com/agentshouse/kit/releases/download/v0.2.1-c3e4a20bb3183/connect-linux.sh)",
7
12
  "asset": {
8
13
  "name": "connect-linux.sh",
9
- "url": "https://github.com/agentshouse/kit/releases/download/v0.2.1-c3e4a20bb3183/connect-linux.sh"
10
- },
11
- "workspace": {
12
- "argument": "--workspace",
13
- "quoting": "posix"
14
- },
15
- "container": {
16
- "argument": "--container"
14
+ "url": "https://github.com/agentshouse/kit/releases/download/v0.2.1-cb6679d048e60/connect-linux.sh"
17
15
  }
18
16
  },
19
17
  "windows": {
20
- "command": "& ([scriptblock]::Create((irm https://github.com/agentshouse/kit/releases/download/v0.2.1-c3e4a20bb3183/connect-windows.ps1)))",
21
18
  "asset": {
22
19
  "name": "connect-windows.ps1",
23
- "url": "https://github.com/agentshouse/kit/releases/download/v0.2.1-c3e4a20bb3183/connect-windows.ps1"
24
- },
25
- "workspace": {
26
- "argument": "--workspace",
27
- "quoting": "powershell"
20
+ "url": "https://github.com/agentshouse/kit/releases/download/v0.2.1-cb6679d048e60/connect-windows.ps1"
28
21
  }
29
22
  }
30
23
  }
package/dist/copies.js CHANGED
@@ -255,11 +255,11 @@ export class LocalCopies {
255
255
  async push(cwd, selector, caller) {
256
256
  const located = await run(cwd, ['rev-parse', '--path-format=absolute', '--git-common-dir', '--show-toplevel']);
257
257
  if (located.status !== 0)
258
- return { refused: true, text: `${cwd} is not a House Local copy; run house git push inside one` };
258
+ return { refused: true, text: `${cwd} is not a House Local copy; run house push inside one` };
259
259
  const [common, worktree] = located.stdout.toString('utf8').split('\n');
260
260
  const key = await this.keyAt(dirname(common));
261
261
  if (key === undefined)
262
- return { refused: true, text: `${worktree} is not a House Local copy; run house git push inside one` };
262
+ return { refused: true, text: `${worktree} is not a House Local copy; run house push inside one` };
263
263
  return this.exclusive(key, () => this.pushed(key, worktree, selector, caller));
264
264
  }
265
265
  async keyAt(repository) {
@@ -597,7 +597,7 @@ export class LocalCopies {
597
597
  const refusal = error instanceof HouseRefusal ? refusalOf(error.text) : null;
598
598
  return {
599
599
  refused: true,
600
- text: refusal?.text ?? `House's answer to ${short(push.commit)} did not arrive; run house git push again`,
600
+ text: refusal?.text ?? `House's answer to ${short(push.commit)} did not arrive; run house push again`,
601
601
  };
602
602
  }
603
603
  if ('refused' in outcome) {
@@ -636,7 +636,7 @@ export class LocalCopies {
636
636
  await this.save(without(current));
637
637
  return {
638
638
  refused: true,
639
- text: `House does not hold ${short(push.commit)}; run house git push again`,
639
+ text: `House does not hold ${short(push.commit)}; run house push again`,
640
640
  };
641
641
  }
642
642
  const written = [];
@@ -664,7 +664,7 @@ export class LocalCopies {
664
664
  catch {
665
665
  return {
666
666
  refused: false,
667
- text: `House accepted ${short(commit)}; run house git push again to finish integrating it here`,
667
+ text: `House accepted ${short(commit)}; run house push again to finish integrating it here`,
668
668
  };
669
669
  }
670
670
  }
package/dist/home.js CHANGED
@@ -1,7 +1,9 @@
1
+ import { existsSync } from 'node:fs';
1
2
  import { mkdir, readFile, rename, rm, writeFile } from 'node:fs/promises';
2
3
  import { homedir } from 'node:os';
3
4
  import { join } from 'node:path';
4
5
  const ENROLMENT = 'credential.json';
6
+ const DISCONNECTED = 'disconnected.json';
5
7
  const CONFIGURATION = 'kit.json';
6
8
  const OWN_AGENT = 'own-agent.json';
7
9
  export function kitHome() {
@@ -33,8 +35,19 @@ export async function writeHome(name, value) {
33
35
  export function readEnrolment() {
34
36
  return readHome(ENROLMENT);
35
37
  }
36
- export function writeEnrolment(enrolment) {
37
- return writeHome(ENROLMENT, enrolment);
38
+ export async function writeEnrolment(enrolment) {
39
+ await writeHome(ENROLMENT, enrolment);
40
+ await rm(join(kitHome(), DISCONNECTED), { force: true });
41
+ }
42
+ export function readDisconnected() {
43
+ return readHome(DISCONNECTED);
44
+ }
45
+ export async function forgetEnrolment({ house, environment }) {
46
+ await writeHome(DISCONNECTED, { house, environment });
47
+ await rm(join(kitHome(), ENROLMENT), { force: true });
48
+ }
49
+ export function enrolled() {
50
+ return existsSync(join(kitHome(), ENROLMENT));
38
51
  }
39
52
  export function readOwnAgent() {
40
53
  return readHome(OWN_AGENT);
@@ -7,7 +7,8 @@ import { kitHome, readOwnAgent } from './home.js';
7
7
  import { callHouse, rpc, UNREACHABLE } from './mcp.js';
8
8
  import { refusalOf } from './refusals.js';
9
9
  const USAGE = "usage: house <tool> ['<arguments as JSON>']";
10
- const GIT_USAGE = 'usage: house git push [commit] [--owner]';
10
+ const PUSH_USAGE = 'usage: house push [commit] [--owner]';
11
+ const PUSH = "push [commit]: sends the Local copy's committed changes to House";
11
12
  const ARGUMENTS = `the arguments are one JSON object in single quotes, like house search '{"query":"invoice"}'`;
12
13
  const CLOSED = "this conversation's House connection is closed; nothing to do from here";
13
14
  const REVOKED = 'this conversation no longer has House access; nothing to do from here';
@@ -97,17 +98,15 @@ async function upload(path, roomRef, missing) {
97
98
  throw new Error(`${path} was not saved: ${saved.upload_failure}; call again later`);
98
99
  return saved.attachment;
99
100
  }
100
- async function gitPush(args) {
101
+ async function push(args) {
101
102
  if (args.includes('--help'))
102
- return GIT_USAGE;
103
- if (args[0] !== 'push')
104
- throw new Error('only house git push [commit] exists; use plain git for the rest');
103
+ return PUSH_USAGE;
105
104
  const owner = args.includes('--owner');
106
- const commit = args.slice(1).find((arg) => arg !== '--owner') ?? 'HEAD';
105
+ const commit = args.find((arg) => arg !== '--owner') ?? 'HEAD';
107
106
  if (owner && socketPath !== undefined)
108
- throw new Error('--owner is not for Agent conversations; run house git push without it');
107
+ throw new Error('--owner is not for Agent conversations; run house push without it');
109
108
  if (!owner && socketPath === undefined)
110
- throw new Error('outside an Agent conversation, house git push needs --owner');
109
+ throw new Error('outside an Agent conversation, house push needs --owner');
111
110
  const pushed = JSON.parse(await bridged('/git/push', { cwd: process.cwd(), commit }, undefined, owner ? join(kitHome(), 'owner.sock') : socketPath));
112
111
  if (pushed.refused)
113
112
  throw new Error(pushed.text);
@@ -128,14 +127,14 @@ function argumentsOf(argument) {
128
127
  return parsed;
129
128
  }
130
129
  async function house([verb, argument]) {
131
- if (verb === undefined || verb === '--help') {
132
- return [USAGE, 'git push [commit]', ...(await tools()).map((tool) => `${tool.name}: ${tool.description}`)].join('\n');
130
+ if (verb === undefined || verb === '--help' || verb === 'help') {
131
+ return [USAGE, 'help', PUSH, ...(await tools()).map((tool) => (tool.description === undefined ? tool.name : `${tool.name}: ${tool.description}`))].join('\n');
133
132
  }
134
133
  if (argument === '--help') {
135
134
  const tool = (await tools()).find((listed) => listed.name === verb);
136
135
  if (tool === undefined)
137
136
  throw new Error(`${verb} is no Tool; house find_command '{"query":"${verb}"}' finds Commands`);
138
- return `${tool.description}\n${JSON.stringify(tool.inputSchema)}`;
137
+ return [...(tool.description === undefined ? [] : [tool.description]), JSON.stringify(tool.inputSchema)].join('\n');
139
138
  }
140
139
  const args = argumentsOf(argument);
141
140
  if (socketPath !== undefined && verb === 'upload_attachment') {
@@ -155,7 +154,7 @@ async function house([verb, argument]) {
155
154
  return text;
156
155
  }
157
156
  const argv = process.argv.slice(2);
158
- (argv[0] === 'git' ? gitPush(argv.slice(1)) : house(argv)).then((text) => {
157
+ (argv[0] === 'push' ? push(argv.slice(1)) : house(argv)).then((text) => {
159
158
  process.stdout.write(`${text}\n`);
160
159
  }, (error) => {
161
160
  process.stderr.write(`house: ${error instanceof Error ? error.message : String(error)}\n`);
@@ -2,7 +2,7 @@ import { HOW_WE_WORK } from './skills.js';
2
2
  const HOUSE_LINE = 'Work with House through the `house` CLI: run `house --help`.';
3
3
  const FILE_LINE = 'To give the User a file or a page, upload it with `house upload_attachment` and link it; never start a server.';
4
4
  const READ_LINE = 'Before working in a Room, read `/private/rooms/<handle>/AGENTS.md`.';
5
- const COPIES_LINE = 'House Local copies; commit, then `house git push`:';
5
+ const COPIES_LINE = 'House Local copies; commit, then `house push`:';
6
6
  const UNREADABLE = /^(?:\S+: )?(?:path_not_found|room_not_found|operation_denied)\b/;
7
7
  const FAILED = /^exit: [1-9]\d*$/;
8
8
  const CUT = /^stderr: shell: output_cut (\d+) of \d+ bytes; continue with: (.+)$/;
package/dist/kit-main.js CHANGED
@@ -1,15 +1,18 @@
1
1
  #!/usr/bin/env node
2
2
  import { setGlobalProxyFromEnv } from 'node:http';
3
3
  import { login } from './login.js';
4
+ import { logout } from './logout.js';
4
5
  import { resident } from './resident.js';
5
6
  const [command, ...argv] = process.argv.slice(2);
6
7
  setGlobalProxyFromEnv();
7
8
  async function run() {
8
9
  if (command === 'login')
9
10
  return login(argv);
11
+ if (command === 'logout')
12
+ return logout();
10
13
  if (command === 'resident')
11
14
  return resident();
12
- process.stderr.write('usage: kit <login|resident>\n');
15
+ process.stderr.write('usage: kit <login|logout|resident>\n');
13
16
  process.exitCode = 2;
14
17
  }
15
18
  run().catch((error) => {
package/dist/login.js CHANGED
@@ -4,7 +4,7 @@ import { hostname } from 'node:os';
4
4
  import { createInterface } from 'node:readline/promises';
5
5
  import { parseArgs } from 'node:util';
6
6
  import { post } from './api.js';
7
- import { forgetOwnAgent, readEnrolment, readOwnAgent, writeEnrolment, writeOwnAgent } from './home.js';
7
+ import { forgetOwnAgent, readDisconnected, readEnrolment, readOwnAgent, writeEnrolment, writeOwnAgent } from './home.js';
8
8
  import { callHouse, rpc } from './mcp.js';
9
9
  const DEFAULT_HOUSE = 'https://agents.house';
10
10
  function listen() {
@@ -78,7 +78,7 @@ export async function login(argv) {
78
78
  manual: { type: 'boolean', default: false },
79
79
  },
80
80
  });
81
- const enrolled = await readEnrolment();
81
+ const enrolled = (await readEnrolment()) ?? (await readDisconnected());
82
82
  const house = values.house ?? enrolled?.house ?? DEFAULT_HOUSE;
83
83
  const replaces = process.env.HOUSE_KIT_REPLACES;
84
84
  const environment = replaces === undefined ? (values.environment ?? (enrolled?.house === house ? enrolled.environment : undefined)) : undefined;
package/dist/logout.js ADDED
@@ -0,0 +1,18 @@
1
+ import { HouseRefusal, post } from './api.js';
2
+ import { forgetEnrolment, readEnrolment } from './home.js';
3
+ export async function logout() {
4
+ const enrolled = await readEnrolment();
5
+ if (enrolled === null) {
6
+ process.stdout.write('This computer is not connected to House.\n');
7
+ return;
8
+ }
9
+ try {
10
+ await post(enrolled.house, '/kit/logout', {}, enrolled.credential);
11
+ }
12
+ catch (error) {
13
+ if (!(error instanceof HouseRefusal && error.status === 401))
14
+ throw error;
15
+ }
16
+ await forgetEnrolment(enrolled);
17
+ process.stdout.write(`Environment ${enrolled.environment} is disconnected; kit login reconnects it.\n`);
18
+ }
package/dist/resident.js CHANGED
@@ -1,4 +1,5 @@
1
1
  import { once } from 'node:events';
2
+ import { watch } from 'node:fs';
2
3
  import { mkdir, rm, writeFile } from 'node:fs/promises';
3
4
  import { createServer } from 'node:http';
4
5
  import { extname, join } from 'node:path';
@@ -9,7 +10,7 @@ import { house } from './api.js';
9
10
  import { received } from './bridge.js';
10
11
  import { Conversations } from './conversations.js';
11
12
  import { LocalCopies } from './copies.js';
12
- import { agentBase, kitHome, readEnrolment } from './home.js';
13
+ import { agentBase, enrolled, kitHome } from './home.js';
13
14
  import { SignIns } from './sign-in.js';
14
15
  import { placeSkillSet } from './skills.js';
15
16
  import { holdStream } from './stream.js';
@@ -50,12 +51,30 @@ async function serveOwner(copies) {
50
51
  server.listen(socketPath);
51
52
  await once(server, 'listening');
52
53
  }
54
+ function connected() {
55
+ return new Promise((resolve) => {
56
+ const watcher = watch(kitHome(), () => {
57
+ if (!enrolled())
58
+ return;
59
+ watcher.close();
60
+ resolve();
61
+ });
62
+ if (!enrolled()) {
63
+ process.stderr.write('kit: this Environment is not connected; run kit login\n');
64
+ return;
65
+ }
66
+ watcher.close();
67
+ resolve();
68
+ });
69
+ }
53
70
  export async function resident() {
54
- if ((await readEnrolment()) === null) {
55
- process.stderr.write('kit: this Environment is not enrolled; run kit login\n');
56
- process.exitCode = 1;
57
- return;
58
- }
71
+ await connected();
72
+ watch(kitHome(), () => {
73
+ if (enrolled())
74
+ return;
75
+ killDescendants();
76
+ process.exit(1);
77
+ });
59
78
  await placeSkillSet();
60
79
  await mkdir(agentBase(), { recursive: true });
61
80
  process.env.HOUSE_KIT_RESIDENT = String(process.pid);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@agentshouse/kit",
3
- "version": "0.2.1-c3e4a20bb3183",
3
+ "version": "0.2.1-cb6679d048e60",
4
4
  "description": "House Kit connects an Environment to agents.house.",
5
5
  "license": "MIT",
6
6
  "repository": {