@schoolai/shipyard-mcp 0.1.0 → 0.1.1

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.
@@ -9,6 +9,19 @@ import {
9
9
  } from "./chunk-GSGLHRWX.js";
10
10
 
11
11
  // src/services/input-request-manager.ts
12
+ function formatDuration(totalSeconds) {
13
+ const minutes = Math.floor(totalSeconds / 60);
14
+ const seconds = totalSeconds % 60;
15
+ if (minutes === 0) {
16
+ return `${seconds} second${seconds === 1 ? "" : "s"}`;
17
+ }
18
+ const minutePart = `${minutes} minute${minutes === 1 ? "" : "s"}`;
19
+ if (seconds === 0) {
20
+ return minutePart;
21
+ }
22
+ const secondPart = `${seconds} second${seconds === 1 ? "" : "s"}`;
23
+ return `${minutePart} ${secondPart}`;
24
+ }
12
25
  var InputRequestManager = class {
13
26
  /**
14
27
  * Create a new input request in the Y.Doc.
@@ -147,9 +160,7 @@ var InputRequestManager = class {
147
160
  if (resolved) return;
148
161
  resolved = true;
149
162
  cleanup();
150
- const minutes = Math.floor(effectiveTimeout / 60);
151
- const seconds = effectiveTimeout % 60;
152
- const timeStr = minutes > 0 ? `${minutes} minute${minutes === 1 ? "" : "s"}${seconds > 0 ? ` ${seconds} second${seconds === 1 ? "" : "s"}` : ""}` : `${seconds} second${seconds === 1 ? "" : "s"}`;
163
+ const timeStr = formatDuration(effectiveTimeout);
153
164
  resolve({
154
165
  success: false,
155
166
  status: "cancelled",
@@ -18,7 +18,7 @@ import {
18
18
  } from "./chunk-EBNL5ZX7.js";
19
19
  import {
20
20
  InputRequestManager
21
- } from "./chunk-SIQIBECG.js";
21
+ } from "./chunk-N44DCU4J.js";
22
22
  import {
23
23
  ArtifactSchema,
24
24
  DeliverableSchema,
@@ -899,15 +899,17 @@ async function waitForApprovalHandler(planId, _reviewRequestIdParam, ctx) {
899
899
  throw err;
900
900
  }
901
901
  const metadata = ydoc.getMap(YDOC_KEYS.METADATA);
902
- const reviewRequestId = nanoid2();
903
902
  const planMetadata = getPlanMetadata(ydoc);
904
903
  const ownerId = planMetadata?.ownerId ?? "unknown";
905
- if (planMetadata?.status === "pending_review") {
906
- ctx.logger.warn(
907
- { planId, currentStatus: planMetadata.status },
908
- "Status already pending_review, another hook may be waiting. Skipping reviewRequestId update."
904
+ let reviewRequestId;
905
+ if (planMetadata?.status === "pending_review" && planMetadata.reviewRequestId) {
906
+ reviewRequestId = planMetadata.reviewRequestId;
907
+ ctx.logger.info(
908
+ { planId, currentStatus: planMetadata.status, reviewRequestId },
909
+ "Status already pending_review, reusing existing reviewRequestId for observer"
909
910
  );
910
911
  } else {
912
+ reviewRequestId = nanoid2();
911
913
  const result = transitionPlanStatus(
912
914
  ydoc,
913
915
  {
@@ -1174,11 +1176,15 @@ function extractFeedbackFromYDoc(ydoc, ctx) {
1174
1176
  return "Changes requested. Check the plan for reviewer comments.";
1175
1177
  }
1176
1178
  const contentFragment = ydoc.getXmlFragment(YDOC_KEYS.DOCUMENT_FRAGMENT);
1177
- const blocks = contentFragment.toJSON();
1178
- const planText = blocks.map((block) => {
1179
- if (!block.content || !Array.isArray(block.content)) return "";
1180
- return block.content.map((item) => typeof item === "object" && item && "text" in item ? item.text : "").join("");
1181
- }).filter(Boolean).join("\n");
1179
+ const fragmentJson = contentFragment.toJSON();
1180
+ let planText = "";
1181
+ if (Array.isArray(fragmentJson)) {
1182
+ const blocks = fragmentJson;
1183
+ planText = blocks.map((block) => {
1184
+ if (!block.content || !Array.isArray(block.content)) return "";
1185
+ return block.content.map((item) => typeof item === "object" && item && "text" in item ? item.text : "").join("");
1186
+ }).filter(Boolean).join("\n");
1187
+ }
1182
1188
  const resolveUser = createUserResolver(ydoc);
1183
1189
  const feedbackText = formatThreadsForLLM(threads, {
1184
1190
  includeResolved: false,
@@ -5058,7 +5064,7 @@ async function setupReviewNotification(planId, pollIntervalSeconds) {
5058
5064
  return { script, fullResponse: text };
5059
5065
  }
5060
5066
  async function requestUserInput(opts) {
5061
- const { InputRequestManager: InputRequestManager2 } = await import("./input-request-manager-YVKAMQPF.js");
5067
+ const { InputRequestManager: InputRequestManager2 } = await import("./input-request-manager-MVKPYLFW.js");
5062
5068
  const ydoc = await getOrCreateDoc3(PLAN_INDEX_DOC_NAME);
5063
5069
  const manager = new InputRequestManager2();
5064
5070
  const params = opts.type === "choice" ? {
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  InputRequestManager
3
- } from "./chunk-SIQIBECG.js";
3
+ } from "./chunk-N44DCU4J.js";
4
4
  import "./chunk-LTC26IRQ.js";
5
5
  import "./chunk-GSGLHRWX.js";
6
6
  import "./chunk-JSBRDJBE.js";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@schoolai/shipyard-mcp",
3
- "version": "0.1.0",
3
+ "version": "0.1.1",
4
4
  "description": "Shipyard MCP server and CLI tools for distributed planning with CRDTs",
5
5
  "type": "module",
6
6
  "bin": {