@snappedly-tools/shipyard 0.8.0 → 0.9.1-staging.36234719249

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.
Files changed (45) hide show
  1. package/README.md +24 -14
  2. package/dist/MountConfig-K5ILnfht.d.ts +26 -0
  3. package/dist/{MountConfig-BHnKnA4h.d.ts → SandboxProvider-oUAwYlWm.d.ts} +1 -26
  4. package/dist/{chunk-L6PX5QTU.js → chunk-57EEKW3R.js} +57 -55
  5. package/dist/chunk-57EEKW3R.js.map +1 -0
  6. package/dist/{chunk-JI3HDDMS.js → chunk-HXSZM52J.js} +3 -3
  7. package/dist/{chunk-JI3HDDMS.js.map → chunk-HXSZM52J.js.map} +1 -1
  8. package/dist/{chunk-44I2BL6E.js → chunk-JZUBT4WG.js} +20 -4
  9. package/dist/chunk-JZUBT4WG.js.map +1 -0
  10. package/dist/chunk-NQRFVKCU.js +1840 -0
  11. package/dist/chunk-NQRFVKCU.js.map +1 -0
  12. package/dist/chunk-Z5C4LHVP.js +137 -0
  13. package/dist/chunk-Z5C4LHVP.js.map +1 -0
  14. package/dist/createSandbox-DmbnWAZv.d.ts +739 -0
  15. package/dist/index.d.ts +7 -2534
  16. package/dist/index.js +216 -7269
  17. package/dist/index.js.map +1 -1
  18. package/dist/integrations/github.d.ts +52 -0
  19. package/dist/integrations/github.js +1049 -0
  20. package/dist/integrations/github.js.map +1 -0
  21. package/dist/integrations/releases.d.ts +136 -0
  22. package/dist/integrations/releases.js +500 -0
  23. package/dist/integrations/releases.js.map +1 -0
  24. package/dist/main.js +641 -383
  25. package/dist/main.js.map +1 -1
  26. package/dist/publication-BPoy_M9M.d.ts +1200 -0
  27. package/dist/sandboxes/docker.d.ts +2 -1
  28. package/dist/sandboxes/docker.js +2 -2
  29. package/dist/templates/parallel-planner/main.mts +11 -7
  30. package/dist/templates/parallel-planner/setup.sh +1 -0
  31. package/dist/templates/parallel-planner-with-review/main.mts +11 -7
  32. package/dist/templates/parallel-planner-with-review/setup.sh +1 -0
  33. package/dist/templates/sequential-reviewer/main.mts +7 -3
  34. package/dist/templates/sequential-reviewer/setup.sh +1 -0
  35. package/dist/templates/shared/setup.sh +1 -0
  36. package/dist/templates/simple-loop/main.mts +7 -3
  37. package/dist/templates/simple-loop/setup.sh +1 -0
  38. package/dist/workflow/coordinator/migrations/002_workflow_phase_records.sql +11 -0
  39. package/dist/workflow/coordinator/migrations/003_phase_record_schema_version.sql +6 -0
  40. package/dist/workflow.d.ts +472 -0
  41. package/dist/workflow.js +4345 -0
  42. package/dist/workflow.js.map +1 -0
  43. package/package.json +13 -1
  44. package/dist/chunk-44I2BL6E.js.map +0 -1
  45. package/dist/chunk-L6PX5QTU.js.map +0 -1
package/README.md CHANGED
@@ -39,9 +39,10 @@ npm install --save-dev @snappedly-tools/shipyard
39
39
  npx shipyard init
