@schoolai/shipyard-mcp 0.1.3-next.460 → 0.1.3-next.466

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-B435ND5d.mjs
28497
+ // ../../packages/schema/dist/yjs-helpers-CFQmkNYl.mjs
28498
28498
  init_cjs_shims();
28499
28499
 
28500
28500
  // ../../packages/schema/dist/plan.mjs
@@ -42665,7 +42665,7 @@ var PRReviewCommentSchema = external_exports.object({
42665
42665
  resolved: external_exports.boolean().optional()
42666
42666
  });
42667
42667
 
42668
- // ../../packages/schema/dist/yjs-helpers-B435ND5d.mjs
42668
+ // ../../packages/schema/dist/yjs-helpers-CFQmkNYl.mjs
42669
42669
  function assertNever2(value) {
42670
42670
  throw new Error(`Unhandled discriminated union member: ${JSON.stringify(value)}`);
42671
42671
  }
@@ -42770,7 +42770,7 @@ var InputRequestBaseSchema = external_exports.object({
42770
42770
  message: external_exports.string().min(1, "Message cannot be empty"),
42771
42771
  status: external_exports.enum(InputRequestStatusValues),
42772
42772
  defaultValue: external_exports.string().optional(),
42773
- timeout: external_exports.number().int().min(10, "Timeout must be at least 10 seconds").max(900, "Timeout cannot exceed 15 minutes").optional(),
42773
+ timeout: external_exports.number().int().min(10, "Timeout must be at least 10 seconds").max(14400, "Timeout cannot exceed 4 hours").optional(),
42774
42774
  planId: external_exports.string().optional(),
42775
42775
  response: external_exports.unknown().optional(),
42776
42776
  answeredAt: external_exports.number().optional(),
@@ -863,7 +863,7 @@ function createHandedOffConversationVersion(params) {
863
863
  return ConversationVersionSchema.parse(version);
864
864
  }
865
865
 
866
- // ../../packages/schema/dist/yjs-helpers-B435ND5d.mjs
866
+ // ../../packages/schema/dist/yjs-helpers-CFQmkNYl.mjs
867
867
  import { z as z2 } from "zod";
868
868
  import { nanoid as nanoid2 } from "nanoid";
869
869
  import * as Y from "yjs";
@@ -959,7 +959,7 @@ var CreateSubscriptionRequestSchema = z2.object({
959
959
  threshold: z2.number().positive().optional()
960
960
  });
961
961
  var CreateSubscriptionResponseSchema = z2.object({ clientId: z2.string() });
962
- var DEFAULT_INPUT_REQUEST_TIMEOUT_SECONDS = 300;
962
+ var DEFAULT_INPUT_REQUEST_TIMEOUT_SECONDS = 1800;
963
963
  var InputRequestTypeValues = [
964
964
  "text",
965
965
  "multiline",
@@ -978,7 +978,7 @@ var InputRequestBaseSchema = z2.object({
978
978
  message: z2.string().min(1, "Message cannot be empty"),
979
979
  status: z2.enum(InputRequestStatusValues),
980
980
  defaultValue: z2.string().optional(),
981
- timeout: z2.number().int().min(10, "Timeout must be at least 10 seconds").max(900, "Timeout cannot exceed 15 minutes").optional(),
981
+ timeout: z2.number().int().min(10, "Timeout must be at least 10 seconds").max(14400, "Timeout cannot exceed 4 hours").optional(),
982
982
  planId: z2.string().optional(),
983
983
  response: z2.unknown().optional(),
984
984
  answeredAt: z2.number().optional(),
@@ -3,7 +3,7 @@ import {
3
3
  YDOC_KEYS,
4
4
  createInputRequest,
5
5
  logPlanEvent
6
- } from "./chunk-4BEPSPPL.js";
6
+ } from "./chunk-75NZRAN5.js";
7
7
  import {
8
8
  logger
9
9
  } from "./chunk-GSGLHRWX.js";
@@ -203,7 +203,7 @@ import {
203
203
  updateLinkedPRStatus,
204
204
  updatePlanIndexViewedBy,
205
205
  validateA2AMessages
206
- } from "./chunk-4BEPSPPL.js";
206
+ } from "./chunk-75NZRAN5.js";
207
207
  import "./chunk-JSBRDJBE.js";
208
208
  export {
209
209
  A2ADataPartSchema,
@@ -19,7 +19,7 @@ import {
19
19
  } from "./chunk-EBNL5ZX7.js";
20
20
  import {
21
21
  InputRequestManager
22
- } from "./chunk-FTOVV4YW.js";
22
+ } from "./chunk-MZTJGBLT.js";
23
23
  import {
24
24
  ArtifactSchema,
25
25
  DeliverableSchema,
@@ -68,7 +68,7 @@ import {
68
68
  setPlanMetadata,
69
69
  touchPlanIndexEntry,
70
70
  transitionPlanStatus
71
- } from "./chunk-4BEPSPPL.js";
71
+ } from "./chunk-75NZRAN5.js";
72
72
  import {
73
73
  loadEnv,
74
74
  logger
@@ -2477,7 +2477,7 @@ import { z as z12 } from "zod";
2477
2477
 
2478
2478
  // src/tools/add-artifact.ts
2479
2479
  import { execSync } from "child_process";
2480
- import { readFile as readFile3 } from "fs/promises";
2480
+ import { readFile as readFile3, writeFile as writeFile4 } from "fs/promises";
2481
2481
  import { ServerBlockNoteEditor as ServerBlockNoteEditor2 } from "@blocknote/server-util";
2482
2482
  import { nanoid as nanoid4 } from "nanoid";
2483
2483
  import { z as z3 } from "zod";
@@ -2909,6 +2909,14 @@ Linked to deliverable: ${input.deliverableId}` : "";
2909
2909
  logger.warn({ planId }, "Cannot update plan index: missing ownerId");
2910
2910
  }
2911
2911
  logger.info({ planId, snapshotUrl }, "Task auto-completed");
2912
+ const { homedir: homedir5 } = await import("os");
2913
+ const { join: join6 } = await import("path");
2914
+ const { mkdir: mkdir3 } = await import("fs/promises");
2915
+ const snapshotsDir = join6(homedir5(), ".shipyard", "snapshots");
2916
+ await mkdir3(snapshotsDir, { recursive: true });
2917
+ const snapshotFile = join6(snapshotsDir, `${planId}.txt`);
2918
+ await writeFile4(snapshotFile, snapshotUrl, "utf-8");
2919
+ logger.info({ planId, snapshotFile }, "Snapshot URL written to file");
2912
2920
  let prText = "";
2913
2921
  if (linkedPR) {
2914
2922
  prText = `
@@ -2934,10 +2942,11 @@ URL: ${artifactUrl}${linkedText}
2934
2942
 
2935
2943
  \u{1F389} ALL DELIVERABLES COMPLETE! Task auto-completed.${prText}
2936
2944
 
2937
- Snapshot URL generated. Access via result.snapshotUrl to embed in PR.`
2945
+ Snapshot URL saved to: ${snapshotFile}
2946
+ (Note: Very long URL - recommend not reading directly. Use file path to attach to PR or access later.)`
2938
2947
  }
2939
2948
  ],
2940
- // Structured data for programmatic access (avoids token limit issues)
2949
+ // Keep structured data for execute_code wrapper
2941
2950
  snapshotUrl,
2942
2951
  allDeliverablesComplete: true
2943
2952
  };
@@ -4140,7 +4149,9 @@ USAGE (for non-hook agents):
4140
4149
  1. Call this tool to get monitoring script
4141
4150
  2. Run script in background: bash <script> &
4142
4151
  3. Script polls registry server for status changes
4143
- 4. Exits when status becomes 'approved' or 'changes_requested'`,
4152
+ 4. Exits when status becomes 'in_progress' (approved) or 'changes_requested' (needs work)
4153
+
4154
+ REQUIREMENTS: The script requires 'jq' for URL encoding. Install with: brew install jq (macOS) or apt install jq (Linux)`,
4144
4155
  inputSchema: {
4145
4156
  type: "object",
4146
4157
  properties: {
@@ -4158,25 +4169,64 @@ USAGE (for non-hook agents):
4158
4169
  const { planId, pollIntervalSeconds = 30 } = input;
4159
4170
  const registryPort2 = registryConfig.REGISTRY_PORT[0];
4160
4171
  const trpcUrl = `http://localhost:${registryPort2}/trpc`;
4161
- const script = `# Subscribe to status and comment changes via tRPC
4162
- CLIENT_ID=$(curl -sf -X POST "${trpcUrl}/subscription.create" \\
4172
+ const statusInProgress = PlanStatusValues.find((s) => s === "in_progress");
4173
+ const statusChangesRequested = PlanStatusValues.find((s) => s === "changes_requested");
4174
+ if (!statusInProgress || !statusChangesRequested) {
4175
+ throw new Error("Required status values not found in PlanStatusValues");
4176
+ }
4177
+ const script = `#!/bin/bash
4178
+ # Monitor plan "${planId}" for approval status changes
4179
+ # Polls the Shipyard registry server and exits when approved/rejected
4180
+
4181
+ # Check for required dependency
4182
+ if ! command -v jq &> /dev/null; then
4183
+ echo "Error: jq is required but not installed."
4184
+ echo "Install with: brew install jq (macOS) or apt install jq (Linux)"
4185
+ exit 1
4186
+ fi
4187
+
4188
+ TRPC_URL="${trpcUrl}"
4189
+ PLAN_ID="${planId}"
4190
+ POLL_INTERVAL=${pollIntervalSeconds}
4191
+
4192
+ # Subscribe to status changes via tRPC mutation
4193
+ echo "Subscribing to plan changes..."
4194
+ RESPONSE=$(curl -sf -X POST "$TRPC_URL/subscription.create" \\
4163
4195
  -H "Content-Type: application/json" \\
4164
- -d '{"planId":"${planId}","subscribe":["status","comments"],"windowMs":5000,"threshold":1}' \\
4165
- | grep -o '"clientId":"[^"]*"' | cut -d'"' -f4)
4166
-
4167
- echo "Subscribed. Monitoring plan..."
4168
-
4169
- # Poll for changes via tRPC
4170
- while sleep ${pollIntervalSeconds}; do
4171
- result=$(curl -sf -X POST "${trpcUrl}/subscription.getChanges" \\
4172
- -H "Content-Type: application/json" \\
4173
- -d '{"planId":"${planId}","clientId":"'"$CLIENT_ID"'"}' 2>/dev/null)
4174
- ready=$(echo "$result" | grep -o '"ready":true')
4175
- if [ -n "$ready" ]; then
4176
- changes=$(echo "$result" | grep -o '"changes":"[^"]*"' | cut -d'"' -f4)
4177
- echo "Changes: $changes"
4178
- # Exit on status change to approved/changes_requested
4179
- echo "$changes" | grep -qE "Status:.*(approved|changes_requested)" && exit 0
4196
+ -d '{"planId":"'"$PLAN_ID"'","subscribe":["status","comments"],"windowMs":5000,"threshold":1}')
4197
+
4198
+ # Extract clientId from response: {"result":{"data":{"clientId":"..."}}}
4199
+ CLIENT_ID=$(echo "$RESPONSE" | sed -n 's/.*"clientId":"\\([^"]*\\)".*/\\1/p')
4200
+
4201
+ if [ -z "$CLIENT_ID" ]; then
4202
+ echo "Failed to subscribe. Is the Shipyard registry server running?"
4203
+ echo "Response: $RESPONSE"
4204
+ exit 1
4205
+ fi
4206
+
4207
+ echo "Subscribed with clientId: $CLIENT_ID"
4208
+ echo "Polling every $POLL_INTERVAL seconds..."
4209
+
4210
+ # Poll for changes via tRPC query (GET with url-encoded input)
4211
+ while true; do
4212
+ sleep $POLL_INTERVAL
4213
+
4214
+ # URL-encode the input JSON for GET request
4215
+ INPUT='{"planId":"'"$PLAN_ID"'","clientId":"'"$CLIENT_ID"'"}'
4216
+ ENCODED_INPUT=$(printf '%s' "$INPUT" | jq -sRr @uri)
4217
+
4218
+ RESULT=$(curl -sf "$TRPC_URL/subscription.getChanges?input=$ENCODED_INPUT" 2>/dev/null)
4219
+
4220
+ # Check if changes are ready: {"result":{"data":{"ready":true,"changes":"..."}}}
4221
+ if echo "$RESULT" | grep -q '"ready":true'; then
4222
+ CHANGES=$(echo "$RESULT" | sed -n 's/.*"changes":"\\([^"]*\\)".*/\\1/p')
4223
+ echo "Changes detected: $CHANGES"
4224
+
4225
+ # Exit on status change to in_progress (approved) or changes_requested (needs work)
4226
+ if echo "$CHANGES" | grep -qE "Status:.*(${statusInProgress}|${statusChangesRequested})"; then
4227
+ echo "Plan status changed. Exiting."
4228
+ exit 0
4229
+ fi
4180
4230
  fi
4181
4231
  done`;
4182
4232
  return {
@@ -4189,10 +4239,13 @@ done`;
4189
4239
  ${script}
4190
4240
  \`\`\`
4191
4241
 
4192
- > Subscribes to status and comment changes with server-side batching.
4193
- > Batching: 5s window or 1 change threshold (whichever comes first).
4194
- > Exits when status becomes approved/changes_requested.
4195
- > Most agent environments support background bash notifications.`
4242
+ **Usage:** Save to a file and run in background: \`bash script.sh &\`
4243
+
4244
+ The script:
4245
+ - Subscribes to status/comment changes via tRPC
4246
+ - Polls every ${pollIntervalSeconds} seconds
4247
+ - Exits when status becomes in_progress (approved) or changes_requested (needs work)
4248
+ - Requires \`jq\` for URL encoding (install: brew install jq)`
4196
4249
  }
4197
4250
  ]
