@agentshouse/kit 0.1.0-alpha.25 → 0.1.0-alpha.27

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 (117) hide show
  1. package/README.md +172 -158
  2. package/bin/connect-linux.sh +15 -4
  3. package/bin/kit.js +48 -46
  4. package/bootstrap.json +3 -3
  5. package/package.json +1 -1
  6. package/src/adapter-mcp.js +23 -1
  7. package/src/bridge.js +4 -0
  8. package/src/configuration.js +13 -209
  9. package/src/connector-login.js +3 -84
  10. package/src/contract.js +4 -0
  11. package/src/delivery.js +4 -7
  12. package/src/directory.js +6 -26
  13. package/src/google/calendar.js +39 -45
  14. package/src/google/drive.js +61 -186
  15. package/src/google/entries.js +346 -0
  16. package/src/google/gateway.js +3 -6
  17. package/src/google/gmail.js +33 -23
  18. package/src/google/oauth.js +106 -66
  19. package/src/google/source.js +21 -23
  20. package/src/house.js +43 -5
  21. package/src/how-we-work.md +25 -0
  22. package/src/kit-work-stream.js +1 -1
  23. package/src/launcher.js +11 -4
  24. package/src/mcp.js +5 -0
  25. package/src/setup.js +8 -14
  26. package/src/skill-set/ask-matt/PHASE-BOUNDARIES.md +55 -0
  27. package/src/skill-set/ask-matt/SKILL.md +91 -0
  28. package/src/skill-set/ask-matt/agents/openai.yaml +4 -0
  29. package/src/skill-set/code-review/LICENSE +21 -0
  30. package/src/skill-set/code-review/SKILL.md +89 -0
  31. package/src/skill-set/code-review/agents/openai.yaml +3 -0
  32. package/src/skill-set/codebase-design/DEEPENING.md +37 -0
  33. package/src/skill-set/codebase-design/DESIGN-IT-TWICE.md +44 -0
  34. package/src/skill-set/codebase-design/LICENSE +21 -0
  35. package/src/skill-set/codebase-design/SKILL.md +116 -0
  36. package/src/skill-set/codebase-design/agents/openai.yaml +3 -0
  37. package/src/skill-set/diagnosing-bugs/LICENSE +21 -0
  38. package/src/skill-set/diagnosing-bugs/SKILL.md +140 -0
  39. package/src/skill-set/diagnosing-bugs/agents/openai.yaml +3 -0
  40. package/src/skill-set/diagnosing-bugs/scripts/hitl-loop.template.sh +44 -0
  41. package/src/skill-set/domain-modeling/ADR-FORMAT.md +47 -0
  42. package/src/skill-set/domain-modeling/CONTEXT-FORMAT.md +60 -0
  43. package/src/skill-set/domain-modeling/LICENSE +21 -0
  44. package/src/skill-set/domain-modeling/SKILL.md +76 -0
  45. package/src/skill-set/domain-modeling/agents/openai.yaml +3 -0
  46. package/src/skill-set/grill-me/LICENSE +21 -0
  47. package/src/skill-set/grill-me/SKILL.md +8 -0
  48. package/src/skill-set/grill-me/agents/openai.yaml +4 -0
  49. package/src/skill-set/grill-with-docs/LICENSE +21 -0
  50. package/src/skill-set/grill-with-docs/SKILL.md +8 -0
  51. package/src/skill-set/grill-with-docs/agents/openai.yaml +4 -0
  52. package/src/skill-set/grilling/LICENSE +21 -0
  53. package/src/{starter-set → skill-set}/grilling/SKILL.md +1 -1
  54. package/src/skill-set/handoff/LICENSE +21 -0
  55. package/src/skill-set/handoff/SKILL.md +17 -0
  56. package/src/skill-set/handoff/agents/openai.yaml +4 -0
  57. package/src/skill-set/implement/LICENSE +21 -0
  58. package/src/skill-set/implement/SKILL.md +16 -0
  59. package/src/skill-set/implement/agents/openai.yaml +4 -0
  60. package/src/skill-set/improve-codebase-architecture/HTML-REPORT.md +123 -0
  61. package/src/skill-set/improve-codebase-architecture/LICENSE +21 -0
  62. package/src/skill-set/improve-codebase-architecture/SKILL.md +72 -0
  63. package/src/skill-set/improve-codebase-architecture/agents/openai.yaml +4 -0
  64. package/src/skill-set/prototype/LICENSE +21 -0
  65. package/src/skill-set/prototype/LOGIC.md +67 -0
  66. package/src/skill-set/prototype/SKILL.md +28 -0
  67. package/src/skill-set/prototype/UI.md +112 -0
  68. package/src/skill-set/prototype/agents/openai.yaml +3 -0
  69. package/src/skill-set/research/LICENSE +21 -0
  70. package/src/skill-set/research/SKILL.md +14 -0
  71. package/src/skill-set/research/agents/openai.yaml +3 -0
  72. package/src/skill-set/resolving-merge-conflicts/LICENSE +21 -0
  73. package/src/skill-set/resolving-merge-conflicts/SKILL.md +16 -0
  74. package/src/skill-set/resolving-merge-conflicts/agents/openai.yaml +3 -0
  75. package/src/skill-set/tdd/LICENSE +21 -0
  76. package/src/skill-set/tdd/SKILL.md +40 -0
  77. package/src/skill-set/tdd/agents/openai.yaml +3 -0
  78. package/src/skill-set/tdd/mocking.md +59 -0
  79. package/src/skill-set/tdd/tests.md +77 -0
  80. package/src/skill-set/teach/GLOSSARY-FORMAT.md +35 -0
  81. package/src/skill-set/teach/LEARNING-RECORD-FORMAT.md +46 -0
  82. package/src/skill-set/teach/LICENSE +21 -0
  83. package/src/skill-set/teach/MISSION-FORMAT.md +31 -0
  84. package/src/skill-set/teach/RESOURCES-FORMAT.md +32 -0
  85. package/src/skill-set/teach/SKILL.md +141 -0
  86. package/src/skill-set/teach/agents/openai.yaml +4 -0
  87. package/src/skill-set/to-questionnaire/LICENSE +21 -0
  88. package/src/skill-set/to-questionnaire/SKILL.md +55 -0
  89. package/src/skill-set/to-questionnaire/agents/openai.yaml +4 -0
  90. package/src/skill-set/to-spec/LICENSE +21 -0
  91. package/src/skill-set/to-spec/SKILL.md +76 -0
  92. package/src/skill-set/to-spec/agents/openai.yaml +4 -0
  93. package/src/skill-set/to-tickets/LICENSE +21 -0
  94. package/src/skill-set/to-tickets/SKILL.md +106 -0
  95. package/src/skill-set/to-tickets/agents/openai.yaml +4 -0
  96. package/src/skill-set/wait-what/LICENSE +21 -0
  97. package/src/skill-set/wait-what/SKILL.md +8 -0
  98. package/src/skill-set/wait-what/agents/openai.yaml +4 -0
  99. package/src/skill-set/wayfinder/LICENSE +21 -0
  100. package/src/skill-set/wayfinder/SKILL.md +129 -0
  101. package/src/skill-set/wayfinder/agents/openai.yaml +4 -0
  102. package/src/skill-set/writing-for-agents/LICENSE +21 -0
  103. package/src/skill-set/writing-for-agents/SKILL-MECHANICS.md +22 -0
  104. package/src/skill-set/writing-for-agents/SKILL.md +83 -0
  105. package/src/skill-set/writing-for-agents/agents/openai.yaml +3 -0
  106. package/src/skill-set.js +85 -0
  107. package/src/source.js +51 -26
  108. package/src/state.js +19 -1
  109. package/src/tasks.js +72 -0
  110. package/src/worker.js +46 -68
  111. package/src/working-copy.js +1 -15
  112. package/src/google/declared.js +0 -146
  113. package/src/google/id.js +0 -1
  114. package/src/instance/google.js +0 -1
  115. package/src/starter-set.js +0 -17
  116. /package/src/{starter-set/grilling → skill-set/ask-matt}/LICENSE +0 -0
  117. /package/src/{starter-set → skill-set}/grilling/agents/openai.yaml +0 -0