40
40
  ```
41
41
 
42
- During `shipyard init`, choose your agent, **Docker**, the template you want, and install the optional
43
- [repository runner](docs/content/docs/repository-runner.mdx). Follow
44
- the authentication prompts.
42
+ During `shipyard init`, choose your agent and template, then follow the
43
+ authentication prompts. GitHub Issues is the built-in tracker. Init builds the
44
+ Docker image and automatically installs the
45
+ [repository runner](docs/content/docs/repository-runner.mdx).
45
46
 
46
47
  On a local Mac, the repository runner automatically wakes Shipyard when you label an issue.
47
48
  It runs as long as its terminal stays open.
@@ -52,25 +53,31 @@ branch options.
52
53
  Fill in any credentials required in `.shipyard/.env`.
53
54
  `GH_TOKEN` in `.shipyard/.env` to a GH token with Contents, Issues, and Pull
54
55
  Requests read/write access and Metadata read access.
56
+
55
57
  Set `SHIPYARD_ROUTINE_MODEL` and `SHIPYARD_STRONG_MODEL` in `.shipyard/.env`
56
- for the roles your template uses. `simple-loop` uses routine for triage and
58
+ for the roles your template uses.
59
+
60
+ `simple-loop` uses routine for triage and
57
61
  implementation. `sequential-reviewer` also uses strong for issue reviews.
58
62
  Parallel planner templates use routine for ticket work and strong for planning,
59
63
  conflict resolution, and integration. The review-enabled planner also uses
60
64
  strong for ticket and final specification reviews. See
61
65
  [agent setup](docs/content/docs/agents.mdx).
62
66
 
63
- Commit the setup and prompt so the sandbox can read them. Make sure the Git ignore file keeps
64
- `.shipyard/.env` out of the commit.
67
+ ```sh
68
+ npx shipyard runner start
69
+ ```
70
+
71
+ To start Shipyard for a single run without the active runner, use:
65
72
 
66
73
  ```sh
67
74
  npx shipyard run
68
75
  ```
69
76
 
70
- Or for the automated runner:
77
+ To remove Shipyard from the repository:
71
78
 
72
79
  ```sh
