@wrongstack/plugins 0.84.1 → 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.
- package/dist/git-autocommit.js +126 -3
- package/dist/index.js +126 -3
- package/package.json +2 -2
package/dist/git-autocommit.js
CHANGED
|
@@ -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.
|
|
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.
|
|
66
|
+
"@wrongstack/core": "0.89.1"
|
|
67
67
|
},
|
|
68
68
|
"scripts": {
|
|
69
69
|
"build": "tsup",
|