@wrongstack/plugins 0.87.0 → 0.89.1

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.
@@ -54,6 +54,60 @@ function getCommitHistory(since, cwd) {
54
54
  return { hash, message, type };
55
55
  });
56
56
  }
57
+ function getWorktrees(cwd) {
58
+ try {
59
+ const out = runGit(["worktree", "list", "--porcelain"], cwd);
60
+ if (!out) return [];
61
+ const entries = [];
62
+ let current = {};
63
+ for (const line of out.split("\n")) {
64
+ if (line === "") {
65
+ if (current.path) entries.push(current);
66
+ current = {};
67
+ continue;
68
+ }
69
+ if (line.startsWith("worktree ")) current.path = line.slice(9);
70
+ else if (line.startsWith("HEAD ")) current.head = line.slice(5);
71
+ else if (line.startsWith("branch ")) current.branch = line.slice(7);
72
+ }
73
+ if (current.path) entries.push(current);
74
+ return entries;
75
+ } catch {
76
+ return [];
77
+ }
78
+ }
79
+ function simultaneousEditWarning(cwd) {
80
+ const worktrees = getWorktrees(cwd);
81
+ if (worktrees.length > 1) {
82
+ const otherBranches = worktrees.filter((wt) => wt.branch).map((wt) => wt.branch.replace("refs/heads/", ""));
83
+ return `\u26A0 Simultaneous edits detected: ${worktrees.length} active worktrees (${otherBranches.join(", ")}). Changes from other agents may mix into this commit. Consider using worktree isolation or verifying the diff below before committing.`;
84
+ }
85
+ return null;
86
+ }
87
+ function getStagedDiff(cwd) {
88
+ try {
89
+ const stat = runGit(["diff", "--cached", "--stat"], cwd);
90
+ const diff = runGit(["diff", "--cached"], cwd);
91
+ const MAX_DIFF = 2e4;
92
+ const truncated = diff.length > MAX_DIFF ? diff.slice(0, MAX_DIFF) + "\n\n... (diff truncated)" : diff;
93
+ return { stat: stat || "(no stat)", diff: truncated || "(clean)" };
94
+ } catch {
95
+ return { stat: "(unavailable)", diff: "(unavailable)" };
96
+ }
97
+ }
98
+ function externalChangesSinceStage(cwd) {
99
+ try {
100
+ const out = runGit(["status", "--porcelain"], cwd);
101
+ if (!out) return null;
102
+ const unstaged = out.split("\n").filter((l) => l.trim()).filter((l) => {
103
+ const idx = l[0] ?? " ";
104
+ return idx === " " || idx === "?";
105
+ }).map((l) => l.slice(3).trim());
106
+ return unstaged.length > 0 ? unstaged : null;
107
+ } catch {
108
+ return null;
109
+ }
110
+ }
57
111
  function generateCommitMessage(type, scope, summary, body) {
58
112
  const scopePart = scope ? `(${scope})` : "";
59
113
  const footer = body ? `
@@ -171,6 +225,39 @@ var plugin = {
171
225
  if (staged.length === 0) {
172
226
  return { ok: false, error: "Nothing staged. Add files with git add or provide files input." };
173
227
  }
228
+ const worktreeWarn = simultaneousEditWarning();
229
+ const externalChanges = externalChangesSinceStage();
230
+ let externalWarning = null;
231
+ if (externalChanges && externalChanges.length > 0) {
232
+ const preview = externalChanges.slice(0, 10).join(", ");
233
+ const suffix = externalChanges.length > 10 ? ` and ${externalChanges.length - 10} more` : "";
234
+ externalWarning = `\u26A0 External changes detected since staging: ${preview}${suffix}. Another agent may be modifying files concurrently. These unstaged changes will NOT be included in this commit, but they indicate simultaneous edits. Review carefully.`;
235
+ }
236
+ const warning = [worktreeWarn, externalWarning].filter(Boolean).join("\n") || void 0;
237
+ const { stat, diff: stagedDiff } = getStagedDiff();
238
+ if (dryRun) {
239
+ return {
240
+ ok: true,
241
+ dryRun: true,
242
+ message: `Would create: ${msg}`,
243
+ warning: warning ?? void 0,
244
+ stagedDiff: `
245
+ ## Staged changes (dry run)
246
+
247
+ ${stat}
248
+
249
+ \`\`\`diff
250
+ ${stagedDiff}
251
+ \`\`\``
252
+ };
253
+ }
254
+ let preCommitDiff = stagedDiff;
255
+ let preCommitStat = stat;
256
+ if (staged.length === 0) {
257
+ const fresh = getStagedDiff();
258
+ preCommitDiff = fresh.diff;
259
+ preCommitStat = fresh.stat;
260
+ }
174
261
  let hash = "";
