@agentshouse/kit 0.1.0-alpha.3 → 0.1.0-alpha.31
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 +722 -263
- package/bin/connect-linux.sh +200 -25
- package/bin/kit.js +179 -157
- package/bootstrap.json +17 -0
- package/package.json +7 -2
- package/src/adapter-mcp.js +76 -12
- package/src/agents.js +63 -8
- package/src/binding.js +52 -0
- package/src/blocks.js +2 -26
- package/src/bridge.js +28 -14
- package/src/bytes.js +19 -8
- package/src/configuration.js +13 -209
- package/src/connector-login.js +3 -84
- package/src/contract.js +36 -11
- package/src/delivery.js +4 -7
- package/src/directory.js +6 -26
- package/src/draft.js +4 -82
- package/src/git-main.js +138 -0
- package/src/git.js +62 -0
- package/src/google/calendar.js +39 -45
- package/src/google/drive.js +61 -186
- package/src/google/entries.js +346 -0
- package/src/google/gateway.js +3 -6
- package/src/google/gmail.js +33 -23
- package/src/google/oauth.js +106 -66
- package/src/google/source.js +21 -23
- package/src/host.js +6 -2
- package/src/house-main.js +65 -8
- package/src/house.js +446 -127
- package/src/how-we-work.md +25 -0
- package/src/inbound.js +2 -18
- package/src/kit-work-stream.js +118 -0
- package/src/launcher.js +46 -10
- package/src/local-files.js +3 -11
- package/src/login.js +23 -11
- package/src/mcp.js +18 -0
- package/src/mount.js +13 -21
- package/src/original.js +4 -4
- package/src/pacing.js +41 -0
- package/src/plan.js +37 -45
- package/src/repository.js +3 -61
- package/src/session-bin/git +2 -0
- package/src/setup.js +14 -15
- package/src/skill-set/ask-matt/PHASE-BOUNDARIES.md +55 -0
- package/src/skill-set/ask-matt/SKILL.md +91 -0
- package/src/skill-set/ask-matt/agents/openai.yaml +4 -0
- package/src/skill-set/code-review/LICENSE +21 -0
- package/src/skill-set/code-review/SKILL.md +89 -0
- package/src/skill-set/code-review/agents/openai.yaml +3 -0
- package/src/skill-set/codebase-design/DEEPENING.md +37 -0
- package/src/skill-set/codebase-design/DESIGN-IT-TWICE.md +44 -0
- package/src/skill-set/codebase-design/LICENSE +21 -0
- package/src/skill-set/codebase-design/SKILL.md +116 -0
- package/src/skill-set/codebase-design/agents/openai.yaml +3 -0
- package/src/skill-set/diagnosing-bugs/LICENSE +21 -0
- package/src/skill-set/diagnosing-bugs/SKILL.md +140 -0
- package/src/skill-set/diagnosing-bugs/agents/openai.yaml +3 -0
- package/src/skill-set/diagnosing-bugs/scripts/hitl-loop.template.sh +44 -0
- package/src/skill-set/domain-modeling/ADR-FORMAT.md +47 -0
- package/src/skill-set/domain-modeling/CONTEXT-FORMAT.md +60 -0
- package/src/skill-set/domain-modeling/LICENSE +21 -0
- package/src/skill-set/domain-modeling/SKILL.md +76 -0
- package/src/skill-set/domain-modeling/agents/openai.yaml +3 -0
- package/src/skill-set/grill-me/LICENSE +21 -0
- package/src/skill-set/grill-me/SKILL.md +8 -0
- package/src/skill-set/grill-me/agents/openai.yaml +4 -0
- package/src/skill-set/grill-with-docs/LICENSE +21 -0
- package/src/skill-set/grill-with-docs/SKILL.md +8 -0
- package/src/skill-set/grill-with-docs/agents/openai.yaml +4 -0
- package/src/skill-set/grilling/LICENSE +21 -0
- package/src/{starter-set → skill-set}/grilling/SKILL.md +1 -1
- package/src/skill-set/handoff/LICENSE +21 -0
- package/src/skill-set/handoff/SKILL.md +17 -0
- package/src/skill-set/handoff/agents/openai.yaml +4 -0
- package/src/skill-set/implement/LICENSE +21 -0
- package/src/skill-set/implement/SKILL.md +16 -0
- package/src/skill-set/implement/agents/openai.yaml +4 -0
- package/src/skill-set/improve-codebase-architecture/HTML-REPORT.md +123 -0
- package/src/skill-set/improve-codebase-architecture/LICENSE +21 -0
- package/src/skill-set/improve-codebase-architecture/SKILL.md +72 -0
- package/src/skill-set/improve-codebase-architecture/agents/openai.yaml +4 -0
- package/src/skill-set/prototype/LICENSE +21 -0
- package/src/skill-set/prototype/LOGIC.md +67 -0
- package/src/skill-set/prototype/SKILL.md +28 -0
- package/src/skill-set/prototype/UI.md +112 -0
- package/src/skill-set/prototype/agents/openai.yaml +3 -0
- package/src/skill-set/research/LICENSE +21 -0
- package/src/skill-set/research/SKILL.md +14 -0
- package/src/skill-set/research/agents/openai.yaml +3 -0
- package/src/skill-set/resolving-merge-conflicts/LICENSE +21 -0
- package/src/skill-set/resolving-merge-conflicts/SKILL.md +16 -0
- package/src/skill-set/resolving-merge-conflicts/agents/openai.yaml +3 -0
- package/src/skill-set/tdd/LICENSE +21 -0
- package/src/skill-set/tdd/SKILL.md +40 -0
- package/src/skill-set/tdd/agents/openai.yaml +3 -0
- package/src/skill-set/tdd/mocking.md +59 -0
- package/src/skill-set/tdd/tests.md +77 -0
- package/src/skill-set/teach/GLOSSARY-FORMAT.md +35 -0
- package/src/skill-set/teach/LEARNING-RECORD-FORMAT.md +46 -0
- package/src/skill-set/teach/LICENSE +21 -0
- package/src/skill-set/teach/MISSION-FORMAT.md +31 -0
- package/src/skill-set/teach/RESOURCES-FORMAT.md +32 -0
- package/src/skill-set/teach/SKILL.md +141 -0
- package/src/skill-set/teach/agents/openai.yaml +4 -0
- package/src/skill-set/to-questionnaire/LICENSE +21 -0
- package/src/skill-set/to-questionnaire/SKILL.md +55 -0
- package/src/skill-set/to-questionnaire/agents/openai.yaml +4 -0
- package/src/skill-set/to-spec/LICENSE +21 -0
- package/src/skill-set/to-spec/SKILL.md +76 -0
- package/src/skill-set/to-spec/agents/openai.yaml +4 -0
- package/src/skill-set/to-tickets/LICENSE +21 -0
- package/src/skill-set/to-tickets/SKILL.md +106 -0
- package/src/skill-set/to-tickets/agents/openai.yaml +4 -0
- package/src/skill-set/wait-what/LICENSE +21 -0
- package/src/skill-set/wait-what/SKILL.md +8 -0
- package/src/skill-set/wait-what/agents/openai.yaml +4 -0
- package/src/skill-set/wayfinder/LICENSE +21 -0
- package/src/skill-set/wayfinder/SKILL.md +129 -0
- package/src/skill-set/wayfinder/agents/openai.yaml +4 -0
- package/src/skill-set/writing-for-agents/LICENSE +21 -0
- package/src/skill-set/writing-for-agents/SKILL-MECHANICS.md +22 -0
- package/src/skill-set/writing-for-agents/SKILL.md +83 -0
- package/src/skill-set/writing-for-agents/agents/openai.yaml +3 -0
- package/src/skill-set.js +85 -0
- package/src/source.js +93 -54
- package/src/state.js +19 -1
- package/src/sync-library.js +7 -11
- package/src/sync-state.js +16 -3
- package/src/sync.js +129 -41
- package/src/tasks.js +75 -0
- package/src/telegram-view.js +214 -0
- package/src/telegram.js +161 -66
- package/src/turn-frames.js +69 -0
- package/src/worker.js +685 -184
- package/src/working-copy.js +1221 -0
- package/src/workspace.js +40 -32
- package/src/google/declared.js +0 -146
- package/src/google/id.js +0 -1
- package/src/instance/google.js +0 -1
- package/src/starter-set.js +0 -17
- /package/src/{starter-set/grilling → skill-set/ask-matt}/LICENSE +0 -0
- /package/src/{starter-set → skill-set}/grilling/agents/openai.yaml +0 -0
package/src/configuration.js
CHANGED
|
@@ -7,18 +7,10 @@ import {
|
|
|
7
7
|
MIGRATOR_TIMEOUT_MS,
|
|
8
8
|
} from "./contract.js";
|
|
9
9
|
import { declarationReader } from "./declaration.js";
|
|
10
|
-
import { GOOGLE_DRIVE_ID } from "./google/id.js";
|
|
11
10
|
import { KitRefusal } from "./refusal.js";
|
|
12
11
|
|
|
13
|
-
const PRESETS = new Set(["custom", "google"]);
|
|
14
12
|
const AGENT_CLIENTS = new Set(["claude-code"]);
|
|
15
|
-
const GOOGLE_CURATED_SERVICES = new Set(["gmail", "calendar", "drive"]);
|
|
16
13
|
const ENVIRONMENT_VALUE_MAX = 4096;
|
|
17
|
-
const GOOGLE_API_HOST = /^[a-z0-9-]+(?:\.[a-z0-9-]+)*\.googleapis\.com$/;
|
|
18
|
-
const GOOGLE_API_PATH = /^\/[A-Za-z0-9._~!$&'()*+,;=:@%/-]+$/;
|
|
19
|
-
const GOOGLE_API_SCOPE = /^https:\/\/www\.googleapis\.com\/auth\/[A-Za-z0-9._-]+$/;
|
|
20
|
-
const EXTRACTION_PATH = /^(?:[A-Za-z_][A-Za-z0-9_-]*|\d+)(?:\.(?:[A-Za-z_][A-Za-z0-9_-]*|\d+))*$/;
|
|
21
|
-
const QUERY_NAME = /^[A-Za-z][A-Za-z0-9_.-]{0,127}$/;
|
|
22
14
|
|
|
23
15
|
const { refuse, plain, closed, text, positiveCount, filled } = declarationReader(
|
|
24
16
|
"kit_configuration_invalid",
|
|
@@ -116,225 +108,33 @@ function backfillOf(value, declaration) {
|
|
|
116
108
|
return { kind: named[0], bound: positiveCount(backfill[named[0]], declaration) };
|
|
117
109
|
}
|
|
118
110
|
|
|
119
|
-
function
|
|
120
|
-
return filled(value, declaration).map((entry, position) =>
|
|
121
|
-
text(entry, `${declaration}[${position}]`, 512),
|
|
122
|
-
);
|
|
123
|
-
}
|
|
124
|
-
|
|
125
|
-
function textArray(value, declaration) {
|
|
126
|
-
if (!Array.isArray(value)) refuse(declaration);
|
|
127
|
-
return value.map((entry, position) => text(entry, `${declaration}[${position}]`, 512));
|
|
128
|
-
}
|
|
129
|
-
|
|
130
|
-
function googleSelectionOf(value, declaration, service) {
|
|
131
|
-
if (service === "gmail") {
|
|
132
|
-
const selection = closed(value, ["labels"], declaration);
|
|
133
|
-
return { labels: textList(selection.labels, `${declaration}.labels`) };
|
|
134
|
-
}
|
|
135
|
-
if (service === "calendar") {
|
|
136
|
-
const selection = closed(value, ["calendars"], declaration);
|
|
137
|
-
return { calendars: textList(selection.calendars, `${declaration}.calendars`) };
|
|
138
|
-
}
|
|
139
|
-
if (service === "drive") {
|
|
140
|
-
const selection = closed(value, ["files", "folders"], declaration);
|
|
141
|
-
const files =
|
|
142
|
-
selection.files === undefined ? [] : textArray(selection.files, `${declaration}.files`);
|
|
143
|
-
const folders =
|
|
144
|
-
selection.folders === undefined ? [] : textArray(selection.folders, `${declaration}.folders`);
|
|
145
|
-
if (files.length + folders.length === 0) refuse(declaration);
|
|
146
|
-
files.forEach((id, position) => {
|
|
147
|
-
if (!GOOGLE_DRIVE_ID.test(id)) refuse(`${declaration}.files[${position}]`);
|
|
148
|
-
});
|
|
149
|
-
folders.forEach((id, position) => {
|
|
150
|
-
if (!GOOGLE_DRIVE_ID.test(id)) refuse(`${declaration}.folders[${position}]`);
|
|
151
|
-
});
|
|
152
|
-
return { files, folders };
|
|
153
|
-
}
|
|
154
|
-
refuse(declaration);
|
|
155
|
-
}
|
|
156
|
-
|
|
157
|
-
function extractionPath(value, declaration) {
|
|
158
|
-
const path = text(value, declaration, 512);
|
|
159
|
-
if (!EXTRACTION_PATH.test(path)) refuse(declaration);
|
|
160
|
-
return path;
|
|
161
|
-
}
|
|
162
|
-
|
|
163
|
-
function queryOf(value, declaration) {
|
|
164
|
-
const query = plain(value, declaration);
|
|
165
|
-
const parsed = {};
|
|
166
|
-
for (const [name, entry] of Object.entries(query)) {
|
|
167
|
-
if (!QUERY_NAME.test(name) || typeof entry !== "string" || entry.length > 2048) {
|
|
168
|
-
refuse(`${declaration}.${name}`);
|
|
169
|
-
}
|
|
170
|
-
parsed[name] = entry;
|
|
171
|
-
}
|
|
172
|
-
return parsed;
|
|
173
|
-
}
|
|
174
|
-
|
|
175
|
-
function declaredServiceOf(value, declaration) {
|
|
176
|
-
const declared = closed(
|
|
177
|
-
value,
|
|
178
|
-
["host", "path", "query", "page_size", "page_token", "items", "fields", "scopes"],
|
|
179
|
-
declaration,
|
|
180
|
-
);
|
|
181
|
-
const host = text(declared.host, `${declaration}.host`, 253);
|
|
182
|
-
if (!GOOGLE_API_HOST.test(host)) refuse(`${declaration}.host`);
|
|
183
|
-
const path = text(declared.path, `${declaration}.path`, 2048);
|
|
184
|
-
if (!GOOGLE_API_PATH.test(path) || path.includes("..") || path.includes("//")) {
|
|
185
|
-
refuse(`${declaration}.path`);
|
|
186
|
-
}
|
|
187
|
-
const tokens = closed(
|
|
188
|
-
declared.page_token,
|
|
189
|
-
["request", "response", "checkpoint_request", "checkpoint_response"],
|
|
190
|
-
`${declaration}.page_token`,
|
|
191
|
-
);
|
|
192
|
-
const pageToken = {
|
|
193
|
-
request: text(tokens.request, `${declaration}.page_token.request`, 128),
|
|
194
|
-
response: extractionPath(tokens.response, `${declaration}.page_token.response`),
|
|
195
|
-
checkpointRequest: text(
|
|
196
|
-
tokens.checkpoint_request,
|
|
197
|
-
`${declaration}.page_token.checkpoint_request`,
|
|
198
|
-
128,
|
|
199
|
-
),
|
|
200
|
-
checkpointResponse: extractionPath(
|
|
201
|
-
tokens.checkpoint_response,
|
|
202
|
-
`${declaration}.page_token.checkpoint_response`,
|
|
203
|
-
),
|
|
204
|
-
};
|
|
205
|
-
if (
|
|
206
|
-
!QUERY_NAME.test(pageToken.request) ||
|
|
207
|
-
!QUERY_NAME.test(pageToken.checkpointRequest) ||
|
|
208
|
-
pageToken.request === pageToken.checkpointRequest
|
|
209
|
-
) {
|
|
210
|
-
refuse(`${declaration}.page_token`);
|
|
211
|
-
}
|
|
212
|
-
const fields = closed(
|
|
213
|
-
declared.fields,
|
|
214
|
-
[
|
|
215
|
-
"native_id",
|
|
216
|
-
"native_version",
|
|
217
|
-
"provider_modified_at",
|
|
218
|
-
"observed_at",
|
|
219
|
-
"body",
|
|
220
|
-
"container",
|
|
221
|
-
"author",
|
|
222
|
-
"url",
|
|
223
|
-
],
|
|
224
|
-
`${declaration}.fields`,
|
|
225
|
-
);
|
|
226
|
-
const pageSize = text(declared.page_size, `${declaration}.page_size`, 128);
|
|
227
|
-
if (!QUERY_NAME.test(pageSize)) refuse(`${declaration}.page_size`);
|
|
228
|
-
const scopes = textList(declared.scopes, `${declaration}.scopes`).map((scope, position) => {
|
|
229
|
-
if (!GOOGLE_API_SCOPE.test(scope)) refuse(`${declaration}.scopes[${position}]`);
|
|
230
|
-
return scope;
|
|
231
|
-
});
|
|
232
|
-
return {
|
|
233
|
-
host,
|
|
234
|
-
path,
|
|
235
|
-
query: queryOf(declared.query, `${declaration}.query`),
|
|
236
|
-
pageSize,
|
|
237
|
-
scopes: [...new Set(scopes)],
|
|
238
|
-
pageToken,
|
|
239
|
-
items: extractionPath(declared.items, `${declaration}.items`),
|
|
240
|
-
fields: {
|
|
241
|
-
nativeId: extractionPath(fields.native_id, `${declaration}.fields.native_id`),
|
|
242
|
-
nativeVersion:
|
|
243
|
-
fields.native_version === undefined
|
|
244
|
-
? null
|
|
245
|
-
: extractionPath(fields.native_version, `${declaration}.fields.native_version`),
|
|
246
|
-
providerModifiedAt:
|
|
247
|
-
fields.provider_modified_at === undefined
|
|
248
|
-
? null
|
|
249
|
-
: extractionPath(
|
|
250
|
-
fields.provider_modified_at,
|
|
251
|
-
`${declaration}.fields.provider_modified_at`,
|
|
252
|
-
),
|
|
253
|
-
observedAt: extractionPath(fields.observed_at, `${declaration}.fields.observed_at`),
|
|
254
|
-
body: textList(fields.body, `${declaration}.fields.body`).map((path, position) =>
|
|
255
|
-
extractionPath(path, `${declaration}.fields.body[${position}]`),
|
|
256
|
-
),
|
|
257
|
-
container: extractionPath(fields.container, `${declaration}.fields.container`),
|
|
258
|
-
author:
|
|
259
|
-
fields.author === undefined
|
|
260
|
-
? null
|
|
261
|
-
: extractionPath(fields.author, `${declaration}.fields.author`),
|
|
262
|
-
url:
|
|
263
|
-
fields.url === undefined ? null : extractionPath(fields.url, `${declaration}.fields.url`),
|
|
264
|
-
},
|
|
265
|
-
};
|
|
266
|
-
}
|
|
267
|
-
|
|
268
|
-
function serviceOf(value, declaration, preset) {
|
|
111
|
+
function serviceOf(value, declaration) {
|
|
269
112
|
const service = closed(
|
|
270
113
|
value,
|
|
271
|
-
["service", "source_ref", "rooms", "backfill", "connector"
|
|
114
|
+
["service", "source_ref", "rooms", "backfill", "connector"],
|
|
272
115
|
declaration,
|
|
273
116
|
);
|
|
274
|
-
const name = declaredId(service.service, `${declaration}.service`);
|
|
275
|
-
if (preset === "custom" && service.connector === undefined) refuse(`${declaration}.connector`);
|
|
276
|
-
if (preset === "custom" && service.selection !== undefined) refuse(`${declaration}.selection`);
|
|
277
|
-
if (preset === "custom" && service.declaration !== undefined) refuse(`${declaration}.declaration`);
|
|
278
|
-
if (preset === "google" && service.connector !== undefined) refuse(`${declaration}.connector`);
|
|
279
|
-
if (preset === "google" && GOOGLE_CURATED_SERVICES.has(name) && service.declaration !== undefined) {
|
|
280
|
-
refuse(`${declaration}.declaration`);
|
|
281
|
-
}
|
|
282
|
-
if (preset === "google" && !GOOGLE_CURATED_SERVICES.has(name)) {
|
|
283
|
-
if (service.selection !== undefined) refuse(`${declaration}.selection`);
|
|
284
|
-
if (service.declaration === undefined) refuse(`${declaration}.declaration`);
|
|
285
|
-
}
|
|
286
117
|
return {
|
|
287
|
-
service:
|
|
118
|
+
service: declaredId(service.service, `${declaration}.service`),
|
|
288
119
|
sourceRef: text(service.source_ref, `${declaration}.source_ref`, 512),
|
|
289
120
|
rooms: filled(service.rooms, `${declaration}.rooms`).map((room, position) =>
|
|
290
121
|
text(room, `${declaration}.rooms[${position}]`, 512),
|
|
291
122
|
),
|
|
292
123
|
backfill: backfillOf(service.backfill, `${declaration}.backfill`),
|
|
293
|
-
|
|
294
|
-
preset === "google" && GOOGLE_CURATED_SERVICES.has(name)
|
|
295
|
-
? googleSelectionOf(service.selection, `${declaration}.selection`, name)
|
|
296
|
-
: null,
|
|
297
|
-
connector: preset === "custom" ? connectorOf(service.connector, `${declaration}.connector`) : null,
|
|
298
|
-
declaration:
|
|
299
|
-
preset === "google" && !GOOGLE_CURATED_SERVICES.has(name)
|
|
300
|
-
? declaredServiceOf(service.declaration, `${declaration}.declaration`)
|
|
301
|
-
: null,
|
|
124
|
+
connector: connectorOf(service.connector, `${declaration}.connector`),
|
|
302
125
|
};
|
|
303
126
|
}
|
|
304
127
|
|
|
305
128
|
function instanceOf(value, declaration) {
|
|
306
|
-
const instance = closed(value, ["id", "preset", "services"
|
|
307
|
-
const preset = declaredId(instance.preset, `${declaration}.preset`);
|
|
308
|
-
if (!PRESETS.has(preset)) refuse(`${declaration}.preset`);
|
|
309
|
-
if (preset !== "google" && instance.scopes !== undefined) refuse(`${declaration}.scopes`);
|
|
310
|
-
const scopes =
|
|
311
|
-
instance.scopes === undefined
|
|
312
|
-
? []
|
|
313
|
-
: textList(instance.scopes, `${declaration}.scopes`).map((scope, position) => {
|
|
314
|
-
if (!GOOGLE_API_SCOPE.test(scope)) refuse(`${declaration}.scopes[${position}]`);
|
|
315
|
-
return scope;
|
|
316
|
-
});
|
|
129
|
+
const instance = closed(value, ["id", "preset", "services"], declaration);
|
|
317
130
|
const services = filled(instance.services, `${declaration}.services`).map((service, position) =>
|
|
318
|
-
serviceOf(service, `${declaration}.services[${position}]
|
|
131
|
+
serviceOf(service, `${declaration}.services[${position}]`),
|
|
319
132
|
);
|
|
320
133
|
services.forEach((service, position) => {
|
|
321
134
|
const first = services.findIndex((candidate) => candidate.service === service.service);
|
|
322
135
|
if (first !== position) refuse(`${declaration}.services[${position}].service`);
|
|
323
136
|
});
|
|
324
|
-
|
|
325
|
-
if (
|
|
326
|
-
service.declaration !== null &&
|
|
327
|
-
service.declaration.scopes.some((scope) => !scopes.includes(scope))
|
|
328
|
-
) {
|
|
329
|
-
refuse(`${declaration}.services[${position}].declaration.scopes`);
|
|
330
|
-
}
|
|
331
|
-
});
|
|
332
|
-
return {
|
|
333
|
-
id: declaredId(instance.id, `${declaration}.id`),
|
|
334
|
-
preset,
|
|
335
|
-
services,
|
|
336
|
-
...(preset === "google" ? { scopes: [...new Set(scopes)] } : {}),
|
|
337
|
-
};
|
|
137
|
+
return { id: declaredId(instance.id, `${declaration}.id`), preset: instance.preset, services };
|
|
338
138
|
}
|
|
339
139
|
|
|
340
140
|
function absolutePath(value, declaration) {
|
|
@@ -388,6 +188,7 @@ export function parseConfiguration(document) {
|
|
|
388
188
|
"migrators",
|
|
389
189
|
"clients",
|
|
390
190
|
"host",
|
|
191
|
+
"skills",
|
|
391
192
|
],
|
|
392
193
|
"configuration",
|
|
393
194
|
);
|
|
@@ -397,10 +198,12 @@ export function parseConfiguration(document) {
|
|
|
397
198
|
if (!EXECUTION_AUTHORITIES.includes(declared.execution_authority)) {
|
|
398
199
|
refuse("execution_authority");
|
|
399
200
|
}
|
|
201
|
+
const skills = declared.skills === undefined ? true : declared.skills;
|
|
202
|
+
if (typeof skills !== "boolean") refuse("skills");
|
|
400
203
|
if (!Array.isArray(declared.instances)) refuse("instances");
|
|
401
204
|
if (!Array.isArray(declared.migrators)) refuse("migrators");
|
|
402
|
-
const instances = declared.instances.
|
|
403
|
-
instanceOf(instance, `instances[${position}]`),
|
|
205
|
+
const instances = declared.instances.flatMap((instance, position) =>
|
|
206
|
+
instance?.preset === "custom" ? [instanceOf(instance, `instances[${position}]`)] : [],
|
|
404
207
|
);
|
|
405
208
|
instances.forEach((instance, position) => {
|
|
406
209
|
const first = instances.findIndex((candidate) => candidate.id === instance.id);
|
|
@@ -428,6 +231,7 @@ export function parseConfiguration(document) {
|
|
|
428
231
|
migrators,
|
|
429
232
|
clients,
|
|
430
233
|
host: hostOf(declared.host, "host"),
|
|
234
|
+
skills,
|
|
431
235
|
};
|
|
432
236
|
}
|
|
433
237
|
|
package/src/connector-login.js
CHANGED
|
@@ -1,91 +1,10 @@
|
|
|
1
1
|
import { readConfiguration, sourceInstance } from "./configuration.js";
|
|
2
2
|
import { authorizeCustom, customAuthorizationStatus } from "./custom/authorization.js";
|
|
3
|
-
import { googleAuthorization, authorizeGoogle, GOOGLE_SCOPES } from "./google/oauth.js";
|
|
4
|
-
import { KitRefusal } from "./refusal.js";
|
|
5
3
|
|
|
6
|
-
function
|
|
7
|
-
const curated = GOOGLE_SCOPES[service.service];
|
|
8
|
-
return curated === undefined ? service.declaration.scopes : [curated];
|
|
9
|
-
}
|
|
10
|
-
|
|
11
|
-
function googleServiceAuthorized(authorization, scopes) {
|
|
12
|
-
return authorization.grants.some((grant) =>
|
|
13
|
-
scopes.every((scope) => grant.scopes.includes(scope)),
|
|
14
|
-
);
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
function googleConsent(service, context) {
|
|
18
|
-
return async ({ url }) => {
|
|
19
|
-
const collected = await context.present(
|
|
20
|
-
{
|
|
21
|
-
steps: [
|
|
22
|
-
{ kind: "visit", label: `Sign in to Google and allow access for ${service.service}`, url },
|
|
23
|
-
{
|
|
24
|
-
kind: "collect",
|
|
25
|
-
label: "The address your browser ended on",
|
|
26
|
-
name: "address",
|
|
27
|
-
description:
|
|
28
|
-
"After you allow access, Google sends your browser to a 127.0.0.1 address that does not open. Copy that whole address from the address bar and paste it here.",
|
|
29
|
-
},
|
|
30
|
-
],
|
|
31
|
-
},
|
|
32
|
-
context.signal,
|
|
33
|
-
);
|
|
34
|
-
return collected.address;
|
|
35
|
-
};
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
const CONNECTOR_LOGINS = {
|
|
39
|
-
custom: {
|
|
40
|
-
status: customAuthorizationStatus,
|
|
41
|
-
login: authorizeCustom,
|
|
42
|
-
},
|
|
43
|
-
google: {
|
|
44
|
-
status: async (instance, context) => {
|
|
45
|
-
const authorization = await googleAuthorization(context.directory, instance.id);
|
|
46
|
-
if (authorization === null) return false;
|
|
47
|
-
return instance.services.every((service) =>
|
|
48
|
-
googleServiceAuthorized(authorization, googleServiceScopes(service)),
|
|
49
|
-
);
|
|
50
|
-
},
|
|
51
|
-
guided: async (instance, context) => {
|
|
52
|
-
for (const service of instance.services) {
|
|
53
|
-
try {
|
|
54
|
-
await authorizeGoogle(
|
|
55
|
-
{
|
|
56
|
-
directory: context.directory,
|
|
57
|
-
instance: instance.id,
|
|
58
|
-
client: context.dependencies.googleOAuthClient(),
|
|
59
|
-
scopes: googleServiceScopes(service),
|
|
60
|
-
approve: googleConsent(service, context),
|
|
61
|
-
},
|
|
62
|
-
context.dependencies.googleDependencies ?? {},
|
|
63
|
-
);
|
|
64
|
-
} catch (error) {
|
|
65
|
-
if (context.signal.aborted) return "cancelled";
|
|
66
|
-
if (error instanceof KitRefusal && error.code === "google_authorization_declined") {
|
|
67
|
-
return "cancelled";
|
|
68
|
-
}
|
|
69
|
-
return "failed";
|
|
70
|
-
}
|
|
71
|
-
}
|
|
72
|
-
return "ready";
|
|
73
|
-
},
|
|
74
|
-
},
|
|
75
|
-
};
|
|
76
|
-
|
|
77
|
-
export function connectorLogin(instance, dependencies = {}) {
|
|
78
|
-
return { ...CONNECTOR_LOGINS, ...(dependencies.connectorLogins ?? {}) }[instance.preset];
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
export async function signInConnector(options, dependencies = {}) {
|
|
4
|
+
export async function signInConnector(options) {
|
|
82
5
|
const configuration = await readConfiguration(options.configuration);
|
|
83
6
|
const instance = sourceInstance(configuration, options.instance);
|
|
84
|
-
const gateway = connectorLogin(instance, dependencies);
|
|
85
|
-
if (gateway.login === undefined) {
|
|
86
|
-
throw new KitRefusal("kit_connector_login_guided", `${instance.id} signs in through House setup`);
|
|
87
|
-
}
|
|
88
7
|
const context = { directory: options.directory, signal: options.signal };
|
|
89
|
-
if (await
|
|
90
|
-
return (await
|
|
8
|
+
if (await customAuthorizationStatus(instance, context)) return "skipped";
|
|
9
|
+
return (await authorizeCustom(instance, context)) ? "ready" : "needs_attention";
|
|
91
10
|
}
|
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 = "
|
|
3
|
+
export const KIT_CONTRACT_VERSION = "3";
|
|
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;
|
|
@@ -21,10 +21,11 @@ export const COMMAND_ADAPTER_SESSION_TIMEOUT_MS = 30_000;
|
|
|
21
21
|
export const WORKER_EXIT_GRACE_MS = 5_000;
|
|
22
22
|
export const WORKER_EXIT_POLL_MS = 100;
|
|
23
23
|
export const WORKER_SUPERVISION_POLL_MS = 2_000;
|
|
24
|
-
export const WORKER_COMMAND_POLL_MS = 2_000;
|
|
25
|
-
export const WORKER_HEARTBEAT_MS = 30_000;
|
|
26
24
|
export const WORKER_COMMAND_BATCH_MAX = 10;
|
|
27
25
|
export const WORKER_RUN_TOKEN_MARGIN_MS = 60_000;
|
|
26
|
+
export const KIT_STREAM_RECONNECT_MS = 1_000;
|
|
27
|
+
export const KIT_STREAM_RECONNECT_MAX_MS = 30_000;
|
|
28
|
+
export const KIT_STREAM_REJOIN_MS = 2_000;
|
|
28
29
|
export const TELEGRAM_IMAGE_UPLOAD_CEILING_BYTES = 10 * 1024 * 1024;
|
|
29
30
|
export const CONVERSATION_FILE_TRANSFER_TIMEOUT_MS = 30_000;
|
|
30
31
|
export const WORKER_INHERITED_ENVIRONMENT = ["PATH", "HOME"];
|
|
@@ -40,17 +41,15 @@ export function runOutcomePath(run) {
|
|
|
40
41
|
return `/kit/runs/${encodeURIComponent(run)}/outcome`;
|
|
41
42
|
}
|
|
42
43
|
|
|
44
|
+
export function runRequestPath(run) {
|
|
45
|
+
return `/kit/runs/${encodeURIComponent(run)}/request`;
|
|
46
|
+
}
|
|
47
|
+
|
|
43
48
|
export const KIT_SESSIONS_REPORT_PATH = "/kit/sessions/report";
|
|
44
49
|
export const KIT_SESSIONS_REPORT_MAX = 256;
|
|
45
50
|
|
|
46
|
-
export const ASSISTANT_TEXT_MAX_BYTES = 4096;
|
|
47
|
-
export const ASSISTANT_BLOCKS_MAX = 500;
|
|
48
51
|
export const ASSISTANT_TABLE_COLUMNS_MAX = 20;
|
|
49
52
|
|
|
50
|
-
export function assistantDraftsPath(workerSession) {
|
|
51
|
-
return `/kit/sessions/${encodeURIComponent(workerSession)}/drafts`;
|
|
52
|
-
}
|
|
53
|
-
|
|
54
53
|
export function assistantTextPath(workerSession) {
|
|
55
54
|
return `/kit/sessions/${encodeURIComponent(workerSession)}/assistant-messages`;
|
|
56
55
|
}
|
|
@@ -61,6 +60,8 @@ export const TELEGRAM_DELIVERY_BATCH_MAX = 10;
|
|
|
61
60
|
export const TELEGRAM_DOWNLOAD_CEILING_BYTES = 20 * 1024 * 1024;
|
|
62
61
|
export const TELEGRAM_BOT_API_TIMEOUT_MS = 30_000;
|
|
63
62
|
export const TELEGRAM_GATEWAY_POLL_MS = 2_000;
|
|
63
|
+
export const TELEGRAM_RICH_MESSAGE_CHARACTERS_MAX = 32_768;
|
|
64
|
+
export const TELEGRAM_RICH_MESSAGE_BLOCKS_MAX = 500;
|
|
64
65
|
export const TELEGRAM_CONTROL_KEYBOARD_COMMANDS = ["/stop", "/kill"];
|
|
65
66
|
export const TELEGRAM_MEDIA_KINDS = [
|
|
66
67
|
"document",
|
|
@@ -114,6 +115,10 @@ export const BRIDGE_NONCE_ENVIRONMENT = "HOUSE_KIT_BRIDGE_NONCE";
|
|
|
114
115
|
export const BRIDGE_RECONNECT_MS = 200;
|
|
115
116
|
export const BRIDGE_RECONNECT_MAX_MS = 5_000;
|
|
116
117
|
|
|
118
|
+
export const HOUSE_CLI_LINE = "The agents.house house CLI is available: run house --help.";
|
|
119
|
+
export const HOW_WE_WORK_PATH = "/private/library/how-we-work.md";
|
|
120
|
+
export const SHELL_RENDER = "shell/1";
|
|
121
|
+
|
|
117
122
|
export const ACP_PROTOCOL = 1;
|
|
118
123
|
export const ACP_AUTH_REQUIRED = -32000;
|
|
119
124
|
export const ADAPTER_EXIT_GRACE_MS = 2_000;
|
|
@@ -195,7 +200,7 @@ export const ADAPTER_CONTRACTS = Object.freeze({
|
|
|
195
200
|
guidedLogin: CLAUDE_PASTED_CODE,
|
|
196
201
|
identity: Object.freeze({ agentInfo: "@agentclientprotocol/claude-agent-acp" }),
|
|
197
202
|
nativeQuestion: null,
|
|
198
|
-
sessionLoad:
|
|
203
|
+
sessionLoad: true,
|
|
199
204
|
sessionConfig: Object.freeze({ model: "model", effort: "effort" }),
|
|
200
205
|
capabilities: Object.freeze({
|
|
201
206
|
field_kinds: ELICITATION_FIELD_KINDS,
|
|
@@ -251,6 +256,10 @@ export const KIT_LOGIN_REPORT_PATH = "/kit/logins/report";
|
|
|
251
256
|
export const GUIDED_LOGIN_TIMEOUT_MS = 10 * 60 * 1000;
|
|
252
257
|
export const GUIDED_LOGIN_OUTPUT_MAX_BYTES = 64 * 1024;
|
|
253
258
|
|
|
259
|
+
export const KIT_SOURCES_DESIRED_PATH = "/kit/sources/desired";
|
|
260
|
+
export const KIT_SOURCES_REPORT_PATH = "/kit/sources/report";
|
|
261
|
+
export const SOURCE_CAPTURE_INTERVAL_MS = 15 * 60 * 1000;
|
|
262
|
+
|
|
254
263
|
export const EXECUTION_AUTHORITIES = ["allow", "refuse"];
|
|
255
264
|
|
|
256
265
|
export const PERMISSION_OPTION_KINDS = Object.freeze({
|
|
@@ -288,9 +297,25 @@ export const KIT_DOOR_DISCOVER_PATH = "/kit/door/discover";
|
|
|
288
297
|
export const KIT_DOOR_BOOTSTRAP_PATH = "/kit/door/bootstrap";
|
|
289
298
|
export const KIT_DOOR_ENUMERATE_PATH = "/kit/door/enumerate";
|
|
290
299
|
export const KIT_DOOR_BATCH_PATH = "/kit/door/batch";
|
|
291
|
-
export const
|
|
300
|
+
export const KIT_DOOR_REVISIONS_PATH = "/kit/door/revisions";
|
|
301
|
+
export const EXPLICIT_SYNC_VERSION = "explicit-sync/2";
|
|
292
302
|
export const KIT_DOOR_UNMOUNT_PATH = "/kit/door/unmount";
|
|
293
303
|
|
|
304
|
+
export const KIT_WORKING_COPY_SELECTION_PATH = "/kit/working-copy/selection";
|
|
305
|
+
export const WORKING_COPY_VERSION = "working-copy-state/3";
|
|
306
|
+
export const WORKING_COPIES_HOME = "working-copies";
|
|
307
|
+
export const WORKING_COPY_ROOM_HOMES = ["capture", "library", "collaboration"];
|
|
308
|
+
export const WORKING_COPY_PRIVATE_HOMES = ["library", "collaboration", "rooms", "agents", "house"];
|
|
309
|
+
export const WORKING_COPY_RECEIVED_REF = "refs/house/received";
|
|
310
|
+
export const WORKING_COPY_BRANCH = "main";
|
|
311
|
+
export const ROOM_REFERENCE = /^r_[0-9a-z]+\.[0-9a-z]$/;
|
|
312
|
+
export const WORKING_COPY_PUSH_METHOD = "house/git/push";
|
|
313
|
+
export const WORKING_COPY_INDEX_METHOD = "house/git/index";
|
|
314
|
+
export const WORKING_COPY_PUSH_HELP =
|
|
315
|
+
"Submit a Room commit to House; default HEAD. Use --owner only outside an Agent Session. Native git push is not a House remote.";
|
|
316
|
+
export const WORKING_COPY_UPLOAD_COMMAND = "prepare_edit_upload";
|
|
317
|
+
export const MCP_REQUEST_BODY_MAX_BYTES = 4 * 1024 * 1024;
|
|
318
|
+
|
|
294
319
|
export const MIGRATOR_CONTRACT = "kit-migrator/1";
|
|
295
320
|
export const MIGRATOR_CATEGORY = "migrator";
|
|
296
321
|
export const MIGRATOR_MANIFEST = "migrator.json";
|
package/src/delivery.js
CHANGED
|
@@ -54,10 +54,8 @@ const FAILURE_CATEGORIES = {
|
|
|
54
54
|
google_provider_unavailable: "provider",
|
|
55
55
|
google_provider_response_invalid: "provider",
|
|
56
56
|
google_checkpoint_invalid: "provider",
|
|
57
|
-
google_service_unsupported: "config",
|
|
58
|
-
google_oauth_client_unconfigured: "config",
|
|
59
|
-
google_drive_selection_exceeded: "config",
|
|
60
57
|
google_drive_item_missing: "provider",
|
|
58
|
+
api_disabled: "config",
|
|
61
59
|
};
|
|
62
60
|
|
|
63
61
|
export function fileDescriptor(file) {
|
|
@@ -184,8 +182,7 @@ export function stallOf(code, houseRetry = null) {
|
|
|
184
182
|
|
|
185
183
|
export function healthOfRun(stall) {
|
|
186
184
|
if (stall === null) return { state: "ok", category: null };
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
};
|
|
185
|
+
const category = stall.category ?? FAILURE_CATEGORIES[stall.code] ?? "internal";
|
|
186
|
+
if (stall.disposition === "retry") return { state: "retrying", category };
|
|
187
|
+
return { state: "failed", category, cause: stall.code };
|
|
191
188
|
}
|
package/src/directory.js
CHANGED
|
@@ -1,10 +1,8 @@
|
|
|
1
1
|
import { constants } from "node:fs";
|
|
2
|
-
import { access, mkdir, realpath,
|
|
3
|
-
import {
|
|
4
|
-
import { dirname, isAbsolute, join, relative, resolve, sep } from "node:path";
|
|
2
|
+
import { access, mkdir, realpath, stat } from "node:fs/promises";
|
|
3
|
+
import { dirname, isAbsolute, relative, resolve, sep } from "node:path";
|
|
5
4
|
import { LAUNCH_DIRECTORY_BASE } from "./contract.js";
|
|
6
5
|
import { KitRefusal } from "./refusal.js";
|
|
7
|
-
import { seedStarterSet } from "./starter-set.js";
|
|
8
6
|
|
|
9
7
|
export function launchBase(dependencies = {}) {
|
|
10
8
|
return dependencies.launchBase ?? LAUNCH_DIRECTORY_BASE;
|
|
@@ -39,25 +37,9 @@ function unavailable(path, cause) {
|
|
|
39
37
|
return new KitRefusal("kit_launch_directory_unavailable", `${path} ${cause}`);
|
|
40
38
|
}
|
|
41
39
|
|
|
42
|
-
async function
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
} catch {
|
|
46
|
-
return false;
|
|
47
|
-
}
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
async function seedDefaultDirectory(selected, base, path) {
|
|
51
|
-
const staging = join(base, `.${randomUUID()}.staging`);
|
|
52
|
-
try {
|
|
53
|
-
await seedStarterSet(staging);
|
|
54
|
-
await rename(staging, path);
|
|
55
|
-
} catch (error) {
|
|
56
|
-
await rm(staging, { recursive: true, force: true }).catch(() => undefined);
|
|
57
|
-
if (!(await isDirectory(path))) {
|
|
58
|
-
throw unavailable(selected, `could not be prepared (${error.code ?? "unknown"})`);
|
|
59
|
-
}
|
|
60
|
-
}
|
|
40
|
+
async function createDefaultDirectory(selected, path) {
|
|
41
|
+
const refused = await made(path);
|
|
42
|
+
if (refused !== null) throw unavailable(selected, `could not be created (${refused})`);
|
|
61
43
|
}
|
|
62
44
|
|
|
63
45
|
function within(base, selected) {
|
|
@@ -73,9 +55,7 @@ export async function readyLaunchDirectory(selected, base, agentId = null, optio
|
|
|
73
55
|
if (options.container && !within(resolve(base), path)) {
|
|
74
56
|
throw unavailable(selected, `resolves outside ${base}`);
|
|
75
57
|
}
|
|
76
|
-
if (path === defaultDirectory(base, agentId)
|
|
77
|
-
await seedDefaultDirectory(selected, base, path);
|
|
78
|
-
}
|
|
58
|
+
if (path === defaultDirectory(base, agentId)) await createDefaultDirectory(selected, path);
|
|
79
59
|
let described;
|
|
80
60
|
try {
|
|
81
61
|
described = await stat(path);
|
package/src/draft.js
CHANGED
|
@@ -1,89 +1,11 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
3
|
-
const DRAFT_INTERVAL_MS = 500;
|
|
1
|
+
import { pacedLatest } from "./pacing.js";
|
|
4
2
|
|
|
5
3
|
export function observedAssistantDrafts(options) {
|
|
6
|
-
const
|
|
7
|
-
const now = options.now ?? (() => Date.now());
|
|
8
|
-
let timer = null;
|
|
9
|
-
let sentAt = null;
|
|
10
|
-
let sent = null;
|
|
11
|
-
let latest = null;
|
|
12
|
-
|
|
13
|
-
function write() {
|
|
14
|
-
timer = null;
|
|
15
|
-
if (latest === null || latest === sent) return;
|
|
16
|
-
sent = latest;
|
|
17
|
-
sentAt = now();
|
|
18
|
-
options.send(sent);
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
function cancel() {
|
|
22
|
-
if (timer === null) return;
|
|
23
|
-
clearTimeout(timer);
|
|
24
|
-
timer = null;
|
|
25
|
-
}
|
|
26
|
-
|
|
4
|
+
const paced = pacedLatest(options);
|
|
27
5
|
return {
|
|
28
6
|
observe(view) {
|
|
29
|
-
if (typeof view
|
|
30
|
-
latest = view;
|
|
31
|
-
if (timer !== null) return;
|
|
32
|
-
const wait = sentAt === null ? 0 : sentAt + intervalMs - now();
|
|
33
|
-
if (wait <= 0) {
|
|
34
|
-
write();
|
|
35
|
-
return;
|
|
36
|
-
}
|
|
37
|
-
timer = setTimeout(write, wait);
|
|
38
|
-
timer.unref?.();
|
|
39
|
-
},
|
|
40
|
-
complete(view) {
|
|
41
|
-
if (typeof view !== "string" || view === "") return;
|
|
42
|
-
latest = view;
|
|
43
|
-
cancel();
|
|
44
|
-
write();
|
|
45
|
-
},
|
|
46
|
-
close: cancel,
|
|
47
|
-
};
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
export function openAssistantDrafts(options) {
|
|
51
|
-
let pending = null;
|
|
52
|
-
let sending = null;
|
|
53
|
-
let sent = null;
|
|
54
|
-
let closed = false;
|
|
55
|
-
|
|
56
|
-
function pump() {
|
|
57
|
-
if (sending !== null || pending === null) return;
|
|
58
|
-
const view = pending;
|
|
59
|
-
pending = null;
|
|
60
|
-
sent = view.text;
|
|
61
|
-
let started;
|
|
62
|
-
try {
|
|
63
|
-
started = Promise.resolve(options.send(view.blocks));
|
|
64
|
-
} catch {
|
|
65
|
-
started = Promise.resolve();
|
|
66
|
-
}
|
|
67
|
-
sending = started
|
|
68
|
-
.catch(() => undefined)
|
|
69
|
-
.finally(() => {
|
|
70
|
-
sending = null;
|
|
71
|
-
pump();
|
|
72
|
-
});
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
return {
|
|
76
|
-
update(text) {
|
|
77
|
-
if (closed || typeof text !== "string" || text === "") return;
|
|
78
|
-
if (text === sent || text === pending?.text) return;
|
|
79
|
-
const blocks = assistantBlocks(text);
|
|
80
|
-
if (blocks === null || !withinAssistantBound(blocksText(blocks))) return;
|
|
81
|
-
pending = { text, blocks };
|
|
82
|
-
pump();
|
|
83
|
-
},
|
|
84
|
-
close() {
|
|
85
|
-
closed = true;
|
|
86
|
-
pump();
|
|
7
|
+
if (typeof view === "string" && view !== "") paced.observe(view);
|
|
87
8
|
},
|
|
9
|
+
close: paced.close,
|
|
88
10
|
};
|
|
89
11
|
}
|