@schoolai/shipyard-mcp 0.2.2-next.493 → 0.2.2-next.497

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.
@@ -44411,9 +44411,29 @@ var planRouter = router({
44411
44411
  if (!cwd) return {
44412
44412
  available: false,
44413
44413
  reason: "no_cwd",
44414
- message: "Plan has no associated working directory. Only Claude Code plans support local changes."
44414
+ message: "Plan has no associated working directory. Local changes are only available for plans created with working directory metadata."
44415
44415
  };
44416
44416
  return ctx.getLocalChanges(cwd);
44417
+ }),
44418
+ getFileContent: publicProcedure.input(external_exports.object({
44419
+ planId: PlanIdSchema.shape.planId,
44420
+ filePath: external_exports.string()
44421
+ })).output(external_exports.object({
44422
+ content: external_exports.string().nullable(),
44423
+ error: external_exports.string().optional()
44424
+ })).query(async ({ input, ctx }) => {
44425
+ const metadata = getPlanMetadata(await ctx.getOrCreateDoc(input.planId));
44426
+ if (!metadata) throw new TRPCError({
44427
+ code: "NOT_FOUND",
44428
+ message: "Plan not found"
44429
+ });
44430
+ const origin = metadata.origin;
44431
+ const cwd = origin?.platform === "claude-code" ? origin.cwd : void 0;
44432
+ if (!cwd) return {
44433
+ content: null,
44434
+ error: "No working directory available"
44435
+ };
44436
+ return ctx.getFileContent(cwd, input.filePath);
44417
44437
  })
44418
44438
  });
44419
44439
  var subscriptionRouter = router({
@@ -3,7 +3,7 @@ import {
3
3
  YDOC_KEYS,
4
4
  createInputRequest,
5
5
  logPlanEvent
6
- } from "./chunk-5V7HUMDU.js";
6
+ } from "./chunk-RSQQVNON.js";
7
7
  import {
8
8
  logger
9
9
  } from "./chunk-GSGLHRWX.js";
@@ -2811,9 +2811,29 @@ var planRouter = router({
2811
2811
  if (!cwd) return {
2812
2812
  available: false,
2813
2813
  reason: "no_cwd",
2814
- message: "Plan has no associated working directory. Only Claude Code plans support local changes."
2814
+ message: "Plan has no associated working directory. Local changes are only available for plans created with working directory metadata."
2815
2815
  };
2816
2816
  return ctx.getLocalChanges(cwd);
2817
+ }),
2818
+ getFileContent: publicProcedure.input(z3.object({
2819
+ planId: PlanIdSchema.shape.planId,
2820
+ filePath: z3.string()
2821
+ })).output(z3.object({
2822
+ content: z3.string().nullable(),
2823
+ error: z3.string().optional()
2824
+ })).query(async ({ input, ctx }) => {
2825
+ const metadata = getPlanMetadata(await ctx.getOrCreateDoc(input.planId));
2826
+ if (!metadata) throw new TRPCError({
2827
+ code: "NOT_FOUND",
2828
+ message: "Plan not found"
2829
+ });
2830
+ const origin = metadata.origin;
2831
+ const cwd = origin?.platform === "claude-code" ? origin.cwd : void 0;
2832
+ if (!cwd) return {
2833
+ content: null,
2834
+ error: "No working directory available"
2835
+ };
2836
+ return ctx.getFileContent(cwd, input.filePath);
2817
2837
  })
2818
2838
  });
