@schoolai/shipyard-mcp 0.2.2-next.482 → 0.2.2-next.485

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.
@@ -28494,7 +28494,7 @@ init_cjs_shims();
28494
28494
  // ../../packages/schema/dist/index.mjs
28495
28495
  init_cjs_shims();
28496
28496
 
28497
- // ../../packages/schema/dist/yjs-helpers-BBG4tC2R.mjs
28497
+ // ../../packages/schema/dist/yjs-helpers-A0hIPiRs.mjs
28498
28498
  init_cjs_shims();
28499
28499
 
28500
28500
  // ../../packages/schema/dist/plan.mjs
@@ -42552,7 +42552,8 @@ var PlanEventSchema = external_exports.discriminatedUnion("type", [
42552
42552
  PlanEventBaseSchema.extend({
42553
42553
  type: external_exports.literal("agent_activity"),
42554
42554
  data: AgentActivityDataSchema
42555
- })
42555
+ }),
42556
+ PlanEventBaseSchema.extend({ type: external_exports.literal("session_token_regenerated") })
42556
42557
  ]);
42557
42558
  var PlanMetadataBaseSchema = external_exports.object({
42558
42559
  id: external_exports.string(),
@@ -42665,7 +42666,7 @@ var PRReviewCommentSchema = external_exports.object({
42665
42666
  resolved: external_exports.boolean().optional()
42666
42667
  });
42667
42668
 
42668
- // ../../packages/schema/dist/yjs-helpers-BBG4tC2R.mjs
42669
+ // ../../packages/schema/dist/yjs-helpers-A0hIPiRs.mjs
42669
42670
  function assertNever2(value) {
42670
42671
  throw new Error(`Unhandled discriminated union member: ${JSON.stringify(value)}`);
42671
42672
  }
@@ -552,7 +552,8 @@ var PlanEventTypes = [
552
552
  "input_request_created",
553
553
  "input_request_answered",
554
554
  "input_request_declined",
555
- "agent_activity"
555
+ "agent_activity",
556
+ "session_token_regenerated"
556
557
  ];
557
558
  var AgentActivityTypes = [
558
559
  "help_request",
@@ -701,7 +702,8 @@ var PlanEventSchema = z.discriminatedUnion("type", [
701
702
  PlanEventBaseSchema.extend({
702
703
  type: z.literal("agent_activity"),
703
704
  data: AgentActivityDataSchema
704
- })
705
+ }),
706
+ PlanEventBaseSchema.extend({ type: z.literal("session_token_regenerated") })
705
707
  ]);
706
708
  function isInboxWorthy(event, username, ownerId) {
707
709
  if (!event.inboxWorthy) return false;
@@ -863,7 +865,7 @@ function createHandedOffConversationVersion(params) {
863
865
  return ConversationVersionSchema.parse(version);
864
866
  }
865
867
 
866
- // ../../packages/schema/dist/yjs-helpers-BBG4tC2R.mjs
868
+ // ../../packages/schema/dist/yjs-helpers-A0hIPiRs.mjs
867
869
  import { z as z2 } from "zod";
868
870
  import { nanoid as nanoid2 } from "nanoid";
869
871
  import * as Y from "yjs";
@@ -1753,6 +1755,27 @@ function declineInputRequest(ydoc, requestId) {
1753
1755
  });
1754
1756
  return { success: true };
1755
1757
  }
1758
+ function atomicRegenerateTokenIfOwner(ydoc, expectedOwnerId, newTokenHash, actor) {
1759
+ let result = {
1760
+ success: false,
1761
+ actualOwner: void 0
1762
+ };
1763
+ ydoc.transact(() => {
1764
+ const map = ydoc.getMap(YDOC_KEYS.METADATA);
1765
+ const currentOwner = map.get("ownerId");
1766
+ if (currentOwner !== expectedOwnerId) {
1767
+ result = {
1768
+ success: false,
1769
+ actualOwner: currentOwner
1770
+ };
1771
+ return;
1772
+ }
1773
+ map.set("sessionTokenHash", newTokenHash);
1774
+ map.set("updatedAt", Date.now());
1775
+ result = { success: true };
1776
+ }, actor ? { actor } : void 0);
1777
+ return result;
1778
+ }
1756
1779
 
