@schoolai/shipyard-mcp 0.3.2 → 0.4.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.
- package/README.md +199 -114
- package/apps/hook/dist/index.cjs +971 -675
- package/apps/server/dist/chunk-6EWQC5VA.js +5690 -0
- package/apps/server/dist/{chunk-EBNL5ZX7.js → chunk-HFZCBGQ3.js} +85 -3
- package/apps/server/dist/index.js +1508 -4533
- package/apps/server/dist/{chunk-GDVRDX7Z.js → input-request-manager-QT4IVCLS.js} +93 -39
- package/apps/server/dist/{session-registry-DMV543RG.js → session-registry-CBDXMXY3.js} +1 -3
- package/package.json +1 -1
- package/apps/server/dist/chunk-GSGLHRWX.js +0 -62
- package/apps/server/dist/chunk-I7UCM5RO.js +0 -3427
- package/apps/server/dist/chunk-JSBRDJBE.js +0 -30
- package/apps/server/dist/dist-QXOKL75H.js +0 -451
- package/apps/server/dist/input-request-manager-IF6M76G4.js +0 -9
package/apps/hook/dist/index.cjs
CHANGED
|
@@ -5970,7 +5970,7 @@ var require_util = __commonJS({
|
|
|
5970
5970
|
return state && state.objectMode === false && state.ended === true && Number.isFinite(state.length) ? state.length : null;
|
|
5971
5971
|
} else if (isBlobLike(body)) {
|
|
5972
5972
|
return body.size != null ? body.size : null;
|
|
5973
|
-
} else if (
|
|
5973
|
+
} else if (isBuffer2(body)) {
|
|
5974
5974
|
return body.byteLength;
|
|
5975
5975
|
}
|
|
5976
5976
|
return null;
|
|
@@ -6065,7 +6065,7 @@ var require_util = __commonJS({
|
|
|
6065
6065
|
}
|
|
6066
6066
|
return headers.map((x) => Buffer.from(x));
|
|
6067
6067
|
}
|
|
6068
|
-
function
|
|
6068
|
+
function isBuffer2(buffer) {
|
|
6069
6069
|
return buffer instanceof Uint8Array || Buffer.isBuffer(buffer);
|
|
6070
6070
|
}
|
|
6071
6071
|
function assertRequestHandler(handler, method, upgrade) {
|
|
@@ -6586,7 +6586,7 @@ var require_util = __commonJS({
|
|
|
6586
6586
|
bodyLength,
|
|
6587
6587
|
deepClone,
|
|
6588
6588
|
ReadableStreamFrom,
|
|
6589
|
-
isBuffer,
|
|
6589
|
+
isBuffer: isBuffer2,
|
|
6590
6590
|
assertRequestHandler,
|
|
6591
6591
|
getSocketInfo,
|
|
6592
6592
|
isFormDataLike,
|
|
@@ -6877,7 +6877,7 @@ var require_request = __commonJS({
|
|
|
6877
6877
|
isValidHeaderValue,
|
|
6878
6878
|
isStream,
|
|
6879
6879
|
destroy,
|
|
6880
|
-
isBuffer,
|
|
6880
|
+
isBuffer: isBuffer2,
|
|
6881
6881
|
isFormDataLike,
|
|
6882
6882
|
isIterable,
|
|
6883
6883
|
isBlobLike,
|
|
@@ -6965,7 +6965,7 @@ var require_request = __commonJS({
|
|
|
6965
6965
|
}
|
|
6966
6966
|
};
|
|
6967
6967
|
this.body.on("error", this.errorHandler);
|
|
6968
|
-
} else if (
|
|
6968
|
+
} else if (isBuffer2(body)) {
|
|
6969
6969
|
this.body = body.byteLength ? body : null;
|
|
6970
6970
|
} else if (ArrayBuffer.isView(body)) {
|
|
6971
6971
|
this.body = body.buffer.byteLength ? Buffer.from(body.buffer, body.byteOffset, body.byteLength) : null;
|
|
@@ -28488,459 +28488,10 @@ 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
|
-
|
|
28937
|
-
// src/adapters/claude-code.ts
|
|
28938
|
-
init_cjs_shims();
|
|
28939
|
-
|
|
28940
28491
|
// ../../packages/schema/dist/index.mjs
|
|
28941
28492
|
init_cjs_shims();
|
|
28942
28493
|
|
|
28943
|
-
// ../../packages/schema/dist/yjs-helpers-
|
|
28494
|
+
// ../../packages/schema/dist/yjs-helpers-CmikQBE7.mjs
|
|
28944
28495
|
init_cjs_shims();
|
|
28945
28496
|
|
|
28946
28497
|
// ../../packages/schema/dist/plan.mjs
|
|
@@ -42837,7 +42388,10 @@ var CursorOriginMetadataSchema = external_exports.object({
|
|
|
42837
42388
|
conversationId: external_exports.string(),
|
|
42838
42389
|
generationId: external_exports.string().optional()
|
|
42839
42390
|
});
|
|
42840
|
-
var UnknownOriginMetadataSchema = external_exports.object({
|
|
42391
|
+
var UnknownOriginMetadataSchema = external_exports.object({
|
|
42392
|
+
platform: external_exports.literal("unknown"),
|
|
42393
|
+
cwd: external_exports.string()
|
|
42394
|
+
});
|
|
42841
42395
|
var OriginMetadataSchema = external_exports.discriminatedUnion("platform", [
|
|
42842
42396
|
ClaudeCodeOriginMetadataSchema,
|
|
42843
42397
|
DevinOriginMetadataSchema,
|
|
@@ -42864,28 +42418,10 @@ var PlanEventBaseSchema = external_exports.object({
|
|
|
42864
42418
|
inboxWorthy: external_exports.boolean().optional(),
|
|
42865
42419
|
inboxFor: external_exports.union([external_exports.string(), external_exports.array(external_exports.string())]).optional()
|
|
42866
42420
|
});
|
|
42867
|
-
var AgentActivityDataSchema = external_exports.
|
|
42868
|
-
external_exports.
|
|
42869
|
-
|
|
42870
|
-
|
|
42871
|
-
message: external_exports.string()
|
|
42872
|
-
}),
|
|
42873
|
-
external_exports.object({
|
|
42874
|
-
activityType: external_exports.literal("help_request_resolved"),
|
|
42875
|
-
requestId: external_exports.string(),
|
|
42876
|
-
resolution: external_exports.string().optional()
|
|
42877
|
-
}),
|
|
42878
|
-
external_exports.object({
|
|
42879
|
-
activityType: external_exports.literal("blocker"),
|
|
42880
|
-
message: external_exports.string(),
|
|
42881
|
-
requestId: external_exports.string()
|
|
42882
|
-
}),
|
|
42883
|
-
external_exports.object({
|
|
42884
|
-
activityType: external_exports.literal("blocker_resolved"),
|
|
42885
|
-
requestId: external_exports.string(),
|
|
42886
|
-
resolution: external_exports.string().optional()
|
|
42887
|
-
})
|
|
42888
|
-
]);
|
|
42421
|
+
var AgentActivityDataSchema = external_exports.object({
|
|
42422
|
+
activityType: external_exports.literal("update"),
|
|
42423
|
+
message: external_exports.string()
|
|
42424
|
+
});
|
|
42889
42425
|
var PlanEventSchema = external_exports.discriminatedUnion("type", [
|
|
42890
42426
|
PlanEventBaseSchema.extend({ type: external_exports.enum([
|
|
42891
42427
|
"plan_created",
|
|
@@ -42996,7 +42532,19 @@ var PlanEventSchema = external_exports.discriminatedUnion("type", [
|
|
|
42996
42532
|
data: external_exports.object({
|
|
42997
42533
|
requestId: external_exports.string(),
|
|
42998
42534
|
response: external_exports.unknown(),
|
|
42999
|
-
answeredBy: external_exports.string()
|
|
42535
|
+
answeredBy: external_exports.string(),
|
|
42536
|
+
requestMessage: external_exports.string().optional(),
|
|
42537
|
+
requestType: external_exports.enum([
|
|
42538
|
+
"text",
|
|
42539
|
+
"multiline",
|
|
42540
|
+
"choice",
|
|
42541
|
+
"confirm",
|
|
42542
|
+
"number",
|
|
42543
|
+
"email",
|
|
42544
|
+
"date",
|
|
42545
|
+
"rating",
|
|
42546
|
+
"multi"
|
|
42547
|
+
]).optional()
|
|
43000
42548
|
})
|
|
43001
42549
|
}),
|
|
43002
42550
|
PlanEventBaseSchema.extend({
|
|
@@ -43118,11 +42666,74 @@ var PRReviewCommentSchema = external_exports.object({
|
|
|
43118
42666
|
createdAt: external_exports.number(),
|
|
43119
42667
|
resolved: external_exports.boolean().optional()
|
|
43120
42668
|
});
|
|
42669
|
+
var LocalDiffCommentSchema = external_exports.object({
|
|
42670
|
+
id: external_exports.string(),
|
|
42671
|
+
type: external_exports.literal("local"),
|
|
42672
|
+
path: external_exports.string(),
|
|
42673
|
+
line: external_exports.number(),
|
|
42674
|
+
body: external_exports.string(),
|
|
42675
|
+
author: external_exports.string(),
|
|
42676
|
+
createdAt: external_exports.number(),
|
|
42677
|
+
baseRef: external_exports.string(),
|
|
42678
|
+
resolved: external_exports.boolean().optional(),
|
|
42679
|
+
lineContentHash: external_exports.string().optional(),
|
|
42680
|
+
machineId: external_exports.string().optional()
|
|
42681
|
+
});
|
|
42682
|
+
var GitHubArtifactParseSchema = external_exports.object({
|
|
42683
|
+
id: external_exports.string(),
|
|
42684
|
+
type: external_exports.enum([
|
|
42685
|
+
"html",
|
|
42686
|
+
"image",
|
|
42687
|
+
"video"
|
|
42688
|
+
]),
|
|
42689
|
+
filename: external_exports.string(),
|
|
42690
|
+
description: external_exports.string().optional(),
|
|
42691
|
+
uploadedAt: external_exports.number().optional(),
|
|
42692
|
+
storage: external_exports.literal("github"),
|
|
42693
|
+
url: external_exports.string()
|
|
42694
|
+
});
|
|
42695
|
+
var LocalArtifactParseSchema = external_exports.object({
|
|
42696
|
+
id: external_exports.string(),
|
|
42697
|
+
type: external_exports.enum([
|
|
42698
|
+
"html",
|
|
42699
|
+
"image",
|
|
42700
|
+
"video"
|
|
42701
|
+
]),
|
|
42702
|
+
filename: external_exports.string(),
|
|
42703
|
+
description: external_exports.string().optional(),
|
|
42704
|
+
uploadedAt: external_exports.number().optional(),
|
|
42705
|
+
storage: external_exports.literal("local"),
|
|
42706
|
+
localArtifactId: external_exports.string()
|
|
42707
|
+
});
|
|
43121
42708
|
|
|
43122
|
-
// ../../packages/schema/dist/yjs-helpers-
|
|
42709
|
+
// ../../packages/schema/dist/yjs-helpers-CmikQBE7.mjs
|
|
43123
42710
|
function assertNever2(value) {
|
|
43124
42711
|
throw new Error(`Unhandled discriminated union member: ${JSON.stringify(value)}`);
|
|
43125
42712
|
}
|
|
42713
|
+
var SyncedFileChangeSchema = external_exports.object({
|
|
42714
|
+
path: external_exports.string(),
|
|
42715
|
+
status: external_exports.enum([
|
|
42716
|
+
"added",
|
|
42717
|
+
"modified",
|
|
42718
|
+
"deleted",
|
|
42719
|
+
"renamed"
|
|
42720
|
+
]),
|
|
42721
|
+
patch: external_exports.string(),
|
|
42722
|
+
staged: external_exports.boolean()
|
|
42723
|
+
});
|
|
42724
|
+
var ChangeSnapshotSchema = external_exports.object({
|
|
42725
|
+
machineId: external_exports.string(),
|
|
42726
|
+
machineName: external_exports.string(),
|
|
42727
|
+
ownerId: external_exports.string(),
|
|
42728
|
+
headSha: external_exports.string(),
|
|
42729
|
+
branch: external_exports.string(),
|
|
42730
|
+
cwd: external_exports.string(),
|
|
42731
|
+
isLive: external_exports.boolean(),
|
|
42732
|
+
updatedAt: external_exports.number(),
|
|
42733
|
+
files: external_exports.array(SyncedFileChangeSchema),
|
|
42734
|
+
totalAdditions: external_exports.number(),
|
|
42735
|
+
totalDeletions: external_exports.number()
|
|
42736
|
+
});
|
|
43126
42737
|
var AgentPresenceSchema = external_exports.object({
|
|
43127
42738
|
agentType: external_exports.string(),
|
|
43128
42739
|
sessionId: external_exports.string(),
|
|
@@ -43205,8 +42816,15 @@ var UnregisterServerResponseSchema = external_exports.object({
|
|
|
43205
42816
|
success: external_exports.boolean(),
|
|
43206
42817
|
existed: external_exports.boolean()
|
|
43207
42818
|
});
|
|
42819
|
+
var ChangeTypeSchema = external_exports.enum([
|
|
42820
|
+
"status",
|
|
42821
|
+
"comments",
|
|
42822
|
+
"resolved",
|
|
42823
|
+
"content",
|
|
42824
|
+
"artifacts"
|
|
42825
|
+
]);
|
|
43208
42826
|
var CreateSubscriptionRequestSchema = external_exports.object({
|
|
43209
|
-
subscribe: external_exports.array(
|
|
42827
|
+
subscribe: external_exports.array(ChangeTypeSchema).optional(),
|
|
43210
42828
|
windowMs: external_exports.number().positive().optional(),
|
|
43211
42829
|
maxWindowMs: external_exports.number().positive().optional(),
|
|
43212
42830
|
threshold: external_exports.number().positive().optional()
|
|
@@ -43318,7 +42936,7 @@ var ChoiceQuestionSchema = QuestionBaseSchema.extend({
|
|
|
43318
42936
|
placeholder: external_exports.string().optional()
|
|
43319
42937
|
});
|
|
43320
42938
|
var ConfirmQuestionSchema = QuestionBaseSchema.extend({ type: external_exports.literal("confirm") });
|
|
43321
|
-
var
|
|
42939
|
+
var NumberQuestionBaseSchema = QuestionBaseSchema.extend({
|
|
43322
42940
|
type: external_exports.literal("number"),
|
|
43323
42941
|
min: external_exports.number().optional(),
|
|
43324
42942
|
max: external_exports.number().optional(),
|
|
@@ -43328,17 +42946,17 @@ var NumberQuestionSchema = QuestionBaseSchema.extend({
|
|
|
43328
42946
|
"currency",
|
|
43329
42947
|
"percentage"
|
|
43330
42948
|
]).optional()
|
|
43331
|
-
})
|
|
42949
|
+
});
|
|
43332
42950
|
var EmailQuestionSchema = QuestionBaseSchema.extend({
|
|
43333
42951
|
type: external_exports.literal("email"),
|
|
43334
42952
|
domain: external_exports.string().optional()
|
|
43335
42953
|
});
|
|
43336
|
-
var
|
|
42954
|
+
var DateQuestionBaseSchema = QuestionBaseSchema.extend({
|
|
43337
42955
|
type: external_exports.literal("date"),
|
|
43338
42956
|
min: external_exports.string().regex(/^\d{4}-\d{2}-\d{2}$/, "Date must be in YYYY-MM-DD format").optional(),
|
|
43339
42957
|
max: external_exports.string().regex(/^\d{4}-\d{2}-\d{2}$/, "Date must be in YYYY-MM-DD format").optional()
|
|
43340
|
-
})
|
|
43341
|
-
var
|
|
42958
|
+
});
|
|
42959
|
+
var RatingQuestionBaseSchema = QuestionBaseSchema.extend({
|
|
43342
42960
|
type: external_exports.literal("rating"),
|
|
43343
42961
|
min: external_exports.number().int().optional(),
|
|
43344
42962
|
max: external_exports.number().int().optional(),
|
|
@@ -43351,20 +42969,58 @@ var RatingQuestionSchema = QuestionBaseSchema.extend({
|
|
|
43351
42969
|
low: external_exports.string().optional(),
|
|
43352
42970
|
high: external_exports.string().optional()
|
|
43353
42971
|
}).optional()
|
|
43354
|
-
})
|
|
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" });
|
|
42972
|
+
});
|
|
43358
42973
|
var QuestionSchema = external_exports.discriminatedUnion("type", [
|
|
43359
42974
|
TextQuestionSchema,
|
|
43360
42975
|
MultilineQuestionSchema,
|
|
43361
42976
|
ChoiceQuestionSchema,
|
|
43362
42977
|
ConfirmQuestionSchema,
|
|
43363
|
-
|
|
42978
|
+
NumberQuestionBaseSchema,
|
|
43364
42979
|
EmailQuestionSchema,
|
|
43365
|
-
|
|
43366
|
-
|
|
42980
|
+
DateQuestionBaseSchema,
|
|
42981
|
+
RatingQuestionBaseSchema
|
|
43367
42982
|
]);
|
|
42983
|
+
function validateNumberQuestion(q, index, ctx) {
|
|
42984
|
+
if (q.min !== void 0 && q.max !== void 0 && q.min > q.max) ctx.addIssue({
|
|
42985
|
+
code: external_exports.ZodIssueCode.custom,
|
|
42986
|
+
message: "min must be <= max",
|
|
42987
|
+
path: ["questions", index]
|
|
42988
|
+
});
|
|
42989
|
+
}
|
|
42990
|
+
function validateDateQuestion(q, index, ctx) {
|
|
42991
|
+
if (q.min !== void 0 && q.max !== void 0 && new Date(q.min) > new Date(q.max)) ctx.addIssue({
|
|
42992
|
+
code: external_exports.ZodIssueCode.custom,
|
|
42993
|
+
message: "min date must be before or equal to max date",
|
|
42994
|
+
path: ["questions", index]
|
|
42995
|
+
});
|
|
42996
|
+
}
|
|
42997
|
+
function validateRatingQuestion(q, index, ctx) {
|
|
42998
|
+
if (q.min === void 0 || q.max === void 0) return;
|
|
42999
|
+
if (q.min > q.max || q.max - q.min > 20) ctx.addIssue({
|
|
43000
|
+
code: external_exports.ZodIssueCode.custom,
|
|
43001
|
+
message: "Rating scale must have min <= max and at most 20 items",
|
|
43002
|
+
path: ["questions", index]
|
|
43003
|
+
});
|
|
43004
|
+
}
|
|
43005
|
+
function validateQuestionConstraints(questions, ctx) {
|
|
43006
|
+
for (let i = 0; i < questions.length; i++) {
|
|
43007
|
+
const q = questions[i];
|
|
43008
|
+
if (!q) continue;
|
|
43009
|
+
switch (q.type) {
|
|
43010
|
+
case "number":
|
|
43011
|
+
validateNumberQuestion(q, i, ctx);
|
|
43012
|
+
break;
|
|
43013
|
+
case "date":
|
|
43014
|
+
validateDateQuestion(q, i, ctx);
|
|
43015
|
+
break;
|
|
43016
|
+
case "rating":
|
|
43017
|
+
validateRatingQuestion(q, i, ctx);
|
|
43018
|
+
break;
|
|
43019
|
+
default:
|
|
43020
|
+
break;
|
|
43021
|
+
}
|
|
43022
|
+
}
|
|
43023
|
+
}
|
|
43368
43024
|
var MultiQuestionInputRequestSchema = external_exports.object({
|
|
43369
43025
|
id: external_exports.string(),
|
|
43370
43026
|
createdAt: external_exports.number(),
|
|
@@ -43377,6 +43033,8 @@ var MultiQuestionInputRequestSchema = external_exports.object({
|
|
|
43377
43033
|
answeredAt: external_exports.number().optional(),
|
|
43378
43034
|
answeredBy: external_exports.string().optional(),
|
|
43379
43035
|
isBlocker: external_exports.boolean().optional()
|
|
43036
|
+
}).superRefine((data, ctx) => {
|
|
43037
|
+
validateQuestionConstraints(data.questions, ctx);
|
|
43380
43038
|
});
|
|
43381
43039
|
var AnyInputRequestSchema = external_exports.union([InputRequestSchema, MultiQuestionInputRequestSchema]);
|
|
43382
43040
|
var YDOC_KEYS = {
|
|
@@ -43392,8 +43050,11 @@ var YDOC_KEYS = {
|
|
|
43392
43050
|
PR_REVIEW_COMMENTS: "prReviewComments",
|
|
43393
43051
|
EVENTS: "events",
|
|
43394
43052
|
SNAPSHOTS: "snapshots",
|
|
43395
|
-
INPUT_REQUESTS: "inputRequests"
|
|
43053
|
+
INPUT_REQUESTS: "inputRequests",
|
|
43054
|
+
LOCAL_DIFF_COMMENTS: "localDiffComments",
|
|
43055
|
+
CHANGE_SNAPSHOTS: "changeSnapshots"
|
|
43396
43056
|
};
|
|
43057
|
+
var validKeys = new Set(Object.values(YDOC_KEYS));
|
|
43397
43058
|
var CommentBodySchema = external_exports.union([external_exports.string(), external_exports.array(external_exports.unknown())]);
|
|
43398
43059
|
var ThreadCommentSchema = external_exports.object({
|
|
43399
43060
|
id: external_exports.string(),
|
|
@@ -43413,10 +43074,13 @@ function extractTextFromCommentBody(body) {
|
|
|
43413
43074
|
return body.map((block) => {
|
|
43414
43075
|
if (typeof block === "string") return block;
|
|
43415
43076
|
if (typeof block !== "object" || block === null) return "";
|
|
43416
|
-
const
|
|
43417
|
-
if (Array.isArray(
|
|
43077
|
+
const content = Object.fromEntries(Object.entries(block)).content;
|
|
43078
|
+
if (Array.isArray(content)) return content.map((item) => {
|
|
43418
43079
|
if (typeof item === "string") return item;
|
|
43419
|
-
if (typeof item === "object" && item !== null && "text" in item)
|
|
43080
|
+
if (typeof item === "object" && item !== null && "text" in item) {
|
|
43081
|
+
const text = Object.fromEntries(Object.entries(item)).text;
|
|
43082
|
+
return typeof text === "string" ? text : "";
|
|
43083
|
+
}
|
|
43420
43084
|
return "";
|
|
43421
43085
|
}).join("");
|
|
43422
43086
|
return "";
|
|
@@ -43446,6 +43110,48 @@ function getPlanMetadataWithValidation(ydoc) {
|
|
|
43446
43110
|
// ../../packages/schema/dist/url-encoding.mjs
|
|
43447
43111
|
init_cjs_shims();
|
|
43448
43112
|
var import_lz_string = __toESM(require_lz_string(), 1);
|
|
43113
|
+
var UrlSnapshotRefSchema = external_exports.object({
|
|
43114
|
+
id: external_exports.string(),
|
|
43115
|
+
status: external_exports.enum(PlanStatusValues),
|
|
43116
|
+
createdBy: external_exports.string(),
|
|
43117
|
+
reason: external_exports.string(),
|
|
43118
|
+
createdAt: external_exports.number(),
|
|
43119
|
+
threads: external_exports.object({
|
|
43120
|
+
total: external_exports.number(),
|
|
43121
|
+
unresolved: external_exports.number()
|
|
43122
|
+
}).optional()
|
|
43123
|
+
});
|
|
43124
|
+
var UrlKeyVersionSchema = external_exports.object({
|
|
43125
|
+
id: external_exports.string(),
|
|
43126
|
+
content: external_exports.array(external_exports.unknown())
|
|
43127
|
+
});
|
|
43128
|
+
var UrlEncodedPlanV1Schema = external_exports.object({
|
|
43129
|
+
v: external_exports.literal(1),
|
|
43130
|
+
id: external_exports.string(),
|
|
43131
|
+
title: external_exports.string(),
|
|
43132
|
+
status: external_exports.enum(PlanStatusValues),
|
|
43133
|
+
repo: external_exports.string().optional(),
|
|
43134
|
+
pr: external_exports.number().optional(),
|
|
43135
|
+
content: external_exports.array(external_exports.unknown()),
|
|
43136
|
+
artifacts: external_exports.array(ArtifactSchema).optional(),
|
|
43137
|
+
deliverables: external_exports.array(DeliverableSchema).optional(),
|
|
43138
|
+
comments: external_exports.array(external_exports.unknown()).optional()
|
|
43139
|
+
});
|
|
43140
|
+
var UrlEncodedPlanV2Schema = external_exports.object({
|
|
43141
|
+
v: external_exports.literal(2),
|
|
43142
|
+
id: external_exports.string(),
|
|
43143
|
+
title: external_exports.string(),
|
|
43144
|
+
status: external_exports.enum(PlanStatusValues),
|
|
43145
|
+
repo: external_exports.string().optional(),
|
|
43146
|
+
pr: external_exports.number().optional(),
|
|
43147
|
+
content: external_exports.array(external_exports.unknown()),
|
|
43148
|
+
artifacts: external_exports.array(ArtifactSchema).optional(),
|
|
43149
|
+
deliverables: external_exports.array(DeliverableSchema).optional(),
|
|
43150
|
+
comments: external_exports.array(external_exports.unknown()).optional(),
|
|
43151
|
+
versionRefs: external_exports.array(UrlSnapshotRefSchema).optional(),
|
|
43152
|
+
keyVersions: external_exports.array(UrlKeyVersionSchema).optional()
|
|
43153
|
+
});
|
|
43154
|
+
var UrlEncodedPlanSchema = external_exports.discriminatedUnion("v", [UrlEncodedPlanV1Schema, UrlEncodedPlanV2Schema]);
|
|
43449
43155
|
|
|
43450
43156
|
// ../../node_modules/.pnpm/@trpc+server@11.8.1_typescript@5.9.3/node_modules/@trpc/server/dist/index.mjs
|
|
43451
43157
|
init_cjs_shims();
|
|
@@ -44235,13 +43941,20 @@ var A2AFilePartSchema = external_exports.object({
|
|
|
44235
43941
|
mediaType: external_exports.string().optional(),
|
|
44236
43942
|
name: external_exports.string().optional()
|
|
44237
43943
|
});
|
|
43944
|
+
function hasStringProperty(obj, prop) {
|
|
43945
|
+
return prop in obj && typeof obj[prop] === "string";
|
|
43946
|
+
}
|
|
43947
|
+
function toRecord(obj) {
|
|
43948
|
+
return Object.fromEntries(Object.entries(obj));
|
|
43949
|
+
}
|
|
44238
43950
|
var A2APartSchema = external_exports.object({ type: external_exports.enum([
|
|
44239
43951
|
"text",
|
|
44240
43952
|
"data",
|
|
44241
43953
|
"file"
|
|
44242
43954
|
]) }).passthrough().superRefine((val, ctx) => {
|
|
43955
|
+
const record2 = toRecord(val);
|
|
44243
43956
|
if (val.type === "text") {
|
|
44244
|
-
if (
|
|
43957
|
+
if (!hasStringProperty(record2, "text")) ctx.addIssue({
|
|
44245
43958
|
code: external_exports.ZodIssueCode.custom,
|
|
44246
43959
|
message: "text part must have a string text field"
|
|
44247
43960
|
});
|
|
@@ -44251,7 +43964,7 @@ var A2APartSchema = external_exports.object({ type: external_exports.enum([
|
|
|
44251
43964
|
message: "data part must have a data field"
|
|
44252
43965
|
});
|
|
44253
43966
|
} else if (val.type === "file") {
|
|
44254
|
-
if (
|
|
43967
|
+
if (!hasStringProperty(record2, "uri")) ctx.addIssue({
|
|
44255
43968
|
code: external_exports.ZodIssueCode.custom,
|
|
44256
43969
|
message: "file part must have a string uri field"
|
|
44257
43970
|
});
|
|
@@ -44259,7 +43972,7 @@ var A2APartSchema = external_exports.object({ type: external_exports.enum([
|
|
|
44259
43972
|
});
|
|
44260
43973
|
function isValidA2APart(part) {
|
|
44261
43974
|
if (!part || typeof part !== "object") return false;
|
|
44262
|
-
const p = part;
|
|
43975
|
+
const p = toRecord(part);
|
|
44263
43976
|
const t$1 = p.type;
|
|
44264
43977
|
if (t$1 === "text") return typeof p.text === "string";
|
|
44265
43978
|
else if (t$1 === "data") return "data" in p;
|
|
@@ -44277,17 +43990,38 @@ var A2AMessageSchema = external_exports.object({
|
|
|
44277
43990
|
taskId: external_exports.string().optional(),
|
|
44278
43991
|
referenceTaskIds: external_exports.array(external_exports.string()).optional(),
|
|
44279
43992
|
metadata: external_exports.record(external_exports.string(), external_exports.unknown()).optional(),
|
|
44280
|
-
extensions: external_exports.array(external_exports.string()).optional()
|
|
43993
|
+
extensions: external_exports.array(external_exports.string()).optional(),
|
|
43994
|
+
parts: external_exports.array(external_exports.unknown())
|
|
44281
43995
|
}).passthrough().refine((val) => {
|
|
44282
|
-
|
|
44283
|
-
return isValidA2AParts(parts);
|
|
43996
|
+
return isValidA2AParts(val.parts);
|
|
44284
43997
|
}, {
|
|
44285
43998
|
message: "Invalid parts array - each part must have valid type and required fields",
|
|
44286
43999
|
path: ["parts"]
|
|
44287
|
-
}).transform((val) =>
|
|
44288
|
-
|
|
44289
|
-
|
|
44290
|
-
|
|
44000
|
+
}).transform((val) => {
|
|
44001
|
+
const parts = val.parts.map((p) => {
|
|
44002
|
+
if (!p || typeof p !== "object") throw new Error("Invalid part: not an object");
|
|
44003
|
+
const record2 = toRecord(p);
|
|
44004
|
+
const partType = record2.type;
|
|
44005
|
+
if (partType === "text") return {
|
|
44006
|
+
type: "text",
|
|
44007
|
+
text: String(record2.text)
|
|
44008
|
+
};
|
|
44009
|
+
else if (partType === "data") return {
|
|
44010
|
+
type: "data",
|
|
44011
|
+
data: record2.data
|
|
44012
|
+
};
|
|
44013
|
+
else return {
|
|
44014
|
+
type: "file",
|
|
44015
|
+
uri: String(record2.uri),
|
|
44016
|
+
mediaType: typeof record2.mediaType === "string" ? record2.mediaType : void 0,
|
|
44017
|
+
name: typeof record2.name === "string" ? record2.name : void 0
|
|
44018
|
+
};
|
|
44019
|
+
});
|
|
44020
|
+
return {
|
|
44021
|
+
...val,
|
|
44022
|
+
parts
|
|
44023
|
+
};
|
|
44024
|
+
});
|
|
44291
44025
|
var ConversationExportMetaSchema = external_exports.object({
|
|
44292
44026
|
exportId: external_exports.string(),
|
|
44293
44027
|
sourcePlatform: external_exports.string(),
|
|
@@ -44319,7 +44053,7 @@ var ClaudeCodeContentBlockSchema = external_exports.object({ type: external_expo
|
|
|
44319
44053
|
"tool_use",
|
|
44320
44054
|
"tool_result"
|
|
44321
44055
|
]) }).passthrough().superRefine((val, ctx) => {
|
|
44322
|
-
const typedVal = val;
|
|
44056
|
+
const typedVal = toRecord(val);
|
|
44323
44057
|
if (val.type === "text") {
|
|
44324
44058
|
if (typeof typedVal.text !== "string") ctx.addIssue({
|
|
44325
44059
|
code: external_exports.ZodIssueCode.custom,
|
|
@@ -44344,6 +44078,32 @@ var ClaudeCodeContentBlockSchema = external_exports.object({ type: external_expo
|
|
|
44344
44078
|
message: "tool_result block must have a string tool_use_id field"
|
|
44345
44079
|
});
|
|
44346
44080
|
}
|
|
44081
|
+
}).transform((val) => {
|
|
44082
|
+
const record2 = toRecord(val);
|
|
44083
|
+
switch (val.type) {
|
|
44084
|
+
case "text":
|
|
44085
|
+
return {
|
|
44086
|
+
type: "text",
|
|
44087
|
+
text: String(record2.text)
|
|
44088
|
+
};
|
|
44089
|
+
case "tool_use": {
|
|
44090
|
+
const inputVal = record2.input;
|
|
44091
|
+
if (!inputVal || typeof inputVal !== "object") throw new Error("Invalid tool_use: input is not an object");
|
|
44092
|
+
return {
|
|
44093
|
+
type: "tool_use",
|
|
44094
|
+
id: String(record2.id),
|
|
44095
|
+
name: String(record2.name),
|
|
44096
|
+
input: toRecord(inputVal)
|
|
44097
|
+
};
|
|
44098
|
+
}
|
|
44099
|
+
case "tool_result":
|
|
44100
|
+
return {
|
|
44101
|
+
type: "tool_result",
|
|
44102
|
+
tool_use_id: String(record2.tool_use_id),
|
|
44103
|
+
content: record2.content,
|
|
44104
|
+
is_error: typeof record2.is_error === "boolean" ? record2.is_error : void 0
|
|
44105
|
+
};
|
|
44106
|
+
}
|
|
44347
44107
|
});
|
|
44348
44108
|
var ClaudeCodeUsageSchema = external_exports.object({
|
|
44349
44109
|
input_tokens: external_exports.number(),
|
|
@@ -44372,6 +44132,18 @@ var ClaudeCodeMessageSchema = external_exports.object({
|
|
|
44372
44132
|
costUSD: external_exports.number().optional(),
|
|
44373
44133
|
durationMs: external_exports.number().optional()
|
|
44374
44134
|
});
|
|
44135
|
+
var UsageMetadataSchema = external_exports.object({
|
|
44136
|
+
input_tokens: external_exports.number(),
|
|
44137
|
+
output_tokens: external_exports.number(),
|
|
44138
|
+
cache_creation_input_tokens: external_exports.number().optional(),
|
|
44139
|
+
cache_read_input_tokens: external_exports.number().optional()
|
|
44140
|
+
});
|
|
44141
|
+
var EnvironmentContextSchema = external_exports.object({
|
|
44142
|
+
projectName: external_exports.string().optional(),
|
|
44143
|
+
branch: external_exports.string().optional(),
|
|
44144
|
+
hostname: external_exports.string().optional(),
|
|
44145
|
+
repo: external_exports.string().optional()
|
|
44146
|
+
});
|
|
44375
44147
|
var GitHubPRResponseSchema = external_exports.object({
|
|
44376
44148
|
number: external_exports.number(),
|
|
44377
44149
|
html_url: external_exports.string().url(),
|
|
@@ -44440,6 +44212,7 @@ var LocalChangesResponseSchema = external_exports.object({
|
|
|
44440
44212
|
available: external_exports.literal(true),
|
|
44441
44213
|
branch: external_exports.string(),
|
|
44442
44214
|
baseBranch: external_exports.string(),
|
|
44215
|
+
headSha: external_exports.string().optional(),
|
|
44443
44216
|
staged: external_exports.array(LocalFileChangeSchema),
|
|
44444
44217
|
unstaged: external_exports.array(LocalFileChangeSchema),
|
|
44445
44218
|
untracked: external_exports.array(external_exports.string()),
|
|
@@ -44530,19 +44303,20 @@ function truncate(text, maxLength) {
|
|
|
44530
44303
|
if (cleaned.length <= maxLength) return cleaned;
|
|
44531
44304
|
return `${cleaned.slice(0, maxLength)}...`;
|
|
44532
44305
|
}
|
|
44533
|
-
var
|
|
44306
|
+
var TOOL_NAMES = {
|
|
44534
44307
|
ADD_ARTIFACT: "add_artifact",
|
|
44535
|
-
ADD_PR_REVIEW_COMMENT: "add_pr_review_comment",
|
|
44536
44308
|
COMPLETE_TASK: "complete_task",
|
|
44537
|
-
|
|
44309
|
+
CREATE_TASK: "create_task",
|
|
44538
44310
|
EXECUTE_CODE: "execute_code",
|
|
44539
44311
|
LINK_PR: "link_pr",
|
|
44540
|
-
|
|
44312
|
+
POST_UPDATE: "post_update",
|
|
44313
|
+
READ_DIFF_COMMENTS: "read_diff_comments",
|
|
44314
|
+
READ_TASK: "read_task",
|
|
44541
44315
|
REGENERATE_SESSION_TOKEN: "regenerate_session_token",
|
|
44542
44316
|
REQUEST_USER_INPUT: "request_user_input",
|
|
44543
44317
|
SETUP_REVIEW_NOTIFICATION: "setup_review_notification",
|
|
44544
44318
|
UPDATE_BLOCK_CONTENT: "update_block_content",
|
|
44545
|
-
|
|
44319
|
+
UPDATE_TASK: "update_task"
|
|
44546
44320
|
};
|
|
44547
44321
|
var PlanIdSchema = external_exports.object({ planId: external_exports.string().min(1) });
|
|
44548
44322
|
var PlanStatusResponseSchema = external_exports.object({ status: external_exports.string() });
|
|
@@ -44551,13 +44325,6 @@ var SubscriptionClientIdSchema = external_exports.object({
|
|
|
44551
44325
|
planId: external_exports.string().min(1),
|
|
44552
44326
|
clientId: external_exports.string().min(1)
|
|
44553
44327
|
});
|
|
44554
|
-
var ChangeTypeSchema = external_exports.enum([
|
|
44555
|
-
"status",
|
|
44556
|
-
"comments",
|
|
44557
|
-
"resolved",
|
|
44558
|
-
"content",
|
|
44559
|
-
"artifacts"
|
|
44560
|
-
]);
|
|
44561
44328
|
var ChangeSchema = external_exports.object({
|
|
44562
44329
|
type: ChangeTypeSchema,
|
|
44563
44330
|
timestamp: external_exports.number(),
|
|
@@ -44595,6 +44362,12 @@ var ImportConversationResponseSchema = external_exports.discriminatedUnion("succ
|
|
|
44595
44362
|
success: external_exports.literal(false),
|
|
44596
44363
|
error: external_exports.string()
|
|
44597
44364
|
})]);
|
|
44365
|
+
var MachineInfoResponseSchema = external_exports.object({
|
|
44366
|
+
machineId: external_exports.string(),
|
|
44367
|
+
machineName: external_exports.string(),
|
|
44368
|
+
ownerId: external_exports.string(),
|
|
44369
|
+
cwd: external_exports.string()
|
|
44370
|
+
});
|
|
44598
44371
|
var t = initTRPC.context().create({ allowOutsideOfServer: true });
|
|
44599
44372
|
var router = t.router;
|
|
44600
44373
|
var publicProcedure = t.procedure;
|
|
@@ -44627,7 +44400,7 @@ var hookRouter = router({
|
|
|
44627
44400
|
})).output(external_exports.object({
|
|
44628
44401
|
approved: external_exports.boolean(),
|
|
44629
44402
|
feedback: external_exports.string().optional(),
|
|
44630
|
-
deliverables: external_exports.array(
|
|
44403
|
+
deliverables: external_exports.array(DeliverableSchema).optional(),
|
|
44631
44404
|
reviewComment: external_exports.string().optional(),
|
|
44632
44405
|
reviewedBy: external_exports.string().optional(),
|
|
44633
44406
|
status: external_exports.string().optional()
|
|
@@ -44674,7 +44447,7 @@ var planRouter = router({
|
|
|
44674
44447
|
message: "Plan not found"
|
|
44675
44448
|
});
|
|
44676
44449
|
const origin = metadata.origin;
|
|
44677
|
-
const cwd = origin?.platform === "claude-code" ? origin.cwd : void 0;
|
|
44450
|
+
const cwd = origin?.platform === "claude-code" || origin?.platform === "unknown" ? origin.cwd : void 0;
|
|
44678
44451
|
if (!cwd) return {
|
|
44679
44452
|
available: false,
|
|
44680
44453
|
reason: "no_cwd",
|
|
@@ -44695,12 +44468,15 @@ var planRouter = router({
|
|
|
44695
44468
|
message: "Plan not found"
|
|
44696
44469
|
});
|
|
44697
44470
|
const origin = metadata.origin;
|
|
44698
|
-
const cwd = origin?.platform === "claude-code" ? origin.cwd : void 0;
|
|
44471
|
+
const cwd = origin?.platform === "claude-code" || origin?.platform === "unknown" ? origin.cwd : void 0;
|
|
44699
44472
|
if (!cwd) return {
|
|
44700
44473
|
content: null,
|
|
44701
44474
|
error: "No working directory available"
|
|
44702
44475
|
};
|
|
44703
44476
|
return ctx.getFileContent(cwd, input.filePath);
|
|
44477
|
+
}),
|
|
44478
|
+
getMachineInfo: publicProcedure.input(PlanIdSchema).output(MachineInfoResponseSchema).query(async ({ ctx }) => {
|
|
44479
|
+
return ctx.getMachineInfo();
|
|
44704
44480
|
})
|
|
44705
44481
|
});
|
|
44706
44482
|
var subscriptionRouter = router({
|
|
@@ -44708,7 +44484,7 @@ var subscriptionRouter = router({
|
|
|
44708
44484
|
const { planId, subscribe, windowMs, maxWindowMs, threshold } = input;
|
|
44709
44485
|
return { clientId: ctx.getPlanStore().createSubscription({
|
|
44710
44486
|
planId,
|
|
44711
|
-
subscribe: subscribe
|
|
44487
|
+
subscribe: subscribe ?? ["status"],
|
|
44712
44488
|
windowMs: windowMs ?? 5e3,
|
|
44713
44489
|
maxWindowMs: maxWindowMs ?? 3e4,
|
|
44714
44490
|
threshold: threshold ?? 1
|
|
@@ -44734,6 +44510,547 @@ var appRouter = router({
|
|
|
44734
44510
|
subscription: subscriptionRouter,
|
|
44735
44511
|
conversation: conversationRouter
|
|
44736
44512
|
});
|
|
44513
|
+
function isBuffer(value) {
|
|
44514
|
+
return Buffer.isBuffer(value);
|
|
44515
|
+
}
|
|
44516
|
+
|
|
44517
|
+
// ../../packages/shared/dist/instructions/index.mjs
|
|
44518
|
+
init_cjs_shims();
|
|
44519
|
+
var TOOL_NAMES2 = {
|
|
44520
|
+
ADD_ARTIFACT: "add_artifact",
|
|
44521
|
+
COMPLETE_TASK: "complete_task",
|
|
44522
|
+
CREATE_TASK: "create_task",
|
|
44523
|
+
EXECUTE_CODE: "execute_code",
|
|
44524
|
+
LINK_PR: "link_pr",
|
|
44525
|
+
POST_UPDATE: "post_update",
|
|
44526
|
+
READ_DIFF_COMMENTS: "read_diff_comments",
|
|
44527
|
+
READ_TASK: "read_task",
|
|
44528
|
+
REGENERATE_SESSION_TOKEN: "regenerate_session_token",
|
|
44529
|
+
REQUEST_USER_INPUT: "request_user_input",
|
|
44530
|
+
SETUP_REVIEW_NOTIFICATION: "setup_review_notification",
|
|
44531
|
+
UPDATE_BLOCK_CONTENT: "update_block_content",
|
|
44532
|
+
UPDATE_TASK: "update_task"
|
|
44533
|
+
};
|
|
44534
|
+
var CRITICAL_USAGE_SECTION = `## CRITICAL: When to Use Shipyard
|
|
44535
|
+
|
|
44536
|
+
\u26A0\uFE0F **MANDATORY USAGE RULE:**
|
|
44537
|
+
|
|
44538
|
+
If Shipyard is available, you MUST use it for:
|
|
44539
|
+
- Creating implementation tasks
|
|
44540
|
+
- Tracking work that needs human review
|
|
44541
|
+
- Documenting proof of work (screenshots, videos, test results)
|
|
44542
|
+
- ANY user request involving "task", "track", "verify", or "prove"
|
|
44543
|
+
|
|
44544
|
+
**DO NOT:**
|
|
44545
|
+
- Create tasks manually in chat or as markdown files
|
|
44546
|
+
- Write implementation docs yourself when Shipyard is available
|
|
44547
|
+
- Suggest alternatives to Shipyard for trackable work
|
|
44548
|
+
- Overthink whether to use it - WHEN IN DOUBT, USE SHIPYARD
|
|
44549
|
+
|
|
44550
|
+
**Decision Tree:**
|
|
44551
|
+
\`\`\`
|
|
44552
|
+
Need to create/track/verify work?
|
|
44553
|
+
\u2502
|
|
44554
|
+
\u25BC
|
|
44555
|
+
Shipyard available?
|
|
44556
|
+
\u2502 \u2502
|
|
44557
|
+
YES NO
|
|
44558
|
+
\u2502 \u2502
|
|
44559
|
+
\u25BC \u25BC
|
|
44560
|
+
USE IT Manual approach
|
|
44561
|
+
NOW (tell user why)
|
|
44562
|
+
\`\`\``;
|
|
44563
|
+
var DELIVERABLES_SECTION = `## What are Deliverables?
|
|
44564
|
+
|
|
44565
|
+
Deliverables are measurable outcomes you can **prove** with artifacts (screenshots, videos, test results).
|
|
44566
|
+
|
|
44567
|
+
**Good deliverables (provable):**
|
|
44568
|
+
\`\`\`
|
|
44569
|
+
- [ ] Screenshot of working login page {#deliverable}
|
|
44570
|
+
- [ ] Video showing drag-and-drop feature {#deliverable}
|
|
44571
|
+
- [ ] Test results showing all tests pass {#deliverable}
|
|
44572
|
+
\`\`\`
|
|
44573
|
+
|
|
44574
|
+
**Bad deliverables (not provable - these are tasks, not deliverables):**
|
|
44575
|
+
\`\`\`
|
|
44576
|
+
- [ ] Implement getUserMedia API \u2190 Implementation detail, not provable
|
|
44577
|
+
- [ ] Add error handling \u2190 Can't capture this with an artifact
|
|
44578
|
+
- [ ] Refactor authentication \u2190 Too vague, no visual proof
|
|
44579
|
+
\`\`\`
|
|
44580
|
+
|
|
44581
|
+
**Rule:** If you can't screenshot/record/export it, it's not a deliverable.`;
|
|
44582
|
+
var ARTIFACT_TYPES_SECTION = `## Artifact Types
|
|
44583
|
+
|
|
44584
|
+
| Type | Use For | File Formats |
|
|
44585
|
+
|------|---------|--------------|
|
|
44586
|
+
| \`html\` | Test results, code reviews, reports, terminal output | .html |
|
|
44587
|
+
| \`image\` | UI screenshots, visual proof, error states | .png, .jpg, .webp |
|
|
44588
|
+
| \`video\` | Complex flows, interactions, animations | .mp4, .webm |
|
|
44589
|
+
|
|
44590
|
+
**Note:** HTML is the primary format for most artifacts. Use it for test results, coverage reports, code reviews, and any text-based output. Only use \`image\` for actual UI screenshots and \`video\` for multi-step flows.`;
|
|
44591
|
+
var TIPS_SECTION = `## Tips for Effective Use
|
|
44592
|
+
|
|
44593
|
+
1. **Define deliverables first** - Decide what proves success before coding
|
|
44594
|
+
2. **Capture during work** - Take screenshots as you implement, not after
|
|
44595
|
+
3. **Be specific** - "Login page with error state" beats "Screenshot"
|
|
44596
|
+
4. **Link every artifact** - Always set \`deliverableId\` for auto-completion
|
|
44597
|
+
5. **Check feedback** - Read reviewer comments and iterate`;
|
|
44598
|
+
var WHEN_NOT_TO_USE_SECTION = `## When NOT to Use Shipyard
|
|
44599
|
+
|
|
44600
|
+
Skip Shipyard for:
|
|
44601
|
+
- Quick answers or research questions (no artifacts to capture)
|
|
44602
|
+
- Internal refactoring with no visible output
|
|
44603
|
+
- Tasks where proof adds no value (trivial fixes)
|
|
44604
|
+
- Exploration or debugging sessions
|
|
44605
|
+
- Pure documentation without implementation`;
|
|
44606
|
+
var USER_INPUT_SECTION = `## Human-Agent Communication
|
|
44607
|
+
|
|
44608
|
+
**\`requestUserInput()\` inside \`${TOOL_NAMES2.EXECUTE_CODE}\` is THE primary way to communicate with humans during active work.**
|
|
44609
|
+
|
|
44610
|
+
Shipyard is the central hub where humans manage AI agents. When you need to ask a question, get clarification, or request a decision - use \`requestUserInput()\`. The human is already in the browser viewing your task. That's where conversations should happen.
|
|
44611
|
+
|
|
44612
|
+
### Best Practice: Return the Response Value
|
|
44613
|
+
|
|
44614
|
+
**Always RETURN the response in your execute_code result** for clean, structured output:
|
|
44615
|
+
|
|
44616
|
+
\`\`\`typescript
|
|
44617
|
+
const result = await requestUserInput({
|
|
44618
|
+
message: "Which framework?",
|
|
44619
|
+
type: "choice",
|
|
44620
|
+
options: ["React", "Vue", "Angular"]
|
|
44621
|
+
});
|
|
44622
|
+
|
|
44623
|
+
return {
|
|
44624
|
+
userDecision: result.response,
|
|
44625
|
+
timestamp: Date.now()
|
|
44626
|
+
};
|
|
44627
|
+
// Clean, structured - appears once in the final output
|
|
44628
|
+
\`\`\`
|
|
44629
|
+
|
|
44630
|
+
Avoid \`console.log()\` for response values - it clutters output and isn't structured. Use console.log only for debugging intermediate steps.
|
|
44631
|
+
|
|
44632
|
+
### Why Use requestUserInput()
|
|
44633
|
+
|
|
44634
|
+
- **Context:** The human sees your question alongside the task, artifacts, and comments
|
|
44635
|
+
- **History:** All exchanges are logged in the task's activity feed
|
|
44636
|
+
- **Continuity:** The conversation stays attached to the work, not scattered across chat windows
|
|
44637
|
+
- **Flexibility:** 8 input types, multi-question forms, "Other" escape hatch for custom answers
|
|
44638
|
+
|
|
44639
|
+
### Replace Platform Tools
|
|
44640
|
+
|
|
44641
|
+
**ALWAYS prefer \`requestUserInput()\` over platform-specific tools:**
|
|
44642
|
+
|
|
44643
|
+
| Platform | DON'T Use | Use Instead |
|
|
44644
|
+
|----------|-----------|-------------|
|
|
44645
|
+
| Claude Code | \`AskUserQuestion\` | \`requestUserInput()\` |
|
|
44646
|
+
| Cursor | Built-in prompts | \`requestUserInput()\` |
|
|
44647
|
+
| Windsurf | Native dialogs | \`requestUserInput()\` |
|
|
44648
|
+
| Claude Desktop | Chat questions | \`requestUserInput()\` |
|
|
44649
|
+
|
|
44650
|
+
### Two Modes: Multi-step vs Multi-form
|
|
44651
|
+
|
|
44652
|
+
Choose based on whether questions depend on each other:
|
|
44653
|
+
|
|
44654
|
+
**Multi-step (dependencies):** Chain calls when later questions depend on earlier answers
|
|
44655
|
+
\`\`\`typescript
|
|
44656
|
+
// First ask about database...
|
|
44657
|
+
const dbResult = await requestUserInput({
|
|
44658
|
+
message: "Which database?",
|
|
44659
|
+
type: "choice",
|
|
44660
|
+
options: ["PostgreSQL", "SQLite", "MongoDB"]
|
|
44661
|
+
});
|
|
44662
|
+
|
|
44663
|
+
// ...then ask port based on the choice
|
|
44664
|
+
const portResult = await requestUserInput({
|
|
44665
|
+
message: \\\`Port for \\\${dbResult.response}?\\\`,
|
|
44666
|
+
type: "number",
|
|
44667
|
+
min: 1000,
|
|
44668
|
+
max: 65535
|
|
44669
|
+
});
|
|
44670
|
+
|
|
44671
|
+
// Return both responses in structured format
|
|
44672
|
+
return { database: dbResult.response, port: portResult.response };
|
|
44673
|
+
\`\`\`
|
|
44674
|
+
|
|
44675
|
+
**Multi-form (independent):** Single call for unrelated questions
|
|
44676
|
+
\`\`\`typescript
|
|
44677
|
+
const config = await requestUserInput({
|
|
44678
|
+
questions: [
|
|
44679
|
+
{ message: "Project name?", type: "text" },
|
|
44680
|
+
{ message: "Use TypeScript?", type: "confirm" },
|
|
44681
|
+
{ message: "License?", type: "choice", options: ["MIT", "Apache-2.0"] }
|
|
44682
|
+
],
|
|
44683
|
+
timeout: 600
|
|
44684
|
+
});
|
|
44685
|
+
// Return responses in structured format
|
|
44686
|
+
return { config: config.response };
|
|
44687
|
+
\`\`\`
|
|
44688
|
+
|
|
44689
|
+
### When to Ask
|
|
44690
|
+
|
|
44691
|
+
Use \`requestUserInput()\` when you need:
|
|
44692
|
+
- Clarification on requirements ("Which auth provider?")
|
|
44693
|
+
- Decisions that affect implementation ("PostgreSQL or SQLite?")
|
|
44694
|
+
- Confirmation before destructive actions ("Delete this file?")
|
|
44695
|
+
- User preferences ("Rate this approach 1-5")
|
|
44696
|
+
- Any information you can't infer from context`;
|
|
44697
|
+
var TROUBLESHOOTING_SECTION = `## Troubleshooting
|
|
44698
|
+
|
|
44699
|
+
**Browser doesn't open:** Check MCP server is running and accessible.
|
|
44700
|
+
|
|
44701
|
+
**Upload fails:** Verify file path exists. For GitHub uploads, check \`GITHUB_TOKEN\` has repo write access.
|
|
44702
|
+
|
|
44703
|
+
**No auto-complete:** Ensure every deliverable has an artifact with matching \`deliverableId\`.
|
|
44704
|
+
|
|
44705
|
+
**Task not syncing:** Check WebSocket connection to registry server.
|
|
44706
|
+
|
|
44707
|
+
**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.
|
|
44708
|
+
|
|
44709
|
+
**Input request declined:** User clicked "Decline." Rephrase your question, proceed with a reasonable default, or use a different approach.
|
|
44710
|
+
|
|
44711
|
+
**No response to input:** Check if browser is connected to the task. User may have closed the browser window.`;
|
|
44712
|
+
var COMMON_INSTRUCTIONS = [
|
|
44713
|
+
CRITICAL_USAGE_SECTION,
|
|
44714
|
+
USER_INPUT_SECTION,
|
|
44715
|
+
DELIVERABLES_SECTION,
|
|
44716
|
+
ARTIFACT_TYPES_SECTION,
|
|
44717
|
+
TIPS_SECTION,
|
|
44718
|
+
WHEN_NOT_TO_USE_SECTION,
|
|
44719
|
+
TROUBLESHOOTING_SECTION
|
|
44720
|
+
].join("\n\n");
|
|
44721
|
+
var CLAUDE_CODE_HEADER = `[SHIPYARD] Collaborative task management with human review & proof-of-work tracking.`;
|
|
44722
|
+
var TASK_MODE_WORKFLOW = `## How to Use (Claude Code with Hooks)
|
|
44723
|
+
|
|
44724
|
+
You have the **full Shipyard experience** with automatic hooks. Use native task mode:
|
|
44725
|
+
|
|
44726
|
+
### Workflow
|
|
44727
|
+
|
|
44728
|
+
1. **Enter task mode** (Shift+Tab) \u2192 Browser opens with live task automatically
|
|
44729
|
+
2. **Write your task** with \`{#deliverable}\` markers for provable outcomes
|
|
44730
|
+
3. **Exit task mode** \u2192 Hook **BLOCKS** until human approves or requests changes
|
|
44731
|
+
4. **On approval** \u2192 You automatically receive: taskId, sessionToken, deliverable IDs
|
|
44732
|
+
5. **Do the work** \u2192 Take screenshots/videos as you implement
|
|
44733
|
+
6. **Upload artifacts** \u2192 \`${TOOL_NAMES2.ADD_ARTIFACT}(filePath, deliverableId)\` for each deliverable
|
|
44734
|
+
7. **Auto-complete** \u2192 When all deliverables have artifacts, task completes with snapshot URL
|
|
44735
|
+
|
|
44736
|
+
### After Approval
|
|
44737
|
+
|
|
44738
|
+
You only need ONE tool: \`${TOOL_NAMES2.ADD_ARTIFACT}\`
|
|
44739
|
+
|
|
44740
|
+
The hook automatically injects everything you need (taskId, sessionToken, deliverables).
|
|
44741
|
+
Just call \`${TOOL_NAMES2.ADD_ARTIFACT}\` with the file path and deliverable ID.
|
|
44742
|
+
|
|
44743
|
+
\`\`\`typescript
|
|
44744
|
+
/**
|
|
44745
|
+
* Example: After approval, you'll have these in context
|
|
44746
|
+
* taskId: "abc123"
|
|
44747
|
+
* sessionToken: "xyz..."
|
|
44748
|
+
* deliverables: [{ id: "del_xxx", text: "Screenshot of login" }]
|
|
44749
|
+
*/
|
|
44750
|
+
|
|
44751
|
+
await addArtifact({
|
|
44752
|
+
taskId,
|
|
44753
|
+
sessionToken,
|
|
44754
|
+
type: 'image',
|
|
44755
|
+
filename: 'login-page.png',
|
|
44756
|
+
source: 'file',
|
|
44757
|
+
filePath: '/tmp/screenshot.png',
|
|
44758
|
+
deliverableId: deliverables[0].id
|
|
44759
|
+
});
|
|
44760
|
+
\`\`\`
|
|
44761
|
+
|
|
44762
|
+
When the last deliverable gets an artifact, the task auto-completes and returns a snapshot URL.`;
|
|
44763
|
+
var POSTING_UPDATES_SECTION = `## Posting Progress Updates
|
|
44764
|
+
|
|
44765
|
+
For long-running tasks, keep reviewers informed with periodic updates:
|
|
44766
|
+
|
|
44767
|
+
\`\`\`typescript
|
|
44768
|
+
await postUpdate({
|
|
44769
|
+
taskId,
|
|
44770
|
+
sessionToken,
|
|
44771
|
+
message: "Starting work on authentication module"
|
|
44772
|
+
});
|
|
44773
|
+
\`\`\`
|
|
44774
|
+
|
|
44775
|
+
**When to post updates:**
|
|
44776
|
+
- After completing a significant milestone
|
|
44777
|
+
- When switching focus to a different part of the task
|
|
44778
|
+
- If you've been working for a while without visible output
|
|
44779
|
+
- When you encounter something interesting or unexpected
|
|
44780
|
+
|
|
44781
|
+
Think about what a human watching your work would want to know.`;
|
|
44782
|
+
var IMPORTANT_NOTES = `## Important Notes for Claude Code
|
|
44783
|
+
|
|
44784
|
+
- **DO NOT call \`createTask()\` directly** - The hook handles task creation when you enter task mode
|
|
44785
|
+
- **DO NOT use the Shipyard skill** - The hook provides everything you need
|
|
44786
|
+
- **DO NOT poll for approval** - The hook blocks automatically until human decides
|
|
44787
|
+
- **DO use task mode** for ANY work that needs tracking, verification, or human review
|
|
44788
|
+
- **DO use \`requestUserInput()\`** inside \`${TOOL_NAMES2.EXECUTE_CODE}\` instead of \`AskUserQuestion\` - The human is in the browser viewing your task, questions should appear there`;
|
|
44789
|
+
var CLAUDE_CODE_INSTRUCTIONS = [
|
|
44790
|
+
CLAUDE_CODE_HEADER,
|
|
44791
|
+
"",
|
|
44792
|
+
CRITICAL_USAGE_SECTION,
|
|
44793
|
+
"",
|
|
44794
|
+
USER_INPUT_SECTION,
|
|
44795
|
+
"",
|
|
44796
|
+
TASK_MODE_WORKFLOW,
|
|
44797
|
+
"",
|
|
44798
|
+
POSTING_UPDATES_SECTION,
|
|
44799
|
+
"",
|
|
44800
|
+
DELIVERABLES_SECTION,
|
|
44801
|
+
"",
|
|
44802
|
+
ARTIFACT_TYPES_SECTION,
|
|
44803
|
+
"",
|
|
44804
|
+
IMPORTANT_NOTES,
|
|
44805
|
+
"",
|
|
44806
|
+
TIPS_SECTION,
|
|
44807
|
+
"",
|
|
44808
|
+
WHEN_NOT_TO_USE_SECTION,
|
|
44809
|
+
"",
|
|
44810
|
+
TROUBLESHOOTING_SECTION
|
|
44811
|
+
].join("\n");
|
|
44812
|
+
var MCP_DIRECT_HEADER = `# Shipyard: Your Agent Management Hub
|
|
44813
|
+
|
|
44814
|
+
> **Shipyard is the central interface where humans manage AI agents.** Tasks, artifacts, feedback, and communication all happen here.
|
|
44815
|
+
|
|
44816
|
+
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.
|
|
44817
|
+
|
|
44818
|
+
**Key principle:** When you're working in Shipyard, ALL human-agent communication should happen through \`requestUserInput()\` inside \`${TOOL_NAMES2.EXECUTE_CODE}\`. The human is already in the browser viewing your task - that's where they expect to interact with you.`;
|
|
44819
|
+
var MCP_TOOLS_OVERVIEW = `## Available MCP Tools
|
|
44820
|
+
|
|
44821
|
+
| Tool | Purpose |
|
|
44822
|
+
|------|---------|
|
|
44823
|
+
| \`${TOOL_NAMES2.EXECUTE_CODE}\` | Run TypeScript that calls ALL Shipyard APIs including \`requestUserInput()\` |
|
|
44824
|
+
|
|
44825
|
+
### requestUserInput(): Your Direct Line to the Human
|
|
44826
|
+
|
|
44827
|
+
This is how you talk to humans during active work. Don't use your platform's built-in question tools (AskUserQuestion, etc.) - use \`requestUserInput()\` inside \`${TOOL_NAMES2.EXECUTE_CODE}\` instead. The human is in the browser viewing your task, and that's where they expect to see your questions.
|
|
44828
|
+
|
|
44829
|
+
All Shipyard operations (createTask, addArtifact, requestUserInput, etc.) are available inside \`${TOOL_NAMES2.EXECUTE_CODE}\`.`;
|
|
44830
|
+
var MCP_WORKFLOW = `## Workflow (MCP Direct)
|
|
44831
|
+
|
|
44832
|
+
### Step 1: Create Task
|
|
44833
|
+
|
|
44834
|
+
\`\`\`typescript
|
|
44835
|
+
const task = await createTask({
|
|
44836
|
+
title: "Add user authentication",
|
|
44837
|
+
content: \`
|
|
44838
|
+
## Deliverables
|
|
44839
|
+
- [ ] Screenshot of login page {#deliverable}
|
|
44840
|
+
- [ ] Screenshot of error handling {#deliverable}
|
|
44841
|
+
|
|
44842
|
+
## Implementation
|
|
44843
|
+
1. Create login form component
|
|
44844
|
+
2. Add validation
|
|
44845
|
+
3. Connect to auth API
|
|
44846
|
+
\`
|
|
44847
|
+
});
|
|
44848
|
+
|
|
44849
|
+
const { taskId, sessionToken, deliverables, monitoringScript } = task;
|
|
44850
|
+
/** deliverables = [{ id: "del_xxx", text: "Screenshot of login page" }, ...] */
|
|
44851
|
+
\`\`\`
|
|
44852
|
+
|
|
44853
|
+
### Step 2: Wait for Approval
|
|
44854
|
+
|
|
44855
|
+
For platforms without hooks, run the monitoring script in the background:
|
|
44856
|
+
|
|
44857
|
+
\`\`\`bash
|
|
44858
|
+
# The monitoringScript polls for approval status
|
|
44859
|
+
# Run it in background while you wait
|
|
44860
|
+
bash <(echo "$monitoringScript") &
|
|
44861
|
+
\`\`\`
|
|
44862
|
+
|
|
44863
|
+
Or poll manually:
|
|
44864
|
+
|
|
44865
|
+
\`\`\`typescript
|
|
44866
|
+
const status = await readTask(taskId, sessionToken);
|
|
44867
|
+
if (status.status === "in_progress") {
|
|
44868
|
+
/** Approved! Proceed with work */
|
|
44869
|
+
}
|
|
44870
|
+
if (status.status === "changes_requested") {
|
|
44871
|
+
/** Read feedback, make changes */
|
|
44872
|
+
}
|
|
44873
|
+
\`\`\`
|
|
44874
|
+
|
|
44875
|
+
### Step 3: Do the Work
|
|
44876
|
+
|
|
44877
|
+
Implement the feature, taking screenshots/recordings as you go.
|
|
44878
|
+
|
|
44879
|
+
### Step 4: Upload Artifacts
|
|
44880
|
+
|
|
44881
|
+
\`\`\`typescript
|
|
44882
|
+
await addArtifact({
|
|
44883
|
+
taskId,
|
|
44884
|
+
sessionToken,
|
|
44885
|
+
type: 'image',
|
|
44886
|
+
filename: 'login-page.png',
|
|
44887
|
+
source: 'file',
|
|
44888
|
+
filePath: '/path/to/screenshot.png',
|
|
44889
|
+
deliverableId: deliverables[0].id
|
|
44890
|
+
});
|
|
44891
|
+
|
|
44892
|
+
const result = await addArtifact({
|
|
44893
|
+
taskId,
|
|
44894
|
+
sessionToken,
|
|
44895
|
+
type: 'image',
|
|
44896
|
+
filename: 'error-handling.png',
|
|
44897
|
+
source: 'file',
|
|
44898
|
+
filePath: '/path/to/error.png',
|
|
44899
|
+
deliverableId: deliverables[1].id
|
|
44900
|
+
});
|
|
44901
|
+
|
|
44902
|
+
/** Auto-complete triggers when ALL deliverables have artifacts */
|
|
44903
|
+
if (result.allDeliverablesComplete) {
|
|
44904
|
+
console.log('Done!', result.snapshotUrl);
|
|
44905
|
+
}
|
|
44906
|
+
\`\`\``;
|
|
44907
|
+
var API_REFERENCE = `## API Reference (inside execute_code)
|
|
44908
|
+
|
|
44909
|
+
### createTask(options)
|
|
44910
|
+
|
|
44911
|
+
Creates a new task and opens it in the browser.
|
|
44912
|
+
|
|
44913
|
+
**Parameters:**
|
|
44914
|
+
- \`title\` (string) - Task title
|
|
44915
|
+
- \`content\` (string) - Markdown content with \`{#deliverable}\` markers
|
|
44916
|
+
- \`repo\` (string, optional) - GitHub repo for artifact storage
|
|
44917
|
+
- \`prNumber\` (number, optional) - PR number to link
|
|
44918
|
+
|
|
44919
|
+
**Returns:** \`{ taskId, sessionToken, url, deliverables, monitoringScript }\`
|
|
44920
|
+
|
|
44921
|
+
### readTask(taskId, sessionToken, options?)
|
|
44922
|
+
|
|
44923
|
+
Reads current task state.
|
|
44924
|
+
|
|
44925
|
+
**Parameters:**
|
|
44926
|
+
- \`taskId\` (string) - Task ID
|
|
44927
|
+
- \`sessionToken\` (string) - Session token from createTask
|
|
44928
|
+
- \`options.includeAnnotations\` (boolean) - Include reviewer comments
|
|
44929
|
+
|
|
44930
|
+
**Returns:** \`{ content, status, title, deliverables }\`
|
|
44931
|
+
|
|
44932
|
+
### addArtifact(options)
|
|
44933
|
+
|
|
44934
|
+
Uploads proof-of-work artifact.
|
|
44935
|
+
|
|
44936
|
+
**Parameters:**
|
|
44937
|
+
- \`taskId\` (string) - Task ID
|
|
44938
|
+
- \`sessionToken\` (string) - Session token
|
|
44939
|
+
- \`type\` ('html' | 'image' | 'video')
|
|
44940
|
+
- \`filename\` (string) - File name
|
|
44941
|
+
- \`source\` ('file' | 'url' | 'base64')
|
|
44942
|
+
- \`filePath\` (string) - Local file path (when source='file')
|
|
44943
|
+
- \`deliverableId\` (string, optional) - Links artifact to deliverable
|
|
44944
|
+
|
|
44945
|
+
**Returns:** \`{ artifactId, url, allDeliverablesComplete, snapshotUrl? }\`
|
|
44946
|
+
|
|
44947
|
+
### requestUserInput(options)
|
|
44948
|
+
|
|
44949
|
+
**THE primary human-agent communication channel.** Asks user a question via browser modal.
|
|
44950
|
+
|
|
44951
|
+
**IMPORTANT: Always RETURN the response value in your execute_code result.**
|
|
44952
|
+
|
|
44953
|
+
\u2705 **RECOMMENDED (primary pattern):**
|
|
44954
|
+
\`\`\`typescript
|
|
44955
|
+
const result = await requestUserInput({ message: "Which database?", type: "choice", options: ["PostgreSQL", "SQLite"] });
|
|
44956
|
+
return { userChoice: result.response, status: result.status };
|
|
44957
|
+
// Clean, structured output appears once in the final result
|
|
44958
|
+
\`\`\`
|
|
44959
|
+
|
|
44960
|
+
\u26A0\uFE0F **AVOID (use only for debugging):**
|
|
44961
|
+
\`\`\`typescript
|
|
44962
|
+
console.log(\\\`User chose: \\\${result.response}\\\`);
|
|
44963
|
+
// Clutters output, not structured
|
|
44964
|
+
\`\`\`
|
|
44965
|
+
|
|
44966
|
+
**Two modes - choose based on dependencies:**
|
|
44967
|
+
|
|
44968
|
+
**Multi-step (dependencies):** Chain calls when later questions depend on earlier answers
|
|
44969
|
+
\`\`\`typescript
|
|
44970
|
+
const db = await requestUserInput({ message: "Database?", type: "choice", options: ["PostgreSQL", "SQLite"] });
|
|
44971
|
+
const port = await requestUserInput({ message: \\\`Port for \\\${db.response}?\\\`, type: "number" });
|
|
44972
|
+
return { database: db.response, port: port.response };
|
|
44973
|
+
\`\`\`
|
|
44974
|
+
|
|
44975
|
+
**Multi-form (independent):** Single call for unrelated questions
|
|
44976
|
+
\`\`\`typescript
|
|
44977
|
+
const config = await requestUserInput({
|
|
44978
|
+
questions: [
|
|
44979
|
+
{ message: "Project name?", type: "text" },
|
|
44980
|
+
{ message: "Use TypeScript?", type: "confirm" }
|
|
44981
|
+
]
|
|
44982
|
+
});
|
|
44983
|
+
return { config: config.response };
|
|
44984
|
+
\`\`\`
|
|
44985
|
+
|
|
44986
|
+
**Parameters (single-question mode):**
|
|
44987
|
+
- \`message\` (string) - Question to ask
|
|
44988
|
+
- \`type\` (string) - Input type (see below)
|
|
44989
|
+
- \`options\` (string[], for 'choice') - Available choices
|
|
44990
|
+
- \`timeout\` (number, optional) - Timeout in seconds
|
|
44991
|
+
- Type-specific parameters (min, max, format, etc.)
|
|
44992
|
+
|
|
44993
|
+
**Parameters (multi-question mode):**
|
|
44994
|
+
- \`questions\` (array) - Array of 1-10 questions (8 recommended)
|
|
44995
|
+
- \`timeout\` (number, optional) - Timeout in seconds
|
|
44996
|
+
|
|
44997
|
+
**Returns:** \`{ success, response?, status }\`
|
|
44998
|
+
|
|
44999
|
+
**Supported types (8 total):**
|
|
45000
|
+
1. \`text\` - Single-line text
|
|
45001
|
+
2. \`multiline\` - Multi-line text area
|
|
45002
|
+
3. \`choice\` - Radio/checkbox/dropdown (auto-adds "Other" option)
|
|
45003
|
+
4. \`confirm\` - Yes/No buttons
|
|
45004
|
+
5. \`number\` - Numeric input with validation
|
|
45005
|
+
6. \`email\` - Email validation
|
|
45006
|
+
7. \`date\` - Date picker with range
|
|
45007
|
+
8. \`rating\` - Scale rating`;
|
|
45008
|
+
var HANDLING_FEEDBACK = `## Handling Reviewer Feedback
|
|
45009
|
+
|
|
45010
|
+
\`\`\`typescript
|
|
45011
|
+
const status = await readTask(taskId, sessionToken, {
|
|
45012
|
+
includeAnnotations: true
|
|
45013
|
+
});
|
|
45014
|
+
|
|
45015
|
+
if (status.status === "changes_requested") {
|
|
45016
|
+
/** Read the content for inline comments */
|
|
45017
|
+
console.log(status.content);
|
|
45018
|
+
|
|
45019
|
+
/**
|
|
45020
|
+
* Make changes based on feedback
|
|
45021
|
+
* Upload new artifacts
|
|
45022
|
+
* Task will transition back to pending_review
|
|
45023
|
+
*/
|
|
45024
|
+
}
|
|
45025
|
+
\`\`\``;
|
|
45026
|
+
var MCP_DIRECT_INSTRUCTIONS = [
|
|
45027
|
+
MCP_DIRECT_HEADER,
|
|
45028
|
+
"",
|
|
45029
|
+
CRITICAL_USAGE_SECTION,
|
|
45030
|
+
"",
|
|
45031
|
+
USER_INPUT_SECTION,
|
|
45032
|
+
"",
|
|
45033
|
+
MCP_TOOLS_OVERVIEW,
|
|
45034
|
+
"",
|
|
45035
|
+
MCP_WORKFLOW,
|
|
45036
|
+
"",
|
|
45037
|
+
DELIVERABLES_SECTION,
|
|
45038
|
+
"",
|
|
45039
|
+
ARTIFACT_TYPES_SECTION,
|
|
45040
|
+
"",
|
|
45041
|
+
API_REFERENCE,
|
|
45042
|
+
"",
|
|
45043
|
+
HANDLING_FEEDBACK,
|
|
45044
|
+
"",
|
|
45045
|
+
TIPS_SECTION,
|
|
45046
|
+
"",
|
|
45047
|
+
WHEN_NOT_TO_USE_SECTION,
|
|
45048
|
+
"",
|
|
45049
|
+
TROUBLESHOOTING_SECTION
|
|
45050
|
+
].join("\n");
|
|
45051
|
+
|
|
45052
|
+
// src/adapters/claude-code.ts
|
|
45053
|
+
init_cjs_shims();
|
|
44737
45054
|
|
|
44738
45055
|
// src/constants.ts
|
|
44739
45056
|
init_cjs_shims();
|
|
@@ -44835,11 +45152,11 @@ function handlePreToolUse(input) {
|
|
|
44835
45152
|
if (toolName === CLAUDE_TOOL_NAMES.ASK_USER_QUESTION) {
|
|
44836
45153
|
logger.info(
|
|
44837
45154
|
{ toolName },
|
|
44838
|
-
"Blocking AskUserQuestion - redirecting to
|
|
45155
|
+
"Blocking AskUserQuestion - redirecting to requestUserInput() in execute_code"
|
|
44839
45156
|
);
|
|
44840
45157
|
return {
|
|
44841
45158
|
type: "tool_deny",
|
|
44842
|
-
reason: `BLOCKED: Use
|
|
45159
|
+
reason: `BLOCKED: Use requestUserInput() inside ${TOOL_NAMES.EXECUTE_CODE} instead. The human is in the browser viewing your plan - that's where they expect to interact with you. See the execute_code tool description for input types and parameters.`
|
|
44843
45160
|
};
|
|
44844
45161
|
}
|
|
44845
45162
|
return { type: "passthrough" };
|
|
@@ -46203,7 +46520,7 @@ async function retryWithBackoff(fn, maxAttempts = 3, baseDelay = 1e3) {
|
|
|
46203
46520
|
try {
|
|
46204
46521
|
return await fn();
|
|
46205
46522
|
} catch (err) {
|
|
46206
|
-
lastError = err;
|
|
46523
|
+
lastError = err instanceof Error ? err : new Error(String(err));
|
|
46207
46524
|
if (attempt < maxAttempts - 1) {
|
|
46208
46525
|
const delay = attempt === 0 ? 0 : baseDelay * 2 ** (attempt - 1);
|
|
46209
46526
|
logger.debug(
|
|
@@ -46236,9 +46553,9 @@ async function getRegistryUrl() {
|
|
|
46236
46553
|
logger.debug({ port }, "Found registry server (with retry)");
|
|
46237
46554
|
return url2;
|
|
46238
46555
|
} catch (err) {
|
|
46239
|
-
const
|
|
46556
|
+
const errorMessage = err instanceof Error ? err.message : String(err);
|
|
46240
46557
|
logger.debug(
|
|
46241
|
-
{ port, error:
|
|
46558
|
+
{ port, error: errorMessage },
|
|
46242
46559
|
"Failed to connect to registry port after retries"
|
|
46243
46560
|
);
|
|
46244
46561
|
}
|
|
@@ -46407,7 +46724,49 @@ var webConfig = loadEnv(schema3);
|
|
|
46407
46724
|
init_cjs_shims();
|
|
46408
46725
|
|
|
46409
46726
|
// src/core/review-status.ts
|
|
46410
|
-
|
|
46727
|
+
function buildApprovalMessage(prefix, deliverableCount, reviewComment) {
|
|
46728
|
+
const countText = `${deliverableCount} deliverable${deliverableCount === 1 ? "" : "s"}`;
|
|
46729
|
+
const feedbackText = reviewComment ? `
|
|
46730
|
+
|
|
46731
|
+
Reviewer comment: ${reviewComment}` : "";
|
|
46732
|
+
return `${prefix} You have ${countText}. Use add_artifact(filePath, deliverableId) to upload proof-of-work.${feedbackText}`;
|
|
46733
|
+
}
|
|
46734
|
+
async function handleApproval(planId, decision, messagePrefix) {
|
|
46735
|
+
const sessionToken = generateSessionToken();
|
|
46736
|
+
const sessionTokenHash = hashSessionToken(sessionToken);
|
|
46737
|
+
const deliverableCount = (decision.deliverables ?? []).length;
|
|
46738
|
+
logger.info({ planId }, "Generating session token for approved plan");
|
|
46739
|
+
try {
|
|
46740
|
+
const tokenResult = await setSessionToken(planId, sessionTokenHash);
|
|
46741
|
+
const url2 = tokenResult.url;
|
|
46742
|
+
logger.info(
|
|
46743
|
+
{ planId, url: url2, deliverableCount },
|
|
46744
|
+
"Session token set and stored by server with deliverables"
|
|
46745
|
+
);
|
|
46746
|
+
return {
|
|
46747
|
+
allow: true,
|
|
46748
|
+
message: buildApprovalMessage(messagePrefix, deliverableCount, decision.reviewComment),
|
|
46749
|
+
planId,
|
|
46750
|
+
sessionToken,
|
|
46751
|
+
url: url2
|
|
46752
|
+
};
|
|
46753
|
+
} catch (err) {
|
|
46754
|
+
logger.error({ err, planId }, "Failed to set session token, approving without it");
|
|
46755
|
+
return {
|
|
46756
|
+
allow: true,
|
|
46757
|
+
message: `${messagePrefix.replace("!", "")} (session token unavailable)`,
|
|
46758
|
+
planId
|
|
46759
|
+
};
|
|
46760
|
+
}
|
|
46761
|
+
}
|
|
46762
|
+
function handleRejection(planId, decision) {
|
|
46763
|
+
return {
|
|
46764
|
+
allow: false,
|
|
46765
|
+
message: decision.reviewComment || "Changes requested",
|
|
46766
|
+
planId
|
|
46767
|
+
};
|
|
46768
|
+
}
|
|
46769
|
+
async function waitForReviewDecision(planId) {
|
|
46411
46770
|
logger.info({ planId }, "Waiting for approval via server endpoint");
|
|
46412
46771
|
const result = await waitForApproval(planId, planId);
|
|
46413
46772
|
logger.info({ planId, approved: result.approved }, "Received approval decision from server");
|
|
@@ -46427,12 +46786,10 @@ async function handleUpdatedPlanReview(sessionId, planId, planContent, _originMe
|
|
|
46427
46786
|
);
|
|
46428
46787
|
logger.info({ planId }, "Syncing updated plan content");
|
|
46429
46788
|
try {
|
|
46430
|
-
await updatePlanContent(planId, {
|
|
46431
|
-
content: planContent
|
|
46432
|
-
});
|
|
46789
|
+
await updatePlanContent(planId, { content: planContent });
|
|
46433
46790
|
} catch (err) {
|
|
46434
|
-
const
|
|
46435
|
-
if (
|
|
46791
|
+
const errorMessage = err instanceof Error ? err.message : String(err);
|
|
46792
|
+
if (errorMessage?.includes("404")) {
|
|
46436
46793
|
logger.warn(
|
|
46437
46794
|
{ planId, sessionId },
|
|
46438
46795
|
"Plan not found (404), creating new plan with updated content"
|
|
@@ -46446,116 +46803,93 @@ async function handleUpdatedPlanReview(sessionId, planId, planContent, _originMe
|
|
|
46446
46803
|
{ planId, url: createPlanWebUrl(baseUrl, planId) },
|
|
46447
46804
|
"Content synced, browser already open. Waiting for server approval..."
|
|
46448
46805
|
);
|
|
46449
|
-
const decision = await waitForReviewDecision(planId
|
|
46806
|
+
const decision = await waitForReviewDecision(planId);
|
|
46450
46807
|
logger.info({ planId, approved: decision.approved }, "Decision received via Y.Doc");
|
|
46451
46808
|
if (decision.approved) {
|
|
46452
|
-
|
|
46453
|
-
|
|
46454
|
-
|
|
46455
|
-
|
|
46456
|
-
|
|
46457
|
-
|
|
46458
|
-
|
|
46459
|
-
|
|
46460
|
-
|
|
46461
|
-
|
|
46462
|
-
|
|
46463
|
-
|
|
46809
|
+
return handleApproval(planId, decision, "Plan re-approved with updates!");
|
|
46810
|
+
}
|
|
46811
|
+
logger.debug({ planId }, "Changes requested - server will manage state cleanup");
|
|
46812
|
+
return handleRejection(planId, decision);
|
|
46813
|
+
}
|
|
46814
|
+
async function handleNewPlanCreation(sessionId, planContent, originMetadata) {
|
|
46815
|
+
logger.info(
|
|
46816
|
+
{ sessionId, contentLength: planContent.length },
|
|
46817
|
+
"Creating plan from ExitPlanMode (blocking mode)"
|
|
46818
|
+
);
|
|
46819
|
+
const result = await createPlan({
|
|
46820
|
+
sessionId,
|
|
46821
|
+
agentType: DEFAULT_AGENT_TYPE,
|
|
46822
|
+
metadata: {
|
|
46823
|
+
source: "ExitPlanMode",
|
|
46824
|
+
...originMetadata
|
|
46825
|
+
}
|
|
46826
|
+
});
|
|
46827
|
+
const planId = result.planId;
|
|
46828
|
+
logger.info({ planId }, "Syncing plan content");
|
|
46829
|
+
await updatePlanContent(planId, { content: planContent });
|
|
46830
|
+
logger.info(
|
|
46831
|
+
{ planId, url: result.url },
|
|
46832
|
+
"Plan created and synced, browser opened. Waiting for server approval..."
|
|
46833
|
+
);
|
|
46834
|
+
const decision = await waitForReviewDecision(planId);
|
|
46835
|
+
logger.info({ planId, approved: decision.approved }, "Decision received via Y.Doc");
|
|
46836
|
+
if (decision.approved) {
|
|
46837
|
+
return handleApproval(planId, decision, "Plan approved!");
|
|
46838
|
+
}
|
|
46839
|
+
logger.debug({ sessionId }, "Changes requested - server will manage state cleanup");
|
|
46840
|
+
return handleRejection(planId, decision);
|
|
46841
|
+
}
|
|
46842
|
+
function buildStatusResponse(status, planId, baseUrl) {
|
|
46843
|
+
switch (status.status) {
|
|
46844
|
+
case "changes_requested":
|
|
46845
|
+
return {
|
|
46846
|
+
allow: false,
|
|
46847
|
+
message: formatFeedbackMessage(status.feedback),
|
|
46848
|
+
feedback: status.feedback,
|
|
46849
|
+
planId
|
|
46850
|
+
};
|
|
46851
|
+
case "pending_review":
|
|
46852
|
+
return {
|
|
46853
|
+
allow: false,
|
|
46854
|
+
message: `Plan is pending review.
|
|
46464
46855
|
|
|
46465
|
-
|
|
46856
|
+
Open: ${createPlanWebUrl(baseUrl, planId)}`,
|
|
46857
|
+
planId
|
|
46858
|
+
};
|
|
46859
|
+
case "draft":
|
|
46860
|
+
return {
|
|
46861
|
+
allow: false,
|
|
46862
|
+
message: `Plan is still in draft.
|
|
46863
|
+
|
|
46864
|
+
Submit for review at: ${createPlanWebUrl(baseUrl, planId)}`,
|
|
46865
|
+
planId
|
|
46866
|
+
};
|
|
46867
|
+
case "in_progress":
|
|
46466
46868
|
return {
|
|
46467
46869
|
allow: true,
|
|
46468
|
-
message:
|
|
46469
|
-
planId
|
|
46470
|
-
sessionToken,
|
|
46471
|
-
url: url2
|
|
46870
|
+
message: "Plan approved. Work is in progress. Use add_artifact(filePath, deliverableId) to upload deliverable proofs.",
|
|
46871
|
+
planId
|
|
46472
46872
|
};
|
|
46473
|
-
|
|
46474
|
-
logger.error({ err, planId }, "Failed to set session token, but plan was approved");
|
|
46873
|
+
case "completed":
|
|
46475
46874
|
return {
|
|
46476
46875
|
allow: true,
|
|
46477
|
-
message:
|
|
46876
|
+
message: `Task completed by ${status.completedBy}`,
|
|
46478
46877
|
planId
|
|
46479
46878
|
};
|
|
46480
|
-
|
|
46879
|
+
default:
|
|
46880
|
+
assertNever2(status);
|
|
46481
46881
|
}
|
|
46482
|
-
logger.debug({ planId }, "Changes requested - server will manage state cleanup");
|
|
46483
|
-
return {
|
|
46484
|
-
allow: false,
|
|
46485
|
-
message: decision.reviewComment || "Changes requested",
|
|
46486
|
-
planId
|
|
46487
|
-
};
|
|
46488
46882
|
}
|
|
46489
46883
|
async function checkReviewStatus(sessionId, planContent, originMetadata) {
|
|
46490
46884
|
const state = await getSessionContext(sessionId);
|
|
46491
|
-
let planId;
|
|
46492
46885
|
if (!state.found && planContent) {
|
|
46493
|
-
|
|
46494
|
-
{ sessionId, contentLength: planContent.length, hasState: !!state },
|
|
46495
|
-
"Creating plan from ExitPlanMode (blocking mode)"
|
|
46496
|
-
);
|
|
46497
|
-
const result = await createPlan({
|
|
46498
|
-
sessionId,
|
|
46499
|
-
agentType: DEFAULT_AGENT_TYPE,
|
|
46500
|
-
metadata: {
|
|
46501
|
-
source: "ExitPlanMode",
|
|
46502
|
-
...originMetadata
|
|
46503
|
-
}
|
|
46504
|
-
});
|
|
46505
|
-
planId = result.planId;
|
|
46506
|
-
logger.info({ planId }, "Syncing plan content");
|
|
46507
|
-
await updatePlanContent(planId, {
|
|
46508
|
-
content: planContent
|
|
46509
|
-
});
|
|
46510
|
-
logger.info(
|
|
46511
|
-
{ planId, url: result.url },
|
|
46512
|
-
"Plan created and synced, browser opened. Waiting for server approval..."
|
|
46513
|
-
);
|
|
46514
|
-
const decision = await waitForReviewDecision(planId, "");
|
|
46515
|
-
logger.info({ planId, approved: decision.approved }, "Decision received via Y.Doc");
|
|
46516
|
-
if (decision.approved) {
|
|
46517
|
-
const sessionToken = generateSessionToken();
|
|
46518
|
-
const sessionTokenHash = hashSessionToken(sessionToken);
|
|
46519
|
-
logger.info({ planId }, "Generating session token for approved plan");
|
|
46520
|
-
try {
|
|
46521
|
-
const tokenResult = await setSessionToken(planId, sessionTokenHash);
|
|
46522
|
-
const url2 = tokenResult.url;
|
|
46523
|
-
const deliverableCount = (decision.deliverables ?? []).length;
|
|
46524
|
-
logger.info(
|
|
46525
|
-
{ planId, url: url2, deliverableCount },
|
|
46526
|
-
"Session token set and stored by server with deliverables"
|
|
46527
|
-
);
|
|
46528
|
-
const reviewFeedback = decision.reviewComment ? `
|
|
46529
|
-
|
|
46530
|
-
Reviewer comment: ${decision.reviewComment}` : "";
|
|
46531
|
-
return {
|
|
46532
|
-
allow: true,
|
|
46533
|
-
message: `Plan approved! You have ${deliverableCount} deliverable${deliverableCount === 1 ? "" : "s"}. Use add_artifact(filePath, deliverableId) to upload proof-of-work.${reviewFeedback}`,
|
|
46534
|
-
planId,
|
|
46535
|
-
sessionToken,
|
|
46536
|
-
url: url2
|
|
46537
|
-
};
|
|
46538
|
-
} catch (err) {
|
|
46539
|
-
logger.error({ err, planId }, "Failed to set session token, approving without it");
|
|
46540
|
-
return {
|
|
46541
|
-
allow: true,
|
|
46542
|
-
message: "Plan approved, but session token unavailable. You may need to refresh the plan in the browser. Check ~/.shipyard/server-debug.log for details.",
|
|
46543
|
-
planId
|
|
46544
|
-
};
|
|
46545
|
-
}
|
|
46546
|
-
}
|
|
46547
|
-
logger.debug({ sessionId }, "Changes requested - server will manage state cleanup");
|
|
46548
|
-
return {
|
|
46549
|
-
allow: false,
|
|
46550
|
-
message: decision.reviewComment || "Changes requested",
|
|
46551
|
-
planId
|
|
46552
|
-
};
|
|
46886
|
+
return handleNewPlanCreation(sessionId, planContent, originMetadata);
|
|
46553
46887
|
}
|
|
46554
46888
|
if (!state.found) {
|
|
46555
46889
|
logger.info({ sessionId }, "No session state or plan content, allowing exit");
|
|
46556
46890
|
return { allow: true };
|
|
46557
46891
|
}
|
|
46558
|
-
if (
|
|
46892
|
+
if (!state.planId && planContent) {
|
|
46559
46893
|
logger.error(
|
|
46560
46894
|
{ sessionId, hasPlanContent: !!planContent, hasState: !!state, statePlanId: state?.planId },
|
|
46561
46895
|
"Unreachable state: plan content exists but no session state"
|
|
@@ -46568,7 +46902,7 @@ Reviewer comment: ${decision.reviewComment}` : "";
|
|
|
46568
46902
|
if (!state.planId) {
|
|
46569
46903
|
throw new Error("Unreachable: state.planId should exist at this point");
|
|
46570
46904
|
}
|
|
46571
|
-
planId = state.planId;
|
|
46905
|
+
const planId = state.planId;
|
|
46572
46906
|
if (planContent) {
|
|
46573
46907
|
logger.info({ planId }, "Plan content provided, triggering re-review");
|
|
46574
46908
|
return await handleUpdatedPlanReview(sessionId, planId, planContent, originMetadata);
|
|
@@ -46587,46 +46921,7 @@ Reviewer comment: ${decision.reviewComment}` : "";
|
|
|
46587
46921
|
}
|
|
46588
46922
|
logger.info({ sessionId, planId, status: status.status }, "Review status retrieved");
|
|
46589
46923
|
const baseUrl = webConfig.SHIPYARD_WEB_URL;
|
|
46590
|
-
|
|
46591
|
-
case "changes_requested":
|
|
46592
|
-
return {
|
|
46593
|
-
allow: false,
|
|
46594
|
-
message: formatFeedbackMessage(status.feedback),
|
|
46595
|
-
feedback: status.feedback,
|
|
46596
|
-
planId
|
|
46597
|
-
};
|
|
46598
|
-
case "pending_review":
|
|
46599
|
-
return {
|
|
46600
|
-
allow: false,
|
|
46601
|
-
message: `Plan is pending review.
|
|
46602
|
-
|
|
46603
|
-
Open: ${createPlanWebUrl(baseUrl, planId)}`,
|
|
46604
|
-
planId
|
|
46605
|
-
};
|
|
46606
|
-
case "draft":
|
|
46607
|
-
return {
|
|
46608
|
-
allow: false,
|
|
46609
|
-
message: `Plan is still in draft.
|
|
46610
|
-
|
|
46611
|
-
Submit for review at: ${createPlanWebUrl(baseUrl, planId)}`,
|
|
46612
|
-
planId
|
|
46613
|
-
};
|
|
46614
|
-
case "in_progress":
|
|
46615
|
-
return {
|
|
46616
|
-
allow: true,
|
|
46617
|
-
message: "Plan approved. Work is in progress. Use add_artifact(filePath, deliverableId) to upload deliverable proofs.",
|
|
46618
|
-
planId
|
|
46619
|
-
};
|
|
46620
|
-
case "completed":
|
|
46621
|
-
return {
|
|
46622
|
-
allow: true,
|
|
46623
|
-
message: `Task completed by ${status.completedBy}`,
|
|
46624
|
-
planId
|
|
46625
|
-
};
|
|
46626
|
-
default: {
|
|
46627
|
-
assertNever2(status);
|
|
46628
|
-
}
|
|
46629
|
-
}
|
|
46924
|
+
return buildStatusResponse(status, planId, baseUrl);
|
|
46630
46925
|
}
|
|
46631
46926
|
function formatFeedbackMessage(feedback) {
|
|
46632
46927
|
if (!feedback?.length) {
|
|
@@ -46683,13 +46978,11 @@ async function handlePlanExit(event) {
|
|
|
46683
46978
|
try {
|
|
46684
46979
|
return await checkReviewStatus(event.sessionId, event.planContent, event.metadata);
|
|
46685
46980
|
} catch (err) {
|
|
46686
|
-
const
|
|
46687
|
-
|
|
46688
|
-
|
|
46689
|
-
|
|
46690
|
-
|
|
46691
|
-
const isConnectionError = error48.code === "ECONNREFUSED" || error48.code === "ECONNRESET" || error48.code === "ETIMEDOUT" || error48.code === "ENOTFOUND" || error48.message?.includes("connect") || error48.message?.includes("timeout") || error48.message?.includes("WebSocket") || error48.message?.includes("not available");
|
|
46692
|
-
const message = isConnectionError ? "Cannot connect to Shipyard server. Ensure the Shipyard MCP server is running. Check ~/.shipyard/hook-debug.log for details." : `Review system error: ${error48.message}. Check ~/.shipyard/hook-debug.log for details.`;
|
|
46981
|
+
const errorMessage = err instanceof Error ? err.message : String(err);
|
|
46982
|
+
const errorCode = err instanceof Error && "code" in err && typeof err.code === "string" ? err.code : void 0;
|
|
46983
|
+
logger.error({ err, message: errorMessage, code: errorCode }, "Failed to check review status");
|
|
46984
|
+
const isConnectionError = errorCode === "ECONNREFUSED" || errorCode === "ECONNRESET" || errorCode === "ETIMEDOUT" || errorCode === "ENOTFOUND" || errorMessage?.includes("connect") || errorMessage?.includes("timeout") || errorMessage?.includes("WebSocket") || errorMessage?.includes("not available");
|
|
46985
|
+
const message = isConnectionError ? "Cannot connect to Shipyard server. Ensure the Shipyard MCP server is running. Check ~/.shipyard/hook-debug.log for details." : `Review system error: ${errorMessage}. Check ~/.shipyard/hook-debug.log for details.`;
|
|
46693
46986
|
return {
|
|
46694
46987
|
allow: false,
|
|
46695
46988
|
message
|
|
@@ -46760,7 +47053,9 @@ async function processEvent(_adapter, event) {
|
|
|
46760
47053
|
async function readStdin() {
|
|
46761
47054
|
const chunks = [];
|
|
46762
47055
|
for await (const chunk of process.stdin) {
|
|
46763
|
-
|
|
47056
|
+
if (isBuffer(chunk)) {
|
|
47057
|
+
chunks.push(chunk);
|
|
47058
|
+
}
|
|
46764
47059
|
}
|
|
46765
47060
|
return Buffer.concat(chunks).toString("utf-8");
|
|
46766
47061
|
}
|
|
@@ -46795,13 +47090,14 @@ async function main() {
|
|
|
46795
47090
|
process.exit(0);
|
|
46796
47091
|
} catch (err) {
|
|
46797
47092
|
logger.error({ err }, "Hook error, failing closed");
|
|
47093
|
+
const errorMessage = err instanceof Error ? err.message : String(err);
|
|
46798
47094
|
console.log(
|
|
46799
47095
|
JSON.stringify({
|
|
46800
47096
|
hookSpecificOutput: {
|
|
46801
47097
|
hookEventName: "PermissionRequest",
|
|
46802
47098
|
decision: {
|
|
46803
47099
|
behavior: "deny",
|
|
46804
|
-
message: `Hook error: ${
|
|
47100
|
+
message: `Hook error: ${errorMessage}. Check ~/.shipyard/hook-debug.log for details.`
|
|
46805
47101
|
}
|
|
46806
47102
|
}
|
|
46807
47103
|
})
|