@agentshouse/kit 0.2.1-alpha.1 → 0.2.1-alpha.11

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.
Files changed (110) hide show
  1. package/README.md +20 -2
  2. package/dist/acp.js +3 -3
  3. package/dist/agents.js +6 -0
  4. package/dist/api.js +6 -1
  5. package/dist/authority-main.js +22 -0
  6. package/dist/bootstrap.json +28 -0
  7. package/dist/bridge.js +198 -46
  8. package/dist/clis.js +16 -1
  9. package/dist/configure-main.js +6 -0
  10. package/dist/conversations.js +97 -20
  11. package/dist/copies.js +809 -0
  12. package/dist/enrol-main.js +4 -0
  13. package/dist/git-main.js +153 -0
  14. package/dist/git.js +81 -0
  15. package/dist/home.js +19 -6
  16. package/dist/house-main.js +90 -29
  17. package/dist/instructions.js +15 -10
  18. package/dist/kit-main.js +2 -0
  19. package/dist/login.js +6 -2
  20. package/dist/operation.js +12 -0
  21. package/dist/refusals.js +41 -0
  22. package/dist/resident.js +62 -7
  23. package/dist/sign-in.js +6 -2
  24. package/dist/skills.js +78 -0
  25. package/dist/translate.js +51 -0
  26. package/dist/update.js +116 -0
  27. package/how-we-work.md +23 -0
  28. package/package.json +11 -4
  29. package/skills/ask-matt/LICENSE +21 -0
  30. package/skills/ask-matt/PHASE-BOUNDARIES.md +55 -0
  31. package/skills/ask-matt/SKILL.md +91 -0
  32. package/skills/ask-matt/agents/openai.yaml +4 -0
  33. package/skills/code-review/LICENSE +21 -0
  34. package/skills/code-review/SKILL.md +89 -0
  35. package/skills/code-review/agents/openai.yaml +3 -0
  36. package/skills/codebase-design/DEEPENING.md +37 -0
  37. package/skills/codebase-design/DESIGN-IT-TWICE.md +44 -0
  38. package/skills/codebase-design/LICENSE +21 -0
  39. package/skills/codebase-design/SKILL.md +116 -0
  40. package/skills/codebase-design/agents/openai.yaml +3 -0
  41. package/skills/diagnosing-bugs/LICENSE +21 -0
  42. package/skills/diagnosing-bugs/SKILL.md +140 -0
  43. package/skills/diagnosing-bugs/agents/openai.yaml +3 -0
  44. package/skills/diagnosing-bugs/scripts/hitl-loop.template.sh +44 -0
  45. package/skills/domain-modeling/ADR-FORMAT.md +47 -0
  46. package/skills/domain-modeling/CONTEXT-FORMAT.md +60 -0
  47. package/skills/domain-modeling/LICENSE +21 -0
  48. package/skills/domain-modeling/SKILL.md +76 -0
  49. package/skills/domain-modeling/agents/openai.yaml +3 -0
  50. package/skills/grill-me/LICENSE +21 -0
  51. package/skills/grill-me/SKILL.md +8 -0
  52. package/skills/grill-me/agents/openai.yaml +4 -0
  53. package/skills/grill-with-docs/LICENSE +21 -0
  54. package/skills/grill-with-docs/SKILL.md +8 -0
  55. package/skills/grill-with-docs/agents/openai.yaml +4 -0
  56. package/skills/grilling/LICENSE +21 -0
  57. package/skills/grilling/SKILL.md +30 -0
  58. package/skills/grilling/agents/openai.yaml +3 -0
  59. package/skills/handoff/LICENSE +21 -0
  60. package/skills/handoff/SKILL.md +17 -0
  61. package/skills/handoff/agents/openai.yaml +4 -0
  62. package/skills/implement/LICENSE +21 -0
  63. package/skills/implement/SKILL.md +16 -0
  64. package/skills/implement/agents/openai.yaml +4 -0
  65. package/skills/improve-codebase-architecture/HTML-REPORT.md +123 -0
  66. package/skills/improve-codebase-architecture/LICENSE +21 -0
  67. package/skills/improve-codebase-architecture/SKILL.md +72 -0
  68. package/skills/improve-codebase-architecture/agents/openai.yaml +4 -0
  69. package/skills/prototype/LICENSE +21 -0
  70. package/skills/prototype/LOGIC.md +67 -0
  71. package/skills/prototype/SKILL.md +28 -0
  72. package/skills/prototype/UI.md +112 -0
  73. package/skills/prototype/agents/openai.yaml +3 -0
  74. package/skills/research/LICENSE +21 -0
  75. package/skills/research/SKILL.md +14 -0
  76. package/skills/research/agents/openai.yaml +3 -0
  77. package/skills/resolving-merge-conflicts/LICENSE +21 -0
  78. package/skills/resolving-merge-conflicts/SKILL.md +16 -0
  79. package/skills/resolving-merge-conflicts/agents/openai.yaml +3 -0
  80. package/skills/tdd/LICENSE +21 -0
  81. package/skills/tdd/SKILL.md +40 -0
  82. package/skills/tdd/agents/openai.yaml +3 -0
  83. package/skills/tdd/mocking.md +59 -0
  84. package/skills/tdd/tests.md +77 -0
  85. package/skills/teach/GLOSSARY-FORMAT.md +35 -0
  86. package/skills/teach/LEARNING-RECORD-FORMAT.md +46 -0
  87. package/skills/teach/LICENSE +21 -0
  88. package/skills/teach/MISSION-FORMAT.md +31 -0
  89. package/skills/teach/RESOURCES-FORMAT.md +32 -0
  90. package/skills/teach/SKILL.md +141 -0
  91. package/skills/teach/agents/openai.yaml +4 -0
  92. package/skills/to-questionnaire/LICENSE +21 -0
  93. package/skills/to-questionnaire/SKILL.md +55 -0
  94. package/skills/to-questionnaire/agents/openai.yaml +4 -0
  95. package/skills/to-spec/LICENSE +21 -0
  96. package/skills/to-spec/SKILL.md +76 -0
  97. package/skills/to-spec/agents/openai.yaml +4 -0
  98. package/skills/to-tickets/LICENSE +21 -0
  99. package/skills/to-tickets/SKILL.md +106 -0
  100. package/skills/to-tickets/agents/openai.yaml +4 -0
  101. package/skills/wait-what/LICENSE +21 -0
  102. package/skills/wait-what/SKILL.md +8 -0
  103. package/skills/wait-what/agents/openai.yaml +4 -0
  104. package/skills/wayfinder/LICENSE +21 -0
  105. package/skills/wayfinder/SKILL.md +129 -0
  106. package/skills/wayfinder/agents/openai.yaml +4 -0
  107. package/skills/writing-for-agents/LICENSE +21 -0
  108. package/skills/writing-for-agents/SKILL-MECHANICS.md +22 -0
  109. package/skills/writing-for-agents/SKILL.md +83 -0
  110. package/skills/writing-for-agents/agents/openai.yaml +3 -0