175
262
  try {
176
263
  hash = commitWithMessage(msg);
@@ -185,7 +272,8 @@ var plugin = {
185
272
  hash: String(hash),
186
273
  commitType: type,
187
274
  scope: String(scope ?? ""),
188
- files: Array.isArray(staged) ? staged : []
275
+ files: Array.isArray(staged) ? staged : [],
276
+ warning: warning ?? null
189
277
  });
190
278
  } catch (_err) {
191
279
  }
@@ -195,7 +283,16 @@ var plugin = {
195
283
  message: msg,
196
284
  stagedFiles: staged,
197
285
  type,
198
- scope: scope ?? null
286
+ scope: scope ?? null,
287
+ warning: warning ?? void 0,
288
+ diff: `
289
+ ## Staged diff
290
+
291
+ ${preCommitStat}
292
+
293
+ \`\`\`diff
294
+ ${preCommitDiff}
295
+ \`\`\``
199
296
  };
200
297
  } catch (err) {
201
298
  return { ok: false, error: `Uncaught error in git_autocommit: ${err instanceof Error ? err.message : String(err)}` };
@@ -264,6 +361,9 @@ var plugin = {
264
361
  let staged = [];
265
362
  let aheadBehind = "";
266
363
  const recentCommits = [];
364
+ let worktrees = [];
365
+ let worktreeWarn = null;
366
+ let externalChanges = null;
267
367
  try {
268
368
  branch = runGit(["branch", "--show-current"]);
269
369
  } catch {
@@ -284,13 +384,36 @@ var plugin = {
284
384
  recentCommits.push(...getCommitHistory("-3", void 0).map((c) => ({ hash: (c.hash ?? "").slice(0, 7), message: c.message })));
285
385
  } catch {
286
386
  }
387
+ try {
388
+ worktrees = getWorktrees();
389
+ } catch {
390
+ }
391
+ try {
392
+ worktreeWarn = simultaneousEditWarning();
393
+ } catch {
394
+ }
395
+ try {
396
+ const out = runGit(["status", "--porcelain"]);
397
+ const unstaged = out.split("\n").filter((l) => {
398
+ const idx = l[0] ?? " ";
399
+ return idx === " " || idx === "?";
400
+ }).map((l) => l.slice(3).trim()).filter(Boolean);
401
+ externalChanges = unstaged.length > 0 ? unstaged : null;
402
+ } catch {
403
+ }
287
404
  return {
288
405
  ok: true,
289
406
  branch,
290
407
  changedFiles: changed,
291
408
  stagedFiles: staged,
292
409
  aheadBehind,
293
- recentCommits
410
+ recentCommits,
411
+ worktrees: worktrees.length > 0 ? worktrees.map((w) => ({
412
+ path: w.path,
413
+ branch: w.branch.replace("refs/heads/", "")
414
+ })) : [],
415
+ worktreeWarning: worktreeWarn ?? void 0,
416
+ externalChanges: externalChanges ?? void 0
294
417
  };
295
418
  }
296
419
  });
package/dist/index.js CHANGED
@@ -294,6 +294,60 @@ function getCommitHistory(since, cwd) {
294
294
  return { hash, message, type };
295
295
  });
296
296
  }