package/src/tasks.js ADDED
@@ -0,0 +1,72 @@
1
+ import { setTimeout as delay } from "node:timers/promises";
2
+
3
+ export function coalescedTask(signal, fail, work) {
4
+ let pending = false;
5
+ let task = null;
6
+ const trigger = () => {
7
+ pending = true;
8
+ if (task !== null) return;
9
+ task = (async () => {
10
+ while (pending && !signal.aborted) {
11
+ pending = false;
12
+ await work();
13
+ }
14
+ })()
15
+ .catch((error) => {
16
+ if (signal.aborted) return;
17
+ fail(error);
18
+ })
19
+ .finally(() => {
20
+ task = null;
21
+ if (pending && !signal.aborted) trigger();
22
+ });
23
+ };
24
+ return { trigger, idle: () => task === null, settled: () => task };
25
+ }
26
+
27
+ export function residentWake() {
28
+ let pending = false;
29
+ let release = null;
30
+ return {
31
+ notify() {
32
+ pending = true;
33
+ release?.();
34
+ },
35
+ async wait(milliseconds, signal) {
36
+ if (pending) {
37
+ pending = false;
38
+ return;
39
+ }
40
+ const pause = new AbortController();
41
+ try {
42
+ await Promise.race([
43
+ new Promise((resolve) => {
44
+ release = resolve;
45
+ }),
46
+ delay(milliseconds, undefined, { signal: AbortSignal.any([signal, pause.signal]) }),
47
+ ]);
48
+ } catch (error) {
49
+ if (!signal.aborted) throw error;
50
+ } finally {
51
+ release = null;
52
+ pending = false;
53
+ pause.abort();
54
+ }
55
+ },
56
+ };
57
+ }
58
+
59
+ const turns = new Map();
60
+
61
+ export function exclusively(path, work) {
62
+ const turn = (turns.get(path) ?? Promise.resolve()).then(work);
63
+ const settled = turn.then(
64
+ () => undefined,
65
+ () => undefined,
66
+ );
67
+ turns.set(path, settled);
68
+ void settled.then(() => {
69
+ if (turns.get(path) === settled) turns.delete(path);
70
+ });
71
+ return turn;
72
+ }
package/src/worker.js CHANGED
@@ -1,5 +1,6 @@
1
1
  import { createHash, randomBytes } from "node:crypto";
