codeharness 0.29.3 → 0.29.4

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.
@@ -2895,7 +2895,7 @@ function generateDockerfileTemplate(projectDir, stackOrDetections) {
2895
2895
  }
2896
2896
 
2897
2897
  // src/modules/infra/init-project.ts
2898
- var HARNESS_VERSION = true ? "0.29.3" : "0.0.0-dev";
2898
+ var HARNESS_VERSION = true ? "0.29.4" : "0.0.0-dev";
2899
2899
  function failResult(opts, error) {
2900
2900
  return {
2901
2901
  status: "fail",
@@ -16,7 +16,7 @@ import {
16
16
  stopCollectorOnly,
17
17
  stopSharedStack,
18
18
  stopStack
19
- } from "./chunk-4QLSEKNP.js";
19
+ } from "./chunk-KVKEUNEB.js";
20
20
  export {
21
21
  checkRemoteEndpoint,
22
22
  cleanupOrphanedContainers,
package/dist/index.js CHANGED
@@ -40,7 +40,7 @@ import {
40
40
  validateDockerfile,
41
41
  warn,
42
42
  writeState
43
- } from "./chunk-4QLSEKNP.js";
43
+ } from "./chunk-KVKEUNEB.js";
44
44
 
45
45
  // src/index.ts
46
46
  import { Command } from "commander";
@@ -5672,13 +5672,14 @@ function startRenderer(options) {
5672
5672
  inkInstance.rerender(/* @__PURE__ */ jsx9(App, { state, onCycleLane: () => cycleLane() }));
5673
5673
  }
5674
5674
  }
5675
+ const heartbeat = setInterval(() => {
5676
+ if (!cleaned) rerender();
5677
+ }, 200);
5675
5678
  function onSigint() {
5676
5679
  cleanupFull();
5677
- process.kill(process.pid, "SIGINT");
5678
5680
  }
5679
5681
  function onSigterm() {
5680
5682
  cleanupFull();
5681
- process.kill(process.pid, "SIGTERM");
5682
5683
  }
5683
5684
  process.on("SIGINT", onSigint);
5684
5685
  process.on("SIGTERM", onSigterm);
