@mgsoftwarebv/mg-dashboard-mcp 7.4.10 → 7.4.12

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 (2) hide show
  1. package/dist/index.js +557 -151
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -20,7 +20,7 @@ import { sql } from 'drizzle-orm';
20
20
  import { once } from 'events';
21
21
  import { lookup } from 'dns/promises';
22
22
  import { connect } from 'tls';
23
- import { pgTable, timestamp, uuid, jsonb, boolean, text, pgEnum, integer, uniqueIndex, index, check, bigint, doublePrecision, primaryKey, foreignKey, date, real } from 'drizzle-orm/pg-core';
23
+ import { pgTable, timestamp, uuid, jsonb, boolean, text, customType, integer, date, real, index, uniqueIndex, pgEnum, check, bigint, doublePrecision, primaryKey, foreignKey } from 'drizzle-orm/pg-core';
24
24
  import { HeadObjectCommand, ListObjectsV2Command, DeleteObjectsCommand, S3Client, DeleteObjectCommand, CreateMultipartUploadCommand, UploadPartCommand, CompleteMultipartUploadCommand, AbortMultipartUploadCommand, PutObjectCommand, GetObjectCommand, CopyObjectCommand } from '@aws-sdk/client-s3';
25
25
 
26
26
  var __defProp = Object.defineProperty;
@@ -990,9 +990,9 @@ ${raw2.substring(0, 500)}` }] };
990
990
  return { content: [{ type: "text", text: `No environment variables for ${project}/${env}.` }] };
991
991
  }
992
992
  const lines = vars.map((v) => `${v.isSecret ? "[secret]" : " "} ${v.name}`).sort();
993
- const text16 = `Env vars for ${project}/${env} (${vars.length}) \u2014 values hidden, use action="get" with a key:
993
+ const text19 = `Env vars for ${project}/${env} (${vars.length}) \u2014 values hidden, use action="get" with a key:
994
994
  ` + "-".repeat(50) + "\n" + lines.join("\n");
995
- return { content: [{ type: "text", text: text16 }] };
995
+ return { content: [{ type: "text", text: text19 }] };
996
996
  }
997
997
  if (action === "get") {
998
998
  const key2 = String(args2.key ?? "");
@@ -1079,9 +1079,9 @@ async function fetchAndFormatRun(conn, proxy, sshExec2, instance, runId) {
1079
1079
  return { content: [{ type: "text", text: `Invalid API response:
1080
1080
  ${rawJson.substring(0, 500)}` }] };
1081
1081
  }
1082
- let text16 = formatRunDetail(run);
1083
- if (logs) text16 += "\n\n--- Logs ---\n" + logs;
1084
- return { content: [{ type: "text", text: text16 }] };
1082
+ let text19 = formatRunDetail(run);
1083
+ if (logs) text19 += "\n\n--- Logs ---\n" + logs;
1084
+ return { content: [{ type: "text", text: text19 }] };
1085
1085
  }
1086
1086
  async function waitForCompletion(conn, proxy, sshExec2, instance, runId, waitSeconds) {
1087
1087
  const pollInterval = 3e3;
@@ -1103,10 +1103,10 @@ async function waitForCompletion(conn, proxy, sshExec2, instance, runId, waitSec
1103
1103
  continue;
1104
1104
  }
1105
1105
  if (TERMINAL_STATUSES.has(run.status)) {
1106
- let text16 = formatRunDetail(run);
1106
+ let text19 = formatRunDetail(run);
1107
1107
  const logs = await fetchRunLogs(runId, conn, proxy, sshExec2);
1108
- if (logs) text16 += "\n\n--- Logs ---\n" + logs;
1109
- return { content: [{ type: "text", text: text16 }] };
1108
+ if (logs) text19 += "\n\n--- Logs ---\n" + logs;
1109
+ return { content: [{ type: "text", text: text19 }] };
1110
1110
  }
1111
1111
  }
