@schoolai/shipyard-mcp 0.2.2 → 0.3.0

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.
@@ -28488,13 +28488,459 @@ var require_undici = __commonJS({
28488
28488
  // src/index.ts
28489
28489
  init_cjs_shims();
28490
28490
 
28491
+ // ../../packages/shared/dist/instructions/index.mjs
28492
+ init_cjs_shims();
28493
+ var TOOL_NAMES = {
28494
+ ADD_ARTIFACT: "add_artifact",
28495
+ ADD_PR_REVIEW_COMMENT: "add_pr_review_comment",
28496
+ COMPLETE_TASK: "complete_task",
28497
+ CREATE_PLAN: "create_plan",
28498
+ EXECUTE_CODE: "execute_code",
28499
+ LINK_PR: "link_pr",
28500
+ READ_PLAN: "read_plan",
28501
+ REGENERATE_SESSION_TOKEN: "regenerate_session_token",
28502
+ REQUEST_USER_INPUT: "request_user_input",
28503
+ SETUP_REVIEW_NOTIFICATION: "setup_review_notification",
28504
+ UPDATE_BLOCK_CONTENT: "update_block_content",
28505
+ UPDATE_PLAN: "update_plan"
28506
+ };
28507
+ var CRITICAL_USAGE_SECTION = `## CRITICAL: When to Use Shipyard
28508
+
28509
+ \u26A0\uFE0F **MANDATORY USAGE RULE:**
28510
+
28511
+ If Shipyard is available, you MUST use it for:
28512
+ - Creating implementation plans
28513
+ - Tracking work that needs human review
28514
+ - Documenting proof of work (screenshots, videos, test results)
28515
+ - ANY user request involving "plan", "track", "verify", or "prove"
28516
+
28517
+ **DO NOT:**
28518
+ - Create plans manually in chat or as markdown files
28519
+ - Write implementation docs yourself when Shipyard is available
28520
+ - Suggest alternatives to Shipyard for trackable work
28521
+ - Overthink whether to use it - WHEN IN DOUBT, USE SHIPYARD
28522
+
28523
+ **Decision Tree:**
28524
+ \`\`\`
28525
+ Need to create/track/verify work?
28526
+ \u2502
28527
+ \u25BC
28528
+ Shipyard available?
28529
+ \u2502 \u2502
28530
+ YES NO
28531
+ \u2502 \u2502
28532
+ \u25BC \u25BC
28533
+ USE IT Manual approach
28534
+ NOW (tell user why)
28535
+ \`\`\``;
28536
+ var DELIVERABLES_SECTION = `## What are Deliverables?
28537
+
28538
+ Deliverables are measurable outcomes you can **prove** with artifacts (screenshots, videos, test results).
28539
+
28540
+ **Good deliverables (provable):**
28541
+ \`\`\`
28542
+ - [ ] Screenshot of working login page {#deliverable}
28543
+ - [ ] Video showing drag-and-drop feature {#deliverable}
28544
+ - [ ] Test results showing all tests pass {#deliverable}
28545
+ \`\`\`
28546
+
28547
+ **Bad deliverables (not provable - these are tasks, not deliverables):**
28548
+ \`\`\`
28549
+ - [ ] Implement getUserMedia API \u2190 Implementation detail, not provable
28550
+ - [ ] Add error handling \u2190 Can't capture this with an artifact
28551
+ - [ ] Refactor authentication \u2190 Too vague, no visual proof
28552
+ \`\`\`
28553
+
28554
+ **Rule:** If you can't screenshot/record/export it, it's not a deliverable.`;
28555
+ var ARTIFACT_TYPES_SECTION = `## Artifact Types
28556
+
28557
+ | Type | Use For | File Formats |
28558
+ |------|---------|--------------|
28559
+ | \`screenshot\` | UI changes, visual proof, error states | .png, .jpg, .webp |
28560
+ | \`video\` | Complex flows, interactions, animations | .mp4, .webm |
28561
+ | \`test_results\` | Test output, coverage reports | .json, .txt, .xml |
28562
+ | \`diff\` | Code changes, before/after comparisons | .diff, .patch |`;
28563
+ var TIPS_SECTION = `## Tips for Effective Use
28564
+
28565
+ 1. **Plan deliverables first** - Decide what proves success before coding
28566
+ 2. **Capture during work** - Take screenshots as you implement, not after
28567
+ 3. **Be specific** - "Login page with error state" beats "Screenshot"
28568
+ 4. **Link every artifact** - Always set \`deliverableId\` for auto-completion
28569
+ 5. **Check feedback** - Read reviewer comments and iterate`;
28570
+ var WHEN_NOT_TO_USE_SECTION = `## When NOT to Use Shipyard
28571
+
28572
+ Skip Shipyard for:
28573
+ - Quick answers or research questions (no artifacts to capture)
28574
+ - Internal refactoring with no visible output
28575
+ - Tasks where proof adds no value (trivial fixes)
28576
+ - Exploration or debugging sessions
28577
+ - Pure documentation without implementation`;
28578
+ var USER_INPUT_SECTION = `## Human-Agent Communication
28579
+
28580
+ **\`${TOOL_NAMES.REQUEST_USER_INPUT}\` is THE primary way to communicate with humans during active work.**
28581
+
28582
+ Shipyard is the central hub where humans manage AI agents. When you need to ask a question, get clarification, or request a decision - use \`${TOOL_NAMES.REQUEST_USER_INPUT}\`. The human is already in the browser viewing your plan. That's where conversations should happen.
28583
+
28584
+ ### Why Use ${TOOL_NAMES.REQUEST_USER_INPUT}
28585
+
28586
+ - **Context:** The human sees your question alongside the plan, artifacts, and comments
28587
+ - **History:** All exchanges are logged in the plan's activity feed
28588
+ - **Continuity:** The conversation stays attached to the work, not scattered across chat windows
28589
+ - **Flexibility:** 8 input types, multi-question forms, "Other" escape hatch for custom answers
28590
+
28591
+ ### Replace Platform Tools
28592
+
28593
+ **ALWAYS prefer \`${TOOL_NAMES.REQUEST_USER_INPUT}\` over platform-specific tools:**
28594
+
28595
+ | Platform | DON'T Use | Use Instead |
28596
+ |----------|-----------|-------------|
28597
+ | Claude Code | \`AskUserQuestion\` | \`${TOOL_NAMES.REQUEST_USER_INPUT}\` |
28598
+ | Cursor | Built-in prompts | \`${TOOL_NAMES.REQUEST_USER_INPUT}\` |
28599
+ | Windsurf | Native dialogs | \`${TOOL_NAMES.REQUEST_USER_INPUT}\` |
28600
+ | Claude Desktop | Chat questions | \`${TOOL_NAMES.REQUEST_USER_INPUT}\` |
28601
+
28602
+ ### When to Ask
28603
+
28604
+ Use \`${TOOL_NAMES.REQUEST_USER_INPUT}\` when you need:
28605
+ - Clarification on requirements ("Which auth provider?")
28606
+ - Decisions that affect implementation ("PostgreSQL or SQLite?")
28607
+ - Confirmation before destructive actions ("Delete this file?")
28608
+ - User preferences ("Rate this approach 1-5")
28609
+ - Any information you can't infer from context
28610
+
28611
+ ### Example
28612
+
28613
+ \`\`\`typescript
28614
+ const result = await requestUserInput({
28615
+ message: "Which database should we use?",
28616
+ type: "choice",
28617
+ options: ["PostgreSQL", "SQLite", "MongoDB"],
28618
+ timeout: 600 // 10 minutes
28619
+ });
28620
+
28621
+ if (result.success) {
28622
+ console.log("User chose:", result.response);
28623
+ }
28624
+ \`\`\`
28625
+
28626
+ **Note:** The MCP tool is named \`${TOOL_NAMES.REQUEST_USER_INPUT}\` (snake_case). Inside \`${TOOL_NAMES.EXECUTE_CODE}\`, it's available as \`requestUserInput()\` (camelCase).`;
28627
+ var TROUBLESHOOTING_SECTION = `## Troubleshooting
28628
+
28629
+ **Browser doesn't open:** Check MCP server is running and accessible.
28630
+
28631
+ **Upload fails:** Verify file path exists. For GitHub uploads, check \`GITHUB_TOKEN\` has repo write access.
28632
+
28633
+ **No auto-complete:** Ensure every deliverable has an artifact with matching \`deliverableId\`.
28634
+
28635
+ **Plan not syncing:** Check WebSocket connection to registry server.
28636
+
28637
+ **Input request times out:** User may not have seen it or needs more time. Default timeout is 30 minutes. Try again with a longer timeout or rephrase the question.
28638
+
28639
+ **Input request declined:** User clicked "Decline." Rephrase your question, proceed with a reasonable default, or use a different approach.
28640
+
28641
+ **No response to input:** Check if browser is connected to the plan. User may have closed the browser window.`;
28642
+ var COMMON_INSTRUCTIONS = [
28643
+ CRITICAL_USAGE_SECTION,
28644
+ USER_INPUT_SECTION,
28645
+ DELIVERABLES_SECTION,
28646
+ ARTIFACT_TYPES_SECTION,
28647
+ TIPS_SECTION,
28648
+ WHEN_NOT_TO_USE_SECTION,
28649
+ TROUBLESHOOTING_SECTION
28650
+ ].join("\n\n");
28651
+ var CLAUDE_CODE_HEADER = `[SHIPYARD] Collaborative planning with human review & proof-of-work tracking.`;
28652
+ var PLAN_MODE_WORKFLOW = `## How to Use (Claude Code with Hooks)
28653
+
28654
+ You have the **full Shipyard experience** with automatic hooks. Use native plan mode:
28655
+
28656
+ ### Workflow
28657
+
28658
+ 1. **Enter plan mode** (Shift+Tab) \u2192 Browser opens with live plan automatically
28659
+ 2. **Write your plan** with \`{#deliverable}\` markers for provable outcomes
28660
+ 3. **Exit plan mode** \u2192 Hook **BLOCKS** until human approves or requests changes
28661
+ 4. **On approval** \u2192 You automatically receive: planId, sessionToken, deliverable IDs
28662
+ 5. **Do the work** \u2192 Take screenshots/videos as you implement
28663
+ 6. **Upload artifacts** \u2192 \`${TOOL_NAMES.ADD_ARTIFACT}(filePath, deliverableId)\` for each deliverable
28664
+ 7. **Auto-complete** \u2192 When all deliverables have artifacts, task completes with snapshot URL
28665
+
28666
+ ### After Approval
28667
+
28668
+ You only need ONE tool: \`${TOOL_NAMES.ADD_ARTIFACT}\`
28669
+
28670
+ The hook automatically injects everything you need (planId, sessionToken, deliverables).
28671
+ Just call \`${TOOL_NAMES.ADD_ARTIFACT}\` with the file path and deliverable ID.
28672
+
28673
+ \`\`\`typescript
28674
+ // Example: After approval, you'll have these in context
28675
+ // planId: "abc123"
28676
+ // sessionToken: "xyz..."
28677
+ // deliverables: [{ id: "del_xxx", text: "Screenshot of login" }]
28678
+
28679
+ await addArtifact({
28680
+ planId,
28681
+ sessionToken,
28682
+ type: 'screenshot',
28683
+ filename: 'login-page.png',
28684
+ source: 'file',
28685
+ filePath: '/tmp/screenshot.png',
28686
+ deliverableId: deliverables[0].id
28687
+ });
28688
+ \`\`\`
28689
+
28690
+ When the last deliverable gets an artifact, the task auto-completes and returns a snapshot URL.`;
28691
+ var IMPORTANT_NOTES = `## Important Notes for Claude Code
28692
+
28693
+ - **DO NOT call \`createPlan()\` directly** - The hook handles plan creation when you enter plan mode
28694
+ - **DO NOT use the Shipyard skill** - The hook provides everything you need
28695
+ - **DO NOT poll for approval** - The hook blocks automatically until human decides
28696
+ - **DO use plan mode** for ANY work that needs tracking, verification, or human review
28697
+ - **DO use \`${TOOL_NAMES.REQUEST_USER_INPUT}\`** instead of \`AskUserQuestion\` - The human is in the browser viewing your plan, questions should appear there`;
28698
+ var CLAUDE_CODE_INSTRUCTIONS = [
28699
+ CLAUDE_CODE_HEADER,
28700
+ "",
28701
+ CRITICAL_USAGE_SECTION,
28702
+ "",
28703
+ USER_INPUT_SECTION,
28704
+ "",
28705
+ PLAN_MODE_WORKFLOW,
28706
+ "",
28707
+ DELIVERABLES_SECTION,
28708
+ "",
28709
+ ARTIFACT_TYPES_SECTION,
28710
+ "",
28711
+ IMPORTANT_NOTES,
28712
+ "",
28713
+ TIPS_SECTION,
28714
+ "",
28715
+ WHEN_NOT_TO_USE_SECTION,
28716
+ "",
28717
+ TROUBLESHOOTING_SECTION
28718
+ ].join("\n");
28719
+ var MCP_DIRECT_HEADER = `# Shipyard: Your Agent Management Hub
28720
+
28721
+ > **Shipyard is the central interface where humans manage AI agents.** Plans, artifacts, feedback, and communication all happen here.
28722
+
28723
+ Shipyard turns invisible agent work into reviewable, verifiable tasks. Instead of trusting that code was written correctly, reviewers see screenshots, videos, and test results as proof.
28724
+
28725
+ **Key principle:** When you're working in Shipyard, ALL human-agent communication should happen through Shipyard's \`${TOOL_NAMES.REQUEST_USER_INPUT}\` tool. The human is already in the browser viewing your plan - that's where they expect to interact with you.`;
28726
+ var MCP_TOOLS_OVERVIEW = `## Available MCP Tools
28727
+
28728
+ | Tool | Purpose |
28729
+ |------|---------|
28730
+ | \`${TOOL_NAMES.REQUEST_USER_INPUT}\` | **THE primary human-agent communication channel** - Ask questions, get decisions, request clarification |
28731
+ | \`${TOOL_NAMES.EXECUTE_CODE}\` | Run TypeScript that calls Shipyard APIs (recommended for multi-step operations) |
28732
+
28733
+ ### ${TOOL_NAMES.REQUEST_USER_INPUT}: Your Direct Line to the Human
28734
+
28735
+ This is how you talk to humans during active work. Don't use your platform's built-in question tools (AskUserQuestion, etc.) - use this instead. The human is in the browser viewing your plan, and that's where they expect to see your questions.
28736
+
28737
+ **Preferred approach:** Use \`${TOOL_NAMES.EXECUTE_CODE}\` to chain multiple API calls in one step.`;
28738
+ var MCP_WORKFLOW = `## Workflow (MCP Direct)
28739
+
28740
+ ### Step 1: Create Plan
28741
+
28742
+ \`\`\`typescript
28743
+ const plan = await createPlan({
28744
+ title: "Add user authentication",
28745
+ content: \`
28746
+ ## Deliverables
28747
+ - [ ] Screenshot of login page {#deliverable}
28748
+ - [ ] Screenshot of error handling {#deliverable}
28749
+
28750
+ ## Implementation
28751
+ 1. Create login form component
28752
+ 2. Add validation
28753
+ 3. Connect to auth API
28754
+ \`
28755
+ });
28756
+
28757
+ const { planId, sessionToken, deliverables, monitoringScript } = plan;
28758
+ // deliverables = [{ id: "del_xxx", text: "Screenshot of login page" }, ...]
28759
+ \`\`\`
28760
+
28761
+ ### Step 2: Wait for Approval
28762
+
28763
+ For platforms without hooks, run the monitoring script in the background:
28764
+
28765
+ \`\`\`bash
28766
+ # The monitoringScript polls for approval status
28767
+ # Run it in background while you wait
28768
+ bash <(echo "$monitoringScript") &
28769
+ \`\`\`
28770
+
28771
+ Or poll manually:
28772
+
28773
+ \`\`\`typescript
28774
+ const status = await readPlan(planId, sessionToken);
28775
+ if (status.status === "in_progress") {
28776
+ // Approved! Proceed with work
28777
+ }
28778
+ if (status.status === "changes_requested") {
28779
+ // Read feedback, make changes
28780
+ }
28781
+ \`\`\`
28782
+
28783
+ ### Step 3: Do the Work
28784
+
28785
+ Implement the feature, taking screenshots/recordings as you go.
28786
+
28787
+ ### Step 4: Upload Artifacts
28788
+
28789
+ \`\`\`typescript
28790
+ await addArtifact({
28791
+ planId,
28792
+ sessionToken,
28793
+ type: 'screenshot',
28794
+ filename: 'login-page.png',
28795
+ source: 'file',
28796
+ filePath: '/path/to/screenshot.png',
28797
+ deliverableId: deliverables[0].id // Links to specific deliverable
28798
+ });
28799
+
28800
+ const result = await addArtifact({
28801
+ planId,
28802
+ sessionToken,
28803
+ type: 'screenshot',
28804
+ filename: 'error-handling.png',
28805
+ source: 'file',
28806
+ filePath: '/path/to/error.png',
28807
+ deliverableId: deliverables[1].id
28808
+ });
28809
+
28810
+ // Auto-complete triggers when ALL deliverables have artifacts
28811
+ if (result.allDeliverablesComplete) {
28812
+ console.log('Done!', result.snapshotUrl);
28813
+ }
28814
+ \`\`\``;
28815
+ var API_REFERENCE = `## API Reference
28816
+
28817
+ ### createPlan(options)
28818
+
28819
+ Creates a new plan and opens it in the browser.
28820
+
28821
+ **Parameters:**
28822
+ - \`title\` (string) - Plan title
28823
+ - \`content\` (string) - Markdown content with \`{#deliverable}\` markers
28824
+ - \`repo\` (string, optional) - GitHub repo for artifact storage
28825
+ - \`prNumber\` (number, optional) - PR number to link
28826
+
28827
+ **Returns:** \`{ planId, sessionToken, url, deliverables, monitoringScript }\`
28828
+
28829
+ ### readPlan(planId, sessionToken, options?)
28830
+
28831
+ Reads current plan state.
28832
+
28833
+ **Parameters:**
28834
+ - \`planId\` (string) - Plan ID
28835
+ - \`sessionToken\` (string) - Session token from createPlan
28836
+ - \`options.includeAnnotations\` (boolean) - Include reviewer comments
28837
+
28838
+ **Returns:** \`{ content, status, title, deliverables }\`
28839
+
28840
+ ### addArtifact(options)
28841
+
28842
+ Uploads proof-of-work artifact.
28843
+
28844
+ **Parameters:**
28845
+ - \`planId\` (string) - Plan ID
28846
+ - \`sessionToken\` (string) - Session token
28847
+ - \`type\` ('screenshot' | 'video' | 'test_results' | 'diff')
28848
+ - \`filename\` (string) - File name
28849
+ - \`source\` ('file' | 'url' | 'base64')
28850
+ - \`filePath\` (string) - Local file path (when source='file')
28851
+ - \`deliverableId\` (string, optional) - Links artifact to deliverable
28852
+
28853
+ **Returns:** \`{ artifactId, url, allDeliverablesComplete, snapshotUrl? }\`
28854
+
28855
+ ### requestUserInput(options)
28856
+
28857
+ Asks user a question via browser modal.
28858
+
28859
+ **Parameters:**
28860
+ - \`message\` (string) - Question to ask
28861
+ - \`type\` (string) - Input type (see below)
28862
+ - \`options\` (string[], for 'choice') - Available choices
28863
+ - \`timeout\` (number, optional) - Timeout in seconds
28864
+ - Type-specific parameters (min, max, format, etc.)
28865
+
28866
+ **Returns:** \`{ success, response?, status }\`
28867
+
28868
+ **Supported types (8 total):**
28869
+ 1. \`text\` - Single-line text
28870
+ 2. \`multiline\` - Multi-line text area
28871
+ 3. \`choice\` - Radio/checkbox/dropdown (auto-adds "Other" option)
28872
+ - Auto-switches: 1-8 options = radio/checkbox, 9+ = dropdown
28873
+ - \`multiSelect: true\` for checkboxes
28874
+ - \`displayAs: 'dropdown'\` to force dropdown UI
28875
+ 4. \`confirm\` - Yes/No buttons
28876
+ 5. \`number\` - Numeric input with validation
28877
+ - \`min\`, \`max\`, \`format\` ('integer' | 'decimal' | 'currency' | 'percentage')
28878
+ 6. \`email\` - Email validation
28879
+ - \`domain\` for restriction
28880
+ 7. \`date\` - Date picker with range
28881
+ - \`minDate\`, \`maxDate\` (YYYY-MM-DD format)
28882
+ 8. \`rating\` - Scale rating (auto-selects stars/numbers)
28883
+ - \`min\`, \`max\`, \`style\` ('stars' | 'numbers' | 'emoji'), \`labels\`
28884
+
28885
+ **Response format:**
28886
+ - All responses are strings
28887
+ - choice (single): \`"PostgreSQL"\` or custom text from "Other"
28888
+ - choice (multi): \`"option1, option2"\` (comma-space separated)
28889
+ - confirm: \`"yes"\` or \`"no"\` (lowercase)
28890
+ - number: \`"42"\` or \`"3.14"\`
28891
+ - email: \`"user@example.com"\`
28892
+ - date: \`"2026-01-24"\` (ISO 8601)
28893
+ - rating: \`"4"\` (integer as string)
28894
+ - See docs/INPUT-RESPONSE-FORMATS.md for complete specification`;
28895
+ var HANDLING_FEEDBACK = `## Handling Reviewer Feedback
28896
+
28897
+ \`\`\`typescript
28898
+ const status = await readPlan(planId, sessionToken, {
28899
+ includeAnnotations: true
28900
+ });
28901
+
28902
+ if (status.status === "changes_requested") {
28903
+ // Read the content for inline comments
28904
+ console.log(status.content);
28905
+
28906
+ // Make changes based on feedback
28907
+ // Upload new artifacts
28908
+ // Plan will transition back to pending_review
28909
+ }
28910
+ \`\`\``;
28911
+ var MCP_DIRECT_INSTRUCTIONS = [
28912
+ MCP_DIRECT_HEADER,
28913
+ "",
28914
+ CRITICAL_USAGE_SECTION,
28915
+ "",
28916
+ USER_INPUT_SECTION,
28917
+ "",
28918
+ MCP_TOOLS_OVERVIEW,
28919
+ "",
28920
+ MCP_WORKFLOW,
28921
+ "",
28922
+ DELIVERABLES_SECTION,
28923
+ "",
28924
+ ARTIFACT_TYPES_SECTION,
28925
+ "",
28926
+ API_REFERENCE,
28927
+ "",
28928
+ HANDLING_FEEDBACK,
28929
+ "",
28930
+ TIPS_SECTION,
28931
+ "",
28932
+ WHEN_NOT_TO_USE_SECTION,
28933
+ "",
28934
+ TROUBLESHOOTING_SECTION
28935
+ ].join("\n");
28936
+
28491
28937
  // src/adapters/claude-code.ts
28492
28938
  init_cjs_shims();
28493
28939
 
28494
28940
  // ../../packages/schema/dist/index.mjs
28495
28941
  init_cjs_shims();
28496
28942
 
28497
- // ../../packages/schema/dist/yjs-helpers-BBG4tC2R.mjs
28943
+ // ../../packages/schema/dist/yjs-helpers-DxqhtEAu.mjs
28498
28944
  init_cjs_shims();
28499
28945
 
28500
28946
  // ../../packages/schema/dist/plan.mjs
@@ -42532,9 +42978,17 @@ var PlanEventSchema = external_exports.discriminatedUnion("type", [
42532
42978
  "text",
42533
42979
  "multiline",
42534
42980
  "choice",
42535
- "confirm"
42981
+ "confirm",
42982
+ "number",
42983
+ "email",
42984
+ "date",
42985
+ "dropdown",
42986
+ "rating",
42987
+ "multi"
42536
42988
  ]),
42537
- requestMessage: external_exports.string()
42989
+ requestMessage: external_exports.string().optional(),
42990
+ questionCount: external_exports.number().optional(),
42991
+ isBlocker: external_exports.boolean().optional()
42538
42992
  })
