tewip-ai 0.70.6 → 0.70.7

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.
@@ -62,19 +62,52 @@ ${noModelHelp()}`);
62
62
  const fileName = framework.fileFor(scenario.id);
63
63
  const file = join(framework.testDir, fileName);
64
64
  if (existsSync(file) || (cmd.moveTo && existsSync(join(cmd.moveTo, fileName)))) {
65
- results.push({ id: scenario.id, title: scenario.title, file, outcome: { kind: 'rejected', reason: `${fileName} already exists; left untouched`, repairs: 0, passedReliably: false } });
65
+ // Every file this command writes carries "tewip" in its name, so one already sitting here is
66
+ // one of its own - an unverified draft from a run that did not finish, not a test the team
67
+ // wrote. Calling that "left untouched" sounds like a decision and hides that the file is in
68
+ // the test folder, where the suite is running it.
69
+ //
70
+ // Matched case-insensitively on the whole name rather than as a prefix, because only the
71
+ // JavaScript frameworks produce `tewip-ls-002.spec.ts`: pytest gives `test_tewip_ls_002.py`
72
+ // and JUnit `TewipLs002Test.java`, and a prefix check would have handed Python and Java teams
73
+ // the misleading message this fix exists to remove.
74
+ const mine = /tewip/i.test(fileName);
75
+ results.push({
76
+ id: scenario.id,
77
+ title: scenario.title,
78
+ file,
79
+ outcome: {
80
+ kind: 'rejected',
81
+ reason: mine
82
+ ? `${fileName} is already here from a run that did not finish, and was never verified. It is in your test folder, so your suite is running it: delete it, or move it to .tewip/drafts/, then ask again.`
83
+ : `${fileName} already exists and was written by somebody else; left untouched`,
84
+ repairs: 0,
85
+ passedReliably: false,
86
+ },
87
+ });
66
88
  continue;
67
89
  }
68
90
  console.error(` ${scenario.id} ${scenario.title}`);
69
- // Stopped part-way (Ctrl+C), a draft that was never verified must not stay in the project.
91
+ // A draft that was never verified must not stay in the project, however the run ended.
92
+ //
93
+ // SIGINT and SIGTERM were covered; nothing else was. A run of this interrupted another way -
94
+ // a closed pipe, an uncaught throw, a kill - left the draft in the **test folder**, where the
95
+ // project's own suite then runs it. Seen for real: a two-scenario run was cut short by a broken
96
+ // shell command, the suite went from green to red, and the next `write` reported the leftover as
97
+ // "already exists; left untouched", which reads like a decision rather than a casualty.
98
+ //
99
+ // `renameSync` is synchronous, so an `exit` handler can still do it: that covers every way out.
100
+ const rescue = () => {
101
+ if (!existsSync(file))
102
+ return;
103
+ mkdirSync(drafts, { recursive: true });
104
+ renameSync(file, join(drafts, fileName));
105
+ };
70
106
  const leaveNothing = () => {
71
- if (existsSync(file)) {
72
- mkdirSync(drafts, { recursive: true });
73
- renameSync(file, join(drafts, fileName));
74
- }
107
+ rescue();
75
108
  process.exit(130);
76
109
  };
77
- process.once('SIGINT', leaveNothing).once('SIGTERM', leaveNothing);
110
+ process.once('SIGINT', leaveNothing).once('SIGTERM', leaveNothing).once('exit', rescue);
78
111
  let outcome;
79
112
  try {
80
113
  ({ outcome } = await writeAndVerify(model, { framework, fileName, pages, feature: saved.feature, code, houseRules: guidanceFor(loadStandards(cmd.root), fileName) }, scenario, file, { runs: cmd.runs, repairs: cmd.repairs, mutateSource: cmd.mutateSource, log: (l) => console.error(l) }));
@@ -83,7 +116,7 @@ ${noModelHelp()}`);
83
116
  outcome = { kind: 'rejected', reason: `stopped: ${error.message}`, repairs: 0, passedReliably: false };
84
117
  }
85
118
  finally {
86
- process.off('SIGINT', leaveNothing).off('SIGTERM', leaveNothing);
119
+ process.off('SIGINT', leaveNothing).off('SIGTERM', leaveNothing).off('exit', rescue);
87
120
  }
88
121
  // Some runners take minutes per run (Angular rebuilds the app for every `ng test`): say how long
89
122
  // the rest will take, so a slow run is not mistaken for a stuck one.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "tewip-ai",
3
- "version": "0.70.6",
3
+ "version": "0.70.7",
4
4
  "mcpName": "io.github.hmamut39/tewip",
5
5
  "description": "Tewip finds why each failing test failed - real bug, flaky test, environment, test data or changed selector - for any stack, from the command line, CI, or your editor.",
6
6
  "keywords": [