@@ -5940,6 +5941,7 @@ function startRenderer(options) {
5940
5941
  function cleanupFull() {
5941
5942
  if (cleaned) return;
5942
5943
  cleaned = true;
5944
+ clearInterval(heartbeat);
5943
5945
  try {
5944
5946
  inkInstance.unmount();
5945
5947
  } catch {
@@ -6186,16 +6188,31 @@ function registerRunCommand(program) {
6186
6188
  let interrupted = false;
6187
6189
  const onInterrupt = () => {
6188
6190
  if (interrupted) {
6189
- renderer.cleanup();
6190
6191
  process.exit(1);
6191
6192
  }
6192
6193
  interrupted = true;
6194
+ renderer.cleanup();
6193
6195
  abortController.abort();
6196
+ info("Interrupted \u2014 waiting for current task to finish...", outputOpts);
6194
6197
  };
6195
6198
  process.on("SIGINT", onInterrupt);
6196
6199
  process.on("SIGTERM", onInterrupt);
6200
+ const sessionStartMs = Date.now();
6197
6201
  let totalCostUsd = 0;
6198
6202
  let storiesDone = counts.done;
6203
+ let currentStoryKey = "";
6204
+ let currentTaskName = "";
6205
+ const headerRefresh = setInterval(() => {
6206
+ if (interrupted) return;
6207
+ renderer.updateSprintState({
6208
+ storyKey: currentStoryKey,
6209
+ phase: currentTaskName,
6210
+ done: storiesDone,
6211
+ total: counts.total,
6212
+ totalCost: totalCostUsd,
6213
+ elapsed: formatElapsed(Date.now() - sessionStartMs)
6214
+ });
6215
+ }, 2e3);
6199
6216
  const taskStates = {};
6200
6217
  const taskMeta = {};
6201
6218
  for (const [tn, task] of Object.entries(parsedWorkflow.tasks)) {
@@ -6216,12 +6233,15 @@ function registerRunCommand(program) {
6216
6233
  renderer.update(event.streamEvent, event.driverName);
6217
6234
  }
6218
6235
  if (event.type === "dispatch-start") {
6236
+ currentStoryKey = event.storyKey;
6237
+ currentTaskName = event.taskName;
6219
6238
  renderer.updateSprintState({
6220
6239
  storyKey: event.storyKey,
6221
6240
  phase: event.taskName,
6222
6241
  done: storiesDone,
6223
6242
  total: counts.total,
6224
- totalCost: totalCostUsd
6243
+ totalCost: totalCostUsd,
6244
+ elapsed: formatElapsed(Date.now() - sessionStartMs)
6225
6245
  });
6226
6246
  taskStates[event.taskName] = "active";
6227
6247
  renderer.updateWorkflowState(parsedWorkflow.flow, event.taskName, { ...taskStates }, { ...taskMeta });
@@ -6345,6 +6365,7 @@ function registerRunCommand(program) {
6345
6365
  } else {
6346
6366
  try {
6347
6367
  const result = await executeWorkflow(config);
6368
+ clearInterval(headerRefresh);
6348
6369
  process.removeListener("SIGINT", onInterrupt);
6349
6370
  process.removeListener("SIGTERM", onInterrupt);
6350
6371
  renderer.cleanup();
@@ -6361,6 +6382,7 @@ function registerRunCommand(program) {
6361
6382
  process.exitCode = 1;
6362
6383
  }
6363
6384
  } catch (err) {
6385
+ clearInterval(headerRefresh);
6364
6386
  renderer.cleanup();
6365
6387
  const msg = err instanceof Error ? err.message : String(err);
6366
6388
  fail(`Workflow engine error: ${msg}`, outputOpts);
@@ -11145,7 +11167,7 @@ function registerTeardownCommand(program) {
11145
11167
  } else if (otlpMode === "remote-routed") {
11146
11168
  if (!options.keepDocker) {
11147
11169
  try {
11148
- const { stopCollectorOnly: stopCollectorOnly2 } = await import("./docker-XNAP7B5H.js");
11170
+ const { stopCollectorOnly: stopCollectorOnly2 } = await import("./docker-PYH5XATT.js");
11149
11171
  stopCollectorOnly2();
11150
11172
  result.docker.stopped = true;
11151
11173
  if (!isJson) {
@@ -11177,7 +11199,7 @@ function registerTeardownCommand(program) {
11177
11199
  info("Shared stack: kept running (other projects may use it)");
11178
11200
  }
11179
11201
  } else if (isLegacyStack) {
11180
- const { isStackRunning: isStackRunning2, stopStack } = await import("./docker-XNAP7B5H.js");
11202
+ const { isStackRunning: isStackRunning2, stopStack } = await import("./docker-PYH5XATT.js");
11181
11203
  let stackRunning = false;
11182
11204
  try {
11183
11205
  stackRunning = isStackRunning2(composeFile);
@@ -13408,11 +13430,38 @@ function classifyError(err) {
13408
13430
  }
13409
13431
  return "UNKNOWN";
13410
13432
  }
13411
- function mapSdkMessage(message) {
13433
+ function mapSdkMessages(message) {
13412
13434
  const type = message.type;
13435
+ const events = [];
13436
+ if (type === "assistant") {
13437
+ const msg = message.message;
13438
+ if (!msg) return events;
13439
+ const content = msg.content;
13440
+ if (!Array.isArray(content)) return events;
13441
+ for (const block of content) {
13442
+ if (block.type === "tool_use") {
13443
+ const name = block.name;
13444
+ const id = block.id;
13445
+ const input = block.input;
13446
+ if (typeof name === "string") {
13447
+ events.push({ type: "tool-start", name, id: typeof id === "string" ? id : "" });
13448
+ if (input != null) {
13449
+ events.push({ type: "tool-input", partial: typeof input === "string" ? input : JSON.stringify(input) });
13450
+ }
13451
+ events.push({ type: "tool-complete" });
13452
+ }
13453
+ } else if (block.type === "text") {
13454
+ const text = block.text;
13455
+ if (typeof text === "string" && text.length > 0) {
13456
+ events.push({ type: "text", text });
13457
+ }
13458
+ }
13459
+ }
13460
+ return events;
13461
+ }
13413
13462
  if (type === "stream_event") {
13414
13463
  const event = message.event;
13415
- if (!event || typeof event !== "object") return null;
13464
+ if (!event || typeof event !== "object") return events;
13416
13465
  const eventType = event.type;
13417
13466
  if (eventType === "content_block_start") {
13418
13467
  const contentBlock = event.content_block;
@@ -13420,34 +13469,26 @@ function mapSdkMessage(message) {
13420
13469
  const name = contentBlock.name;
13421
13470
  const id = contentBlock.id;
13422
13471
  if (typeof name === "string" && typeof id === "string") {
13423
- return { type: "tool-start", name, id };
13472
+ events.push({ type: "tool-start", name, id });
13424
13473
  }
13425
13474
  }
13426
- return null;
13475
+ return events;
13427
13476
  }
13428
13477
  if (eventType === "content_block_delta") {
13429
13478
  const delta = event.delta;
13430
- if (!delta) return null;
13431
- if (delta.type === "input_json_delta") {
13432
- const partialJson = delta.partial_json;
13433
- if (typeof partialJson === "string") {
13434
- return { type: "tool-input", partial: partialJson };
13435
- }
13436
- return null;
13437
- }
13438
- if (delta.type === "text_delta") {
13439
- const text = delta.text;
13440
- if (typeof text === "string") {
13441
- return { type: "text", text };
13442
- }
13443
- return null;
13479
+ if (!delta) return events;
13480
+ if (delta.type === "input_json_delta" && typeof delta.partial_json === "string") {
13481
+ events.push({ type: "tool-input", partial: delta.partial_json });
13482
+ } else if (delta.type === "text_delta" && typeof delta.text === "string") {
13483
+ events.push({ type: "text", text: delta.text });
13444
13484
  }
13445
- return null;
13485
+ return events;
13446
13486
  }
13447
13487
  if (eventType === "content_block_stop") {
13448
- return { type: "tool-complete" };
13488
+ events.push({ type: "tool-complete" });
13489
+ return events;
13449
13490
  }
13450
- return null;
13491
+ return events;
13451
13492
  }
13452
13493
  if (type === "system") {
13453
13494
  const subtype = message.subtype;
@@ -13455,12 +13496,12 @@ function mapSdkMessage(message) {
13455
13496
  const attempt = message.attempt;
13456
13497
  const delay = message.retry_delay_ms;
13457
13498
  if (typeof attempt === "number" && typeof delay === "number") {
13458
- return { type: "retry", attempt, delay };
13499
+ events.push({ type: "retry", attempt, delay });
13459
13500
  }
13460
13501
  }
13461
- return null;
13502
+ return events;
13462
13503
  }
13463
- return null;
13504
+ return events;
13464
13505
  }
13465
13506
  var ClaudeCodeDriver = class {
13466
13507
  name = "claude-code";
@@ -13521,8 +13562,7 @@ var ClaudeCodeDriver = class {
13521
13562
  yieldedResult = true;
13522
13563
  continue;
13523
13564
  }
13524
- const streamEvent = mapSdkMessage(msg);
13525
- if (streamEvent) {
13565
+ for (const streamEvent of mapSdkMessages(msg)) {
13526
13566
  yield streamEvent;
13527
13567
  }
13528
13568
  }
@@ -14055,7 +14095,7 @@ function registerDriversCommand(program) {
14055
14095
  }
14056
14096
 
14057
14097
  // src/index.ts
14058
- var VERSION = true ? "0.29.3" : "0.0.0-dev";
14098
+ var VERSION = true ? "0.29.4" : "0.0.0-dev";
14059
14099
  function createProgram() {
14060
14100
  const program = new Command();
14061
14101
  program.name("codeharness").description("Makes autonomous coding agents produce software that actually works").version(VERSION).option("--json", "Output in machine-readable JSON format");
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "codeharness",
3
- "version": "0.29.3",
3
+ "version": "0.29.4",
4
4
  "type": "module",
5
5
  "description": "CLI for codeharness — makes autonomous coding agents produce software that actually works",
6
6
  "bin": {