cursor-guard 4.9.12 → 4.9.15

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.
Files changed (30) hide show
  1. package/README.md +697 -697
  2. package/README.zh-CN.md +696 -696
  3. package/ROADMAP.md +1775 -1758
  4. package/SKILL.md +631 -629
  5. package/docs/RELEASE.md +197 -196
  6. package/docs/SNAPSHOT-BOOKMARK.md +47 -0
  7. package/package.json +2 -1
  8. package/references/dashboard/public/app.js +2079 -2050
  9. package/references/dashboard/public/style.css +1660 -1628
  10. package/references/lib/core/backups.js +509 -507
  11. package/references/lib/core/core.test.js +39 -1
  12. package/references/lib/core/snapshot.js +441 -416
  13. package/references/mcp/mcp.test.js +381 -362
  14. package/references/mcp/server.js +404 -347
  15. package/references/vscode-extension/{cursor-guard-ide-4.9.12.vsix → dist/cursor-guard-ide-4.9.15.vsix} +0 -0
  16. package/references/vscode-extension/dist/dashboard/public/app.js +2079 -2050
  17. package/references/vscode-extension/dist/dashboard/public/style.css +1660 -1628
  18. package/references/vscode-extension/dist/extension.js +780 -704
  19. package/references/vscode-extension/dist/guard-version.json +1 -1
  20. package/references/vscode-extension/dist/lib/auto-setup.js +201 -192
  21. package/references/vscode-extension/dist/lib/core/backups.js +509 -507
  22. package/references/vscode-extension/dist/lib/core/snapshot.js +441 -416
  23. package/references/vscode-extension/dist/mcp/server.js +78 -12
  24. package/references/vscode-extension/dist/package.json +7 -1
  25. package/references/vscode-extension/dist/skill/ROADMAP.md +1775 -1758
  26. package/references/vscode-extension/dist/skill/SKILL.md +631 -629
  27. package/references/vscode-extension/extension.js +780 -704
  28. package/references/vscode-extension/lib/auto-setup.js +201 -192
  29. package/references/vscode-extension/package.json +7 -1
  30. package/references/vscode-extension/dist/cursor-guard-ide-4.9.12.vsix +0 -0