73
- npx shipyard runner start
80
+ npx shipyard uninstall
74
81
  ```
75
82
 
76
83
  ## Turn GitHub issues into pull requests
@@ -79,8 +86,8 @@ Then:
79
86
 
80
87
  1. Write an issue with a clear goal and add the `shipyard` and
81
88
  `ready-for-agent` labels.
82
- 2. Make sure the runner is running, or start `npx shipyard run`. Shipyard checks the issue, implements it in Docker,
83
- reviews the work, and opens a pull request.
89
+ 2. Run Shipyard to check for the issue, implement it in Docker,
90
+ review the work, and open a pull request.
84
91
  3. Inspect the pull request and merge it when you are happy with the result.
85
92
 
86
93
  ## Choose a workflow
@@ -92,10 +99,13 @@ Then:
92
99
  | `parallel-planner` | Plans and works on independent issues in parallel. |
93
100
  | `parallel-planner-with-review` | Adds review to the parallel workflow. |
94
101
 
95
- Shipyard also exports TypeScript APIs for custom workflows. Configure prompts,
96
- branches, limits, and hooks in the generated `.shipyard/main.ts` or
97
- `.shipyard/main.mts`. See [configuration](docs/content/docs/configuration.mdx)
98
- and [agent setup](docs/content/docs/agents.mdx).
102
+ The package root exports the core run, interactive, and sandbox APIs. Import
103
+ hosted workflow coordination and GitHub integration APIs from
104
+ `@snappedly-tools/shipyard/workflow` and
105
+ `@snappedly-tools/shipyard/integrations/github`. Configure prompts, branches,
106
+ limits, and hooks in the generated `.shipyard/main.ts` or `.shipyard/main.mts`.
107
+ See [configuration](docs/content/docs/configuration.mdx) and
108
+ [agent setup](docs/content/docs/agents.mdx).
99
109
 
100
110
  ## Safety and license
101
111
 
@@ -0,0 +1,26 @@
1
+ /**
2
+ * User-facing mount configuration for Docker.
3
+ *
4
+ * Each entry describes a host directory to mount into the sandbox container.
5
+ */
6
+ /** A single bind-mount descriptor for the Docker provider. */
7
+ interface MountConfig {
8
+ /**
9
+ * Path on the host. Supports:
10
+ * - Absolute paths (`/data/cache`)
11
+ * - Tilde-expanded paths (`~/data` → `<home>/data`)
12
+ * - Relative paths (`data` or `./data`) — resolved from `process.cwd()`
13
+ */
14
+ readonly hostPath: string;
15
+ /**
16
+ * Path inside the sandbox container. Supports:
17
+ * - Absolute paths (`/mnt/data`)
18
+ * - Tilde-expanded paths (`~/.npm` → `/home/agent/.npm`) — expanded using the provider's sandbox home directory
19
+ * - Relative paths (`data` or `./data`) — resolved from the worktree directory (`/home/agent/workspace`)
20
+ */
21
+ readonly sandboxPath: string;
22
+ /** Mount as read-only. Defaults to `false`. */
23
+ readonly readonly?: boolean;
24
+ }
25
+
26
+ export type { MountConfig as M };
@@ -117,29 +117,4 @@ type BranchStrategy = MergeToHeadBranchStrategy | NamedBranchStrategy;
117
117
  /** Construct the isolated provider contract used by Docker. */
118
118
  declare const createIsolatedSandboxProvider: (config: IsolatedSandboxProviderConfig) => IsolatedSandboxProvider;
119
119
 
120
- /**
121
- * User-facing mount configuration for Docker.
122
- *
123
- * Each entry describes a host directory to mount into the sandbox container.
124
- */
125
- /** A single bind-mount descriptor for the Docker provider. */
126
- interface MountConfig {
127
- /**
128
- * Path on the host. Supports:
129
- * - Absolute paths (`/data/cache`)
130
- * - Tilde-expanded paths (`~/data` → `<home>/data`)
131
- * - Relative paths (`data` or `./data`) — resolved from `process.cwd()`
132
- */
133
- readonly hostPath: string;
134
- /**
135
- * Path inside the sandbox container. Supports:
136
- * - Absolute paths (`/mnt/data`)
137
- * - Tilde-expanded paths (`~/.npm` → `/home/agent/.npm`) — expanded using the provider's sandbox home directory
138
- * - Relative paths (`data` or `./data`) — resolved from the worktree directory (`/home/agent/workspace`)
139
- */
140
- readonly sandboxPath: string;
141
- /** Mount as read-only. Defaults to `false`. */
142
- readonly readonly?: boolean;
143
- }
144
-
145
- export { type BranchStrategy as B, type ExecResult as E, type IsolatedSandboxProvider as I, type MountConfig as M, type NamedBranchStrategy as N, type SessionTransferHandle as S, type SandboxProvider as a, type MergeToHeadBranchStrategy as b, type InteractiveExecOptions as c, type IsolatedCreateOptions as d, type IsolatedSandboxHandle as e, type IsolatedSandboxProviderConfig as f, createIsolatedSandboxProvider as g };
120
+ export { type BranchStrategy as B, type ExecResult as E, type IsolatedSandboxProvider as I, type MergeToHeadBranchStrategy as M, type NamedBranchStrategy as N, type SandboxProvider as S, type InteractiveExecOptions as a, type IsolatedCreateOptions as b, type IsolatedSandboxHandle as c, type IsolatedSandboxProviderConfig as d, createIsolatedSandboxProvider as e, type SessionTransferHandle as f };
@@ -31,12 +31,21 @@ var SilentDisplay = {
31
31
  ),
32
32
  progress: (title, effect) => Effect.gen(function* () {
33
33
  const updates = [];
34
- const result = yield* effect((update) => updates.push(update));
34
+ const report = Object.assign(
35
+ (update) => {
36
+ updates.push(update);
37
+ },
38
+ { pause: () => {
39
+ }, resume: () => {
40
+ } }
41
+ );
42
+ const exit = yield* Effect.exit(effect(report));
35
43
  yield* Ref.update(ref, (entries) => [
36
44
  ...entries,
37
45
  { _tag: "progress", title, updates: [...updates] }
38
46
  ]);
39
- return result;
47
+ if (Exit.isFailure(exit)) return yield* Effect.failCause(exit.cause);
48
+ return exit.value;
40
49
  }),
41
50
  summary: (title, rows) => Ref.update(ref, (entries) => [
42
51
  ...entries,
@@ -140,7 +149,15 @@ var FileDisplay = {
140
149
  yield* appendToLog(`${title}...`);
141
150
  const start = Date.now();
142
151
  const updates = [];
143
- const result = yield* effect((update) => updates.push(update));
152
+ const report = Object.assign(
153
+ (update) => {
154
+ updates.push(update);
155
+ },
156
+ { pause: () => {
157
+ }, resume: () => {
158
+ } }
159
+ );
160
+ const result = yield* effect(report);
144
161
  for (const update of updates) {
145
162
  yield* appendToLog(
146
163
  ` ${update.message} (${update.current}/${update.total})`
@@ -211,25 +228,39 @@ var ClackDisplay = {
211
228
  ),
212
229
  progress: (title, effect) => Effect.acquireUseRelease(
213
230
  Effect.sync(() => {
214
- const progress2 = clack.progress({ max: 100 });
231
+ const progress2 = clack.progress({ max: 100, withGuide: false });
215
232
  let percent = 0;
233
+ let currentMessage = title;
234
+ let paused = false;
216
235
  progress2.start(title);
217
- const report = (update) => {
236
+ const report = ((update) => {
218
237
  const total = Math.max(1, update.total);
219
238
  const current = Math.min(total, Math.max(0, update.current));
220
239
  const nextPercent = Math.round(current / total * 100);
221
240
  const message = `${update.message} (${current}/${total})`;
241
+ currentMessage = message;
222
242
  if (nextPercent > percent) {
223
243
  progress2.advance(nextPercent - percent, message);
224
244
  } else {
225
245
  progress2.message(message);
226
246
  }
227
247
  percent = nextPercent;
248
+ });
249
+ report.pause = () => {
250
+ if (paused) return;
251
+ progress2.clear();
252
+ paused = true;
253
+ };
254
+ report.resume = () => {
255
+ if (!paused) return;
256
+ progress2.start(currentMessage);
257
+ paused = false;
228
258
  };
229
259
  return { progress: progress2, report };
230
260
  }),
231
261
  ({ report }) => effect(report),
232
- ({ progress: progress2 }, exit) => Effect.sync(() => {
262
+ ({ progress: progress2, report }, exit) => Effect.sync(() => {
263
+ report.resume();
233
264
  if (exit._tag === "Success") {
234
265
  progress2.stop(`${title} complete`);
235
266
  } else {
@@ -1053,22 +1084,21 @@ var formatCommandBlock = (commands) => {
1053
1084
  }
1054
1085
  return commands.map((cmd, i) => i < commands.length - 1 ? ` ${cmd} && \\` : ` ${cmd}`).join("\n");
1055
1086
  };
1056
-
1057
- // src/syncOut.ts
1058
1087
  var execHostGit2 = (args, cwd) => Effect.tryPromise({
1059
1088
  try: () => execHostGit(args, cwd),
1060
- catch: (e) => new SyncError({
1089
+ catch: (error) => new SyncError({
1061
1090
  message: `Host command failed: git ${args.join(" ")}