2819
2839
  var subscriptionRouter = router({
@@ -212,7 +212,7 @@ import {
212
212
  updateLinkedPRStatus,
213
213
  updatePlanIndexViewedBy,
214
214
  validateA2AMessages
215
- } from "./chunk-5V7HUMDU.js";
215
+ } from "./chunk-RSQQVNON.js";
216
216
  import "./chunk-JSBRDJBE.js";
217
217
  export {
218
218
  A2ADataPartSchema,
@@ -20,7 +20,7 @@ import {
20
20
  } from "./chunk-EBNL5ZX7.js";
21
21
  import {
22
22
  InputRequestManager
23
- } from "./chunk-ZD2SHV5V.js";
23
+ } from "./chunk-BL4TO47B.js";
24
24
  import {
25
25
  ArtifactSchema,
26
26
  DeliverableSchema,
@@ -72,7 +72,7 @@ import {
72
72
  setPlanMetadata,
73
73
  touchPlanIndexEntry,
74
74
  transitionPlanStatus
75
- } from "./chunk-5V7HUMDU.js";
75
+ } from "./chunk-RSQQVNON.js";
76
76
  import {
77
77
  loadEnv,
78
78
  logger
@@ -165,11 +165,11 @@ async function hasActiveConnections(planId) {
165
165
  }
166
166
 
167
167
  // src/registry-server.ts
168
- import { mkdirSync, readFileSync, unlinkSync } from "fs";
168
+ import { mkdirSync, readFileSync as readFileSync2, unlinkSync } from "fs";
169
169
  import { readFile, unlink, writeFile as writeFile2 } from "fs/promises";
170
170
  import http from "http";
171
171
  import { homedir as homedir3 } from "os";
172
- import { join as join3, resolve, sep } from "path";
172
+ import { join as join4, resolve, sep } from "path";
173
173
  import { createExpressMiddleware } from "@trpc/server/adapters/express";
174
174
  import express from "express";
175
175
  import * as decoding from "lib0/decoding";
@@ -385,6 +385,8 @@ function attachCRDTValidation(planId, doc) {
385
385
 
386
386
  // src/git-local-changes.ts
387
387
  import { execSync } from "child_process";
388
+ import { readFileSync } from "fs";
389
+ import { isAbsolute, join as join3, normalize } from "path";
388
390
  function getLocalChanges(cwd) {
389
391
  try {
390
392
  try {
@@ -395,11 +397,24 @@ function getLocalChanges(cwd) {
395
397
  stdio: ["pipe", "pipe", "pipe"]
396
398
  });
397
399
  } catch {
398
- return {
399
- available: false,
400
- reason: "not_git_repo",
401
- message: `Directory is not a git repository: ${cwd}`
402
- };
400
+ logger.info({ cwd }, "Not a git repo, initializing with git init");
401
+ try {
402
+ execSync("git init", {
403
+ cwd,
404
+ encoding: "utf-8",
405
+ timeout: 5e3,
406
+ stdio: ["pipe", "pipe", "pipe"]
407
+ });
408
+ logger.info({ cwd }, "Git repository initialized");
409
+ } catch (initError) {
410
+ const message = initError instanceof Error ? initError.message : "Unknown error";
411
+ logger.error({ error: initError, cwd }, "Failed to initialize git repository");
412
+ return {
413
+ available: false,
414
+ reason: "git_error",
415
+ message: `Failed to initialize git repository: ${message}`
416
+ };
417
+ }
403
418
  }
404
419
  let branch;
405
420
  try {
@@ -623,6 +638,32 @@ function detectStatus(fileDiff) {
623
638
  }
624
639
  return "modified";
625
640
  }
641
+ function getFileContent(cwd, filePath) {
642
+ try {
643
+ const normalizedPath = normalize(filePath);
644
+ if (isAbsolute(normalizedPath) || normalizedPath.startsWith("..")) {
645
+ return { content: null, error: "Invalid file path" };
646
+ }
647
+ const fullPath = join3(cwd, normalizedPath);
648
+ if (!fullPath.startsWith(cwd)) {
649
+ return { content: null, error: "Invalid file path" };
650
+ }
651
+ const content = readFileSync(fullPath, { encoding: "utf-8" });
652
+ if (content.length > 10 * 1024 * 1024) {
653
+ return { content: null, error: "File too large to display" };
654
+ }
655
+ return { content };
656
+ } catch (error) {
657
+ const message = error instanceof Error ? error.message : "Unknown error";
658
+ if (message.includes("ENOENT")) {
659
+ return { content: null, error: "File not found" };
660
+ }
661
+ if (message.includes("EISDIR")) {
662
+ return { content: null, error: "Path is a directory" };
663
+ }
664
+ return { content: null, error: `Failed to read file: ${message}` };
665
+ }
666
+ }
626
667
 
627
668
  // src/github-artifacts.ts
628
669
  import { Octokit } from "@octokit/rest";
@@ -1929,9 +1970,9 @@ function getParam(value) {
1929
1970
  if (Array.isArray(value)) return value[0];
1930
1971
  return value;
1931
1972
  }
1932
- var PERSISTENCE_DIR = join3(homedir3(), ".shipyard", "plans");
1933
- var HUB_LOCK_FILE = join3(homedir3(), ".shipyard", "hub.lock");
1934
- var SHIPYARD_DIR = join3(homedir3(), ".shipyard");
1973
+ var PERSISTENCE_DIR = join4(homedir3(), ".shipyard", "plans");
1974
+ var HUB_LOCK_FILE = join4(homedir3(), ".shipyard", "hub.lock");
1975
+ var SHIPYARD_DIR = join4(homedir3(), ".shipyard");
1935
1976
  var MAX_LOCK_RETRIES = 3;
1936
1977
  var messageSync = 0;
1937
1978
  var messageAwareness = 1;
@@ -2029,9 +2070,9 @@ function isProcessAlive(pid) {
2029
2070
  }
2030
2071
  }
2031
2072
  function tryRecoverStaleLock(originalError) {
2032
- const lockFile = join3(PERSISTENCE_DIR, "LOCK");
2073
+ const lockFile = join4(PERSISTENCE_DIR, "LOCK");
2033
2074
  try {
2034
- const hubLockContent = readFileSync(HUB_LOCK_FILE, "utf-8");
2075
+ const hubLockContent = readFileSync2(HUB_LOCK_FILE, "utf-8");
2035
2076
  const pidStr = hubLockContent.split("\n")[0] ?? "";
2036
2077
  const pid = Number.parseInt(pidStr, 10);
2037
2078
  if (isProcessAlive(pid)) {
@@ -2365,7 +2406,8 @@ function createContext() {
2365
2406
  logger,
2366
2407
  hookHandlers: createHookHandlers(),
2367
2408
  conversationHandlers: createConversationHandlers(),
2368
- getLocalChanges
2409
+ getLocalChanges,
2410
+ getFileContent
2369
2411
  };
2370
2412
  }
2371
2413
  function createApp() {
@@ -2408,7 +2450,7 @@ function createApp() {
2408
2450
  res.status(400).json({ error: "Missing planId or filename" });
2409
2451
  return;
2410
2452
  }
2411
- const ARTIFACTS_DIR2 = join3(homedir3(), ".shipyard", "artifacts");
2453
+ const ARTIFACTS_DIR2 = join4(homedir3(), ".shipyard", "artifacts");
2412
2454
  const fullPath = resolve(ARTIFACTS_DIR2, planId, filename);
2413
2455
  if (!fullPath.startsWith(ARTIFACTS_DIR2 + sep)) {
2414
2456
  res.status(400).json({ error: "Invalid artifact path" });
@@ -2725,11 +2767,11 @@ import { z as z3 } from "zod";
2725
2767
  // src/local-artifacts.ts
2726
2768
  import { mkdir as mkdir2, readFile as readFile2, rm, writeFile as writeFile3 } from "fs/promises";
2727
2769
  import { homedir as homedir4 } from "os";
2728
- import { join as join4, resolve as resolve2, sep as sep2 } from "path";
2770
+ import { join as join5, resolve as resolve2, sep as sep2 } from "path";
2729
2771
  async function storeLocalArtifact(planId, filename, buffer) {
2730
- const planDir = join4(ARTIFACTS_DIR, planId);
2772
+ const planDir = join5(ARTIFACTS_DIR, planId);
2731
2773
  await mkdir2(planDir, { recursive: true });
2732
- const filepath = join4(planDir, filename);
2774
+ const filepath = join5(planDir, filename);
2733
2775
  await writeFile3(filepath, buffer);
2734
2776
  logger.info({ planId, filename, size: buffer.length }, "Artifact stored locally");
2735
2777
  return `${planId}/${filename}`;
@@ -2752,7 +2794,7 @@ async function deleteLocalArtifact(artifactId) {
2752
2794
  return false;
2753
2795
  }
2754
2796
  }
2755
- var ARTIFACTS_DIR = join4(homedir4(), ".shipyard", "artifacts");
2797
+ var ARTIFACTS_DIR = join5(homedir4(), ".shipyard", "artifacts");
2756
2798
 
2757
2799
  // src/session-token.ts
2758
2800
  import { timingSafeEqual } from "crypto";
@@ -3177,11 +3219,11 @@ Linked to deliverable: ${input.deliverableId}` : "";
3177
3219
  }
3178
3220
  logger.info({ planId, snapshotUrl }, "Task auto-completed");
3179
3221
  const { homedir: homedir5 } = await import("os");
3180
- const { join: join6 } = await import("path");
3222
+ const { join: join7 } = await import("path");
3181
3223
  const { mkdir: mkdir3 } = await import("fs/promises");
3182
- const snapshotsDir = join6(homedir5(), ".shipyard", "snapshots");
3224
+ const snapshotsDir = join7(homedir5(), ".shipyard", "snapshots");
3183
3225
  await mkdir3(snapshotsDir, { recursive: true });
3184
- const snapshotFile = join6(snapshotsDir, `${planId}.txt`);
3226
+ const snapshotFile = join7(snapshotsDir, `${planId}.txt`);
3185
3227
  await writeFile4(snapshotFile, snapshotUrl, "utf-8");
3186
3228
  logger.info({ planId, snapshotFile }, "Snapshot URL written to file");
3187
3229
  let prText = "";
@@ -5650,7 +5692,7 @@ async function setupReviewNotification(planId, pollIntervalSeconds) {
5650
5692
  return { script, fullResponse: text };
5651
5693
  }
5652
5694
  async function requestUserInput(opts) {
5653
- const { InputRequestManager: InputRequestManager2 } = await import("./input-request-manager-QX7MYHH7.js");
5695
+ const { InputRequestManager: InputRequestManager2 } = await import("./input-request-manager-S5RMTI23.js");
5654
5696
  const ydoc = await getOrCreateDoc3(PLAN_INDEX_DOC_NAME);
5655
5697
  const manager = new InputRequestManager2();
5656
5698
  const params = opts.type === "choice" ? {
@@ -5694,7 +5736,7 @@ async function requestUserInput(opts) {
5694
5736
  };
5695
5737
  }
5696
5738
  async function postActivityUpdate(opts) {
5697
- const { logPlanEvent: logPlanEvent2 } = await import("./dist-2W7US5HB.js");
5739
+ const { logPlanEvent: logPlanEvent2 } = await import("./dist-XVATLWFP.js");
5698
5740
  const { getGitHubUsername: getGitHubUsername2 } = await import("./server-identity-LSZ4CZRK.js");
5699
5741
  const { nanoid: nanoid8 } = await import("nanoid");
5700
5742
  const doc = await getOrCreateDoc3(opts.planId);
@@ -5717,7 +5759,7 @@ async function postActivityUpdate(opts) {
5717
5759
  return { success: true, eventId, requestId };
5718
5760
  }
5719
5761
  async function resolveActivityRequest(opts) {
5720
- const { logPlanEvent: logPlanEvent2, getPlanEvents } = await import("./dist-2W7US5HB.js");
5762
+ const { logPlanEvent: logPlanEvent2, getPlanEvents } = await import("./dist-XVATLWFP.js");
5721
5763
  const { getGitHubUsername: getGitHubUsername2 } = await import("./server-identity-LSZ4CZRK.js");
5722
5764
  const doc = await getOrCreateDoc3(opts.planId);
5723
5765
  const actorName = await getGitHubUsername2();
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  InputRequestManager
3
- } from "./chunk-ZD2SHV5V.js";
4
- import "./chunk-5V7HUMDU.js";
3
+ } from "./chunk-BL4TO47B.js";
4
+ import "./chunk-RSQQVNON.js";
5
5
  import "./chunk-GSGLHRWX.js";
6
6
  import "./chunk-JSBRDJBE.js";
7
7
  export {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@schoolai/shipyard-mcp",
3
- "version": "0.2.2-next.493",
3
+ "version": "0.2.2-next.497",
4
4
  "description": "Shipyard MCP server and CLI tools for distributed planning with CRDTs",
5
5
  "type": "module",
6
6
  "bin": {