4198
4251
  };
@@ -4779,17 +4832,36 @@ Parameters:
4779
4832
  - pollIntervalSeconds (number, optional): Polling interval (default: 30)
4780
4833
 
4781
4834
  Returns:
4782
- - script: Bash script that polls registry server and exits when status becomes 'changes_requested' or 'in_progress'
4835
+ - script: Bash script that polls registry server and exits when status becomes 'in_progress' (approved) or 'changes_requested' (needs work)
4783
4836
 
4784
- Use this for agents WITHOUT hook support (Cursor, Devin, etc). The script can be run in background.
4837
+ **IMPORTANT:** This is ONLY for agents WITHOUT hook support (Cursor, Devin, Windsurf, etc).
4838
+ Claude Code users have automatic blocking via the shipyard hook - you don't need this.
4785
4839
 
4786
- Example:
4840
+ **Complete workflow for non-hook agents (example user code):**
4787
4841
  \`\`\`typescript
4842
+ // 1. Create plan and get the monitoring script in ONE code block
4843
+ const plan = await createPlan({
4844
+ title: "My Feature Implementation",
4845
+ content: "- [ ] Screenshot of working feature {#deliverable}"
4846
+ });
4847
+
4848
+ // 2. Get the polling script (returns bash script as string)
4788
4849
  const { script } = await setupReviewNotification(plan.planId, 15);
4789
- // Agent runs this script in background to wait for approval
4790
- console.log(script);
4850
+
4851
+ // 3. Return both so the agent can run the script
4852
+ return {
4853
+ planId: plan.planId,
4854
+ sessionToken: plan.sessionToken,
4855
+ monitoringScript: script,
4856
+ instructions: "Run the monitoring script in background: bash <script> &"
4857
+ };
4791
4858
  \`\`\`
4792
4859
 
4860
+ The agent then runs the returned bash script in the background. The script will:
4861
+ - Poll the registry server every N seconds
4862
+ - Print status changes to stdout
4863
+ - Exit with code 0 when the plan is approved/rejected
4864
+
4793
4865
  ---
4794
4866
 
4795
4867
  ### requestUserInput(opts): Promise<{ success, response?, status, reason? }>
@@ -4801,7 +4873,7 @@ Parameters:
4801
4873
  - options (string[], optional): For 'choice' type - available options (required for choice)
4802
4874
  - multiSelect (boolean, optional): For 'choice' type - allow selecting multiple options (uses checkboxes instead of radio buttons)
4803
4875
  - defaultValue (string, optional): Pre-filled value for text/multiline inputs
4804
- - timeout (number, optional): Timeout in seconds (default: 300, min: 10, max: 600)
4876
+ - timeout (number, optional): Timeout in seconds (default: 1800, min: 10, max: 14400)
4805
4877
  - planId (string, optional): Optional metadata to link request to plan (for activity log filtering)
4806
4878
 
4807
4879
  Returns:
@@ -5076,7 +5148,7 @@ async function setupReviewNotification(planId, pollIntervalSeconds) {
5076
5148
  return { script, fullResponse: text };
5077
5149
  }
5078
5150
  async function requestUserInput(opts) {
5079
- const { InputRequestManager: InputRequestManager2 } = await import("./input-request-manager-YMNFW4JM.js");
5151
+ const { InputRequestManager: InputRequestManager2 } = await import("./input-request-manager-43QSOJS3.js");
5080
5152
  const ydoc = await getOrCreateDoc3(PLAN_INDEX_DOC_NAME);
5081
5153
  const manager = new InputRequestManager2();
5082
5154
  const params = opts.type === "choice" ? {
@@ -5120,7 +5192,7 @@ async function requestUserInput(opts) {
5120
5192
  };
5121
5193
  }
5122
5194
  async function postActivityUpdate(opts) {
5123
- const { logPlanEvent: logPlanEvent2 } = await import("./dist-FZ4WTJ2H.js");
5195
+ const { logPlanEvent: logPlanEvent2 } = await import("./dist-HIDISXZO.js");
5124
5196
  const { getGitHubUsername: getGitHubUsername2 } = await import("./server-identity-6PHKR2FY.js");
5125
5197
  const { nanoid: nanoid7 } = await import("nanoid");
5126
5198
  const doc = await getOrCreateDoc3(opts.planId);
@@ -5143,7 +5215,7 @@ async function postActivityUpdate(opts) {
5143
5215
  return { success: true, eventId, requestId };
5144
5216
  }
5145
5217
  async function resolveActivityRequest(opts) {
5146
- const { logPlanEvent: logPlanEvent2, getPlanEvents } = await import("./dist-FZ4WTJ2H.js");
5218
+ const { logPlanEvent: logPlanEvent2, getPlanEvents } = await import("./dist-HIDISXZO.js");
5147
5219
  const { getGitHubUsername: getGitHubUsername2 } = await import("./server-identity-6PHKR2FY.js");
5148
5220
  const doc = await getOrCreateDoc3(opts.planId);
5149
5221
  const actorName = await getGitHubUsername2();
@@ -5278,7 +5350,7 @@ var RequestUserInputInput = z13.object({
5278
5350
  options: z13.array(z13.string()).optional().describe("For 'choice' type - available options (required for choice)"),
5279
5351
  multiSelect: z13.boolean().optional().describe("For 'choice' type - allow selecting multiple options"),
5280
5352
  defaultValue: z13.string().optional().describe("Pre-filled value for text/multiline inputs"),
5281
- timeout: z13.number().optional().describe("Timeout in seconds (default: 300, min: 10, max: 900)"),
5353
+ timeout: z13.number().optional().describe("Timeout in seconds (default: 1800, min: 10, max: 14400)"),
5282
5354
  planId: z13.string().optional().describe("Optional metadata to link request to plan (for activity log filtering)")
5283
5355
  });
5284
5356
  var requestUserInputTool = {
@@ -5335,7 +5407,7 @@ NOTE: This is also available as requestUserInput() inside execute_code for multi
5335
5407
  },
5336
5408
  timeout: {
5337
5409
  type: "number",
5338
- description: "Timeout in seconds (default: 300, min: 10, max: 900)"
5410
+ description: "Timeout in seconds (default: 1800, min: 10, max: 14400)"
5339
5411
  },
5340
5412
  planId: {
5341
5413
  type: "string",
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  InputRequestManager
3
- } from "./chunk-FTOVV4YW.js";
4
- import "./chunk-4BEPSPPL.js";
3
+ } from "./chunk-MZTJGBLT.js";
4
+ import "./chunk-75NZRAN5.js";
5
5
  import "./chunk-GSGLHRWX.js";
6
6
  import "./chunk-JSBRDJBE.js";
7
7
  export {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@schoolai/shipyard-mcp",
3
- "version": "0.1.3-next.460",
3
+ "version": "0.1.3-next.466",
4
4
  "description": "Shipyard MCP server and CLI tools for distributed planning with CRDTs",
5
5
  "type": "module",
6
6
  "bin": {