@schoolai/shipyard-mcp 0.2.1 → 0.2.2-next.483

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.
@@ -4742,7 +4742,7 @@ var BUNDLED_DOCS = `Execute TypeScript code that calls Shipyard APIs. Use this f
4742
4742
 
4743
4743
  ## Available APIs
4744
4744
 
4745
- ### createPlan(opts): Promise<{ planId, sessionToken, url, deliverables }>
4745
+ ### createPlan(opts): Promise<{ planId, sessionToken, url, deliverables, monitoringScript }>
4746
4746
  Create a new plan and open it in browser.
4747
4747
 
4748
4748
  Parameters:
@@ -4756,6 +4756,7 @@ Returns:
4756
4756
  - sessionToken: Required for subsequent API calls
4757
4757
  - url: Browser URL for the plan
4758
4758
  - deliverables: Array of { id, text } for linking artifacts
4759
+ - monitoringScript: Bash script to poll for approval (for non-hook agents)
4759
4760
 
4760
4761
  Example:
4761
4762
  \`\`\`typescript
@@ -4763,7 +4764,10 @@ const plan = await createPlan({
4763
4764
  title: "Add auth",
4764
4765
  content: "- [ ] Screenshot of login {#deliverable}"
4765
4766
  });
4766
- // Returns: { planId: "abc", sessionToken: "xyz", url: "...", deliverables: [{ id: "del_xxx", text: "Screenshot of login" }] }
4767
+ // Returns: { planId: "abc", sessionToken: "xyz", url: "...", deliverables: [...], monitoringScript: "#!/bin/bash..." }
4768
+
4769
+ // For non-hook agents: Run the monitoring script in background to wait for approval
4770
+ // bash <(echo "$monitoringScript") &
4767
4771
  \`\`\`
4768
4772
 
4769
4773
  ---
@@ -4801,7 +4805,7 @@ data.deliverables.forEach(d => console.log(d.id, d.completed));
4801
4805
 
4802
4806
  ---
4803
4807
 
4804
- ### updatePlan(planId, sessionToken, updates): Promise<void>
4808
+ ### updatePlan(planId, sessionToken, updates): Promise<{ success, monitoringScript }>
4805
4809
  Update plan metadata.
4806
4810
 
4807
4811
  Parameters:
@@ -4810,6 +4814,10 @@ Parameters:
4810
4814
  - updates.title (string, optional): New title
4811
4815
  - updates.status (string, optional): 'draft' | 'pending_review' | 'changes_requested' | 'in_progress'
4812
4816
 
4817
+ Returns:
4818
+ - success: Boolean indicating update succeeded
4819
+ - monitoringScript: Bash script to poll for approval (for non-hook agents)
4820
+
4813
4821
  Note: Most status transitions are automatic. Rarely needed.
4814
4822
 
4815
4823
  ---
@@ -4900,46 +4908,6 @@ Parameters:
4900
4908
 
4901
4909
  ---
4902
4910
 
4903
- ### setupReviewNotification(planId, pollIntervalSeconds?): Promise<{ script }>
4904
- Get a bash script to poll for plan approval status changes.
4905
-
4906
- Parameters:
4907
- - planId (string): Plan ID to monitor
4908
- - pollIntervalSeconds (number, optional): Polling interval (default: 30)
4909
-
4910
- Returns:
4911
- - script: Bash script that polls registry server and exits when status becomes 'in_progress' (approved) or 'changes_requested' (needs work)
4912
-
4913
- **IMPORTANT:** This is ONLY for agents WITHOUT hook support (Cursor, Devin, Windsurf, etc).
4914
- Claude Code users have automatic blocking via the shipyard hook - you don't need this.
4915
-
4916
- **Complete workflow for non-hook agents (example user code):**
4917
- \`\`\`typescript
4918
- // 1. Create plan and get the monitoring script in ONE code block
4919
- const plan = await createPlan({
4920
- title: "My Feature Implementation",
4921
- content: "- [ ] Screenshot of working feature {#deliverable}"
4922
- });
4923
-
4924
- // 2. Get the polling script (returns bash script as string)
4925
- const { script } = await setupReviewNotification(plan.planId, 15);
4926
-
4927
- // 3. Return both so the agent can run the script
4928
- return {
4929
- planId: plan.planId,
4930
- sessionToken: plan.sessionToken,
4931
- monitoringScript: script,
4932
- instructions: "Run the monitoring script in background: bash <script> &"
4933
- };
4934
- \`\`\`
4935
-
4936
- The agent then runs the returned bash script in the background. The script will:
4937
- - Poll the registry server every N seconds
4938
- - Print status changes to stdout
4939
- - Exit with code 0 when the plan is approved/rejected
4940
-
4941
- ---
4942
-
4943
4911
  ### requestUserInput(opts): Promise<{ success, response?, status, reason? }>
4944
4912
  Request input from the user via browser modal.
4945
4913
 
@@ -5075,7 +5043,9 @@ const plan = await createPlan({
5075
5043
  content: "- [ ] Screenshot {#deliverable}\\n- [ ] Video {#deliverable}"
5076
5044
  });
5077
5045
 
5078
- // plan.deliverables = [{ id: "del_xxx", text: "Screenshot" }, { id: "del_yyy", text: "Video" }]
5046
+ // plan includes: planId, sessionToken, url, deliverables, monitoringScript
5047
+ // For non-hook agents: Run monitoringScript in background to wait for approval
5048
+ // The script polls and exits when human approves/rejects
5079
5049
 
5080
5050
  // Do work, take screenshots...
5081
5051
 
@@ -5105,6 +5075,7 @@ return { planId: plan.planId, snapshotUrl: result.snapshotUrl };
5105
5075
  var ExecuteCodeInput = z12.object({
5106
5076
  code: z12.string().describe("TypeScript code to execute")
5107
5077
  });
5078
+ var scriptTracker = [];
5108
5079
  async function createPlan(opts) {
5109
5080
  const result = await createPlanTool.handler(opts);
5110
5081
  const text = result.content[0]?.text || "";
@@ -5115,11 +5086,16 @@ async function createPlan(opts) {
5115
5086
  const allDeliverables = getDeliverables(ydoc);
5116
5087
  deliverables = allDeliverables.map((d) => ({ id: d.id, text: d.text }));
5117
5088
  }
5089
+ const { script: monitoringScript } = await setupReviewNotification(planId, 30);
5090
+ scriptTracker.push(`Plan "${planId}" created.
5091
+
5092
+ ${monitoringScript}`);
5118
5093
  return {
5119
5094
  planId,
5120
5095
  sessionToken: text.match(/Session Token: (\S+)/)?.[1] || "",
5121
5096
  url: text.match(/URL: (\S+)/)?.[1] || "",
5122
- deliverables
5097
+ deliverables,
5098
+ monitoringScript
5123
5099
  };
5124
5100
  }
5125
5101
  async function readPlan(planId, sessionToken, opts) {
@@ -5149,6 +5125,14 @@ async function readPlan(planId, sessionToken, opts) {
5149
5125
  }
5150
5126
  async function updatePlan(planId, sessionToken, updates) {
5151
5127
  await updatePlanTool.handler({ planId, sessionToken, ...updates });
5128
+ const { script: monitoringScript } = await setupReviewNotification(planId, 30);
5129
+ scriptTracker.push(`Plan "${planId}" updated.
5130
+
5131
+ ${monitoringScript}`);
5132
+ return {
5133
+ success: true,
5134
+ monitoringScript
5135
+ };
5152
5136
  }
5153
5137
  async function addArtifact2(opts) {
5154
5138
  const result = await addArtifactTool.handler(opts);
@@ -5335,6 +5319,7 @@ var executeCodeTool = {
5335
5319
  handler: async (args) => {
5336
5320
  const { code } = ExecuteCodeInput.parse(args);
5337
5321
  logger.info({ codeLength: code.length }, "Executing code");
5322
+ scriptTracker.length = 0;
5338
5323
  try {
5339
5324
  async function encodeVideo(opts) {
5340
5325
  const fps = opts.fps || 6;
@@ -5399,14 +5384,33 @@ var executeCodeTool = {
5399
5384
  const script = new vm.Script(wrappedCode);
5400
5385
  const result = await script.runInContext(context, { timeout: 12e4 });
5401
5386
  logger.info({ result }, "Code execution complete");
5402
- return {
5403
- content: [
5404
- {
5405
- type: "text",
5406
- text: typeof result === "object" ? JSON.stringify(result, null, 2) : String(result ?? "Done")
5407
- }
5408
- ]
5409
- };
5387
+ const content = [
5388
+ {
5389
+ type: "text",
5390
+ text: typeof result === "object" ? JSON.stringify(result, null, 2) : String(result ?? "Done")
5391
+ }
5392
+ ];
5393
+ const latestScript = scriptTracker[scriptTracker.length - 1];
5394
+ if (latestScript) {
5395
+ const [planAction, ...scriptParts] = latestScript.split("\n\n");
5396
+ content.push({
5397
+ type: "text",
5398
+ text: `
5399
+
5400
+ ---
5401
+ **\u26A0\uFE0F IMPORTANT FOR NON-HOOK AGENTS (Cursor, Devin, Windsurf, etc.):**
5402
+
5403
+ ${planAction} To wait for human approval before proceeding, run this monitoring script in background:
5404
+
5405
+ \`\`\`bash
5406
+ ${scriptParts.join("\n\n")}
5407
+ \`\`\`
5408
+
5409
+ Save the script to a file and run: \`bash script.sh &\`
5410
+ The script will exit when the human approves or requests changes.`
5411
+ });
5412
+ }
5413
+ return { content };
5410
5414
  } catch (error) {
5411
5415
  logger.error({ error, code }, "Code execution failed");
5412
5416
  const message = error instanceof Error ? error.message : "Unknown error";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@schoolai/shipyard-mcp",
3
- "version": "0.2.1",
3
+ "version": "0.2.2-next.483",
4
4
  "description": "Shipyard MCP server and CLI tools for distributed planning with CRDTs",
5
5
  "type": "module",
6
6
  "bin": {