@wrongstack/sdd 0.287.0 → 0.291.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.
@@ -60,13 +60,21 @@ export interface SddDeadlockChain {
60
60
  /** One entry in the live activity feed (the board's "what just happened" ticker). */
61
61
  export interface SddBoardFeedEntry {
62
62
  ts: number;
63
- kind: 'started' | 'completed' | 'failed' | 'retrying' | 'wave' | 'deadlock' | 'verification_failed' | 'conflict' | 'split' | 'supervisor';
63
+ kind: 'started' | 'completed' | 'failed' | 'retrying' | 'wave' | 'deadlock' | 'verification_failed' | 'conflict' | 'split' | 'supervisor' | 'tool' | 'file';
64
+ /** Full task id for durable per-task history; older snapshots may only carry shortId. */
65
+ taskId?: string | undefined;
64
66
  /** Short id of the task this entry concerns, when applicable. */
65
67
  taskShortId?: string | undefined;
66
68
  /** Worker involved, when applicable. */
67
69
  agentName?: string | undefined;
68
70
  /** Human-readable one-line summary. */
69
71
  text: string;
72
+ /** Structured event-log fields used by richer board surfaces. */
73
+ action?: string | undefined;
74
+ detail?: string | undefined;
75
+ filePath?: string | undefined;
76
+ durationMs?: number | undefined;
77
+ ok?: boolean | undefined;
70
78
  }
71
79
  export interface SddBoardSnapshot {
72
80
  runId: string;
@@ -86,6 +94,8 @@ export interface SddBoardSnapshot {
86
94
  } | undefined;
87
95
  /** Live activity feed — most recent first (capped). */
88
96
  feed?: SddBoardFeedEntry[] | undefined;
97
+ /** Per-task event history — most recent first and capped independently per task. */
98
+ taskEvents?: Record<string, SddBoardFeedEntry[]> | undefined;
89
99
  /** Run-level default worker model (task overrides take precedence). */
90
100
  defaultModel?: string | undefined;
91
101
  /** Run-level default worker provider. */
@@ -1 +1 @@
1
- {"version":3,"file":"board-types.d.ts","sourceRoot":"","sources":["../src/board-types.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"board-types.d.ts","sourceRoot":"","sources":["../src/board-types.ts"],"names":[],"mappings":"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"}
package/dist/index.js CHANGED
@@ -242,6 +242,91 @@ var TaskGenerator = class {
242
242
  opts;
243
243
  async generateFromSpec(spec) {
244
244
  const graph = await this.opts.taskTracker.createGraph(spec.id, spec.title);
245
+ const overviewSection = spec.sections?.find((s) => s.type === "overview");
246
+ if (overviewSection?.content) {
247
+ this.opts.taskTracker.addNode({
248
+ title: `Implement: ${spec.title}`,
249
+ description: overviewSection.content,
250
+ type: "feature",
251
+ priority: "high",
252
+ status: "pending",
253
+ estimateHours: 4
254
+ });
255
+ }
256
+ const priorityOrder = { critical: 0, high: 1, medium: 2, low: 3 };
257
+ const sorted = [...spec.requirements ?? []].sort(
258
+ (a, b) => (priorityOrder[a.priority] ?? 9) - (priorityOrder[b.priority] ?? 9)
259
+ );
260
+ for (const req of sorted) {
261
+ const estimateHours = req.priority === "critical" ? 8 : req.priority === "high" ? 4 : req.priority === "medium" ? 2 : 1;
262
+ const tags = [req.type, req.priority];
263
+ const acLines = (req.acceptanceCriteria ?? []).map((ac) => `- ${ac}`).join("\n");
264
+ const blockedLine = req.blockedBy?.length ? `
265
+
266
+ **Blocked by:** ${req.blockedBy.join(", ")}` : "";
267
+ const description = `${req.description}
268
+
269
+ **Type:** ${req.type}` + (acLines ? `
270
+
271
+ **Acceptance Criteria:**
272
+ ${acLines}` : "") + blockedLine;
273
+ const metadata = {};
274
+ if (this.opts.verificationFromAcceptance) {
275
+ const cmd = extractVerificationCommand(req.acceptanceCriteria ?? []);
276
+ if (cmd) metadata.verificationCommand = cmd;
277
+ }
278
+ this.opts.taskTracker.addNode({
279
+ title: req.description,
280
+ description,
281
+ type: "feature",
282
+ priority: req.priority,
283
+ status: "pending",
284
+ estimateHours,
285
+ tags,
286
+ specRequirementId: req.id,
287
+ ...Object.keys(metadata).length > 0 ? { metadata } : {}
288
+ });
289
+ }
290
+ if (spec.apiEndpoints?.length) {
291
+ const apiParent = this.opts.taskTracker.addNode({
292
+ title: "API Implementation",
293
+ description: "Implement API endpoints as specified in the spec.",
294
+ type: "feature",
295
+ priority: "high",
296
+ status: "pending",
297
+ estimateHours: 0
298
+ });
299
+ for (const ep of spec.apiEndpoints) {
300
+ const baseHours = 2;
301
+ const authHours = ep.auth ? 1 : 0;
302
+ const reqHours = ep.request ? 1 : 0;
303
+ this.opts.taskTracker.addNode({
304
+ title: `${ep.method} ${ep.path} \u2014 ${ep.description}`,
305
+ description: `${ep.method} ${ep.path}: ${ep.description}`,
306
+ type: "feature",
307
+ priority: "medium",
308
+ status: "pending",
309
+ estimateHours: baseHours + authHours + reqHours,
310
+ parentId: apiParent.id
311
+ });
312
+ }
313
+ }
314
+ this.opts.taskTracker.addNode({
315
+ title: "Write Tests",
316
+ description: "Write comprehensive tests for the implemented features.",
317
+ type: "test",
318
+ priority: "high",
319
+ status: "pending",
320
+ estimateHours: 4
321
+ });
322
+ this.opts.taskTracker.addNode({
323
+ title: "Update Documentation",
324
+ description: "Update project documentation to reflect the changes.",
325
+ type: "docs",
326
+ priority: "low",
327
+ status: "pending",
328
+ estimateHours: 2
329
+ });
245
330
  return graph;
246
331
  }
247
332
  async generateSubtasks(parentTaskId, spec) {
@@ -890,11 +975,31 @@ var SddBoardStore = class {
890
975
  };
891
976
 
892
977
  // src/sdd-board-projector.ts
978
+ import { DefaultSecretScrubber } from "@wrongstack/core";
979
+ function summarizeToolInput(input, scrubber) {
980
+ if (!input || typeof input !== "object" || Array.isArray(input)) return void 0;
981
+ const record = input;
982
+ for (const key of ["filePath", "path"]) {
983
+ const value = record[key];
984
+ if (typeof value === "string" && value.trim()) {
985
+ const compact = scrubber.scrub(value).replace(/\s+/g, " ").trim();
986
+ return compact.length > 240 ? `${compact.slice(0, 239)}\u2026` : compact;
987
+ }
988
+ }
989
+ if (typeof record["command"] === "string" || typeof record["cmd"] === "string") {
990
+ return "[command omitted]";
991
+ }
992
+ if (typeof record["query"] === "string" || typeof record["pattern"] === "string") {
993
+ return "[query omitted]";
994
+ }
995
+ return void 0;
996
+ }
893
997
  var SddBoardProjector = class _SddBoardProjector {
894
998
  o;
895
999
  now;
896
1000
  throttleMs;
897
1001
  shortId;
1002
+ scrubber;
898
1003
  status = "idle";
899
1004
  wave = 0;
900
1005
  startedAt;
@@ -902,6 +1007,9 @@ var SddBoardProjector = class _SddBoardProjector {
902
1007
  /** Live activity feed, most recent first (capped). */
903
1008
  feed = [];
904
1009
  static FEED_CAP = 60;
1010
+ /** Rich history is retained independently so a busy board cannot erase a task's log. */
1011
+ taskEvents = /* @__PURE__ */ new Map();
1012
+ static TASK_EVENT_CAP = 250;
905
1013
  finished = false;
906
1014
  runDeadlocked = false;
907
1015
  runStopped = false;
@@ -919,6 +1027,7 @@ var SddBoardProjector = class _SddBoardProjector {
919
1027
  this.now = opts.now ?? Date.now;
920
1028
  this.throttleMs = opts.throttleMs ?? 250;
921
1029
  this.shortId = shortIdMap(opts.graph);
1030
+ this.scrubber = opts.secretScrubber ?? new DefaultSecretScrubber();
922
1031
  this.startedAt = this.now();
923
1032
  this.unsubs.push(opts.tracker.subscribe(() => this.markDirty()));
924
1033
  this.onRun("sdd.run.started", (e) => {
@@ -951,6 +1060,7 @@ var SddBoardProjector = class _SddBoardProjector {
951
1060
  this.pushFeed({
952
1061
  ts: this.now(),
953
1062
  kind: "started",
1063
+ taskId: e.taskId,
954
1064
  taskShortId: sid,
955
1065
  agentName: e.agentName,
956
1066
  text: `${e.agentName || "a worker"} picked up ${sid ?? "a task"}${this.titleOf(e.taskId)}`
@@ -963,6 +1073,7 @@ var SddBoardProjector = class _SddBoardProjector {
963
1073
  this.pushFeed({
964
1074
  ts: this.now(),
965
1075
  kind: "completed",
1076
+ taskId: e.taskId,
966
1077
  taskShortId: sid,
967
1078
  agentName: agent,
968
1079
  text: `${sid ?? "task"}${this.titleOf(e.taskId)} completed${agent ? ` by ${agent}` : ""} \xB7 ${(e.durationMs / 1e3).toFixed(1)}s`
@@ -974,6 +1085,7 @@ var SddBoardProjector = class _SddBoardProjector {
974
1085
  this.pushFeed({
975
1086
  ts: this.now(),
976
1087
  kind: "failed",
1088
+ taskId: e.taskId,
977
1089
  taskShortId: sid,
978
1090
  agentName: this.assigneeOf(e.taskId),
979
1091
  text: `${sid ?? "task"}${this.titleOf(e.taskId)} failed \u2014 ${e.error}`
@@ -985,6 +1097,7 @@ var SddBoardProjector = class _SddBoardProjector {
985
1097
  this.pushFeed({
986
1098
  ts: this.now(),
987
1099
  kind: "retrying",
1100
+ taskId: e.taskId,
988
1101
  taskShortId: sid,
989
1102
  text: `${sid ?? "task"}${this.titleOf(e.taskId)} retrying (${e.attempt}/${e.maxRetries})`
990
1103
  });
@@ -995,6 +1108,7 @@ var SddBoardProjector = class _SddBoardProjector {
995
1108
  this.pushFeed({
996
1109
  ts: this.now(),
997
1110
  kind: "verification_failed",
1111
+ taskId: e.taskId,
998
1112
  taskShortId: sid,
999
1113
  agentName: this.assigneeOf(e.taskId),
1000
1114
  text: `${sid ?? "task"}${this.titleOf(e.taskId)} failed verification \u2014 ${e.reason}`
@@ -1007,6 +1121,7 @@ var SddBoardProjector = class _SddBoardProjector {
1007
1121
  this.pushFeed({
1008
1122
  ts: this.now(),
1009
1123
  kind: "conflict",
1124
+ taskId: e.taskId,
1010
1125
  taskShortId: sid,
1011
1126
  agentName: this.assigneeOf(e.taskId),
1012
1127
  text: `${sid ?? "task"}${this.titleOf(e.taskId)} merge conflict \u2014 ${files} file(s)${files ? `: ${e.conflictFiles.slice(0, 3).join(", ")}${files > 3 ? "\u2026" : ""}` : ""}`
@@ -1020,6 +1135,7 @@ var SddBoardProjector = class _SddBoardProjector {
1020
1135
  this.pushFeed({
1021
1136
  ts: this.now(),
1022
1137
  kind: "completed",
1138
+ taskId: e.taskId,
1023
1139
  taskShortId: sid,
1024
1140
  text: `${sid ?? "task"}${this.titleOf(e.taskId)} merged \u2192 ${this.runBaseBranch ?? this.o.baseBranch ?? "base"} (${e.sha.slice(0, 8)})`
1025
1141
  });
@@ -1030,6 +1146,7 @@ var SddBoardProjector = class _SddBoardProjector {
1030
1146
  this.pushFeed({
1031
1147
  ts: this.now(),
1032
1148
  kind: "split",
1149
+ taskId: e.taskId,
1033
1150
  taskShortId: sid,
1034
1151
  text: `${sid ?? "task"}${this.titleOf(e.taskId)} split into ${e.subtaskIds.length} sub-task(s)`
1035
1152
  });
@@ -1040,15 +1157,90 @@ var SddBoardProjector = class _SddBoardProjector {
1040
1157
  this.pushFeed({
1041
1158
  ts: this.now(),
1042
1159
  kind: "supervisor",
1160
+ taskId: e.taskId,
1043
1161
  taskShortId: sid,
1044
1162
  text: `supervisor \u2192 ${e.action} for ${sid ?? "task"}${this.titleOf(e.taskId)}${e.rationale ? ` (${e.rationale})` : ""}`
1045
1163
  });
1046
1164
  this.markDirty();
1047
1165
  });
1166
+ this.onTask("subagent.tool_executed", (e, taskId) => {
1167
+ const sid = this.shortId.get(taskId);
1168
+ const detail = summarizeToolInput(e.input, this.scrubber);
1169
+ const agentName = e.agentName ? this.scrubber.scrub(e.agentName) : void 0;
1170
+ const action = this.scrubber.scrub(e.name);
1171
+ this.pushFeed({
1172
+ ts: this.now(),
1173
+ kind: "tool",
1174
+ taskId,
1175
+ taskShortId: sid,
1176
+ agentName,
1177
+ action,
1178
+ detail,
1179
+ durationMs: e.durationMs,
1180
+ ok: e.ok,
1181
+ text: `${agentName ?? "worker"} ran ${action}${detail ? ` \xB7 ${detail}` : ""}`
1182
+ });
1183
+ void this.o.store?.appendEvent(this.o.runId, {
1184
+ ts: this.now(),
1185
+ type: "subagent.tool_executed",
1186
+ payload: {
1187
+ runId: this.o.runId,
1188
+ taskId,
1189
+ subagentId: e.subagentId,
1190
+ agentName,
1191
+ name: action,
1192
+ durationMs: e.durationMs,
1193
+ ok: e.ok,
1194
+ detail
1195
+ }
1196
+ });
1197
+ this.markDirty();
1198
+ });
1199
+ this.onTask("file.event", (e, taskId) => {
1200
+ if (e.scope !== "task") return;
1201
+ const sid = this.shortId.get(taskId);
1202
+ const agentName = this.scrubber.scrub(e.agentName);
1203
+ const filePath = this.scrubber.scrub(e.filePath);
1204
+ this.pushFeed({
1205
+ ts: Date.parse(e.timestamp) || this.now(),
1206
+ kind: "file",
1207
+ taskId,
1208
+ taskShortId: sid,
1209
+ agentName,
1210
+ action: e.operation,
1211
+ filePath,
1212
+ durationMs: e.durationMs,
1213
+ ok: true,
1214
+ text: `${e.operation} ${filePath}`
1215
+ });
1216
+ void this.o.store?.appendEvent(this.o.runId, {
1217
+ ts: this.now(),
1218
+ type: "file.event",
1219
+ payload: {
1220
+ runId: this.o.runId,
1221
+ taskId,
1222
+ agentName,
1223
+ operation: e.operation,
1224
+ filePath,
1225
+ toolName: this.scrubber.scrub(e.toolName),
1226
+ durationMs: e.durationMs,
1227
+ timestamp: e.timestamp
1228
+ }
1229
+ });
1230
+ this.markDirty();
1231
+ });
1048
1232
  }
1049
1233
  pushFeed(entry) {
1050
1234
  this.feed.unshift(entry);
1051
1235
  if (this.feed.length > _SddBoardProjector.FEED_CAP) this.feed.length = _SddBoardProjector.FEED_CAP;
1236
+ if (entry.taskId) {
1237
+ const taskFeed = this.taskEvents.get(entry.taskId) ?? [];
1238
+ taskFeed.unshift(entry);
1239
+ if (taskFeed.length > _SddBoardProjector.TASK_EVENT_CAP) {
1240
+ taskFeed.length = _SddBoardProjector.TASK_EVENT_CAP;
1241
+ }
1242
+ this.taskEvents.set(entry.taskId, taskFeed);
1243
+ }
1052
1244
  }
1053
1245
  /** ` (title…)` suffix for a feed line, or '' when the node/title is missing. */
1054
1246
  titleOf(taskId) {
@@ -1087,6 +1279,18 @@ var SddBoardProjector = class _SddBoardProjector {
1087
1279
  const off = this.o.events.on(event, wrapped);
1088
1280
  this.unsubs.push(off);
1089
1281
  }
1282
+ /** Subscribe to task-correlated telemetry and ignore events outside this graph. */
1283
+ onTask(event, handler) {
1284
+ const wrapped = (e) => {
1285
+ const correlated = e;
1286
+ const taskId = correlated.taskId;
1287
+ if (!taskId || !this.o.graph.nodes.has(taskId)) return;
1288
+ if (correlated.runId !== this.o.runId) return;
1289
+ handler(e, taskId);
1290
+ };
1291
+ const off = this.o.events.on(event, wrapped);
1292
+ this.unsubs.push(off);
1293
+ }
1090
1294
  resolveStatus(completed, total) {
1091
1295
  if (!this.finished) return this.status;
1092
1296
  if (this.runDeadlocked) return "deadlocked";
@@ -1114,6 +1318,9 @@ var SddBoardProjector = class _SddBoardProjector {
1114
1318
  );
1115
1319
  snap.status = this.resolveStatus(snap.progress.completed, snap.progress.total);
1116
1320
  snap.feed = this.feed.slice(0, _SddBoardProjector.FEED_CAP);
1321
+ snap.taskEvents = Object.fromEntries(
1322
+ [...this.taskEvents].map(([taskId, entries]) => [taskId, entries.slice()])
1323
+ );
1117
1324
  return snap;
1118
1325
  }
1119
1326
  markDirty() {
@@ -1987,6 +2194,9 @@ function isExplanatoryText(text) {
1987
2194
  return lower.startsWith("i'") || lower.startsWith("i will") || lower.startsWith("let me") || lower.startsWith("here's my") || lower.startsWith("here is my") || lower.startsWith("i'm going to") || lower.startsWith("first, let me") || lower.startsWith("sure") || lower.startsWith("of course") || lower.startsWith("okay") || lower.startsWith("ok,") || lower.startsWith("sounds good") || lower.startsWith("no problem") || text.split("\n").length < 3 && !text.includes(".");
1988
2195
  }
1989
2196
 
2197
+ // src/start-sdd-run.ts
2198
+ import { TOKENS } from "@wrongstack/core";
2199
+
1990
2200
  // src/sdd-parallel-run.ts
1991
2201
  import { expectDefined as expectDefined2 } from "@wrongstack/core";
1992
2202
  import { randomUUID as randomUUID2 } from "node:crypto";
@@ -2605,7 +2815,10 @@ var SddParallelRun = class {
2605
2815
  this.coordinator = new DefaultMultiAgentCoordinator(config);
2606
2816
  const baseFactory = this.opts.subagentFactory ?? this.defaultFactory();
2607
2817
  const filteredFactory = withDisabledToolFiltering(baseFactory);
2608
- const runner = makeAgentSubagentRunner({ factory: filteredFactory });
2818
+ const runner = makeAgentSubagentRunner({
2819
+ factory: filteredFactory,
2820
+ hostEvents: this.events
2821
+ });
2609
2822
  this.coordinator.setRunner?.(runner);
2610
2823
  }
2611
2824
  defaultFactory() {
@@ -2715,7 +2928,12 @@ var SddParallelRun = class {
2715
2928
  task.description
2716
2929
  ].join("\n"),
2717
2930
  subagentId,
2718
- ...this.timeoutMs ? { timeoutMs: this.timeoutMs } : {}
2931
+ ...this.timeoutMs ? { timeoutMs: this.timeoutMs } : {},
2932
+ context: {
2933
+ telemetryTaskId: taskId,
2934
+ telemetryRunId: this.runId,
2935
+ telemetryBoardId: this.opts.graph.id
2936
+ }
2719
2937
  });
2720
2938
  let result;
2721
2939
  try {
@@ -3048,7 +3266,8 @@ function startSddRun(opts) {
3048
3266
  specId: opts.graph.specId,
3049
3267
  defaultModel: opts.defaultModel,
3050
3268
  defaultProvider: opts.defaultProvider,
3051
- fallbackModels: opts.fallbackModels
3269
+ fallbackModels: opts.fallbackModels,
3270
+ secretScrubber: opts.agent.container?.safeResolve(TOKENS.SecretScrubber)
3052
3271
  });
3053
3272
  opts.registry?.register({
3054
3273
  runId: run.runId,