42539
42993
  }),
42540
42994
  PlanEventBaseSchema.extend({
@@ -42552,7 +43006,8 @@ var PlanEventSchema = external_exports.discriminatedUnion("type", [
42552
43006
  PlanEventBaseSchema.extend({
42553
43007
  type: external_exports.literal("agent_activity"),
42554
43008
  data: AgentActivityDataSchema
42555
- })
43009
+ }),
43010
+ PlanEventBaseSchema.extend({ type: external_exports.literal("session_token_regenerated") })
42556
43011
  ]);
42557
43012
  var PlanMetadataBaseSchema = external_exports.object({
42558
43013
  id: external_exports.string(),
@@ -42602,10 +43057,9 @@ var PlanMetadataSchema = external_exports.discriminatedUnion("status", [
42602
43057
  var BaseArtifactSchema = external_exports.object({
42603
43058
  id: external_exports.string(),
42604
43059
  type: external_exports.enum([
42605
- "screenshot",
42606
- "video",
42607
- "test_results",
42608
- "diff"
43060
+ "html",
43061
+ "image",
43062
+ "video"
42609
43063
  ]),
42610
43064
  filename: external_exports.string(),
42611
43065
  description: external_exports.string().optional(),
@@ -42665,7 +43119,7 @@ var PRReviewCommentSchema = external_exports.object({
42665
43119
  resolved: external_exports.boolean().optional()
42666
43120
  });
42667
43121
 
42668
- // ../../packages/schema/dist/yjs-helpers-BBG4tC2R.mjs
43122
+ // ../../packages/schema/dist/yjs-helpers-DxqhtEAu.mjs
42669
43123
  function assertNever2(value) {
42670
43124
  throw new Error(`Unhandled discriminated union member: ${JSON.stringify(value)}`);
42671
43125
  }
@@ -42770,26 +43224,161 @@ var InputRequestBaseSchema = external_exports.object({
42770
43224
  message: external_exports.string().min(1, "Message cannot be empty"),
42771
43225
  status: external_exports.enum(InputRequestStatusValues),
42772
43226
  defaultValue: external_exports.string().optional(),
42773
- timeout: external_exports.number().int().min(10, "Timeout must be at least 10 seconds").max(14400, "Timeout cannot exceed 4 hours").optional(),
43227
+ timeout: external_exports.number().int().min(300, "Timeout must be at least 5 minutes (300 seconds)").max(1800, "Timeout cannot exceed 30 minutes (1800 seconds)").optional(),
42774
43228
  planId: external_exports.string().optional(),
42775
43229
  response: external_exports.unknown().optional(),
42776
43230
  answeredAt: external_exports.number().optional(),
42777
- answeredBy: external_exports.string().optional()
43231
+ answeredBy: external_exports.string().optional(),
43232
+ isBlocker: external_exports.boolean().optional()
42778
43233
  });
42779
43234
  var TextInputSchema = InputRequestBaseSchema.extend({ type: external_exports.literal("text") });
42780
43235
  var MultilineInputSchema = InputRequestBaseSchema.extend({ type: external_exports.literal("multiline") });
43236
+ var ChoiceOptionSchema = external_exports.union([external_exports.string(), external_exports.object({
43237
+ value: external_exports.string(),
43238
+ label: external_exports.string().optional(),
43239
+ description: external_exports.string().optional(),
43240
+ icon: external_exports.string().optional(),
43241
+ disabled: external_exports.boolean().optional()
43242
+ })]);
42781
43243
  var ChoiceInputSchema = InputRequestBaseSchema.extend({
42782
43244
  type: external_exports.literal("choice"),
42783
- options: external_exports.array(external_exports.string()).min(1, "Choice requests must have at least one option"),
42784
- multiSelect: external_exports.boolean().optional()
43245
+ options: external_exports.array(ChoiceOptionSchema).min(1, "Choice requests must have at least one option"),
43246
+ multiSelect: external_exports.boolean().optional(),
43247
+ displayAs: external_exports.enum([
43248
+ "radio",
43249
+ "checkbox",
43250
+ "dropdown"
43251
+ ]).optional(),
43252
+ placeholder: external_exports.string().optional()
42785
43253
  });
42786
43254
  var ConfirmInputSchema = InputRequestBaseSchema.extend({ type: external_exports.literal("confirm") });
43255
+ var NumberInputSchema = InputRequestBaseSchema.extend({
43256
+ type: external_exports.literal("number"),
43257
+ min: external_exports.number().optional(),
43258
+ max: external_exports.number().optional(),
43259
+ format: external_exports.enum([
43260
+ "integer",
43261
+ "decimal",
43262
+ "currency",
43263
+ "percentage"
43264
+ ]).optional()
43265
+ }).refine((data) => data.min === void 0 || data.max === void 0 || data.min <= data.max, { message: "min must be <= max" });
43266
+ var EmailInputSchema = InputRequestBaseSchema.extend({
43267
+ type: external_exports.literal("email"),
43268
+ domain: external_exports.string().optional()
43269
+ });
43270
+ var DateInputSchema = InputRequestBaseSchema.extend({
43271
+ type: external_exports.literal("date"),
43272
+ min: external_exports.string().regex(/^\d{4}-\d{2}-\d{2}$/, "Date must be in YYYY-MM-DD format").optional(),
43273
+ max: external_exports.string().regex(/^\d{4}-\d{2}-\d{2}$/, "Date must be in YYYY-MM-DD format").optional()
43274
+ }).refine((data) => data.min === void 0 || data.max === void 0 || new Date(data.min) <= new Date(data.max), { message: "min date must be before or equal to max date" });
43275
+ var RatingInputSchema = InputRequestBaseSchema.extend({
43276
+ type: external_exports.literal("rating"),
43277
+ min: external_exports.number().int().optional(),
43278
+ max: external_exports.number().int().optional(),
43279
+ style: external_exports.enum([
43280
+ "stars",
43281
+ "numbers",
43282
+ "emoji"
43283
+ ]).optional(),
43284
+ labels: external_exports.object({
43285
+ low: external_exports.string().optional(),
43286
+ high: external_exports.string().optional()
43287
+ }).optional()
43288
+ }).refine((data) => {
43289
+ if (data.min === void 0 || data.max === void 0) return true;
43290
+ return data.min <= data.max && data.max - data.min <= 20;
43291
+ }, { message: "Rating scale must have min <= max and at most 20 items" });
42787
43292
  var InputRequestSchema = external_exports.discriminatedUnion("type", [
42788
43293
  TextInputSchema,
42789
43294
  MultilineInputSchema,
42790
43295
  ChoiceInputSchema,
42791
- ConfirmInputSchema
43296
+ ConfirmInputSchema,
43297
+ NumberInputSchema,
43298
+ EmailInputSchema,
43299
+ DateInputSchema,
43300
+ RatingInputSchema
42792
43301
  ]);
43302
+ var MAX_QUESTIONS_PER_REQUEST = 10;
43303
+ var QuestionBaseSchema = external_exports.object({
43304
+ message: external_exports.string().min(1, "Message cannot be empty"),
43305
+ defaultValue: external_exports.string().optional()
43306
+ });
43307
+ var TextQuestionSchema = QuestionBaseSchema.extend({ type: external_exports.literal("text") });
43308
+ var MultilineQuestionSchema = QuestionBaseSchema.extend({ type: external_exports.literal("multiline") });
43309
+ var ChoiceQuestionSchema = QuestionBaseSchema.extend({
43310
+ type: external_exports.literal("choice"),
43311
+ options: external_exports.array(ChoiceOptionSchema).min(1, "Choice questions must have at least one option"),
43312
+ multiSelect: external_exports.boolean().optional(),
43313
+ displayAs: external_exports.enum([
43314
+ "radio",
43315
+ "checkbox",
43316
+ "dropdown"
43317
+ ]).optional(),
43318
+ placeholder: external_exports.string().optional()
43319
+ });
43320
+ var ConfirmQuestionSchema = QuestionBaseSchema.extend({ type: external_exports.literal("confirm") });
43321
+ var NumberQuestionSchema = QuestionBaseSchema.extend({
43322
+ type: external_exports.literal("number"),
43323
+ min: external_exports.number().optional(),
43324
+ max: external_exports.number().optional(),
43325
+ format: external_exports.enum([
43326
+ "integer",
43327
+ "decimal",
43328
+ "currency",
43329
+ "percentage"
43330
+ ]).optional()
43331
+ }).refine((data) => data.min === void 0 || data.max === void 0 || data.min <= data.max, { message: "min must be <= max" });
43332
+ var EmailQuestionSchema = QuestionBaseSchema.extend({
43333
+ type: external_exports.literal("email"),
43334
+ domain: external_exports.string().optional()
43335
+ });
43336
+ var DateQuestionSchema = QuestionBaseSchema.extend({
43337
+ type: external_exports.literal("date"),
43338
+ min: external_exports.string().regex(/^\d{4}-\d{2}-\d{2}$/, "Date must be in YYYY-MM-DD format").optional(),
43339
+ max: external_exports.string().regex(/^\d{4}-\d{2}-\d{2}$/, "Date must be in YYYY-MM-DD format").optional()
43340
+ }).refine((data) => data.min === void 0 || data.max === void 0 || new Date(data.min) <= new Date(data.max), { message: "min date must be before or equal to max date" });
43341
+ var RatingQuestionSchema = QuestionBaseSchema.extend({
43342
+ type: external_exports.literal("rating"),
43343
+ min: external_exports.number().int().optional(),
43344
+ max: external_exports.number().int().optional(),
43345
+ style: external_exports.enum([
43346
+ "stars",
43347
+ "numbers",
43348
+ "emoji"
43349
+ ]).optional(),
43350
+ labels: external_exports.object({
43351
+ low: external_exports.string().optional(),
43352
+ high: external_exports.string().optional()
43353
+ }).optional()
43354
+ }).refine((data) => {
43355
+ if (data.min === void 0 || data.max === void 0) return true;
43356
+ return data.min <= data.max && data.max - data.min <= 20;
43357
+ }, { message: "Rating scale must have min <= max and at most 20 items" });
43358
+ var QuestionSchema = external_exports.discriminatedUnion("type", [
43359
+ TextQuestionSchema,
43360
+ MultilineQuestionSchema,
43361
+ ChoiceQuestionSchema,
43362
+ ConfirmQuestionSchema,
43363
+ NumberQuestionSchema,
43364
+ EmailQuestionSchema,
43365
+ DateQuestionSchema,
43366
+ RatingQuestionSchema
43367
+ ]);
43368
+ var MultiQuestionInputRequestSchema = external_exports.object({
43369
+ id: external_exports.string(),
43370
+ createdAt: external_exports.number(),
43371
+ type: external_exports.literal("multi"),
43372
+ questions: external_exports.array(QuestionSchema).min(1, "At least one question is required").max(MAX_QUESTIONS_PER_REQUEST, `Maximum ${MAX_QUESTIONS_PER_REQUEST} questions allowed (8 recommended for optimal UX)`),
43373
+ status: external_exports.enum(InputRequestStatusValues),
43374
+ timeout: external_exports.number().int().min(10, "Timeout must be at least 10 seconds").max(14400, "Timeout cannot exceed 4 hours").optional(),
43375
+ planId: external_exports.string().optional(),
43376
+ responses: external_exports.record(external_exports.string(), external_exports.unknown()).optional(),
43377
+ answeredAt: external_exports.number().optional(),
43378
+ answeredBy: external_exports.string().optional(),
43379
+ isBlocker: external_exports.boolean().optional()
43380
+ });
43381
+ var AnyInputRequestSchema = external_exports.union([InputRequestSchema, MultiQuestionInputRequestSchema]);
42793
43382
  var YDOC_KEYS = {
42794
43383
  METADATA: "metadata",
42795
43384
  DOCUMENT_FRAGMENT: "document",
@@ -43792,6 +44381,29 @@ var GitHubPRResponseSchema = external_exports.object({
43792
44381
  merged: external_exports.boolean(),
43793
44382
  head: external_exports.object({ ref: external_exports.string() })
43794
44383
  });
44384
+ var ROUTES = {
44385
+ REGISTRY_LIST: "/registry",
44386
+ REGISTRY_REGISTER: "/register",
44387
+ REGISTRY_UNREGISTER: "/unregister",
44388
+ PLAN_STATUS: (planId) => `/api/plan/${planId}/status`,
44389
+ PLAN_HAS_CONNECTIONS: (planId) => `/api/plan/${planId}/has-connections`,
44390
+ PLAN_TRANSCRIPT: (planId) => `/api/plan/${planId}/transcript`,
44391
+ PLAN_SUBSCRIBE: (planId) => `/api/plan/${planId}/subscribe`,
44392
+ PLAN_CHANGES: (planId) => `/api/plan/${planId}/changes`,
44393
+ PLAN_UNSUBSCRIBE: (planId) => `/api/plan/${planId}/unsubscribe`,
44394
+ PLAN_PR_DIFF: (planId, prNumber) => `/api/plans/${planId}/pr-diff/${prNumber}`,
44395
+ PLAN_PR_FILES: (planId, prNumber) => `/api/plans/${planId}/pr-files/${prNumber}`,
44396
+ HOOK_SESSION: "/api/hook/session",
44397
+ HOOK_CONTENT: (planId) => `/api/hook/plan/${planId}/content`,
44398
+ HOOK_REVIEW: (planId) => `/api/hook/plan/${planId}/review`,
44399
+ HOOK_SESSION_TOKEN: (planId) => `/api/hook/plan/${planId}/session-token`,
44400
+ HOOK_PRESENCE: (planId) => `/api/hook/plan/${planId}/presence`,
44401
+ CONVERSATION_IMPORT: "/api/conversation/import",
44402
+ WEB_TASK: (planId) => `/task/${planId}`
44403
+ };
44404
+ function createPlanWebUrl(baseUrl, planId) {
44405
+ return `${baseUrl.replace(/\/$/, "")}${ROUTES.WEB_TASK(planId)}`;
44406
+ }
43795
44407
  var InviteTokenSchema = external_exports.object({
43796
44408
  id: external_exports.string(),
43797
44409
  tokenHash: external_exports.string(),
@@ -43809,6 +44421,42 @@ var InviteRedemptionSchema = external_exports.object({
43809
44421
  redeemedAt: external_exports.number(),
43810
44422
  tokenId: external_exports.string()
43811
44423
  });
44424
+ var GitFileStatusSchema = external_exports.enum([
44425
+ "added",
44426
+ "modified",
44427
+ "deleted",
44428
+ "renamed",
44429
+ "copied",
44430
+ "untracked"
44431
+ ]);
44432
+ var LocalFileChangeSchema = external_exports.object({
44433
+ path: external_exports.string(),
44434
+ status: GitFileStatusSchema,
44435
+ additions: external_exports.number(),
44436
+ deletions: external_exports.number(),
44437
+ patch: external_exports.string().optional()
44438
+ });
44439
+ var LocalChangesResponseSchema = external_exports.object({
44440
+ available: external_exports.literal(true),
44441
+ branch: external_exports.string(),
44442
+ baseBranch: external_exports.string(),
44443
+ staged: external_exports.array(LocalFileChangeSchema),
44444
+ unstaged: external_exports.array(LocalFileChangeSchema),
44445
+ untracked: external_exports.array(external_exports.string()),
44446
+ files: external_exports.array(LocalFileChangeSchema)
44447
+ });
44448
+ var LocalChangesUnavailableReasonSchema = external_exports.enum([
44449
+ "no_cwd",
44450
+ "not_git_repo",
44451
+ "mcp_not_connected",
44452
+ "git_error"
44453
+ ]);
44454
+ var LocalChangesUnavailableSchema = external_exports.object({
44455
+ available: external_exports.literal(false),
44456
+ reason: LocalChangesUnavailableReasonSchema,
44457
+ message: external_exports.string()
44458
+ });
44459
+ var LocalChangesResultSchema = external_exports.discriminatedUnion("available", [LocalChangesResponseSchema, LocalChangesUnavailableSchema]);
43812
44460
  var ConversationExportStartMetaSchema = external_exports.object({
43813
44461
  exportId: external_exports.string(),
43814
44462
  totalChunks: external_exports.number().int().positive(),
@@ -43882,6 +44530,20 @@ function truncate(text, maxLength) {
43882
44530
  if (cleaned.length <= maxLength) return cleaned;
43883
44531
  return `${cleaned.slice(0, maxLength)}...`;
43884
44532
  }
44533
+ var TOOL_NAMES2 = {
44534
+ ADD_ARTIFACT: "add_artifact",
44535
+ ADD_PR_REVIEW_COMMENT: "add_pr_review_comment",
44536
+ COMPLETE_TASK: "complete_task",
44537
+ CREATE_PLAN: "create_plan",
44538
+ EXECUTE_CODE: "execute_code",
44539
+ LINK_PR: "link_pr",
44540
+ READ_PLAN: "read_plan",
44541
+ REGENERATE_SESSION_TOKEN: "regenerate_session_token",
44542
+ REQUEST_USER_INPUT: "request_user_input",
44543
+ SETUP_REVIEW_NOTIFICATION: "setup_review_notification",
44544
+ UPDATE_BLOCK_CONTENT: "update_block_content",
44545
+ UPDATE_PLAN: "update_plan"
44546
+ };
43885
44547
  var PlanIdSchema = external_exports.object({ planId: external_exports.string().min(1) });
43886
44548
  var PlanStatusResponseSchema = external_exports.object({ status: external_exports.string() });
43887
44549
  var HasConnectionsResponseSchema = external_exports.object({ hasConnections: external_exports.boolean() });
@@ -44004,6 +44666,41 @@ var planRouter = router({
44004
44666
  }),
44005
44667
  hasConnections: publicProcedure.input(PlanIdSchema).output(HasConnectionsResponseSchema).query(async ({ input, ctx }) => {
44006
44668
  return { hasConnections: await ctx.getPlanStore().hasActiveConnections(input.planId) };
44669
+ }),
44670
+ getLocalChanges: publicProcedure.input(PlanIdSchema).output(LocalChangesResultSchema).query(async ({ input, ctx }) => {
44671
+ const metadata = getPlanMetadata(await ctx.getOrCreateDoc(input.planId));
44672
+ if (!metadata) throw new TRPCError({
44673
+ code: "NOT_FOUND",
44674
+ message: "Plan not found"
44675
+ });
44676
+ const origin = metadata.origin;
44677
+ const cwd = origin?.platform === "claude-code" ? origin.cwd : void 0;
44678
+ if (!cwd) return {
44679
+ available: false,
44680
+ reason: "no_cwd",
44681
+ message: "Plan has no associated working directory. Local changes are only available for plans created with working directory metadata."
44682
+ };
44683
+ return ctx.getLocalChanges(cwd);
44684
+ }),
44685
+ getFileContent: publicProcedure.input(external_exports.object({
44686
+ planId: PlanIdSchema.shape.planId,
44687
+ filePath: external_exports.string()
44688
+ })).output(external_exports.object({
44689
+ content: external_exports.string().nullable(),
44690
+ error: external_exports.string().optional()
44691
+ })).query(async ({ input, ctx }) => {
44692
+ const metadata = getPlanMetadata(await ctx.getOrCreateDoc(input.planId));
44693
+ if (!metadata) throw new TRPCError({
44694
+ code: "NOT_FOUND",
44695
+ message: "Plan not found"
44696
+ });
44697
+ const origin = metadata.origin;
44698
+ const cwd = origin?.platform === "claude-code" ? origin.cwd : void 0;
44699
+ if (!cwd) return {
44700
+ content: null,
44701
+ error: "No working directory available"
44702
+ };
44703
+ return ctx.getFileContent(cwd, input.filePath);
44007
44704
  })
44008
44705
  });
44009
44706
  var subscriptionRouter = router({
@@ -44046,9 +44743,6 @@ var CLAUDE_TOOL_NAMES = {
44046
44743
  EXIT_PLAN_MODE: "ExitPlanMode",
44047
44744
  ASK_USER_QUESTION: "AskUserQuestion"
44048
44745
  };
44049
- var MCP_TOOL_NAMES = {
44050
- REQUEST_USER_INPUT: "request_user_input"
44051
- };
44052
44746
  var CLAUDE_PERMISSION_MODES = {
44053
44747
  PLAN: "plan",
44054
44748
  DEFAULT: "default",
@@ -44145,7 +44839,7 @@ function handlePreToolUse(input) {
44145
44839
  );
44146
44840
  return {
44147
44841
  type: "tool_deny",
44148
- reason: `BLOCKED: Use the ${MCP_TOOL_NAMES.REQUEST_USER_INPUT} MCP tool instead for consistent browser UI. See the tool description for available parameters.`
44842
+ reason: `BLOCKED: Use the ${TOOL_NAMES2.REQUEST_USER_INPUT} MCP tool instead. The human is in the browser viewing your plan - that's where they expect to interact with you. See the tool description for input types and parameters.`
44149
44843
  };
44150
44844
  }
44151
44845
  return { type: "passthrough" };
@@ -45749,7 +46443,7 @@ async function handleUpdatedPlanReview(sessionId, planId, planContent, _originMe
45749
46443
  }
45750
46444
  const baseUrl = webConfig.SHIPYARD_WEB_URL;
45751
46445
  logger.info(
45752
- { planId, url: `${baseUrl}/plan/${planId}` },
46446
+ { planId, url: createPlanWebUrl(baseUrl, planId) },
45753
46447
  "Content synced, browser already open. Waiting for server approval..."
45754
46448
  );
45755
46449
  const decision = await waitForReviewDecision(planId, "");
@@ -45906,7 +46600,7 @@ Reviewer comment: ${decision.reviewComment}` : "";
45906
46600
  allow: false,
45907
46601
  message: `Plan is pending review.
45908
46602
 
45909
- Open: ${baseUrl}/plan/${planId}`,
46603
+ Open: ${createPlanWebUrl(baseUrl, planId)}`,
45910
46604
  planId
45911
46605
  };
45912
46606
  case "draft":
@@ -45914,7 +46608,7 @@ Open: ${baseUrl}/plan/${planId}`,
45914
46608
  allow: false,
45915
46609
  message: `Plan is still in draft.
45916
46610
 
45917
- Submit for review at: ${baseUrl}/plan/${planId}`,
46611
+ Submit for review at: ${createPlanWebUrl(baseUrl, planId)}`,
45918
46612
  planId
45919
46613
  };
45920
46614
  case "in_progress":
@@ -46071,46 +46765,10 @@ async function readStdin() {
46071
46765
  return Buffer.concat(chunks).toString("utf-8");
46072
46766
  }
46073
46767
  function outputSessionStartContext() {
46074
- const context = `[SHIPYARD] Collaborative planning with human review & proof-of-work tracking.
46075
-
46076
- IMPORTANT: Use native plan mode (Shift+Tab) to create plans. The hook handles everything automatically.
46077
-
46078
- ## What are Deliverables?
46079
-
46080
- Deliverables are measurable outcomes you can prove with artifacts (screenshots, videos, test results).
46081
-
46082
- Good deliverables (provable):
46083
- \`\`\`
46084
- - [ ] Screenshot of working login page {#deliverable}
46085
- - [ ] Video showing feature in action {#deliverable}
46086
- - [ ] Test results showing all tests pass {#deliverable}
46087
- \`\`\`
46088
-
46089
- Bad deliverables (implementation details, not provable):
46090
- \`\`\`
46091
- - [ ] Implement getUserMedia API \u2190 This is a task, not a deliverable
46092
- - [ ] Add error handling \u2190 Can't prove this with an artifact
46093
- \`\`\`
46094
-
46095
- ## Workflow
46096
-
46097
- 1. Enter plan mode (Shift+Tab) \u2192 Browser opens with live plan
46098
- 2. Write plan with {#deliverable} markers for provable outcomes
46099
- 3. Exit plan mode \u2192 Hook BLOCKS until human approves
46100
- 4. On approval \u2192 You receive planId, sessionToken, and deliverable IDs
46101
- 5. Do work \u2192 Take screenshots/videos as you go
46102
- 6. \`add_artifact(filePath, deliverableId)\` for each deliverable
46103
- 7. When all deliverables fulfilled \u2192 Auto-completes with snapshot URL
46104
-
46105
- ## After Approval
46106
-
46107
- You only need ONE tool: \`add_artifact\`
46108
-
46109
- When the last deliverable gets an artifact, the task auto-completes and returns a snapshot URL for your PR.`;
46110
46768
  const hookOutput = {
46111
46769
  hookSpecificOutput: {
46112
46770
  hookEventName: "SessionStart",
46113
- additionalContext: context
46771
+ additionalContext: CLAUDE_CODE_INSTRUCTIONS
46114
46772
  }
46115
46773
  };
46116
46774
  console.log(JSON.stringify(hookOutput));