@@ -9,11 +9,15 @@ import { CLIS } from './clis.js';
9
9
  import { placeFiles } from './files.js';
10
10
  import { instructions } from './instructions.js';
11
11
  import { holdSecretInput } from './secret-input.js';
12
+ import { createHowWeWork } from './skills.js';
12
13
  const LAUNCH_BASE = '/agents/house';
13
14
  const KILLED = 'the conversation was killed';
14
15
  function causeOf(error) {
15
16
  return error instanceof Error ? error.message : String(error);
16
17
  }
18
+ function answerMessage(request, response) {
19
+ return `The User answered a question you asked earlier.\nQuestion: ${JSON.stringify(request)}\nAnswer: ${JSON.stringify(response)}`;
20
+ }
17
21
  function logged(error) {
18
22
  process.stderr.write(`kit: ${causeOf(error)}\n`);
19
23
  }
@@ -32,15 +36,18 @@ function stop(bridge) {
32
36
  class Turn {
33
37
  id = randomUUID();
34
38
  text = '';
39
+ segment = null;
40
+ admitted = false;
41
+ notes = [];
35
42
  sent = [];
36
43
  unsentFrom = null;
37
44
  draftSequence = 0;
38
45
  planSequence = 0;
46
+ entries = null;
39
47
  questions = 0;
40
48
  secrets = 0;
41
49
  prompt = null;
42
50
  ended = false;
43
- ready = Promise.resolve();
44
51
  }
45
52
  class Conversation {
46
53
  id;
@@ -140,8 +147,13 @@ export class Conversations {
140
147
  }
141
148
  if (input.kind === 'option')
142
149
  await this.option(conversation, String(input.option), input.value);
143
- if (input.kind === 'answer')
144
- this.questions.get(String(input.interaction_id))?.answer(input.response);
150
+ if (input.kind === 'answer') {
151
+ const question = this.questions.get(String(input.interaction_id));
152
+ if (question === undefined) {
153
+ return this.message(conversation, { ...input, text: answerMessage(input.request, input.response), files: [], first: false });
154
+ }
155
+ question.answer(input.response);
156
+ }
145
157
  return {};
146
158
  }
147
159
  async open(conversation, input) {
@@ -166,7 +178,10 @@ export class Conversations {
166
178
  ack = { provider_session_id: opened };
167
179
  }
168
180
  if (input.first === true) {
169
- prompt.push({ type: 'text', text: await instructions(conversation.running.bridge, route.base_instructions) });
181
+ prompt.push({
182
+ type: 'text',
183
+ text: await instructions(conversation.running.bridge, route.base_instructions, await this.kit.copies.mapping()),
184
+ });
170
185
  }
171
186
  prompt.push({ type: 'text', text: String(input.text) });
172
187
  if (paths.length > 0)
@@ -239,14 +254,15 @@ export class Conversations {
239
254
  .onRequest('session/request_permission', ({ params, signal }) => this.ask(conversation, 'session/request_permission', params, false, signal))
240
255
  .onRequest('elicitation/create', ({ params, signal }) => this.ask(conversation, 'elicitation/create', params, asksSecret(params), signal));
241
256
  await unlessKilled(this.kit.agents.installed(), conversation.killed.signal);
242
- const bridge = await openBridge(this.kit.house, conversation.id, conversation.killed.signal);
257
+ const bridge = await openBridge(this.kit.house, this.kit.copies, conversation.id, conversation.killed.signal);
243
258
  if (conversation.kills > 0) {
244
259
  bridge.close();
245
260
  throw new Error(KILLED);
246
261
  }
247
262
  conversation.opening = bridge;
248
263
  try {
249
- const adapter = await startAdapter(route.kind, route.working_directory, app, (job) => this.job(conversation, job), { ...process.env, ...bridge.env });
264
+ await unlessKilled(createHowWeWork(bridge), conversation.killed.signal);
265
+ const adapter = await startAdapter(route.kind, route.working_directory, app, (job) => this.job(conversation, job), bridge.env);
250
266
  void adapter.exited.then(() => bridge.close());
251
267
  const agent = adapter.connection.agent;
252
268
  const cwd = route.working_directory;
@@ -259,6 +275,7 @@ export class Conversations {
259
275
  sessionId: opened.sessionId,
260
276
  killed: false,
261
277
  queues: CLIS[route.kind].queues,
278
+ phase: CLIS[route.kind].phase,
262
279
  };
263
280
  const options = await this.launchSettings(running, route, opened.configOptions ?? []);
264
281
  conversation.running = running;
@@ -340,15 +357,39 @@ export class Conversations {
340
357
  report(conversation) {
341
358
  const turn = new Turn();
342
359
  conversation.open++;
343
- turn.ready = this.deliver(conversation, turn, 'started', {}).then(() => undefined, logged);
360
+ void this.deliver(conversation, turn, 'started', {})
361
+ .then(() => this.admitted(conversation, turn))
362
+ .catch(logged);
344
363
  return turn;
345
364
  }
365
+ admitted(conversation, turn) {
366
+ turn.admitted = true;
367
+ for (const note of turn.notes.splice(0))
368
+ this.kit.send(note);
369
+ if (turn.text !== '') {
370
+ turn.unsentFrom = 0;
371
+ this.draft(conversation, turn);
372
+ }
373
+ if (turn.entries !== null)
374
+ this.plan(conversation, turn);
375
+ }
346
376
  begin(conversation) {
347
377
  const turn = this.report(conversation);
348
378
  conversation.turn = turn;
349
379
  this.kit.changed();
350
380
  return turn;
351
381
  }
382
+ finish(conversation, turn) {
383
+ if (turn.ended)
384
+ return;
385
+ const segment = turn.segment;
386
+ turn.segment = null;
387
+ if (segment?.phase === 'note')
388
+ this.note(conversation, turn, segment.text);
389
+ else if (segment !== null)
390
+ this.answer(conversation, turn, segment.text);
391
+ this.end(conversation, turn, { text: turn.text });
392
+ }
352
393
  end(conversation, turn, outcome) {
353
394
  if (turn.ended)
354
395
  return;
@@ -406,7 +447,7 @@ export class Conversations {
406
447
  this.end(conversation, turn, { failed });
407
448
  }
408
449
  else if (turn.prompt === sent) {
409
- this.end(conversation, turn, { text: turn.text });
450
+ this.finish(conversation, turn);
410
451
  }
411
452
  }
412
453
  started(conversation) {
@@ -423,7 +464,7 @@ export class Conversations {
423
464
  if (turn === null)
424
465
  return;
425
466
  if (turn.prompt === null) {
426
- this.end(conversation, turn, { text: turn.text });
467
+ this.finish(conversation, turn);
427
468
  }
428
469
  else {
429
470
  conversation.turn = null;
@@ -477,17 +518,21 @@ export class Conversations {
477
518
  update(conversation, notification) {
478
519
  const update = notification.update;
479
520
  if (update.sessionUpdate === 'agent_message_chunk' && update.content.type === 'text') {
480
- const turn = this.started(conversation);
481
- turn.text += update.content.text;
482
- const text = turn.text;
483
- void turn.ready.then(() => this.draft(conversation, turn, text));
521
+ this.chunk(conversation, this.started(conversation), update, update.content.text);
484
522
  }
485
523
  else if (update.sessionUpdate === 'plan') {
486
524
  const turn = this.started(conversation);
487
- void turn.ready.then(() => this.plan(conversation, turn, update.entries));
525
+ this.close(conversation, turn);
526
+ turn.entries = update.entries;
527
+ this.plan(conversation, turn);
528
+ }
529
+ else if (update.sessionUpdate === 'tool_call') {
530
+ this.close(conversation, this.started(conversation));
488
531
  }
489
- else if (update.sessionUpdate === 'agent_thought_chunk' || update.sessionUpdate === 'tool_call') {
490
- this.started(conversation);
532
+ else if (update.sessionUpdate === 'agent_thought_chunk') {
533
+ const turn = this.started(conversation);
534
+ if (turn.segment?.messageId !== (update.messageId ?? null))
535
+ this.close(conversation, turn);
491
536
  }
492
537
  else if (update.sessionUpdate === 'available_commands_update') {
493
538
  this.commands(conversation, update.availableCommands);
@@ -503,8 +548,40 @@ export class Conversations {
503
548
  conversation.jobs.delete(job.id);
504
549
  this.kit.changed();
505
550
  }
506
- draft(conversation, turn, text) {
507
- const blocks = blocksOf(text);
551
+ chunk(conversation, turn, chunk, text) {
552
+ const phase = conversation.running?.phase(chunk) ?? null;
553
+ const messageId = chunk.messageId ?? null;
554
+ if (turn.segment?.messageId !== messageId || turn.segment.phase !== phase)
555
+ this.close(conversation, turn);
556
+ if (phase === 'answer') {
557
+ this.answer(conversation, turn, text);
558
+ return;
559
+ }
560
+ turn.segment ??= { messageId, phase, text: '' };
561
+ turn.segment.text += text;
562
+ }
563
+ close(conversation, turn) {
564
+ const segment = turn.segment;
565
+ if (segment === null)
566
+ return;
567
+ turn.segment = null;
568
+ this.note(conversation, turn, segment.text);
569
+ }
570
+ note(conversation, turn, text) {
571
+ if (text.trim() === '')
572
+ return;
573
+ const note = { type: 'working-note', conversation_id: conversation.id, note_id: randomUUID(), text };
574
+ if (turn.admitted)
575
+ this.kit.send(note);
576
+ else
577
+ turn.notes.push(note);
578
+ }
579
+ answer(conversation, turn, text) {
580
+ turn.text += text;
581
+ this.draft(conversation, turn);
582
+ }
583
+ draft(conversation, turn) {
584
+ const blocks = blocksOf(turn.text);
508
585
  const from = Math.min(firstChange(turn.sent, blocks), turn.unsentFrom ?? Infinity);
509
586
  const sent = this.kit.send({
510
587
  type: 'draft',
@@ -523,14 +600,14 @@ export class Conversations {
523
600
  turn.unsentFrom = from;
524
601
  }
525
602
  }
526
- plan(conversation, turn, entries) {
603
+ plan(conversation, turn) {
527
604
  const sent = this.kit.send({
528
605
  type: 'plan',
529
606
  conversation_id: conversation.id,
530
607
  turn_id: turn.id,
531
608
  sequence: turn.planSequence + 1,
532
609
  from: 0,
533
- steps: entries.map((entry) => ({ label: entry.content, priority: entry.priority, status: entry.status })),
610
+ steps: turn.entries.map((entry) => ({ label: entry.content, priority: entry.priority, status: entry.status })),
534
611
  });
535
612
  if (sent)
536
613
  turn.planSequence++;