@@ -35594,7 +35594,7 @@ var require_package = __commonJS({
35594
35594
  "package.json"(exports2, module2) {
35595
35595
  module2.exports = {
35596
35596
  name: "cursor-guard",
35597
- version: "4.9.12",
35597
+ version: "4.9.15",
35598
35598
  description: "Protects code from accidental AI overwrite or deletion in Cursor IDE \u2014 mandatory pre-write snapshots, review-before-apply, local Git safety net, and deterministic recovery. | \u4FDD\u62A4\u4EE3\u7801\u514D\u53D7 Cursor AI \u4EE3\u7406\u610F\u5916\u8986\u5199\u6216\u5220\u9664\u2014\u2014\u5F3A\u5236\u5199\u524D\u5FEB\u7167\u3001\u9884\u89C8\u518D\u6267\u884C\u3001\u672C\u5730 Git \u5B89\u5168\u7F51\u3001\u786E\u5B9A\u6027\u6062\u590D\u3002",
35599
35599
  keywords: [
35600
35600
  "cursor",
@@ -35633,6 +35633,7 @@ var require_package = __commonJS({
35633
35633
  "README.md",
35634
35634
  "README.zh-CN.md",
35635
35635
  "docs/RELEASE.md",
35636
+ "docs/SNAPSHOT-BOOKMARK.md",
35636
35637
  "ROADMAP.md",
35637
35638
  "LICENSE",
35638
35639
  "references/auto-backup.ps1",
@@ -36078,6 +36079,10 @@ var require_snapshot = __commonJS({
36078
36079
  }
36079
36080
  return excluded;
36080
36081
  }
36082
+ function trailerScalar2(val, maxLen = 500) {
36083
+ if (val == null) return "";
36084
+ return String(val).replace(/\r\n/g, " ").replace(/\r/g, " ").replace(/\n/g, " ").trim().slice(0, maxLen);
36085
+ }
36081
36086
  function buildCommitMessage(ts, opts) {
36082
36087
  if (opts.message && !opts.context) return opts.message;
36083
36088
  const ctx = opts.context || {};
@@ -36085,11 +36090,12 @@ var require_snapshot = __commonJS({
36085
36090
  const subject = opts.message || `guard: auto-backup ${ts}${countTag}`;
36086
36091
  const trailers = [];
36087
36092
  if (ctx.changedFileCount != null) trailers.push(`Files-Changed: ${ctx.changedFileCount}`);
36088
- if (ctx.summary) trailers.push(`Summary: ${ctx.summary}`);
36089
- if (ctx.trigger) trailers.push(`Trigger: ${ctx.trigger}`);
36090
- if (ctx.intent) trailers.push(`Intent: ${ctx.intent}`);
36091
- if (ctx.agent) trailers.push(`Agent: ${ctx.agent}`);
36092
- if (ctx.session) trailers.push(`Session: ${ctx.session}`);
36093
+ if (ctx.summary) trailers.push(`Summary: ${trailerScalar2(ctx.summary, 2e3)}`);
36094
+ if (ctx.trigger) trailers.push(`Trigger: ${trailerScalar2(ctx.trigger)}`);
36095
+ if (ctx.intent) trailers.push(`Intent: ${trailerScalar2(ctx.intent)}`);
36096
+ if (ctx.agent) trailers.push(`Agent: ${trailerScalar2(ctx.agent)}`);
36097
+ if (ctx.session) trailers.push(`Session: ${trailerScalar2(ctx.session)}`);
36098
+ if (ctx.guardEvent) trailers.push(`Guard-Event: ${trailerScalar2(ctx.guardEvent)}`);
36093
36099
  if (trailers.length === 0) return subject;
36094
36100
  return subject + "\n\n" + trailers.join("\n");
36095
36101
  }
@@ -36128,6 +36134,7 @@ var require_snapshot = __commonJS({
36128
36134
  if (newTree === parentTree && !opts.allowEmptyTree) {
36129
36135
  return { status: "skipped", reason: "tree unchanged" };
36130
36136
  }
36137
+ const isBookmarkCommit = !!(opts.allowEmptyTree && parentTree && newTree === parentTree);
36131
36138
  let changedCount;
36132
36139
  let incrementalSummary;
36133
36140
  let changedFiles;
@@ -36216,6 +36223,13 @@ var require_snapshot = __commonJS({
36216
36223
  if (changedCount != null && opts.context) {
36217
36224
  opts.context.changedFileCount = changedCount;
36218
36225
  }
36226
+ if (isBookmarkCommit && opts.context) {
36227
+ const s = opts.context.summary;
36228
+ if (s == null || String(s).trim() === "") {
36229
+ opts.context.summary = "No file changes since last Guard baseline (bookmark).";
36230
+ }
36231
+ if (opts.context.changedFileCount == null) opts.context.changedFileCount = 0;
36232
+ }
36219
36233
  const ts = formatTimestamp(/* @__PURE__ */ new Date());
36220
36234
  let msg = buildCommitMessage(ts, opts);
36221
36235
  const autoTip = git(["rev-parse", "--verify", REF_GUARD_AUTO_BACKUP], { cwd, allowFail: true });
@@ -36230,7 +36244,7 @@ var require_snapshot = __commonJS({
36230
36244
  }
36231
36245
  const scopeTrailer = narrowProtect ? "narrow" : "full";
36232
36246
  const guardBlock = `Guard-Diff-Base: ${diffBaseLabel}
36233
- Guard-Scope: ${scopeTrailer}`;
36247
+ Guard-Scope: ${scopeTrailer}${isBookmarkCommit ? "\nGuard-Bookmark: true" : ""}`;
36234
36248
  msg = msg.includes("\n\n") ? `${msg}
36235
36249
  ${guardBlock}` : `${msg}
36236
36250
 
@@ -36251,7 +36265,8 @@ ${guardBlock}`;
36251
36265
  changedCount,
36252
36266
  changedFiles,
36253
36267
  incrementalSummary,
36254
- secretsExcluded: secretsExcluded.length > 0 ? secretsExcluded : void 0
36268
+ secretsExcluded: secretsExcluded.length > 0 ? secretsExcluded : void 0,
36269
+ ...isBookmarkCommit ? { bookmark: true } : {}
36255
36270
  };
36256
36271
  } catch (e) {
36257
36272
  return { status: "error", error: e.message };
@@ -36335,7 +36350,7 @@ ${guardBlock}`;
36335
36350
  return { status: "error", error: e.message };
36336
36351
  }
36337
36352
  }
36338
- module2.exports = { createGitSnapshot: createGitSnapshot2, createShadowCopy: createShadowCopy2, formatTimestamp, removeSecretsFromIndex };
36353
+ module2.exports = { createGitSnapshot: createGitSnapshot2, createShadowCopy: createShadowCopy2, formatTimestamp, removeSecretsFromIndex, trailerScalar: trailerScalar2 };
36339
36354
  }
36340
36355
  });
36341
36356
 
@@ -36387,11 +36402,13 @@ var require_backups = __commonJS({
36387
36402
  "Intent": { key: "intent" },
36388
36403
  "Agent": { key: "agent" },
36389
36404
  "Session": { key: "session" },
36405
+ "Guard-Event": { key: "guardEvent" },
36390
36406
  "From": { key: "from" },
36391
36407
  "Restore-To": { key: "restoreTo" },
36392
36408
  "File": { key: "restoreFile" },
36393
36409
  "Guard-Diff-Base": { key: "guardDiffBase" },
36394
- "Guard-Scope": { key: "guardScope" }
36410
+ "Guard-Scope": { key: "guardScope" },
36411
+ "Guard-Bookmark": { key: "guardBookmark", parse: (v) => String(v).trim().toLowerCase() === "true" }
36395
36412
  };
36396
36413
  function parseCommitTrailers(body) {
36397
36414
  if (!body) return {};
@@ -38101,7 +38118,7 @@ var { McpServer } = require_mcp();
38101
38118
  var { StdioServerTransport } = require_stdio2();
38102
38119
  var { z } = require_zod();
38103
38120
  var { runDiagnostics } = require_doctor();
38104
- var { createGitSnapshot, createShadowCopy } = require_snapshot();
38121
+ var { createGitSnapshot, createShadowCopy, trailerScalar } = require_snapshot();
38105
38122
  var { listBackups } = require_backups();
38106
38123
  var { restoreFile, previewProjectRestore, executeProjectRestore } = require_restore();
38107
38124
  var { runFixes } = require_doctor_fix();
@@ -38223,7 +38240,7 @@ server.tool(
38223
38240
  );
38224
38241
  server.tool(
38225
38242
  "snapshot_now",
38226
- "Create an immediate backup snapshot of the current project state. Use before risky operations to preserve a restore point.",
38243
+ "Create an immediate backup snapshot of the current project state. Use before risky operations to preserve a restore point. If the snapshot tree matches the previous Guard baseline (no file changes), a bookmark commit is still created on refs/guard/snapshot so intent/time stay visible \u2014 not silently skipped.",
38227
38244
  {
38228
38245
  path: z.string().describe("Absolute path to the project directory"),
38229
38246
  strategy: z.enum(["git", "shadow", "both"]).optional().describe('Backup strategy (default: from config, or "git")'),
@@ -38268,6 +38285,55 @@ server.tool(
38268
38285
  };
38269
38286
  }
38270
38287
  );
38288
+ server.tool(
38289
+ "record_guard_event",
38290
+ "Create a Git bookmark on refs/guard/snapshot focused on MCP/agent audit: stores Guard-Event (what happened), optional detail/summary, intent, agent, session. When the tree matches the previous baseline, still creates a commit (same as snapshot_now) so the timeline shows the event with no silent skip. Use after other MCP calls when you need a visible record without relying on file diffs alone.",
38291
+ {
38292
+ path: z.string().describe("Absolute path to the project directory"),
38293
+ event: z.string().describe("Short event label, e.g. restore_project:execute, doctor_fix, list_backups:query"),
38294
+ detail: z.string().optional().describe("Longer text stored in Summary trailer (optional)"),
38295
+ intent: z.string().optional().describe("Human-readable intent; defaults to event if omitted"),
38296
+ agent: z.string().optional().describe("AI model identifier"),
38297
+ session: z.string().optional().describe("Conversation or session ID")
38298
+ },
38299
+ async ({ path: projectPath, event, detail, intent, agent, session }) => {
38300
+ const resolved = path.resolve(projectPath);
38301
+ ensureWatcher(resolved);
38302
+ const { cfg } = loadConfig(resolved);
38303
+ const ev = trailerScalar(event);
38304
+ if (!ev) {
38305
+ const err = { git: { status: "error", error: "event must be a non-empty string" } };
38306
+ injectPreWarning(resolved, injectAlert(resolved, err));
38307
+ injectWatcherWarning(resolved, err);
38308
+ return { content: [{ type: "text", text: JSON.stringify(err, null, 2) }] };
38309
+ }
38310
+ const context = {
38311
+ trigger: "mcp-event",
38312
+ guardEvent: ev,
38313
+ summary: detail ? trailerScalar(detail, 2e3) : `MCP event: ${ev}`
38314
+ };
38315
+ if (intent) context.intent = trailerScalar(intent);
38316
+ if (agent) context.agent = trailerScalar(agent);
38317
+ if (session) context.session = trailerScalar(session);
38318
+ const results = {
38319
+ git: createGitSnapshot(resolved, cfg, {
38320
+ branchRef: "refs/guard/snapshot",
38321
+ message: `guard: MCP event ${(/* @__PURE__ */ new Date()).toISOString()}`,
38322
+ context,
38323
+ allowEmptyTree: true,
38324
+ fullWorkspaceSnapshot: true
38325
+ })
38326
+ };
38327
+ injectPreWarning(resolved, injectAlert(resolved, results));
38328
+ injectWatcherWarning(resolved, results);
38329
+ return {
38330
+ content: [{
38331
+ type: "text",
38332
+ text: JSON.stringify(results, null, 2)
38333
+ }]
38334
+ };
38335
+ }
38336
+ );
38271
38337
  server.tool(
38272
38338
  "restore_file",
38273
38339
  "Restore a single file from a backup source (git commit/ref or shadow copy timestamp). By default, preserves the current version in a pre-restore snapshot before restoring.",
@@ -2,7 +2,7 @@
2
2
  "name": "cursor-guard-ide",
3
3
  "displayName": "Cursor Guard",
4
4
  "description": "AI code protection dashboard embedded in your IDE — real-time alerts, backup history, one-click snapshots",
5
- "version": "4.9.12",
5
+ "version": "4.9.15",
6
6
  "publisher": "zhangqiang8vipp",
7
7
  "license": "BUSL-1.1",
8
8
  "engines": {
@@ -67,6 +67,12 @@
67
67
  "category": "Cursor Guard",
68
68
  "icon": "$(search)"
69
69
  },
70
+ {
71
+ "command": "cursorGuard.setupSkill",
72
+ "title": "Install Agent Skill",
73
+ "category": "Cursor Guard",
74
+ "icon": "$(book)"
75
+ },
70
76
  {
71
77
  "command": "cursorGuard.addToProtect",
72
78
  "title": "Add to Protected",