2
2
  import { existsSync } from "node:fs";
3
+ import { homedir } from "node:os";
3
4
  import { join } from "node:path";
4
5
  import { setTimeout as delay } from "node:timers/promises";
5
6
  import { fileURLToPath } from "node:url";
@@ -17,9 +18,11 @@ import { retryConversationFiles } from "./conversation-originals.js";
17
18
  import { openAssistantDrafts } from "./draft.js";
18
19
  import { localRequest, reconcileInbound } from "./inbound.js";
19
20
  import { localFiles } from "./local-files.js";
20
- import { answerText, answerYaml } from "./mcp.js";
21
+ import { answerText, answerYaml, editRefusal } from "./mcp.js";
21
22
  import { inheritedEnvironment } from "./command.js";
23
+ import { sourceEntries } from "./google/entries.js";
22
24
  import { watchKitWork } from "./kit-work-stream.js";
25
+ import { coalescedTask, residentWake } from "./tasks.js";
23
26
  import {
24
27
  applyWorkingCopies,
25
28
  deliverWorkingCopies,
@@ -84,6 +87,7 @@ import {
84
87
  import { operationId } from "./operation.js";
85
88
  import { runSetup, signInWantedAgent } from "./setup.js";
86
89
  import { readSettlements, removeSettlement, writeSettlement } from "./settlement.js";
90
+ import { howWeWorkOwed, noteHowWeWork, reconcileSkillSet } from "./skill-set.js";
87
91
  import { writeText } from "./state.js";
88
92
  import { failedReport, terminalReport } from "./terminal.js";
89
93
  import {
@@ -285,13 +289,12 @@ function endOnEpochReport(ended, act) {
285
289
  }
286
290
 
287
291
  function refusedWith(text) {
288
- const conflicts = answerYaml(text.slice(text.indexOf("\n") + 1))?.conflicts;
289
- const current = Array.isArray(conflicts)
290
- ? conflicts.map(({ path, state, revision }) =>
291
- state === "absent" ? { path, revision: null, content: null } : { path, revision },
292
- )
293
- : null;
294
- return { refused: { code: text.split(":")[0].trim(), text, current } };
292
+ const { code, conflicts } = editRefusal(text);
293
+ const current =
294
+ conflicts?.map(({ path, state, revision }) =>
295
+ state === "absent" ? { path, revision: null, content: null } : { path, revision },
296
+ ) ?? null;
297
+ return { refused: { code, text, current } };
295
298
  }
296
299
 
297
300
  function acceptedWith(text) {
@@ -389,6 +392,10 @@ async function openRunBridge(context, bound, authority, start) {
389
392
  start,
390
393
  question: handed((batch) => admitInteraction(context.session, bound.session, batch)),
391
394
  plan: handed((snapshot) => admitPlanSnapshot(context.session, bound.session, snapshot)),
395
+ howWeWork: () =>
396
+ noteHowWeWork(context.directory).catch((error) =>
397
+ reported(`How-we-work note unwritable (${error.code ?? "unknown"})`),
398
+ ),
392
399
  interrupt: handed((interrupt, outcome) =>
393
400
  reportInterruptOutcome(context.session, interrupt, outcome),
394
401
  ),
@@ -576,6 +583,7 @@ async function prepareAssignment(context, assignment, resumed) {
576
583
  const authority = { token: assignment.session.token, expiresAt: assignment.session.expiresAt };
577
584
  const start = {
578
585
  base_instructions: assignment.baseInstructions,
586
+ create_how_we_work: await howWeWorkOwed(context.directory),
579
587
  working_directory: assignment.workingDirectory,
580
588
  working_copies: await appliedWorkingCopies(context),
581
589
  execution_authority: context.configuration.executionAuthority,
@@ -855,6 +863,7 @@ async function workerContext(options, dependencies, resident = false) {
855
863
  launchBase: launchBase(dependencies),
856
864
  container: dependencies.container ?? process.env.HOUSE_KIT_CONTAINER === "1",
857
865
  directory: options.directory,
866
+ home: dependencies.home ?? homedir(),
858
867
  files: { originals: [], failures: [] },
859
868
  epochReport: null,
860
869
  agentRefresh: Promise.resolve(),
@@ -903,6 +912,11 @@ function queueAgentRefresh(context, dependencies, signal, configuration, pointer
903
912
  async function controlledPass(context, dependencies, configuration, signal) {
904
913
  context.signal = signal;
905
914
  context.session.signal = signal;
915
+ await reconcileSkillSet({
916
+ directory: context.directory,
917
+ home: context.home,
918
+ accepted: configuration.skills,
919
+ });
906
920
  context.busy = true;
907
921
  try {
908
922
  return await afterEpochReport(context, () => workerPass(context, dependencies, configuration));
@@ -943,62 +957,6 @@ async function reportedWorkingCopies(act, context, signal) {
943
957
  }
944
958
  }
945
959
 
946
- function coalescedTask(signal, fail, work) {
947
- let pending = false;
948
- let task = null;
949
- const trigger = () => {
950
- pending = true;
951
- if (task !== null) return;
952
- task = (async () => {
953
- while (pending && !signal.aborted) {
954
- pending = false;
955
- await work();
956
- }
957
- })()
958
- .catch((error) => {
959
- if (signal.aborted) return;
960
- fail(error);
961
- })
962
- .finally(() => {
963
- task = null;
964
- if (pending && !signal.aborted) trigger();
965
- });
966
- };
967
- return { trigger, idle: () => task === null, settled: () => task };
968
- }
969
-
970
- function residentWake() {
971
- let pending = false;
972
- let release = null;
973
- return {
974
- notify() {
975
- pending = true;
976
- release?.();
977
- },
978
- async wait(milliseconds, signal) {
979
- if (pending) {
980
- pending = false;
981
- return;
982
- }
983
- const pause = new AbortController();
984
- try {
985
- await Promise.race([
986
- new Promise((resolve) => {
987
- release = resolve;
988
- }),
989
- delay(milliseconds, undefined, { signal: AbortSignal.any([signal, pause.signal]) }),
990
- ]);
991
- } catch (error) {
992
- if (!signal.aborted) throw error;
993
- } finally {
994
- release = null;
995
- pending = false;
996
- pause.abort();
997
- }
998
- },
999
- };
1000
- }
1001
-
1002
960
  function residentUpdate(context, wake) {
1003
961
  let requested = existsSync(updateDrain(context.directory));
1004
962
  let ready = null;
@@ -1066,6 +1024,7 @@ export async function runResident(options, dependencies = {}) {
1066
1024
  const wake = residentWake();
1067
1025
  const update = residentUpdate(context, wake);
1068
1026
  context.update = update;
1027
+ let sources = null;
1069
1028
  const served = await serveResident(
1070
1029
  session,
1071
1030
  context.directory,
@@ -1075,6 +1034,8 @@ export async function runResident(options, dependencies = {}) {
1075
1034
  pushWorkingCopy({ directory: context.directory, session }, request, ownerCaller(session), signal).catch(
1076
1035
  (error) => ({ refused: true, text: formatCommandError(error) }),
1077
1036
  ),
1037
+ (source) =>
1038
+ sources === null ? Promise.reject(new KitRefusal("kit_resident_unavailable")) : sources.capture(source),
1078
1039
  );
1079
1040
  const serve = async (signal) => {
1080
1041
  context.busy = true;
@@ -1137,13 +1098,24 @@ export async function runResident(options, dependencies = {}) {
1137
1098
  const deliveries = coalescedTask(signal, unavailable, () =>
1138
1099
  reportedWorkingCopies(deliverWorkingCopies, context, signal),
1139
1100
  );
1101
+ sources = sourceEntries({
1102
+ session: context.session,
1103
+ directory: context.directory,
1104
+ dependencies,
1105
+ signal: AbortSignal.any([signal, watcher.signal]),
1106
+ now: session.now,
1107
+ draining: () => update.requested,
1108
+ unavailable: (error) => reported(`google sources unavailable: ${error?.message ?? error}`),
1109
+ });
1110
+ await sources.start();
1140
1111
  const pointer = () => {
1141
1112
  if (!update.requested) agentRefresh.trigger();
1142
1113
  };
1143
- const available = (subject) => {
1114
+ const available = (subject = null) => {
1144
1115
  if (update.requested) return;
1145
- if (subject !== "working_copy") agentRefresh.trigger();
1146
- if (subject !== "agents") copies.trigger();
1116
+ if (subject === null || subject === "agents") agentRefresh.trigger();
1117
+ if (subject === null || subject === "working_copy") copies.trigger();
1118
+ if (subject === null || subject === "sources") sources.reconcile();
1147
1119
  };
1148
1120
  context.onIdle = pointer;
1149
1121
  context.workingCopiesApplied = copies.settled;
@@ -1168,7 +1140,12 @@ export async function runResident(options, dependencies = {}) {
1168
1140
  if (sessions.length > 0) update.answer({ ready: false, sessions });
1169
1141
  else if (
1170
1142
  session.refused ||
1171
- (!served.serving() && logins.size === 0 && agentRefresh.idle() && copies.idle() && deliveries.idle())
1143
+ (!served.serving() &&
1144
+ logins.size === 0 &&
1145
+ agentRefresh.idle() &&
1146
+ copies.idle() &&
1147
+ deliveries.idle() &&
1148
+ sources.idle())
1172
1149
  ) {
1173
1150
  return;
1174
1151
  }
@@ -1182,6 +1159,7 @@ export async function runResident(options, dependencies = {}) {
1182
1159
  await agentRefresh.settled();
1183
1160
  await copies.settled();
1184
1161
  await deliveries.settled();
1162
+ await sources.settled();
1185
1163
  for (const running of logins.values()) running.controller.abort();
1186
1164
  await Promise.all([...logins.values()].map((running) => running.task));
1187
1165
  await context.agentRefresh;
@@ -23,6 +23,7 @@ import { readNote, writeNote, writeText } from "./state.js";
23
23
  import { bootstrapBundle, discoveryOf, door, withSession } from "./sync.js";
24
24
  import { isGeneratedProvenance, sidecarPath, structuredOrReplace } from "./sync-library.js";
25
25
  import { locate, removeReplicaFile, writeReplicaFile } from "./sync-state.js";
26
+ import { exclusively } from "./tasks.js";
26
27
 
27
28
  const COMMITTER_NAME = "House Kit";
28
29
  const COMMITTER_EMAIL = "house-kit@localhost";
@@ -366,21 +367,6 @@ async function heldCopies(directory) {
366
367
  return held.filter((copy) => copy !== null);
367
368
  }
368
369
 
369
- const turns = new Map();
370
-
371
- function exclusively(path, work) {
372
- const turn = (turns.get(path) ?? Promise.resolve()).then(work);
373
- const settled = turn.then(
374
- () => undefined,
375
- () => undefined,
376
- );
377
- turns.set(path, settled);
378
- void settled.then(() => {
379
- if (turns.get(path) === settled) turns.delete(path);
380
- });
381
- return turn;
382
- }
383
-
384
370
  function received(scope, read, parents) {
385
371
  const files = read.files.filter((file) => file.writable);
386
372
  return { message: `House ${housePath(scope)} at position ${read.position}`, parents, files, whole: true };
@@ -1,146 +0,0 @@
1
- import { ITEM_BODY_MAX_BYTES } from "../contract.js";
2
- import { KitRefusal } from "../refusal.js";
3
- import { googleJson } from "./gateway.js";
4
-
5
- function valueAt(value, path) {
6
- let current = value;
7
- for (const segment of path.split(".")) {
8
- if (current === null || current === undefined || typeof current !== "object") return undefined;
9
- current = current[segment];
10
- }
11
- return current;
12
- }
13
-
14
- function requiredText(value, declaration) {
15
- if (typeof value !== "string" || value.length === 0) {
16
- throw new KitRefusal("google_provider_response_invalid", declaration);
17
- }
18
- return value;
19
- }
20
-
21
- function optionalText(value, declaration) {
22
- if (value === undefined || value === null) return null;
23
- return requiredText(value, declaration);
24
- }
25
-
26
- function cursorOf(value) {
27
- if (value === null) return { pageToken: null, checkpoint: null };
28
- let cursor;
29
- try {
30
- cursor = JSON.parse(value);
31
- } catch {
32
- throw new KitRefusal("google_checkpoint_invalid", "declared service");
33
- }
34
- if (
35
- typeof cursor !== "object" ||
36
- cursor === null ||
37
- (cursor.pageToken !== null && typeof cursor.pageToken !== "string") ||
38
- (cursor.checkpoint !== null && typeof cursor.checkpoint !== "string")
39
- ) {
40
- throw new KitRefusal("google_checkpoint_invalid", "declared service");
41
- }
42
- return cursor;
43
- }
44
-
45
- function composedBody(item, paths) {
46
- const parts = paths.map((path) => valueAt(item, path));
47
- if (parts.some((part) => !["string", "number", "boolean"].includes(typeof part))) {
48
- throw new KitRefusal("google_provider_response_invalid", "declared body");
49
- }
50
- const body = parts.map((part) => `${part}`).join("\n\n");
51
- if (Buffer.byteLength(body, "utf8") > ITEM_BODY_MAX_BYTES) {
52
- throw new KitRefusal("google_provider_response_invalid", "declared body");
53
- }
54
- return body;
55
- }
56
-
57
- function normalizedItem(service, item) {
58
- const fields = service.declaration.fields;
59
- const observedAt = requiredText(valueAt(item, fields.observedAt), "declared observed time");
60
- if (Number.isNaN(Date.parse(observedAt))) {
61
- throw new KitRefusal("google_provider_response_invalid", "declared observed time");
62
- }
63
- const container = requiredText(valueAt(item, fields.container), "declared container");
64
- const nativeVersion =
65
- fields.nativeVersion === null
66
- ? null
67
- : optionalText(valueAt(item, fields.nativeVersion), "declared native version");
68
- const providerModifiedAt =
69
- fields.providerModifiedAt === null
70
- ? null
71
- : optionalText(
72
- valueAt(item, fields.providerModifiedAt),
73
- "declared provider modification time",
74
- );
75
- if (providerModifiedAt !== null && Number.isNaN(Date.parse(providerModifiedAt))) {
76
- throw new KitRefusal("google_provider_response_invalid", "declared provider modification time");
77
- }
78
- return {
79
- namespace: `google/${service.service}`,
80
- nativeObjectId: requiredText(valueAt(item, fields.nativeId), "declared native id"),
81
- nativeVersion,
82
- providerModifiedAt:
83
- providerModifiedAt === null ? null : new Date(providerModifiedAt).toISOString(),
84
- observedAt: new Date(observedAt).toISOString(),
85
- body: composedBody(item, fields.body),
86
- author:
87
- fields.author === null
88
- ? null
89
- : optionalText(valueAt(item, fields.author), "declared author"),
90
- url:
91
- fields.url === null ? null : optionalText(valueAt(item, fields.url), "declared url"),
92
- attachments: [],
93
- container: `google/${service.service}/${container}`,
94
- };
95
- }
96
-
97
- export async function declaredPage(options, dependencies = {}) {
98
- const declared = options.service.declaration;
99
- const cursor = cursorOf(options.cursor);
100
- const url = new URL(declared.path, `https://${declared.host}`);
101
- for (const [name, value] of Object.entries(declared.query)) url.searchParams.set(name, value);
102
- url.searchParams.set(declared.pageSize, `${options.limit}`);
103
- if (cursor.pageToken !== null) {
104
- url.searchParams.set(declared.pageToken.request, cursor.pageToken);
105
- }
106
- if (cursor.checkpoint !== null) {
107
- url.searchParams.set(declared.pageToken.checkpointRequest, cursor.checkpoint);
108
- }
109
- const answer = await googleJson(
110
- {
111
- directory: options.directory,
112
- instance: options.instance,
113
- client: options.client,
114
- requiredScopes: declared.scopes,
115
- url: url.toString(),
116
- signal: options.signal,
117
- },
118
- dependencies,
119
- );
120
- const entries = valueAt(answer, declared.items);
121
- if (!Array.isArray(entries) || entries.length > options.limit) {
122
- throw new KitRefusal("google_provider_response_invalid", "declared items");
123
- }
124
- const pageToken = valueAt(answer, declared.pageToken.response);
125
- let next;
126
- if (pageToken !== undefined && pageToken !== null) {
127
- next = {
128
- pageToken: requiredText(pageToken, "declared page token"),
129
- checkpoint: cursor.checkpoint,
130
- };
131
- } else {
132
- next = {
133
- pageToken: null,
134
- checkpoint: requiredText(
135
- valueAt(answer, declared.pageToken.checkpointResponse),
136
- "declared checkpoint",
137
- ),
138
- };
139
- }
140
- return {
141
- items: entries.map((entry) => normalizedItem(options.service, entry)),
142
- dropped: [],
143
- cursor: JSON.stringify(next),
144
- more: pageToken !== undefined && pageToken !== null,
145
- };
146
- }
package/src/google/id.js DELETED
@@ -1 +0,0 @@
1
- export const GOOGLE_DRIVE_ID = /^[A-Za-z0-9_-]{1,512}$/;
@@ -1 +0,0 @@
1
- export const GOOGLE_OAUTH_CLIENT = Object.freeze({"id":"911965338518-867gdvuddb7kdkjo3qvpv6gds369alb7.apps.googleusercontent.com","secret":"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"});
@@ -1,17 +0,0 @@
1
- import { cp, mkdir, symlink, writeFile } from "node:fs/promises";
2
- import { join } from "node:path";
3
- import { fileURLToPath } from "node:url";
4
-
5
- const AGENTS_INSTRUCTION = "The agents.house `house` CLI is available: run `house --help`.\n";
6
- const GRILLING_SOURCE = fileURLToPath(new URL("starter-set/grilling/", import.meta.url));
7
-
8
- export async function seedStarterSet(target) {
9
- await mkdir(target, { recursive: true });
10
- await writeFile(join(target, "AGENTS.md"), AGENTS_INSTRUCTION);
11
- await symlink("AGENTS.md", join(target, "CLAUDE.md"));
12
- const skills = join(target, ".agents", "skills");
13
- await mkdir(skills, { recursive: true });
14
- await cp(GRILLING_SOURCE, join(skills, "grilling"), { recursive: true });
15
- await mkdir(join(target, ".claude"), { recursive: true });
16
- await symlink(join("..", ".agents", "skills"), join(target, ".claude", "skills"));
17
- }