@contextstream/mcp-server 0.3.20 → 0.3.21

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 (3) hide show
  1. package/README.md +79 -334
  2. package/dist/index.js +723 -524
  3. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -4611,7 +4611,9 @@ var CacheTTL = {
4611
4611
  // Search results - cache for 60 seconds
4612
4612
  SEARCH: 60 * 1e3,
4613
4613
  // User preferences - cache for 5 minutes
4614
- USER_PREFS: 5 * 60 * 1e3
4614
+ USER_PREFS: 5 * 60 * 1e3,
4615
+ // Credits/plan - cache briefly to reflect upgrades quickly
4616
+ CREDIT_BALANCE: 60 * 1e3
4615
4617
  };
4616
4618
  var CacheKeys = {
4617
4619
  workspace: (id) => `workspace:${id}`,
@@ -4620,7 +4622,8 @@ var CacheKeys = {
4620
4622
  projectList: (workspaceId) => `projects:${workspaceId}`,
4621
4623
  sessionInit: (workspaceId, projectId) => `session_init:${workspaceId || ""}:${projectId || ""}`,
4622
4624
  memoryEvents: (workspaceId) => `memory:${workspaceId}`,
4623
- search: (query, workspaceId) => `search:${workspaceId || ""}:${query}`
4625
+ search: (query, workspaceId) => `search:${workspaceId || ""}:${query}`,
4626
+ creditBalance: () => "credits:balance"
4624
4627
  };
4625
4628
  var globalCache = new MemoryCache();
4626
4629
 
@@ -4666,6 +4669,25 @@ var ContextStreamClient = class {
4666
4669
  me() {
4667
4670
  return request(this.config, "/auth/me");
4668
4671
  }
4672
+ // Credits / Billing (used for plan gating)
4673
+ async getCreditBalance() {
4674
+ const cacheKey = CacheKeys.creditBalance();
4675
+ const cached = globalCache.get(cacheKey);
4676
+ if (cached) return cached;
4677
+ const result = await request(this.config, "/credits/balance", { method: "GET" });
4678
+ const data = result && typeof result === "object" && "data" in result && result.data ? result.data : result;
4679
+ globalCache.set(cacheKey, data, CacheTTL.CREDIT_BALANCE);
4680
+ return data;
4681
+ }
4682
+ async getPlanName() {
4683
+ try {
4684
+ const balance = await this.getCreditBalance();
4685
+ const planName = balance?.plan?.name;
4686
+ return typeof planName === "string" ? planName.toLowerCase() : null;
4687
+ } catch {
4688
+ return null;
4689
+ }
4690
+ }
4669
4691
  // Workspaces & Projects
4670
4692
  listWorkspaces(params) {
4671
4693
  const query = new URLSearchParams();
@@ -5053,22 +5075,15 @@ var ContextStreamClient = class {
5053
5075
  return context;
5054
5076
  }
5055
5077
  } else {
5056
- const newWorkspace = await this.createWorkspace({
5057
- name: folderName || "My Workspace",
5058
- description: `Workspace created for ${rootPath}`,
5059
- visibility: "private"
5060
- });
5061
- if (newWorkspace.id) {
5062
- workspaceId = newWorkspace.id;
5063
- workspaceName = newWorkspace.name;
5064
- context.workspace_source = "auto_created";
5065
- context.workspace_created = true;
5066
- writeLocalConfig(rootPath, {
5067
- workspace_id: newWorkspace.id,
5068
- workspace_name: newWorkspace.name,
5069
- associated_at: (/* @__PURE__ */ new Date()).toISOString()
5070
- });
5071
- }
5078
+ const folderDisplayName = rootPath?.split("/").pop() || "this folder";
5079
+ context.status = "requires_workspace_name";
5080
+ context.workspace_source = "none_found";
5081
+ context.ide_roots = ideRoots;
5082
+ context.folder_name = folderDisplayName;
5083
+ context.folder_path = rootPath;
5084
+ context.suggested_project_name = folderDisplayName;
5085
+ context.message = `No workspaces found for this account. Ask the user for a name for a new workspace, then create a project for "${folderDisplayName}".`;
5086
+ return context;
5072
5087
  }
5073
5088
  } catch (e) {
5074
5089
  context.workspace_error = String(e);
@@ -6455,6 +6470,39 @@ function toStructured(data) {
6455
6470
  return void 0;
6456
6471
  }
6457
6472
  function registerTools(server, client, sessionManager) {
6473
+ const upgradeUrl2 = process.env.CONTEXTSTREAM_UPGRADE_URL || "https://contextstream.io/pricing";
6474
+ const defaultProTools = /* @__PURE__ */ new Set([
6475
+ // AI endpoints (typically paid/credit-metered)
6476
+ "ai_context",
6477
+ "ai_enhanced_context",
6478
+ "ai_context_budget",
6479
+ "ai_embeddings",
6480
+ "ai_plan",
6481
+ "ai_tasks"
6482
+ ]);
6483
+ const proTools = (() => {
6484
+ const raw = process.env.CONTEXTSTREAM_PRO_TOOLS;
6485
+ if (!raw) return defaultProTools;
6486
+ const parsed = raw.split(",").map((t) => t.trim()).filter(Boolean);
6487
+ return parsed.length > 0 ? new Set(parsed) : defaultProTools;
6488
+ })();
6489
+ function getToolAccessTier(toolName) {
6490
+ return proTools.has(toolName) ? "pro" : "free";
6491
+ }
6492
+ function getToolAccessLabel(toolName) {
6493
+ return getToolAccessTier(toolName) === "pro" ? "PRO" : "Free";
6494
+ }
6495
+ async function gateIfProTool(toolName) {
6496
+ if (getToolAccessTier(toolName) !== "pro") return null;
6497
+ const planName = await client.getPlanName();
6498
+ if (planName !== "free") return null;
6499
+ return errorResult(
6500
+ [
6501
+ `Access denied: \`${toolName}\` requires ContextStream PRO.`,
6502
+ `Upgrade: ${upgradeUrl2}`
6503
+ ].join("\n")
6504
+ );
6505
+ }
6458
6506
  function wrapWithAutoContext(toolName, handler) {
6459
6507
  if (!sessionManager) {
6460
6508
  return handler;
@@ -6483,8 +6531,18 @@ function registerTools(server, client, sessionManager) {
6483
6531
  };
6484
6532
  }
6485
6533
  function registerTool(name, config, handler) {
6534
+ const accessLabel = getToolAccessLabel(name);
6535
+ const labeledConfig = {
6536
+ ...config,
6537
+ title: `${config.title} (${accessLabel})`,
6538
+ description: `${config.description}
6539
+
6540
+ Access: ${accessLabel}${accessLabel === "PRO" ? ` (upgrade: ${upgradeUrl2})` : ""}`
6541
+ };
6486
6542
  const safeHandler = async (input) => {
6487
6543
  try {
6544
+ const gated = await gateIfProTool(name);
6545
+ if (gated) return gated;
6488
6546
  return await handler(input);
6489
6547
  } catch (error) {
6490
6548
  const errorMessage = error?.message || String(error);
@@ -6498,10 +6556,26 @@ function registerTools(server, client, sessionManager) {
6498
6556
  };
6499
6557
  server.registerTool(
6500
6558
  name,
6501
- config,
6559
+ labeledConfig,
6502
6560
  wrapWithAutoContext(name, safeHandler)
6503
6561
  );
6504
6562
  }
6563
+ function errorResult(text) {
6564
+ return {
6565
+ content: [{ type: "text", text }],
6566
+ isError: true
6567
+ };
6568
+ }
6569
+ function resolveWorkspaceId(explicitWorkspaceId) {
6570
+ if (explicitWorkspaceId) return explicitWorkspaceId;
6571
+ const ctx = sessionManager?.getContext();
6572
+ return typeof ctx?.workspace_id === "string" ? ctx.workspace_id : void 0;
6573
+ }
6574
+ function resolveProjectId(explicitProjectId) {
6575
+ if (explicitProjectId) return explicitProjectId;
6576
+ const ctx = sessionManager?.getContext();
6577
+ return typeof ctx?.project_id === "string" ? ctx.project_id : void 0;
6578
+ }
6505
6579
  registerTool(
6506
6580
  "auth_me",
6507
6581
  {
@@ -6638,10 +6712,14 @@ function registerTools(server, client, sessionManager) {
6638
6712
  {
6639
6713
  title: "Index project",
6640
6714
  description: "Trigger indexing for a project",
6641
- inputSchema: external_exports.object({ project_id: external_exports.string().uuid() })
6715
+ inputSchema: external_exports.object({ project_id: external_exports.string().uuid().optional() })
6642
6716
  },
6643
6717
  async (input) => {
6644
- const result = await client.indexProject(input.project_id);
6718
+ const projectId = resolveProjectId(input.project_id);
6719
+ if (!projectId) {
6720
+ return errorResult("Error: project_id is required. Please call session_init first or provide project_id explicitly.");
6721
+ }
6722
+ const result = await client.indexProject(projectId);
6645
6723
  return { content: [{ type: "text", text: formatContent(result) }], structuredContent: toStructured(result) };
6646
6724
  }
6647
6725
  );
@@ -6991,10 +7069,14 @@ function registerTools(server, client, sessionManager) {
6991
7069
  {
6992
7070
  title: "Get project",
6993
7071
  description: "Get project details by ID",
6994
- inputSchema: external_exports.object({ project_id: external_exports.string().uuid() })
7072
+ inputSchema: external_exports.object({ project_id: external_exports.string().uuid().optional() })
6995
7073
  },
6996
7074
  async (input) => {
6997
- const result = await client.getProject(input.project_id);
7075
+ const projectId = resolveProjectId(input.project_id);
7076
+ if (!projectId) {
7077
+ return errorResult("Error: project_id is required. Please call session_init first or provide project_id explicitly.");
7078
+ }
7079
+ const result = await client.getProject(projectId);
6998
7080
  return { content: [{ type: "text", text: formatContent(result) }], structuredContent: toStructured(result) };
6999
7081
  }
7000
7082
  );
@@ -7003,10 +7085,14 @@ function registerTools(server, client, sessionManager) {
7003
7085
  {
7004
7086
  title: "Project overview",
7005
7087
  description: "Get project overview with summary information",
7006
- inputSchema: external_exports.object({ project_id: external_exports.string().uuid() })
7088
+ inputSchema: external_exports.object({ project_id: external_exports.string().uuid().optional() })
7007
7089
  },
7008
7090
  async (input) => {
7009
- const result = await client.projectOverview(input.project_id);
7091
+ const projectId = resolveProjectId(input.project_id);
7092
+ if (!projectId) {
7093
+ return errorResult("Error: project_id is required. Please call session_init first or provide project_id explicitly.");
7094
+ }
7095
+ const result = await client.projectOverview(projectId);
7010
7096
  return { content: [{ type: "text", text: formatContent(result) }], structuredContent: toStructured(result) };
7011
7097
  }
7012
7098
  );
@@ -7015,10 +7101,14 @@ function registerTools(server, client, sessionManager) {
7015
7101
  {
7016
7102
  title: "Project statistics",
7017
7103
  description: "Get project statistics (files, lines, complexity)",
7018
- inputSchema: external_exports.object({ project_id: external_exports.string().uuid() })
7104
+ inputSchema: external_exports.object({ project_id: external_exports.string().uuid().optional() })
7019
7105
  },
7020
7106
  async (input) => {
7021
- const result = await client.projectStatistics(input.project_id);
7107
+ const projectId = resolveProjectId(input.project_id);
7108
+ if (!projectId) {
7109
+ return errorResult("Error: project_id is required. Please call session_init first or provide project_id explicitly.");
7110
+ }
7111
+ const result = await client.projectStatistics(projectId);
7022
7112
  return { content: [{ type: "text", text: formatContent(result) }], structuredContent: toStructured(result) };
7023
7113
  }
7024
7114
  );
@@ -7027,10 +7117,14 @@ function registerTools(server, client, sessionManager) {
7027
7117
  {
7028
7118
  title: "List project files",
7029
7119
  description: "List all indexed files in a project",
7030
- inputSchema: external_exports.object({ project_id: external_exports.string().uuid() })
7120
+ inputSchema: external_exports.object({ project_id: external_exports.string().uuid().optional() })
7031
7121
  },
7032
7122
  async (input) => {
7033
- const result = await client.projectFiles(input.project_id);
7123
+ const projectId = resolveProjectId(input.project_id);
7124
+ if (!projectId) {
7125
+ return errorResult("Error: project_id is required. Please call session_init first or provide project_id explicitly.");
7126
+ }
7127
+ const result = await client.projectFiles(projectId);
7034
7128
  return { content: [{ type: "text", text: formatContent(result) }], structuredContent: toStructured(result) };
7035
7129
  }
7036
7130
  );
@@ -7039,10 +7133,14 @@ function registerTools(server, client, sessionManager) {
7039
7133
  {
7040
7134
  title: "Index status",
7041
7135
  description: "Get project indexing status",
7042
- inputSchema: external_exports.object({ project_id: external_exports.string().uuid() })
7136
+ inputSchema: external_exports.object({ project_id: external_exports.string().uuid().optional() })
7043
7137
  },
7044
7138
  async (input) => {
7045
- const result = await client.projectIndexStatus(input.project_id);
7139
+ const projectId = resolveProjectId(input.project_id);
7140
+ if (!projectId) {
7141
+ return errorResult("Error: project_id is required. Please call session_init first or provide project_id explicitly.");
7142
+ }
7143
+ const result = await client.projectIndexStatus(projectId);
7046
7144
  return { content: [{ type: "text", text: formatContent(result) }], structuredContent: toStructured(result) };
7047
7145
  }
7048
7146
  );
@@ -7054,18 +7152,22 @@ function registerTools(server, client, sessionManager) {
7054
7152
  This indexes your entire project by reading files in batches.
7055
7153
  Automatically detects code files and skips ignored directories like node_modules, target, dist, etc.`,
7056
7154
  inputSchema: external_exports.object({
7057
- project_id: external_exports.string().uuid().describe("Project to ingest files into"),
7155
+ project_id: external_exports.string().uuid().optional().describe("Project to ingest files into (defaults to current session project)"),
7058
7156
  path: external_exports.string().describe("Local directory path to read files from")
7059
7157
  })
7060
7158
  },
7061
7159
  async (input) => {
7160
+ const projectId = resolveProjectId(input.project_id);
7161
+ if (!projectId) {
7162
+ return errorResult("Error: project_id is required. Please call session_init first or provide project_id explicitly.");
7163
+ }
7062
7164
  (async () => {
7063
7165
  try {
7064
7166
  let totalIndexed = 0;
7065
7167
  let batchCount = 0;
7066
- console.error(`[ContextStream] Starting background ingestion for project ${input.project_id} from ${input.path}`);
7168
+ console.error(`[ContextStream] Starting background ingestion for project ${projectId} from ${input.path}`);
7067
7169
  for await (const batch of readAllFilesInBatches(input.path, { batchSize: 50 })) {
7068
- const result = await client.ingestFiles(input.project_id, batch);
7170
+ const result = await client.ingestFiles(projectId, batch);
7069
7171
  totalIndexed += result.data?.files_indexed ?? batch.length;
7070
7172
  batchCount++;
7071
7173
  }
@@ -7077,7 +7179,7 @@ Automatically detects code files and skips ignored directories like node_modules
7077
7179
  const summary = {
7078
7180
  status: "started",
7079
7181
  message: "Ingestion running in background",
7080
- project_id: input.project_id,
7182
+ project_id: projectId,
7081
7183
  path: input.path,
7082
7184
  note: "Use 'projects_index_status' to monitor progress."
7083
7185
  };
@@ -7095,10 +7197,14 @@ Automatically detects code files and skips ignored directories like node_modules
7095
7197
  {
7096
7198
  title: "Get workspace",
7097
7199
  description: "Get workspace details by ID",
7098
- inputSchema: external_exports.object({ workspace_id: external_exports.string().uuid() })
7200
+ inputSchema: external_exports.object({ workspace_id: external_exports.string().uuid().optional() })
7099
7201
  },
7100
7202
  async (input) => {
7101
- const result = await client.getWorkspace(input.workspace_id);
7203
+ const workspaceId = resolveWorkspaceId(input.workspace_id);
7204
+ if (!workspaceId) {
7205
+ return errorResult("Error: workspace_id is required. Please call session_init first or provide workspace_id explicitly.");
7206
+ }
7207
+ const result = await client.getWorkspace(workspaceId);
7102
7208
  return { content: [{ type: "text", text: formatContent(result) }], structuredContent: toStructured(result) };
7103
7209
  }
7104
7210
  );
@@ -7107,10 +7213,14 @@ Automatically detects code files and skips ignored directories like node_modules
7107
7213
  {
7108
7214
  title: "Workspace overview",
7109
7215
  description: "Get workspace overview with summary information",
7110
- inputSchema: external_exports.object({ workspace_id: external_exports.string().uuid() })
7216
+ inputSchema: external_exports.object({ workspace_id: external_exports.string().uuid().optional() })
7111
7217
  },
7112
7218
  async (input) => {
7113
- const result = await client.workspaceOverview(input.workspace_id);
7219
+ const workspaceId = resolveWorkspaceId(input.workspace_id);
7220
+ if (!workspaceId) {
7221
+ return errorResult("Error: workspace_id is required. Please call session_init first or provide workspace_id explicitly.");
7222
+ }
7223
+ const result = await client.workspaceOverview(workspaceId);
7114
7224
  return { content: [{ type: "text", text: formatContent(result) }], structuredContent: toStructured(result) };
7115
7225
  }
7116
7226
  );
@@ -7119,10 +7229,14 @@ Automatically detects code files and skips ignored directories like node_modules
7119
7229
  {
7120
7230
  title: "Workspace analytics",
7121
7231
  description: "Get workspace usage analytics",
7122
- inputSchema: external_exports.object({ workspace_id: external_exports.string().uuid() })
7232
+ inputSchema: external_exports.object({ workspace_id: external_exports.string().uuid().optional() })
7123
7233
  },
7124
7234
  async (input) => {
7125
- const result = await client.workspaceAnalytics(input.workspace_id);
7235
+ const workspaceId = resolveWorkspaceId(input.workspace_id);
7236
+ if (!workspaceId) {
7237
+ return errorResult("Error: workspace_id is required. Please call session_init first or provide workspace_id explicitly.");
7238
+ }
7239
+ const result = await client.workspaceAnalytics(workspaceId);
7126
7240
  return { content: [{ type: "text", text: formatContent(result) }], structuredContent: toStructured(result) };
7127
7241
  }
7128
7242
  );
@@ -7131,10 +7245,14 @@ Automatically detects code files and skips ignored directories like node_modules
7131
7245
  {
7132
7246
  title: "Workspace content",
7133
7247
  description: "List content in a workspace",
7134
- inputSchema: external_exports.object({ workspace_id: external_exports.string().uuid() })
7248
+ inputSchema: external_exports.object({ workspace_id: external_exports.string().uuid().optional() })
7135
7249
  },
7136
7250
  async (input) => {
7137
- const result = await client.workspaceContent(input.workspace_id);
7251
+ const workspaceId = resolveWorkspaceId(input.workspace_id);
7252
+ if (!workspaceId) {
7253
+ return errorResult("Error: workspace_id is required. Please call session_init first or provide workspace_id explicitly.");
7254
+ }
7255
+ const result = await client.workspaceContent(workspaceId);
7138
7256
  return { content: [{ type: "text", text: formatContent(result) }], structuredContent: toStructured(result) };
7139
7257
  }
7140
7258
  );
@@ -7256,10 +7374,14 @@ Automatically detects code files and skips ignored directories like node_modules
7256
7374
  {
7257
7375
  title: "Memory timeline",
7258
7376
  description: "Get chronological timeline of memory events for a workspace",
7259
- inputSchema: external_exports.object({ workspace_id: external_exports.string().uuid() })
7377
+ inputSchema: external_exports.object({ workspace_id: external_exports.string().uuid().optional() })
7260
7378
  },
7261
7379
  async (input) => {
7262
- const result = await client.memoryTimeline(input.workspace_id);
7380
+ const workspaceId = resolveWorkspaceId(input.workspace_id);
7381
+ if (!workspaceId) {
7382
+ return errorResult("Error: workspace_id is required. Please call session_init first or provide workspace_id explicitly.");
7383
+ }
7384
+ const result = await client.memoryTimeline(workspaceId);
7263
7385
  return { content: [{ type: "text", text: formatContent(result) }], structuredContent: toStructured(result) };
7264
7386
  }
7265
7387
  );
@@ -7268,10 +7390,14 @@ Automatically detects code files and skips ignored directories like node_modules
7268
7390
  {
7269
7391
  title: "Memory summary",
7270
7392
  description: "Get condensed summary of workspace memory",
7271
- inputSchema: external_exports.object({ workspace_id: external_exports.string().uuid() })
7393
+ inputSchema: external_exports.object({ workspace_id: external_exports.string().uuid().optional() })
7272
7394
  },
7273
7395
  async (input) => {
7274
- const result = await client.memorySummary(input.workspace_id);
7396
+ const workspaceId = resolveWorkspaceId(input.workspace_id);
7397
+ if (!workspaceId) {
7398
+ return errorResult("Error: workspace_id is required. Please call session_init first or provide workspace_id explicitly.");
7399
+ }
7400
+ const result = await client.memorySummary(workspaceId);
7275
7401
  return { content: [{ type: "text", text: formatContent(result) }], structuredContent: toStructured(result) };
7276
7402
  }
7277
7403
  );
@@ -7280,10 +7406,14 @@ Automatically detects code files and skips ignored directories like node_modules
7280
7406
  {
7281
7407
  title: "Find circular dependencies",
7282
7408
  description: "Detect circular dependencies in project code",
7283
- inputSchema: external_exports.object({ project_id: external_exports.string().uuid() })
7409
+ inputSchema: external_exports.object({ project_id: external_exports.string().uuid().optional() })
7284
7410
  },
7285
7411
  async (input) => {
7286
- const result = await client.findCircularDependencies(input.project_id);
7412
+ const projectId = resolveProjectId(input.project_id);
7413
+ if (!projectId) {
7414
+ return errorResult("Error: project_id is required. Please call session_init first or provide project_id explicitly.");
7415
+ }
7416
+ const result = await client.findCircularDependencies(projectId);
7287
7417
  return { content: [{ type: "text", text: formatContent(result) }], structuredContent: toStructured(result) };
7288
7418
  }
7289
7419
  );
@@ -7292,10 +7422,14 @@ Automatically detects code files and skips ignored directories like node_modules
7292
7422
  {
7293
7423
  title: "Find unused code",
7294
7424
  description: "Detect unused code in project",
7295
- inputSchema: external_exports.object({ project_id: external_exports.string().uuid() })
7425
+ inputSchema: external_exports.object({ project_id: external_exports.string().uuid().optional() })
7296
7426
  },
7297
7427
  async (input) => {
7298
- const result = await client.findUnusedCode(input.project_id);
7428
+ const projectId = resolveProjectId(input.project_id);
7429
+ if (!projectId) {
7430
+ return errorResult("Error: project_id is required. Please call session_init first or provide project_id explicitly.");
7431
+ }
7432
+ const result = await client.findUnusedCode(projectId);
7299
7433
  return { content: [{ type: "text", text: formatContent(result) }], structuredContent: toStructured(result) };
7300
7434
  }
7301
7435
  );
@@ -7440,6 +7574,117 @@ Optionally generates AI editor rules for automatic ContextStream usage.`,
7440
7574
  return { content: [{ type: "text", text: formatContent(response) }], structuredContent: toStructured(response) };
7441
7575
  }
7442
7576
  );
7577
+ registerTool(
7578
+ "workspace_bootstrap",
7579
+ {
7580
+ title: "Create workspace + project from folder",
7581
+ description: `Create a new workspace (user-provided name) and onboard the current folder as a project.
7582
+ This is useful when session_init returns status='requires_workspace_name' (no workspaces exist yet) or when you want to create a new workspace for a repo.
7583
+
7584
+ Behavior:
7585
+ - Creates a workspace with the given name
7586
+ - Associates the folder to that workspace (writes .contextstream/config.json)
7587
+ - Initializes a session for the folder, which creates the project (folder name) and starts indexing (if enabled)`,
7588
+ inputSchema: external_exports.object({
7589
+ workspace_name: external_exports.string().min(1).describe("Name for the new workspace (ask the user)"),
7590
+ folder_path: external_exports.string().optional().describe("Absolute folder path (defaults to IDE root/cwd)"),
7591
+ description: external_exports.string().optional().describe("Optional workspace description"),
7592
+ visibility: external_exports.enum(["private", "public"]).optional().describe("Workspace visibility (default: private)"),
7593
+ create_parent_mapping: external_exports.boolean().optional().describe("Also create a parent folder mapping (e.g., /dev/company/* -> workspace)"),
7594
+ generate_editor_rules: external_exports.boolean().optional().describe("Generate AI editor rules in the folder for automatic ContextStream usage"),
7595
+ context_hint: external_exports.string().optional().describe("Optional context hint for session initialization"),
7596
+ auto_index: external_exports.boolean().optional().describe("Automatically create and index project from folder (default: true)")
7597
+ })
7598
+ },
7599
+ async (input) => {
7600
+ let folderPath = input.folder_path;
7601
+ if (!folderPath) {
7602
+ try {
7603
+ const rootsResponse = await server.server.listRoots();
7604
+ if (rootsResponse?.roots && rootsResponse.roots.length > 0) {
7605
+ folderPath = rootsResponse.roots[0].uri.replace("file://", "");
7606
+ }
7607
+ } catch {
7608
+ }
7609
+ }
7610
+ if (!folderPath) {
7611
+ folderPath = process.cwd();
7612
+ }
7613
+ if (!folderPath) {
7614
+ return errorResult("Error: folder_path is required. Provide folder_path or run from a project directory.");
7615
+ }
7616
+ const folderName = folderPath.split("/").pop() || "My Project";
7617
+ const newWorkspace = await client.createWorkspace({
7618
+ name: input.workspace_name,
7619
+ description: input.description || `Workspace created for ${folderPath}`,
7620
+ visibility: input.visibility || "private"
7621
+ });
7622
+ if (!newWorkspace?.id) {
7623
+ return errorResult("Error: failed to create workspace.");
7624
+ }
7625
+ const associateResult = await client.associateWorkspace({
7626
+ folder_path: folderPath,
7627
+ workspace_id: newWorkspace.id,
7628
+ workspace_name: newWorkspace.name || input.workspace_name,
7629
+ create_parent_mapping: input.create_parent_mapping
7630
+ });
7631
+ let rulesGenerated = [];
7632
+ if (input.generate_editor_rules) {
7633
+ const fs3 = await import("fs");
7634
+ const path3 = await import("path");
7635
+ for (const editor of getAvailableEditors()) {
7636
+ const rule = generateRuleContent(editor, {
7637
+ workspaceName: newWorkspace.name || input.workspace_name,
7638
+ workspaceId: newWorkspace.id
7639
+ });
7640
+ if (!rule) continue;
7641
+ const filePath = path3.join(folderPath, rule.filename);
7642
+ try {
7643
+ let existingContent = "";
7644
+ try {
7645
+ existingContent = fs3.readFileSync(filePath, "utf-8");
7646
+ } catch {
7647
+ }
7648
+ if (!existingContent) {
7649
+ fs3.writeFileSync(filePath, rule.content);
7650
+ rulesGenerated.push(rule.filename);
7651
+ } else if (!existingContent.includes("ContextStream Integration")) {
7652
+ fs3.writeFileSync(filePath, existingContent + "\n\n" + rule.content);
7653
+ rulesGenerated.push(rule.filename + " (appended)");
7654
+ }
7655
+ } catch {
7656
+ }
7657
+ }
7658
+ }
7659
+ const session = await client.initSession(
7660
+ {
7661
+ workspace_id: newWorkspace.id,
7662
+ context_hint: input.context_hint,
7663
+ include_recent_memory: true,
7664
+ include_decisions: true,
7665
+ auto_index: input.auto_index
7666
+ },
7667
+ [folderPath]
7668
+ );
7669
+ if (sessionManager) {
7670
+ sessionManager.markInitialized(session);
7671
+ }
7672
+ const response = {
7673
+ ...session,
7674
+ bootstrap: {
7675
+ folder_path: folderPath,
7676
+ project_name: folderName,
7677
+ workspace: {
7678
+ id: newWorkspace.id,
7679
+ name: newWorkspace.name || input.workspace_name
7680
+ },
7681
+ association: associateResult,
7682
+ editor_rules_generated: rulesGenerated.length > 0 ? rulesGenerated : void 0
7683
+ }
7684
+ };
7685
+ return { content: [{ type: "text", text: formatContent(response) }], structuredContent: toStructured(response) };
7686
+ }
7687
+ );
7443
7688
  registerTool(
7444
7689
  "session_capture",
7445
7690
  {
@@ -7626,7 +7871,7 @@ Returns lessons filtered by:
7626
7871
  limit: input.limit * 2
7627
7872
  // Fetch more to filter
7628
7873
  });
7629
- let lessons = (searchResult?.results || []).filter((item) => {
7874
+ let lessons = (searchResult.results || []).filter((item) => {
7630
7875
  const tags = item.metadata?.tags || [];
7631
7876
  const isLesson = tags.includes("lesson");
7632
7877
  if (!isLesson) return false;
@@ -8171,34 +8416,47 @@ function registerResources(server, client, apiUrl) {
8171
8416
  }
8172
8417
 
8173
8418
  // src/prompts.ts
8419
+ var ID_NOTES = [
8420
+ "Notes:",
8421
+ "- If ContextStream is not initialized in this conversation, call `session_init` first (omit ids).",
8422
+ "- Do not ask me for `workspace_id`/`project_id` \u2014 use session defaults or IDs returned by `session_init`.",
8423
+ "- Prefer omitting IDs in tool calls when the tool supports defaults."
8424
+ ];
8425
+ var upgradeUrl = process.env.CONTEXTSTREAM_UPGRADE_URL || "https://contextstream.io/pricing";
8426
+ var proPrompts = /* @__PURE__ */ new Set([
8427
+ "build-context",
8428
+ "generate-plan",
8429
+ "generate-tasks",
8430
+ "token-budget-context"
8431
+ ]);
8432
+ function promptAccessLabel(promptName) {
8433
+ return proPrompts.has(promptName) ? "PRO" : "Free";
8434
+ }
8174
8435
  function registerPrompts(server) {
8175
8436
  server.registerPrompt(
8176
8437
  "explore-codebase",
8177
8438
  {
8178
- title: "Explore Codebase",
8179
- description: "Get an overview of a project codebase structure and key components",
8180
- argsSchema: {
8181
- project_id: external_exports.string().uuid().optional().describe("Project ID to explore (optional if session_init has set defaults)"),
8182
- focus_area: external_exports.string().optional().describe('Optional area to focus on (e.g., "authentication", "api routes")')
8183
- }
8439
+ title: `Explore Codebase (${promptAccessLabel("explore-codebase")})`,
8440
+ description: "Get an overview of a project codebase structure and key components"
8184
8441
  },
8185
- async (args) => ({
8442
+ async () => ({
8186
8443
  messages: [
8187
8444
  {
8188
8445
  role: "user",
8189
8446
  content: {
8190
8447
  type: "text",
8191
- text: `I want to understand the codebase${args.project_id ? ` for project ${args.project_id}` : ""}${args.focus_area ? ` with focus on ${args.focus_area}` : ""}.
8192
-
8193
- If project_id is not provided, first call \`session_init\` (or \`projects_list\`) to resolve the current project ID.
8194
-
8195
- Please help me by:
8196
- 1. First, use \`projects_overview\` to get the project summary
8197
- 2. Use \`projects_files\` to list the key files
8198
- 3. Use \`search_semantic\` to find relevant code${args.focus_area ? ` related to "${args.focus_area}"` : ""}
8199
- 4. Summarize the architecture and key patterns you observe
8200
-
8201
- Provide a clear, structured overview that helps me navigate this codebase effectively.`
8448
+ text: [
8449
+ "I want to understand the current codebase.",
8450
+ "",
8451
+ ...ID_NOTES,
8452
+ "",
8453
+ "Please help me by:",
8454
+ "1. Use `projects_overview` to get a project summary (use session defaults; only pass `project_id` if required).",
8455
+ "2. Use `projects_files` to identify key entry points.",
8456
+ "3. If a focus area is clear from our conversation, prioritize it; otherwise ask me what to focus on.",
8457
+ "4. Use `search_semantic` (and optionally `search_hybrid`) to find the most relevant files.",
8458
+ "5. Summarize the architecture, major modules, and where to start editing."
8459
+ ].join("\n")
8202
8460
  }
8203
8461
  }
8204
8462
  ]
@@ -8207,40 +8465,32 @@ Provide a clear, structured overview that helps me navigate this codebase effect
8207
8465
  server.registerPrompt(
8208
8466
  "capture-decision",
8209
8467
  {
8210
- title: "Capture Decision",
8211
- description: "Document an architectural or technical decision in workspace memory",
8212
- argsSchema: {
8213
- workspace_id: external_exports.string().uuid().optional().describe("Workspace ID (optional if session_init has set defaults)"),
8214
- decision_title: external_exports.string().describe("Brief title of the decision"),
8215
- context: external_exports.string().describe("What prompted this decision"),
8216
- decision: external_exports.string().describe("The decision made"),
8217
- consequences: external_exports.string().optional().describe("Expected consequences or tradeoffs")
8218
- }
8468
+ title: `Capture Decision (${promptAccessLabel("capture-decision")})`,
8469
+ description: "Document an architectural or technical decision in workspace memory"
8219
8470
  },
8220
- async (args) => ({
8471
+ async () => ({
8221
8472
  messages: [
8222
8473
  {
8223
8474
  role: "user",
8224
8475
  content: {
8225
8476
  type: "text",
8226
- text: `Please document the following decision in workspace memory:
8227
-
8228
- **Title:** ${args.decision_title}
8229
- **Context:** ${args.context}
8230
- **Decision:** ${args.decision}
8231
- ${args.consequences ? `**Consequences:** ${args.consequences}` : ""}
8232
-
8233
- If workspace_id is not provided, first call \`session_init\` to resolve the workspace, then capture the decision.
8234
-
8235
- Use \`session_capture\` with:
8236
- - event_type: "decision"
8237
- ${args.workspace_id ? `- workspace_id: "${args.workspace_id}"` : "- workspace_id: (omit to use session defaults)"}
8238
- - title: "${args.decision_title}"
8239
- - content: A well-formatted ADR (Architecture Decision Record) with context, decision, and consequences
8240
- - tags: Include relevant tags (e.g., "adr", "architecture")
8241
- - importance: "high"
8242
-
8243
- After creating, confirm the decision was recorded and summarize it.`
8477
+ text: [
8478
+ "Please capture an architectural/technical decision in ContextStream memory.",
8479
+ "",
8480
+ ...ID_NOTES,
8481
+ "",
8482
+ "Instructions:",
8483
+ "- If the decision is already described in this conversation, extract: title, context, decision, consequences/tradeoffs.",
8484
+ "- If anything is missing, ask me 1\u20133 quick questions to fill the gaps.",
8485
+ "- Then call `session_capture` with:",
8486
+ ' - event_type: "decision"',
8487
+ " - title: (short ADR title)",
8488
+ " - content: a well-formatted ADR (Context, Decision, Consequences)",
8489
+ ' - tags: include relevant tags (e.g., "adr", "architecture")',
8490
+ ' - importance: "high"',
8491
+ "",
8492
+ "After capturing, confirm what was saved."
8493
+ ].join("\n")
8244
8494
  }
8245
8495
  }
8246
8496
  ]
@@ -8249,35 +8499,35 @@ After creating, confirm the decision was recorded and summarize it.`
8249
8499
  server.registerPrompt(
8250
8500
  "review-context",
8251
8501
  {
8252
- title: "Code Review Context",
8253
- description: "Build context for reviewing code changes",
8254
- argsSchema: {
8255
- project_id: external_exports.string().uuid().optional().describe("Project ID (optional if session_init has set defaults)"),
8256
- file_paths: external_exports.string().describe("Comma-separated file paths being changed"),
8257
- change_description: external_exports.string().describe("Brief description of the changes")
8258
- }
8502
+ title: `Code Review Context (${promptAccessLabel("review-context")})`,
8503
+ description: "Build context for reviewing code changes"
8259
8504
  },
8260
- async (args) => ({
8505
+ async () => ({
8261
8506
  messages: [
8262
8507
  {
8263
8508
  role: "user",
8264
8509
  content: {
8265
8510
  type: "text",
8266
- text: `I need context to review changes in these files: ${args.file_paths}
8267
-
8268
- Change description: ${args.change_description}
8269
-
8270
- Please help me understand the impact by:
8271
- 1. Use \`graph_dependencies\` to find what depends on these files
8272
- 2. Use \`graph_impact\` to analyze potential impact
8273
- 3. Use \`memory_search\` to find related decisions or notes about these areas
8274
- 4. Use \`search_semantic\` to find related code patterns
8275
-
8276
- Provide:
8277
- - Summary of what these files do
8278
- - What other parts of the codebase might be affected
8279
- - Any relevant past decisions or context from memory
8280
- - Potential risks or areas to focus the review on`
8511
+ text: [
8512
+ "I need context to review a set of code changes.",
8513
+ "",
8514
+ ...ID_NOTES,
8515
+ "",
8516
+ "First:",
8517
+ "- If file paths and a short change description are not already in this conversation, ask me for them.",
8518
+ "",
8519
+ "Then build review context by:",
8520
+ "1. Using `graph_dependencies` to find what depends on the changed areas.",
8521
+ "2. Using `graph_impact` to assess potential blast radius.",
8522
+ "3. Using `memory_search` to find related decisions/notes.",
8523
+ "4. Using `search_semantic` to find related code patterns.",
8524
+ "",
8525
+ "Provide:",
8526
+ "- What the files/components do",
8527
+ "- What might be affected",
8528
+ "- Relevant prior decisions/lessons",
8529
+ "- Review checklist + risks to focus on"
8530
+ ].join("\n")
8281
8531
  }
8282
8532
  }
8283
8533
  ]
@@ -8286,36 +8536,36 @@ Provide:
8286
8536
  server.registerPrompt(
8287
8537
  "investigate-bug",
8288
8538
  {
8289
- title: "Investigate Bug",
8290
- description: "Build context for debugging an issue",
8291
- argsSchema: {
8292
- project_id: external_exports.string().uuid().optional().describe("Project ID (optional if session_init has set defaults)"),
8293
- error_message: external_exports.string().describe("Error message or symptom"),
8294
- affected_area: external_exports.string().optional().describe("Known affected area or component")
8295
- }
8539
+ title: `Investigate Bug (${promptAccessLabel("investigate-bug")})`,
8540
+ description: "Build context for debugging an issue"
8296
8541
  },
8297
- async (args) => ({
8542
+ async () => ({
8298
8543
  messages: [
8299
8544
  {
8300
8545
  role: "user",
8301
8546
  content: {
8302
8547
  type: "text",
8303
- text: `I'm investigating a bug:
8304
-
8305
- **Error/Symptom:** ${args.error_message}
8306
- ${args.affected_area ? `**Affected Area:** ${args.affected_area}` : ""}
8307
-
8308
- Please help me investigate by:
8309
- 1. Use \`search_semantic\` to find code related to this error
8310
- 2. Use \`search_pattern\` to find where similar errors are thrown
8311
- 3. Use \`graph_call_path\` to trace call flows if we identify key functions
8312
- 4. Use \`memory_search\` to check if this issue has been encountered before
8313
-
8314
- Provide:
8315
- - Likely locations where this error originates
8316
- - Call flow analysis
8317
- - Any related past issues from memory
8318
- - Suggested debugging approach`
8548
+ text: [
8549
+ "I want help investigating a bug.",
8550
+ "",
8551
+ ...ID_NOTES,
8552
+ "",
8553
+ "First:",
8554
+ "- If the error/symptom is not already stated, ask me for the exact error message and what I expected vs what happened.",
8555
+ "- If an affected area/component is not known, ask me where I noticed it.",
8556
+ "",
8557
+ "Then:",
8558
+ "1. Use `search_semantic` to find code related to the error/symptom.",
8559
+ "2. Use `search_pattern` to locate where similar errors are thrown or logged.",
8560
+ "3. If you identify key functions, use `graph_call_path` to trace call flows.",
8561
+ "4. Use `memory_search` to check if we have prior notes/bugs about this area.",
8562
+ "",
8563
+ "Return:",
8564
+ "- Likely origin locations",
8565
+ "- Call flow (if found)",
8566
+ "- Related past context",
8567
+ "- Suggested debugging steps"
8568
+ ].join("\n")
8319
8569
  }
8320
8570
  }
8321
8571
  ]
@@ -8324,34 +8574,32 @@ Provide:
8324
8574
  server.registerPrompt(
8325
8575
  "explore-knowledge",
8326
8576
  {
8327
- title: "Explore Knowledge Graph",
8328
- description: "Navigate and understand the knowledge graph for a workspace",
8329
- argsSchema: {
8330
- workspace_id: external_exports.string().uuid().optional().describe("Workspace ID (optional if session_init has set defaults)"),
8331
- starting_topic: external_exports.string().optional().describe("Topic to start exploration from")
8332
- }
8577
+ title: `Explore Knowledge Graph (${promptAccessLabel("explore-knowledge")})`,
8578
+ description: "Navigate and understand the knowledge graph for a workspace"
8333
8579
  },
8334
- async (args) => ({
8580
+ async () => ({
8335
8581
  messages: [
8336
8582
  {
8337
8583
  role: "user",
8338
8584
  content: {
8339
8585
  type: "text",
8340
- text: `Help me explore the knowledge captured in the current workspace${args.workspace_id ? ` (${args.workspace_id})` : ""}${args.starting_topic ? ` starting from "${args.starting_topic}"` : ""}.
8341
-
8342
- If workspace_id is not provided, first call \`session_init\` to resolve the workspace.
8343
-
8344
- Please:
8345
- 1. Use \`memory_list_nodes\` to see available knowledge nodes
8346
- 2. Use \`memory_decisions\` to see decision history
8347
- 3. ${args.starting_topic ? `Use \`memory_search\` to find nodes related to "${args.starting_topic}"` : "Use `memory_summary` to get an overview"}
8348
- 4. Use \`graph_related\` to explore connections between nodes
8349
-
8350
- Provide:
8351
- - Overview of knowledge captured
8352
- - Key themes and topics
8353
- - Important decisions and their rationale
8354
- - Connections between different pieces of knowledge`
8586
+ text: [
8587
+ "Help me explore the knowledge captured in this workspace.",
8588
+ "",
8589
+ ...ID_NOTES,
8590
+ "",
8591
+ "Approach:",
8592
+ "1. Use `memory_summary` for a high-level overview.",
8593
+ "2. Use `memory_decisions` to see decision history (titles + a few key details).",
8594
+ "3. Use `memory_list_nodes` to see available knowledge nodes.",
8595
+ "4. If a starting topic is clear from the conversation, use `memory_search` for it.",
8596
+ "5. Use `graph_related` on the most relevant nodes to expand connections.",
8597
+ "",
8598
+ "Provide:",
8599
+ "- Key themes and topics",
8600
+ "- Important decisions + rationale",
8601
+ "- Suggested \u201Cnext nodes\u201D to explore"
8602
+ ].join("\n")
8355
8603
  }
8356
8604
  }
8357
8605
  ]
@@ -8360,37 +8608,37 @@ Provide:
8360
8608
  server.registerPrompt(
8361
8609
  "onboard-to-project",
8362
8610
  {
8363
- title: "Project Onboarding",
8364
- description: "Generate onboarding context for a new team member",
8365
- argsSchema: {
8366
- project_id: external_exports.string().uuid().optional().describe("Project ID (optional if session_init has set defaults)"),
8367
- workspace_id: external_exports.string().uuid().optional().describe("Workspace ID (optional if session_init has set defaults)"),
8368
- role: external_exports.string().optional().describe('Role of the person being onboarded (e.g., "backend developer", "frontend developer")')
8369
- }
8611
+ title: `Project Onboarding (${promptAccessLabel("onboard-to-project")})`,
8612
+ description: "Generate onboarding context for a new team member"
8370
8613
  },
8371
- async (args) => ({
8614
+ async () => ({
8372
8615
  messages: [
8373
8616
  {
8374
8617
  role: "user",
8375
8618
  content: {
8376
8619
  type: "text",
8377
- text: `Create an onboarding guide for a new team member joining this project.
8378
- ${args.role ? `They will be working as a ${args.role}.` : ""}
8379
-
8380
- Please gather comprehensive context:
8381
- 1. Use \`projects_overview\` and \`projects_statistics\` for project summary
8382
- 2. Use \`projects_files\` to identify key entry points
8383
- 3. Use \`memory_timeline\` to see recent activity and changes
8384
- 4. Use \`memory_decisions\` to understand key architectural choices
8385
- 5. Use \`search_semantic\` to find documentation and READMEs
8386
-
8387
- Provide an onboarding guide that includes:
8388
- - Project overview and purpose
8389
- - Technology stack and architecture
8390
- - Key files and entry points${args.role ? ` relevant to ${args.role}` : ""}
8391
- - Important decisions and their rationale
8392
- - Recent changes and current focus areas
8393
- - Getting started steps`
8620
+ text: [
8621
+ "Create an onboarding guide for a new team member joining this project.",
8622
+ "",
8623
+ ...ID_NOTES,
8624
+ "",
8625
+ "First:",
8626
+ "- If the role is not specified, ask me what role they are onboarding into (backend, frontend, fullstack, etc.).",
8627
+ "",
8628
+ "Gather context:",
8629
+ "1. Use `projects_overview` and `projects_statistics` for project summary.",
8630
+ "2. Use `projects_files` to identify key entry points.",
8631
+ "3. Use `memory_timeline` and `memory_decisions` to understand recent changes and architectural choices.",
8632
+ "4. Use `search_semantic` to find READMEs/docs/setup instructions.",
8633
+ "",
8634
+ "Output:",
8635
+ "- Project overview and purpose",
8636
+ "- Tech stack + architecture map",
8637
+ "- Key files/entry points relevant to the role",
8638
+ "- Important decisions + rationale",
8639
+ "- Recent changes/current focus",
8640
+ "- Step-by-step getting started"
8641
+ ].join("\n")
8394
8642
  }
8395
8643
  }
8396
8644
  ]
@@ -8399,33 +8647,30 @@ Provide an onboarding guide that includes:
8399
8647
  server.registerPrompt(
8400
8648
  "analyze-refactoring",
8401
8649
  {
8402
- title: "Refactoring Analysis",
8403
- description: "Analyze a codebase for refactoring opportunities",
8404
- argsSchema: {
8405
- project_id: external_exports.string().uuid().optional().describe("Project ID (optional if session_init has set defaults)"),
8406
- target_area: external_exports.string().optional().describe("Specific area to analyze")
8407
- }
8650
+ title: `Refactoring Analysis (${promptAccessLabel("analyze-refactoring")})`,
8651
+ description: "Analyze a codebase for refactoring opportunities"
8408
8652
  },
8409
- async (args) => ({
8653
+ async () => ({
8410
8654
  messages: [
8411
8655
  {
8412
8656
  role: "user",
8413
8657
  content: {
8414
8658
  type: "text",
8415
- text: `Analyze the codebase for refactoring opportunities${args.target_area ? ` in ${args.target_area}` : ""}.
8416
-
8417
- Please investigate:
8418
- 1. Use \`graph_circular_dependencies\` to find circular dependencies
8419
- 2. Use \`graph_unused_code\` to find dead code
8420
- 3. Use \`search_pattern\` to find code duplication patterns
8421
- 4. Use \`projects_statistics\` to identify complex areas
8422
-
8423
- Provide:
8424
- - Circular dependencies that should be broken
8425
- - Unused code that can be removed
8426
- - Duplicate patterns that could be consolidated
8427
- - High complexity areas that need simplification
8428
- - Prioritized refactoring recommendations`
8659
+ text: [
8660
+ "Analyze the codebase for refactoring opportunities.",
8661
+ "",
8662
+ ...ID_NOTES,
8663
+ "",
8664
+ "If a target area is obvious from our conversation, focus there; otherwise ask me what area to analyze.",
8665
+ "",
8666
+ "Please investigate:",
8667
+ "1. `graph_circular_dependencies` (circular deps to break)",
8668
+ "2. `graph_unused_code` (dead code to remove)",
8669
+ "3. `search_pattern` (duplication patterns)",
8670
+ "4. `projects_statistics` (high complexity hotspots)",
8671
+ "",
8672
+ "Provide a prioritized list with quick wins vs deeper refactors."
8673
+ ].join("\n")
8429
8674
  }
8430
8675
  }
8431
8676
  ]
@@ -8434,34 +8679,30 @@ Provide:
8434
8679
  server.registerPrompt(
8435
8680
  "build-context",
8436
8681
  {
8437
- title: "Build LLM Context",
8438
- description: "Build comprehensive context for an LLM task",
8439
- argsSchema: {
8440
- query: external_exports.string().describe("What you need context for"),
8441
- workspace_id: external_exports.string().uuid().optional().describe("Workspace ID"),
8442
- project_id: external_exports.string().uuid().optional().describe("Project ID"),
8443
- include_memory: external_exports.string().optional().describe('Include memory/decisions ("true" or "false")')
8444
- }
8682
+ title: `Build LLM Context (${promptAccessLabel("build-context")})`,
8683
+ description: "Build comprehensive context for an LLM task"
8445
8684
  },
8446
- async (args) => ({
8685
+ async () => ({
8447
8686
  messages: [
8448
8687
  {
8449
8688
  role: "user",
8450
8689
  content: {
8451
8690
  type: "text",
8452
- text: `Build comprehensive context for the following task:
8453
-
8454
- **Query:** ${args.query}
8455
-
8456
- Please use \`ai_enhanced_context\` with:
8457
- - query: "${args.query}"
8458
- ${args.workspace_id ? `- workspace_id: "${args.workspace_id}"` : ""}
8459
- ${args.project_id ? `- project_id: "${args.project_id}"` : ""}
8460
- - include_code: true
8461
- - include_docs: true
8462
- - include_memory: ${args.include_memory ?? true}
8463
-
8464
- Then synthesize the retrieved context into a coherent briefing that will help with the task.`
8691
+ text: [
8692
+ "Build comprehensive context for the task we are working on.",
8693
+ "",
8694
+ `Access: ${promptAccessLabel("build-context")}${promptAccessLabel("build-context") === "PRO" ? ` (upgrade: ${upgradeUrl})` : ""}`,
8695
+ "",
8696
+ ...ID_NOTES,
8697
+ "",
8698
+ "First:",
8699
+ "- If the \u201Cquery\u201D is clear from the latest user request, use that.",
8700
+ "- Otherwise ask me: \u201CWhat do you need context for?\u201D",
8701
+ "",
8702
+ "Then:",
8703
+ "- Call `ai_enhanced_context` with include_code=true, include_docs=true, include_memory=true (omit IDs unless required).",
8704
+ "- Synthesize the returned context into a short briefing with links/file paths and key decisions/risks."
8705
+ ].join("\n")
8465
8706
  }
8466
8707
  }
8467
8708
  ]
@@ -8470,28 +8711,29 @@ Then synthesize the retrieved context into a coherent briefing that will help wi
8470
8711
  server.registerPrompt(
8471
8712
  "smart-search",
8472
8713
  {
8473
- title: "Smart Search",
8474
- description: "Search across memory, decisions, and code for a query",
8475
- argsSchema: {
8476
- query: external_exports.string().describe("What you want to find"),
8477
- workspace_id: external_exports.string().uuid().optional().describe("Workspace ID (optional)"),
8478
- project_id: external_exports.string().uuid().optional().describe("Project ID (optional)")
8479
- }
8714
+ title: `Smart Search (${promptAccessLabel("smart-search")})`,
8715
+ description: "Search across memory, decisions, and code for a query"
8480
8716
  },
8481
- async (args) => ({
8717
+ async () => ({
8482
8718
  messages: [
8483
8719
  {
8484
8720
  role: "user",
8485
8721
  content: {
8486
8722
  type: "text",
8487
- text: `Find the most relevant context for: "${args.query}"
8488
-
8489
- If workspace_id/project_id are not provided, call \`session_init\` first to resolve the current workspace/project.
8490
-
8491
- Please:
8492
- 1. Use \`session_smart_search\` with query "${args.query}"${args.workspace_id ? ` and workspace_id "${args.workspace_id}"` : ""}${args.project_id ? ` and project_id "${args.project_id}"` : ""}
8493
- 2. If results are thin, follow up with \`search_hybrid\` and \`memory_search\`
8494
- 3. Return the top results with file paths/links and a short synthesis of what matters`
8723
+ text: [
8724
+ "Find the most relevant context for what I am asking about.",
8725
+ "",
8726
+ ...ID_NOTES,
8727
+ "",
8728
+ "First:",
8729
+ "- If a query is clear from the conversation, use it.",
8730
+ "- Otherwise ask me what I want to find.",
8731
+ "",
8732
+ "Then:",
8733
+ "1. Use `session_smart_search` for the query.",
8734
+ "2. If results are thin, follow up with `search_hybrid` and `memory_search`.",
8735
+ "3. Return the top results with file paths/links and a short synthesis."
8736
+ ].join("\n")
8495
8737
  }
8496
8738
  }
8497
8739
  ]
@@ -8500,26 +8742,28 @@ Please:
8500
8742
  server.registerPrompt(
8501
8743
  "recall-context",
8502
8744
  {
8503
- title: "Recall Context",
8504
- description: "Retrieve relevant past decisions and memory for a query",
8505
- argsSchema: {
8506
- query: external_exports.string().describe("What to recall (natural language)"),
8507
- workspace_id: external_exports.string().uuid().optional().describe("Workspace ID (optional)"),
8508
- project_id: external_exports.string().uuid().optional().describe("Project ID (optional)")
8509
- }
8745
+ title: `Recall Context (${promptAccessLabel("recall-context")})`,
8746
+ description: "Retrieve relevant past decisions and memory for a query"
8510
8747
  },
8511
- async (args) => ({
8748
+ async () => ({
8512
8749
  messages: [
8513
8750
  {
8514
8751
  role: "user",
8515
8752
  content: {
8516
8753
  type: "text",
8517
- text: `Recall relevant context for: "${args.query}"
8518
-
8519
- If workspace_id/project_id are not provided, call \`session_init\` first to resolve the current workspace/project.
8520
-
8521
- Use \`session_recall\` with query "${args.query}"${args.workspace_id ? ` and workspace_id "${args.workspace_id}"` : ""}${args.project_id ? ` and project_id "${args.project_id}"` : ""}.
8522
- Then summarize the key points and any relevant decisions/lessons.`
8754
+ text: [
8755
+ "Recall relevant past context (decisions, notes, lessons) for what I am asking about.",
8756
+ "",
8757
+ ...ID_NOTES,
8758
+ "",
8759
+ "First:",
8760
+ "- If a recall query is clear from the conversation, use it.",
8761
+ "- Otherwise ask me what topic I want to recall.",
8762
+ "",
8763
+ "Then:",
8764
+ "- Use `session_recall` with the query (omit IDs unless required).",
8765
+ "- Summarize the key points and any relevant decisions/lessons."
8766
+ ].join("\n")
8523
8767
  }
8524
8768
  }
8525
8769
  ]
@@ -8528,26 +8772,25 @@ Then summarize the key points and any relevant decisions/lessons.`
8528
8772
  server.registerPrompt(
8529
8773
  "session-summary",
8530
8774
  {
8531
- title: "Session Summary",
8532
- description: "Get a compact summary of workspace/project context",
8533
- argsSchema: {
8534
- workspace_id: external_exports.string().uuid().optional().describe("Workspace ID (optional)"),
8535
- project_id: external_exports.string().uuid().optional().describe("Project ID (optional)"),
8536
- max_tokens: external_exports.string().optional().describe("Max tokens for summary (default: 500)")
8537
- }
8775
+ title: `Session Summary (${promptAccessLabel("session-summary")})`,
8776
+ description: "Get a compact summary of workspace/project context"
8538
8777
  },
8539
- async (args) => ({
8778
+ async () => ({
8540
8779
  messages: [
8541
8780
  {
8542
8781
  role: "user",
8543
8782
  content: {
8544
8783
  type: "text",
8545
- text: `Generate a compact, token-efficient summary of the current workspace/project context.
8546
-
8547
- If workspace_id/project_id are not provided, call \`session_init\` first to resolve the current workspace/project.
8548
-
8549
- Use \`session_summary\`${args.workspace_id ? ` with workspace_id "${args.workspace_id}"` : ""}${args.project_id ? ` and project_id "${args.project_id}"` : ""}${args.max_tokens ? ` and max_tokens ${args.max_tokens} (number)` : ""}.
8550
- Then list the top decisions (titles only) and any high-priority lessons to watch for.`
8784
+ text: [
8785
+ "Generate a compact, token-efficient summary of the current workspace/project context.",
8786
+ "",
8787
+ ...ID_NOTES,
8788
+ "",
8789
+ "Use `session_summary` (default max_tokens=500 unless I specify otherwise).",
8790
+ "Then list:",
8791
+ "- Top decisions (titles only)",
8792
+ "- Any high-priority lessons to watch for"
8793
+ ].join("\n")
8551
8794
  }
8552
8795
  }
8553
8796
  ]
@@ -8556,39 +8799,31 @@ Then list the top decisions (titles only) and any high-priority lessons to watch
8556
8799
  server.registerPrompt(
8557
8800
  "capture-lesson",
8558
8801
  {
8559
- title: "Capture Lesson",
8560
- description: "Record a lesson learned from an error or correction",
8561
- argsSchema: {
8562
- workspace_id: external_exports.string().uuid().optional().describe("Workspace ID (optional)"),
8563
- project_id: external_exports.string().uuid().optional().describe("Project ID (optional)"),
8564
- title: external_exports.string().describe("Lesson title (what to remember)"),
8565
- severity: external_exports.string().optional().describe("low|medium|high|critical (default: medium)"),
8566
- category: external_exports.string().describe("workflow|code_quality|verification|communication|project_specific"),
8567
- trigger: external_exports.string().describe("What action caused the problem"),
8568
- impact: external_exports.string().describe("What went wrong"),
8569
- prevention: external_exports.string().describe("How to prevent in future"),
8570
- keywords: external_exports.string().optional().describe("Comma-separated keywords (optional)")
8571
- }
8802
+ title: `Capture Lesson (${promptAccessLabel("capture-lesson")})`,
8803
+ description: "Record a lesson learned from an error or correction"
8572
8804
  },
8573
- async (args) => ({
8805
+ async () => ({
8574
8806
  messages: [
8575
8807
  {
8576
8808
  role: "user",
8577
8809
  content: {
8578
8810
  type: "text",
8579
- text: `Capture this lesson so it is surfaced in future sessions:
8580
-
8581
- Title: ${args.title}
8582
- Severity: ${args.severity || "medium"}
8583
- Category: ${args.category}
8584
- Trigger: ${args.trigger}
8585
- Impact: ${args.impact}
8586
- Prevention: ${args.prevention}
8587
- ${args.keywords ? `Keywords: ${args.keywords}` : ""}
8588
-
8589
- If workspace_id/project_id are not provided, call \`session_init\` first to resolve the current workspace/project.
8590
-
8591
- Use \`session_capture_lesson\` with the fields above. If keywords were provided, split the comma-separated list into an array of strings.`
8811
+ text: [
8812
+ "Capture a lesson learned so it is surfaced in future sessions.",
8813
+ "",
8814
+ ...ID_NOTES,
8815
+ "",
8816
+ "If the lesson details are not fully present in the conversation, ask me for:",
8817
+ "- title (what to remember)",
8818
+ "- severity (low|medium|high|critical, default medium)",
8819
+ "- category (workflow|code_quality|verification|communication|project_specific)",
8820
+ "- trigger (what caused it)",
8821
+ "- impact (what went wrong)",
8822
+ "- prevention (how to prevent it)",
8823
+ "- keywords (optional)",
8824
+ "",
8825
+ "Then call `session_capture_lesson` with those fields and confirm it was saved."
8826
+ ].join("\n")
8592
8827
  }
8593
8828
  }
8594
8829
  ]
@@ -8597,33 +8832,28 @@ Use \`session_capture_lesson\` with the fields above. If keywords were provided,
8597
8832
  server.registerPrompt(
8598
8833
  "capture-preference",
8599
8834
  {
8600
- title: "Capture Preference",
8601
- description: "Save a user preference to memory",
8602
- argsSchema: {
8603
- workspace_id: external_exports.string().uuid().optional().describe("Workspace ID (optional)"),
8604
- project_id: external_exports.string().uuid().optional().describe("Project ID (optional)"),
8605
- title: external_exports.string().optional().describe("Preference title (optional)"),
8606
- preference: external_exports.string().describe("Preference details to remember")
8607
- }
8835
+ title: `Capture Preference (${promptAccessLabel("capture-preference")})`,
8836
+ description: "Save a user preference to memory"
8608
8837
  },
8609
- async (args) => ({
8838
+ async () => ({
8610
8839
  messages: [
8611
8840
  {
8612
8841
  role: "user",
8613
8842
  content: {
8614
8843
  type: "text",
8615
- text: `Save this preference to memory:
8616
-
8617
- ${args.title ? `Title: ${args.title}
8618
- ` : ""}Preference: ${args.preference}
8619
-
8620
- If workspace_id/project_id are not provided, call \`session_init\` first to resolve the current workspace/project.
8621
-
8622
- Use \`session_capture\` with:
8623
- - event_type: "preference"
8624
- - title: ${args.title ? `"${args.title}"` : "(choose a short title)"}
8625
- - content: "${args.preference}"
8626
- - importance: "medium"`
8844
+ text: [
8845
+ "Save a user preference to ContextStream memory.",
8846
+ "",
8847
+ ...ID_NOTES,
8848
+ "",
8849
+ "If the preference is not explicit in the conversation, ask me what to remember.",
8850
+ "",
8851
+ "Then call `session_capture` with:",
8852
+ '- event_type: "preference"',
8853
+ "- title: (short title)",
8854
+ "- content: (preference text)",
8855
+ '- importance: "medium"'
8856
+ ].join("\n")
8627
8857
  }
8628
8858
  }
8629
8859
  ]
@@ -8632,33 +8862,28 @@ Use \`session_capture\` with:
8632
8862
  server.registerPrompt(
8633
8863
  "capture-task",
8634
8864
  {
8635
- title: "Capture Task",
8636
- description: "Capture an action item into memory",
8637
- argsSchema: {
8638
- workspace_id: external_exports.string().uuid().optional().describe("Workspace ID (optional)"),
8639
- project_id: external_exports.string().uuid().optional().describe("Project ID (optional)"),
8640
- title: external_exports.string().optional().describe("Task title (optional)"),
8641
- task: external_exports.string().describe("Task details")
8642
- }
8865
+ title: `Capture Task (${promptAccessLabel("capture-task")})`,
8866
+ description: "Capture an action item into memory"
8643
8867
  },
8644
- async (args) => ({
8868
+ async () => ({
8645
8869
  messages: [
8646
8870
  {
8647
8871
  role: "user",
8648
8872
  content: {
8649
8873
  type: "text",
8650
- text: `Capture this task in memory for tracking:
8651
-
8652
- ${args.title ? `Title: ${args.title}
8653
- ` : ""}Task: ${args.task}
8654
-
8655
- If workspace_id/project_id are not provided, call \`session_init\` first to resolve the current workspace/project.
8656
-
8657
- Use \`session_capture\` with:
8658
- - event_type: "task"
8659
- - title: ${args.title ? `"${args.title}"` : "(choose a short title)"}
8660
- - content: "${args.task}"
8661
- - importance: "medium"`
8874
+ text: [
8875
+ "Capture an action item into ContextStream memory.",
8876
+ "",
8877
+ ...ID_NOTES,
8878
+ "",
8879
+ "If the task is not explicit in the conversation, ask me what to capture.",
8880
+ "",
8881
+ "Then call `session_capture` with:",
8882
+ '- event_type: "task"',
8883
+ "- title: (short title)",
8884
+ "- content: (task details)",
8885
+ '- importance: "medium"'
8886
+ ].join("\n")
8662
8887
  }
8663
8888
  }
8664
8889
  ]
@@ -8667,44 +8892,34 @@ Use \`session_capture\` with:
8667
8892
  server.registerPrompt(
8668
8893
  "capture-bug",
8669
8894
  {
8670
- title: "Capture Bug",
8671
- description: "Capture a bug report into workspace memory",
8672
- argsSchema: {
8673
- workspace_id: external_exports.string().uuid().optional().describe("Workspace ID (optional)"),
8674
- project_id: external_exports.string().uuid().optional().describe("Project ID (optional)"),
8675
- title: external_exports.string().describe("Bug title"),
8676
- description: external_exports.string().describe("Bug description"),
8677
- reproduction_steps: external_exports.string().optional().describe("Steps to reproduce (optional)"),
8678
- expected: external_exports.string().optional().describe("Expected behavior (optional)"),
8679
- actual: external_exports.string().optional().describe("Actual behavior (optional)")
8680
- }
8895
+ title: `Capture Bug (${promptAccessLabel("capture-bug")})`,
8896
+ description: "Capture a bug report into workspace memory"
8681
8897
  },
8682
- async (args) => ({
8898
+ async () => ({
8683
8899
  messages: [
8684
8900
  {
8685
8901
  role: "user",
8686
8902
  content: {
8687
8903
  type: "text",
8688
- text: `Capture this bug report in memory:
8689
-
8690
- Title: ${args.title}
8691
- Description: ${args.description}
8692
- ${args.reproduction_steps ? `Steps to reproduce:
8693
- ${args.reproduction_steps}
8694
- ` : ""}${args.expected ? `Expected:
8695
- ${args.expected}
8696
- ` : ""}${args.actual ? `Actual:
8697
- ${args.actual}
8698
- ` : ""}
8699
-
8700
- If workspace_id/project_id are not provided, call \`session_init\` first to resolve the current workspace/project.
8701
-
8702
- Use \`session_capture\` with:
8703
- - event_type: "bug"
8704
- - title: "${args.title}"
8705
- - content: A well-formatted bug report with the details above
8706
- - tags: include relevant component/area tags
8707
- - importance: "high"`
8904
+ text: [
8905
+ "Capture a bug report in ContextStream memory.",
8906
+ "",
8907
+ ...ID_NOTES,
8908
+ "",
8909
+ "If details are missing, ask me for:",
8910
+ "- title",
8911
+ "- description",
8912
+ "- steps to reproduce (optional)",
8913
+ "- expected behavior (optional)",
8914
+ "- actual behavior (optional)",
8915
+ "",
8916
+ "Then call `session_capture` with:",
8917
+ '- event_type: "bug"',
8918
+ "- title: (bug title)",
8919
+ "- content: a well-formatted bug report (include all provided details)",
8920
+ "- tags: component/area tags",
8921
+ '- importance: "high"'
8922
+ ].join("\n")
8708
8923
  }
8709
8924
  }
8710
8925
  ]
@@ -8713,41 +8928,33 @@ Use \`session_capture\` with:
8713
8928
  server.registerPrompt(
8714
8929
  "capture-feature",
8715
8930
  {
8716
- title: "Capture Feature",
8717
- description: "Capture a feature request into workspace memory",
8718
- argsSchema: {
8719
- workspace_id: external_exports.string().uuid().optional().describe("Workspace ID (optional)"),
8720
- project_id: external_exports.string().uuid().optional().describe("Project ID (optional)"),
8721
- title: external_exports.string().describe("Feature title"),
8722
- description: external_exports.string().describe("Feature description"),
8723
- rationale: external_exports.string().optional().describe("Why this matters (optional)"),
8724
- acceptance_criteria: external_exports.string().optional().describe("Acceptance criteria (optional)")
8725
- }
8931
+ title: `Capture Feature (${promptAccessLabel("capture-feature")})`,
8932
+ description: "Capture a feature request into workspace memory"
8726
8933
  },
8727
- async (args) => ({
8934
+ async () => ({
8728
8935
  messages: [
8729
8936
  {
8730
8937
  role: "user",
8731
8938
  content: {
8732
8939
  type: "text",
8733
- text: `Capture this feature request in memory:
8734
-
8735
- Title: ${args.title}
8736
- Description: ${args.description}
8737
- ${args.rationale ? `Rationale:
8738
- ${args.rationale}
8739
- ` : ""}${args.acceptance_criteria ? `Acceptance criteria:
8740
- ${args.acceptance_criteria}
8741
- ` : ""}
8742
-
8743
- If workspace_id/project_id are not provided, call \`session_init\` first to resolve the current workspace/project.
8744
-
8745
- Use \`session_capture\` with:
8746
- - event_type: "feature"
8747
- - title: "${args.title}"
8748
- - content: A well-formatted feature request with the details above
8749
- - tags: include relevant component/area tags
8750
- - importance: "medium"`
8940
+ text: [
8941
+ "Capture a feature request in ContextStream memory.",
8942
+ "",
8943
+ ...ID_NOTES,
8944
+ "",
8945
+ "If details are missing, ask me for:",
8946
+ "- title",
8947
+ "- description",
8948
+ "- rationale (optional)",
8949
+ "- acceptance criteria (optional)",
8950
+ "",
8951
+ "Then call `session_capture` with:",
8952
+ '- event_type: "feature"',
8953
+ "- title: (feature title)",
8954
+ "- content: a well-formatted feature request",
8955
+ "- tags: component/area tags",
8956
+ '- importance: "medium"'
8957
+ ].join("\n")
8751
8958
  }
8752
8959
  }
8753
8960
  ]
@@ -8756,30 +8963,26 @@ Use \`session_capture\` with:
8756
8963
  server.registerPrompt(
8757
8964
  "generate-plan",
8758
8965
  {
8759
- title: "Generate Plan",
8760
- description: "Generate a development plan from a description",
8761
- argsSchema: {
8762
- description: external_exports.string().describe("What you want to build/fix"),
8763
- project_id: external_exports.string().uuid().optional().describe("Project ID (optional)"),
8764
- complexity: external_exports.string().optional().describe("low|medium|high (optional)")
8765
- }
8966
+ title: `Generate Plan (${promptAccessLabel("generate-plan")})`,
8967
+ description: "Generate a development plan from a description"
8766
8968
  },
8767
- async (args) => ({
8969
+ async () => ({
8768
8970
  messages: [
8769
8971
  {
8770
8972
  role: "user",
8771
8973
  content: {
8772
8974
  type: "text",
8773
- text: `Generate a development plan for:
8774
-
8775
- ${args.description}
8776
-
8777
- Use \`ai_plan\` with:
8778
- - description: "${args.description}"
8779
- ${args.project_id ? `- project_id: "${args.project_id}"` : ""}
8780
- ${args.complexity ? `- complexity: "${args.complexity}"` : ""}
8781
-
8782
- Then present the plan as a concise ordered list with clear milestones and risks.`
8975
+ text: [
8976
+ "Generate a development plan for what I am trying to build/fix.",
8977
+ "",
8978
+ `Access: ${promptAccessLabel("generate-plan")}${promptAccessLabel("generate-plan") === "PRO" ? ` (upgrade: ${upgradeUrl})` : ""}`,
8979
+ "",
8980
+ ...ID_NOTES,
8981
+ "",
8982
+ "Use the most recent user request as the plan description. If unclear, ask me for a one-paragraph description.",
8983
+ "",
8984
+ "Then call `ai_plan` and present the plan as an ordered list with milestones and risks."
8985
+ ].join("\n")
8783
8986
  }
8784
8987
  }
8785
8988
  ]
@@ -8788,31 +8991,27 @@ Then present the plan as a concise ordered list with clear milestones and risks.
8788
8991
  server.registerPrompt(
8789
8992
  "generate-tasks",
8790
8993
  {
8791
- title: "Generate Tasks",
8792
- description: "Generate actionable tasks from a plan or description",
8793
- argsSchema: {
8794
- plan_id: external_exports.string().optional().describe("Plan ID (optional)"),
8795
- description: external_exports.string().optional().describe("Description to generate tasks from (optional if plan_id provided)"),
8796
- project_id: external_exports.string().uuid().optional().describe("Project ID (optional)"),
8797
- granularity: external_exports.string().optional().describe("fine|medium|coarse (optional)")
8798
- }
8994
+ title: `Generate Tasks (${promptAccessLabel("generate-tasks")})`,
8995
+ description: "Generate actionable tasks from a plan or description"
8799
8996
  },
8800
- async (args) => ({
8997
+ async () => ({
8801
8998
  messages: [
8802
8999
  {
8803
9000
  role: "user",
8804
9001
  content: {
8805
9002
  type: "text",
8806
- text: `Generate actionable tasks.
8807
-
8808
- ${args.plan_id ? `Use plan_id: ${args.plan_id}` : ""}${!args.plan_id && args.description ? `Use description: ${args.description}` : ""}
8809
-
8810
- Use \`ai_tasks\` with:
8811
- ${args.plan_id ? `- plan_id: "${args.plan_id}"` : ""}${!args.plan_id && args.description ? `- description: "${args.description}"` : ""}
8812
- ${args.project_id ? `- project_id: "${args.project_id}"` : ""}
8813
- ${args.granularity ? `- granularity: "${args.granularity}"` : ""}
8814
-
8815
- Then output a checklist of tasks with clear acceptance criteria for each.`
9003
+ text: [
9004
+ "Generate actionable tasks for the work we are discussing.",
9005
+ "",
9006
+ `Access: ${promptAccessLabel("generate-tasks")}${promptAccessLabel("generate-tasks") === "PRO" ? ` (upgrade: ${upgradeUrl})` : ""}`,
9007
+ "",
9008
+ ...ID_NOTES,
9009
+ "",
9010
+ "If a plan_id exists in the conversation, use it. Otherwise use the latest user request as the description.",
9011
+ "If granularity is not specified, default to medium.",
9012
+ "",
9013
+ "Call `ai_tasks` and return a checklist of tasks with acceptance criteria for each."
9014
+ ].join("\n")
8816
9015
  }
8817
9016
  }
8818
9017
  ]
@@ -8821,35 +9020,28 @@ Then output a checklist of tasks with clear acceptance criteria for each.`
8821
9020
  server.registerPrompt(
8822
9021
  "token-budget-context",
8823
9022
  {
8824
- title: "Token-Budget Context",
8825
- description: "Get the most relevant context that fits within a token budget",
8826
- argsSchema: {
8827
- query: external_exports.string().describe("What you need context for"),
8828
- max_tokens: external_exports.string().describe("Max tokens for context (e.g., 500, 1000, 2000)"),
8829
- workspace_id: external_exports.string().uuid().optional().describe("Workspace ID (optional)"),
8830
- project_id: external_exports.string().uuid().optional().describe("Project ID (optional)"),
8831
- include_code: external_exports.string().optional().describe('Include code ("true" or "false")')
8832
- }
9023
+ title: `Token-Budget Context (${promptAccessLabel("token-budget-context")})`,
9024
+ description: "Get the most relevant context that fits within a token budget"
8833
9025
  },
8834
- async (args) => ({
9026
+ async () => ({
8835
9027
  messages: [
8836
9028
  {
8837
9029
  role: "user",
8838
9030
  content: {
8839
9031
  type: "text",
8840
- text: `Build the most relevant context for:
8841
-
8842
- Query: ${args.query}
8843
- Token budget: ${args.max_tokens}
8844
-
8845
- Use \`ai_context_budget\` with:
8846
- - query: "${args.query}"
8847
- - max_tokens: ${args.max_tokens} (number)
8848
- ${args.workspace_id ? `- workspace_id: "${args.workspace_id}"` : ""}
8849
- ${args.project_id ? `- project_id: "${args.project_id}"` : ""}
8850
- ${args.include_code ? `- include_code: ${args.include_code}` : ""}
8851
-
8852
- Return the packed context plus a short note about what was included/excluded.`
9032
+ text: [
9033
+ "Build the most relevant context that fits within a token budget.",
9034
+ "",
9035
+ `Access: ${promptAccessLabel("token-budget-context")}${promptAccessLabel("token-budget-context") === "PRO" ? ` (upgrade: ${upgradeUrl})` : ""}`,
9036
+ "",
9037
+ ...ID_NOTES,
9038
+ "",
9039
+ "First:",
9040
+ "- If a query is clear from the conversation, use it; otherwise ask me for a query.",
9041
+ "- If max_tokens is not specified, ask me for a token budget (e.g., 500/1000/2000).",
9042
+ "",
9043
+ "Then call `ai_context_budget` and return the packed context plus a short note about what was included/excluded."
9044
+ ].join("\n")
8853
9045
  }
8854
9046
  }
8855
9047
  ]
@@ -8858,25 +9050,23 @@ Return the packed context plus a short note about what was included/excluded.`
8858
9050
  server.registerPrompt(
8859
9051
  "find-todos",
8860
9052
  {
8861
- title: "Find TODOs",
8862
- description: "Scan the codebase for TODO/FIXME/HACK notes and summarize",
8863
- argsSchema: {
8864
- project_id: external_exports.string().uuid().optional().describe("Project ID (optional)"),
8865
- pattern: external_exports.string().optional().describe("Regex/pattern to search (default: TODO|FIXME|HACK)")
8866
- }
9053
+ title: `Find TODOs (${promptAccessLabel("find-todos")})`,
9054
+ description: "Scan the codebase for TODO/FIXME/HACK notes and summarize"
8867
9055
  },
8868
- async (args) => ({
9056
+ async () => ({
8869
9057
  messages: [
8870
9058
  {
8871
9059
  role: "user",
8872
9060
  content: {
8873
9061
  type: "text",
8874
- text: `Find TODO-style notes in the codebase.
8875
-
8876
- If project_id is not provided, first call \`session_init\` (or \`projects_list\`) to resolve the current project ID.
8877
-
8878
- Use \`search_pattern\` with query "${args.pattern || "TODO|FIXME|HACK"}"${args.project_id ? ` and project_id "${args.project_id}"` : ""}.
8879
- Group results by file path, summarize themes, and propose a small prioritized cleanup list.`
9062
+ text: [
9063
+ "Scan the codebase for TODO/FIXME/HACK notes and summarize them.",
9064
+ "",
9065
+ ...ID_NOTES,
9066
+ "",
9067
+ "Use `search_pattern` with query `TODO|FIXME|HACK` (or a pattern inferred from the conversation).",
9068
+ "Group results by file path, summarize themes, and propose a small prioritized cleanup list."
9069
+ ].join("\n")
8880
9070
  }
8881
9071
  }
8882
9072
  ]
@@ -8885,36 +9075,27 @@ Group results by file path, summarize themes, and propose a small prioritized cl
8885
9075
  server.registerPrompt(
8886
9076
  "generate-editor-rules",
8887
9077
  {
8888
- title: "Generate Editor Rules",
8889
- description: "Generate ContextStream AI rule files for your editor",
8890
- argsSchema: {
8891
- folder_path: external_exports.string().describe("Project folder path (ideally absolute)"),
8892
- editors: external_exports.string().optional().describe('Comma-separated editors or "all" (windsurf,cursor,cline,kilo,roo,claude,aider)'),
8893
- workspace_id: external_exports.string().uuid().optional().describe("Workspace ID (optional)"),
8894
- workspace_name: external_exports.string().optional().describe("Workspace name (optional)"),
8895
- project_name: external_exports.string().optional().describe("Project name (optional)"),
8896
- additional_rules: external_exports.string().optional().describe("Additional project-specific rules (optional)"),
8897
- dry_run: external_exports.string().optional().describe('Dry run ("true" or "false", default: false)')
8898
- }
9078
+ title: `Generate Editor Rules (${promptAccessLabel("generate-editor-rules")})`,
9079
+ description: "Generate ContextStream AI rule files for your editor"
8899
9080
  },
8900
- async (args) => ({
9081
+ async () => ({
8901
9082
  messages: [
8902
9083
  {
8903
9084
  role: "user",
8904
9085
  content: {
8905
9086
  type: "text",
8906
- text: `Generate ContextStream editor rule files in: ${args.folder_path}
8907
-
8908
- Use \`generate_editor_rules\` with:
8909
- - folder_path: "${args.folder_path}"
8910
- ${args.editors ? `- editors: "${args.editors}"` : ""}
8911
- ${args.workspace_id ? `- workspace_id: "${args.workspace_id}"` : ""}
8912
- ${args.workspace_name ? `- workspace_name: "${args.workspace_name}"` : ""}
8913
- ${args.project_name ? `- project_name: "${args.project_name}"` : ""}
8914
- ${args.additional_rules ? `- additional_rules: "${args.additional_rules}"` : ""}
8915
- ${args.dry_run ? `- dry_run: ${args.dry_run}` : ""}
8916
-
8917
- If editors is provided as a comma-separated string, split it into an array (or use ["all"] to generate for all editors). If dry_run is provided as a string, convert to boolean.`
9087
+ text: [
9088
+ "Generate ContextStream AI rule files for my editor.",
9089
+ "",
9090
+ ...ID_NOTES,
9091
+ "",
9092
+ "First:",
9093
+ "- If you can infer the project folder path from the environment/IDE roots, use it.",
9094
+ "- Otherwise ask me for an absolute folder path.",
9095
+ "- Ask which editor(s) (windsurf,cursor,cline,kilo,roo,claude,aider) or default to all.",
9096
+ "",
9097
+ "Then call `generate_editor_rules` and confirm which files were created/updated."
9098
+ ].join("\n")
8918
9099
  }
8919
9100
  }
8920
9101
  ]
@@ -8923,30 +9104,27 @@ If editors is provided as a comma-separated string, split it into an array (or u
8923
9104
  server.registerPrompt(
8924
9105
  "index-local-repo",
8925
9106
  {
8926
- title: "Index Local Repo",
8927
- description: "Ingest local files into ContextStream for indexing/search",
8928
- argsSchema: {
8929
- project_id: external_exports.string().uuid().optional().describe("Project ID (optional if session_init has set defaults)"),
8930
- path: external_exports.string().describe("Local directory path to ingest")
8931
- }
9107
+ title: `Index Local Repo (${promptAccessLabel("index-local-repo")})`,
9108
+ description: "Ingest local files into ContextStream for indexing/search"
8932
9109
  },
8933
- async (args) => ({
9110
+ async () => ({
8934
9111
  messages: [
8935
9112
  {
8936
9113
  role: "user",
8937
9114
  content: {
8938
9115
  type: "text",
8939
- text: `Ingest local files for indexing/search.
8940
-
8941
- Path: ${args.path}
8942
-
8943
- If project_id is not provided, call \`session_init\` first and use the resolved project_id (or use \`projects_list\` to select).
8944
-
8945
- Use \`projects_ingest_local\` with:
8946
- - project_id: ${args.project_id ? `"${args.project_id}"` : "(resolved from session_init)"}
8947
- - path: "${args.path}"
8948
-
8949
- Then advise how to monitor progress via \`projects_index_status\`.`
9116
+ text: [
9117
+ "Ingest local files into ContextStream for indexing/search.",
9118
+ "",
9119
+ ...ID_NOTES,
9120
+ "",
9121
+ "First:",
9122
+ "- Ask me for the local directory path to ingest if it is not already specified.",
9123
+ "",
9124
+ "Then:",
9125
+ "- Call `projects_ingest_local` with the path (use session defaults for project, or the `project_id` returned by `session_init`).",
9126
+ "- Explain how to monitor progress via `projects_index_status`."
9127
+ ].join("\n")
8950
9128
  }
8951
9129
  }
8952
9130
  ]
@@ -9127,6 +9305,25 @@ var SessionManager = class {
9127
9305
  parts.push("\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550");
9128
9306
  parts.push("\u{1F9E0} AUTO-CONTEXT LOADED (ContextStream)");
9129
9307
  parts.push("\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550");
9308
+ if (context.status === "requires_workspace_name") {
9309
+ parts.push("");
9310
+ parts.push("\u26A0\uFE0F NO WORKSPACE FOUND");
9311
+ parts.push(`Folder: ${context.folder_name || "unknown"}`);
9312
+ parts.push("");
9313
+ parts.push("Please ask the user for a name for the new workspace.");
9314
+ parts.push("Then create a project for this folder.");
9315
+ parts.push("");
9316
+ parts.push("Recommended: call `workspace_bootstrap` with:");
9317
+ if (typeof context.folder_path === "string") {
9318
+ parts.push(` - folder_path: ${context.folder_path}`);
9319
+ } else {
9320
+ parts.push(" - folder_path: (your repo folder path)");
9321
+ }
9322
+ parts.push(' - workspace_name: "<user-provided name>"');
9323
+ parts.push("");
9324
+ parts.push("\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550");
9325
+ return parts.join("\n");
9326
+ }
9130
9327
  if (context.status === "requires_workspace_selection") {
9131
9328
  parts.push("");
9132
9329
  parts.push("\u26A0\uFE0F NEW FOLDER DETECTED");
@@ -9260,6 +9457,8 @@ Environment variables:
9260
9457
  CONTEXTSTREAM_JWT JWT for authentication (alternative to API key)
9261
9458
  CONTEXTSTREAM_WORKSPACE_ID Optional default workspace ID
9262
9459
  CONTEXTSTREAM_PROJECT_ID Optional default project ID
9460
+ CONTEXTSTREAM_PRO_TOOLS Optional comma-separated PRO tool names (default: AI tools)
9461
+ CONTEXTSTREAM_UPGRADE_URL Optional upgrade URL shown for PRO tools on Free plan
9263
9462
 
9264
9463
  Examples:
9265
9464
  CONTEXTSTREAM_API_URL="https://api.contextstream.io" \\