297
+ function getWorktrees(cwd) {
298
+ try {
299
+ const out = runGit(["worktree", "list", "--porcelain"], cwd);
300
+ if (!out) return [];
301
+ const entries = [];
302
+ let current = {};
303
+ for (const line of out.split("\n")) {
304
+ if (line === "") {
305
+ if (current.path) entries.push(current);
306
+ current = {};
307
+ continue;
308
+ }
309
+ if (line.startsWith("worktree ")) current.path = line.slice(9);
310
+ else if (line.startsWith("HEAD ")) current.head = line.slice(5);
311
+ else if (line.startsWith("branch ")) current.branch = line.slice(7);
312
+ }
313
+ if (current.path) entries.push(current);
314
+ return entries;
315
+ } catch {
316
+ return [];
317
+ }
318
+ }
319
+ function simultaneousEditWarning(cwd) {
320
+ const worktrees = getWorktrees(cwd);
321
+ if (worktrees.length > 1) {
322
+ const otherBranches = worktrees.filter((wt) => wt.branch).map((wt) => wt.branch.replace("refs/heads/", ""));
323
+ return `\u26A0 Simultaneous edits detected: ${worktrees.length} active worktrees (${otherBranches.join(", ")}). Changes from other agents may mix into this commit. Consider using worktree isolation or verifying the diff below before committing.`;
324
+ }
325
+ return null;
326
+ }
327
+ function getStagedDiff(cwd) {
328
+ try {
329
+ const stat = runGit(["diff", "--cached", "--stat"], cwd);
330
+ const diff = runGit(["diff", "--cached"], cwd);
331
+ const MAX_DIFF = 2e4;
332
+ const truncated = diff.length > MAX_DIFF ? diff.slice(0, MAX_DIFF) + "\n\n... (diff truncated)" : diff;
333
+ return { stat: stat || "(no stat)", diff: truncated || "(clean)" };
334
+ } catch {
335
+ return { stat: "(unavailable)", diff: "(unavailable)" };
336
+ }
337
+ }
338
+ function externalChangesSinceStage(cwd) {
339
+ try {
340
+ const out = runGit(["status", "--porcelain"], cwd);
341
+ if (!out) return null;
342
+ const unstaged = out.split("\n").filter((l) => l.trim()).filter((l) => {
343
+ const idx = l[0] ?? " ";
344
+ return idx === " " || idx === "?";
345
+ }).map((l) => l.slice(3).trim());
346
+ return unstaged.length > 0 ? unstaged : null;
347
+ } catch {
348
+ return null;
349
+ }
350
+ }
297
351
  function generateCommitMessage(type, scope, summary, body) {
298
352
  const scopePart = scope ? `(${scope})` : "";
299
353
  const footer = body ? `
@@ -411,6 +465,39 @@ var plugin2 = {
411
465
  if (staged.length === 0) {
412
466
  return { ok: false, error: "Nothing staged. Add files with git add or provide files input." };
413
467
  }
468
+ const worktreeWarn = simultaneousEditWarning();
469
+ const externalChanges = externalChangesSinceStage();
470
+ let externalWarning = null;
471
+ if (externalChanges && externalChanges.length > 0) {
472
+ const preview = externalChanges.slice(0, 10).join(", ");
473
+ const suffix = externalChanges.length > 10 ? ` and ${externalChanges.length - 10} more` : "";
474
+ externalWarning = `\u26A0 External changes detected since staging: ${preview}${suffix}. Another agent may be modifying files concurrently. These unstaged changes will NOT be included in this commit, but they indicate simultaneous edits. Review carefully.`;
475
+ }
476
+ const warning = [worktreeWarn, externalWarning].filter(Boolean).join("\n") || void 0;
477
+ const { stat, diff: stagedDiff } = getStagedDiff();
478
+ if (dryRun) {
479
+ return {
480
+ ok: true,
481
+ dryRun: true,
482
+ message: `Would create: ${msg}`,
483
+ warning: warning ?? void 0,
484
+ stagedDiff: `
485
+ ## Staged changes (dry run)
486
+
487
+ ${stat}
488
+
489
+ \`\`\`diff
490
+ ${stagedDiff}
491
+ \`\`\``
492
+ };
493
+ }
494
+ let preCommitDiff = stagedDiff;
495
+ let preCommitStat = stat;
496
+ if (staged.length === 0) {
497
+ const fresh = getStagedDiff();
498
+ preCommitDiff = fresh.diff;
499
+ preCommitStat = fresh.stat;
500
+ }
414
501
  let hash = "";
