@agentshouse/kit 0.1.0-alpha.9 → 0.2.0
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 +14 -1740
- package/dist/api.js +11 -0
- package/dist/home.js +24 -0
- package/dist/house-main.js +4 -0
- package/dist/kit-main.js +16 -0
- package/dist/login.js +112 -0
- package/dist/resident.js +10 -0
- package/dist/stream.js +31 -0
- package/package.json +16 -11
- package/bin/connect-linux.sh +0 -134
- package/bin/kit.js +0 -1023
- package/bootstrap.json +0 -17
- package/src/acp.js +0 -99
- package/src/adapter-mcp.js +0 -44
- package/src/adapter.js +0 -252
- package/src/agent-logins.js +0 -65
- package/src/agents.js +0 -504
- package/src/apply.js +0 -29
- package/src/attach.js +0 -52
- package/src/binding.js +0 -90
- package/src/blocks.js +0 -156
- package/src/bridge.js +0 -449
- package/src/bytes.js +0 -89
- package/src/channel.js +0 -37
- package/src/command.js +0 -109
- package/src/configuration.js +0 -465
- package/src/connector-login.js +0 -91
- package/src/connector.js +0 -107
- package/src/continuation.js +0 -61
- package/src/contract.js +0 -363
- package/src/conversation-originals.js +0 -143
- package/src/custom/authorization.js +0 -63
- package/src/declaration.js +0 -35
- package/src/delivery.js +0 -191
- package/src/directory.js +0 -102
- package/src/draft.js +0 -89
- package/src/google/calendar.js +0 -177
- package/src/google/declared.js +0 -146
- package/src/google/drive.js +0 -435
- package/src/google/gateway.js +0 -166
- package/src/google/gmail.js +0 -249
- package/src/google/id.js +0 -1
- package/src/google/oauth.js +0 -273
- package/src/google/source.js +0 -25
- package/src/hook.js +0 -376
- package/src/host.js +0 -121
- package/src/house-main.js +0 -79
- package/src/house.js +0 -1090
- package/src/inbound.js +0 -175
- package/src/instance/google.js +0 -1
- package/src/kit-work-stream.js +0 -84
- package/src/launcher-main.js +0 -19
- package/src/launcher.js +0 -276
- package/src/local-files.js +0 -113
- package/src/login.js +0 -274
- package/src/mcp.js +0 -71
- package/src/migrator.js +0 -248
- package/src/mount.js +0 -582
- package/src/operation.js +0 -20
- package/src/original.js +0 -631
- package/src/peer.js +0 -124
- package/src/plan.js +0 -57
- package/src/question.js +0 -316
- package/src/refusal.js +0 -79
- package/src/repository.js +0 -521
- package/src/session-bin/house +0 -2
- package/src/settlement.js +0 -57
- package/src/setup.js +0 -190
- package/src/source-originals.js +0 -116
- package/src/source.js +0 -286
- package/src/starter-set/grilling/LICENSE +0 -21
- package/src/starter-set/grilling/SKILL.md +0 -30
- package/src/starter-set/grilling/agents/openai.yaml +0 -3
- package/src/starter-set.js +0 -17
- package/src/state.js +0 -157
- package/src/sync-library.js +0 -293
- package/src/sync-state.js +0 -120
- package/src/sync.js +0 -482
- package/src/telegram.js +0 -1045
- package/src/terminal.js +0 -57
- package/src/tmux.js +0 -119
- package/src/worker.js +0 -925
- package/src/workspace.js +0 -500
package/dist/api.js
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
export async function post(house, path, body) {
|
|
2
|
+
const answer = await fetch(new URL(path, house), {
|
|
3
|
+
method: 'POST',
|
|
4
|
+
headers: { 'content-type': 'application/json' },
|
|
5
|
+
body: JSON.stringify(body),
|
|
6
|
+
});
|
|
7
|
+
const text = await answer.text();
|
|
8
|
+
if (!answer.ok)
|
|
9
|
+
throw new Error(`House refused ${path} with ${answer.status}: ${text}`);
|
|
10
|
+
return JSON.parse(text);
|
|
11
|
+
}
|
package/dist/home.js
ADDED
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { mkdir, readFile, rename, writeFile } from 'node:fs/promises';
|
|
2
|
+
import { homedir } from 'node:os';
|
|
3
|
+
import { join } from 'node:path';
|
|
4
|
+
const ENROLMENT = 'credential.json';
|
|
5
|
+
export function kitHome() {
|
|
6
|
+
return process.env.HOUSE_KIT_HOME ?? join(homedir(), '.house-kit');
|
|
7
|
+
}
|
|
8
|
+
export async function readEnrolment() {
|
|
9
|
+
try {
|
|
10
|
+
return JSON.parse(await readFile(join(kitHome(), ENROLMENT), 'utf8'));
|
|
11
|
+
}
|
|
12
|
+
catch (error) {
|
|
13
|
+
if (error.code === 'ENOENT')
|
|
14
|
+
return null;
|
|
15
|
+
throw error;
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
export async function writeEnrolment(enrolment) {
|
|
19
|
+
const home = kitHome();
|
|
20
|
+
await mkdir(home, { recursive: true, mode: 0o700 });
|
|
21
|
+
const temporary = join(home, `${ENROLMENT}.${process.pid}`);
|
|
22
|
+
await writeFile(temporary, `${JSON.stringify(enrolment)}\n`, { mode: 0o600 });
|
|
23
|
+
await rename(temporary, join(home, ENROLMENT));
|
|
24
|
+
}
|
package/dist/kit-main.js
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { login } from './login.js';
|
|
3
|
+
import { resident } from './resident.js';
|
|
4
|
+
const [command, ...argv] = process.argv.slice(2);
|
|
5
|
+
async function run() {
|
|
6
|
+
if (command === 'login')
|
|
7
|
+
return login(argv);
|
|
8
|
+
if (command === 'resident')
|
|
9
|
+
return resident();
|
|
10
|
+
process.stderr.write('usage: kit <login|resident>\n');
|
|
11
|
+
process.exitCode = 2;
|
|
12
|
+
}
|
|
13
|
+
run().catch((error) => {
|
|
14
|
+
process.stderr.write(`kit: ${error instanceof Error ? error.message : String(error)}\n`);
|
|
15
|
+
process.exitCode = 1;
|
|
16
|
+
});
|
package/dist/login.js
ADDED
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
import { createHash, randomBytes } from 'node:crypto';
|
|
2
|
+
import { createServer } from 'node:http';
|
|
3
|
+
import { hostname } from 'node:os';
|
|
4
|
+
import { createInterface } from 'node:readline/promises';
|
|
5
|
+
import { parseArgs } from 'node:util';
|
|
6
|
+
import { post } from './api.js';
|
|
7
|
+
import { readEnrolment, writeEnrolment } from './home.js';
|
|
8
|
+
const DEFAULT_HOUSE = 'https://agents.house';
|
|
9
|
+
function listen() {
|
|
10
|
+
return new Promise((resolve, reject) => {
|
|
11
|
+
let deliver = () => undefined;
|
|
12
|
+
let held = null;
|
|
13
|
+
const code = new Promise((settle) => {
|
|
14
|
+
deliver = settle;
|
|
15
|
+
});
|
|
16
|
+
const server = createServer((request, response) => {
|
|
17
|
+
const received = new URL(request.url ?? '/', 'http://127.0.0.1').searchParams.get('code');
|
|
18
|
+
if (received === null || held !== null) {
|
|
19
|
+
response.writeHead(404).end();
|
|
20
|
+
return;
|
|
21
|
+
}
|
|
22
|
+
held = response;
|
|
23
|
+
deliver(received);
|
|
24
|
+
});
|
|
25
|
+
const close = () => {
|
|
26
|
+
server.close();
|
|
27
|
+
server.closeAllConnections();
|
|
28
|
+
};
|
|
29
|
+
server.once('error', reject);
|
|
30
|
+
server.listen(0, '127.0.0.1', () => {
|
|
31
|
+
const address = server.address();
|
|
32
|
+
if (address === null || typeof address === 'string') {
|
|
33
|
+
reject(new Error('the login callback has no port'));
|
|
34
|
+
return;
|
|
35
|
+
}
|
|
36
|
+
resolve({
|
|
37
|
+
uri: `http://127.0.0.1:${address.port}/callback`,
|
|
38
|
+
code,
|
|
39
|
+
answer: (text) => new Promise((written) => {
|
|
40
|
+
if (held === null || held.destroyed || !held.socket || held.socket.destroyed)
|
|
41
|
+
return written();
|
|
42
|
+
held.once('close', () => written());
|
|
43
|
+
held.writeHead(200, { 'content-type': 'text/plain; charset=utf-8', connection: 'close' }).end(`${text}\n`);
|
|
44
|
+
}),
|
|
45
|
+
close,
|
|
46
|
+
});
|
|
47
|
+
});
|
|
48
|
+
});
|
|
49
|
+
}
|
|
50
|
+
async function typed(question) {
|
|
51
|
+
const reader = createInterface({ input: process.stdin, output: process.stdout });
|
|
52
|
+
try {
|
|
53
|
+
return (await reader.question(question)).trim();
|
|
54
|
+
}
|
|
55
|
+
finally {
|
|
56
|
+
reader.close();
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
export async function login(argv) {
|
|
60
|
+
const { values } = parseArgs({
|
|
61
|
+
args: argv,
|
|
62
|
+
options: {
|
|
63
|
+
house: { type: 'string' },
|
|
64
|
+
environment: { type: 'string' },
|
|
65
|
+
manual: { type: 'boolean', default: false },
|
|
66
|
+
},
|
|
67
|
+
});
|
|
68
|
+
const enrolled = await readEnrolment();
|
|
69
|
+
const house = values.house ?? enrolled?.house ?? DEFAULT_HOUSE;
|
|
70
|
+
const environment = values.environment ?? (enrolled?.house === house ? enrolled.environment : undefined);
|
|
71
|
+
const verifier = randomBytes(32).toString('base64url');
|
|
72
|
+
const started = {
|
|
73
|
+
...(environment === undefined
|
|
74
|
+
? { act: 'new_environment', label: hostname() }
|
|
75
|
+
: { act: 'existing_environment', environment_id: environment }),
|
|
76
|
+
code_challenge: createHash('sha256').update(verifier).digest('base64url'),
|
|
77
|
+
};
|
|
78
|
+
const exchange = async (code) => {
|
|
79
|
+
const exchanged = await post(house, '/kit/token', { code, code_verifier: verifier });
|
|
80
|
+
await writeEnrolment({ house, environment: exchanged.environment, credential: exchanged.credential });
|
|
81
|
+
process.stdout.write(`Environment ${exchanged.environment} is connected to ${house}.\n`);
|
|
82
|
+
};
|
|
83
|
+
if (values.manual) {
|
|
84
|
+
const { start_url } = await post(house, '/kit', {
|
|
85
|
+
...started,
|
|
86
|
+
presentation: 'manual',
|
|
87
|
+
});
|
|
88
|
+
process.stdout.write(`Open this link and confirm: ${start_url}\n`);
|
|
89
|
+
await exchange(await typed('Code: '));
|
|
90
|
+
return;
|
|
91
|
+
}
|
|
92
|
+
const callback = await listen();
|
|
93
|
+
try {
|
|
94
|
+
const { start_url } = await post(house, '/kit', {
|
|
95
|
+
...started,
|
|
96
|
+
presentation: 'loopback',
|
|
97
|
+
loopback_uri: callback.uri,
|
|
98
|
+
});
|
|
99
|
+
process.stdout.write(`Open this link and confirm: ${start_url}\n`);
|
|
100
|
+
try {
|
|
101
|
+
await exchange(await callback.code);
|
|
102
|
+
}
|
|
103
|
+
catch (error) {
|
|
104
|
+
await callback.answer(`This Environment was not connected: ${error.message}`);
|
|
105
|
+
throw error;
|
|
106
|
+
}
|
|
107
|
+
await callback.answer('This Environment is connected. You can close this tab.');
|
|
108
|
+
}
|
|
109
|
+
finally {
|
|
110
|
+
callback.close();
|
|
111
|
+
}
|
|
112
|
+
}
|
package/dist/resident.js
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { readEnrolment } from './home.js';
|
|
2
|
+
import { holdStream } from './stream.js';
|
|
3
|
+
export async function resident() {
|
|
4
|
+
if ((await readEnrolment()) === null) {
|
|
5
|
+
process.stderr.write('kit: this Environment is not enrolled; run kit login\n');
|
|
6
|
+
process.exitCode = 1;
|
|
7
|
+
return;
|
|
8
|
+
}
|
|
9
|
+
holdStream();
|
|
10
|
+
}
|
package/dist/stream.js
ADDED
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { readEnrolment } from './home.js';
|
|
2
|
+
const SUBPROTOCOL = 'house.kit.stream.1';
|
|
3
|
+
function streamUrl(house) {
|
|
4
|
+
const url = new URL('/kit/stream', house);
|
|
5
|
+
url.protocol = url.protocol === 'https:' ? 'wss:' : 'ws:';
|
|
6
|
+
return url;
|
|
7
|
+
}
|
|
8
|
+
export function holdStream() {
|
|
9
|
+
let failures = 0;
|
|
10
|
+
const connect = async () => {
|
|
11
|
+
const { house, credential } = (await readEnrolment());
|
|
12
|
+
const opening = new WebSocket(streamUrl(house), {
|
|
13
|
+
protocols: [SUBPROTOCOL],
|
|
14
|
+
headers: { authorization: `Bearer ${credential}` },
|
|
15
|
+
});
|
|
16
|
+
let opened = false;
|
|
17
|
+
opening.onopen = () => {
|
|
18
|
+
opened = true;
|
|
19
|
+
failures = 0;
|
|
20
|
+
};
|
|
21
|
+
opening.onerror = () => undefined;
|
|
22
|
+
opening.onclose = (event) => {
|
|
23
|
+
process.stderr.write(`kit: control stream closed ${event.code} ${event.reason}\n`);
|
|
24
|
+
const delay = opened
|
|
25
|
+
? 1000 + Math.random() * 2000
|
|
26
|
+
: Math.min(30_000, 1000 * 2 ** failures++);
|
|
27
|
+
setTimeout(() => void connect(), delay);
|
|
28
|
+
};
|
|
29
|
+
};
|
|
30
|
+
void connect();
|
|
31
|
+
}
|
package/package.json
CHANGED
|
@@ -1,25 +1,30 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@agentshouse/kit",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.2.0",
|
|
4
|
+
"description": "House Kit connects an Environment to agents.house.",
|
|
4
5
|
"license": "MIT",
|
|
5
6
|
"repository": {
|
|
6
7
|
"type": "git",
|
|
7
8
|
"url": "git+https://github.com/agentshouse/kit.git"
|
|
8
9
|
},
|
|
9
|
-
"private": false,
|
|
10
10
|
"type": "module",
|
|
11
11
|
"bin": {
|
|
12
|
-
"kit": "
|
|
12
|
+
"kit": "dist/kit-main.js",
|
|
13
|
+
"house": "dist/house-main.js"
|
|
13
14
|
},
|
|
14
|
-
"
|
|
15
|
-
"
|
|
15
|
+
"files": [
|
|
16
|
+
"dist"
|
|
17
|
+
],
|
|
18
|
+
"scripts": {
|
|
19
|
+
"build": "tsc -p tsconfig.build.json",
|
|
20
|
+
"test": "tsc -p tsconfig.json && vitest run"
|
|
16
21
|
},
|
|
17
|
-
"
|
|
18
|
-
"@
|
|
19
|
-
"@
|
|
20
|
-
"
|
|
21
|
-
"
|
|
22
|
-
"
|
|
22
|
+
"devDependencies": {
|
|
23
|
+
"@types/node": "24.13.6",
|
|
24
|
+
"@types/ws": "8.18.2",
|
|
25
|
+
"typescript": "7.0.2",
|
|
26
|
+
"vitest": "5.0.1",
|
|
27
|
+
"ws": "8.22.0"
|
|
23
28
|
},
|
|
24
29
|
"packageManager": "npm@11.19.0",
|
|
25
30
|
"engines": {
|
package/bin/connect-linux.sh
DELETED
|
@@ -1,134 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env bash
|
|
2
|
-
set -euo pipefail
|
|
3
|
-
|
|
4
|
-
IMAGE='ghcr.io/agentshouse/kit@sha256:__IMAGE_DIGEST__'
|
|
5
|
-
NAME='house-kit'
|
|
6
|
-
HOUSE='https://agents.house'
|
|
7
|
-
WORKSPACE="$HOME/AgentsHouse"
|
|
8
|
-
MANUAL=0
|
|
9
|
-
WORKSPACE_SELECTED=0
|
|
10
|
-
HOUSE_SELECTED=0
|
|
11
|
-
|
|
12
|
-
refuse() {
|
|
13
|
-
printf 'kit_bootstrap_refused: %s\n' "$1" >&2
|
|
14
|
-
exit 1
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
bind_mount() {
|
|
18
|
-
local source=${1//\"/\"\"}
|
|
19
|
-
printf 'type=bind,"src=%s",dst=%s' "$source" "$2"
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
while (($#)); do
|
|
23
|
-
case "$1" in
|
|
24
|
-
--workspace|--house)
|
|
25
|
-
(($# >= 2)) || refuse "$1 requires one value"
|
|
26
|
-
if [[ "$1" == --workspace ]]; then
|
|
27
|
-
((WORKSPACE_SELECTED == 0)) || refuse 'supply exactly one workspace root'
|
|
28
|
-
WORKSPACE="$2"
|
|
29
|
-
WORKSPACE_SELECTED=1
|
|
30
|
-
else
|
|
31
|
-
((HOUSE_SELECTED == 0)) || refuse 'supply exactly one House origin'
|
|
32
|
-
HOUSE="$2"
|
|
33
|
-
HOUSE_SELECTED=1
|
|
34
|
-
fi
|
|
35
|
-
shift 2
|
|
36
|
-
;;
|
|
37
|
-
--manual)
|
|
38
|
-
MANUAL=1
|
|
39
|
-
shift
|
|
40
|
-
;;
|
|
41
|
-
*) refuse "unknown argument $1" ;;
|
|
42
|
-
esac
|
|
43
|
-
done
|
|
44
|
-
|
|
45
|
-
[[ "$IMAGE" =~ ^ghcr\.io/agentshouse/kit@sha256:[0-9a-f]{64}$ ]] || refuse 'this bootstrap has not been published with an immutable image digest'
|
|
46
|
-
[[ "$(uname -s)" == Linux ]] || refuse "unsupported host $(uname -s); this bootstrap is for Linux"
|
|
47
|
-
case "$(uname -m)" in
|
|
48
|
-
x86_64|amd64) ARCH=amd64 ;;
|
|
49
|
-
aarch64|arm64) ARCH=arm64 ;;
|
|
50
|
-
*) refuse "unsupported Linux architecture $(uname -m)" ;;
|
|
51
|
-
esac
|
|
52
|
-
[[ "$WORKSPACE" == /* ]] || refuse 'workspace root must be an absolute path'
|
|
53
|
-
command -v docker >/dev/null || refuse 'Docker Engine client is unavailable'
|
|
54
|
-
DOCKER_PLATFORM=$(docker info --format '{{.OSType}}/{{.Architecture}}' 2>/dev/null) || refuse 'Docker Engine is unavailable'
|
|
55
|
-
case "$DOCKER_PLATFORM" in
|
|
56
|
-
linux/x86_64|linux/amd64) DOCKER_ARCH=amd64 ;;
|
|
57
|
-
linux/aarch64|linux/arm64) DOCKER_ARCH=arm64 ;;
|
|
58
|
-
*) refuse "unsupported Docker Engine platform $DOCKER_PLATFORM" ;;
|
|
59
|
-
esac
|
|
60
|
-
[[ "$DOCKER_ARCH" == "$ARCH" ]] || refuse "host linux/$ARCH does not match Docker Engine linux/$DOCKER_ARCH"
|
|
61
|
-
|
|
62
|
-
umask 077
|
|
63
|
-
KIT_HOME="$HOME/.house-kit"
|
|
64
|
-
for path in "$KIT_HOME" "$WORKSPACE"; do
|
|
65
|
-
[[ ! -L "$path" ]] || refuse "$path is a symbolic link"
|
|
66
|
-
mkdir -p -m 700 "$path" || refuse "$path could not be created"
|
|
67
|
-
[[ -d "$path" ]] || refuse "$path is not a directory"
|
|
68
|
-
[[ "$(stat -c %u "$path")" == "$(id -u)" ]] || refuse "$path is not owned by this User"
|
|
69
|
-
chmod 700 "$path" || refuse "$path could not be owner-protected"
|
|
70
|
-
done
|
|
71
|
-
KIT_HOME=$(cd "$KIT_HOME" && pwd -P)
|
|
72
|
-
WORKSPACE=$(cd "$WORKSPACE" && pwd -P)
|
|
73
|
-
KIT_HOME_MOUNT=$(bind_mount "$KIT_HOME" /kit-home)
|
|
74
|
-
WORKSPACE_MOUNT=$(bind_mount "$WORKSPACE" /agents/house)
|
|
75
|
-
if [[ -f "$KIT_HOME/credential" || -f "$KIT_HOME/environment" ]] && [[ ! -f "$KIT_HOME/house" ]]; then
|
|
76
|
-
refuse 'stored House origin is missing for an enrolled Environment'
|
|
77
|
-
fi
|
|
78
|
-
if [[ -f "$KIT_HOME/house" ]]; then
|
|
79
|
-
IFS= read -r BOUND_HOUSE < "$KIT_HOME/house" || refuse 'stored House origin is unreadable'
|
|
80
|
-
if ((HOUSE_SELECTED)) && [[ "$HOUSE" != "$BOUND_HOUSE" ]]; then
|
|
81
|
-
refuse 'this Environment is bound to another House origin'
|
|
82
|
-
fi
|
|
83
|
-
HOUSE="$BOUND_HOUSE"
|
|
84
|
-
fi
|
|
85
|
-
[[ "$HOUSE" == https://* || "$HOUSE" == http://127.0.0.1:* || "$HOUSE" == http://localhost:* ]] || refuse 'House origin must use HTTPS or local loopback HTTP'
|
|
86
|
-
DOCKER_RUN=(docker run --rm --network host --user "$(id -u):$(id -g)" --mount "$KIT_HOME_MOUNT" --mount "$WORKSPACE_MOUNT" --env HOME=/kit-home --env HOUSE_KIT_HOME=/kit-home --env HOUSE_KIT_CONTAINER=1 --env "HOUSE_KIT_HOSTNAME=$(hostname)" "$IMAGE")
|
|
87
|
-
|
|
88
|
-
if docker container inspect "$NAME" >/dev/null 2>&1; then
|
|
89
|
-
[[ "$(docker inspect --format '{{.Config.Image}}' "$NAME")" == "$IMAGE" ]] || refuse 'an installed Kit uses a different image; update it explicitly'
|
|
90
|
-
[[ "$(docker inspect --format '{{.HostConfig.RestartPolicy.Name}}' "$NAME")" == unless-stopped ]] || refuse 'the installed Kit has a different lifecycle'
|
|
91
|
-
[[ "$(docker inspect --format '{{len .Mounts}}' "$NAME")" == 2 ]] || refuse 'the installed Kit has unexpected mounts'
|
|
92
|
-
[[ "$(docker inspect --format '{{range .Mounts}}{{if eq .Destination "/kit-home"}}{{.Source}}{{end}}{{end}}' "$NAME")" == "$KIT_HOME" ]] || refuse 'the installed Kit uses another Kit home'
|
|
93
|
-
[[ "$(docker inspect --format '{{range .Mounts}}{{if eq .Destination "/kit-home"}}{{.Type}}/{{.RW}}{{end}}{{end}}' "$NAME")" == bind/true ]] || refuse 'the installed Kit home is not a writable bind mount'
|
|
94
|
-
[[ "$(docker inspect --format '{{range .Mounts}}{{if eq .Destination "/agents/house"}}{{.Source}}{{end}}{{end}}' "$NAME")" == "$WORKSPACE" ]] || refuse 'the installed Kit uses another workspace root'
|
|
95
|
-
[[ "$(docker inspect --format '{{range .Mounts}}{{if eq .Destination "/agents/house"}}{{.Type}}/{{.RW}}{{end}}{{end}}' "$NAME")" == bind/true ]] || refuse 'the installed workspace is not a writable bind mount'
|
|
96
|
-
[[ "$(docker inspect --format '{{index .Config.Labels "agentshouse.house"}}' "$NAME")" == "$HOUSE" ]] || refuse 'the installed Kit uses another House origin'
|
|
97
|
-
[[ -f "$KIT_HOME/credential" && -f "$KIT_HOME/environment" && -f "$KIT_HOME/house" ]] || refuse 'the installed Kit has no enrolled authority'
|
|
98
|
-
"${DOCKER_RUN[@]}" credential check --house "$HOUSE"
|
|
99
|
-
if [[ "$(docker inspect --format '{{.State.Running}}' "$NAME")" == true ]]; then
|
|
100
|
-
printf 'House Kit is already running for Environment %s.\n' "$(cat "$KIT_HOME/environment")"
|
|
101
|
-
else
|
|
102
|
-
docker start "$NAME" >/dev/null
|
|
103
|
-
printf 'House Kit restarted for Environment %s.\n' "$(cat "$KIT_HOME/environment")"
|
|
104
|
-
fi
|
|
105
|
-
exit 0
|
|
106
|
-
fi
|
|
107
|
-
|
|
108
|
-
docker pull --quiet --platform "linux/$ARCH" "$IMAGE" >/dev/null
|
|
109
|
-
|
|
110
|
-
if [[ ! -f "$KIT_HOME/kit.json" ]]; then
|
|
111
|
-
printf '{"availability":"intermittent","execution_authority":"allow","migrators":[],"instances":[],"clients":[],"host":null}\n' > "$KIT_HOME/kit.json"
|
|
112
|
-
fi
|
|
113
|
-
|
|
114
|
-
if [[ -f "$KIT_HOME/credential" ]]; then
|
|
115
|
-
"${DOCKER_RUN[@]}" credential check --house "$HOUSE"
|
|
116
|
-
else
|
|
117
|
-
if ((MANUAL)); then
|
|
118
|
-
"${DOCKER_RUN[@]:0:2}" -i "${DOCKER_RUN[@]:2}" login --house "$HOUSE" --manual
|
|
119
|
-
else
|
|
120
|
-
command -v xdg-open >/dev/null || refuse 'no host browser opener; rerun with --manual'
|
|
121
|
-
"${DOCKER_RUN[@]}" login --house "$HOUSE" --host-browser | while IFS= read -r line; do
|
|
122
|
-
if [[ "$line" == 'Open '* ]]; then
|
|
123
|
-
printf 'Opening House Login in the host browser.\n'
|
|
124
|
-
xdg-open "${line#Open }" >/dev/null 2>&1 || refuse 'host browser did not open; rerun with --manual'
|
|
125
|
-
else
|
|
126
|
-
printf '%s\n' "$line"
|
|
127
|
-
fi
|
|
128
|
-
done
|
|
129
|
-
fi
|
|
130
|
-
fi
|
|
131
|
-
|
|
132
|
-
"${DOCKER_RUN[@]}" apply --house "$HOUSE"
|
|
133
|
-
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
|
|
134
|
-
printf 'House Kit connected for Environment %s.\n' "$(cat "$KIT_HOME/environment")"
|