@wrongstack/plugins 0.275.1 → 0.276.2

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.
@@ -4,8 +4,9 @@ import { Plugin } from '@wrongstack/core';
4
4
  * auto-doc plugin — Auto-generates JSDoc/TSDoc comments for source files.
5
5
  *
6
6
  * Tools registered:
7
- * - auto_doc: Generate and inject doc comments into JS/TS files
8
- * - auto_doc_preview: Preview doc comments without writing them
7
+ * - auto_doc: Generate and inject doc comments into JS/TS files.
8
+ * Pass `dry_run: true` to preview without writing (replaces the former
9
+ * `auto_doc (dry_run)` tool).
9
10
  */
10
11
 
11
12
  declare const plugin: Plugin;
package/dist/auto-doc.js CHANGED
@@ -117,7 +117,7 @@ async function runAutoDoc(input, api) {
117
117
  modified = injectDocComment(modified, entity, doc);
118
118
  results.push({ file, entity: entity.name });
119
119
  }
120
- if (!input.dryRun && results.length > 0) {
120
+ if (!input.dry_run && results.length > 0) {
121
121
  writeFileSync(file, modified, "utf-8");
122
122
  api.log.info(`auto-doc: updated ${file}`);
123
123
  }
@@ -127,31 +127,9 @@ async function runAutoDoc(input, api) {
127
127
  }
128
128
  return { ok: true, filesProcessed: input.files.length, changes: results };
129
129
  }
