@agentshouse/kit 0.2.1-cd9cbd8b6428c → 0.2.1-cfe80fd914176
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 +8 -9
- package/dist/acp.js +26 -13
- package/dist/agents.js +79 -38
- package/dist/api.js +30 -2
- package/dist/app-git.js +64 -0
- package/dist/bootstrap.json +4 -4
- package/dist/bridge.js +34 -40
- package/dist/clis.js +81 -65
- package/dist/conversations.js +282 -231
- package/dist/copies.js +27 -35
- package/dist/end.js +8 -0
- package/dist/events.js +587 -0
- package/dist/files.js +14 -0
- package/dist/house-main.js +28 -10
- package/dist/instructions.js +2 -2
- package/dist/kit-main.js +3 -0
- package/dist/login.js +4 -0
- package/dist/logout.js +3 -0
- package/dist/parts.js +64 -0
- package/dist/refusals.js +12 -0
- package/dist/resident.js +3 -3
- package/dist/secret-input.js +4 -1
- package/dist/shell.js +3 -0
- package/dist/sign-in.js +33 -8
- package/dist/skills.js +1 -1
- package/dist/stream.js +29 -4
- package/dist/transcription.js +54 -6
- package/dist/update.js +2 -0
- package/package.json +1 -1
- package/dist/blocks.js +0 -51
package/dist/clis.js
CHANGED
|
@@ -1,48 +1,50 @@
|
|
|
1
1
|
import { spawn } from 'node:child_process';
|
|
2
|
-
import { readFileSync } from 'node:fs';
|
|
3
|
-
import { readFile } from 'node:fs/promises';
|
|
4
|
-
import { userInfo } from 'node:os';
|
|
5
|
-
import { join } from 'node:path';
|
|
2
|
+
import { constants, readFileSync } from 'node:fs';
|
|
3
|
+
import { access, mkdir, readFile, writeFile } from 'node:fs/promises';
|
|
4
|
+
import { homedir, userInfo } from 'node:os';
|
|
5
|
+
import { delimiter, isAbsolute, join } from 'node:path';
|
|
6
6
|
import { kitHome } from './home.js';
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
return
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
const update = params?.update;
|
|
15
|
-
if (method !== 'session/update' || update?.asyncTaskId === undefined)
|
|
16
|
-
return null;
|
|
17
|
-
if (update.sessionUpdate === 'async_task_spawned')
|
|
18
|
-
return { id: update.asyncTaskId, running: true };
|
|
19
|
-
if (update.sessionUpdate === 'async_task_state_update' && !RUNNING_JOB.has(update.state ?? '')) {
|
|
20
|
-
return { id: update.asyncTaskId, running: false };
|
|
7
|
+
async function executable(path) {
|
|
8
|
+
try {
|
|
9
|
+
await access(path, constants.X_OK);
|
|
10
|
+
return true;
|
|
11
|
+
}
|
|
12
|
+
catch {
|
|
13
|
+
return false;
|
|
21
14
|
}
|
|
22
|
-
return null;
|
|
23
15
|
}
|
|
24
|
-
function
|
|
25
|
-
const
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
16
|
+
async function allowHouseInCodex(path) {
|
|
17
|
+
const candidates = [...new Set(path.split(delimiter).filter((directory) => isAbsolute(directory)))].map((directory) => join(directory, 'house'));
|
|
18
|
+
const houses = [];
|
|
19
|
+
for (const candidate of candidates)
|
|
20
|
+
if (await executable(candidate))
|
|
21
|
+
houses.push(candidate);
|
|
22
|
+
const rules = join(process.env.CODEX_HOME || join(homedir(), '.codex'), 'rules');
|
|
23
|
+
await mkdir(rules, { recursive: true });
|
|
24
|
+
await writeFile(join(rules, 'house.rules'), `prefix_rule(pattern = ["house"], decision = "allow")\nhost_executable(name = "house", paths = ${JSON.stringify(houses)})\n`);
|
|
25
|
+
}
|
|
26
|
+
async function nothing() { }
|
|
27
|
+
function bridgeInClaudeSandbox(bridge) {
|
|
28
|
+
return process.platform === 'darwin' ? { allowUnixSockets: [bridge] } : { allowAllUnixSockets: true };
|
|
31
29
|
}
|
|
32
30
|
export const CLIS = {
|
|
33
31
|
'codex-acp': {
|
|
34
32
|
bin: 'codex',
|
|
35
33
|
minimum: '0.159.1',
|
|
36
34
|
install: 'curl -fsSL https://chatgpt.com/codex/install.sh | sh',
|
|
37
|
-
adapter: {
|
|
35
|
+
adapter: {
|
|
36
|
+
package: '@agentclientprotocol/codex-acp',
|
|
37
|
+
bin: 'codex-acp',
|
|
38
|
+
executable: 'CODEX_PATH',
|
|
39
|
+
env: { CODEX_CONFIG: JSON.stringify({ features: { shell_zsh_fork: true } }) },
|
|
40
|
+
},
|
|
38
41
|
args: [],
|
|
42
|
+
fullAccess: 'agent-full-access',
|
|
43
|
+
sessionMeta: () => ({}),
|
|
44
|
+
allowHouse: allowHouseInCodex,
|
|
39
45
|
signedIn: { command: ['login', 'status'] },
|
|
40
46
|
login: { args: ['login', '--device-auth'], code: 'show' },
|
|
41
|
-
|
|
42
|
-
turnStarted: (notice) => threadStatus(notice) === 'active',
|
|
43
|
-
turnEnded: (notice) => threadStatus(notice) === 'idle',
|
|
44
|
-
job: asyncTask,
|
|
45
|
-
phase: airPhase,
|
|
47
|
+
air: ['asyncTasks', 'nativeSubagentSessions'],
|
|
46
48
|
},
|
|
47
49
|
'claude-agent-acp': {
|
|
48
50
|
bin: 'claude',
|
|
@@ -52,45 +54,45 @@ export const CLIS = {
|
|
|
52
54
|
package: '@agentclientprotocol/claude-agent-acp',
|
|
53
55
|
bin: 'claude-agent-acp',
|
|
54
56
|
executable: 'CLAUDE_CODE_EXECUTABLE',
|
|
55
|
-
env: { CLAUDE_CODE_ENTRYPOINT: 'claude-agent-acp' },
|
|
57
|
+
env: { CLAUDE_CODE_ENTRYPOINT: 'claude-agent-acp', IS_SANDBOX: '1' },
|
|
56
58
|
},
|
|
57
59
|
args: [],
|
|
60
|
+
fullAccess: 'bypassPermissions',
|
|
61
|
+
sessionMeta: (bridge) => ({
|
|
62
|
+
claudeCode: {
|
|
63
|
+
options: {
|
|
64
|
+
allowedTools: ['Bash(house:*)'],
|
|
65
|
+
settings: { sandbox: { network: bridgeInClaudeSandbox(bridge) } },
|
|
66
|
+
},
|
|
67
|
+
emitRawSDKMessages: ['background_tasks_changed', 'session_state_changed', 'task_started', 'task_notification'].map((subtype) => ({ type: 'system', subtype })),
|
|
68
|
+
},
|
|
69
|
+
}),
|
|
70
|
+
allowHouse: nothing,
|
|
58
71
|
signedIn: { command: ['auth', 'status'] },
|
|
59
72
|
login: { args: ['auth', 'login', '--claudeai'], code: 'collect', rejected: 'Invalid code' },
|
|
60
|
-
|
|
61
|
-
turnStarted: () => false,
|
|
62
|
-
turnEnded: ({ method, params }) => method === 'session/update' &&
|
|
63
|
-
params?.update?.sessionUpdate === 'usage_update' &&
|
|
64
|
-
params.update._meta?.['_claude/origin'] !== undefined,
|
|
65
|
-
job: asyncTask,
|
|
66
|
-
phase: () => null,
|
|
73
|
+
air: ['asyncTasks', 'sessionFailure'],
|
|
67
74
|
},
|
|
68
75
|
'grok-build': {
|
|
69
76
|
bin: 'grok',
|
|
70
77
|
minimum: '1.0.46',
|
|
71
78
|
install: 'curl -fsSL https://x.ai/cli/install.sh | bash',
|
|
72
79
|
adapter: null,
|
|
73
|
-
args: ['agent', '--no-leader', 'stdio'],
|
|
80
|
+
args: ['agent', '--always-approve', '--no-leader', 'stdio'],
|
|
81
|
+
fullAccess: null,
|
|
82
|
+
sessionMeta: () => ({}),
|
|
83
|
+
allowHouse: nothing,
|
|
74
84
|
signedIn: { initializeMeta: 'defaultAuthMethodId' },
|
|
75
85
|
login: { args: ['login', '--device-auth'], code: 'show' },
|
|
76
|
-
|
|
77
|
-
turnStarted: ({ method, params }) => method === '_x.ai/queue/changed' && params?.runningPromptId !== undefined,
|
|
78
|
-
turnEnded: ({ method, params }) => method === '_x.ai/session_notification' && params?.update?.sessionUpdate === 'turn_completed',
|
|
79
|
-
job: ({ method, params }) => {
|
|
80
|
-
if (method === '_x.ai/task_backgrounded')
|
|
81
|
-
return { id: params.update.task_id, running: true };
|
|
82
|
-
if (method === '_x.ai/task_completed')
|
|
83
|
-
return { id: params.update.task_snapshot.task_id, running: false };
|
|
84
|
-
return null;
|
|
85
|
-
},
|
|
86
|
-
phase: () => null,
|
|
86
|
+
air: ['asyncTasks'],
|
|
87
87
|
},
|
|
88
88
|
};
|
|
89
89
|
const KIT_PACKAGE = JSON.parse(readFileSync(new URL('../package.json', import.meta.url), 'utf8'));
|
|
90
90
|
export const KIT_VERSION = KIT_PACKAGE.version;
|
|
91
91
|
const PROXY = /^https?_proxy$/i;
|
|
92
92
|
const VERSION = /\d+\.\d+\.\d+(?:-[0-9A-Za-z.]+)?/;
|
|
93
|
+
// An install still running after fifteen minutes is ended and reported as failed, so a hung download cannot hold its CLI's report.
|
|
93
94
|
const INSTALL_MS = 15 * 60_000;
|
|
95
|
+
// A login shell or a version read is ended after half a minute, so a profile that waits for input cannot stall the report.
|
|
94
96
|
const READ_MS = 30_000;
|
|
95
97
|
const CAUSE_CHARACTERS = 4000;
|
|
96
98
|
function prefix(kind) {
|
|
@@ -118,8 +120,22 @@ export function run(command, args, timeoutMs, detached = false, signal) {
|
|
|
118
120
|
timeout: timeoutMs,
|
|
119
121
|
env: withoutProxy(),
|
|
120
122
|
detached,
|
|
121
|
-
signal,
|
|
123
|
+
signal: detached ? undefined : signal,
|
|
122
124
|
});
|
|
125
|
+
const stop = () => {
|
|
126
|
+
try {
|
|
127
|
+
process.kill(-child.pid, 'SIGKILL');
|
|
128
|
+
}
|
|
129
|
+
catch { }
|
|
130
|
+
};
|
|
131
|
+
if (detached && signal?.aborted)
|
|
132
|
+
stop();
|
|
133
|
+
if (detached)
|
|
134
|
+
signal?.addEventListener('abort', stop, { once: true });
|
|
135
|
+
const ended = (ran) => {
|
|
136
|
+
signal?.removeEventListener('abort', stop);
|
|
137
|
+
resolve(ran);
|
|
138
|
+
};
|
|
123
139
|
let stdout = '';
|
|
124
140
|
let output = '';
|
|
125
141
|
child.stdout.setEncoding('utf8').on('data', (chunk) => {
|
|
@@ -129,25 +145,25 @@ export function run(command, args, timeoutMs, detached = false, signal) {
|
|
|
129
145
|
child.stderr.setEncoding('utf8').on('data', (chunk) => {
|
|
130
146
|
output += chunk;
|
|
131
147
|
});
|
|
132
|
-
child.on('error', (error) =>
|
|
133
|
-
child.on('close', (status) =>
|
|
148
|
+
child.on('error', (error) => ended({ status: null, stdout, output: error.message }));
|
|
149
|
+
child.on('close', (status) => ended({ status, stdout, output }));
|
|
134
150
|
});
|
|
135
151
|
}
|
|
136
152
|
export function failureOf(ran, program) {
|
|
137
153
|
return ran.output.trim().slice(-CAUSE_CHARACTERS) || `${program} exited with ${ran.status ?? 'a signal'}`;
|
|
138
154
|
}
|
|
139
|
-
export async function installAdapter(kind) {
|
|
155
|
+
export async function installAdapter(kind, signal) {
|
|
140
156
|
const adapter = CLIS[kind].adapter;
|
|
141
157
|
if (adapter === null)
|
|
142
158
|
return null;
|
|
143
159
|
const release = KIT_PACKAGE.peerDependencies[adapter.package];
|
|
144
160
|
if ((await installedAdapter(kind)) === release)
|
|
145
161
|
return null;
|
|
146
|
-
const ran = await run('npm', ['install', '--prefix', prefix(kind), '--no-save', '--no-audit', '--no-fund', '--omit=optional', `${adapter.package}@${release}`], INSTALL_MS);
|
|
162
|
+
const ran = await run('npm', ['install', '--prefix', prefix(kind), '--no-save', '--no-audit', '--no-fund', '--omit=optional', `${adapter.package}@${release}`], INSTALL_MS, true, signal);
|
|
147
163
|
return ran.status === 0 ? null : failureOf(ran, 'npm');
|
|
148
164
|
}
|
|
149
|
-
export async function installCli(kind) {
|
|
150
|
-
const ran = await run('bash', ['-o', 'pipefail', '-c', CLIS[kind].install], INSTALL_MS, true);
|
|
165
|
+
export async function installCli(kind, signal) {
|
|
166
|
+
const ran = await run('bash', ['-o', 'pipefail', '-c', CLIS[kind].install], INSTALL_MS, true, signal);
|
|
151
167
|
return ran.status === 0 ? null : failureOf(ran, 'the install');
|
|
152
168
|
}
|
|
153
169
|
function loginShell() {
|
|
@@ -156,11 +172,11 @@ function loginShell() {
|
|
|
156
172
|
const FOUND = 'house-kit-cli ';
|
|
157
173
|
const LOOKUP = `found=$(command -v "$1") || exit 0; case $found in /*) ;; *) found=$(pwd -P)/$found ;; esac; printf "${FOUND}%s\\n" "$found"`;
|
|
158
174
|
const USER_BIN = 'case ":$PATH:" in *":$HOME/.local/bin:"*) ;; *) PATH="$PATH:$HOME/.local/bin" ;; esac; export PATH';
|
|
159
|
-
function inLoginShell(script, argument = '') {
|
|
160
|
-
return run(loginShell(), ['-l', '-i', '-c', `exec /bin/sh -c '${USER_BIN}; ${script}' sh ${argument}`], READ_MS, true);
|
|
175
|
+
function inLoginShell(script, argument = '', signal) {
|
|
176
|
+
return run(loginShell(), ['-l', '-i', '-c', `exec /bin/sh -c '${USER_BIN}; ${script}' sh ${argument}`], READ_MS, true, signal);
|
|
161
177
|
}
|
|
162
|
-
export async function locate(kind) {
|
|
163
|
-
const ran = await inLoginShell(LOOKUP, CLIS[kind].bin);
|
|
178
|
+
export async function locate(kind, signal) {
|
|
179
|
+
const ran = await inLoginShell(LOOKUP, CLIS[kind].bin, signal);
|
|
164
180
|
return ran.stdout.split('\n').findLast((line) => line.startsWith(FOUND))?.slice(FOUND.length) ?? null;
|
|
165
181
|
}
|
|
166
182
|
export async function loginPath() {
|
|
@@ -168,8 +184,8 @@ export async function loginPath() {
|
|
|
168
184
|
const ran = await inLoginShell(`printf "${marker}%s\\n" "$PATH"`);
|
|
169
185
|
return ran.stdout.split('\n').findLast((line) => line.startsWith(marker)).slice(marker.length);
|
|
170
186
|
}
|
|
171
|
-
export async function versionOf(path) {
|
|
172
|
-
return VERSION.exec((await run(path, ['--version'], READ_MS)).stdout)?.[0] ?? null;
|
|
187
|
+
export async function versionOf(path, signal) {
|
|
188
|
+
return VERSION.exec((await run(path, ['--version'], READ_MS, false, signal)).stdout)?.[0] ?? null;
|
|
173
189
|
}
|
|
174
190
|
function numbers(version) {
|
|
175
191
|
return version.split(/[.-]/, 3).map(Number);
|