1757
1780
  // ../../packages/schema/dist/url-encoding.mjs
1758
1781
  var import_lz_string = __toESM(require_lz_string(), 1);
@@ -2896,6 +2919,7 @@ export {
2896
2919
  answerInputRequest,
2897
2920
  cancelInputRequest,
2898
2921
  declineInputRequest,
2922
+ atomicRegenerateTokenIfOwner,
2899
2923
  isUrlEncodedPlanV1,
2900
2924
  isUrlEncodedPlanV2,
2901
2925
  encodePlan,
@@ -3,7 +3,7 @@ import {
3
3
  YDOC_KEYS,
4
4
  createInputRequest,
5
5
  logPlanEvent
6
- } from "./chunk-76JWRTPI.js";
6
+ } from "./chunk-BBYZISY2.js";
7
7
  import {
8
8
  logger
9
9
  } from "./chunk-GSGLHRWX.js";
@@ -152,6 +152,34 @@ function getUsernameFromGitConfig() {
152
152
  return null;
153
153
  }
154
154
  }
155
+ async function getVerifiedGitHubUsername() {
156
+ if (githubConfig.GITHUB_USERNAME) {
157
+ logger.info({ username: githubConfig.GITHUB_USERNAME }, "Using GITHUB_USERNAME from env");
158
+ return githubConfig.GITHUB_USERNAME;
159
+ }
160
+ if (githubConfig.GITHUB_TOKEN) {
161
+ try {
162
+ const username = await getUsernameFromToken(githubConfig.GITHUB_TOKEN);
163
+ if (username) {
164
+ logger.info({ username }, "Got verified username from GITHUB_TOKEN");
165
+ return username;
166
+ }
167
+ } catch (error) {
168
+ logger.warn({ error }, "Failed to get username from GITHUB_TOKEN");
169
+ }
170
+ }
171
+ try {
172
+ const username = getUsernameFromCLI();
173
+ if (username) {
174
+ logger.info({ username }, "Got verified username from gh CLI");
175
+ return username;
176
+ }
177
+ } catch (error) {
178
+ logger.debug({ error }, "Failed to get username from gh CLI");
179
+ }
180
+ logger.warn("No verified GitHub authentication available");
181
+ return null;
182
+ }
155
183
  function getGitBranch() {
156
184
  try {
157
185
  return execSync2("git branch --show-current", {
@@ -176,5 +204,6 @@ export {
176
204
  githubConfig,
177
205
  getRepositoryFullName,
178
206
  getGitHubUsername,
207
+ getVerifiedGitHubUsername,
179
208
  getEnvironmentContext
180
209
  };
@@ -92,6 +92,7 @@ import {
92
92
  asWebRTCPeerId,
93
93
  assertNever,
94
94
  assertNeverP2PMessage,
95
+ atomicRegenerateTokenIfOwner,
95
96
  buildInviteUrl,
96
97
  cancelInputRequest,
97
98
  claudeCodeToA2A,
@@ -204,7 +205,7 @@ import {
204
205
  updateLinkedPRStatus,
205
206
  updatePlanIndexViewedBy,
206
207
  validateA2AMessages
207
- } from "./chunk-76JWRTPI.js";
208
+ } from "./chunk-BBYZISY2.js";
208
209
  import "./chunk-JSBRDJBE.js";
209
210
  export {
210
211
  A2ADataPartSchema,
@@ -300,6 +301,7 @@ export {
300
301
  asWebRTCPeerId,
301
302
  assertNever,
302
303
  assertNeverP2PMessage,
304
+ atomicRegenerateTokenIfOwner,
303
305
  buildInviteUrl,
304
306
  cancelInputRequest,
305
307
  claudeCodeToA2A,
@@ -3,8 +3,9 @@ import {
3
3
  getEnvironmentContext,
4
4
  getGitHubUsername,
5
5
  getRepositoryFullName,
6
+ getVerifiedGitHubUsername,
6
7
  githubConfig
7
- } from "./chunk-E5DWX2WU.js";
8
+ } from "./chunk-OLFHVNPI.js";
8
9
  import {
9
10
  assertNever,
10
11
  getSessionIdByPlanId,
@@ -19,7 +20,7 @@ import {
19
20
  } from "./chunk-EBNL5ZX7.js";
20
21
  import {
21
22
  InputRequestManager
22
- } from "./chunk-BWP37ADP.js";
23
+ } from "./chunk-NH6GXGQO.js";
23
24
  import {
24
25
  ArtifactSchema,
25
26
  DeliverableSchema,
@@ -40,6 +41,7 @@ import {
40
41
  addPRReviewComment,
41
42
  addSnapshot,
42
43
  appRouter,
44
+ atomicRegenerateTokenIfOwner,
43
45
  createInitialConversationVersion,
44
46
  createLinkedPR,
45
47
  createPlanSnapshot,
@@ -69,7 +71,7 @@ import {
69
71
  setPlanMetadata,
70
72
  touchPlanIndexEntry,
71
73
  transitionPlanStatus
72
- } from "./chunk-76JWRTPI.js";
74
+ } from "./chunk-BBYZISY2.js";
73
75
  import {
74
76
  loadEnv,
75
77
  logger
@@ -2472,7 +2474,7 @@ import * as os from "os";
2472
2474
  import * as path from "path";
2473
2475
  import * as vm from "vm";
2474
2476
  import ffmpegInstaller from "@ffmpeg-installer/ffmpeg";
2475
- import { z as z12 } from "zod";
2477
+ import { z as z13 } from "zod";
2476
2478
 
2477
2479
  // src/tools/add-artifact.ts
2478
2480
  import { execSync } from "child_process";
@@ -2538,6 +2540,7 @@ var TOOL_NAMES = {
2538
2540
  EXECUTE_CODE: "execute_code",
2539
2541
  LINK_PR: "link_pr",
2540
2542
  READ_PLAN: "read_plan",
2543
+ REGENERATE_SESSION_TOKEN: "regenerate_session_token",
2541
2544
  REQUEST_USER_INPUT: "request_user_input",
2542
2545
  SETUP_REVIEW_NOTIFICATION: "setup_review_notification",
2543
2546
  UPDATE_BLOCK_CONTENT: "update_block_content",
@@ -4136,11 +4139,146 @@ OUTPUT INCLUDES:
4136
4139
  }
4137
4140
  };
4138
4141
 
4139
- // src/tools/setup-review-notification.ts
4142
+ // src/tools/regenerate-session-token.ts
4140
4143
  import { z as z9 } from "zod";
4141
- var SetupReviewNotificationInput = z9.object({
4142
- planId: z9.string().describe("Plan ID to monitor"),
4143
- pollIntervalSeconds: z9.number().optional().default(30).describe("Polling interval in seconds (default: 30)")
4144
+ var RegenerateSessionTokenInput = z9.object({
4145
+ planId: z9.string().describe("The plan ID to regenerate token for")
4146
+ });
4147
+ var regenerateSessionTokenTool = {
4148
+ definition: {
4149
+ name: TOOL_NAMES.REGENERATE_SESSION_TOKEN,
4150
+ description: `Regenerate the session token for a plan.
4151
+
4152
+ USE WHEN:
4153
+ - Your Claude Code session ended and you lost the original token
4154
+ - You need to resume work on a plan you own
4155
+ - The old token may have been compromised
4156
+
4157
+ REQUIREMENTS:
4158
+ - You must be the plan owner (verified via GitHub identity)
4159
+ - The plan must exist and have an ownerId set
4160
+
4161
+ RETURNS:
4162
+ - New session token that can be used for add_artifact, read_plan, etc.
4163
+
4164
+ SECURITY:
4165
+ - Only the plan owner can regenerate tokens
4166
+ - Old token is immediately invalidated
4167
+ - New token is returned only once - store it securely`,
4168
+ inputSchema: {
4169
+ type: "object",
4170
+ properties: {
4171
+ planId: { type: "string", description: "The plan ID to regenerate token for" }
4172
+ },
4173
+ required: ["planId"]
4174
+ }
4175
+ },
4176
+ handler: async (args) => {
4177
+ const { planId } = RegenerateSessionTokenInput.parse(args);
4178
+ logger.info({ planId }, "Attempting to regenerate session token");
4179
+ const currentUser = await getVerifiedGitHubUsername();
4180
+ if (!currentUser) {
4181
+ return {
4182
+ content: [
4183
+ {
4184
+ type: "text",
4185
+ text: `Token regeneration requires verified GitHub authentication.
4186
+
4187
+ Please configure ONE of:
4188
+ 1. GITHUB_USERNAME environment variable
4189
+ 2. GITHUB_TOKEN environment variable (will verify via API)
4190
+ 3. Run: gh auth login
4191
+
4192
+ Note: git config user.name is NOT accepted for security-critical operations.`
4193
+ }
4194
+ ],
4195
+ isError: true
4196
+ };
4197
+ }
4198
+ const doc = await getOrCreateDoc3(planId);
4199
+ const metadata = getPlanMetadata(doc);
4200
+ if (!metadata) {
4201
+ return {
4202
+ content: [{ type: "text", text: `Plan "${planId}" not found.` }],
4203
+ isError: true
4204
+ };
4205
+ }
4206
+ if (!metadata.ownerId) {
4207
+ return {
4208
+ content: [
4209
+ {
4210
+ type: "text",
4211
+ text: `Plan "${planId}" has no owner set. Cannot regenerate token for ownerless plans.`
4212
+ }
4213
+ ],
4214
+ isError: true
4215
+ };
4216
+ }
4217
+ const newToken = generateSessionToken();
4218
+ const newTokenHash = hashSessionToken(newToken);
4219
+ const updateResult = atomicRegenerateTokenIfOwner(
4220
+ doc,
4221
+ metadata.ownerId,
4222
+ newTokenHash,
4223
+ currentUser
4224
+ );
4225
+ if (!updateResult.success) {
4226
+ const actualOwner = updateResult.actualOwner;
4227
+ if (actualOwner !== currentUser) {
4228
+ logger.warn(
4229
+ { planId, expectedOwner: metadata.ownerId, actualOwner, currentUser },
4230
+ "Token regeneration denied - ownership changed during operation"
4231
+ );
4232
+ return {
4233
+ content: [
4234
+ {
4235
+ type: "text",
4236
+ text: `Access denied. You do not have permission to regenerate the session token for plan "${planId}".`
4237
+ }
4238
+ ],
4239
+ isError: true
4240
+ };
4241
+ }
4242
+ logger.error(
4243
+ { planId, expectedOwner: metadata.ownerId, actualOwner, currentUser },
4244
+ "Unexpected failure in atomic token regeneration"
4245
+ );
4246
+ return {
4247
+ content: [
4248
+ {
4249
+ type: "text",
4250
+ text: "Token regeneration failed due to an unexpected error. Please try again."
4251
+ }
4252
+ ],
4253
+ isError: true
4254
+ };
4255
+ }
4256
+ logPlanEvent(doc, "session_token_regenerated", currentUser);
4257
+ logger.info({ planId, ownerId: metadata.ownerId }, "Session token regenerated successfully");
4258
+ return {
4259
+ content: [
4260
+ {
4261
+ type: "text",
4262
+ text: `Session token regenerated successfully!
4263
+
4264
+ Plan: ${metadata.title}
4265
+ Plan ID: ${planId}
4266
+
4267
+ New Session Token: ${newToken}
4268
+
4269
+ IMPORTANT: Store this token securely. The old token has been invalidated.
4270
+ Use this token for add_artifact, read_plan, link_pr, and other plan operations.`
4271
+ }
4272
+ ]
4273
+ };
4274
+ }
4275
+ };
4276
+
4277
+ // src/tools/setup-review-notification.ts
4278
+ import { z as z10 } from "zod";
4279
+ var SetupReviewNotificationInput = z10.object({
4280
+ planId: z10.string().describe("Plan ID to monitor"),
4281
+ pollIntervalSeconds: z10.number().optional().default(30).describe("Polling interval in seconds (default: 30)")
4144
4282
  });
4145
4283
  var setupReviewNotificationTool = {
4146
4284
  definition: {
@@ -4258,31 +4396,31 @@ The script:
4258
4396
 
4259
4397
  // src/tools/update-block-content.ts
4260
4398
  import { ServerBlockNoteEditor as ServerBlockNoteEditor6 } from "@blocknote/server-util";
4261
- import { z as z10 } from "zod";
4262
- var BlockOperationSchema = z10.discriminatedUnion("type", [
4263
- z10.object({
4264
- type: z10.literal("update"),
4265
- blockId: z10.string().describe("The block ID to update (from read_plan output)"),
4266
- content: z10.string().describe("New markdown content for this block")
4399
+ import { z as z11 } from "zod";
4400
+ var BlockOperationSchema = z11.discriminatedUnion("type", [
4401
+ z11.object({
4402
+ type: z11.literal("update"),
4403
+ blockId: z11.string().describe("The block ID to update (from read_plan output)"),
4404
+ content: z11.string().describe("New markdown content for this block")
4267
4405
  }),
4268
- z10.object({
4269
- type: z10.literal("insert"),
4270
- afterBlockId: z10.string().nullable().describe("Insert after this block ID (null = insert at beginning)"),
4271
- content: z10.string().describe("Markdown content to insert as new block(s)")
4406
+ z11.object({
4407
+ type: z11.literal("insert"),
4408
+ afterBlockId: z11.string().nullable().describe("Insert after this block ID (null = insert at beginning)"),
4409
+ content: z11.string().describe("Markdown content to insert as new block(s)")
4272
4410
  }),
4273
- z10.object({
4274
- type: z10.literal("delete"),
4275
- blockId: z10.string().describe("The block ID to delete")
4411
+ z11.object({
4412
+ type: z11.literal("delete"),
4413
+ blockId: z11.string().describe("The block ID to delete")
4276
4414
  }),
4277
- z10.object({
4278
- type: z10.literal("replace_all"),
4279
- content: z10.string().describe("Complete markdown content to replace the entire plan")
4415
+ z11.object({
4416
+ type: z11.literal("replace_all"),
4417
+ content: z11.string().describe("Complete markdown content to replace the entire plan")
4280
4418
  })
4281
4419
  ]);
4282
- var UpdateBlockContentInput = z10.object({
4283
- planId: z10.string().describe("The plan ID to modify"),
4284
- sessionToken: z10.string().describe("Session token from create_plan"),
4285
- operations: z10.array(BlockOperationSchema).min(1).describe("Array of operations to perform atomically")
4420
+ var UpdateBlockContentInput = z11.object({
4421
+ planId: z11.string().describe("The plan ID to modify"),
4422
+ sessionToken: z11.string().describe("Session token from create_plan"),
4423
+ operations: z11.array(BlockOperationSchema).min(1).describe("Array of operations to perform atomically")
4286
4424
  });
4287
4425
  var updateBlockContentTool = {
4288
4426
  definition: {
@@ -4544,7 +4682,7 @@ async function applyOperation(blocks, operation, editor) {
4544
4682
  // src/tools/update-plan.ts
4545
4683
  import { ServerBlockNoteEditor as ServerBlockNoteEditor7 } from "@blocknote/server-util";
4546
4684
  import { nanoid as nanoid7 } from "nanoid";
4547
- import { z as z11 } from "zod";
4685
+ import { z as z12 } from "zod";
4548
4686
  function buildStatusTransition(targetStatus, actorName) {
4549
4687
  const now = Date.now();
4550
4688
  switch (targetStatus) {
@@ -4577,12 +4715,12 @@ function buildStatusTransition(targetStatus, actorName) {
4577
4715
  return null;
4578
4716
  }
4579
4717
  }
4580
- var UpdatePlanInput = z11.object({
4581
- planId: z11.string().describe("The plan ID to update"),
4582
- sessionToken: z11.string().describe("Session token from create_plan"),
4583
- title: z11.string().optional().describe("New title"),
4584
- status: z11.enum(["draft", "pending_review", "changes_requested", "in_progress", "completed"]).optional().describe("New status"),
4585
- tags: z11.array(z11.string()).optional().describe("Updated tags (replaces existing tags)")
4718
+ var UpdatePlanInput = z12.object({
4719
+ planId: z12.string().describe("The plan ID to update"),
4720
+ sessionToken: z12.string().describe("Session token from create_plan"),
4721
+ title: z12.string().optional().describe("New title"),
4722
+ status: z12.enum(["draft", "pending_review", "changes_requested", "in_progress", "completed"]).optional().describe("New status"),
4723
+ tags: z12.array(z12.string()).optional().describe("Updated tags (replaces existing tags)")
4586
4724
  });
4587
4725
  var updatePlanTool = {
4588
4726
  definition: {
@@ -5035,6 +5173,46 @@ await resolveActivityRequest({
5035
5173
 
5036
5174
  ---
5037
5175
 
5176
+ ### regenerateSessionToken(planId): Promise<{ sessionToken, planId }>
5177
+ Regenerate the session token for a plan you own.
5178
+
5179
+ USE WHEN:
5180
+ - Your Claude Code session ended and you lost the original token
5181
+ - You need to resume work on a plan from a previous session
5182
+ - The old token may have been compromised
5183
+
5184
+ REQUIREMENTS:
5185
+ - You must be the plan owner (verified via GitHub identity)
5186
+ - The plan must exist and have an ownerId set
5187
+
5188
+ Returns:
5189
+ - sessionToken: New token for API calls
5190
+ - planId: The plan ID
5191
+
5192
+ SECURITY:
5193
+ - Only the plan owner can regenerate tokens
5194
+ - Old token is immediately invalidated
5195
+ - GitHub identity verification happens on MCP server (via gh auth login)
5196
+
5197
+ Example:
5198
+ \`\`\`typescript
5199
+ // Lost your session token? Regenerate it:
5200
+ const { sessionToken, planId } = await regenerateSessionToken("abc123");
5201
+
5202
+ // Now use the new token for operations
5203
+ await addArtifact({
5204
+ planId,
5205
+ sessionToken,
5206
+ type: 'screenshot',
5207
+ filename: 'screenshot.png',
5208
+ source: 'file',
5209
+ filePath: '/tmp/screenshot.png',
5210
+ deliverableId: 'del_xxx'
5211
+ });
5212
+ \`\`\`
5213
+
5214
+ ---
5215
+
5038
5216
  ## Common Pattern
5039
5217
 
5040
5218
  \`\`\`typescript
@@ -5072,9 +5250,10 @@ const result = await addArtifact({
5072
5250
  return { planId: plan.planId, snapshotUrl: result.snapshotUrl };
5073
5251
  \`\`\`
5074
5252
  `;
5075
- var ExecuteCodeInput = z12.object({
5076
- code: z12.string().describe("TypeScript code to execute")
5253
+ var ExecuteCodeInput = z13.object({
5254
+ code: z13.string().describe("TypeScript code to execute")
5077
5255
  });
5256
+ var scriptTracker = [];
5078
5257
  async function createPlan(opts) {
5079
5258
  const result = await createPlanTool.handler(opts);
5080
5259
  const text = result.content[0]?.text || "";
@@ -5086,6 +5265,9 @@ async function createPlan(opts) {
5086
5265
  deliverables = allDeliverables.map((d) => ({ id: d.id, text: d.text }));
5087
5266
  }
5088
5267
  const { script: monitoringScript } = await setupReviewNotification(planId, 30);
5268
+ scriptTracker.push(`Plan "${planId}" created.
5269
+
5270
+ ${monitoringScript}`);
5089
5271
  return {
5090
5272
  planId,
5091
5273
  sessionToken: text.match(/Session Token: (\S+)/)?.[1] || "",
@@ -5122,6 +5304,9 @@ async function readPlan(planId, sessionToken, opts) {
5122
5304
  async function updatePlan(planId, sessionToken, updates) {
5123
5305
  await updatePlanTool.handler({ planId, sessionToken, ...updates });
5124
5306
  const { script: monitoringScript } = await setupReviewNotification(planId, 30);
5307
+ scriptTracker.push(`Plan "${planId}" updated.
5308
+
5309
+ ${monitoringScript}`);
5125
5310
  return {
5126
5311
  success: true,
5127
5312
  monitoringScript
@@ -5201,7 +5386,7 @@ async function setupReviewNotification(planId, pollIntervalSeconds) {
5201
5386
  return { script, fullResponse: text };
5202
5387
  }
5203
5388
  async function requestUserInput(opts) {
5204
- const { InputRequestManager: InputRequestManager2 } = await import("./input-request-manager-73GSTOIB.js");
5389
+ const { InputRequestManager: InputRequestManager2 } = await import("./input-request-manager-3STPPPYU.js");
5205
5390
  const ydoc = await getOrCreateDoc3(PLAN_INDEX_DOC_NAME);
5206
5391
  const manager = new InputRequestManager2();
5207
5392
  const params = opts.type === "choice" ? {
@@ -5245,8 +5430,8 @@ async function requestUserInput(opts) {
5245
5430
  };
5246
5431
  }
5247
5432
  async function postActivityUpdate(opts) {
5248
- const { logPlanEvent: logPlanEvent2 } = await import("./dist-ORKL4P3L.js");
5249
- const { getGitHubUsername: getGitHubUsername2 } = await import("./server-identity-6PHKR2FY.js");
5433
+ const { logPlanEvent: logPlanEvent2 } = await import("./dist-D4DG2R4R.js");
5434
+ const { getGitHubUsername: getGitHubUsername2 } = await import("./server-identity-LSZ4CZRK.js");
5250
5435
  const { nanoid: nanoid8 } = await import("nanoid");
5251
5436
  const doc = await getOrCreateDoc3(opts.planId);
5252
5437
  const actorName = await getGitHubUsername2();
@@ -5268,8 +5453,8 @@ async function postActivityUpdate(opts) {
5268
5453
  return { success: true, eventId, requestId };
5269
5454
  }
5270
5455
  async function resolveActivityRequest(opts) {
5271
- const { logPlanEvent: logPlanEvent2, getPlanEvents } = await import("./dist-ORKL4P3L.js");
5272
- const { getGitHubUsername: getGitHubUsername2 } = await import("./server-identity-6PHKR2FY.js");
5456
+ const { logPlanEvent: logPlanEvent2, getPlanEvents } = await import("./dist-D4DG2R4R.js");
5457
+ const { getGitHubUsername: getGitHubUsername2 } = await import("./server-identity-LSZ4CZRK.js");
5273
5458
  const doc = await getOrCreateDoc3(opts.planId);
5274
5459
  const actorName = await getGitHubUsername2();
5275
5460
  const events = getPlanEvents(doc);
@@ -5294,6 +5479,18 @@ async function resolveActivityRequest(opts) {
5294
5479
  });
5295
5480
  return { success: true };
5296
5481
  }
5482
+ async function regenerateSessionToken(planId) {
5483
+ const result = await regenerateSessionTokenTool.handler({ planId });
5484
+ const text = result.content[0]?.text || "";
5485
+ if (result.isError) {
5486
+ throw new Error(text);
5487
+ }
5488
+ const tokenMatch = text.match(/New Session Token: (\S+)/);
5489
+ return {
5490
+ sessionToken: tokenMatch?.[1] || "",
5491
+ planId
5492
+ };
5493
+ }
5297
5494
  var executeCodeTool = {
5298
5495
  definition: {
5299
5496
  name: TOOL_NAMES.EXECUTE_CODE,
@@ -5312,6 +5509,7 @@ var executeCodeTool = {
5312
5509
  handler: async (args) => {
5313
5510
  const { code } = ExecuteCodeInput.parse(args);
5314
5511
  logger.info({ codeLength: code.length }, "Executing code");
5512
+ scriptTracker.length = 0;
5315
5513
  try {
5316
5514
  async function encodeVideo(opts) {
5317
5515
  const fps = opts.fps || 6;
@@ -5357,6 +5555,7 @@ var executeCodeTool = {
5357
5555
  requestUserInput,
5358
5556
  postActivityUpdate,
5359
5557
  resolveActivityRequest,
5558
+ regenerateSessionToken,
5360
5559
  // Video encoding helper (uses bundled FFmpeg)
5361
5560
  encodeVideo,
5362
5561
  // Node.js modules for advanced workflows (file ops, process spawning)
@@ -5376,14 +5575,33 @@ var executeCodeTool = {
5376
5575
  const script = new vm.Script(wrappedCode);
5377
5576
  const result = await script.runInContext(context, { timeout: 12e4 });
5378
5577
  logger.info({ result }, "Code execution complete");
5379
- return {
5380
- content: [
5381
- {
5382
- type: "text",
5383
- text: typeof result === "object" ? JSON.stringify(result, null, 2) : String(result ?? "Done")
5384
- }
5385
- ]
5386
- };
5578
+ const content = [
5579
+ {
5580
+ type: "text",
5581
+ text: typeof result === "object" ? JSON.stringify(result, null, 2) : String(result ?? "Done")
5582
+ }
5583
+ ];
5584
+ const latestScript = scriptTracker[scriptTracker.length - 1];
5585
+ if (latestScript) {
5586
+ const [planAction, ...scriptParts] = latestScript.split("\n\n");
5587
+ content.push({
5588
+ type: "text",
5589
+ text: `
5590
+
5591
+ ---
5592
+ **\u26A0\uFE0F IMPORTANT FOR NON-HOOK AGENTS (Cursor, Devin, Windsurf, etc.):**
5593
+
5594
+ ${planAction} To wait for human approval before proceeding, run this monitoring script in background:
5595
+
5596
+ \`\`\`bash
5597
+ ${scriptParts.join("\n\n")}
5598
+ \`\`\`
5599
+
5600
+ Save the script to a file and run: \`bash script.sh &\`
5601
+ The script will exit when the human approves or requests changes.`
5602
+ });
5603
+ }
5604
+ return { content };
5387
5605
  } catch (error) {
5388
5606
  logger.error({ error, code }, "Code execution failed");
5389
5607
  const message = error instanceof Error ? error.message : "Unknown error";
@@ -5396,15 +5614,15 @@ var executeCodeTool = {
5396
5614
  };
5397
5615
 
5398
5616
  // src/tools/request-user-input.ts
5399
- import { z as z13 } from "zod";
5400
- var RequestUserInputInput = z13.object({
5401
- message: z13.string().describe("The question to ask the user"),
5402
- type: z13.enum(["text", "choice", "confirm", "multiline"]).describe("Type of input to request"),
5403
- options: z13.array(z13.string()).optional().describe("For 'choice' type - available options (required for choice)"),
5404
- multiSelect: z13.boolean().optional().describe("For 'choice' type - allow selecting multiple options"),
5405
- defaultValue: z13.string().optional().describe("Pre-filled value for text/multiline inputs"),
5406
- timeout: z13.number().optional().describe("Timeout in seconds (default: 1800, min: 10, max: 14400)"),
5407
- planId: z13.string().optional().describe("Optional metadata to link request to plan (for activity log filtering)")
5617
+ import { z as z14 } from "zod";
5618
+ var RequestUserInputInput = z14.object({
5619
+ message: z14.string().describe("The question to ask the user"),
5620
+ type: z14.enum(["text", "choice", "confirm", "multiline"]).describe("Type of input to request"),
5621
+ options: z14.array(z14.string()).optional().describe("For 'choice' type - available options (required for choice)"),
5622
+ multiSelect: z14.boolean().optional().describe("For 'choice' type - allow selecting multiple options"),
5623
+ defaultValue: z14.string().optional().describe("Pre-filled value for text/multiline inputs"),
5624
+ timeout: z14.number().optional().describe("Timeout in seconds (default: 1800, min: 10, max: 14400)"),
5625
+ planId: z14.string().optional().describe("Optional metadata to link request to plan (for activity log filtering)")
5408
5626
  });
5409
5627
  var requestUserInputTool = {
5410
5628
  definition: {
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  InputRequestManager
3
- } from "./chunk-BWP37ADP.js";
4
- import "./chunk-76JWRTPI.js";
3
+ } from "./chunk-NH6GXGQO.js";
4
+ import "./chunk-BBYZISY2.js";
5
5
  import "./chunk-GSGLHRWX.js";
6
6
  import "./chunk-JSBRDJBE.js";
7
7
  export {
@@ -1,12 +1,14 @@
1
1
  import {
2
2
  getEnvironmentContext,
3
3
  getGitHubUsername,
4
- getRepositoryFullName
5
- } from "./chunk-E5DWX2WU.js";
4
+ getRepositoryFullName,
5
+ getVerifiedGitHubUsername
6
+ } from "./chunk-OLFHVNPI.js";
6
7
  import "./chunk-GSGLHRWX.js";
7
8
  import "./chunk-JSBRDJBE.js";
8
9
  export {
9
10
  getEnvironmentContext,
10
11
  getGitHubUsername,
11
- getRepositoryFullName
12
+ getRepositoryFullName,
13
+ getVerifiedGitHubUsername
12
14
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@schoolai/shipyard-mcp",
3
- "version": "0.2.2-next.482",
3
+ "version": "0.2.2-next.485",
4
4
  "description": "Shipyard MCP server and CLI tools for distributed planning with CRDTs",
5
5
  "type": "module",
6
6
  "bin": {