415
502
  try {
416
503
  hash = commitWithMessage(msg);
@@ -425,7 +512,8 @@ var plugin2 = {
425
512
  hash: String(hash),
426
513
  commitType: type,
427
514
  scope: String(scope ?? ""),
428
- files: Array.isArray(staged) ? staged : []
515
+ files: Array.isArray(staged) ? staged : [],
516
+ warning: warning ?? null
429
517
  });
430
518
  } catch (_err) {
431
519
  }
@@ -435,7 +523,16 @@ var plugin2 = {
435
523
  message: msg,
436
524
  stagedFiles: staged,
437
525
  type,
438
- scope: scope ?? null
526
+ scope: scope ?? null,
527
+ warning: warning ?? void 0,
528
+ diff: `
529
+ ## Staged diff
530
+
531
+ ${preCommitStat}
532
+
533
+ \`\`\`diff
534
+ ${preCommitDiff}
535
+ \`\`\``
439
536
  };
440
537
  } catch (err) {
441
538
  return { ok: false, error: `Uncaught error in git_autocommit: ${err instanceof Error ? err.message : String(err)}` };
@@ -504,6 +601,9 @@ var plugin2 = {
504
601
  let staged = [];
505
602
  let aheadBehind = "";
506
603
  const recentCommits = [];
604
+ let worktrees = [];
605
+ let worktreeWarn = null;
606
+ let externalChanges = null;
507
607
  try {
508
608
  branch = runGit(["branch", "--show-current"]);
509
609
  } catch {
@@ -524,13 +624,36 @@ var plugin2 = {
524
624
  recentCommits.push(...getCommitHistory("-3", void 0).map((c) => ({ hash: (c.hash ?? "").slice(0, 7), message: c.message })));
525
625
  } catch {
526
626
  }
627
+ try {
628
+ worktrees = getWorktrees();
629
+ } catch {
630
+ }
631
+ try {
632
+ worktreeWarn = simultaneousEditWarning();
633
+ } catch {
634
+ }
635
+ try {
636
+ const out = runGit(["status", "--porcelain"]);
637
+ const unstaged = out.split("\n").filter((l) => {
638
+ const idx = l[0] ?? " ";
639
+ return idx === " " || idx === "?";
640
+ }).map((l) => l.slice(3).trim()).filter(Boolean);
641
+ externalChanges = unstaged.length > 0 ? unstaged : null;
642
+ } catch {
643
+ }
527
644
  return {
528
645
  ok: true,
529
646
  branch,
530
647
  changedFiles: changed,
531
648
  stagedFiles: staged,
532
649
  aheadBehind,
533
- recentCommits
650
+ recentCommits,
651
+ worktrees: worktrees.length > 0 ? worktrees.map((w) => ({
652
+ path: w.path,
653
+ branch: w.branch.replace("refs/heads/", "")
654
+ })) : [],
655
+ worktreeWarning: worktreeWarn ?? void 0,
656
+ externalChanges: externalChanges ?? void 0
534
657
  };
535
658
  }
536
659
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@wrongstack/plugins",
3
- "version": "0.87.0",
3
+ "version": "0.89.1",
4
4
  "description": "Official WrongStack plugin collection — auto-doc, git-autocommit, shell-check, cost-tracker, file-watcher, web-search, json-path, cron, template-engine, semver-bump",
5
5
  "license": "MIT",
6
6
  "author": "ECOSTACK TECHNOLOGY OÜ",
@@ -63,7 +63,7 @@
63
63
  "vitest": "^4.1.7"
64
64
  },
65
65
  "dependencies": {
66
- "@wrongstack/core": "0.87.0"
66
+ "@wrongstack/core": "0.89.1"
67
67
  },
68
68
  "scripts": {
69
69
  "build": "tsup",