1112
1112
  return {
@@ -3793,10 +3793,10 @@ var ZodObject = class _ZodObject extends ZodType {
3793
3793
  // }) as any;
3794
3794
  // return merged;
3795
3795
  // }
3796
- catchall(index13) {
3796
+ catchall(index16) {
3797
3797
  return new _ZodObject({
3798
3798
  ...this._def,
3799
- catchall: index13
3799
+ catchall: index16
3800
3800
  });
3801
3801
  }
3802
3802
  pick(mask) {
@@ -4114,9 +4114,9 @@ function mergeValues(a, b) {
4114
4114
  return { valid: false };
4115
4115
  }
4116
4116
  const newArray = [];
4117
- for (let index13 = 0; index13 < a.length; index13++) {
4118
- const itemA = a[index13];
4119
- const itemB = b[index13];
4117
+ for (let index16 = 0; index16 < a.length; index16++) {
4118
+ const itemA = a[index16];
4119
+ const itemB = b[index16];
4120
4120
  const sharedValue = mergeValues(itemA, itemB);
4121
4121
  if (!sharedValue.valid) {
4122
4122
  return { valid: false };
@@ -4322,10 +4322,10 @@ var ZodMap = class extends ZodType {
4322
4322
  }
4323
4323
  const keyType = this._def.keyType;
4324
4324
  const valueType = this._def.valueType;
4325
- const pairs = [...ctx.data.entries()].map(([key, value], index13) => {
4325
+ const pairs = [...ctx.data.entries()].map(([key, value], index16) => {
4326
4326
  return {
4327
- key: keyType._parse(new ParseInputLazyPath(ctx, key, ctx.path, [index13, "key"])),
4328
- value: valueType._parse(new ParseInputLazyPath(ctx, value, ctx.path, [index13, "value"]))
4327
+ key: keyType._parse(new ParseInputLazyPath(ctx, key, ctx.path, [index16, "key"])),
4328
+ value: valueType._parse(new ParseInputLazyPath(ctx, value, ctx.path, [index16, "value"]))
4329
4329
  };
4330
4330
  });
4331
4331
  if (ctx.common.async) {
@@ -5295,6 +5295,232 @@ pgTable("two_factor", {
5295
5295
  secret: text("secret").notNull(),
5296
5296
  backupCodes: text("backup_codes")
5297
5297
  });
5298
+ var WIKI_EMBEDDING_DIMENSIONS = 1536;
5299
+ var vector = customType({
5300
+ dataType(config) {
5301
+ return `vector(${config?.dimensions ?? WIKI_EMBEDDING_DIMENSIONS})`;
5302
+ },
5303
+ toDriver(value) {
5304
+ return `[${value.join(",")}]`;
5305
+ },
5306
+ fromDriver(value) {
5307
+ if (Array.isArray(value)) return value.map(Number);
5308
+ if (typeof value !== "string") return [];
5309
+ const trimmed = value.replace(/^\[/, "").replace(/\]$/, "");
5310
+ if (!trimmed) return [];
5311
+ return trimmed.split(",").map((part) => Number(part.trim()));
5312
+ }
5313
+ });
5314
+ pgTable(
5315
+ "wiki_page",
5316
+ {
5317
+ id: uuid("id").primaryKey().defaultRandom(),
5318
+ slug: text("slug").notNull().unique(),
5319
+ title: text("title").notNull().default(""),
5320
+ summary: text("summary"),
5321
+ content: text("content").notNull().default(""),
5322
+ frontmatter: jsonb("frontmatter").$type(),
5323
+ sources: jsonb("sources").$type(),
5324
+ sourcesArchive: jsonb("sources_archive").$type(),
5325
+ tags: text("tags").array().notNull().default([]),
5326
+ status: text("status").notNull().default("draft"),
5327
+ pageUpdatedOn: date("page_updated_on"),
5328
+ contentHash: text("content_hash"),
5329
+ /** Legacy app-layer cosine storage; dual-written with embeddingVec. */
5330
+ embedding: real("embedding").array(),
5331
+ embeddingVec: vector("embedding_vec", {
5332
+ dimensions: WIKI_EMBEDDING_DIMENSIONS
5333
+ }),
5334
+ embeddingModel: text("embedding_model"),
5335
+ embeddedAt: timestamp("embedded_at", { withTimezone: true }),
5336
+ reviewedBy: text("reviewed_by"),
5337
+ reviewedOn: date("reviewed_on"),
5338
+ lastVerifiedOn: date("last_verified_on"),
5339
+ verifyCount: integer("verify_count").notNull().default(0),
5340
+ verifyNote: text("verify_note"),
5341
+ dirty: boolean("dirty").notNull().default(false),
5342
+ vaultSyncedAt: timestamp("vault_synced_at", { withTimezone: true }),
5343
+ createdAt: timestamp("created_at", { withTimezone: true }).notNull().defaultNow(),
5344
+ updatedAt: timestamp("updated_at", { withTimezone: true }).notNull().defaultNow()
5345
+ },
5346
+ (table) => [
5347
+ index("idx_wiki_page_status").on(table.status),
5348
+ index("idx_wiki_page_last_verified").on(table.lastVerifiedOn),
5349
+ index("idx_wiki_page_dirty").on(table.dirty)
5350
+ ]
5351
+ );
5352
+ pgTable(
5353
+ "wiki_change_log",
5354
+ {
5355
+ id: uuid("id").primaryKey().defaultRandom(),
5356
+ authorJob: text("author_job").notNull(),
5357
+ summary: text("summary").notNull().default(""),
5358
+ slugs: text("slugs").array().notNull().default([]),
5359
+ syncedAt: timestamp("synced_at", { withTimezone: true }),
5360
+ createdAt: timestamp("created_at", { withTimezone: true }).notNull().defaultNow()
5361
+ },
5362
+ (table) => [index("idx_wiki_change_log_created").on(table.createdAt)]
5363
+ );
5364
+ pgTable(
5365
+ "wiki_page_flag",
5366
+ {
5367
+ id: uuid("id").primaryKey().defaultRandom(),
5368
+ pageSlug: text("page_slug").notNull(),
5369
+ kind: text("kind").notNull(),
5370
+ detail: text("detail").notNull().default(""),
5371
+ sourceRef: text("source_ref"),
5372
+ createdBy: text("created_by"),
5373
+ createdAt: timestamp("created_at", { withTimezone: true }).notNull().defaultNow(),
5374
+ resolvedAt: timestamp("resolved_at", { withTimezone: true }),
5375
+ resolvedBy: text("resolved_by")
5376
+ },
5377
+ (table) => [index("idx_wiki_page_flag_created").on(table.createdAt)]
5378
+ );
5379
+ pgTable(
5380
+ "wiki_page_evidence",
5381
+ {
5382
+ id: uuid("id").primaryKey().defaultRandom(),
5383
+ pageSlug: text("page_slug").notNull(),
5384
+ evidenceType: text("evidence_type").notNull(),
5385
+ evidenceRef: text("evidence_ref").notNull(),
5386
+ matchScore: real("match_score"),
5387
+ matchReason: text("match_reason"),
5388
+ snippet: text("snippet"),
5389
+ status: text("status").notNull().default("pending"),
5390
+ createdAt: timestamp("created_at", { withTimezone: true }).notNull().defaultNow(),
5391
+ resolvedAt: timestamp("resolved_at", { withTimezone: true })
5392
+ },
5393
+ (table) => [
5394
+ uniqueIndex("wiki_page_evidence_page_slug_evidence_type_evidence_ref_key").on(
5395
+ table.pageSlug,
5396
+ table.evidenceType,
5397
+ table.evidenceRef
5398
+ ),
5399
+ index("idx_wiki_page_evidence_created").on(table.createdAt)
5400
+ ]
5401
+ );
5402
+ pgTable(
5403
+ "wiki_page_link",
5404
+ {
5405
+ id: uuid("id").primaryKey().defaultRandom(),
5406
+ sourceSlug: text("source_slug").notNull(),
5407
+ targetSlug: text("target_slug").notNull(),
5408
+ kind: text("kind").notNull().default("wikilink"),
5409
+ createdAt: timestamp("created_at", { withTimezone: true }).notNull().defaultNow()
5410
+ },
5411
+ (table) => [
5412
+ uniqueIndex("wiki_page_link_source_target_kind_key").on(
5413
+ table.sourceSlug,
5414
+ table.targetSlug,
5415
+ table.kind
5416
+ ),
5417
+ index("idx_wiki_page_link_source").on(table.sourceSlug),
5418
+ index("idx_wiki_page_link_target").on(table.targetSlug)
5419
+ ]
5420
+ );
5421
+ pgTable(
5422
+ "wiki_page_read",
5423
+ {
5424
+ id: uuid("id").primaryKey().defaultRandom(),
5425
+ slug: text("slug").notNull(),
5426
+ caller: text("caller"),
5427
+ includedArchive: boolean("included_archive").notNull().default(false),
5428
+ createdAt: timestamp("created_at", { withTimezone: true }).notNull().defaultNow()
5429
+ },
5430
+ (table) => [
5431
+ index("idx_wiki_page_read_slug").on(table.slug, table.createdAt),
5432
+ index("idx_wiki_page_read_created").on(table.createdAt)
5433
+ ]
5434
+ );
5435
+ pgTable(
5436
+ "wiki_verify_event",
5437
+ {
5438
+ id: uuid("id").primaryKey().defaultRandom(),
5439
+ pageSlug: text("page_slug").notNull(),
5440
+ outcome: text("outcome").notNull(),
5441
+ runMode: text("run_mode"),
5442
+ note: text("note"),
5443
+ createdAt: timestamp("created_at", { withTimezone: true }).notNull().defaultNow()
5444
+ },
5445
+ (table) => [
5446
+ index("idx_wiki_verify_event_created").on(table.createdAt),
5447
+ index("idx_wiki_verify_event_outcome_created").on(
5448
+ table.outcome,
5449
+ table.createdAt
5450
+ )
5451
+ ]
5452
+ );
5453
+ pgTable(
5454
+ "wiki_search_log",
5455
+ {
5456
+ id: uuid("id").primaryKey().defaultRandom(),
5457
+ query: text("query").notNull(),
5458
+ hitCount: integer("hit_count").notNull().default(0),
5459
+ topScore: real("top_score"),
5460
+ topSlug: text("top_slug"),
5461
+ caller: text("caller"),
5462
+ createdAt: timestamp("created_at", { withTimezone: true }).notNull().defaultNow()
5463
+ },
5464
+ (table) => [index("idx_wiki_search_log_created").on(table.createdAt)]
5465
+ );
5466
+ pgTable(
5467
+ "team_memory_search_log",
5468
+ {
5469
+ id: uuid("id").primaryKey().defaultRandom(),
5470
+ query: text("query").notNull(),
5471
+ hitCount: integer("hit_count").notNull().default(0),
5472
+ topScore: real("top_score"),
5473
+ topId: text("top_id"),
5474
+ caller: text("caller"),
5475
+ repo: text("repo"),
5476
+ createdAt: timestamp("created_at", { withTimezone: true }).notNull().defaultNow()
5477
+ },
5478
+ (table) => [index("idx_team_memory_search_log_created").on(table.createdAt)]
5479
+ );
5480
+
5481
+ // ../db/src/schema/agent-memory.ts
5482
+ pgTable(
5483
+ "agent_memory",
5484
+ {
5485
+ id: uuid("id").primaryKey().defaultRandom(),
5486
+ conversationId: uuid("conversation_id"),
5487
+ localConversationId: text("local_conversation_id"),
5488
+ source: text("source").notNull().default("mirror"),
5489
+ userId: text("user_id"),
5490
+ hostId: uuid("host_id"),
5491
+ workspaceId: uuid("workspace_id"),
5492
+ gitRepository: text("git_repository"),
5493
+ title: text("title").notNull().default(""),
5494
+ summary: text("summary"),
5495
+ content: text("content").notNull().default(""),
5496
+ contentHash: text("content_hash"),
5497
+ embedding: real("embedding").array(),
5498
+ embeddingVec: vector("embedding_vec", {
5499
+ dimensions: WIKI_EMBEDDING_DIMENSIONS
5500
+ }),
5501
+ embeddingModel: text("embedding_model"),
5502
+ messageCount: integer("message_count").notNull().default(0),
5503
+ startedAt: timestamp("started_at", { withTimezone: true }),
5504
+ lastMessageAt: timestamp("last_message_at", { withTimezone: true }),
5505
+ embeddedAt: timestamp("embedded_at", { withTimezone: true }),
5506
+ resolved: boolean("resolved"),
5507
+ category: text("category"),
5508
+ tech: text("tech").array(),
5509
+ kind: text("kind").notNull().default("human"),
5510
+ symbols: text("symbols").array(),
5511
+ createdAt: timestamp("created_at", { withTimezone: true }).notNull().defaultNow(),
5512
+ updatedAt: timestamp("updated_at", { withTimezone: true }).notNull().defaultNow()
5513
+ },
5514
+ (table) => [
5515
+ uniqueIndex("uq_agent_memory_local_conversation").on(
5516
+ table.localConversationId
5517
+ ),
5518
+ index("idx_agent_memory_repo").on(table.gitRepository),
5519
+ index("idx_agent_memory_user").on(table.userId),
5520
+ index("idx_agent_memory_kind").on(table.kind),
5521
+ index("idx_agent_memory_category").on(table.category)
5522
+ ]
5523
+ );
5298
5524
  var contentSourceType = pgEnum("content_source_type", [
5299
5525
  "own_site",
5300
5526
  "client_site",
@@ -6012,6 +6238,47 @@ pgTable(
6012
6238
  index("alert_rule_enabled_severity_idx").on(table.enabled, table.severity)
6013
6239
  ]
6014
6240
  );
6241
+ var cursorSkill = pgTable(
6242
+ "cursor_skill",
6243
+ {
6244
+ id: uuid("id").primaryKey().defaultRandom(),
6245
+ slug: text("slug").notNull(),
6246
+ title: text("title").notNull().default(""),
6247
+ currentVersion: integer("current_version").notNull().default(0),
6248
+ createdAt: timestamp("created_at", { withTimezone: true }).notNull().defaultNow(),
6249
+ updatedAt: timestamp("updated_at", { withTimezone: true }).notNull().defaultNow()
6250
+ },
6251
+ (table) => [
6252
+ uniqueIndex("uq_cursor_skill_slug").on(table.slug)
6253
+ ]
6254
+ );
6255
+ pgTable(
6256
+ "cursor_skill_revision",
6257
+ {
6258
+ id: uuid("id").primaryKey().defaultRandom(),
6259
+ skillId: uuid("skill_id").notNull().references(() => cursorSkill.id, { onDelete: "cascade" }),
6260
+ version: integer("version").notNull(),
6261
+ parentVersion: integer("parent_version"),
6262
+ message: text("message").notNull().default(""),
6263
+ files: jsonb("files").notNull().$type(),
6264
+ fileHashes: jsonb("file_hashes").notNull().$type().default({}),
6265
+ sourceRepo: text("source_repo"),
6266
+ sourcePath: text("source_path"),
6267
+ authorUserId: text("author_user_id"),
6268
+ authorLabel: text("author_label"),
6269
+ status: text("status").notNull().default("accepted"),
6270
+ published: boolean("published").notNull().default(true),
6271
+ createdAt: timestamp("created_at", { withTimezone: true }).notNull().defaultNow()
6272
+ },
6273
+ (table) => [
6274
+ uniqueIndex("uq_cursor_skill_revision_skill_version").on(
6275
+ table.skillId,
6276
+ table.version
6277
+ ),
6278
+ index("idx_cursor_skill_revision_skill").on(table.skillId),
6279
+ index("idx_cursor_skill_revision_created").on(table.createdAt)
6280
+ ]
6281
+ );
6015
6282
  pgTable(
6016
6283
  "deployment_project_server",
6017
6284
  {
@@ -6388,6 +6655,49 @@ pgTable(
6388
6655
  index("github_webhook_secret_owner_idx").on(table.owner)
6389
6656
  ]
6390
6657
  );
6658
+ pgTable(
6659
+ "handoff_loop_run",
6660
+ {
6661
+ id: uuid("id").primaryKey().defaultRandom(),
6662
+ runSlug: text("run_slug").notNull(),
6663
+ userId: text("user_id"),
6664
+ gitRepository: text("git_repository"),
6665
+ machine: text("machine"),
6666
+ planSummary: text("plan_summary").notNull().default(""),
6667
+ workerModel: text("worker_model").notNull().default(""),
6668
+ outcome: text("outcome").notNull().default("completed"),
6669
+ executeRounds: integer("execute_rounds").notNull().default(0),
6670
+ planRoundTrips: integer("plan_round_trips").notNull().default(0),
6671
+ questionsSelfAnswered: integer("questions_self_answered").notNull().default(0),
6672
+ questionsEscalated: integer("questions_escalated").notNull().default(0),
6673
+ protocolViolations: integer("protocol_violations").notNull().default(0),
6674
+ reviewIssuesFound: integer("review_issues_found").notNull().default(0),
6675
+ checklistInitial: integer("checklist_initial").notNull().default(0),
6676
+ checklistProposed: integer("checklist_proposed").notNull().default(0),
6677
+ checklistAccepted: integer("checklist_accepted").notNull().default(0),
6678
+ checklistVerified: integer("checklist_verified").notNull().default(0),
6679
+ inputTokens: bigint("input_tokens", { mode: "number" }).notNull().default(0),
6680
+ outputTokens: bigint("output_tokens", { mode: "number" }).notNull().default(0),
6681
+ cacheReadTokens: bigint("cache_read_tokens", { mode: "number" }).notNull().default(0),
6682
+ totalDurationMs: bigint("total_duration_ms", { mode: "number" }).notNull().default(0),
6683
+ retro: text("retro"),
6684
+ metrics: jsonb("metrics"),
6685
+ reviewed: boolean("reviewed").notNull().default(false),
6686
+ reviewNotes: text("review_notes"),
6687
+ reviewedAt: timestamp("reviewed_at", { withTimezone: true }),
6688
+ startedAt: timestamp("started_at", { withTimezone: true }),
6689
+ completedAt: timestamp("completed_at", { withTimezone: true }),
6690
+ createdAt: timestamp("created_at", { withTimezone: true }).notNull().defaultNow(),
6691
+ updatedAt: timestamp("updated_at", { withTimezone: true }).notNull().defaultNow()
6692
+ },
6693
+ (table) => [
6694
+ uniqueIndex("uq_handoff_loop_run_slug").on(table.runSlug),
6695
+ index("idx_handoff_loop_run_user").on(table.userId),
6696
+ index("idx_handoff_loop_run_outcome").on(table.outcome),
6697
+ index("idx_handoff_loop_run_reviewed").on(table.reviewed),
6698
+ index("idx_handoff_loop_run_created").on(table.createdAt)
6699
+ ]
6700
+ );
6391
6701
  var managedSiteSyncMode = pgEnum("managed_site_sync_mode", [
6392
6702
  "sitemap",
6393
6703
  "git",
@@ -6493,6 +6803,8 @@ var refrontCustomer = pgTable(
6493
6803
  status: text("status"),
6494
6804
  teamId: text("team_id"),
6495
6805
  teamName: text("team_name"),
6806
+ /** Alternative names from Refront (trading names / brands). */
6807
+ aliases: text("aliases").array().notNull().default([]),
6496
6808
  syncedAt: timestamp("synced_at", { withTimezone: true }).notNull(),
6497
6809
  createdAt: timestamp("created_at", { withTimezone: true }).notNull().defaultNow(),
6498
6810
  updatedAt: timestamp("updated_at", { withTimezone: true }).notNull().defaultNow()
@@ -6644,114 +6956,6 @@ pgTable(
6644
6956
  }).onDelete("cascade")
6645
6957
  ]
6646
6958
  );
6647
- pgTable(
6648
- "wiki_page",
6649
- {
6650
- id: uuid("id").primaryKey().defaultRandom(),
6651
- slug: text("slug").notNull().unique(),
6652
- title: text("title").notNull().default(""),
6653
- summary: text("summary"),
6654
- content: text("content").notNull().default(""),
6655
- status: text("status").notNull().default("draft"),
6656
- pageUpdatedOn: date("page_updated_on"),
6657
- reviewedBy: text("reviewed_by"),
6658
- reviewedOn: date("reviewed_on"),
6659
- lastVerifiedOn: date("last_verified_on"),
6660
- verifyCount: integer("verify_count").notNull().default(0),
6661
- verifyNote: text("verify_note"),
6662
- dirty: boolean("dirty").notNull().default(false),
6663
- vaultSyncedAt: timestamp("vault_synced_at", { withTimezone: true }),
6664
- createdAt: timestamp("created_at", { withTimezone: true }).notNull().defaultNow(),
6665
- updatedAt: timestamp("updated_at", { withTimezone: true }).notNull().defaultNow()
6666
- },
6667
- (table) => [
6668
- index("idx_wiki_page_status").on(table.status),
6669
- index("idx_wiki_page_last_verified").on(table.lastVerifiedOn),
6670
- index("idx_wiki_page_dirty").on(table.dirty)
6671
- ]
6672
- );
6673
- pgTable(
6674
- "wiki_change_log",
6675
- {
6676
- id: uuid("id").primaryKey().defaultRandom(),
6677
- authorJob: text("author_job").notNull(),
6678
- summary: text("summary").notNull().default(""),
6679
- slugs: text("slugs").array().notNull().default([]),
6680
- syncedAt: timestamp("synced_at", { withTimezone: true }),
6681
- createdAt: timestamp("created_at", { withTimezone: true }).notNull().defaultNow()
6682
- },
6683
- (table) => [index("idx_wiki_change_log_created").on(table.createdAt)]
6684
- );
6685
- pgTable(
6686
- "wiki_page_flag",
6687
- {
6688
- id: uuid("id").primaryKey().defaultRandom(),
6689
- pageSlug: text("page_slug").notNull(),
6690
- kind: text("kind").notNull(),
6691
- detail: text("detail").notNull().default(""),
6692
- sourceRef: text("source_ref"),
6693
- createdBy: text("created_by"),
6694
- createdAt: timestamp("created_at", { withTimezone: true }).notNull().defaultNow(),
6695
- resolvedAt: timestamp("resolved_at", { withTimezone: true }),
6696
- resolvedBy: text("resolved_by")
6697
- },
6698
- (table) => [index("idx_wiki_page_flag_created").on(table.createdAt)]
6699
- );
6700
- pgTable(
6701
- "wiki_page_evidence",
6702
- {
6703
- id: uuid("id").primaryKey().defaultRandom(),
6704
- pageSlug: text("page_slug").notNull(),
6705
- evidenceType: text("evidence_type").notNull(),
6706
- evidenceRef: text("evidence_ref").notNull(),
6707
- matchScore: real("match_score"),
6708
- matchReason: text("match_reason"),
6709
- snippet: text("snippet"),
6710
- status: text("status").notNull().default("pending"),
6711
- createdAt: timestamp("created_at", { withTimezone: true }).notNull().defaultNow(),
6712
- resolvedAt: timestamp("resolved_at", { withTimezone: true })
6713
- },
6714
- (table) => [
6715
- uniqueIndex("wiki_page_evidence_page_slug_evidence_type_evidence_ref_key").on(
6716
- table.pageSlug,
6717
- table.evidenceType,
6718
- table.evidenceRef
6719
- ),
6720
- index("idx_wiki_page_evidence_created").on(table.createdAt)
6721
- ]
6722
- );
6723
- pgTable(
6724
- "wiki_page_read",
6725
- {
6726
- id: uuid("id").primaryKey().defaultRandom(),
6727
- slug: text("slug").notNull(),
6728
- caller: text("caller"),
6729
- includedArchive: boolean("included_archive").notNull().default(false),
6730
- createdAt: timestamp("created_at", { withTimezone: true }).notNull().defaultNow()
6731
- },
6732
- (table) => [
6733
- index("idx_wiki_page_read_slug").on(table.slug, table.createdAt),
6734
- index("idx_wiki_page_read_created").on(table.createdAt)
6735
- ]
6736
- );
6737
- pgTable(
6738
- "wiki_verify_event",
6739
- {
6740
- id: uuid("id").primaryKey().defaultRandom(),
6741
- pageSlug: text("page_slug").notNull(),
6742
- outcome: text("outcome").notNull(),
6743
- runMode: text("run_mode"),
6744
- note: text("note"),
6745
- createdAt: timestamp("created_at", { withTimezone: true }).notNull().defaultNow()
6746
- },
6747
- (table) => [
6748
- index("idx_wiki_verify_event_created").on(table.createdAt),
6749
- index("idx_wiki_verify_event_outcome_created").on(
6750
- table.outcome,
6751
- table.createdAt
6752
- )
6753
- ]
6754
- );
6755
6959
  var wikiActor = pgTable(
6756
6960
  "wiki_actor",
6757
6961
  {
@@ -8074,6 +8278,7 @@ var TOOL_MODULE_MAP = {
8074
8278
  "dns-record": "domains",
8075
8279
  "cursor-remote-list": "cursor_remote",
8076
8280
  "cursor-remote-run": "cursor_remote",
8281
+ // cursor-skill intentionally unmapped — any valid API key may pull shared skills
8077
8282
  ...TRIGGER_TOOL_MODULE_MAP
8078
8283
  };
8079
8284
  var SUPERADMIN_ONLY_TOOLS = /* @__PURE__ */ new Set(["trigger-env"]);
@@ -8635,7 +8840,7 @@ function getEncryptionKey() {
8635
8840
  throw new Error("ENCRYPTION_KEY must be a 64-character hex string");
8636
8841
  return buf;
8637
8842
  }
8638
- function encrypt(text16) {
8843
+ function encrypt(text19) {
8639
8844
  const key = getEncryptionKey();
8640
8845
  const iv = randomBytes(ENC_IV_LENGTH);
8641
8846
  const cipher = createCipheriv(
@@ -8643,7 +8848,7 @@ function encrypt(text16) {
8643
8848
  new Uint8Array(key),
8644
8849
  new Uint8Array(iv)
8645
8850
  );
8646
- let encrypted = cipher.update(text16, "utf8", "hex");
8851
+ let encrypted = cipher.update(text19, "utf8", "hex");
8647
8852
  encrypted += cipher.final("hex");
8648
8853
  const authTag = cipher.getAuthTag();
8649
8854
  return Buffer.concat([
@@ -9363,10 +9568,10 @@ async function r2GetObjectRange(bucket, key, range) {
9363
9568
  const body = result.Body;
9364
9569
  if (!body?.transformToString)
9365
9570
  throw new Error("R2 returned no readable body");
9366
- const text16 = await body.transformToString();
9571
+ const text19 = await body.transformToString();
9367
9572
  const header = `# range: bytes ${range.offset}-${end} of ${size} (${effectiveLen} bytes)`;
9368
9573
  return `${header}
9369
- ${text16}`;
9574
+ ${text19}`;
9370
9575
  } catch (e) {
9371
9576
  throw r2WrapError(bucket, key, e);
9372
9577
  }
@@ -9729,15 +9934,15 @@ async function sftpRead(opts, filePath, proxy, options) {
9729
9934
  clearTimeout(timer);
9730
9935
  cleanup?.();
9731
9936
  cleanup = void 0;
9732
- const text16 = Buffer.concat(
9937
+ const text19 = Buffer.concat(
9733
9938
  chunks.map((ch) => new Uint8Array(ch))
9734
9939
  ).toString("utf-8");
9735
9940
  if (!isWholeFileRequest) {
9736
9941
  const header = `# range: bytes ${offset}-${offset + effectiveLen - 1} of ${total} (${effectiveLen} bytes)`;
9737
9942
  resolve(`${header}
9738
- ${text16}`);
9943
+ ${text19}`);
9739
9944
  } else {
9740
- resolve(text16);
9945
+ resolve(text19);
9741
9946
  }
9742
9947
  });
9743
9948
  rs.on("error", (e) => {
@@ -9884,11 +10089,11 @@ function getKnownContainers(serverId, maxAgeMs = 5 * 6e4) {
9884
10089
  if (Date.now() - e.capturedAt > maxAgeMs) return void 0;
9885
10090
  return e.names;
9886
10091
  }
9887
- function truncateForLLM(text16, maxBytes) {
9888
- const totalBytes = Buffer.byteLength(text16, "utf8");
10092
+ function truncateForLLM(text19, maxBytes) {
10093
+ const totalBytes = Buffer.byteLength(text19, "utf8");
9889
10094
  if (totalBytes <= maxBytes)
9890
- return { text: text16, truncated: false, totalBytes, shownBytes: totalBytes };
9891
- const buf = Buffer.from(text16, "utf8");
10095
+ return { text: text19, truncated: false, totalBytes, shownBytes: totalBytes };
10096
+ const buf = Buffer.from(text19, "utf8");
9892
10097
  let cut = maxBytes;
9893
10098
  while (cut > 0 && (buf[cut] & 192) === 128) cut--;
9894
10099
  const head = buf.subarray(0, cut).toString("utf8");
@@ -9919,10 +10124,10 @@ function postprocessResult(result, meta) {
9919
10124
  if (!result.content?.length) return result;
9920
10125
  if (RAW_JSON_TOOLS.has(meta.toolName)) return result;
9921
10126
  const block = result.content[0];
9922
- let text16 = String(block.text ?? "");
9923
- const trunc = truncateForLLM(text16, RESPONSE_MAX_BYTES);
10127
+ let text19 = String(block.text ?? "");
10128
+ const trunc = truncateForLLM(text19, RESPONSE_MAX_BYTES);
9924
10129
  if (trunc.truncated) {
9925
- text16 = trunc.text + "\n\n... " + buildTruncationHint(
10130
+ text19 = trunc.text + "\n\n... " + buildTruncationHint(
9926
10131
  meta.toolName,
9927
10132
  meta.args,
9928
10133
  trunc.totalBytes,
@@ -9936,11 +10141,11 @@ function postprocessResult(result, meta) {
9936
10141
  const parts = [`took ${tookStr}`, sizeStr];
9937
10142
  if (meta.serverIdLabel) parts.push(`server: ${meta.serverIdLabel}`);
9938
10143
  if (meta.cached) parts.push("cached");
9939
- text16 = `${text16}
10144
+ text19 = `${text19}
9940
10145
 
9941
10146
  [${parts.join(", ")}]`;
9942
10147
  }
9943
- return { ...result, content: [{ ...block, text: text16 }] };
10148
+ return { ...result, content: [{ ...block, text: text19 }] };
9944
10149
  }
9945
10150
  function buildPipelineScript(commands, shell, marker, stopOnError) {
9946
10151
  if (shell === "powershell") {
@@ -12400,7 +12605,7 @@ var TOOLS = [
12400
12605
  },
12401
12606
  {
12402
12607
  name: "search-team-memory",
12403
- description: "Search the team's ENTIRE past Cursor history (every developer, every project) for how something was handled before. Use this FIRST, before investigating from scratch, whenever you: hit a non-trivial bug or error, are about to build something that may have been done before, need a project-specific convention/gotcha, or the user asks 'have we done X', 'how did we fix Y', or 'did we solve this already'. Hybrid semantic + keyword search over mirrored conversations. Returns ranked past chats with repo, date, a solution snippet and a similarity score. Phrase the query as the problem in natural language (e.g. 'release pipeline PM2 deploy fails with module not found').",
12608
+ description: "Search the team's ENTIRE past Cursor history (every developer, every project) for how something was handled before. Prefer search-wiki FIRST for curated answers; fall back here when the wiki has nothing, returns no confident hit, or a page looks stale. Use before investigating from scratch whenever you: hit a non-trivial bug or error, are about to build something that may have been done before, need a project-specific convention/gotcha, or the user asks 'have we done X', 'how did we fix Y', or 'did we solve this already'. Hybrid semantic + keyword search over mirrored conversations. Returns ranked past chats with repo, date, a solution snippet and a similarity score. Phrase the query as the problem in natural language (e.g. 'release pipeline PM2 deploy fails with module not found').",
12404
12609
  inputSchema: {
12405
12610
  type: "object",
12406
12611
  properties: {
@@ -12595,10 +12800,38 @@ var TOOLS = [
12595
12800
  required: ["project", "prompt"]
12596
12801
  }
12597
12802
  },
12803
+ // ----- Shared Cursor skills (pull only; publish from mg-dashboard pack script) -----
12804
+ {
12805
+ name: "cursor-skill",
12806
+ description: "Shared Cursor skill registry (pull only \u2014 publish from mg-dashboard via pack-and-publish). Actions: list (all slugs+versions), status (compare localVersion to tip), pull (return file map; agent MUST write files under .cursor/skills/<slug>/). No push from other repos.",
12807
+ inputSchema: {
12808
+ type: "object",
12809
+ properties: {
12810
+ action: {
12811
+ type: "string",
12812
+ enum: ["list", "status", "pull"],
12813
+ description: "list = registry overview; status = local vs remote; pull = download tip (or version) as files"
12814
+ },
12815
+ slug: {
12816
+ type: "string",
12817
+ description: "Required for status/pull. e.g. plan-handoff-loop"
12818
+ },
12819
+ localVersion: {
12820
+ type: "number",
12821
+ description: "For status: version from .cursor/skills/<slug>/.mg-skill.json (0 if missing)"
12822
+ },
12823
+ version: {
12824
+ type: "number",
12825
+ description: "For pull: optional specific revision (default tip)"
12826
+ }
12827
+ },
12828
+ required: ["action"]
12829
+ }
12830
+ },
12598
12831
  // ----- Trigger.dev -----
12599
12832
  ...TRIGGER_TOOLS
12600
12833
  ];
12601
- var MCP_VERSION = "7.3.0";
12834
+ var MCP_VERSION = "7.4.12";
12602
12835
  async function handleListTools() {
12603
12836
  if (!authContext) return { tools: TOOLS };
12604
12837
  const allowedTools = authContext.allowedTools;
@@ -12856,7 +13089,7 @@ async function executeToolCall(name, a, _serverId) {
12856
13089
  ]
12857
13090
  };
12858
13091
  }
12859
- const lines = data.hits.map((hit, index13) => {
13092
+ const lines = data.hits.map((hit, index16) => {
12860
13093
  const when = hit.lastMessageAt ? new Date(hit.lastMessageAt).toISOString().slice(0, 10) : "unknown date";
12861
13094
  const repo = hit.repo ?? "unknown repo";
12862
13095
  const sim = hit.similarity !== null ? ` \xB7 ${(hit.similarity * 100).toFixed(0)}% match` : "";
@@ -12866,7 +13099,7 @@ async function executeToolCall(name, a, _serverId) {
12866
13099
  ...Array.isArray(hit.tech) ? hit.tech.slice(0, 4) : []
12867
13100
  ].filter(Boolean);
12868
13101
  const tags = facets.length > 0 ? ` \xB7 ${facets.join(", ")}` : "";
12869
- return `${index13 + 1}. [${repo} \xB7 ${when}${sim}${tags}] ${hit.title}
13102
+ return `${index16 + 1}. [${repo} \xB7 ${when}${sim}${tags}] ${hit.title}
12870
13103
  id: ${hit.id}
12871
13104
  ${(hit.summary ?? hit.snippet).replace(/\s+/g, " ").slice(0, 500)}`;
12872
13105
  });
@@ -13073,12 +13306,12 @@ Searchable via search-team-memory once indexing completes (usually immediate).`
13073
13306
  ]
13074
13307
  };
13075
13308
  }
13076
- const lines = data.hits.map((hit, index13) => {
13309
+ const lines = data.hits.map((hit, index16) => {
13077
13310
  const sim = hit.similarity !== null ? ` \xB7 ${Math.round(hit.similarity * 100)}% match` : "";
13078
13311
  const tags = hit.tags.length ? ` \xB7 ${hit.tags.slice(0, 5).join(", ")}` : "";
13079
13312
  const sources = hit.sources.length ? `
13080
13313
  sources: ${hit.sources.slice(0, 6).map((s) => `${s.type}:${s.ref}`).join(", ")}` : "";
13081
- return `${index13 + 1}. [${hit.status} \xB7 updated ${hit.pageUpdatedOn ?? "unknown"}${sim}${tags}] ${hit.title}
13314
+ return `${index16 + 1}. [${hit.status} \xB7 updated ${hit.pageUpdatedOn ?? "unknown"}${sim}${tags}] ${hit.title}
13082
13315
  slug: ${hit.slug}${sources}
13083
13316
  ${(hit.summary ?? hit.snippet).replace(/\s+/g, " ").slice(0, 400)}`;
13084
13317
  });
@@ -14335,8 +14568,8 @@ ${sample.join("\n")}${files.length > 5 ? `
14335
14568
  };
14336
14569
  const filtered = sortRows(applyFilter(only.rows));
14337
14570
  if (format === "json") {
14338
- const text17 = filtered.map((c) => JSON.stringify(c)).join("\n") || "(no containers)";
14339
- return { content: [{ type: "text", text: text17 }] };
14571
+ const text20 = filtered.map((c) => JSON.stringify(c)).join("\n") || "(no containers)";
14572
+ return { content: [{ type: "text", text: text20 }] };
14340
14573
  }
14341
14574
  if (groupByProject) {
14342
14575
  const groups = /* @__PURE__ */ new Map();
@@ -14363,8 +14596,8 @@ ${sample.join("\n")}${files.length > 5 ? `
14363
14596
  }
14364
14597
  const header = `${"NAMES".padEnd(36)} ${"IMAGE".padEnd(40)} ${"STATUS".padEnd(24)} ${"HEALTH".padEnd(10)} ${"PORTS".padEnd(40)} PROJECT`;
14365
14598
  const body = filtered.map((r) => `${fmtRow(r)} ${r.Project || ""}`);
14366
- const text16 = filtered.length === 0 ? "(no containers match)" : [header, ...body].join("\n");
14367
- return { content: [{ type: "text", text: text16 }] };
14599
+ const text19 = filtered.length === 0 ? "(no containers match)" : [header, ...body].join("\n");
14600
+ return { content: [{ type: "text", text: text19 }] };
14368
14601
  }
14369
14602
  if (format === "json") {
14370
14603
  const lines = [];
@@ -16010,6 +16243,179 @@ ${lines.join("\n")}`
16010
16243
  return { content: [{ type: "text", text: okMessage }] };
16011
16244
  });
16012
16245
  }
16246
+ // ----- Shared Cursor skills (pull) -----
16247
+ case "cursor-skill": {
16248
+ const action = String(a.action || "").trim().toLowerCase();
16249
+ if (!["list", "status", "pull"].includes(action)) {
16250
+ return {
16251
+ content: [
16252
+ {
16253
+ type: "text",
16254
+ text: 'Error: action must be "list" | "status" | "pull"'
16255
+ }
16256
+ ]
16257
+ };
16258
+ }
16259
+ if (action === "list") {
16260
+ const rows = await db.execute(sql`
16261
+ SELECT slug, title, current_version, updated_at
16262
+ FROM cursor_skill
16263
+ ORDER BY slug
16264
+ `);
16265
+ if (!rows.length) {
16266
+ return {
16267
+ content: [
16268
+ {
16269
+ type: "text",
16270
+ text: "No shared skills registered yet. Publish from mg-dashboard with scripts/skills/pack-and-publish.ts"
16271
+ }
16272
+ ]
16273
+ };
16274
+ }
16275
+ const lines = rows.map(
16276
+ (r) => `${r.slug}@${r.current_version} ${r.title || ""} (updated ${r.updated_at})`
16277
+ );
16278
+ return {
16279
+ content: [
16280
+ {
16281
+ type: "text",
16282
+ text: `${lines.join("\n")}
16283
+
16284
+ Pull: cursor-skill action=pull slug=\u2026 (write files to .cursor/skills/<slug>/).`
16285
+ }
16286
+ ]
16287
+ };
16288
+ }
16289
+ const slug = String(a.slug || "").trim().toLowerCase();
16290
+ if (!slug) {
16291
+ return {
16292
+ content: [
16293
+ {
16294
+ type: "text",
16295
+ text: `Error: slug is required for action=${action}`
16296
+ }
16297
+ ]
16298
+ };
16299
+ }
16300
+ if (action === "status") {
16301
+ const localVersion = Number(a.localVersion ?? 0);
16302
+ const rows = await db.execute(sql`
16303
+ SELECT current_version, title
16304
+ FROM cursor_skill
16305
+ WHERE slug = ${slug}
16306
+ LIMIT 1
16307
+ `);
16308
+ const tip = rows[0];
16309
+ if (!tip) {
16310
+ return {
16311
+ content: [
16312
+ {
16313
+ type: "text",
16314
+ text: JSON.stringify(
16315
+ {
16316
+ state: "unknown",
16317
+ slug,
16318
+ localVersion,
16319
+ remoteVersion: null,
16320
+ hint: "Skill not in registry"
16321
+ },
16322
+ null,
16323
+ 2
16324
+ )
16325
+ }
16326
+ ]
16327
+ };
16328
+ }
16329
+ const remoteVersion = Number(tip.current_version);
16330
+ const state = localVersion >= remoteVersion && localVersion > 0 ? "up-to-date" : remoteVersion > localVersion ? "behind" : "up-to-date";
16331
+ return {
16332
+ content: [
16333
+ {
16334
+ type: "text",
16335
+ text: JSON.stringify(
16336
+ {
16337
+ state,
16338
+ slug,
16339
+ title: tip.title,
16340
+ localVersion,
16341
+ remoteVersion,
16342
+ next: state === "behind" ? `cursor-skill action=pull slug=${slug}` : "No pull needed"
16343
+ },
16344
+ null,
16345
+ 2
16346
+ )
16347
+ }
16348
+ ]
16349
+ };
16350
+ }
16351
+ const skills = await db.execute(sql`
16352
+ SELECT id, current_version, title
16353
+ FROM cursor_skill
16354
+ WHERE slug = ${slug}
16355
+ LIMIT 1
16356
+ `);
16357
+ const skill = skills[0];
16358
+ if (!skill) {
16359
+ return {
16360
+ content: [
16361
+ {
16362
+ type: "text",
16363
+ text: `Error: skill "${slug}" not found in registry`
16364
+ }
16365
+ ]
16366
+ };
16367
+ }
16368
+ const wantVersion = typeof a.version === "number" && Number.isFinite(a.version) ? Math.floor(a.version) : Number(skill.current_version);
16369
+ const revisions = await db.execute(sql`
16370
+ SELECT version, message, files, created_at
16371
+ FROM cursor_skill_revision
16372
+ WHERE skill_id = ${skill.id} AND version = ${wantVersion}
16373
+ LIMIT 1
16374
+ `);
16375
+ const rev = revisions[0];
16376
+ if (!rev) {
16377
+ return {
16378
+ content: [
16379
+ {
16380
+ type: "text",
16381
+ text: `Error: revision ${wantVersion} not found for ${slug}`
16382
+ }
16383
+ ]
16384
+ };
16385
+ }
16386
+ const files = typeof rev.files === "object" && rev.files !== null ? { ...rev.files } : JSON.parse(String(rev.files));
16387
+ files[".mg-skill.json"] = JSON.stringify(
16388
+ {
16389
+ id: slug,
16390
+ version: rev.version,
16391
+ pulledAt: (/* @__PURE__ */ new Date()).toISOString(),
16392
+ requires: { dashboardApi: dashboardBaseUrl }
16393
+ },
16394
+ null,
16395
+ 2
16396
+ ) + "\n";
16397
+ const installPath = `.cursor/skills/${slug}`;
16398
+ return {
16399
+ content: [
16400
+ {
16401
+ type: "text",
16402
+ text: JSON.stringify(
16403
+ {
16404
+ slug,
16405
+ title: skill.title,
16406
+ version: rev.version,
16407
+ message: rev.message,
16408
+ installPath,
16409
+ instruction: `Write every entry in files to ${installPath}/<path> (create dirs as needed, overwrite). Then the skill is ready. Do not commit unless the user asks.`,
16410
+ files
16411
+ },
16412
+ null,
16413
+ 2
16414
+ )
16415
+ }
16416
+ ]
16417
+ };
16418
+ }
16013
16419
  default:
16014
16420
  if (TRIGGER_TOOL_NAMES.has(name)) {
16015
16421
  return handleTriggerTool(name, a, { sshExec, getServerConnection });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mgsoftwarebv/mg-dashboard-mcp",
3
- "version": "7.4.10",
3
+ "version": "7.4.12",
4
4
  "description": "MCP Server for MG Dashboard - SSH, SFTP, Docker, domains, DNS, and environment config tools for Cursor",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",