@kitman-sh/cli 0.7.5 → 0.8.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.
@@ -64,6 +64,8 @@ import {
64
64
  transform,
65
65
  encodeBase64Url,
66
66
  decodeBase64UrlString,
67
+ transform2,
68
+ declare,
67
69
  decodeUnknownEffect,
68
70
  decodeEffect,
69
71
  decodeSync,
@@ -76,6 +78,7 @@ import {
76
78
  Literal,
77
79
  Never,
78
80
  Unknown,
81
+ Null,
79
82
  String2,
80
83
  Boolean2,
81
84
  Void,
@@ -83,24 +86,237 @@ import {
83
86
  Record,
84
87
  Tuple,
85
88
  ArraySchema,
89
+ NonEmptyArray,
86
90
  Union,
87
91
  Literals,
88
92
  decodeTo,
89
93
  tag,
90
94
  makeFilter,
95
+ isPattern,
91
96
  Finite,
97
+ isGreaterThanOrEqualTo,
98
+ isLessThanOrEqualTo2,
92
99
  Int,
100
+ isMinLength,
101
+ isMaxLength,
93
102
  Defect,
94
103
  fromJsonString,
95
104
  Cause,
96
105
  Exit,
97
106
  Class,
98
107
  TaggedError2,
108
+ toEquivalence,
99
109
  toJsonSchemaDocument,
100
110
  toCodecJson,
101
111
  Json,
102
- LoopCapabilities
103
- } from "./chunk-p2wk2v39.js";
112
+ guard,
113
+ SafeJson,
114
+ relativePathPattern,
115
+ skillNamePattern,
116
+ AgentSandboxNetwork,
117
+ AgentEfforts,
118
+ LoopDataSchemaRef,
119
+ ProgramLoop,
120
+ KitKinds
121
+ } from "./chunk-fpyy4rpd.js";
122
+
123
+ // packages/core/src/schedule.ts
124
+ var ScheduleFrequency = ["daily", "weekly"];
125
+ var ScheduleMisfirePolicies = ["skip", "fire_once", "catch_up"];
126
+ var ScheduleOverlapPolicies = ["allow", "skip", "coalesce"];
127
+ var ScheduleVersionStatuses = ["draft", "published", "disabled", "archived"];
128
+ var ScheduleCalendarRule = Struct({
129
+ frequency: Literals(ScheduleFrequency),
130
+ hour: Int.check(isGreaterThanOrEqualTo(0), isLessThanOrEqualTo2(23)),
131
+ minute: Int.check(isGreaterThanOrEqualTo(0), isLessThanOrEqualTo2(59)),
132
+ second: optionalKey(Int.check(isGreaterThanOrEqualTo(0), isLessThanOrEqualTo2(59))),
133
+ daysOfWeek: optionalKey(ArraySchema(Int.check(isGreaterThanOrEqualTo(0), isLessThanOrEqualTo2(6))).check(isMinLength(1), isMaxLength(7)))
134
+ });
135
+ var ScheduleCronRule = Struct({
136
+ cron: String2.check(isMinLength(9), isMaxLength(200), isPattern(new RegExp("^[0-9*,/-]+( [0-9*,/-]+){4}$", "u")))
137
+ });
138
+ var ScheduleRule = Union([ScheduleCalendarRule, ScheduleCronRule]);
139
+ var cronBounds = [
140
+ [0, 59],
141
+ [0, 23],
142
+ [1, 31],
143
+ [1, 12],
144
+ [0, 7]
145
+ ];
146
+ function cronField(field, [min, max]) {
147
+ const values = new Set;
148
+ for (const part of field.split(",")) {
149
+ const match = /^(\*|(\d+)(?:-(\d+))?)(?:\/(\d+))?$/.exec(part);
150
+ if (match === null)
151
+ return;
152
+ const from = match[1] === "*" ? min : Number(match[2]);
153
+ const to = match[1] === "*" ? max : match[3] === undefined ? match[4] === undefined ? from : max : Number(match[3]);
154
+ const step = match[4] === undefined ? 1 : Number(match[4]);
155
+ if (from < min || to > max || from > to || step < 1)
156
+ return;
157
+ for (let value = from;value <= to; value += step)
158
+ values.add(value);
159
+ }
160
+ return values;
161
+ }
162
+ function parseCron(cron) {
163
+ const fields = cron.split(" ");
164
+ const [minutes, hours, days, months, weekdays] = fields.map((field, index) => cronField(field, cronBounds[index] ?? [0, 0]));
165
+ if (fields.length !== 5 || !minutes || !hours || !days || !months || !weekdays)
166
+ return;
167
+ return {
168
+ minutes,
169
+ hours,
170
+ days,
171
+ months,
172
+ weekdays: new Set([...weekdays].map((value) => value % 7)),
173
+ dayRestricted: !(fields[2] ?? "").startsWith("*"),
174
+ weekdayRestricted: !(fields[4] ?? "").startsWith("*")
175
+ };
176
+ }
177
+ function isScheduleRule(value) {
178
+ return guard(ScheduleRule)(value) && (!("cron" in value) || parseCron(value.cron) !== undefined);
179
+ }
180
+ var ScheduleVersion = Struct({
181
+ contractVersion: Literal("schedule.v1"),
182
+ id: String2.check(isMinLength(1)),
183
+ scheduleId: String2.check(isMinLength(1)),
184
+ workspaceId: String2.check(isMinLength(1)),
185
+ teamId: optionalKey(String2.check(isMinLength(1))),
186
+ loopId: optionalKey(String2.check(isMinLength(1))),
187
+ name: optionalKey(String2.check(isMinLength(1), isMaxLength(200))),
188
+ version: Int.check(isGreaterThanOrEqualTo(1)),
189
+ status: Literals(ScheduleVersionStatuses),
190
+ timezone: String2.check(isMinLength(1), isMaxLength(80)),
191
+ rule: ScheduleRule,
192
+ misfirePolicy: Literals(ScheduleMisfirePolicies),
193
+ overlapPolicy: Literals(ScheduleOverlapPolicies),
194
+ maxCatchUp: Int.check(isGreaterThanOrEqualTo(0), isLessThanOrEqualTo2(200)),
195
+ misfireGraceSeconds: optionalKey(Int.check(isGreaterThanOrEqualTo(0), isLessThanOrEqualTo2(604800))),
196
+ inputSchemaRef: optionalKey(LoopDataSchemaRef),
197
+ input: optionalKey(SafeJson),
198
+ createdAt: String2.check(isMinLength(1))
199
+ });
200
+ var zones = new Map;
201
+ var resolvedLocalDateTimes = new Map;
202
+
203
+ // packages/core/src/package-declarations.ts
204
+ var LoopCapabilities = [
205
+ "agent_work",
206
+ "ask",
207
+ "call",
208
+ "verify",
209
+ "change_request",
210
+ "write_back",
211
+ "post_comment",
212
+ "create_tasks",
213
+ "merge_change_request",
214
+ "publish_release",
215
+ "read_transcripts",
216
+ "propose",
217
+ "read_project",
218
+ "draft_update"
219
+ ];
220
+ var JsonObject = Record(String2, Json);
221
+ var recordKeyedBy = (pattern, value) => Record(String2, value).check(makeFilter((record) => {
222
+ const bad = Object.keys(record).find((key) => !new RegExp(pattern).test(key));
223
+ return bad === undefined ? true : `${JSON.stringify(bad)} is not a valid name or relative path`;
224
+ }));
225
+ var SecretName = String2.check(isPattern(/^[A-Za-z_][A-Za-z0-9_]{0,127}$/));
226
+ var EventFilterValue = Union([String2, Finite, Boolean2, Null]);
227
+ var LoopManifest = Struct({
228
+ id: String2,
229
+ title: String2,
230
+ input: JsonObject,
231
+ output: JsonObject,
232
+ outcome: optionalKey(Literals(["feature", "bug", "refactor", "investigation", "docs", "migration"])),
233
+ agents: Record(String2, String2),
234
+ checkout: Literals(["none", "read", "write"]),
235
+ when: ArraySchema(Struct({
236
+ event: String2,
237
+ filter: optionalKey(Record(String2, Union([EventFilterValue, ArraySchema(EventFilterValue)]))),
238
+ input: Record(String2, String2)
239
+ })),
240
+ offers: ArraySchema(Struct({ id: String2, title: String2, loop: String2 })),
241
+ capabilities: ArraySchema(Literals(LoopCapabilities)),
242
+ secrets: optionalKey(ArraySchema(SecretName)),
243
+ network: optionalKey(AgentSandboxNetwork),
244
+ schedule: optionalKey(Struct({ rule: ScheduleRule, timezone: String2 }))
245
+ });
246
+ var LoopDetail = Struct({
247
+ id: String2,
248
+ resolved: optionalKey(Struct({
249
+ ...ProgramLoop.fields,
250
+ agents: LoopManifest.fields.agents,
251
+ when: LoopManifest.fields.when,
252
+ schedule: optionalKey(Struct({
253
+ rule: ScheduleRule,
254
+ timezone: String2,
255
+ on: Boolean2,
256
+ nextRunAt: optionalKey(String2)
257
+ }))
258
+ }))
259
+ });
260
+ var AgentDeclaration = Struct({
261
+ extends: optionalKey(String2),
262
+ instructions: optionalKey(String2),
263
+ harness: optionalKey(String2),
264
+ model: optionalKey(String2),
265
+ effort: optionalKey(Literals(AgentEfforts)),
266
+ kits: optionalKey(ArraySchema(String2)),
267
+ network: optionalKey(Union([Struct({ hosts: ArraySchema(String2) }), Literal("open")])),
268
+ sandbox: optionalKey(Literal("docker"))
269
+ });
270
+ var scheduleFields = {
271
+ name: String2.check(isMinLength(1)),
272
+ loop: String2,
273
+ team: optionalKey(String2),
274
+ input: optionalKey(JsonObject),
275
+ timezone: String2,
276
+ misfire: optionalKey(Literals(ScheduleMisfirePolicies)),
277
+ overlap: optionalKey(Literals(ScheduleOverlapPolicies))
278
+ };
279
+ var ScheduleDeclaration = Union([
280
+ Struct({
281
+ ...scheduleFields,
282
+ cron: String2.check(makeFilter((cron) => isScheduleRule({ cron }) || "five cron fields, each within its range"))
283
+ }),
284
+ Struct({
285
+ ...scheduleFields,
286
+ rule: declare((value) => isScheduleRule(value), {
287
+ expected: "a Schedule rule: frequency daily or weekly, hour, minute, and optionally second and daysOfWeek"
288
+ })
289
+ })
290
+ ]);
291
+ var AuthoredKitDeclaration = Struct({
292
+ name: String2.check(isMinLength(1)),
293
+ kind: optionalKey(Literals(KitKinds)),
294
+ description: optionalKey(String2),
295
+ context: String2,
296
+ skills: optionalKey(recordKeyedBy(skillNamePattern, recordKeyedBy(relativePathPattern, String2)))
297
+ });
298
+ var KitInstallationDeclaration = Struct({
299
+ source: String2.check(isMinLength(1)),
300
+ version: optionalKey(String2)
301
+ });
302
+ var KitAssignmentDeclaration = Struct({
303
+ kit: String2.check(isMinLength(1)),
304
+ workspace: optionalKey(Literals(["default", "mandatory"])),
305
+ teams: optionalKey(ArraySchema(String2))
306
+ });
307
+ var KitDeclaration = Union([
308
+ KitInstallationDeclaration,
309
+ KitAssignmentDeclaration,
310
+ AuthoredKitDeclaration
311
+ ]);
312
+ var PackageDeclarations = Struct({
313
+ loops: ArraySchema(LoopManifest),
314
+ agents: Record(String2, AgentDeclaration),
315
+ schedules: optionalKey(Record(String2, ScheduleDeclaration)),
316
+ kits: optionalKey(Record(String2, KitDeclaration))
317
+ });
318
+ var sameLoop = toEquivalence(LoopManifest);
319
+ var sameAgent = toEquivalence(AgentDeclaration);
104
320
 
105
321
  // packages/sdk/src/loop/define.ts
106
322
  var LoopOutcome = Literals(["feature", "bug", "refactor", "investigation", "docs", "migration"]);
@@ -754,11 +970,17 @@ var WriteBackRequest = Struct({
754
970
  milestone: optional(Literals(WriteBackMilestones)),
755
971
  changeRequestUrl: optional(String2)
756
972
  });
973
+ var RunFile = Struct({ runFile: String2 }).pipe(decodeTo(Struct({ id: String2 }), transform2({
974
+ decode: ({ runFile }) => ({ id: runFile }),
975
+ encode: ({ id }) => ({ runFile: id })
976
+ })));
977
+ var FileRequest = Struct({ path: String2, caption: optional(String2) });
757
978
  var ArtifactRequest = Struct({
758
979
  kind: String2,
759
980
  title: String2,
760
981
  text: String2,
761
- data: optional(Json)
982
+ data: optional(Json),
983
+ files: optional(ArraySchema(RunFile))
762
984
  });
763
985
  var ArtifactResult = Struct({ artifactId: String2 });
764
986
  var NoteRequest = Struct({ text: String2, artifactId: optional(String2) });
@@ -785,6 +1007,68 @@ var ReleaseRequest = Struct({
785
1007
  notes: String2
786
1008
  });
787
1009
  var ReleaseResult = Struct({ tag: String2, revision: String2, url: String2 });
1010
+ var TranscriptPoint = Struct({
1011
+ runId: String2,
1012
+ stepAttemptId: String2,
1013
+ sequence: Int
1014
+ });
1015
+ var TranscriptsRequest = Struct({
1016
+ days: Int.check(isGreaterThanOrEqualTo(1), isLessThanOrEqualTo2(31))
1017
+ });
1018
+ var TranscriptsResult = Struct({
1019
+ runs: ArraySchema(Struct({
1020
+ runId: String2,
1021
+ loopId: String2,
1022
+ teamId: optional(String2),
1023
+ failure: optional(String2),
1024
+ entries: ArraySchema(Struct({ stepAttemptId: String2, sequence: Int, kind: String2, text: String2 }))
1025
+ }))
1026
+ });
1027
+ var Citations = NonEmptyArray(TranscriptPoint);
1028
+ var ProposeRequest = Union([
1029
+ Struct({
1030
+ kind: Literal("memory"),
1031
+ teamId: String2,
1032
+ content: String2,
1033
+ citations: Citations
1034
+ }),
1035
+ Struct({
1036
+ kind: Literal("task"),
1037
+ title: String2,
1038
+ description: String2,
1039
+ teamId: optional(String2),
1040
+ citations: Citations
1041
+ })
1042
+ ]);
1043
+ var ProposeResult = Struct({ kind: Literals(["memory", "task"]), id: String2 });
1044
+ var Health = Literals(["on_track", "at_risk", "off_track"]);
1045
+ var ProjectActivityRequest = Struct({ projectId: String2 });
1046
+ var ProjectActivityResult = Struct({
1047
+ project: Struct({ id: String2, name: String2 }),
1048
+ health: optional(Health),
1049
+ since: optional(String2),
1050
+ runs: ArraySchema(Struct({
1051
+ runId: String2,
1052
+ loopId: String2,
1053
+ status: String2,
1054
+ taskKey: optional(String2),
1055
+ taskTitle: optional(String2),
1056
+ summary: optional(String2),
1057
+ entries: ArraySchema(Struct({ stepAttemptId: String2, sequence: Int, kind: String2, text: String2 }))
1058
+ })),
1059
+ taskChanges: ArraySchema(Struct({ taskKey: String2, title: String2, change: String2, at: String2 }))
1060
+ });
1061
+ var DraftUpdateRequest = Struct({
1062
+ projectId: String2,
1063
+ health: Health,
1064
+ note: String2,
1065
+ writtenFrom: Struct({
1066
+ runs: Int,
1067
+ taskChanges: Int,
1068
+ since: optional(String2)
1069
+ })
1070
+ });
1071
+ var DraftUpdateResult = Struct({ id: String2 });
788
1072
 
789
1073
  class ChangeRequestActivity extends Service()("@kitman-sh/sdk/loop/ChangeRequestActivity") {
790
1074
  }
@@ -795,6 +1079,9 @@ class WriteBackActivity extends Service()("@kitman-sh/sdk/loop/WriteBackActivity
795
1079
  class ArtifactActivity extends Service()("@kitman-sh/sdk/loop/ArtifactActivity") {
796
1080
  }
797
1081
 
1082
+ class FileActivity extends Service()("@kitman-sh/sdk/loop/FileActivity") {
1083
+ }
1084
+
798
1085
  class NoteActivity extends Service()("@kitman-sh/sdk/loop/NoteActivity") {
799
1086
  }
800
1087
 
@@ -812,6 +1099,18 @@ class MergeChangeRequestActivity extends Service()("@kitman-sh/sdk/loop/MergeCha
812
1099
 
813
1100
  class ReleaseActivity extends Service()("@kitman-sh/sdk/loop/ReleaseActivity") {
814
1101
  }
1102
+
1103
+ class TranscriptsActivity extends Service()("@kitman-sh/sdk/loop/TranscriptsActivity") {
1104
+ }
1105
+
1106
+ class ProposeActivity extends Service()("@kitman-sh/sdk/loop/ProposeActivity") {
1107
+ }
1108
+
1109
+ class ProjectActivityActivity extends Service()("@kitman-sh/sdk/loop/ProjectActivityActivity") {
1110
+ }
1111
+
1112
+ class DraftUpdateActivity extends Service()("@kitman-sh/sdk/loop/DraftUpdateActivity") {
1113
+ }
815
1114
  var hostActivity = (name, kind, capability, success, execute) => takeStep(name, kind, capability, make3({ name: `${kind}/${name}`, success, error: StepFailed, execute }));
816
1115
  var changeRequest = (name, request) => hostActivity(name, "change_request", "change_request", ChangeRequestResult, gen(function* () {
817
1116
  return yield* (yield* ChangeRequestActivity).run(request, name);
@@ -840,6 +1139,18 @@ var mergeChangeRequest = (name, request) => hostActivity(name, "merge_change_req
840
1139
  var release2 = (name, request) => hostActivity(name, "release", "publish_release", ReleaseResult, gen(function* () {
841
1140
  return yield* (yield* ReleaseActivity).run(request, name);
842
1141
  }));
1142
+ var transcripts = (name, request) => hostActivity(name, "transcripts", "read_transcripts", TranscriptsResult, gen(function* () {
1143
+ return yield* (yield* TranscriptsActivity).run(request, name);
1144
+ }));
1145
+ var propose = (name, request) => hostActivity(name, "propose", "propose", ProposeResult, gen(function* () {
1146
+ return yield* (yield* ProposeActivity).run(request, name);
1147
+ }));
1148
+ var projectActivity = (name, request) => hostActivity(name, "project_activity", "read_project", ProjectActivityResult, gen(function* () {
1149
+ return yield* (yield* ProjectActivityActivity).run(request, name);
1150
+ }));
1151
+ var draftUpdate = (name, request) => hostActivity(name, "draft_update", "draft_update", DraftUpdateResult, gen(function* () {
1152
+ return yield* (yield* DraftUpdateActivity).run(request, name);
1153
+ }));
843
1154
  // packages/sdk/src/loop/test-loop.ts
844
1155
  var LoopJournal = Struct({
845
1156
  activities: Record(String2, Json),
@@ -959,4 +1270,4 @@ class ReplayDiverged extends TaggedError2()("ReplayDiverged", {
959
1270
  }
960
1271
  }
961
1272
  var LoopCheckError = Union([CheckFailed, StepNamedTwice, ReplayDiverged]);
962
- export { LoopOutcome, defineLoop, ManifestInvalid, make, Suspended, make2, await_, make3, evidenceGate, ChildFailed, agentWork, ask, call, waitFor, verify, PlanTickets, planWaves, ChangeRequestResult, CreateTasksResult, changeRequest, writeBack, artifact, note, comment, createTasks, integrationBranch, mergeChangeRequest, release2, Finding, MergedFinding, Rebuttal, RebuttalVerdict, ScopeJudgement, isBlocking, mergeFindings, settleRound, rallyStop, LoopCheckError };
1273
+ export { LoopManifest, AgentDeclaration, KitInstallationDeclaration, KitAssignmentDeclaration, PackageDeclarations, LoopOutcome, defineLoop, ManifestInvalid, make, Suspended, make2, await_, make3, evidenceGate, ChildFailed, agentWork, ask, call, waitFor, verify, PlanTickets, planWaves, ChangeRequestResult, CreateTasksResult, TranscriptPoint, changeRequest, writeBack, artifact, note, comment, createTasks, integrationBranch, mergeChangeRequest, release2, transcripts, propose, projectActivity, draftUpdate, Finding, MergedFinding, Rebuttal, RebuttalVerdict, ScopeJudgement, isBlocking, mergeFindings, settleRound, rallyStop, LoopCheckError };
@@ -31,7 +31,7 @@ import {
31
31
  Int,
32
32
  TaggedError2,
33
33
  Json
34
- } from "./chunk-p2wk2v39.js";
34
+ } from "./chunk-fpyy4rpd.js";
35
35
  import {
36
36
  LoopOutcome,
37
37
  defineLoop,
@@ -49,6 +49,7 @@ import {
49
49
  planWaves,
50
50
  ChangeRequestResult,
51
51
  CreateTasksResult,
52
+ TranscriptPoint,
52
53
  changeRequest,
53
54
  writeBack,
54
55
  artifact,
@@ -58,6 +59,10 @@ import {
58
59
  integrationBranch,
59
60
  mergeChangeRequest,
60
61
  release2,
62
+ transcripts,
63
+ propose,
64
+ projectActivity,
65
+ draftUpdate,
61
66
  Finding,
62
67
  MergedFinding,
63
68
  Rebuttal,
@@ -67,7 +72,7 @@ import {
67
72
  mergeFindings,
68
73
  settleRound,
69
74
  rallyStop
70
- } from "./chunk-a44szh8v.js";
75
+ } from "./chunk-2npvts4c.js";
71
76
 
72
77
  // node_modules/.bun/effect@4.0.4/node_modules/effect/dist/workflow/DurableClock.js
73
78
  var TypeId = "~effect/workflow/DurableClock";
@@ -897,8 +902,53 @@ var plan_default = defineLoop({
897
902
  })
898
903
  });
899
904
 
905
+ // packages/loops/src/project-update.ts
906
+ var Health = Literals(["on_track", "at_risk", "off_track"]);
907
+ var Input6 = Struct({ projectId: String2 });
908
+ var Output6 = Struct({ draftId: String2, health: Health });
909
+ var Written = Struct({
910
+ health: Health,
911
+ note: String2
912
+ });
913
+ var day = (iso) => new Date(iso).toLocaleDateString("en-US", { month: "short", day: "numeric", timeZone: "UTC" });
914
+ var prompt = (read) => [
915
+ `Write a Project Update for ${read.project.name} from what happened ${read.since === undefined ? "so far" : `since its last Update on ${day(read.since)}`}.`,
916
+ "```json",
917
+ JSON.stringify({ health: read.health, runs: read.runs, taskChanges: read.taskChanges }, null, 2),
918
+ "```",
919
+ "Say in a few short paragraphs what moved, what is stuck and what comes next, naming Tasks by key. Suggest a health: on_track, at_risk or off_track. A person reviews and posts it, so claim nothing the Runs and Task changes do not show."
920
+ ].join(`
921
+ `);
922
+ var nothingNew = (read) => ({
923
+ health: read.health ?? "on_track",
924
+ note: read.since === undefined ? "No Runs or Task changes yet." : `No Runs or Task changes since the last Update on ${day(read.since)}.`
925
+ });
926
+ var project_update_default = defineLoop({
927
+ id: "project-update",
928
+ title: "Project update",
929
+ input: Input6,
930
+ output: Output6,
931
+ agents: { writer: "investigator" },
932
+ checkout: "none",
933
+ capabilities: ["read_project", "agent_work", "draft_update"],
934
+ run: ({ projectId }) => gen(function* () {
935
+ const read = yield* projectActivity("read", { projectId });
936
+ const written = read.runs.length === 0 && read.taskChanges.length === 0 ? nothingNew(read) : yield* agentWork("write", { agent: "writer", prompt: prompt(read), output: Written });
937
+ const draft = yield* draftUpdate("draft", {
938
+ projectId,
939
+ ...written,
940
+ writtenFrom: {
941
+ runs: read.runs.length,
942
+ taskChanges: read.taskChanges.length,
943
+ ...read.since === undefined ? undefined : { since: read.since }
944
+ }
945
+ });
946
+ return { draftId: draft.id, health: written.health };
947
+ })
948
+ });
949
+
900
950
  // packages/loops/src/release.ts
901
- var Input6 = Struct({
951
+ var Input7 = Struct({
902
952
  tag: optional(String2),
903
953
  revision: optional(String2),
904
954
  deployEvent: optional(String2),
@@ -910,7 +960,7 @@ var Drafted = Struct({
910
960
  notes: String2,
911
961
  changeRequests: ArraySchema(String2)
912
962
  });
913
- var Output6 = Union([
963
+ var Output7 = Union([
914
964
  Struct({ status: Literal("rejected"), tag: String2, notesArtifactId: String2 }),
915
965
  Struct({
916
966
  status: Literals(["deployed", "deploy_failed", "timed_out"]),
@@ -935,8 +985,8 @@ var reports = {
935
985
  var release_default = defineLoop({
936
986
  id: "release",
937
987
  title: "Release",
938
- input: Input6,
939
- output: Output6,
988
+ input: Input7,
989
+ output: Output7,
940
990
  agents: { releaser: "releaser" },
941
991
  checkout: "read",
942
992
  capabilities: ["agent_work", "ask", "publish_release"],
@@ -983,7 +1033,7 @@ ${drafted.notes}`,
983
1033
  });
984
1034
 
985
1035
  // packages/loops/src/research.ts
986
- var Input7 = Struct({
1036
+ var Input8 = Struct({
987
1037
  taskId: String2,
988
1038
  repoBindingId: optional(String2)
989
1039
  });
@@ -996,8 +1046,8 @@ var Report = Struct({
996
1046
  openQuestions: ArraySchema(String2),
997
1047
  nextSteps: ArraySchema(String2)
998
1048
  });
999
- var Output7 = Struct({ reportArtifactId: String2 });
1000
- var prompt = [
1049
+ var Output8 = Struct({ reportArtifactId: String2 });
1050
+ var prompt2 = [
1001
1051
  "Research the question this Task asks, using the `research` skill. The Task's title, description, Acceptance Criteria and comments are in your context.",
1002
1052
  "Cite primary sources for every finding: the code, official documentation, specifications and first-party APIs. Say what you read or ran and what it showed; separate what you established from what you suspect.",
1003
1053
  "Return the report as your Output, with `title` set to the Task's title. Do not write it into the repository."
@@ -1038,15 +1088,15 @@ var sample = {
1038
1088
  var research_default = defineLoop({
1039
1089
  id: "research",
1040
1090
  title: "Research",
1041
- input: Input7,
1042
- output: Output7,
1091
+ input: Input8,
1092
+ output: Output8,
1043
1093
  outcome: "investigation",
1044
1094
  agents: { researcher: "researcher" },
1045
1095
  checkout: "read",
1046
1096
  capabilities: ["agent_work"],
1047
1097
  checks: [{ name: "reports", script: { input: { taskId: "task-1" }, outputs: { research: sample } } }],
1048
1098
  run: () => gen(function* () {
1049
- const report = yield* agentWork("research", { agent: "researcher", prompt, output: Report });
1099
+ const report = yield* agentWork("research", { agent: "researcher", prompt: prompt2, output: Report });
1050
1100
  const { artifactId } = yield* artifact("report", {
1051
1101
  kind: "research_report",
1052
1102
  title: report.title,
@@ -1058,6 +1108,82 @@ var research_default = defineLoop({
1058
1108
  })
1059
1109
  });
1060
1110
 
1111
+ // packages/loops/src/retrospective.ts
1112
+ var Input9 = Struct({});
1113
+ var Proposal = Struct({
1114
+ kind: Literals(["memory", "task"]),
1115
+ id: String2,
1116
+ runIds: ArraySchema(String2)
1117
+ });
1118
+ var Output9 = Struct({ proposals: ArraySchema(Proposal) });
1119
+ var Findings = Struct({
1120
+ findings: ArraySchema(Struct({
1121
+ kind: Literals(["memory", "task"]),
1122
+ lesson: String2,
1123
+ detail: optional(String2),
1124
+ citations: ArraySchema(TranscriptPoint)
1125
+ }))
1126
+ });
1127
+ var days = 7;
1128
+ var prompt3 = (read) => [
1129
+ `These Runs failed in the last ${days} days. Find what keeps going wrong: the same mistake or failure in more than one Run.`,
1130
+ "```json",
1131
+ JSON.stringify(read.runs, null, 2),
1132
+ "```",
1133
+ "For each, propose Memory when agents can avoid it by knowing something, or a Task when something has to change. Cite every Transcript point (runId, stepAttemptId, sequence) it shows in. Leave out anything seen in one Run only."
1134
+ ].join(`
1135
+ `);
1136
+ var point = (cited) => `${cited.runId}/${cited.stepAttemptId}/${cited.sequence}`;
1137
+ var shared = (cited, field) => {
1138
+ const values = new Set(cited.map((run) => run[field]));
1139
+ const [only] = values;
1140
+ return values.size === 1 ? only : undefined;
1141
+ };
1142
+ var proposal = (finding, read) => {
1143
+ const readPoints = new Set(read.runs.flatMap((run) => run.entries.map((entry) => point({ runId: run.runId, stepAttemptId: entry.stepAttemptId, sequence: entry.sequence }))));
1144
+ const citations = [
1145
+ ...new Map(finding.citations.filter((cited) => readPoints.has(point(cited))).map((cited) => [point(cited), cited])).values()
1146
+ ];
1147
+ const runIds = new Set(citations.map((cited) => cited.runId));
1148
+ const [first, ...rest] = citations;
1149
+ if (first === undefined || runIds.size < 2)
1150
+ return;
1151
+ const cited = read.runs.filter((run) => runIds.has(run.runId));
1152
+ const teamId = shared(cited, "teamId");
1153
+ if (finding.kind === "memory" && teamId !== undefined)
1154
+ return { kind: "memory", teamId, content: finding.lesson, citations: [first, ...rest] };
1155
+ return {
1156
+ kind: "task",
1157
+ title: finding.lesson,
1158
+ description: finding.detail ?? finding.lesson,
1159
+ ...teamId === undefined ? undefined : { teamId },
1160
+ citations: [first, ...rest]
1161
+ };
1162
+ };
1163
+ var retrospective_default = defineLoop({
1164
+ id: "retrospective",
1165
+ title: "Retrospective",
1166
+ input: Input9,
1167
+ output: Output9,
1168
+ outcome: "investigation",
1169
+ agents: { investigator: "investigator" },
1170
+ checkout: "none",
1171
+ schedule: { rule: { frequency: "weekly", daysOfWeek: [1], hour: 9, minute: 0 }, timezone: "UTC" },
1172
+ capabilities: ["read_transcripts", "agent_work", "propose"],
1173
+ run: () => gen(function* () {
1174
+ const read = yield* transcripts("read", { days });
1175
+ if (read.runs.length < 2)
1176
+ return { proposals: [] };
1177
+ const { findings } = yield* agentWork("find", { agent: "investigator", prompt: prompt3(read), output: Findings });
1178
+ const requests = findings.flatMap((finding) => proposal(finding, read) ?? []);
1179
+ const proposals = yield* forEach(requests, (request, index) => map3(propose(`propose-${index + 1}`, request), (made) => ({
1180
+ ...made,
1181
+ runIds: [...new Set(request.citations.map((cited) => cited.runId))]
1182
+ })));
1183
+ return { proposals };
1184
+ })
1185
+ });
1186
+
1061
1187
  // packages/loops/src/index.ts
1062
1188
  var shippedLoops = {
1063
1189
  build: build_default,
@@ -1066,8 +1192,10 @@ var shippedLoops = {
1066
1192
  hello: hello_default,
1067
1193
  incident: incident_default,
1068
1194
  plan: plan_default,
1195
+ "project-update": project_update_default,
1069
1196
  release: release_default,
1070
1197
  research: research_default,
1198
+ retrospective: retrospective_default,
1071
1199
  review: review_default
1072
1200
  };
1073
1201
  export {
@@ -1077,8 +1205,10 @@ export {
1077
1205
  hello_default as hello,
1078
1206
  incident_default as incident,
1079
1207
  plan_default as plan,
1208
+ project_update_default as projectUpdate,
1080
1209
  release_default as release,
1081
1210
  research_default as research,
1211
+ retrospective_default as retrospective,
1082
1212
  review_default as review,
1083
1213
  shippedLoops
1084
1214
  };