1062
- ${e instanceof Error ? e.message : String(e)}`
1091
+ ${error instanceof Error ? error.message : String(error)}`
1063
1092
  })
1064
1093
  });
1065
- var execOk = (handle, command, options) => Effect.tryPromise({
1094
+ var execSandbox = (handle, command, options) => Effect.tryPromise({
1066
1095
  try: () => handle.exec(command, options),
1067
- catch: (e) => new SyncError({
1096
+ catch: (error) => new SyncError({
1068
1097
  message: `Sandbox exec failed: ${command}
1069
- ${e instanceof Error ? e.message : String(e)}`
1098
+ ${error instanceof Error ? error.message : String(error)}`
1070
1099
  })
1071
- }).pipe(
1100
+ });
1101
+ var execOk = (handle, command, options) => execSandbox(handle, command, options).pipe(
1072
1102
  Effect.flatMap(
1073
1103
  (result) => result.exitCode !== 0 ? Effect.fail(
1074
1104
  new SyncError({
@@ -1078,13 +1108,8 @@ ${result.stderr}`
1078
1108
  ) : Effect.succeed(result)
1079
1109
  )
1080
1110
  );
1081
- var execSandbox = (handle, command, options) => Effect.tryPromise({
1082
- try: () => handle.exec(command, options),
1083
- catch: (e) => new SyncError({
1084
- message: `Sandbox exec failed: ${command}
1085
- ${e instanceof Error ? e.message : String(e)}`
1086
- })
1087
- });
1111
+
1112
+ // src/syncOut.ts
1088
1113
  var isEmptyPatch = (patchPath) => Effect.tryPromise({
1089
1114
  try: async () => {
1090
1115
  const info = await stat(patchPath);
@@ -1977,32 +2002,9 @@ var WorktreeDockerSandboxFactory = {
1977
2002
  })
1978
2003
  )
1979
2004
  };
1980
- var execHostGit3 = (args, cwd) => Effect.tryPromise({
1981
- try: () => execHostGit(args, cwd),
1982
- catch: (e) => new SyncError({
1983
- message: `Host command failed: git ${args.join(" ")}
1984
- ${e instanceof Error ? e.message : String(e)}`
1985
- })
1986
- });
1987
- var execOk3 = (handle, command, options) => Effect.tryPromise({
1988
- try: () => handle.exec(command, options),
1989
- catch: (e) => new SyncError({
1990
- message: `Sandbox exec failed: ${command}
1991
- ${e instanceof Error ? e.message : String(e)}`
1992
- })
1993
- }).pipe(
1994
- Effect.flatMap(
1995
- (result) => result.exitCode !== 0 ? Effect.fail(
1996
- new SyncError({
1997
- message: `Sandbox command failed (exit ${result.exitCode}): ${command}
1998
- ${result.stderr}`
1999
- })
2000
- ) : Effect.succeed(result)
2001
- )
2002
- );
2003
2005
  var syncIn = (hostRepoDir, handle) => Effect.gen(function* () {
2004
2006
  const protectedRunnerPath = `${CONFIG_DIR}/${RUNNER_DIR}`;
2005
- const runnerObjects = yield* execHostGit3(
2007
+ const runnerObjects = yield* execHostGit2(
2006
2008
  ["rev-list", "--objects", "--all", "--", protectedRunnerPath],
2007
2009
  hostRepoDir
2008
2010
  );
@@ -2013,7 +2015,7 @@ var syncIn = (hostRepoDir, handle) => Effect.gen(function* () {
2013
2015
  })
2014
2016
  );
2015
2017
  }
2016
- const branch = (yield* execHostGit3(
2018
+ const branch = (yield* execHostGit2(
2017
2019
  ["rev-parse", "--abbrev-ref", "HEAD"],
2018
2020
  hostRepoDir
2019
2021
  )).trim();
@@ -2026,11 +2028,11 @@ var syncIn = (hostRepoDir, handle) => Effect.gen(function* () {
2026
2028
  const bundleHostPath = join(bundleDir, "repo.bundle");
2027
2029
  yield* Effect.ensuring(
2028
2030
  Effect.gen(function* () {
2029
- yield* execHostGit3(
2031
+ yield* execHostGit2(
2030
2032
  ["bundle", "create", bundleHostPath, "--all"],
2031
2033
  hostRepoDir
2032
2034
  );
2033
- const mkTempResult = yield* execOk3(
2035
+ const mkTempResult = yield* execOk(
2034
2036
  handle,
2035
2037
  `mktemp -d -t ${RUNTIME_NAMESPACE}-XXXXXX`
2036
2038
  );
@@ -2043,26 +2045,26 @@ var syncIn = (hostRepoDir, handle) => Effect.gen(function* () {
2043
2045
  })
2044
2046
  });
2045
2047
  const worktreePath = handle.worktreePath;
2046
- yield* execOk3(
2048
+ yield* execOk(
2047
2049
  handle,
2048
2050
  `git clone ${shellQuote(bundleSandboxPath)} ${shellQuote(`${worktreePath}_clone`)}`
2049
2051
  );
2050
- yield* execOk3(
2052
+ yield* execOk(
2051
2053
  handle,
2052
2054
  `rm -rf ${shellQuote(worktreePath)} && mv ${shellQuote(`${worktreePath}_clone`)} ${shellQuote(worktreePath)}`
2053
2055
  );
2054
- yield* execOk3(handle, `git checkout ${shellQuote(branch)}`, {
2056
+ yield* execOk(handle, `git checkout ${shellQuote(branch)}`, {
2055
2057
  cwd: worktreePath
2056
2058
  });
2057
2059
  yield* Effect.tryPromise({
2058
2060
  try: () => handle.exec(`rm -rf ${shellQuote(sandboxTmpDir)}`),
2059
2061
  catch: () => new SyncError({ message: "Failed to clean up sandbox temp dir" })
2060
2062
  });
2061
- const hostHead = (yield* execHostGit3(
2063
+ const hostHead = (yield* execHostGit2(
2062
2064
  ["rev-parse", "HEAD"],
2063
2065
  hostRepoDir
2064
2066
  )).trim();
2065
- const sandboxHead = (yield* execOk3(handle, "git rev-parse HEAD", {
2067
+ const sandboxHead = (yield* execOk(handle, "git rev-parse HEAD", {
2066
2068
  cwd: worktreePath
2067
2069
  })).stdout.trim();
2068
2070
  if (hostHead !== sandboxHead) {
@@ -2181,5 +2183,5 @@ var startSandbox = (options) => Effect.gen(function* () {
2181
2183
  });
2182
2184
 
2183
2185
  export { ACTIVATION_LABEL, AgentError, AgentIdleTimeoutError, CLI_NAME, CONFIG_DIR, ClackDisplay, ConfigDirError, CopyToWorktreeError, CopyToWorktreeTimeoutError, CwdError, Display, DockerError, ExecHostError, FileDisplay, InitError, LOCKS_DIR, LOGS_DIR, PRODUCT_NAME, PromptError, PromptExpansionTimeoutError, RUNNER_DIR, RUNTIME_NAMESPACE, SANDBOX_REPO_DIR, SandboxConfig, SandboxFactory, SessionCaptureError, SilentDisplay, WorktreeDockerSandboxFactory, assertExcludesRepositoryRunner, assertNoSymlinkComponents, assertProtectedDirectoryIdentities, create, createIsolatedSandboxProvider, generateTempBranchName, getCurrentBranch, hasUncommittedChanges, makeSandboxFromHandle, pruneStale, registerShutdown, remove, repositoryRunnerEnvironment, resolveCwd, resolveSafeRelativePath, runHostHooks, shellQuote, startSandbox, syncOut, toSessionTransferHandle, withSandboxLifecycle, withTimeout };
2184
- //# sourceMappingURL=chunk-L6PX5QTU.js.map
2185
- //# sourceMappingURL=chunk-L6PX5QTU.js.map
2186
+ //# sourceMappingURL=chunk-57EEKW3R.js.map
2187
+ //# sourceMappingURL=chunk-57EEKW3R.js.map