130
- async function runAutoDocPreview(input, api) {
131
- if (!input.files || typeof input.files !== "object" || !Array.isArray(input.files)) {
132
- return { ok: false, error: "input.files must be an array of file paths", previews: [] };
133
- }
134
- if (input.files.length === 0) {
135
- return { ok: false, error: "input.files is empty \u2014 provide at least one file path", previews: [] };
136
- }
137
- const includeTypes = api.config.extensions?.["auto-doc"]?.["includeTypes"] ?? false;
138
- const previews = [];
139
- for (const file of input.files) {
140
- try {
141
- const { readFileSync } = await import('fs');
142
- const content = readFileSync(file, "utf-8");
143
- const entities = parseSource(content);
144
- const generated = entities.filter((e) => needsDocComment(content, e)).map((e) => generateDocComment(e, includeTypes));
145
- previews.push({ file, entities: generated });
146
- } catch {
147
- api.log.warn(`auto-doc-preview: could not read file ${file}`);
148
- }
149
- }
150
- return { ok: true, previews };
151
- }
152
130
  var plugin = {
153
131
  name: "auto-doc",
154
- version: "0.1.0",
132
+ version: "0.2.0",
155
133
  description: "Auto-generates JSDoc/TSDoc comments for functions, classes, types, and interfaces",
156
134
  apiVersion: AUTO_DOC_API_VERSION,
157
135
  capabilities: { tools: true, pipelines: ["toolCall"] },
@@ -167,41 +145,25 @@ var plugin = {
167
145
  setup(api) {
168
146
  api.tools.register({
169
147
  name: "auto_doc",
170
- description: "Auto-generate JSDoc/TSDoc comments for functions, classes, types, and interfaces in source files",
148
+ description: "Auto-generate JSDoc/TSDoc comments for functions, classes, types, and interfaces in source files. Set `dry_run: true` to preview without writing.",
171
149
  inputSchema: {
172
150
  type: "object",
173
151
  properties: {
174
152
  files: { type: "array", items: { type: "string" }, description: "Source files to document" },
175
153
  style: { type: "string", enum: ["jsdoc", "tsdoc"], default: "tsdoc", description: "Comment style" },
176
154
  force: { type: "boolean", default: false, description: "Overwrite existing docstrings" },
177
- dryRun: { type: "boolean", default: false, description: "Preview without writing" }
155
+ dry_run: { type: "boolean", default: false, description: "Preview generated comments without writing to files" }
178
156
  },
179
157
  required: ["files"]
180
158
  },
181
159
  permission: "auto",
182
160
  mutating: true,
161
+ category: "Project",
183
162
  async execute(input) {
184
163
  return runAutoDoc(input, api);
185
164
  }
186
165
  });
187
- api.tools.register({
188
- name: "auto_doc_preview",
189
- description: "Preview what JSDoc/TSDoc comments would be generated for files, without writing",
190
- inputSchema: {
191
- type: "object",
192
- properties: {
193
- files: { type: "array", items: { type: "string" }, description: "Source files to preview" },
194
- style: { type: "string", enum: ["jsdoc", "tsdoc"], default: "tsdoc" }
195
- },
196
- required: ["files"]
197
- },
198
- permission: "auto",
199
- mutating: false,
200
- async execute(input) {
201
- return runAutoDocPreview(input, api);
202
- }
203
- });
204
- api.log.info("auto-doc plugin loaded", { version: "0.1.0", capabilities: ["auto_doc", "auto_doc_preview"] });
166
+ api.log.info("auto-doc plugin loaded", { version: "0.2.0", capabilities: ["auto_doc"] });
205
167
  },
206
168
  teardown(api) {
207
169
  api.log.info("auto-doc plugin unloaded");
@@ -91,6 +91,7 @@ var plugin = {
91
91
  description: "Returns the current session's token usage breakdown by model, total cost estimate, and budget status.",
92
92
  inputSchema: { type: "object", properties: {} },
93
93
  permission: "auto",
94
+ category: "Meta",
94
95
  mutating: false,
95
96
  async execute() {
96
97
  const { budgetLimit, warningThreshold } = readCostTrackerConfig(
package/dist/cron.js CHANGED
@@ -119,6 +119,7 @@ var plugin = {
119
119
  required: ["name", "intervalMs", "action"]
120
120
  },
121
121
  permission: "confirm",
122
+ category: "Session",
122
123
  mutating: false,
123
124
  capabilities: [COORDINATION_CRON_CAPABILITY],
124
125
  async execute(input) {
@@ -3,9 +3,9 @@ import * as path from 'path';
3
3
 
4
4
  // src/file-watcher/index.ts
5
5
  var API_VERSION = "^0.1.10";
6
- var watchIdCounter = 0;
6
+ var watch_idCounter = 0;
7
7
  function nextId() {
8
- return `watch_${++watchIdCounter}_${Date.now().toString(36)}`;
8
+ return `watch_${++watch_idCounter}_${Date.now().toString(36)}`;
9
9
  }
10
10
  var watches = /* @__PURE__ */ new Map();
11
11
  var debounceTimers = /* @__PURE__ */ new Map();
@@ -90,7 +90,7 @@ var plugin = {
90
90
  const key = `${handle.id}:${fullPath}:${eventType}`;
91
91
  debounceEvent(key, () => {
92
92
  api.emitCustom("file-watcher:changed", {
93
- watchId: handle.id,
93
+ watch_id: handle.id,
94
94
  path: fullPath,
95
95
  event: eventType,
96
96
  filename,
@@ -151,15 +151,16 @@ var plugin = {
151
151
  required: ["paths"]
152
152
  },
153
153
  permission: "confirm",
154
+ category: "Filesystem",
154
155
  mutating: false,
155
156
  async execute(input) {
156
157
  const rawPaths = input["paths"];
157
158
  if (!rawPaths || typeof rawPaths !== "object" || !Array.isArray(rawPaths)) {
158
- return { ok: false, error: "paths must be an array of file/directory paths", watchId: null };
159
+ return { ok: false, error: "paths must be an array of file/directory paths", watch_id: null };
159
160
  }
160
161
  const paths = rawPaths;
161
162
  if (paths.length === 0) {
162
- return { ok: false, error: "paths array is empty \u2014 provide at least one path", watchId: null };
163
+ return { ok: false, error: "paths array is empty \u2014 provide at least one path", watch_id: null };
163
164
  }
164
165
  const events = input["events"] ?? ["change", "add", "delete"];
165
166
  const recursive = input["recursive"] ?? true;
@@ -179,7 +180,7 @@ var plugin = {
179
180
  api.metrics.gauge("active_watches", watches.size);
180
181
  return {
181
182
  ok: true,
182
- watchId: id,
183
+ watch_id: id,
183
184
  paths,
184
185
  events,
185
186
  recursive,
@@ -193,17 +194,17 @@ var plugin = {
193
194
  inputSchema: {
194
195
  type: "object",
195
196
  properties: {
196
- watchId: { type: "string", description: "Watch ID returned by watch_start" }
197
+ watch_id: { type: "string", description: "Watch ID returned by watch_start" }
197
198
  },
198
- required: ["watchId"]
199
+ required: ["watch_id"]
199
200
  },
200
201
  permission: "auto",
201
202
  mutating: false,
202
203
  async execute(input) {
203
- const watchId = input["watchId"];
204
- const handle = watches.get(watchId);
204
+ const watch_id = input["watch_id"];
205
+ const handle = watches.get(watch_id);
205
206
  if (!handle) {
206
- return { ok: false, error: `No active watch with ID: ${watchId}` };
207
+ return { ok: false, error: `No active watch with ID: ${watch_id}` };
207
208
  }
208
209
  for (const w of handle.watchers) {
209
210
  try {
@@ -211,12 +212,12 @@ var plugin = {
211
212
  } catch {
212
213
  }
213
214
  }
214
- watches.delete(watchId);
215
+ watches.delete(watch_id);
215
216
  api.metrics.gauge("active_watches", watches.size);
216
217
  return {
217
218
  ok: true,
218
- watchId,
219
- message: `Stopped watch ${watchId}. ${watches.size} watch(es) remaining.`
219
+ watch_id,
220
+ message: `Stopped watch ${watch_id}. ${watches.size} watch(es) remaining.`
220
221
  };
221
222
  }
222
223
  });
@@ -4,9 +4,12 @@ import { Plugin } from '@wrongstack/core';
4
4
  * git-autocommit plugin — AI-powered git staging and commit message generation.
5
5
  *
6
6
  * Tools registered:
7
- * - git_autocommit: Generate and create a commit with AI-written messages
8
- * - git_stage: Stage specific files for commit
9
- * - git_status_summary: Show a summary of current git status
7
+ * - git_autocommit: Stage files and create a commit with AI-written conventional commit messages.
8
+ * Supports `files` for specific staging and `dry_run` for preview.
9
+ *
10
+ * Note: The former `git_autocommit` and `git_autocommit` tools have been removed.
11
+ * - For staging: use `git_autocommit` with `files` (it stages automatically), or `bash` with `git add`.
12
+ * - For status: use the built-in `git` tool with `command: "status"` or `command: "diff"`.
10
13
  */
11
14
 
12
15
  declare const plugin: Plugin;
@@ -42,19 +42,6 @@ function stageFiles(files, cwd) {
42
42
  function commitWithMessage(message, cwd) {
43
43
  return runGit(["commit", "-m", message], cwd);
44
44
  }
45
- function getCommitHistory(since, cwd) {
46
- const range = `${since}..HEAD` ;
47
- const output = runGit(["log", range, "--format=%H %s"], cwd);
48
- if (!output) return [];
49
- return output.split("\n").filter(Boolean).map((line) => {
50
- const spaceIdx = line.indexOf(" ");
51
- const hash = line.slice(0, spaceIdx);
52
- const message = line.slice(spaceIdx + 1);
53
- const typeMatch = message.match(/^(\w+)(!)?:\s/);
54
- const type = typeMatch?.[1] ?? "chore";
55
- return { hash, message, type };
56
- });
57
- }
58
45
  function getWorktrees(cwd) {
59
46
  try {
60
47
  const out = runGit(["worktree", "list", "--porcelain"], cwd);
@@ -118,7 +105,7 @@ ${body}` : "";
118
105
  }
119
106
  var plugin = {
120
107
  name: "git-autocommit",
121
- version: "0.1.0",
108
+ version: "0.2.0",
122
109
  description: "AI-powered git staging and conventional commit message generation",
123
110
  apiVersion: API_VERSION,
124
111
  capabilities: { tools: true },
@@ -161,10 +148,11 @@ var plugin = {
161
148
  scope: { type: "string", description: "Commit scope (e.g. auth, api, ui)" },
162
149
  message: { type: "string", description: "Commit summary message" },
163
150
  body: { type: "string", description: "Optional commit body/description" },
164
- dryRun: { type: "boolean", default: false, description: "Show what would be committed without committing" }
151
+ dry_run: { type: "boolean", default: false, description: "Show what would be committed without committing" }
165
152
  }
166
153
  },
167
154
  permission: "confirm",
155
+ category: "Git",
168
156
  mutating: true,
169
157
  async execute(input, _ctx) {
170
158
  try {
@@ -172,13 +160,13 @@ var plugin = {
172
160
  const scope = input["scope"];
173
161
  const summary = input["message"] ?? "";
174
162
  const body = input["body"];
175
- const dryRun = input["dryRun"] ?? false;
163
+ const dryRun = input["dry_run"] ?? false;
176
164
  const validTypes = ["feat", "fix", "docs", "style", "refactor", "test", "chore", "perf", "ci", "build", "revert"];
177
165
  if (!type || !validTypes.includes(type)) {
178
166
  if (dryRun) {
179
167
  return {
180
168
  ok: true,
181
- dryRun: true,
169
+ dry_run: true,
182
170
  message: `Would create: ${summary || "update code"}`
183
171
  };
184
172
  }
@@ -239,7 +227,7 @@ var plugin = {
239
227
  if (dryRun) {
240
228
  return {
241
229
  ok: true,
242
- dryRun: true,
230
+ dry_run: true,
243
231
  message: `Would create: ${msg}`,
244
232
  warning: warning ?? void 0,
245
233
  stagedDiff: `
@@ -301,126 +289,8 @@ ${preCommitDiff}
301
289
  }
302
290
  }
303
291
  });
304
- api.tools.register({
305
- name: "git_stage",
306
- description: "Stage specific files for commit. Shows what would be staged without staging if dryRun is true.",
307
- inputSchema: {
308
- type: "object",
309
- properties: {
310
- files: { type: "array", items: { type: "string" }, description: "Files to stage" },
311
- dryRun: { type: "boolean", default: false }
312
- },
313
- required: ["files"]
314
- },
315
- permission: "confirm",
316
- mutating: true,
317
- async execute(input) {
318
- try {
319
- let files;
320
- try {
321
- files = input["files"] ?? [];
322
- } catch {
323
- files = [];
324
- }
325
- const dryRun = input["dryRun"] ?? false;
326
- if (!Array.isArray(files) || files.length === 0) {
327
- return { ok: false, error: "files must be a non-empty array of file paths" };
328
- }
329
- if (dryRun) {
330
- return { ok: true, dryRun: true, files, message: `Would stage: ${files.join(", ")}` };
331
- }
332
- try {
333
- stageFiles(files);
334
- } catch (err) {
335
- return { ok: false, error: `Failed to stage files: ${err instanceof Error ? err.message : String(err)}` };
336
- }
337
- let stillChanged = [];
338
- try {
339
- stillChanged = getChangedFiles();
340
- } catch {
341
- stillChanged = [];
342
- }
343
- return {
344
- ok: true,
345
- staged: files,
346
- stillChanged,
347
- message: `Staged ${files.length} file(s). ${stillChanged.length} file(s) still changed.`
348
- };
349
- } catch (err) {
350
- return { ok: false, error: `git_stage error: ${err instanceof Error ? err.message : String(err)}` };
351
- }
352
- }
353
- });
354
- api.tools.register({
355
- name: "git_status_summary",
356
- description: "Returns a summary of the current git repository status: changed files, staged files, current branch, and recent commits.",
357
- inputSchema: { type: "object", properties: {} },
358
- permission: "auto",
359
- mutating: false,
360
- async execute() {
361
- let branch = "";
362
- let changed = [];
363
- let staged = [];
364
- let aheadBehind = "";
365
- const recentCommits = [];
366
- let worktrees = [];
367
- let worktreeWarn = null;
368
- let externalChanges = null;
369
- try {
370
- branch = runGit(["branch", "--show-current"]);
371
- } catch {
372
- }
373
- try {
374
- changed = getChangedFiles();
375
- } catch {
376
- }
377
- try {
378
- staged = getStagedFiles();
379
- } catch {
380
- }
381
- try {
382
- aheadBehind = runGit(["status", "-sb"]).split("\n")[0] ?? "";
383
- } catch {
384
- }
385
- try {
386
- recentCommits.push(...getCommitHistory("-3", void 0).map((c) => ({ hash: (c.hash ?? "").slice(0, 7), message: c.message })));
387
- } catch {
388
- }
389
- try {
390
- worktrees = getWorktrees();
391
- } catch {
392
- }
393
- try {
394
- worktreeWarn = simultaneousEditWarning();
395
- } catch {
396
- }
397
- try {
398
- const out = runGit(["status", "--porcelain"]);
399
- const unstaged = out.split("\n").filter((l) => {
400
- const idx = l[0] ?? " ";
401
- return idx === " " || idx === "?";
402
- }).map((l) => l.slice(3).trim()).filter(Boolean);
403
- externalChanges = unstaged.length > 0 ? unstaged : null;
404
- } catch {
405
- }
406
- return {
407
- ok: true,
408
- branch,
409
- changedFiles: changed,
410
- stagedFiles: staged,
411
- aheadBehind,
412
- recentCommits,
413
- worktrees: worktrees.length > 0 ? worktrees.map((w) => ({
414
- path: w.path,
415
- branch: w.branch.replace("refs/heads/", "")
416
- })) : [],
417
- worktreeWarning: worktreeWarn ?? void 0,
418
- externalChanges: externalChanges ?? void 0
419
- };
420
- }
421
- });
422
292
  api.log.info("git-autocommit plugin loaded", {
423
- version: "0.1.0",
293
+ version: "0.2.0",
424
294
  conventionalCommits: opts.conventionalCommits
425
295
  });
426
296
  }